1 // MPTable generation (on emulators)
3 // Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2006 Fabrice Bellard
6 // This file may be distributed under the terms of the GNU GPLv3 license.
8 #include "util.h" // dprintf
9 #include "memmap.h" // bios_table_cur_addr
11 static void putb(u8 **pp, int val)
19 static void putstr(u8 **pp, const char *str)
28 static void putle16(u8 **pp, int val)
37 static void putle32(u8 **pp, int val)
51 u8 *mp_config_table, *q, *float_pointer_struct;
52 int ioapic_id, i, len;
53 int mp_config_table_size;
55 int smp_cpus = smp_probe();
56 if (CONFIG_QEMU && smp_cpus <= 1)
59 bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
60 mp_config_table = (u8 *)bios_table_cur_addr;
62 putstr(&q, "PCMP"); /* "PCMP signature */
63 putle16(&q, 0); /* table length (patched later) */
64 putb(&q, 4); /* spec rev */
65 putb(&q, 0); /* checksum (patched later) */
67 putstr(&q, "QEMUCPU "); /* OEM id */
69 putstr(&q, "BOCHSCPU");
70 putstr(&q, "0.1 "); /* vendor id */
71 putle32(&q, 0); /* OEM table ptr */
72 putle16(&q, 0); /* OEM table size */
73 putle16(&q, smp_cpus + 18); /* entry count */
74 putle32(&q, 0xfee00000); /* local APIC addr */
75 putle16(&q, 0); /* ext table length */
76 putb(&q, 0); /* ext table checksum */
77 putb(&q, 0); /* reserved */
79 for(i = 0; i < smp_cpus; i++) {
80 putb(&q, 0); /* entry type = processor */
81 putb(&q, i); /* APIC id */
82 putb(&q, 0x11); /* local APIC version number */
84 putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
86 putb(&q, 1); /* cpu flags: enabled */
87 putb(&q, 0); /* cpu signature */
91 putle16(&q, 0x201); /* feature flags */
94 putle16(&q, 0); /* reserved */
101 putb(&q, 1); /* entry type = bus */
102 putb(&q, 0); /* bus ID */
106 ioapic_id = smp_cpus;
107 putb(&q, 2); /* entry type = I/O APIC */
108 putb(&q, ioapic_id); /* apic ID */
109 putb(&q, 0x11); /* I/O APIC version number */
110 putb(&q, 1); /* enable */
111 putle32(&q, 0xfec00000); /* I/O APIC addr */
114 for(i = 0; i < 16; i++) {
115 putb(&q, 3); /* entry type = I/O interrupt */
116 putb(&q, 0); /* interrupt type = vectored interrupt */
117 putb(&q, 0); /* flags: po=0, el=0 */
119 putb(&q, 0); /* source bus ID = ISA */
120 putb(&q, i); /* source bus IRQ */
121 putb(&q, ioapic_id); /* dest I/O APIC ID */
122 putb(&q, i); /* dest I/O APIC interrupt in */
125 len = q - mp_config_table;
126 mp_config_table[4] = len;
127 mp_config_table[5] = len >> 8;
129 mp_config_table[7] = -checksum(mp_config_table, q - mp_config_table);
131 mp_config_table_size = q - mp_config_table;
133 bios_table_cur_addr += mp_config_table_size;
135 /* floating pointer structure */
136 bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
137 float_pointer_struct = (u8 *)bios_table_cur_addr;
138 q = float_pointer_struct;
140 /* pointer to MP config table */
141 putle32(&q, (unsigned long)mp_config_table);
143 putb(&q, 1); /* length in 16 byte units */
144 putb(&q, 4); /* MP spec revision */
145 putb(&q, 0); /* checksum (patched later) */
146 putb(&q, 0); /* MP feature byte 1 */
152 float_pointer_struct[10] = -checksum(float_pointer_struct
153 , q - float_pointer_struct);
154 bios_table_cur_addr += (q - float_pointer_struct);
155 dprintf(1, "MP table addr=0x%08lx MPC table addr=0x%08lx size=0x%x\n",
156 (unsigned long)float_pointer_struct,
157 (unsigned long)mp_config_table,
158 mp_config_table_size);