summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/arch/x86/index.md32
-rw-r--r--Makefile.inc2
-rw-r--r--src/arch/x86/Kconfig8
-rw-r--r--src/arch/x86/bootblock_crt0.S6
-rw-r--r--src/cpu/qemu-x86/cache_as_ram_bootblock.S11
-rw-r--r--src/cpu/x86/64bit/entry64.inc62
-rw-r--r--util/pgtblgen/Makefile.inc19
-rw-r--r--util/pgtblgen/description.md1
-rw-r--r--util/pgtblgen/pgtblgen.c168
9 files changed, 297 insertions, 12 deletions
diff --git a/Documentation/arch/x86/index.md b/Documentation/arch/x86/index.md
index 73c982385a11..462e7e6c6ec1 100644
--- a/Documentation/arch/x86/index.md
+++ b/Documentation/arch/x86/index.md
@@ -16,24 +16,36 @@ In order to add support for x86_64 the following assumptions are made:
* The reference implementation is qemu
* The CPU supports 1GiB hugepages
-## Assuptions for ARCH_ROMSTAGE_X86_64 reference implementation
-* 0-4GiB are identity mapped using 1GiB huge-pages
+## Assuptions for all stages using the reference implementation
+* 0-4GiB are identity mapped using 2MiB-pages as WB
* Memory above 4GiB isn't accessible
-* pagetables reside in _pagetables
-* Romstage must install new pagetables in CBMEM after RAMINIT
+* page tables reside in memory mapped ROM
+* A stage can install new page tables in RAM
-## Assuptions for ARCH_RAMSTAGE_X86_64 reference implementation
-* Romstage installed pagetables according to memory layout
-* Memory above 4GiB is accessible
+## Page tables
+Page tables are generated by a tool in `util/pgtblgen/pgtblgen`. It writes
+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
+place the file.
+
+The page tables contains the following structure:
+* PML4E pointing to PDPE
+* PDPE with *$n* entries each pointing to PDE
+* *$n* PDEs with 512 entries each
+
+At the moment *$n* is 4, which results in identity mapping the lower 4 GiB.
## Steps to add basic support for x86_64
* Add x86_64 toolchain support - *DONE*
* Fix compilation errors - *DONE*
* Fix linker errors - *TODO*
-* Add x86_64 rmodule support - *ONGERRIT*
+* Add x86_64 rmodule support - *DONE*
* Add x86_64 exception handlers - *TODO*
-* Setup page tables for long mode - *TODO*
-* Add assembly code for long mode - *TODO*
+* Setup page tables for long mode - *DONE*
+* Add assembly code for long mode - *DONE*
+* Add assembly code for postcar stage - *TODO*
* Add assembly code to return to protected mode - *TODO*
* Implement reference code for mainboard `emulation/qemu-q35` - *TODO*
diff --git a/Makefile.inc b/Makefile.inc
index e8a2d524f619..8ecc0ef3b274 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -93,7 +93,7 @@ subdirs-y += $(wildcard src/soc/*/*) $(wildcard src/northbridge/*/*)
subdirs-y += src/superio
subdirs-y += $(wildcard src/drivers/*) $(wildcard src/drivers/*/*)
subdirs-y += src/cpu src/vendorcode
-subdirs-y += util/cbfstool util/sconfig util/nvramtool
+subdirs-y += util/cbfstool util/sconfig util/nvramtool util/pgtblgen
subdirs-y += util/futility util/marvell util/bincfg
subdirs-y += $(wildcard src/arch/*)
subdirs-y += src/mainboard/$(MAINBOARDDIR)
diff --git a/src/arch/x86/Kconfig b/src/arch/x86/Kconfig
index 171b408da252..37b7d2daaafa 100644
--- a/src/arch/x86/Kconfig
+++ b/src/arch/x86/Kconfig
@@ -66,6 +66,14 @@ config ARCH_RAMSTAGE_X86_64
bool
default n
+config ARCH_X86_64_PGTBL_LOC
+ hex "x86_64 page table location in CBFS"
+ depends on ARCH_BOOTBLOCK_X86_64
+ default 0xfffea000
+ help
+ The position where to place pagetables. Needs to be known at
+ compile time. Must not overlap other files in CBFS.
+
config USE_MARCH_586
def_bool n
help
diff --git a/src/arch/x86/bootblock_crt0.S b/src/arch/x86/bootblock_crt0.S
index 3cb57e058c72..9fcb5c4e4a94 100644
--- a/src/arch/x86/bootblock_crt0.S
+++ b/src/arch/x86/bootblock_crt0.S
@@ -31,6 +31,12 @@
#include <cpu/x86/16bit/reset16.inc>
#include <cpu/x86/32bit/entry32.inc>
+ /* BIST result in eax */
+ mov %eax, %ebx
+ /* entry64.inc preserves ebx. */
+#include <cpu/x86/64bit/entry64.inc>
+ mov %ebx, %eax
+
#if CONFIG(BOOTBLOCK_DEBUG_SPINLOOP)
/* Wait for a JTAG debugger to break in and set EBX non-zero */
diff --git a/src/cpu/qemu-x86/cache_as_ram_bootblock.S b/src/cpu/qemu-x86/cache_as_ram_bootblock.S
index 6ec2e4dc2c00..f5678a180760 100644
--- a/src/cpu/qemu-x86/cache_as_ram_bootblock.S
+++ b/src/cpu/qemu-x86/cache_as_ram_bootblock.S
@@ -38,9 +38,17 @@ cache_as_ram:
/* Align the stack and keep aligned for call to bootblock_c_entry() */
and $0xfffffff0, %esp
- sub $4, %esp
/* Restore the BIST result and timestamps. */
+#if defined(__x86_64__)
+ movd %mm1, %rdi
+ shld %rdi, 32
+ movd %mm1, %rsi
+ or %rsi, %rdi
+ movd %mm2, %rsi
+#else
+ sub $4, %esp
+
movd %mm0, %ebx
movd %mm1, %eax
movd %mm2, %edx
@@ -48,6 +56,7 @@ cache_as_ram:
pushl %ebx
pushl %edx
pushl %eax
+#endif
before_c_entry:
post_code(0x29)
diff --git a/src/cpu/x86/64bit/entry64.inc b/src/cpu/x86/64bit/entry64.inc
new file mode 100644
index 000000000000..f726fab506fe
--- /dev/null
+++ b/src/cpu/x86/64bit/entry64.inc
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2019 Patrick Rudolph <siro@das-labor.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * For starting coreboot in long mode.
+ *
+ * For reference see "AMD64 ArchitectureProgrammer's Manual Volume 2",
+ * Document 24593-Rev. 3.31-July 2019 Chapter 5.3
+ *
+ * Clobbers: eax, ecx, edx
+ */
+
+#if defined(__x86_64__)
+ .code32
+#if (CONFIG_ARCH_X86_64_PGTBL_LOC & 0xfff) > 0
+#error pagetables must be 4KiB aligned!
+#endif
+
+#include <cpu/x86/msr.h>
+#include <arch/rom_segs.h>
+
+setup_longmode:
+ /* Get page table address */
+ movl $(CONFIG_ARCH_X86_64_PGTBL_LOC), %eax
+
+ /* load identity mapped page tables */
+ movl %eax, %cr3
+
+ /* enable PAE */
+ movl %cr4, %eax
+ btsl $5, %eax
+ movl %eax, %cr4
+
+ /* enable long mode */
+ movl $(IA32_EFER), %ecx
+ rdmsr
+ btsl $8, %eax
+ wrmsr
+
+ /* enable paging */
+ movl %cr0, %eax
+ btsl $31, %eax
+ movl %eax, %cr0
+
+ /* use long jump to switch to 64-bit code segment */
+ ljmp $ROM_CODE_SEG64, $__longmode_start
+.code64
+__longmode_start:
+
+#endif
diff --git a/util/pgtblgen/Makefile.inc b/util/pgtblgen/Makefile.inc
new file mode 100644
index 000000000000..c4f3ef37b6fb
--- /dev/null
+++ b/util/pgtblgen/Makefile.inc
@@ -0,0 +1,19 @@
+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) $< -I$(obj) -o $@
+
+endif
diff --git a/util/pgtblgen/description.md b/util/pgtblgen/description.md
new file mode 100644
index 000000000000..f2e4763d75fb
--- /dev/null
+++ b/util/pgtblgen/description.md
@@ -0,0 +1 @@
+Generates page tables based on fixed physical address. `C`
diff --git a/util/pgtblgen/pgtblgen.c b/util/pgtblgen/pgtblgen.c
new file mode 100644
index 000000000000..efbad5520494
--- /dev/null
+++ b/util/pgtblgen/pgtblgen.c
@@ -0,0 +1,168 @@
+/*
+ * This file is part of pgtblgen.
+ *
+ * Copyright (c) 2019 Patrick Rudolph <siro@das-labor.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#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>
+
+static void usage(char *argv[])
+{
+ printf("usage: %s -b <addr> -a <arch> -o <file>\n", argv[0]);
+ printf(" -a\t architecure. Supported: x86_64\n");
+ printf(" -b\t base address\n");
+ printf(" -b\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
+ */
+#define PRES (1ULL << 0)
+#define RW (1ULL << 1)
+#define US (1ULL << 2)
+#define PS (1ULL << 7)
+#define _GEN_DIR(a) (PRES | RW | US | (a))
+#define _GEN_PAGE(a) (PRES | RW | US | PS | (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;
+}