Skip to content

Commit 83073fd

Browse files
shankerwangmiaoWangYuli
authored andcommitted
loongarch: parse BPI data and add memory mapping
On legacy firmwares, the memory mapping information passed in the EFI system table is not enough to cover all the available memory regions, but only contains the memory region which occupied by the firmware, with the total size of ~1GiB. More information is stored in the BPI data structure. The complete information is combined into from the both sources. This patch addes the mechanism to parse the BPI data structure and extract the memory mapping information from it. This patch also adds the memory regions defined in the BPI to the kernel, letting the kernel to discover all the available memory regions. With this patch, machines with legacy firmware, with the BPI version BPI01001, i.e. the newer version, can boot normally.
1 parent ec43d52 commit 83073fd

File tree

8 files changed

+334
-1
lines changed

8 files changed

+334
-1
lines changed

arch/loongarch/kernel/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ obj-$(CONFIG_UPROBES) += uprobes.o
7979
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
8080

8181
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
82+
83+
obj-y += legacy_boot.o

arch/loongarch/kernel/efi.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <asm/efi.h>
2626
#include <asm/loongson.h>
2727

28+
#include "legacy_boot.h"
29+
2830
static unsigned long efi_nr_tables;
2931
static unsigned long efi_config_table;
3032

@@ -35,6 +37,7 @@ static efi_system_table_t *efi_systab;
3537
static efi_config_table_type_t arch_tables[] __initdata = {
3638
{LINUX_EFI_BOOT_MEMMAP_GUID, &boot_memmap, "MEMMAP" },
3739
{DEVICE_TREE_GUID, &fdt_pointer, "FDTPTR" },
40+
{LOONGARCH_BPI_GUID, &loongarch_bpi_info.bpi, "BPI" },
3841
{},
3942
};
4043

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
#include <linux/efi.h>
2+
#include <linux/memblock.h>
3+
4+
#include <asm/early_ioremap.h>
5+
6+
#include "legacy_boot.h"
7+
8+
#define LOONGARCH_BOOT_MEM_MAP_MAX 128
9+
10+
enum bpi_vers {
11+
BPI_VERSION_NONE = 0,
12+
BPI_VERSION_V1 = 1000,
13+
BPI_VERSION_V2 = 1001,
14+
};
15+
16+
struct loongarch_bpi_ext_hdr {
17+
u64 signature;
18+
u32 length;
19+
u8 revision;
20+
u8 checksum;
21+
u64 next;
22+
} __packed;
23+
24+
struct loongarch_bpi_hdr {
25+
u64 signature;
26+
u64 systemtable;
27+
u64 extlist;
28+
u64 flags;
29+
} __packed;
30+
31+
enum bpi_mem_type {
32+
ADDRESS_TYPE_SYSRAM = 1,
33+
ADDRESS_TYPE_RESERVED = 2,
34+
ADDRESS_TYPE_ACPI = 3,
35+
ADDRESS_TYPE_NVS = 4,
36+
ADDRESS_TYPE_PMEM = 5,
37+
ADDRESS_TYPE_MAX,
38+
};
39+
40+
struct loongarch_bpi_mem_map {
41+
struct loongarch_bpi_ext_hdr header; /*{"M", "E", "M"}*/
42+
u8 map_count;
43+
struct loongarch_bpi_mem_map_entry {
44+
u32 mem_type;
45+
u64 mem_start;
46+
u64 mem_size;
47+
} __packed map[];
48+
} __packed;
49+
50+
struct loongarch_bpi_info __initdata loongarch_bpi_info = {
51+
.bpi = EFI_INVALID_TABLE_ADDR,
52+
};
53+
54+
static enum bpi_vers __initdata bpi_version = BPI_VERSION_NONE;
55+
static u64 __initdata bpi_flags = 0;
56+
57+
static int have_bpi = 0;
58+
59+
static __initdata struct {
60+
size_t map_count;
61+
struct loongarch_bpi_memmap{
62+
enum bpi_mem_type type;
63+
unsigned long mem_start;
64+
size_t mem_size;
65+
} map[LOONGARCH_BOOT_MEM_MAP_MAX];
66+
} bpi_meminfo = {0};
67+
68+
static __initdata struct {
69+
unsigned long addr;
70+
size_t size;
71+
} bpi_memmap = {
72+
.addr = EFI_INVALID_TABLE_ADDR,
73+
.size = 0,
74+
};
75+
76+
static const __initconst struct bpi_extlist_desc {
77+
union {
78+
u64 signature;
79+
char chars[8];
80+
};
81+
unsigned long *ptr;
82+
size_t *length;
83+
} bpi_extlist[] = {
84+
{ .chars = "MEM", &bpi_memmap.addr, &bpi_memmap.size },
85+
{ .signature = 0, NULL, NULL },
86+
};
87+
88+
89+
static void __init parse_bpi_ext_list(unsigned long exthdr)
90+
{
91+
unsigned long cur_hdr = exthdr;
92+
while(cur_hdr){
93+
struct loongarch_bpi_ext_hdr *hdr = early_memremap_ro(cur_hdr, sizeof(*hdr));
94+
if(!hdr) {
95+
break;
96+
}
97+
u64 sig = hdr->signature;
98+
u32 len = hdr->length;
99+
u8 rev = hdr->revision;
100+
unsigned long next = hdr->next;
101+
early_memunmap(hdr, sizeof(*hdr));
102+
103+
pr_info("BPI: ext hdr: %.8s, rev %u\n", (const char *)&sig, rev);
104+
105+
for(const struct bpi_extlist_desc *desc = bpi_extlist; desc->signature; desc++) {
106+
if(sig == desc->signature) {
107+
*(desc->ptr) = cur_hdr;
108+
*(desc->length) = len;
109+
}
110+
}
111+
cur_hdr = next;
112+
}
113+
}
114+
115+
116+
static u8 __init ext_listhdr_checksum(void *buffer, size_t length)
117+
{
118+
u8 sum = 0;
119+
u8 *end = buffer + length;
120+
u8 *buf = buffer;
121+
122+
while (buf < end)
123+
sum = (u8)(sum + *(buf++));
124+
125+
return sum;
126+
}
127+
128+
static void __init parse_bpi_mem_map(void)
129+
{
130+
if(bpi_memmap.addr == EFI_INVALID_TABLE_ADDR) {
131+
return;
132+
}
133+
if(bpi_memmap.size < sizeof(struct loongarch_bpi_mem_map)) {
134+
pr_err("BPI: invalid memmap size %ld\n", bpi_memmap.size);
135+
return;
136+
}
137+
struct loongarch_bpi_mem_map *memmap = early_memremap_ro(bpi_memmap.addr, bpi_memmap.size);
138+
if(!memmap) {
139+
return;
140+
}
141+
142+
u8 checksum = ext_listhdr_checksum(memmap, bpi_memmap.size);
143+
if (checksum != 0) {
144+
pr_err("BPI: memmap checksum mismatch\n");
145+
goto err_out;
146+
}
147+
148+
size_t map_count = memmap->map_count;
149+
if (map_count > LOONGARCH_BOOT_MEM_MAP_MAX) {
150+
pr_err("BPI: too many memmap entries\n");
151+
goto err_out;
152+
}
153+
if (map_count * sizeof(memmap->map[0]) + sizeof(*memmap) > bpi_memmap.size) {
154+
pr_err("BPI: invalid memmap size %ld, not enough to hold %ld entries\n", bpi_memmap.size, map_count);
155+
goto err_out;
156+
}
157+
for(int i = 0; i < map_count; i++) {
158+
bpi_meminfo.map[i].type = memmap->map[i].mem_type;
159+
bpi_meminfo.map[i].mem_start = memmap->map[i].mem_start;
160+
bpi_meminfo.map[i].mem_size = memmap->map[i].mem_size;
161+
162+
static const char * const __initconst mem_type_str[] = {
163+
NULL,
164+
[ADDRESS_TYPE_SYSRAM] = "SYSRAM",
165+
[ADDRESS_TYPE_RESERVED] = "RESERVED",
166+
[ADDRESS_TYPE_ACPI] = "ACPI",
167+
[ADDRESS_TYPE_NVS] = "NVS",
168+
[ADDRESS_TYPE_PMEM] = "PMEM",
169+
};
170+
if(bpi_meminfo.map[i].type >= ADDRESS_TYPE_MAX || bpi_meminfo.map[i].type == 0) {
171+
pr_info("BPI: memmap type unknown(%d), start 0x%lx, size 0x%lx\n", bpi_meminfo.map[i].type, bpi_meminfo.map[i].mem_start, bpi_meminfo.map[i].mem_size);
172+
}else{
173+
pr_info("BPI: memmap type %s, start 0x%lx, size 0x%lx\n", mem_type_str[bpi_meminfo.map[i].type], bpi_meminfo.map[i].mem_start, bpi_meminfo.map[i].mem_size);
174+
}
175+
}
176+
bpi_meminfo.map_count = map_count;
177+
178+
err_out:
179+
early_memunmap(memmap, bpi_memmap.size);
180+
}
181+
182+
static int __init bpi_parse_signature (u64 signature)
183+
{
184+
union {
185+
u64 signature;
186+
char chars[9];
187+
} sig;
188+
sig.signature = signature;
189+
sig.chars[8] = '\0';
190+
191+
if (!(sig.chars[0] == 'B' && sig.chars[1] == 'P' && sig.chars[2] == 'I')) {
192+
pr_err("BPI: invalid signature\n");
193+
return -EINVAL;
194+
}
195+
int version;
196+
int rc = kstrtoint(&sig.chars[3], 10, &version);
197+
if(rc != 0 || version == BPI_VERSION_NONE) {
198+
pr_err("BPI: invalid version\n");
199+
return -EINVAL;
200+
}
201+
bpi_version = version;
202+
pr_info("BPI: version %d\n", bpi_version);
203+
return 0;
204+
}
205+
206+
void __init bpi_init(void)
207+
{
208+
if (loongarch_bpi_info.bpi == EFI_INVALID_TABLE_ADDR) {
209+
return;
210+
}
211+
struct loongarch_bpi_hdr *tbl;
212+
213+
tbl = early_memremap_ro(loongarch_bpi_info.bpi, sizeof(*tbl));
214+
if (tbl) {
215+
int rc = bpi_parse_signature(tbl->signature);
216+
if (rc != 0) {
217+
goto err_out;
218+
}
219+
have_bpi = 1;
220+
if (bpi_version >= BPI_VERSION_V2) {
221+
bpi_flags = tbl->flags;
222+
pr_info("BPI: flags 0x%llx\n", bpi_flags);
223+
}
224+
unsigned long bpi_extlist = tbl->extlist;
225+
parse_bpi_ext_list(bpi_extlist);
226+
parse_bpi_mem_map();
227+
err_out:
228+
early_memunmap(tbl, sizeof(*tbl));
229+
}
230+
}
231+
232+
void __init bpi_memblock_init(unsigned long *p_max_low_pfn)
233+
{
234+
for(int i = 0; i < bpi_meminfo.map_count; i++) {
235+
unsigned long start = bpi_meminfo.map[i].mem_start;
236+
size_t size = bpi_meminfo.map[i].mem_size;
237+
unsigned long end = start + size;
238+
239+
switch(bpi_meminfo.map[i].type) {
240+
case ADDRESS_TYPE_SYSRAM:
241+
// EFI_CONVENTIONAL_MEMORY
242+
case ADDRESS_TYPE_PMEM:
243+
// EFI_PERSISTENT_MEMORY
244+
memblock_add(start, size);
245+
if (*p_max_low_pfn < (end >> PAGE_SHIFT))
246+
*p_max_low_pfn = end >> PAGE_SHIFT;
247+
break;
248+
case ADDRESS_TYPE_ACPI:
249+
// EFI_ACPI_RECLAIM_MEMORY
250+
memblock_add(start, size);
251+
fallthrough;
252+
case ADDRESS_TYPE_RESERVED:
253+
// EFI_RUNTIME_SERVICES_DATA or
254+
// EFI_RUNTIME_SERVICES_CODE or
255+
// EFI_RESERVED_MEMORY_TYPE
256+
memblock_reserve(start, size);
257+
break;
258+
default:
259+
break;
260+
}
261+
}
262+
}
263+
264+
void __init bpi_init_node_memblock(void (*p_add_numamem_region)(u64 start, u64 end, u32 type))
265+
{
266+
for(int i = 0; i < bpi_meminfo.map_count; i++) {
267+
u64 mem_start = bpi_meminfo.map[i].mem_start;
268+
u64 mem_size = bpi_meminfo.map[i].mem_size;
269+
u64 mem_end = mem_start + mem_size;
270+
u32 mem_type;
271+
272+
switch(bpi_meminfo.map[i].type) {
273+
case ADDRESS_TYPE_SYSRAM:
274+
mem_type = EFI_CONVENTIONAL_MEMORY;
275+
p_add_numamem_region(mem_start, mem_end, mem_type);
276+
break;
277+
case ADDRESS_TYPE_PMEM:
278+
mem_type = EFI_PERSISTENT_MEMORY;
279+
p_add_numamem_region(mem_start, mem_end, mem_type);
280+
break;
281+
case ADDRESS_TYPE_ACPI:
282+
mem_type = EFI_ACPI_RECLAIM_MEMORY;
283+
p_add_numamem_region(mem_start, mem_end, mem_type);
284+
fallthrough;
285+
case ADDRESS_TYPE_RESERVED:
286+
pr_info("Resvd: mem_type:BPI_%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n",
287+
bpi_meminfo.map[i].type, mem_start, mem_size);
288+
break;
289+
default:
290+
break;
291+
}
292+
}
293+
}
294+
295+
int loongarch_have_legacy_bpi (void){
296+
return have_bpi;
297+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef __LEGACY_BOOT_H_
2+
#define __LEGACY_BOOT_H_
3+
4+
#include <linux/efi.h>
5+
6+
#define LOONGARCH_BPI_GUID EFI_GUID(0x4660f721, 0x2ec5, 0x416a, 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9)
7+
8+
struct loongarch_bpi_info {
9+
unsigned long bpi;
10+
};
11+
12+
extern struct loongarch_bpi_info loongarch_bpi_info;
13+
extern void bpi_init(void);
14+
extern void bpi_memblock_init(unsigned long *p_max_low_pfn);
15+
extern void bpi_init_node_memblock(void (*p_add_numamem_region)(u64 start, u64 end, u32 type));
16+
extern int loongarch_have_legacy_bpi(void);
17+
18+
#endif /* __LEGACY_BOOT_H_ */

arch/loongarch/kernel/mem.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <asm/loongson.h>
1111
#include <asm/sections.h>
1212

13+
#include "legacy_boot.h"
14+
1315
void __init memblock_init(void)
1416
{
1517
u32 mem_type;
@@ -50,6 +52,8 @@ void __init memblock_init(void)
5052
}
5153
}
5254

