blob: 49a88e44c10cb11504df088f046e167ba9a8da98 [file] [log] [blame]
Kevin O'Connor84ad59a2008-07-04 05:47:26 -04001// 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
Kevin O'Connor9521e262008-07-04 13:04:29 -040010#include "config.h" // CONFIG_*
Kevin O'Connor84ad59a2008-07-04 05:47:26 -040011
12static void putb(u8 **pp, int val)
13{
14 u8 *q;
15 q = *pp;
16 *q++ = val;
17 *pp = q;
18}
19
20static void putstr(u8 **pp, const char *str)
21{
22 u8 *q;
23 q = *pp;
24 while (*str)
25 *q++ = *str++;
26 *pp = q;
27}
28
29static void putle16(u8 **pp, int val)
30{
31 u8 *q;
32 q = *pp;
33 *q++ = val;
34 *q++ = val >> 8;
35 *pp = q;
36}
37
38static void putle32(u8 **pp, int val)
39{
40 u8 *q;
41 q = *pp;
42 *q++ = val;
43 *q++ = val >> 8;
44 *q++ = val >> 16;
45 *q++ = val >> 24;
46 *pp = q;
47}
48
49void
50mptable_init(void)
51{
Kevin O'Connord3817022008-07-12 12:46:07 -040052 if (! CONFIG_MPTABLE)
53 return;
54
Kevin O'Connor7b49cd92008-11-08 10:35:26 -050055 dprintf(3, "init MPTable\n");
56
Kevin O'Connor84ad59a2008-07-04 05:47:26 -040057 u8 *mp_config_table, *q, *float_pointer_struct;
58 int ioapic_id, i, len;
59 int mp_config_table_size;
60
61 int smp_cpus = smp_probe();
Kevin O'Connor6cb8ba92008-08-17 11:03:24 -040062 if (smp_cpus <= 1)
63 // Building an mptable on uniprocessor machines confuses some OSes.
Kevin O'Connor84ad59a2008-07-04 05:47:26 -040064 return;
65
66 bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
67 mp_config_table = (u8 *)bios_table_cur_addr;
68 q = mp_config_table;
69 putstr(&q, "PCMP"); /* "PCMP signature */
70 putle16(&q, 0); /* table length (patched later) */
71 putb(&q, 4); /* spec rev */
72 putb(&q, 0); /* checksum (patched later) */
Kevin O'Connor6cb8ba92008-08-17 11:03:24 -040073 putstr(&q, CONFIG_CPUNAME8); /* OEM id */
Kevin O'Connor84ad59a2008-07-04 05:47:26 -040074 putstr(&q, "0.1 "); /* vendor id */
75 putle32(&q, 0); /* OEM table ptr */
76 putle16(&q, 0); /* OEM table size */
77 putle16(&q, smp_cpus + 18); /* entry count */
78 putle32(&q, 0xfee00000); /* local APIC addr */
79 putle16(&q, 0); /* ext table length */
80 putb(&q, 0); /* ext table checksum */
81 putb(&q, 0); /* reserved */
82
83 for(i = 0; i < smp_cpus; i++) {
84 putb(&q, 0); /* entry type = processor */
85 putb(&q, i); /* APIC id */
86 putb(&q, 0x11); /* local APIC version number */
87 if (i == 0)
88 putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
89 else
90 putb(&q, 1); /* cpu flags: enabled */
91 putb(&q, 0); /* cpu signature */
92 putb(&q, 6);
93 putb(&q, 0);
94 putb(&q, 0);
95 putle16(&q, 0x201); /* feature flags */
96 putle16(&q, 0);
97
98 putle16(&q, 0); /* reserved */
99 putle16(&q, 0);
100 putle16(&q, 0);
101 putle16(&q, 0);
102 }
103
104 /* isa bus */
105 putb(&q, 1); /* entry type = bus */
106 putb(&q, 0); /* bus ID */
107 putstr(&q, "ISA ");
108
109 /* ioapic */
110 ioapic_id = smp_cpus;
111 putb(&q, 2); /* entry type = I/O APIC */
112 putb(&q, ioapic_id); /* apic ID */
113 putb(&q, 0x11); /* I/O APIC version number */
114 putb(&q, 1); /* enable */
115 putle32(&q, 0xfec00000); /* I/O APIC addr */
116
117 /* irqs */
118 for(i = 0; i < 16; i++) {
119 putb(&q, 3); /* entry type = I/O interrupt */
120 putb(&q, 0); /* interrupt type = vectored interrupt */
121 putb(&q, 0); /* flags: po=0, el=0 */
122 putb(&q, 0);
123 putb(&q, 0); /* source bus ID = ISA */
124 putb(&q, i); /* source bus IRQ */
125 putb(&q, ioapic_id); /* dest I/O APIC ID */
126 putb(&q, i); /* dest I/O APIC interrupt in */
127 }
128 /* patch length */
129 len = q - mp_config_table;
130 mp_config_table[4] = len;
131 mp_config_table[5] = len >> 8;
132
133 mp_config_table[7] = -checksum(mp_config_table, q - mp_config_table);
134
135 mp_config_table_size = q - mp_config_table;
136
137 bios_table_cur_addr += mp_config_table_size;
138
139 /* floating pointer structure */
140 bios_table_cur_addr = ALIGN(bios_table_cur_addr, 16);
141 float_pointer_struct = (u8 *)bios_table_cur_addr;
142 q = float_pointer_struct;
143 putstr(&q, "_MP_");
144 /* pointer to MP config table */
145 putle32(&q, (unsigned long)mp_config_table);
146
147 putb(&q, 1); /* length in 16 byte units */
148 putb(&q, 4); /* MP spec revision */
149 putb(&q, 0); /* checksum (patched later) */
150 putb(&q, 0); /* MP feature byte 1 */
151
152 putb(&q, 0);
153 putb(&q, 0);
154 putb(&q, 0);
155 putb(&q, 0);
156 float_pointer_struct[10] = -checksum(float_pointer_struct
157 , q - float_pointer_struct);
158 bios_table_cur_addr += (q - float_pointer_struct);
159 dprintf(1, "MP table addr=0x%08lx MPC table addr=0x%08lx size=0x%x\n",
160 (unsigned long)float_pointer_struct,
161 (unsigned long)mp_config_table,
162 mp_config_table_size);
163}