cpu/x86/64bit: Generate static page tables from an assembly file

This removes the need for a tool to generate simple identity pages.
Future patches will link this page table directly into the stages on
some platforms so having an assembly file makes a lot of sense.

This also optimizes the size of the page of each 4K page by placing
the PDPE_table below the PDE.

Change-Id: Ia1e31b701a2584268c85d327bf139953213899e3
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/63725
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Raul Rangel <rrangel@chromium.org>
This commit is contained in:
Arthur Heymans 2022-04-19 20:48:42 +02:00 committed by Felix Held
parent 34f5cd9cb2
commit 597b9e9d71
6 changed files with 48 additions and 181 deletions

View File

@ -26,9 +26,7 @@ In order to add support for x86_64 the following assumptions were made:
* A stage can install new page tables in RAM * A stage can install new page tables in RAM
## Page tables ## Page tables
Page tables are generated by a tool in `util/pgtblgen/pgtblgen`. It writes A `pagetables` cbfs file is generated based on an assembly file.
the page tables to a file which is then included into the CBFS as file called
`pagetables`.
To generate the static page tables it must know the physical address where to To generate the static page tables it must know the physical address where to
place the file. place the file.

View File

@ -5,3 +5,15 @@ endif
romstage-y += mode_switch.S romstage-y += mode_switch.S
postcar-y += mode_switch.S postcar-y += mode_switch.S
ramstage-y += mode_switch.S ramstage-y += mode_switch.S
# Add --defsym=_start=0 to suppress a linker warning.
$(objcbfs)/pt: $(dir)/pt.S
$(CC_bootblock) $(CFLAGS_bootblock) $(CPPFLAGS_bootblock) -o $@.tmp $< -Wl,--section-start=.rodata=$(CONFIG_ARCH_X86_64_PGTBL_LOC),--defsym=_start=0
$(OBJCOPY_ramstage) -Obinary -j .rodata $@.tmp $@
rm $@.tmp
cbfs-files-y += pagetables
pagetables-file := $(objcbfs)/pt
pagetables-type := raw
pagetables-compression := none
pagetables-COREBOOT-position := $(CONFIG_ARCH_X86_64_PGTBL_LOC)

35
src/cpu/x86/64bit/pt.S Normal file
View File

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* For reference see "AMD64 Architecture Programmer's Manual Volume 2",
* Document 24593-Rev. 3.31-July 2019 Chapter 5.3.4
*
* Page table attributes: WB, User+Supervisor, Present, Writeable, Accessed, Dirty
*/
.section .rodata
#define _PRES (1ULL << 0)
#define _RW (1ULL << 1)
#define _US (1ULL << 2)
#define _A (1ULL << 5)
#define _D (1ULL << 6)
#define _PS (1ULL << 7)
#define _GEN_DIR(a) (_PRES + _RW + _US + _A + (a))
#define _GEN_PAGE(a) (_PRES + _RW + _US + _PS + _A + _D + (a))
.global PM4LE
.align 32
PM4LE:
.quad _GEN_DIR(PDPE_table)
.align 4096
PDE_tables: /* identity map 2MiB pages */
.rept 2048
.quad _GEN_PAGE(0x200000 * ((. - PDE_tables) >> 3))
.endr
.align 4096
PDPE_table: /* Point to PDE */
.rept 4
.quad _GEN_DIR(PDE_tables + 4096 * ((. - PDPE_table) >> 3))
.endr

View File

@ -1,19 +0,0 @@
ifeq ($(CONFIG_ARCH_BOOTBLOCK_X86_64),y)
PGTBLGEN:= $(obj)/pgtblgen
cbfs-files-y += pagetables
pagetables-file := $(obj)/mainboard/$(MAINBOARDDIR)/pagetables
pagetables-type := raw
pagetables-compression := none
pagetables-COREBOOT-position := $(CONFIG_ARCH_X86_64_PGTBL_LOC)
$(obj)/mainboard/$(MAINBOARDDIR)/pagetables: $(PGTBLGEN) $(obj)/config.h
printf " TOOL Creating page tables\n"
$(PGTBLGEN) -b $(CONFIG_ARCH_X86_64_PGTBL_LOC) -a x86_64 -o $@
$(PGTBLGEN): util/pgtblgen/pgtblgen.c
printf " MAKE Creating PGTBLGEN tool\n"
$(HOSTCC) -std=c99 $< -I$(obj) -o $@
endif

