internal unsafe x86_64_cpu(Virtual_Regions.Region cpu_region) { /* We divide the cpu region into a pointer at offset 0 which * points to the actual Cpu class ('this' pointer) and a cpu-specific * heap following it. * * We then set the GS pointer to the start of the cpu region, thus * gs:0x0 is a pointer to the current Cpu instance for the current * processor. Setting of cur cpu's gs is done in InitCurrentCpu() * which is called on the BSP and every AP (and also sets up other * stuff like Apic address) */ gs = cpu_region.start; *(void **)cpu_region.start = libsupcs.CastOperations.ReinterpretAsPointer(this); this.cpu_alloc_current = (byte *)cpu_region.start + 8; this.cpu_alloc_max = (byte *)cpu_region.end; }
public override void Init(UIntPtr entry_address, Virtual_Regions.Region stack, Virtual_Regions.Region tls, UIntPtr exit_address, object[] parameters) { unsafe { max_stack = stack.start + stack.length; fs_base = tls.start + tls.length; // TLS offsets in x86_64 are negative relative to %fs so // set %fs to the end of the TLS section ulong *p_st = (ulong *)(max_stack); *--p_st = (ulong)exit_address; // address of __exit() /* The entry point to the thread */ *--p_st = (ulong)entry_address; Formatter.WriteLine("Thread.Init(" + ((ulong)entry_address).ToString("X") + ")", Program.arch.DebugOutput); if (parameters.Length > 6) { throw new NotImplementedException("x86_64 switcher: only <= 6 parameters of type INTEGER supported"); } /* The next entries are designed to reflect what is pushed when we call the task * switch function, so that returing from the task switch function, with rsp set to the end * of these entries will effect a task switch and restore the state */ *--p_st = DEFAULT_RFLAGS; *--p_st = 0; // RAX *--p_st = 0; // RBX *--p_st = get_param(parameters, 3); // RCX *--p_st = get_param(parameters, 2); // RDX *--p_st = get_param(parameters, 1); // RSI *--p_st = get_param(parameters, 0); // RDI *--p_st = 0; // RBP *--p_st = get_param(parameters, 4); // R8 *--p_st = get_param(parameters, 5); // R9 *--p_st = 0; // R10 *--p_st = 0; // R11 *--p_st = 0; // R12 *--p_st = 0; // R13 *--p_st = 0; // R14 *--p_st = 0; // R15 // XMMs *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; *--p_st = 0; rsp = (ulong)p_st; } }
public unsafe static void PFHandler(ulong error_code, ulong return_rip, ulong return_cs, ulong rflags, ulong return_rsp, ulong return_ss, libsupcs.x86_64.Cpu.InterruptRegisters64 *regs) { ulong fault_address = libsupcs.x86_64.Cpu.Cr2; /*Formatter.Write("PFault: ", Program.arch.DebugOutput); * Formatter.Write(fault_address, "X", Program.arch.DebugOutput); * Formatter.WriteLine(Program.arch.DebugOutput);*/ // Adjust the tss segment's ist1 pointer if (ist_stack != null) { cur_ist_idx++; if (cur_ist_idx >= 4) { Formatter.Write("kernel: Warning, increasing number of page fault virtual stacks being used, fault_address: ", Program.arch.DebugOutput); Formatter.Write(fault_address, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); } if (cur_ist_idx >= ist_stack.Count) { /* Catch page faults in this final unwind */ if (unwind_fail) { Formatter.WriteLine("kernel: Page fault: stack unwind failed", Program.arch.DebugOutput); libsupcs.OtherOperations.Halt(); } unwind_fail = true; Formatter.Write("Page fault. Address: 0x", Program.arch.DebugOutput); Formatter.Write(fault_address, "X", Program.arch.DebugOutput); Formatter.WriteLine("Page fault handler has run out of virtual stacks!", Program.arch.BootInfoOutput); Formatter.WriteLine("kernel: Page fault handler has run out of virtual stacks!", Program.arch.DebugOutput); Formatter.WriteLine("kernel: Stack dump", Program.arch.DebugOutput); // Switch to protected heap if (Program.arch.CurrentCpu != null) { Program.arch.CurrentCpu.UseCpuAlloc = true; } else { tysos.gc.gc.Heap = gc.gc.HeapType.Startup; } Unwind.DumpUnwindInfo(pf_unwinder.Init().UnwindOne().DoUnwind((UIntPtr)Program.arch.ExitAddress), Program.arch.DebugOutput); libsupcs.OtherOperations.Halt(); } unsafe { *(ulong *)(tss_addr + ist1_offset) = ist_stack[cur_ist_idx]; } } if (Program.arch.VirtualRegions.heap.contains(fault_address)) { // If the faulting address is in the heap, map a new page //Program.arch.VirtMem.map_page(fault_address); //Formatter.WriteLine("IN HEAP", Program.arch.DebugOutput); do_map(fault_address, error_code); } else { //Formatter.WriteLine("NOT IN HEAP", Program.arch.DebugOutput); /* Check if it something we can allocate, i.e. stack space or SSE storage space or cpu-specific space */ Virtual_Regions.Region cur_reg = Program.arch.VirtualRegions.list_start; bool success = false; while ((cur_reg != null) && !success) { if (cur_reg.contains(fault_address)) { if ((cur_reg.type == Virtual_Regions.Region.RegionType.SSE_state) || (cur_reg.type == Virtual_Regions.Region.RegionType.CPU_specific) || (cur_reg.type == Virtual_Regions.Region.RegionType.IPC) || cur_reg.type == Virtual_Regions.Region.RegionType.ModuleSection) { //Program.arch.VirtMem.map_page(fault_address); do_map(fault_address, error_code); success = true; } else if (cur_reg.type == Virtual_Regions.Region.RegionType.Stack) { /* Check for stack overflow into the guard page */ if (fault_address < (cur_reg.start + cur_reg.stack_protect)) { Formatter.Write("Page fault. Address: 0x", Program.arch.BootInfoOutput); Formatter.Write(fault_address, "X", Program.arch.BootInfoOutput); Formatter.WriteLine(Program.arch.BootInfoOutput); Formatter.WriteLine("Stack overflow!", Program.arch.BootInfoOutput); Formatter.Write("Page fault. Address: 0x", Program.arch.DebugOutput); Formatter.Write(fault_address, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); Formatter.WriteLine("Stack overflow!", Program.arch.DebugOutput); /* Unwind the stack */ if (pf_unwinder != null) { if (Program.arch.CurrentCpu != null) { Program.arch.CurrentCpu.UseCpuAlloc = true; } else { tysos.gc.gc.Heap = gc.gc.HeapType.Startup; } Formatter.WriteLine("Stack trace: ", Program.arch.DebugOutput); pf_unwinder.Init(); Unwind.DumpUnwindInfo(((libsupcs.x86_64.Unwinder)pf_unwinder).UnwindOneWithErrorCode().DoUnwind((UIntPtr)Program.arch.ExitAddress, false), Program.arch.DebugOutput); } libsupcs.OtherOperations.Halt(); } else { //Program.arch.VirtMem.map_page(fault_address); do_map(fault_address, error_code); success = true; } } } cur_reg = cur_reg.next; } if (!success) { if (Arch.unwinding) { // If we are in the middle of unwinding a previous page fault then // any new fault is caught when we reach the end of the stack, so we // should stop. Formatter.Write("Invalid page fault whilst unwinding. Address: 0x", Program.arch.DebugOutput); Formatter.Write(fault_address, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); Formatter.Write("Invalid page fault whilst unwinding. Address: 0x", Program.arch.BootInfoOutput); Formatter.Write(fault_address, "X", Program.arch.BootInfoOutput); Formatter.WriteLine(Program.arch.BootInfoOutput); libsupcs.OtherOperations.Halt(); } Formatter.Write("Page fault. Address: 0x", Program.arch.BootInfoOutput); Formatter.Write(fault_address, "X", Program.arch.BootInfoOutput); Formatter.WriteLine(Program.arch.BootInfoOutput); Formatter.WriteLine("Address not allowed!", Program.arch.BootInfoOutput); Formatter.Write("Page fault. Address: 0x", Program.arch.DebugOutput); Formatter.Write(fault_address, "X", Program.arch.DebugOutput); Formatter.WriteLine(" - address not allowed!", Program.arch.DebugOutput); // Extract error code and return eip ulong rbp = libsupcs.x86_64.Cpu.RBP; ulong ec, rip; unsafe { ec = *(ulong *)(rbp + 8); rip = *(ulong *)(rbp + 16); rbp = *(ulong *)rbp; } Formatter.Write("Error code: ", Program.arch.DebugOutput); Formatter.Write(ec, Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); Formatter.Write("RIP: ", Program.arch.DebugOutput); Formatter.Write(rip, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); tysos.x86_64.Exceptions.DumpExceptionData(error_code, return_rip, return_cs, rflags, return_rsp, return_ss, rbp, regs); //Program.arch.VirtualRegions.Dump(Program.arch.DebugOutput); if (pf_unwinder != null) { if (Program.arch.CurrentCpu != null) { Program.arch.CurrentCpu.UseCpuAlloc = true; } else { tysos.gc.gc.Heap = gc.gc.HeapType.Startup; } Arch.unwinding = true; Formatter.WriteLine("Stack trace: ", Program.arch.DebugOutput); pf_unwinder.Init(); //Unwind.DumpUnwindInfo(((libsupcs.x86_64.Unwinder)pf_unwinder).UnwindOneWithErrorCode().DoUnwind((UIntPtr)Program.arch.ExitAddress), // Program.arch.DebugOutput); Unwind.DumpUnwindInfo(pf_unwinder.DoUnwind((UIntPtr)Program.arch.ExitAddress), Program.arch.DebugOutput); } /* Unwind the stack */ /*Unwind u2 = new Unwind(); * * DumpIP(u2.UnwindOneWithErrorCode()); * ulong next_rip2; * do * { * next_rip2 = u2.UnwindOne(); * DumpIP(next_rip2); * } while (next_rip2 != 0);*/ libsupcs.OtherOperations.Halt(); } } // Restore the tss segment's ist1 pointer if (ist_stack != null) { cur_ist_idx--; unsafe { *(ulong *)(tss_addr + ist1_offset) = ist_stack[cur_ist_idx]; } } }
internal override void Init(UIntPtr chunk_vaddr, UIntPtr chunk_length, Multiboot.Header mboot) { /* Set up an x86_64 environment */ /* Get the top of the stack * * cur_rbp points to prev_rbp (rbp within Main) * [prev_rbp + 8] is the rip within tload */ unsafe { ulong cur_rbp = libsupcs.x86_64.Cpu.RBP; ulong prev_rbp = *(ulong *)cur_rbp; init_exit_address = *(ulong *)(prev_rbp + 8); } // Enable sse (used for virtftnptr stores and loads) - see Intel 3a:13.1.4 ulong cr4 = libsupcs.x86_64.Cpu.Cr4; cr4 |= 0x200; // set cr4.OSFXSR libsupcs.x86_64.Cpu.Cr4 = cr4; cr4 |= 0x400; // set cr4.OSXMMXCPT libsupcs.x86_64.Cpu.Cr4 = cr4; ulong cr0 = libsupcs.x86_64.Cpu.Cr0; cr0 |= 0x4; cr0 ^= 0x4; // clear cr0.EM libsupcs.x86_64.Cpu.Cr0 = cr0; cr0 |= 0x2; // set cr0.MP libsupcs.x86_64.Cpu.Cr0 = cr0; cr0 |= (1 << 16); // set cr0.WP libsupcs.x86_64.Cpu.Cr0 = cr0; /* Set-up the MXCSR register * * We want to unmask all exceptions except the precision exception which is thrown if the * result of an operation cannot be stored with complete precision in an xmm register, * e.g. 1/3 - this happens frequently and is expected, so we don't not want to raise a #XM * exception here. The precision mask is bit 12. * * We set the rounding mode (bits 13 and 14) to 00b which is round to even as the Math.Round * function expects this mode * * All other bits are cleared. */ uint mxcsr = 0x1000; libsupcs.x86_64.Cpu.Mxcsr = mxcsr; /* Set up the memory managers */ bda_va = (ulong)chunk_vaddr; pmem_bitmap_va = bda_va + 0x1000; vmem_temppage_va = bda_va + 0x3000; vga_fb_va = bda_va + 0x4000; VirtMem = new Vmem(); PhysMem = new Pmem(); PhysMem.vmem = VirtMem; Multiboot.MachineMinorType_x86 bios = (Multiboot.MachineMinorType_x86)mboot.machine_minor_type; /* Set up the debug outputs */ DebugOutput = new SerialDebug(); /*if (mboot.has_vga && bios == Multiboot.MachineMinorType_x86.BIOS) * { * VirtMem.Map(0, 0x1000, bda_va, 0); // TODO: will this cause Map() to allocate a physical page? * //VirtMem.map_page(bda_va, 0x0); * BootInfoOutput = new Vga(bda_va, vga_fb_va, VirtMem); * } * else*/ BootInfoOutput = DebugOutput; /* Say hi */ Formatter.WriteLine("Tysos x86_64 architecture initialising", DebugOutput); // Only provide free pages to the memory allocator var fmem = new List <EarlyPageProvider.EPPRegion>(); // Iterate through each free block for (int i = 0; i < mboot.mmap.Length; i++) { Multiboot.MemoryMap cur_mmap = mboot.mmap[i]; if (IsUefiFreeMemory(cur_mmap.type)) { // do not use first page if (cur_mmap.base_addr < 0x1000) { if (cur_mmap.length < 0x1000) { continue; } cur_mmap.base_addr += 0x1000; cur_mmap.length -= 0x1000; } // x is the current address to add var x = util.align(cur_mmap.base_addr, 0x1000); while (x < cur_mmap.base_addr + cur_mmap.length - 0x1000) { // is x in a used block? bool in_used = false; for (int j = 0; j < mboot.mmap.Length; j++) { Multiboot.MemoryMap cur_mmap2 = mboot.mmap[j]; if (!IsUefiFreeMemory(cur_mmap2.type)) { if (x >= cur_mmap2.base_addr && x < (cur_mmap2.base_addr + cur_mmap2.length)) { in_used = true; // advance x x = cur_mmap2.base_addr + cur_mmap2.length; break; } } } if (in_used) { continue; // loop and check again if in used block } // Now we know we are not currently in a free block, // but need to ensure we don't cross over the boundary of the next // lowest block, so find this while (true) { // Find lowest used block greater than or equal to x ulong lowest_start = ulong.MaxValue; ulong lowest_len = 0; bool has_lowest = false; for (int j = 0; j < mboot.mmap.Length; j++) { Multiboot.MemoryMap cur_mmap2 = mboot.mmap[j]; if (!IsUefiFreeMemory(cur_mmap2.type)) { if (x < cur_mmap2.base_addr && cur_mmap2.base_addr < lowest_start) { has_lowest = true; lowest_start = cur_mmap2.base_addr; lowest_len = cur_mmap2.length; } } } // if the lowest block is outside the current block, ignore it if (lowest_start >= (cur_mmap.base_addr + cur_mmap.length)) { has_lowest = false; } // now, if has_lowest is true, we set the max here to it, else // we use the total size of the free block, aligned down ulong cur_block_max = (has_lowest ? lowest_start : (cur_mmap.base_addr + cur_mmap.length)) & ~0xFFFUL; // Debug out Formatter.Write("x86_64 PhysMem: adding block ", DebugOutput); Formatter.Write(x, "X", DebugOutput); Formatter.Write(" - ", DebugOutput); Formatter.Write(cur_block_max, "X", DebugOutput); Formatter.WriteLine(DebugOutput); fmem.Add(new EarlyPageProvider.EPPRegion { start = x, length = cur_block_max - x, used = 0 }); // subtract a page size cur_block_max -= 0x1000; while (x <= cur_block_max) { //PhysMem.ReleasePage(x); x += 0x1000; } Formatter.Write(x, "X", DebugOutput); Formatter.WriteLine(DebugOutput); // have we reached the end of the block? if (x >= cur_mmap.base_addr + cur_mmap.length - 0x1000) { break; } else { // if not, we have hit a used block, skip on to after it x = util.align(lowest_start + lowest_len, 0x1000); } } } } } // Use the free memory list to create a direct mapping of all physical memory var pp = new EarlyPageProvider(fmem); ((Vmem)VirtMem).GenerateDirectMapping(fmem, pp); Formatter.WriteLine("Direct physical memory mapping generated @ 0x0xffffff0000000000", DebugOutput); // Now create the actual physical memory manager with the free blocks PhysMem.vmem = VirtMem; for (int i = 0; i < fmem.Count; i++) { var fmemi = fmem[i]; if (fmemi.length > fmemi.used + 0x2000) { PhysMem.Release(fmemi.start, fmemi.length - fmemi.used); } } PageFault.pf_unwinder = new libsupcs.x86_64.Unwinder(); // Display success Formatter.Write("Allocated: ", DebugOutput); Formatter.Write(PhysMem.FreeSpace, DebugOutput); Formatter.WriteLine(" B", DebugOutput); VirtMem.pmem = PhysMem; Formatter.Write("x86_64: mboot.max_tysos: ", DebugOutput); Formatter.Write(mboot.max_tysos, "X", DebugOutput); Formatter.Write(", tysos_virtaddr: ", DebugOutput); Formatter.Write(mboot.tysos_virtaddr, "X", DebugOutput); Formatter.Write(", tysos_size: ", DebugOutput); Formatter.Write(mboot.tysos_size, "X", DebugOutput); Formatter.WriteLine(DebugOutput); /* Set up the virtual region allocator */ if (mboot.max_tysos != 0) { VirtualRegions = new Virtual_Regions(0, mboot.max_tysos); } else { VirtualRegions = new Virtual_Regions(mboot.tysos_virtaddr, mboot.tysos_size); } Formatter.WriteLine("x86_64: Virtual region allocator started", DebugOutput); VirtualRegions.Dump(DebugOutput); /* Set up interrupts */ ulong idt_start = VirtualRegions.Alloc(256 * 16, 0x1000, "idt"); VirtMem.Map(PhysMem.GetPage(), 0x1000, idt_start, VirtMem.FLAG_writeable); Interrupts = new Interrupts(idt_start); Formatter.WriteLine("x86_64: IDT allocated", DebugOutput); unsafe { // Install the page fault handler Interrupts.InstallHandler(14, new Interrupts.ISREC(PageFault.PFHandler)); // Install some default handlers Interrupts.InstallHandler(0, new Interrupts.ISR(Exceptions.DivideError_0_Handler)); Interrupts.InstallHandler(1, new Interrupts.ISR(Exceptions.DebugError_1_Handler)); Interrupts.InstallHandler(2, new Interrupts.ISR(Exceptions.NMIError_2_Handler)); Interrupts.InstallHandler(3, new Interrupts.ISR(Exceptions.BreakPoint_3_Handler)); Interrupts.InstallHandler(4, new Interrupts.ISR(Exceptions.OverflowError_4_Handler)); Interrupts.InstallHandler(5, new Interrupts.ISR(Exceptions.BoundCheckError_5_Handler)); Interrupts.InstallHandler(6, new Interrupts.ISR(Exceptions.InvalidOpcode_6_Handler)); Interrupts.InstallHandler(7, new Interrupts.ISR(Exceptions.DeviceNotPresentError_7_Handler)); Interrupts.InstallHandler(8, new Interrupts.ISREC(Exceptions.DoubleFault_8_Handler)); Interrupts.InstallHandler(10, new Interrupts.ISREC(Exceptions.TSSError_10_Handler)); Interrupts.InstallHandler(11, new Interrupts.ISREC(Exceptions.SegmentNotPresentError_11_Handler)); Interrupts.InstallHandler(12, new Interrupts.ISREC(Exceptions.StackeFaultError_12_Handler)); Interrupts.InstallHandler(13, new Interrupts.ISREC(Exceptions.GeneralProtection_13_Handler)); Interrupts.InstallHandler(16, new Interrupts.ISR(Exceptions.FPUError_16_Handler)); Interrupts.InstallHandler(17, new Interrupts.ISREC(Exceptions.AlignmentCheck_17_Handler)); Interrupts.InstallHandler(18, new Interrupts.ISR(Exceptions.MachineCheckError_18_Handler)); Interrupts.InstallHandler(19, new Interrupts.ISR(Exceptions.SIMD_19_Handler)); } Formatter.WriteLine("x86_64: Default exception handlers installed", DebugOutput); /* Set up the tss and IST stacks */ ulong tss; tss = VirtualRegions.Alloc(0x1000, 0x1000, "tss"); ulong[] ists = new ulong[7]; /* Create 2 ISTs with guard pages */ int ist_count = 2; ulong ist_size = 0x2000; ulong ist_guard_size = 0x1000; for (int i = 0; i < ist_count; i++) { ulong ist_base = VirtualRegions.Alloc(ist_size + ist_guard_size, 0x1000, "IST"); ists[i] = ist_base + ist_guard_size + ist_size; for (ulong addr = ist_base + ist_guard_size; addr < ist_base + ist_guard_size + ist_size; addr += 0x1000) { VirtMem.Map(PhysMem.GetPage(), 0x1000, addr, VirtMem.FLAG_writeable); } } VirtMem.Map(PhysMem.GetPage(), 0x1000, tss, VirtMem.FLAG_writeable); Tss.Init(tss, ists); Formatter.WriteLine("x86_64: TSS installed", DebugOutput); // Now inform the page fault and double fault handlers to use their own stack unsafe { Interrupts.InstallHandler(14, new Interrupts.ISREC(PageFault.PFHandler), 1); Interrupts.InstallHandler(8, new Interrupts.ISREC(Exceptions.DoubleFault_8_Handler), 2); } Formatter.WriteLine("x86_64: Page fault and double fault handlers installed", DebugOutput); /* Set up the current cpu */ Virtual_Regions.Region cpu_reg = VirtualRegions.AllocRegion(0x8000, 0x1000, "BSP cpu", 0, Virtual_Regions.Region.RegionType.CPU_specific, true); VirtMem.Map(PhysMem.GetPage(), 0x1000, cpu_reg.start, VirtMem.FLAG_writeable); x86_64_cpu bsp = new x86_64_cpu(cpu_reg); bsp.InitCurrentCpu(); cpu_structure_setup = true; // Set up the page fault handler's stack switching mechanism /*ulong pfault_ist_block = VirtualRegions.Alloc(VirtMem.page_size * 7, VirtMem.page_size, "PageFault ISTs"); * List<ulong> pfault_ists = new List<ulong>(); * pfault_ists.Add(ist_block + VirtMem.page_size); * for (int i = 0; i < 7; i++) * { * VirtMem.map_page(pfault_ist_block + (ulong)i * VirtMem.page_size); * pfault_ists.Add(pfault_ist_block + (ulong)(i + 1) * VirtMem.page_size); * } * PageFault.cur_ist_idx = 0; * PageFault.tss_addr = tss_start; * PageFault.ist1_offset = (ulong)(((libsupcs.TysosField)typeof(tysos.x86_64.Tss.Tss_struct).GetField("ist1")).Offset); * PageFault.ist_stack = pfault_ists;*/ /* Test the gengc */ Formatter.WriteLine("x86_64: testing gengc", Program.arch.DebugOutput); gc.gengc.heap = new gc.gengc(); Formatter.Write("gengc object created @ ", Program.arch.DebugOutput); Formatter.Write(libsupcs.CastOperations.ReinterpretAsUlong(gc.gengc.heap), "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); unsafe { gc.gengc.heap.Init((void *)heap_small_start, (void *)heap_long_end); /* Initial roots are the current stack, all static fields and the original heap */ gc.gengc.heap.AddRoots((byte *)mboot.stack_low, (byte *)mboot.stack_high); gc.gengc.heap.AddRoots((byte *)mboot.tysos_static_start, (byte *)mboot.tysos_static_end); gc.gengc.heap.AddRoots((byte *)mboot.heap_start, (byte *)mboot.heap_end); } Formatter.WriteLine("heap initialized", Program.arch.DebugOutput); int[] test_array = new int[] { 8, 8, 8, 8, 8, 8, 8 }; Formatter.WriteLine("test array created", Program.arch.DebugOutput); gc.gc.Heap = gc.gc.HeapType.GenGC; Formatter.WriteLine("heap set to gengc", Program.arch.DebugOutput); for (int i = 0; i < test_array.Length; i++) { Formatter.Write((ulong)i, Program.arch.DebugOutput); Formatter.Write(": size ", Program.arch.DebugOutput); Formatter.Write((ulong)test_array[i], Program.arch.DebugOutput); Formatter.Write(" returns ", Program.arch.DebugOutput); ulong addr = gc.gc.Alloc((ulong)test_array[i]); Formatter.Write(addr, "X", Program.arch.DebugOutput); Formatter.WriteLine(Program.arch.DebugOutput); } // Now point the heap to its proper location //ulong heap_start = 0xFFFF800000000000; //ulong heap_len = 0xFFFFFF8000000000 - heap_start; //gc.heap.Init(heap_start, heap_len); /*Formatter.Write("x86_64: setting heap to final location: ", Program.arch.DebugOutput); * Formatter.Write(heap_small_start, "X", Program.arch.DebugOutput); * Formatter.Write(" - ", Program.arch.DebugOutput); * Formatter.Write(heap_long_end, "X", Program.arch.DebugOutput); * Formatter.Write(" ", Program.arch.DebugOutput); * #if NO_BOEHM #if NO_TYSOSGC * gc.gc.Heap = gc.gc.HeapType.Startup; * gc.simple_heap.Init(heap_small_start, heap_long_end); #else * gc.gc.Heap = gc.gc.HeapType.TysosGC; * gc.heap.Init(heap_small_cutoff, heap_small_start, heap_small_end, heap_long_start, heap_long_end); #endif #else * gc.boehm.InitHeap(heap_small_start, heap_long_end); * gc.gc.Heap = gc.gc.HeapType.BoehmGC; #endif * * Formatter.WriteLine("done", Program.arch.DebugOutput); * Formatter.Write("x86_64: new heap of type ", Program.arch.DebugOutput); * Formatter.WriteLine(gc.gc.Heap.ToString(), Program.arch.DebugOutput); */ /* Test a dictionary */ var dtest = new Dictionary <int, int>(new Program.MyGenericEqualityComparer <int>()); dtest[2] = 42; var dout = dtest[2]; Formatter.Write("x86_64: dictionary test: ", DebugOutput); Formatter.Write((ulong)dout, DebugOutput); Formatter.WriteLine(DebugOutput); /* Test enum comparer */ var enumcomp = new metadata.GenericEqualityComparerEnum <metadata.MetadataStream.TableId>(); if (enumcomp.Equals(metadata.MetadataStream.TableId.Assembly, metadata.MetadataStream.TableId.Assembly)) { Formatter.WriteLine("x86_64: enumcomp test passed", DebugOutput); } else { Formatter.WriteLine("x86_64: enumcomp test failed", DebugOutput); } /* Test an enum dictionary */ var dtest2 = new Dictionary <metadata.MetadataStream.TableId, int>(new metadata.GenericEqualityComparerEnum <metadata.MetadataStream.TableId>()); dtest2[metadata.MetadataStream.TableId.TypeDef] = 42; var dout2 = dtest2[metadata.MetadataStream.TableId.TypeDef]; Formatter.Write("x86_64: enum dictionary test: ", DebugOutput); Formatter.Write((ulong)dout, DebugOutput); Formatter.WriteLine(DebugOutput); /* Test MetadataStream ctor */ Formatter.WriteLine("x86_64: Testing metadata ctor", DebugOutput); var mtest = new metadata.MetadataStream(); Formatter.WriteLine("x86_64: done", DebugOutput); /* Set-up the architecture for the JIT engine */ jit.Jit.t = libtysila5.target.Target.targets["x86_64"]; jit.Jit.t.Options["mcmodel"] = "large"; jit.Jit.t.InitIntcalls(); jit.Jit.bness = binary_library.Bitness.Bits64; jit.Jit.jsa = new JitStubAssembler(); /* Initialize firmware */ switch (bios) { case Multiboot.MachineMinorType_x86.UEFI: fwconf = new UEFI(VirtualRegions, VirtMem, mboot.virt_bda); break; case Multiboot.MachineMinorType_x86.BIOS: fwconf = new BIOS(VirtualRegions, VirtMem, mboot.virt_bda); break; default: throw new Exception("Unsupported firmware: " + bios.ToString()); } /* Load ACPI tables */ Acpi acpi = new Acpi(VirtualRegions, VirtMem, fwconf); //tysos.x86_64.Acpi acpi = new tysos.x86_64.Acpi(VirtualRegions, VirtMem, // (bios == Multiboot.MachineMinorType_x86.BIOS) ? bda_va : mboot.virt_bda, // bios); /* Disable the PIC if we have one */ if ((acpi.Apic != null) && (acpi.Apic.Has8259)) { tysos.x86_64.PIC_8295a.Disable(); } /* Set up the local apic for the current processor */ tysos.x86_64.LApic bsp_lapic = new tysos.x86_64.LApic(VirtualRegions, VirtMem); /* Calibrate the lapic */ if (acpi.Hpet == null) { bsp_lapic.CalibrateDirectly(133000000.0); } else { tysos.x86_64.Hpet hpet = new tysos.x86_64.Hpet(VirtualRegions, VirtMem, acpi.Hpet.paddr); bsp_lapic.CalibrateTimerWithHpet(hpet, 1000000); } bsp_lapic.SetSpuriousVector(0x60); unsafe { Interrupts.InstallHandler(0x60, new Interrupts.ISR(tysos.x86_64.LApic.SpuriousApicInterrupt)); } bsp_lapic.SetTimer(true, 100.0, 0x40); // 10 ms timer //bsp_lapic.SetTimer(true, 0x144b50, 0x40); // 10ms timer with 133 Mhz bus and divisor 1, interrupt vector 0x40 unsafe { Interrupts.InstallHandler(0x40, new Interrupts.ISR(tysos.x86_64.LApic.TimerInterrupt)); } SchedulerTimer = bsp_lapic; /* Set up the current cpu */ bsp.CurrentLApic = bsp_lapic; Processors = new List <Cpu>(); Processors.Add(Program.arch.CurrentCpu); /* Set up the task switcher */ Switcher = new tysos.x86_64.TaskSwitcher(); /* Now we have a working heap we can set up the rest of the physical memory */ //SetUpHighMemory(this.PhysMem, mboot); /* Finally, create a list of parameters for handing to the system device enumerator */ if (acpi == null) { throw new Exception("ACPI required"); } ps = new List <tysos.lib.File.Property>(); ps.Add(new tysos.lib.File.Property { Name = "driver", Value = "acpipc" }); foreach (Acpi.AcpiTable table in acpi.tables) { string tab_name = "table_" + table.signature.ToString("X8"); ps.Add(new tysos.lib.File.Property { Name = tab_name, Value = new VirtualMemoryResource64(table.start_vaddr, table.length) }); } ps.Add(new tysos.lib.File.Property { Name = "vmem", Value = new VirtualMemoryResource64(VirtualRegions.devs.start, VirtualRegions.devs.length) }); ps.Add(new tysos.lib.File.Property { Name = "pmem", Value = new PhysicalMemoryResource64(0, UInt64.MaxValue) }); ps.Add(new tysos.lib.File.Property { Name = "io", Value = new x86_64.IOResource(0, 0x10000) }); Formatter.WriteLine("x86_64: Arch initialized", Program.arch.DebugOutput); }