|
|
1.1 root 1: add SRAT ACPI table support (Andre Przywara)
2:
3: Take NUMA topology info from the QEMU firmware configuration interface
4: (number of nodes, node for each (V)CPU and amount of memory) and build
5: a SRAT table describing this topology for the guest OS. Handles more than
6: 4 GB of RAM by including a hole for 32bit PCI memory mapping.
7:
8: Signed-off-by: Andre Przywara <[email protected]>
9: Signed-off-by: Anthony Liguori <[email protected]>
10:
11: diff --git a/bios/rombios32.c b/bios/rombios32.c
12: index 49dfd62..d8f6d4e 100644
13: --- a/bios/rombios32.c
14: +++ b/bios/rombios32.c
15: @@ -450,6 +450,11 @@ int pm_sci_int;
16: unsigned long bios_table_cur_addr;
17: unsigned long bios_table_end_addr;
18:
19: +static inline uint64_t le64_to_cpu(uint64_t x)
20: +{
21: + return x;
22: +}
23: +
24: void wrmsr_smp(uint32_t index, uint64_t val)
25: {
26: static struct { uint32_t ecx, eax, edx; } *p = (void *)SMP_MSR_ADDR;
27: @@ -468,6 +473,7 @@ void wrmsr_smp(uint32_t index, uint64_t val)
28: #define QEMU_CFG_SIGNATURE 0x00
29: #define QEMU_CFG_ID 0x01
30: #define QEMU_CFG_UUID 0x02
31: +#define QEMU_CFG_NUMA 0x0D
32: #define QEMU_CFG_ARCH_LOCAL 0x8000
33: #define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
34: #define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
35: @@ -529,6 +535,14 @@ static uint16_t smbios_entries(void)
36:
37: return cnt;
38: }
39: +
40: +uint64_t qemu_cfg_get64 (void)
41: +{
42: + uint64_t ret;
43: +
44: + qemu_cfg_read((uint8_t*)&ret, 8);
45: + return le64_to_cpu(ret);
46: +}
47: #endif
48:
49: void cpu_probe(void)
50: @@ -1281,7 +1295,7 @@ struct rsdt_descriptor_rev1
51: {
52: ACPI_TABLE_HEADER_DEF /* ACPI common table header */
53: #ifdef BX_QEMU
54: - uint32_t table_offset_entry [4]; /* Array of pointers to other */
55: + uint32_t table_offset_entry [5]; /* Array of pointers to other */
56: #else
57: uint32_t table_offset_entry [3]; /* Array of pointers to other */
58: #endif
59: @@ -1389,7 +1403,7 @@ struct multiple_apic_table
60: } __attribute__((__packed__));
61:
62:
63: -/* Values for Type in APIC_HEADER_DEF */
64: +/* Values for Type in APIC sub-headers */
65:
66: #define APIC_PROCESSOR 0
67: #define APIC_IO 1
68: @@ -1402,18 +1416,18 @@ struct multiple_apic_table
69: #define APIC_XRUPT_SOURCE 8
70: #define APIC_RESERVED 9 /* 9 and greater are reserved */
71:
72: -/*
73: - * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
74: - */
75: -#define APIC_HEADER_DEF /* Common APIC sub-structure header */\
76: +#define ACPI_SUB_HEADER_DEF /* Common ACPI sub-structure header */\
77: uint8_t type; \
78: uint8_t length;
79:
80: +/*
81: + * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
82: + */
83: /* Sub-structures for MADT */
84:
85: struct madt_processor_apic
86: {
87: - APIC_HEADER_DEF
88: + ACPI_SUB_HEADER_DEF
89: uint8_t processor_id; /* ACPI processor id */
90: uint8_t local_apic_id; /* Processor's local APIC id */
91: #if 0
92: @@ -1424,6 +1438,43 @@ struct madt_processor_apic
93: #endif
94: } __attribute__((__packed__));
95:
96: +/*
97: + * SRAT (NUMA topology description) table
98: + */
99: +
100: +#define SRAT_PROCESSOR 0
101: +#define SRAT_MEMORY 1
102: +
103: +struct system_resource_affinity_table
104: +{
105: + ACPI_TABLE_HEADER_DEF
106: + uint32_t reserved1;
107: + uint32_t reserved2[2];
108: +};
109: +
110: +struct srat_processor_affinity
111: +{
112: + ACPI_SUB_HEADER_DEF
113: + uint8_t proximity_lo;
114: + uint8_t local_apic_id;
115: + uint32_t flags;
116: + uint8_t local_sapic_eid;
117: + uint8_t proximity_hi[3];
118: + uint32_t reserved;
119: +};
120: +
121: +struct srat_memory_affinity
122: +{
123: + ACPI_SUB_HEADER_DEF
124: + uint8_t proximity[4];
125: + uint16_t reserved1;
126: + uint32_t base_addr_low,base_addr_high;
127: + uint32_t length_low,length_high;
128: + uint32_t reserved2;
129: + uint32_t flags;
130: + uint32_t reserved3[2];
131: +};
132: +
133: #ifdef BX_QEMU
134: /*
135: * * ACPI 2.0 Generic Address Space definition.
136: @@ -1452,7 +1503,7 @@ struct acpi_20_hpet {
137:
138: struct madt_io_apic
139: {
140: - APIC_HEADER_DEF
141: + ACPI_SUB_HEADER_DEF
142: uint8_t io_apic_id; /* I/O APIC ID */
143: uint8_t reserved; /* Reserved - must be zero */
144: uint32_t address; /* APIC physical address */
145: @@ -1463,7 +1514,7 @@ struct madt_io_apic
146: #ifdef BX_QEMU
147: struct madt_int_override
148: {
149: - APIC_HEADER_DEF
150: + ACPI_SUB_HEADER_DEF
151: uint8_t bus; /* Identifies ISA Bus */
152: uint8_t source; /* Bus-relative interrupt source */
153: uint32_t gsi; /* GSI that source will signal */
154: @@ -1567,6 +1618,21 @@ int acpi_build_processor_ssdt(uint8_t *ssdt)
155: return ssdt_ptr - ssdt;
156: }
157:
158: +static void acpi_build_srat_memory(struct srat_memory_affinity *numamem,
159: + uint64_t base, uint64_t len, int node, int enabled)
160: +{
161: + numamem->type = SRAT_MEMORY;
162: + numamem->length = sizeof(*numamem);
163: + memset (numamem->proximity, 0 ,4);
164: + numamem->proximity[0] = node;
165: + numamem->flags = cpu_to_le32(!!enabled);
166: + numamem->base_addr_low = base & 0xFFFFFFFF;
167: + numamem->base_addr_high = base >> 32;
168: + numamem->length_low = len & 0xFFFFFFFF;
169: + numamem->length_high = len >> 32;
170: + return;
171: +}
172: +
173: /* base_addr must be a multiple of 4KB */
174: void acpi_bios_init(void)
175: {
176: @@ -1577,12 +1643,15 @@ void acpi_bios_init(void)
177: struct multiple_apic_table *madt;
178: uint8_t *dsdt, *ssdt;
179: #ifdef BX_QEMU
180: + struct system_resource_affinity_table *srat;
181: struct acpi_20_hpet *hpet;
182: uint32_t hpet_addr;
183: #endif
184: uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr;
185: uint32_t acpi_tables_size, madt_addr, madt_size, rsdt_size;
186: + uint32_t srat_addr,srat_size;
187: uint16_t i, external_tables;
188: + int nb_numa_nodes;
189:
190: /* reserve memory space for tables */
191: #ifdef BX_USE_EBDA_TABLES
192: @@ -1624,6 +1693,25 @@ void acpi_bios_init(void)
193: ssdt_addr = addr;
194: ssdt = (void *)(addr);
195: addr += acpi_build_processor_ssdt(ssdt);
196: +#ifdef BX_QEMU
197: + qemu_cfg_select(QEMU_CFG_NUMA);
198: + nb_numa_nodes = qemu_cfg_get64();
199: +#else
200: + nb_numa_nodes = 0;
201: +#endif
202: + if (nb_numa_nodes > 0) {
203: + addr = (addr + 7) & ~7;
204: + srat_addr = addr;
205: + srat_size = sizeof(*srat) +
206: + sizeof(struct srat_processor_affinity) * smp_cpus +
207: + sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
208: + srat = (void *)(addr);
209: + addr += srat_size;
210: + } else {
211: + srat_addr = addr;
212: + srat = (void*)(addr);
213: + srat_size = 0;
214: + }
215:
216: addr = (addr + 7) & ~7;
217: madt_addr = addr;
218: @@ -1733,6 +1821,69 @@ void acpi_bios_init(void)
219:
220: memset(rsdt, 0, rsdt_size);
221: #ifdef BX_QEMU
222: + /* SRAT */
223: + if (nb_numa_nodes > 0) {
224: + struct srat_processor_affinity *core;
225: + struct srat_memory_affinity *numamem;
226: + int slots;
227: + uint64_t mem_len, mem_base, next_base = 0, curnode;
228: +
229: + qemu_cfg_select(QEMU_CFG_NUMA);
230: + qemu_cfg_get64();
231: + memset (srat, 0 , srat_size);
232: + srat->reserved1=1;
233: +
234: + core = (void*)(srat + 1);
235: + for (i = 0; i < smp_cpus; ++i) {
236: + core->type = SRAT_PROCESSOR;
237: + core->length = sizeof(*core);
238: + core->local_apic_id = i;
239: + curnode = qemu_cfg_get64();
240: + core->proximity_lo = curnode;
241: + memset (core->proximity_hi, 0, 3);
242: + core->local_sapic_eid = 0;
243: + if (i < smp_cpus)
244: + core->flags = cpu_to_le32(1);
245: + else
246: + core->flags = 0;
247: + core++;
248: + }
249: +
250: + /* the memory map is a bit tricky, it contains at least one hole
251: + * from 640k-1M and possibly another one from 3.5G-4G.
252: + */
253: + numamem = (void*)core; slots = 0;
254: + acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
255: + next_base = 1024 * 1024; numamem++;slots++;
256: + for (i = 1; i < nb_numa_nodes + 1; ++i) {
257: + mem_base = next_base;
258: + mem_len = qemu_cfg_get64();
259: + if (i == 1) mem_len -= 1024 * 1024;
260: + next_base = mem_base + mem_len;
261: +
262: + /* Cut out the PCI hole */
263: + if (mem_base <= ram_size && next_base > ram_size) {
264: + mem_len -= next_base - ram_size;
265: + if (mem_len > 0) {
266: + acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
267: + numamem++; slots++;
268: + }
269: + mem_base = 1ULL << 32;
270: + mem_len = next_base - ram_size;
271: + next_base += (1ULL << 32) - ram_size;
272: + }
273: + acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
274: + numamem++; slots++;
275: + }
276: + for (; slots < nb_numa_nodes + 2; slots++) {
277: + acpi_build_srat_memory(numamem, 0, 0, 0, 0);
278: + numamem++;
279: + }
280: +
281: + acpi_build_table_header((struct acpi_table_header *)srat,
282: + "SRAT", srat_size, 1);
283: + }
284: +
285: /* HPET */
286: memset(hpet, 0, sizeof(*hpet));
287: /* Note timer_block_id value must be kept in sync with value advertised by
288: @@ -1761,9 +1912,11 @@ void acpi_bios_init(void)
289: rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr);
290: #ifdef BX_QEMU
291: rsdt->table_offset_entry[3] = cpu_to_le32(hpet_addr);
292: + if (nb_numa_nodes > 0)
293: + rsdt->table_offset_entry[4] = cpu_to_le32(srat_addr);
294: #endif
295: - acpi_build_table_header((struct acpi_table_header *)rsdt,
296: - "RSDT", rsdt_size, 1);
297: + acpi_build_table_header((struct acpi_table_header *)rsdt, "RSDT",
298: + rsdt_size - (nb_numa_nodes > 0? 0: sizeof(uint32_t)), 1);
299:
300: acpi_tables_size = addr - base_addr;
301:
302: --
303: 1.6.1.3
304:
305:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.