Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 1 | // MPTable generation (on emulators) |
| 2 | // |
| 3 | // Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> |
| 4 | // Copyright (C) 2006 Fabrice Bellard |
| 5 | // |
Kevin O'Connor | b1b7c2a | 2009-01-15 20:52:58 -0500 | [diff] [blame] | 6 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 7 | |
| 8 | #include "util.h" // dprintf |
| 9 | #include "memmap.h" // bios_table_cur_addr |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 10 | #include "config.h" // CONFIG_* |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 11 | #include "mptable.h" // MPTABLE_SIGNATURE |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 12 | |
| 13 | void |
| 14 | mptable_init(void) |
| 15 | { |
Kevin O'Connor | d381702 | 2008-07-12 12:46:07 -0400 | [diff] [blame] | 16 | if (! CONFIG_MPTABLE) |
| 17 | return; |
| 18 | |
Kevin O'Connor | 7b49cd9 | 2008-11-08 10:35:26 -0500 | [diff] [blame] | 19 | dprintf(3, "init MPTable\n"); |
| 20 | |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 21 | int smp_cpus = smp_probe(); |
Kevin O'Connor | 6cb8ba9 | 2008-08-17 11:03:24 -0400 | [diff] [blame] | 22 | if (smp_cpus <= 1) |
| 23 | // Building an mptable on uniprocessor machines confuses some OSes. |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 24 | return; |
| 25 | |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 26 | u32 start = ALIGN(bios_table_cur_addr, 16); |
| 27 | int length = (sizeof(struct mptable_floating_s) |
| 28 | + sizeof(struct mptable_config_s) |
| 29 | + sizeof(struct mpt_cpu) * smp_cpus |
| 30 | + sizeof(struct mpt_bus) |
| 31 | + sizeof(struct mpt_ioapic) |
| 32 | + sizeof(struct mpt_intsrc) * 16); |
| 33 | if (start + length > bios_table_end_addr) { |
| 34 | dprintf(1, "No room for MPTABLE!\n"); |
| 35 | return; |
| 36 | } |
Kevin O'Connor | a69a559 | 2009-02-28 11:46:40 -0500 | [diff] [blame] | 37 | bios_table_cur_addr = start + length; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 38 | |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 39 | /* floating pointer structure */ |
| 40 | struct mptable_floating_s *floating = (void*)start; |
| 41 | memset(floating, 0, sizeof(*floating)); |
| 42 | struct mptable_config_s *config = (void*)&floating[1]; |
| 43 | floating->signature = MPTABLE_SIGNATURE; |
| 44 | floating->physaddr = (u32)config; |
| 45 | floating->length = 1; |
| 46 | floating->spec_rev = 4; |
| 47 | floating->checksum = -checksum(floating, sizeof(*floating)); |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 48 | |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 49 | // Config structure. |
| 50 | memset(config, 0, sizeof(*config)); |
| 51 | config->signature = MPCONFIG_SIGNATURE; |
| 52 | config->length = length - sizeof(*floating); |
| 53 | config->spec = 4; |
| 54 | memcpy(config->oemid, CONFIG_CPUNAME8, sizeof(config->oemid)); |
| 55 | memcpy(config->productid, "0.1 ", sizeof(config->productid)); |
| 56 | config->entrycount = smp_cpus + 2 + 16; |
| 57 | config->lapic = BUILD_APIC_ADDR; |
| 58 | |
| 59 | // CPU definitions. |
| 60 | struct mpt_cpu *cpus = (void*)&config[1]; |
| 61 | int i; |
| 62 | for (i = 0; i < smp_cpus; i++) { |
| 63 | struct mpt_cpu *cpu = &cpus[i]; |
| 64 | memset(cpu, 0, sizeof(*cpu)); |
| 65 | cpu->type = MPT_TYPE_CPU; |
| 66 | cpu->apicid = i; |
| 67 | cpu->apicver = 0x11; |
| 68 | /* cpu flags: enabled, bootstrap cpu */ |
| 69 | cpu->cpuflag = (i == 0 ? 3 : 1); |
| 70 | cpu->cpufeature = 0x600; |
| 71 | cpu->featureflag = 0x201; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | /* isa bus */ |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 75 | struct mpt_bus *bus = (void*)&cpus[smp_cpus]; |
| 76 | memset(bus, 0, sizeof(*bus)); |
| 77 | bus->type = MPT_TYPE_BUS; |
| 78 | memcpy(bus->bustype, "ISA ", sizeof(bus->bustype)); |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 79 | |
| 80 | /* ioapic */ |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 81 | u8 ioapic_id = smp_cpus; |
| 82 | struct mpt_ioapic *ioapic = (void*)&bus[1]; |
| 83 | memset(ioapic, 0, sizeof(*ioapic)); |
| 84 | ioapic->type = MPT_TYPE_IOAPIC; |
| 85 | ioapic->apicid = ioapic_id; |
| 86 | ioapic->apicver = 0x11; |
| 87 | ioapic->flags = 1; // enable |
| 88 | ioapic->apicaddr = BUILD_IOAPIC_ADDR; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 89 | |
| 90 | /* irqs */ |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 91 | struct mpt_intsrc *intsrcs = (void *)&ioapic[1]; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 92 | for(i = 0; i < 16; i++) { |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 93 | struct mpt_intsrc *isrc = &intsrcs[i]; |
| 94 | memset(isrc, 0, sizeof(*isrc)); |
| 95 | isrc->type = MPT_TYPE_INTSRC; |
| 96 | isrc->srcbusirq = i; |
| 97 | isrc->dstapic = ioapic_id; |
| 98 | isrc->dstirq = i; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 99 | } |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 100 | |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 101 | // Set checksum. |
| 102 | config->checksum = -checksum(config, config->length); |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 103 | |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 104 | dprintf(1, "MP table addr=0x%x MPC table addr=0x%x size=0x%x\n", |
| 105 | (u32)floating, (u32)config, length); |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 106 | } |