1#include <asm.h>
2#include <console/panic.h>
3#include <console/printf.h>
4#include <global.h>
5#include <log.h>
6#include <math/sort.h>
7#include <mem/alloc.h>
8#include <mem/alloc_or_die.h>
9#include <mem/numa.h>
10#include <mem/vmm.h>
11#include <smp/core.h>
12#include <stdint.h>
13#include <string.h>
14#include <uacpi/tables.h>
15
16#include "uacpi/acpi.h"
17#include "uacpi/status.h"
18
19static LOG_HANDLE_DECLARE_DEFAULT(srat);
20
21void srat_init(void) {
22 struct uacpi_table srat_table;
23 if (uacpi_table_find_by_signature(signature: "SRAT", out_table: &srat_table) != UACPI_STATUS_OK) {
24 log_warn_global(LOG_HANDLE(srat),
25 "SRAT table not found, assuming single NUMA node");
26
27 global.numa_nodes =
28 kmalloc_or_die(sizeof(struct numa_node), ALLOC_FLAGS_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 = alloc_or_die(
71 kmalloc(numa_node_count * sizeof(struct numa_node), ALLOC_FLAGS_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 = alloc_or_die(
79 kmalloc(numa_node_count * sizeof(uint8_t), ALLOC_FLAGS_ZERO));
80
81 alloc_or_die(
82 cpu_mask_init(&global.numa_nodes[i].cpus, global.core_count));
83 }
84
85 ptr = (uint8_t *) srat + sizeof(struct acpi_srat);
86 remaining = srat->hdr.length - sizeof(struct acpi_srat);
87
88 while (remaining >= sizeof(struct acpi_entry_hdr)) {
89 struct acpi_entry_hdr *entry = (void *) ptr;
90 switch (entry->type) {
91
92 case ACPI_SRAT_ENTRY_TYPE_PROCESSOR_AFFINITY: {
93 struct acpi_srat_processor_affinity *cpu = (void *) ptr;
94 if (cpu->flags & 1) {
95 uint64_t prox_domain =
96 (uint64_t) cpu->proximity_domain_low |
97 (uint64_t) cpu->proximity_domain_high[0] << 8 |
98 (uint64_t) cpu->proximity_domain_high[1] << 16 |
99 (uint64_t) cpu->proximity_domain_high[2] << 24;
100
101 cpu_mask_set(m: &global.numa_nodes[prox_domain].cpus, cpu: cpu->id);
102 }
103 break;
104 }
105
106 case ACPI_SRAT_ENTRY_TYPE_MEMORY_AFFINITY: {
107
108 struct acpi_srat_memory_affinity *mem = (void *) ptr;
109 if (!(mem->flags & 1))
110 break;
111
112 uint64_t node_id = mem->proximity_domain;
113 if (node_id >= numa_node_count)
114 break;
115
116 struct numa_node *n = &global.numa_nodes[node_id];
117 n->mem_base = mem->address;
118 n->mem_size = mem->length;
119 break;
120 }
121
122 default: break;
123 }
124
125 ptr += entry->length;
126 remaining -= entry->length;
127 }
128}
129