-
Notifications
You must be signed in to change notification settings - Fork 2
/
k-mpspec.cc
206 lines (184 loc) · 5.08 KB
/
k-mpspec.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include "kernel.hh"
#include "k-pci.hh"
namespace {
static uint8_t sum_bytes(const uint8_t* x, size_t len) {
uint8_t sum = 0;
for (; len > 0; ++x, --len) {
sum += *x;
}
return sum;
}
struct mpfloat {
char signature[4];
uint32_t mpconfig_pa;
uint8_t len;
uint8_t spec_rev;
uint8_t checksum;
uint8_t feature[5];
bool check() const {
return memcmp(signature, "_MP_", 4) == 0
&& len == 1
&& (spec_rev == 1 || spec_rev == 4)
&& sum_bytes(reinterpret_cast<const uint8_t*>(this),
sizeof(*this)) == 0;
}
};
struct mpconfig {
char signature[4];
uint16_t len;
uint8_t spec_rev;
uint8_t checksum;
char oem_id[8];
char product_id[12];
uint32_t oemt_pa;
uint16_t oemt_length;
uint16_t entry_count;
uint32_t lapic_pa;
uint16_t ext_len;
uint8_t ext_checksum;
uint8_t reserved;
bool check() const {
return memcmp(signature, "PCMP", 4) == 0
&& len >= sizeof(*this)
&& (spec_rev == 1 || spec_rev == 4)
&& sum_bytes(reinterpret_cast<const uint8_t*>(this), len) == 0;
}
const uint8_t* first() const {
return reinterpret_cast<const uint8_t*>(this) + sizeof(*this);
}
const uint8_t* last() const {
return reinterpret_cast<const uint8_t*>(this) + len;
}
inline const uint8_t* next(const uint8_t* e) const;
static const mpconfig* find();
};
struct proc_config {
static constexpr int id = 0;
uint8_t entry_type;
uint8_t lapic_id;
uint8_t lapic_version;
uint8_t cpu_flags;
uint32_t cpu_signature;
uint32_t feature_flags;
uint32_t reserved[2];
};
struct bus_config {
static constexpr int id = 1;
uint8_t entry_type;
uint8_t bus_id;
uint8_t bus_type[6];
};
struct ioapic_config {
static constexpr int id = 2;
uint8_t entry_type;
uint8_t ioapic_id;
uint8_t ioapic_version;
uint8_t ioapic_flags;
uint32_t ioapic_pa;
bool unusable() const {
return ioapic_flags & 1;
}
};
struct int_config {
static constexpr int ioint_id = 3;
static constexpr int lint_id = 4;
uint8_t entry_type;
uint8_t int_type;
uint16_t int_flags;
uint8_t bus_id;
uint8_t bus_irq;
uint8_t apic_id;
uint8_t apic_intno;
};
inline const uint8_t* mpconfig::next(const uint8_t* e) const {
switch (*e) {
case proc_config::id:
return e + sizeof(proc_config);
case bus_config::id:
return e + sizeof(bus_config);
case ioapic_config::id:
return e + sizeof(ioapic_config);
case int_config::ioint_id:
case int_config::lint_id:
return e + sizeof(int_config);
default:
return last();
}
}
static const mpfloat* find_float(const uint8_t* x, size_t len) {
const uint8_t* end = x + len - sizeof(mpfloat);
for (; x <= end; x += sizeof(mpfloat)) {
auto mpf = reinterpret_cast<const mpfloat*>(x);
if (mpf->check()) {
return mpf;
}
}
return nullptr;
}
const mpconfig* mpconfig::find() {
static const mpconfig* config;
static bool initialized = false;
if (!initialized) {
const mpfloat* mpf;
disable_asan();
if (uint16_t ebda_base = read_unaligned_pa<uint16_t>
(X86_BDA_EBDA_BASE_ADDRESS_PA)) {
mpf = find_float(pa2ka<const uint8_t*>(ebda_base << 4), 1024);
} else {
// `basemem` is reported in KiB - 1KiB
uint16_t basemem = read_unaligned_pa<uint16_t>
(X86_BDA_BASE_MEMORY_SIZE_PA);
mpf = find_float(pa2ka<const uint8_t*>(basemem << 10), 1024);
}
if (!mpf) {
mpf = find_float(pa2ka<const uint8_t*>(0xF0000), 0x10000);
}
if (mpf && mpf->mpconfig_pa) {
const mpconfig* c = pa2ka<const mpconfig*>(mpf->mpconfig_pa);
if (c->check()) {
config = c;
}
}
enable_asan();
initialized = true;
}
return config;
}
}
unsigned machine_ncpu() {
auto mpc = mpconfig::find();
if (!mpc) {
return 0;
}
size_t n = 0;
for (auto e = mpc->first(); e < mpc->last(); e = mpc->next(e)) {
if (*e == proc_config::id) {
++n;
}
}
return n;
}
unsigned machine_pci_irq(int pci_addr, int intr_pin) {
auto mpc = mpconfig::find();
if (!mpc) {
return 0;
}
int bus_id = -1;
int bus_irq = intr_pin | (pcistate::addr_slot(pci_addr) << 2);
for (auto e = mpc->first(); e < mpc->last(); e = mpc->next(e)) {
if (*e == bus_config::id) {
auto x = reinterpret_cast<const bus_config*>(e);
if (bus_id == -1 && memcmp(x->bus_type, "PCI ", 6) == 0) {
bus_id = x->bus_id;
}
} else if (*e == int_config::ioint_id) {
auto x = reinterpret_cast<const int_config*>(e);
if (x->bus_id == bus_id
&& x->bus_irq == bus_irq
&& x->apic_id == 0) {
return x->apic_intno;
}
}
}
return 0;
}