Separate out smp detection and mp table generation from rombios32.c
[seabios.git] / src / mptable.c
1 // MPTable generation (on emulators)
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2006 Fabrice Bellard
5 //
6 // This file may be distributed under the terms of the GNU GPLv3 license.
7
8 #include "util.h" // dprintf
9 #include "memmap.h" // bios_table_cur_addr
10
11 static void putb(u8 **pp, int val)
12 {
13     u8 *q;
14     q = *pp;
15     *q++ = val;
16     *pp = q;
17 }
18
19 static void putstr(u8 **pp, const char *str)
20 {
21     u8 *q;
22     q = *pp;
23     while (*str)
24         *q++ = *str++;
25     *pp = q;
26 }
27
28 static void putle16(u8 **pp, int val)
29 {
30     u8 *q;
31     q = *pp;
32     *q++ = val;
33     *q++ = val >> 8;
34     *pp = q;
35 }
36
37 static void putle32(u8 **pp, int val)
38 {
39     u8 *q;
40     q = *pp;
41     *q++ = val;
42     *q++ = val >> 8;
43     *q++ = val >> 16;
44     *q++ = val >> 24;
45     *pp = q;
46 }
47
48 void
49 mptable_init(void)
50 {
51     u8 *mp_config_table, *q, *float_pointer_struct;
52     int ioapic_id, i, len;
53     int mp_config_table_size;
54
55     int smp_cpus = smp_probe();
56     if (CONFIG_QEMU && smp_cpus <= 1)
57         return;
58
59     bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
60     mp_config_table = (u8 *)bios_table_cur_addr;
61     q = mp_config_table;
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) */
66     if (CONFIG_QEMU)
67         putstr(&q, "QEMUCPU "); /* OEM id */
68     else
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 */
78
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 */
83         if (i == 0)
84             putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
85         else
86             putb(&q, 1); /* cpu flags: enabled */
87         putb(&q, 0); /* cpu signature */
88         putb(&q, 6);
89         putb(&q, 0);
90         putb(&q, 0);
91         putle16(&q, 0x201); /* feature flags */
92         putle16(&q, 0);
93
94         putle16(&q, 0); /* reserved */
95         putle16(&q, 0);
96         putle16(&q, 0);
97         putle16(&q, 0);
98     }
99
100     /* isa bus */
101     putb(&q, 1); /* entry type = bus */
102     putb(&q, 0); /* bus ID */
103     putstr(&q, "ISA   ");
104
105     /* ioapic */
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 */
112
113     /* irqs */
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 */
118         putb(&q, 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 */
123     }
124     /* patch length */
125     len = q - mp_config_table;
126     mp_config_table[4] = len;
127     mp_config_table[5] = len >> 8;
128
129     mp_config_table[7] = -checksum(mp_config_table, q - mp_config_table);
130
131     mp_config_table_size = q - mp_config_table;
132
133     bios_table_cur_addr += mp_config_table_size;
134
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;
139     putstr(&q, "_MP_");
140     /* pointer to MP config table */
141     putle32(&q, (unsigned long)mp_config_table);
142
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 */
147
148     putb(&q, 0);
149     putb(&q, 0);
150     putb(&q, 0);
151     putb(&q, 0);
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);
159 }