55+
bpi_memblock_init(&max_low_pfn);
56+
5357
memblock_set_current_limit(PFN_PHYS(max_low_pfn));
5458

5559
/* Reserve the first 2MB */

arch/loongarch/kernel/numa.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include <asm/sections.h>
2727
#include <asm/time.h>
2828

29+
#include "legacy_boot.h"
30+
2931
int numa_off;
3032
struct pglist_data *node_data[MAX_NUMNODES];
3133
unsigned char node_distances[MAX_NUMNODES][MAX_NUMNODES];
@@ -396,6 +398,7 @@ int __init init_numa_memory(void)
396398
return -EINVAL;
397399

398400
init_node_memblock();
401+
bpi_init_node_memblock(add_numamem_region);
399402
if (numa_meminfo_cover_memory(&numa_meminfo) == false)
400403
return -EINVAL;
401404

arch/loongarch/kernel/setup.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
#include <asm/setup.h>
5050
#include <asm/time.h>
5151

52+
#include "legacy_boot.h"
53+
5254
#define SMBIOS_BIOSSIZE_OFFSET 0x09
5355
#define SMBIOS_BIOSEXTERN_OFFSET 0x13
5456
#define SMBIOS_FREQLOW_OFFSET 0x16
@@ -610,11 +612,11 @@ static void __init prefill_possible_map(void)
610612
void __init setup_arch(char **cmdline_p)
611613
{
612614
cpu_probe();
613-
unwind_init();
614615

615616
init_environ();
616617
efi_init();
617618
fdt_setup();
619+
bpi_init();
618620
memblock_init();
619621
pagetable_init();
620622
bootcmdline_init(cmdline_p);

0 commit comments

Comments
 (0)