View File

@ -1 +0,0 @@
Generates page tables based on fixed physical address. `C`

View File

@ -1,158 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <inttypes.h>
#include <getopt.h>
static void usage(char *argv[])
{
printf("usage: %s -b <addr> -a <arch> -o <file>\n", argv[0]);
printf(" -a\t architecture. Supported: x86_64\n");
printf(" -b\t base address\n");
printf(" -o\t the file to write to\n");
printf(" -h\t show this help text\n");
}
/*
* For reference see "AMD64 ArchitectureProgrammer's Manual Volume 2",
* Document 24593-Rev. 3.31-July 2019 Chapter 5.3.4
*
* Page table attributes: WB, User+Supervisor, Present, Writeable, Accessed, Dirty
*/
#define _PRES (1ULL << 0)
#define _RW (1ULL << 1)
#define _US (1ULL << 2)
#define _A (1ULL << 5)
#define _D (1ULL << 6)
#define _PS (1ULL << 7)
#define _GEN_DIR(a) (_PRES | _RW | _US | _A | (a))
#define _GEN_PAGE(a) (_PRES | _RW | _US | _PS | _A | _D | (a))
/*
* Generate x86_64 page tables.
* The page tables needs to be placed at @base_address, and identity map
* the first @size_gib GiB of physical memory.
*/
static int gen_pgtbl_x86_64(const uint64_t base_address,
const size_t size_gib,
void **out_buf,
size_t *out_size)
{
uint64_t *entry;
if (!out_size || !out_buf)
return 1;
*out_size = (size_gib + 2) * 4096;
*out_buf = malloc(*out_size);
if (!*out_buf)
return 1;
memset(*out_buf, 0, *out_size);
entry = (uint64_t *)*out_buf;
/* Generate one PM4LE entry - point to PDPE */
entry[0] = _GEN_DIR(base_address + 4096);
entry += 512;
/* PDPE table - point to PDE */
for (size_t i = 0; i < size_gib; i++)
entry[i] = _GEN_DIR(base_address + 4096 * (i + 2));
entry += 512;
/* PDE tables - identity map 2MiB pages */
for (size_t g = 0; g < size_gib; g++) {
for (size_t i = 0; i < 512; i++) {
uint64_t addr = ((1ULL << (12 + 9)) * i) | ((1ULL << (12 + 9 + 9)) * g);
entry[i] = _GEN_PAGE(addr);
}
entry += 512;
}
return 0;
}
int main(int argc, char *argv[])
{
int ret = 1;
uint64_t base_address = 0;
char *filename = NULL;
char *arch = NULL;
void *buf = NULL;
size_t buf_size = 0;
int c;
while ((c = getopt(argc, argv, "ho:a:b:")) != -1)
switch (c) {
case '?': /* falltrough */
case 'h':
usage(argv);
return 0;
case 'o':
filename = optarg;
break;
case 'a':
arch = optarg;
break;
case 'b':
base_address = strtoull(optarg, NULL, 0);
break;
default:
break;
}
if (!filename) {
fprintf(stderr, "E: Missing filename.\n");
goto done;
}
if (!arch) {
fprintf(stderr, "E: Missing architecture.\n");
goto done;
} else if (strcmp(arch, "x86_64") != 0) {
fprintf(stderr, "E: Unsupported architecture.\n");
goto done;
}
if (base_address & 4095) {
fprintf(stderr, "E: Base address not 4 KiB aligned\n");
goto done;
}
/* FIXME: Identity map 4GiB for now, increase if necessary */
if (strcmp(arch, "x86_64") == 0)
ret = gen_pgtbl_x86_64(base_address, 4, &buf, &buf_size);
if (ret) {
fprintf(stderr, "Failed to generate page tables\n");
goto done;
}
// write the table
FILE *fd = fopen(filename, "wb");
if (!fd) {
fprintf(stderr, "%s open failed: %s\n", filename, strerror(errno));
goto done;
}
if (fwrite(buf, 1, buf_size, fd) != buf_size) {
fprintf(stderr, "%s write failed: %s\n", filename, strerror(errno));
fclose(fd);
goto done;
}
if (fclose(fd)) {
fprintf(stderr, "%s close failed: %s\n", filename, strerror(errno));
goto done;
}
ret = 0;
done:
free(buf);
return ret;
}