示例#1
0
        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;
        }
示例#2
0
        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;
            }
        }
示例#3
0
        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];
                }
            }
        }
示例#4
0
文件: Arch.cs 项目: jncronin/tysos
        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);
        }