1#include <acpi/acpi.h>
2#include <asm.h>
3#include <console/panic.h>
4#include <console/printf.h>
5#include <global.h>
6#include <log.h>
7#include <math/sort.h>
8#include <mem/alloc.h>
9#include <mem/nofail.h>
10#include <mem/numa.h>
11#include <mem/vmm.h>
12#include <smp/core.h>
13#include <stdint.h>
14#include <string.h>
15#include <uacpi/tables.h>
16
17#include "uacpi/acpi.h"
18#include "uacpi/status.h"
19
20LOG_HANDLE_DEFINE_PRINT_STATIC(srat);
21
22void srat_init(void) {
23 struct uacpi_table srat_table;
24 if (uacpi_table_find_by_signature(signature: "SRAT", out_table: &srat_table) != UACPI_STATUS_OK) {
25 log_warn_global(LOG_HANDLE(srat),
26 "SRAT table not found, assuming single NUMA node");
27
28 global.numa_nodes = nofail_vnew(global.numa_nodes, ALLOC_ZERO);
29
30 global.numa_nodes[0].topo = NULL;
31 global.numa_nodes[0].mem_base = 0;
32 global.numa_nodes[0].mem_size = 0;
33 global.numa_nodes[0].distances_cnt = 0;
34 global.numa_nodes[0].distance = NULL;
35 return;
36 }
37
38 struct acpi_srat *srat = (struct acpi_srat *) srat_table.ptr;
39 uint8_t *ptr = (uint8_t *) srat + sizeof(struct acpi_srat);
40 uint64_t remaining = srat->hdr.length - sizeof(struct acpi_srat);
41
42 uint64_t max_prox_domain = 0;
43
44 while (remaining >= sizeof(struct acpi_entry_hdr)) {
45 struct acpi_entry_hdr *entry = (void *) ptr;
46 if (entry->type == ACPI_SRAT_ENTRY_TYPE_PROCESSOR_AFFINITY) {
47 struct acpi_srat_processor_affinity *cpu = (void *) ptr;
48 if (cpu->flags & 1) {
49 uint64_t prox_domain =
50 (uint64_t) cpu->proximity_domain_low |
51 (uint64_t) cpu->proximity_domain_high[0] << 8 |
52 (uint64_t) cpu->proximity_domain_high[1] << 16 |
53 (uint64_t) cpu->proximity_domain_high[2] << 24;
54
55 if (prox_domain > max_prox_domain)
56 max_prox_domain = prox_domain;
57 }
58 } else if (entry->type == ACPI_SRAT_ENTRY_TYPE_MEMORY_AFFINITY) {
59 struct acpi_srat_memory_affinity *mem = (void *) ptr;
60 if (mem->flags & 1 && mem->proximity_domain > max_prox_domain)
61 max_prox_domain = mem->proximity_domain;
62 }
63
64 ptr += entry->length;
65 remaining -= entry->length;
66 }
67
68 global.numa_node_count = max_prox_domain + 1;
69 size_t numa_node_count = global.numa_node_count;
70 global.numa_nodes =
71 nofail_vnews(global.numa_nodes, numa_node_count, ALLOC_ZERO);
72
73 for (size_t i = 0; i < numa_node_count; i++) {
74 global.numa_nodes[i].topo = NULL;
75 global.numa_nodes[i].mem_base = 0;
76 global.numa_nodes[i].mem_size = 0;
77 global.numa_nodes[i].distances_cnt = numa_node_count;
78 global.numa_nodes[i].distance = nofail_vnews(
79 global.numa_nodes[i].distance, numa_node_count, ALLOC_ZERO);
80
81 cpu_mask_init(m: &global.numa_nodes[i].cpus, nbits: global.core_count);
82 }
83
84 ptr = (uint8_t *) srat + sizeof(struct acpi_srat);
85 remaining = srat->hdr.length - sizeof(struct acpi_srat);
86
87 while (remaining >= sizeof(struct acpi_entry_hdr)) {
88 struct acpi_entry_hdr *entry = (void *) ptr;
89 switch (entry->type) {
90
91 case ACPI_SRAT_ENTRY_TYPE_PROCESSOR_AFFINITY: {
92 struct acpi_srat_processor_affinity *cpu = (void *) ptr;
93 if (cpu->flags & 1) {
94 uint64_t prox_domain =
95 (uint64_t) cpu->proximity_domain_low |
96 (uint64_t) cpu->proximity_domain_high[0] << 8 |
97 (uint64_t) cpu->proximity_domain_high[1] << 16 |
98 (uint64_t) cpu->proximity_domain_high[2] << 24;
99
100 cpu_id_t cpu_id = smp_cpu_from_apic_id(apic_id: cpu->id);
101 if (cpu_id != CPU_ID_NONE) {
102 /* NOLINTNEXTLINE(*ArrayBound) */
103 cpu_mask_set(m: &global.numa_nodes[prox_domain].cpus, cpu: cpu_id);
104 }
105 }
106 break;
107 }
108
109 case ACPI_SRAT_ENTRY_TYPE_MEMORY_AFFINITY: {
110
111 struct acpi_srat_memory_affinity *mem = (void *) ptr;
112 if (!(mem->flags & 1))
113 break;
114
115 uint64_t node_id = mem->proximity_domain;
116 if (node_id >= numa_node_count)
117 break;
118
119 struct numa_node *n = &global.numa_nodes[node_id];
120 n->mem_base = mem->address;
121 n->mem_size = mem->length;
122 break;
123 }
124
125 default: break;
126 }
127
128 ptr += entry->length;
129 remaining -= entry->length;
130 }
131}
132