Beispiel #1
0
        internal LApic(Virtual_Regions vreg, VirtMem vmem)
        {
            /* Initialize the local APIC for the current processor */

            /* First, detect support for LAPIC: CPUID EAX=1 sets bit 9 of EDX if present */
            uint[] cpuid_1 = libsupcs.x86_64.Cpu.Cpuid(1);
            if ((cpuid_1[3] & (1 << 9)) != (1 << 9))
            {
                throw new Exception("LAPIC not supported by this processor");
            }

            /* Read the LAPIC base address */
            ulong lapic_base_msr = libsupcs.x86_64.Cpu.RdMsr(IA32_APIC_BASE_MSR);

            /* The base physical address is contained in bits 12 - 35, left shifted by 12 */
            lapic_base_paddr = lapic_base_msr & IA32_APIC_BASE_ADDR_MASK;

            /* Get the lapic id: CPUID EAX=1 sets bits 31-24 of EBX */
            ulong lapic_id = (ulong)(cpuid_1[1] >> 24);

            Formatter.Write("LAPIC: ID: ", Program.arch.DebugOutput);
            Formatter.Write(lapic_id, "X", Program.arch.DebugOutput);
            Formatter.Write(", paddr: ", Program.arch.DebugOutput);
            Formatter.Write(lapic_base_paddr, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            /* Map in the lapic register space
             *
             * Intel 3A:10.4.1:
             * The LAPIC register space is 4 kiB and must be mapped to an area of memory marked as
             * strong uncacheable (UC).
             *
             * Intel 3A:11.5.2.1, table 11-6:
             * Setting PCD and PWT bits on a page table entry ensures UC state regardless of MTRRs             *
             */
            lapic_base_vaddr = vreg.Alloc(0x1000, 0x1000, "LAPIC " + lapic_id.ToString() + " registers");
            vmem.Map(lapic_base_paddr, 0x1000, lapic_base_vaddr, VirtMem.FLAG_writeable | VirtMem.FLAG_cache_disable | VirtMem.FLAG_write_through);

            /* Intel 3A:10.4.7.1:
             *
             * After reset, the LAPIC state is:
             *
             * IRR                              = 0
             * ISR                              = 0
             * TMR                              = 0
             * ICR                              = 0
             * LDR                              = 0
             * TPR                              = 0
             * Timer initial count              = 0
             * Timer current count              = 0
             * Divide configuration register    = 0
             * DFR                              = all 1s
             * LVT                              = all 0s except mask bits which are 1
             * Version reg                      = unaffected
             * LAPIC ID reg                     = unique ID
             * Arb ID reg                       = LAPIC ID
             * Spurious interrupt reg           = 0x000000FF
             */
        }
Beispiel #2
0
 public Acpi(Virtual_Regions vreg, VirtMem vmem, ulong bda_vaddr, Multiboot.MachineMinorType_x86 bios)
 {
     if (bios == Multiboot.MachineMinorType_x86.BIOS)
     {
         InitBIOS(vreg, vmem, bda_vaddr);
     }
     else if (bios == Multiboot.MachineMinorType_x86.UEFI)
     {
         InitUEFI(vreg, vmem, bda_vaddr);
     }
 }
Beispiel #3
0
        public Hpet(Virtual_Regions vreg, VirtMem vmem, ulong paddr)
        {
            Formatter.Write("Initialising HPET at physical address ", Program.arch.DebugOutput);
            Formatter.Write(paddr, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);
            hpet_reg_space_vaddr = Program.map_in(paddr, 0x1000, "HPET", true, true, true);

            /* General capabilities register at offset 0
             *
             * bits 0-7         revision id
             * bits 12-8        one less than number of timers (i.e. id of last timer)
             * bit 13           count size cap.  1 if main counter is 64 bits wide, else 0
             * bit 14           reserved
             * bit 15           legacy replacement route capable
             * bits 16-31       vendor ID (as per PCI)
             * bits 32-63       rate at which main counter increments in femtoseconds (10 ^ -15)
             */
            ulong gen_cap = ReadQwordRegister(0);

            timer_count          = (int)(((gen_cap >> 8) & 0x1f) + 1);
            main_timer_is_64_bit = ((gen_cap & 0x2000) == 0x2000);
            counter_clk_period   = (uint)(gen_cap >> 32);

            Formatter.Write("CounterClkPeriod: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)counter_clk_period, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            double hpet_freq_mhz = Convert.ToDouble((long)counter_clk_period);

            hpet_freq_mhz *= 0.000000001;
            hpet_freq_mhz  = 1 / hpet_freq_mhz;

            Program.arch.DebugOutput.Write("HPET frequency is " + hpet_freq_mhz.ToString() + " Mhz\n");

            DisableMainCounter();
        }
Beispiel #4
0
        public unsafe UEFI(Virtual_Regions vreg, VirtMem vmem, ulong system_table_paddr)
        {
            /* The following assumes a 64-bit platform */
            Formatter.Write("UEFI: system table at paddr: ",
                            Program.arch.DebugOutput);
            Formatter.Write(system_table_paddr, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            /* Load up the system table */
            ulong st_vaddr = Program.map_in(system_table_paddr, UEFIHeaderSize, "UEFI ST Header");
            ulong sig      = *(ulong *)st_vaddr;
            uint  revision = *(uint *)(st_vaddr + 8);
            uint  hdr_size = *(uint *)(st_vaddr + 12);
            uint  crc32    = *(uint *)(st_vaddr + 16);
            uint  reserved = *(uint *)(st_vaddr + 20);

            Formatter.Write("UEFI: system table signature: ", Program.arch.DebugOutput);
            Formatter.Write(sig, "X", Program.arch.DebugOutput);
            Formatter.Write(", revision: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)revision, "X", Program.arch.DebugOutput);
            Formatter.Write(", header size: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)hdr_size, Program.arch.DebugOutput);
            Formatter.Write(", crc32: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)crc32, "X", Program.arch.DebugOutput);
            Formatter.Write(", reserved: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)reserved, Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            if (sig != UEFISystemTableSignature)
            {
                throw new Exception("UEFI system table bad signature: " +
                                    sig.ToString("X16"));
            }

            st_vaddr = Program.map_in(system_table_paddr, hdr_size, "UEFI ST");

            /* Get the configuration table pointer */
            ulong NumberOfTableEntries = *(ulong *)(st_vaddr + 104);
            ulong ConfigurationTable   = *(ulong *)(st_vaddr + 112);

            Formatter.Write("UEFI: NumberOfTableEntries: ", Program.arch.DebugOutput);
            Formatter.Write(NumberOfTableEntries, Program.arch.DebugOutput);
            Formatter.Write(", ConfigurationTable: ", Program.arch.DebugOutput);
            Formatter.Write(ConfigurationTable, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            /* Load the configuration table pointer array.  This is an array of
             * struct {
             *      EFI_GUID            VendorGuid;
             *      VOID *              VendorTable;
             * };
             * located at address ConfigurationTable.
             *
             * NB EFI_GUID is a 128 bit buffer
             */

            ulong cfg_vaddr = Program.map_in(ConfigurationTable, NumberOfTableEntries * 24,
                                             "UEFI CfgTableArray");

            for (ulong i = 0; i < NumberOfTableEntries; i++)
            {
                ulong guid1 = *(ulong *)(cfg_vaddr + i * 24);
                ulong guid2 = *(ulong *)(cfg_vaddr + i * 24 + 8);
                ulong table = *(ulong *)(cfg_vaddr + i * 24 + 16);

                Formatter.Write("UEFI: Table GUID: ", Program.arch.DebugOutput);
                Formatter.Write(guid1, "X", Program.arch.DebugOutput);
                Formatter.Write(guid2, "X", Program.arch.DebugOutput);
                Formatter.Write(", Address: ", Program.arch.DebugOutput);
                Formatter.Write(table, "X", Program.arch.DebugOutput);

                if (guid1 == ACPI10GUID1 && guid2 == ACPI10GUID2)
                {
                    Formatter.Write(" (ACPI_10_TABLE)", Program.arch.DebugOutput);
                    acpi_10_table = (void *)table;
                }
                if (guid1 == ACPI20GUID1 && guid2 == ACPI20GUID2)
                {
                    Formatter.Write(" (ACPI_20_TABLE)", Program.arch.DebugOutput);
                    acpi_20_table = (void *)table;
                }
                if (guid1 == SMBIOSGUID1 && guid2 == SMBIOSGUID2)
                {
                    Formatter.Write(" (SMBIOS_TABLE)", Program.arch.DebugOutput);
                    smbios_table = (void *)table;
                }
                Formatter.WriteLine(Program.arch.DebugOutput);
            }
        }
Beispiel #5
0
        public unsafe Acpi(Virtual_Regions vreg, VirtMem vmem, Arch.FirmwareConfiguration fwconf)
        {
            ulong xsdt = 0;
            uint  rsdt = 0;

            /* Decide which table to use
             *
             * Use XSDT first if available */

            if (fwconf.ACPI_20_table != null)
            {
                ulong va_acpi_20  = Program.map_in((ulong)fwconf.ACPI_20_table, 36, "RSDP");
                uint  acpi_20_len = *(uint *)(va_acpi_20 + 20);
                if (acpi_20_len > 32)
                {
                    xsdt = *(ulong *)(va_acpi_20 + 24);
                }
                if (xsdt == 0)
                {
                    rsdt = *(uint *)(va_acpi_20 + 16);
                }
            }
            else if (fwconf.ACPI_10_table != null)
            {
                ulong va_acpi_10 = Program.map_in((ulong)fwconf.ACPI_10_table, 24, "RSDP");
                rsdt = *(uint *)(va_acpi_10 + 16);
            }

            if (xsdt == 0 && rsdt == 0)
            {
                throw new Exception("ACPI: RSDP not found");
            }

            Formatter.Write("ACPI: RSDT: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)rsdt, "X", Program.arch.DebugOutput);
            Formatter.Write(", XSDT: ", Program.arch.DebugOutput);
            Formatter.Write(xsdt, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            tables = new List <AcpiTable>();

            if (xsdt != 0)
            {
                /* Use XSDT */
                ulong xsdt_va = Program.map_in(xsdt, 36, "XSDT header");
                uint  len     = *(uint *)(xsdt_va + 4);
                xsdt_va = Program.map_in(xsdt, len, "XSDT");

                uint entries = (len - 36) / 8;
                for (uint i = 0; i < entries; i++)
                {
                    ulong tbl_address = *(ulong *)(xsdt_va + 36 + i * 8);
                    Formatter.Write("ACPI: XSDT entry: ", Program.arch.DebugOutput);
                    Formatter.Write(tbl_address, "X", Program.arch.DebugOutput);
                    Formatter.WriteLine(Program.arch.DebugOutput);
                    InterpretTable(tbl_address);
                }
            }
            else if (rsdt != 0)
            {
                /* Use RSDT */
                ulong rsdt_va = Program.map_in(rsdt, 36, "RSDT header");
                uint  len     = *(uint *)(rsdt_va + 4);
                rsdt_va = Program.map_in(rsdt, len, "RSDT");

                uint entries = (len - 36) / 4;
                for (uint i = 0; i < entries; i++)
                {
                    uint tbl_address = *(uint *)(rsdt_va + 36 + i * 4);
                    Formatter.Write("ACPI: RSDT entry: ", Program.arch.DebugOutput);
                    Formatter.Write((ulong)tbl_address, "X", Program.arch.DebugOutput);
                    Formatter.WriteLine(Program.arch.DebugOutput);
                    InterpretTable(tbl_address);
                }
            }
        }
Beispiel #6
0
        unsafe void InitBIOS(Virtual_Regions vreg, VirtMem vmem, ulong bda_vaddr)
        {
            /* To set up ACPI, we first need to find the Root System Description Pointer (RDSP)
             * This is a data structure that is in one of two places:
             *
             * 1) The extended bios data area, this is pointed to by the word at physical address 0x040e,
             *      left shifted by 4)
             * 2) The memory from 0xe0000 to 0xfffff
             *
             * The RDSP is 16-byte aligned and starts with the string value "RSD PTR "
             * this is equal to 0x2052545020445352
             */

            ulong ebda_paddr  = ((ulong)*(ushort *)(bda_vaddr + 0x40e)) << 4;
            ulong ebda_length = 0xa0000 - ebda_paddr;

            Formatter.Write("EBDA found at: ", Program.arch.DebugOutput);
            Formatter.Write(ebda_paddr, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            /* map in the EBDA */
            ulong ebda_vaddr = Program.map_in(ebda_paddr, ebda_length, "EBDA");


            rdsp_vaddr = 0;
            ulong cur_addr = ebda_vaddr;

            while (cur_addr < (ebda_vaddr + ebda_length))
            {
                if (*(ulong *)cur_addr == 0x2052545020445352UL)
                {
                    if (verify_rdsp(cur_addr))
                    {
                        rdsp_vaddr = cur_addr;
                        break;
                    }
                }
                cur_addr += 16;
            }

            if (rdsp_vaddr == 0)
            {
                /* we didn't find the RDSP in the EDBA, therefore search the range 0xe0000 to 0xfffff */
                ulong search_base_vaddr = Program.map_in(0xe0000, 0x20000, "RDSP Search");
                cur_addr = search_base_vaddr;
                while (cur_addr < (search_base_vaddr + 0x20000))
                {
                    if (*(ulong *)cur_addr == 0x2052545020445352UL)
                    {
                        if (verify_rdsp(cur_addr))
                        {
                            rdsp_vaddr = cur_addr;
                            break;
                        }
                    }
                    cur_addr += 16;
                }
            }

            if (rdsp_vaddr == 0)
            {
                throw new Exception("RDSP not found");
            }


            /* We have found the RDSP, now interpret it */
            RDSPDescriptor *rdsp       = (RDSPDescriptor *)rdsp_vaddr;
            ulong           revision   = rdsp->checksum_oemid_revision >> 56;
            bool            use_xsdt   = false;
            ulong           sdt_paddr  = 0;
            ulong           sdt_length = 0;

            if (revision == 0)
            {
                sdt_paddr  = (ulong)rdsp->RSDT_paddr;
                sdt_length = 36;
            }
            else
            {
                use_xsdt   = true;
                sdt_paddr  = rdsp->XSDT_paddr;
                sdt_length = (ulong)rdsp->length;
            }

            if (use_xsdt)
            {
                Formatter.Write("XSDT at ", Program.arch.DebugOutput);
            }
            else
            {
                Formatter.Write("RDST at ", Program.arch.DebugOutput);
            }
            Formatter.Write(sdt_paddr, "X", Program.arch.DebugOutput);
            Formatter.Write(" length: ", Program.arch.DebugOutput);
            Formatter.Write(sdt_length, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            /* Map in the xsdt */
            string tab_name = "RSDT";

            if (use_xsdt)
            {
                tab_name = "XSDT";
            }
            ulong xsdt_vaddr = Program.map_in(sdt_paddr, sdt_length, tab_name);
            XSDT *xsdt       = (XSDT *)xsdt_vaddr;

            if (use_xsdt)
            {
                Formatter.Write("XSDT signature: ", Program.arch.DebugOutput);
            }
            else
            {
                Formatter.Write("RSDT signature: ", Program.arch.DebugOutput);
            }
            Formatter.Write((ulong)xsdt->signature, "X", Program.arch.DebugOutput);
            Formatter.Write(" length: ", Program.arch.DebugOutput);
            Formatter.Write((ulong)xsdt->length, "X", Program.arch.DebugOutput);
            Formatter.WriteLine(Program.arch.DebugOutput);

            /* Now remap it based on its new length */
            xsdt_vaddr = Program.map_in(sdt_paddr, xsdt->length, tab_name);

            /* Read in the various tables */
            tables = new List <AcpiTable>();
            ulong table_pointer = xsdt_vaddr + 36;

            while (table_pointer < (xsdt_vaddr + xsdt->length))
            {
                if (use_xsdt)
                {
                    InterpretTable(*(ulong *)table_pointer);
                    table_pointer += 8;
                }
                else
                {
                    InterpretTable((ulong)*(uint *)table_pointer);
                    table_pointer += 4;
                }
            }
        }
Beispiel #7
0
 unsafe void InitUEFI(Virtual_Regions vreg, VirtMem vmem, ulong system_table_paddr)
 {
     System.Diagnostics.Debugger.Break();
 }
Beispiel #8
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);
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
 public unsafe BIOS(Virtual_Regions vreg, VirtMem vmem, ulong system_table_paddr)
 {
     acpi_table = (void *)system_table_paddr;
 }