[coreboot-gerrit] Change in coreboot[master]: [WIP]x86|mb/emulation/qemu-q35: 64bit ramstage support

Patrick Rudolph (Code Review) gerrit at coreboot.org
Sat Nov 17 11:30:14 CET 2018


Hello Patrick Rudolph,

I'd like you to do a code review. Please visit

    https://review.coreboot.org/29667

to review the following change.


Change subject: [WIP]x86|mb/emulation/qemu-q35: 64bit ramstage support
......................................................................

[WIP]x86|mb/emulation/qemu-q35: 64bit ramstage support

* Add mmu.c ported from arm64
* Generate 4 level page tables for long mode
* Enable long mode
* Activate long mode in c_start.S
* Some fixes for 64bit
* Add support for 64bit rmodule

Non working:
* Loading gdt and setting %ds

Signed-off-by: Patrick Rudolph <siro at das-labor.org>
Change-Id: If2f02a95b2f91ab51043d4e81054354f4a6eb5d5
---
M src/arch/x86/Kconfig
M src/arch/x86/Makefile.inc
M src/arch/x86/boot.c
M src/arch/x86/c_start.S
M src/arch/x86/exception.c
A src/arch/x86/include/arch/mmu.h
A src/arch/x86/mmu.c
M src/commonlib/include/commonlib/cbmem_id.h
M src/cpu/qemu-x86/Kconfig
M src/cpu/x86/Makefile.inc
M src/lib/timestamp.c
M src/mainboard/emulation/qemu-q35/Kconfig
M src/mainboard/emulation/qemu-q35/Makefile.inc
M src/mainboard/emulation/qemu-q35/romstage.c
M src/southbridge/intel/common/smi.c
M src/southbridge/intel/i82801ix/hdaudio.c
M src/southbridge/intel/i82801ix/lpc.c
M src/southbridge/intel/i82801ix/sata.c
M util/cbfstool/elf.h
M util/cbfstool/elfheaders.c
M util/cbfstool/rmodule.c
M util/xcompile/xcompile
22 files changed, 663 insertions(+), 14 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/67/29667/1

diff --git a/src/arch/x86/Kconfig b/src/arch/x86/Kconfig
index 7c8371e..ed07a05 100644
--- a/src/arch/x86/Kconfig
+++ b/src/arch/x86/Kconfig
@@ -330,3 +330,7 @@
 config HAVE_CF9_RESET_PREPARE
 	bool
 	depends on HAVE_CF9_RESET
+
+config TTB_SIZE_KB
+	hex "Size of TTB"
+	default 0x1000
diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc
index fcc57c5..c5cf625 100644
--- a/src/arch/x86/Makefile.inc
+++ b/src/arch/x86/Makefile.inc
@@ -398,7 +398,7 @@
 
 $(objgenerated)/ramstage.o: $$(ramstage-objs) $(COMPILER_RT_ramstage) $$(ramstage-libs)
 	@printf "    CC         $(subst $(obj)/,,$(@))\n"
-ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32),y)
+ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32),y)
 	$(LD_ramstage) -m elf_i386 -r -o $@ $(COMPILER_RT_FLAGS_ramstage) --whole-archive --start-group $(filter-out %.ld,$(ramstage-objs)) $(ramstage-libs) --no-whole-archive $(COMPILER_RT_ramstage) --end-group
 else
 	$(LD_ramstage) -m elf_x86_64 -r -o $@ $(COMPILER_RT_FLAGS_ramstage) --whole-archive --start-group $(filter-out %.ld,$(ramstage-objs)) $(ramstage-libs) --no-whole-archive $(COMPILER_RT_ramstage) --end-group
diff --git a/src/arch/x86/boot.c b/src/arch/x86/boot.c
index 2967cf6..fa98704 100644
--- a/src/arch/x86/boot.c
+++ b/src/arch/x86/boot.c
@@ -29,16 +29,17 @@
 
 	return 0;
 }
+	#include <arch/mmu.h>
 
 void arch_prog_run(struct prog *prog)
 {
+	printk(BIOS_DEBUG, "Jumping to %p\n", (void*)prog_entry(prog));
 	__asm__ volatile (
 #ifdef __x86_64__
 		"jmp  *%%rdi\n"
 #else
 		"jmp  *%%edi\n"
 #endif
-
 		:: "D"(prog_entry(prog))
 	);
 }
diff --git a/src/arch/x86/c_start.S b/src/arch/x86/c_start.S
index 6426ef3..11b0145 100644
--- a/src/arch/x86/c_start.S
+++ b/src/arch/x86/c_start.S
@@ -12,6 +12,7 @@
  */
 
 #include <cpu/x86/post_code.h>
+#include <arch/rom_segs.h>
 
 /* Place the stack in the bss section. It's not necessary to define it in the
  * the linker script. */
@@ -35,13 +36,57 @@
 #else
 	.code32
 #endif
+
 	.globl _start
 _start:
+
 	cli
-	lgdt	%cs:gdtaddr
+#ifdef __x86_64__
+	/* Test for page tables installed */
+	mov	%cr3, %eax
+	cmp	$0, %eax
+	je	longmode_setup_err
+
+	/* Test for long mode active (EFER.LMA = 1 EFER.LME = 1) */
+	movl	$0xC0000080, %ecx          // EFER MSR number.
+	rdmsr
+	andl	$0x500, %eax
+	cmp	$0x500, %eax
+	je	longmode_active
+
+	/* Test for long mode disabled (EFER.LME = 0) */
+	cmp	$0, %eax
+	je	longmode_setup_err
+
+	/*
+	 * Previous stage prepared long mode:
+	 * + Long mode is enabled (EFER.LME = 1)
+	 * + paging is disalbed
+	 * + page tables are installed
+	 */
+
+	/* Enable paging */
+	mov	%cr0, %eax
+	orl	$(1 <<31), %eax
+	mov	%eax, %cr0
+
+	jmp	longmode_active
+
+longmode_setup_err:
+	post_code(POST_DEAD_CODE)	/* post ee */
+	hlt
+	jmp	longmode_setup_err
+
+longmode_active:
+#endif
+
+	lgdt %cs:gdtaddr
+
 #ifndef __x86_64__
+	/* Enable protected mode */
 	ljmp	$0x10, $1f
 #endif
+	/* Use flat data segment */
 1:	movl	$0x18, %eax
 	movl	%eax, %ds
 	movl	%eax, %es
@@ -134,7 +179,7 @@
 #endif
 
 	 .data
-
+	.balign 8
 	/* This is the gdt for GCC part of coreboot.
 	 * It is different from the gdt in ROMCC/ASM part of coreboot
 	 * which is defined in entry32.inc
diff --git a/src/arch/x86/exception.c b/src/arch/x86/exception.c
index 0f42fdf..9dda706 100644
--- a/src/arch/x86/exception.c
+++ b/src/arch/x86/exception.c
@@ -516,7 +516,7 @@
 		"edi: %08x esi: %08x ebp: %08x esp: %08x\n",
 		logical_processor, (unsigned int)lapicid(),
 		info->vector, info->cs, info->eip,
-		info->error_code, info->eflags, read_cr2(),
+		info->error_code, info->eflags, (unsigned int)read_cr2(),
 		info->eax, info->ebx, info->ecx, info->edx,
 		info->edi, info->esi, info->ebp, info->esp);
 	u8 *code = (u8 *)((uintptr_t)info->eip - (MDUMP_SIZE >> 1));
diff --git a/src/arch/x86/include/arch/mmu.h b/src/arch/x86/include/arch/mmu.h
new file mode 100644
index 0000000..c3bd3f7
--- /dev/null
+++ b/src/arch/x86/include/arch/mmu.h
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * 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.
+ */
+
+#ifndef __ARCH_X86_MMU_H__
+#define __ARCH_X86_MMU_H__
+
+#include <types.h>
+
+/* Memory attributes for mmap regions
+ * These attributes act as tag values for memrange regions
+ */
+
+/* Descriptor attributes */
+
+#define DESC_MASK 0xeaf
+#define INVALID_DESC 0
+#define TABLE_DESC 0x623
+#define PAGE_DESC 0x4a3
+#define BLOCK_DESC 0x2a3
+
+#define AVAIL_SHIFT 9
+#define AVAIL_MASK (7 << AVAIL_SHIFT)
+#define AVAIL_INVAL 0
+#define AVAIL_TABLE 3
+#define AVAIL_PAGE 2
+#define AVAIL_BLOCK 1
+
+
+/* Block descriptor */
+#define BLOCK_NS                   (1 << 5)
+
+#define BLOCK_AP_RW                (0 << 7)
+#define BLOCK_AP_RO                (1 << 7)
+
+#define BLOCK_ACCESS               (1 << 10)
+
+#define BLOCK_XN                   (1ULL << 54)
+
+#define BLOCK_SH_SHIFT                 (8)
+#define BLOCK_SH_NON_SHAREABLE         (0 << BLOCK_SH_SHIFT)
+#define BLOCK_SH_UNPREDICTABLE         (1 << BLOCK_SH_SHIFT)
+#define BLOCK_SH_OUTER_SHAREABLE       (2 << BLOCK_SH_SHIFT)
+#define BLOCK_SH_INNER_SHAREABLE       (3 << BLOCK_SH_SHIFT)
+
+/* Sentinel descriptor to mark first PTE of an unused table. It must be a value
+ * that cannot occur naturally as part of a page table. (Bits [1:0] = 0b00 makes
+ * this an unmapped page, but some page attribute bits are still set.) */
+#define UNUSED_DESC                0x6EbAAD0BBADbA000ULL
+
+/* XLAT Table Init Attributes */
+
+#define VA_START                   0x0
+#define BITS_PER_VA                48
+/* Granule size of 4KB is being used */
+#define GRANULE_SIZE_SHIFT         12
+#define GRANULE_SIZE               (1 << GRANULE_SIZE_SHIFT)
+#define XLAT_ADDR_MASK             ((1ULL << BITS_PER_VA) - GRANULE_SIZE)
+#define GRANULE_SIZE_MASK          ((1ULL << GRANULE_SIZE_SHIFT) - 1)
+
+#define BITS_RESOLVED_PER_LVL   (GRANULE_SIZE_SHIFT - 3)
+#define L0_ADDR_SHIFT           (GRANULE_SIZE_SHIFT + BITS_RESOLVED_PER_LVL * 3)
+#define L1_ADDR_SHIFT           (GRANULE_SIZE_SHIFT + BITS_RESOLVED_PER_LVL * 2)
+#define L2_ADDR_SHIFT           (GRANULE_SIZE_SHIFT + BITS_RESOLVED_PER_LVL * 1)
+#define L3_ADDR_SHIFT           (GRANULE_SIZE_SHIFT + BITS_RESOLVED_PER_LVL * 0)
+
+#define L0_ADDR_MASK     (((1ULL << BITS_RESOLVED_PER_LVL) - 1) << L0_ADDR_SHIFT)
+#define L1_ADDR_MASK     (((1ULL << BITS_RESOLVED_PER_LVL) - 1) << L1_ADDR_SHIFT)
+#define L2_ADDR_MASK     (((1ULL << BITS_RESOLVED_PER_LVL) - 1) << L2_ADDR_SHIFT)
+#define L3_ADDR_MASK     (((1ULL << BITS_RESOLVED_PER_LVL) - 1) << L3_ADDR_SHIFT)
+
+/* These macros give the size of the region addressed by each entry of a xlat
+   table at any given level */
+#define L3_XLAT_SIZE               (1ULL << L3_ADDR_SHIFT)
+#define L2_XLAT_SIZE               (1ULL << L2_ADDR_SHIFT)
+#define L1_XLAT_SIZE               (1ULL << L1_ADDR_SHIFT)
+#define L0_XLAT_SIZE               (1ULL << L0_ADDR_SHIFT)
+
+#define PAT_UC		0
+#define PAT_WC		1
+#define PAT_WT		4
+#define PAT_WP		5
+#define PAT_WB		6
+#define PAT_UC_MINUS	7
+
+/* Initialize MMU registers and page table memory region. */
+void mmu_init(void);
+/* Install page tables and enable long mode */
+void mmu_install_pagetables(void);
+void mmu_config_range(uint64_t start, uint64_t size, uint64_t tag);
+/* Disable the MMU (which also disables dcache but not icache). */
+void mmu_disable(void);
+
+#endif /* __ARCH_X86_MMU_H__ */
diff --git a/src/arch/x86/mmu.c b/src/arch/x86/mmu.c
new file mode 100644
index 0000000..a0e3e78
--- /dev/null
+++ b/src/arch/x86/mmu.c
@@ -0,0 +1,403 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <symbols.h>
+
+#include <console/console.h>
+#include <arch/mmu.h>
+#include <arch/cache.h>
+#include <cpu/x86/msr.h>
+#include <cbmem.h>
+
+/* This just caches the next free table slot (okay to do since they fill up from
+ * bottom to top and can never be freed up again). It will reset to its initial
+ * value on stage transition, so we still need to check it for UNUSED_DESC. */
+static CAR_GLOBAL uint64_t *next_free_table;
+
+#define PTE_PRES (1ULL << 0)
+#define PTE_RW   (1ULL << 1)
+#define PTE_US   (1ULL << 2)
+#define PTE_PWT  (1ULL << 3)
+#define PTE_PCD  (1ULL << 4)
+#define PTE_A    (1ULL << 5)
+#define PTE_D    (1ULL << 6)
+#define PTE_PAT  (1ULL << 7)
+#define PTE_G    (1ULL << 8)
+#define PTE_XD   (1ULL << 63)
+#define PDE_PS   (1ULL << 7)
+
+#define BLOCK_INDEX_MASK (PTE_PWT | PTE_PCD | PTE_PRES | PTE_RW | PTE_A | PTE_D)
+#define BLOCK_INDEX_SHIFT 0
+#define BLOCK_INDEX_MEM_NORMAL (PTE_PRES | PTE_RW | PTE_A | PTE_D)
+
+static void print_tag(int level, uint64_t pat)
+{
+	switch (pat) {
+	case PAT_UC:
+		printk(level, "UC\n");
+		break;
+	case PAT_WC:
+		printk(level, "WC\n");
+		break;
+	case PAT_WT:
+		printk(level, "WT\n");
+		break;
+	case PAT_WP:
+		printk(level, "WP\n");
+		break;
+	case PAT_WB:
+		printk(level, "WB\n");
+		break;
+	case PAT_UC_MINUS:
+		printk(level, "UC-\n");
+		break;
+	default:
+		break;
+	}
+}
+
+static uint64_t pte_pat_flags(unsigned long pat)
+{
+	switch (pat) {
+	case PAT_UC:
+		return 0 | PTE_PCD | PTE_PWT;
+	case PAT_WC:
+		return 0 | 0 | PTE_PWT;
+	case PAT_WT:
+		return PTE_PAT | PTE_PCD | PTE_PWT;
+	case PAT_WP:
+		return PTE_PAT | 0 | PTE_PWT;
+	case PAT_WB:
+		return 0 | 0 | 0;
+	case PAT_UC_MINUS:
+		return 0 | PTE_PCD | 0;
+	default:
+		printk(BIOS_ERR, "PTE PAT defaulting to WB: %lx\n", pat);
+		return 0 | 0 | 0;
+	}
+}
+
+static u8 *ttb(void)
+{
+	return cbmem_find(CBMEM_ID_TTB);
+}
+
+static u8 *ettb(void)
+{
+	return (u8 *)cbmem_find(CBMEM_ID_TTB) + (CONFIG_TTB_SIZE_KB * 1024);
+}
+
+/* Func : get_block_attr
+ * Desc : Get block descriptor attributes based on the value of tag in memrange
+ * region
+ */
+static uint64_t get_block_attr(unsigned long tag, bool ps)
+{
+	uint64_t flags = PTE_PRES | PTE_RW | PTE_US | PTE_A | PTE_D;
+	flags |= pte_pat_flags(tag);
+	if (ps) {
+		if (flags & PTE_PAT) {
+			/* If PS=1 PAT is at position 12 instead of 7 */
+			flags &= ~PTE_PAT;
+			flags |= (PTE_PAT << 5);
+		}
+		flags |= PDE_PS;
+	}
+	return flags;
+}
+
+/* Func : setup_new_table
+ * Desc : Get next free table from TTB and set it up to match old parent entry.
+ */
+static uint64_t *setup_new_table(uint64_t desc, uint64_t xlat_size)
+{
+	while (next_free_table[0] != UNUSED_DESC) {
+		next_free_table += GRANULE_SIZE/sizeof(*next_free_table);
+		if (ettb() - (u8 *)next_free_table <= 0)
+			die("Ran out of page table space!");
+	}
+
+	uint64_t frame_base = desc & XLAT_ADDR_MASK;
+	printk(BIOS_DEBUG, "Backing address range [0x%llx:0x%llx) with new page"
+	       " table @%p\n", frame_base, frame_base +
+	       (xlat_size << BITS_RESOLVED_PER_LVL), next_free_table);
+
+	if (desc == INVALID_DESC) {
+		memset(next_free_table, 0, GRANULE_SIZE);
+	} else {
+		/* Can reuse old parent entry, but may need to adjust type. */
+		if (xlat_size == L3_XLAT_SIZE)
+			desc |= PAGE_DESC;
+
+		int i = 0;
+		for (; i < GRANULE_SIZE/sizeof(*next_free_table); i++) {
+			next_free_table[i] = desc;
+			desc += xlat_size;
+		}
+	}
+
+	return next_free_table;
+}
+
+/* Func: get_next_level_table
+ * Desc: Check if the table entry is a valid descriptor. If not, initialize new
+ * table, update the entry and return the table addr. If valid, return the addr
+ */
+static uint64_t *get_next_level_table(uint64_t *ptr, size_t xlat_size)
+{
+	uint64_t desc = *ptr;
+
+	if ((desc & DESC_MASK) != TABLE_DESC) {
+		uint64_t *new_table = setup_new_table(desc, xlat_size);
+		desc = ((uintptr_t)new_table) | TABLE_DESC;
+		*ptr = desc;
+	}
+	return (uint64_t *)(uintptr_t)(desc & XLAT_ADDR_MASK);
+}
+
+/*
+ Func : init_xlat_table
+ * Desc : Given a base address and size, it identifies the indices within
+ * different level XLAT tables which map the given base addr. Similar to table
+ * walk, except that all invalid entries during the walk are updated
+ * accordingly. On success, it returns the size of the block/page addressed by
+ * the final table.
+ */
+static uint64_t init_xlat_table(uint64_t base_addr,
+				uint64_t size,
+				uint64_t tag)
+{
+	uint64_t l0_index = (base_addr & L0_ADDR_MASK) >> L0_ADDR_SHIFT;
+	uint64_t l1_index = (base_addr & L1_ADDR_MASK) >> L1_ADDR_SHIFT;
+	uint64_t l2_index = (base_addr & L2_ADDR_MASK) >> L2_ADDR_SHIFT;
+	uint64_t l3_index = (base_addr & L3_ADDR_MASK) >> L3_ADDR_SHIFT;
+	uint64_t *table = (uint64_t *)ttb();
+	uint64_t desc;
+
+	/* check if CPU supports 1GB huge tables */
+	const bool hugepage_1gb = !!(cpuid_edx(0x80000001) & (1 << 26));
+
+	/* L0 entry stores a table descriptor (doesn't support blocks) */
+	table = get_next_level_table(&table[l0_index], L1_XLAT_SIZE);
+
+	/* L1 table lookup */
+	if ((size >= L1_XLAT_SIZE) &&
+	    IS_ALIGNED(base_addr, (1UL << L1_ADDR_SHIFT)) &&
+	    hugepage_1gb) {
+			/* If block address is aligned and size is greater than
+			 * or equal to size addressed by each L1 entry, we can
+			 * directly store a block desc */
+			desc = base_addr | BLOCK_DESC | get_block_attr(tag, 1);
+			table[l1_index] = desc;
+			/* L2 lookup is not required */
+			return L1_XLAT_SIZE;
+	}
+
+	/* L1 entry stores a table descriptor */
+	table = get_next_level_table(&table[l1_index], L2_XLAT_SIZE);
+
+	/* L2 table lookup */
+	if ((size >= L2_XLAT_SIZE) &&
+	    IS_ALIGNED(base_addr, (1UL << L2_ADDR_SHIFT))) {
+		/* If block address is aligned and size is greater than
+		 * or equal to size addressed by each L2 entry, we can
+		 * directly store a block desc */
+		desc = base_addr | BLOCK_DESC | get_block_attr(tag, 1);
+		table[l2_index] = desc;
+		/* L3 lookup is not required */
+		return L2_XLAT_SIZE;
+	}
+
+	/* L2 entry stores a table descriptor */
+	table = get_next_level_table(&table[l2_index], L3_XLAT_SIZE);
+
+	/* L3 table lookup */
+	desc = base_addr | PAGE_DESC | get_block_attr(tag, 0);
+	table[l3_index] = desc;
+	return L3_XLAT_SIZE;
+}
+
+/* Func : sanity_check
+ * Desc : Check address/size alignment of a table or page.
+ */
+static void sanity_check(uint64_t addr, uint64_t size)
+{
+	assert(!(addr & GRANULE_SIZE_MASK) &&
+	       !(size & GRANULE_SIZE_MASK) &&
+	       (addr + size < (1ULL << BITS_PER_VA)) &&
+	       size >= GRANULE_SIZE);
+}
+
+/* Func : get_pte
+ * Desc : Returns the page table entry governing a specific address. */
+static uint64_t get_pte(uint64_t addr)
+{
+	int shift = L0_ADDR_SHIFT;
+	/* Using pointer here is OK, as _ttb must be in 32bit space */
+	uint64_t *pte = (uint64_t *)ttb();
+	printk(BIOS_DEBUG, "%llx ", addr);
+
+	while (1) {
+		int index = ((uintptr_t)addr >> shift) &
+			    ((1ULL << BITS_RESOLVED_PER_LVL) - 1);
+
+		switch ((pte[index] & AVAIL_MASK) >> AVAIL_SHIFT) {
+			case AVAIL_INVAL:
+				printk(BIOS_DEBUG, "INVAL ");break;
+			case AVAIL_TABLE:
+				printk(BIOS_DEBUG, "TABLE @ %llx\n", pte[index] & XLAT_ADDR_MASK);break;
+			case AVAIL_PAGE:
+				printk(BIOS_DEBUG, "PAGE %llx, %llx %llx\n", pte[index] & ((XLAT_ADDR_MASK<<1)),
+			(pte[index] & ((XLAT_ADDR_MASK<<1))) + (1ULL << shift) -1,pte[index] & 0xfff);break;
+
+			case AVAIL_BLOCK:
+			printk(BIOS_DEBUG, "BLOCK %llx, %llx %llx\n", pte[index] & ((XLAT_ADDR_MASK<<1)),
+			(pte[index] & ((XLAT_ADDR_MASK<<1))) + (1ULL << shift) -1,pte[index] & 0xfff);break;
+		}
+		//printk(BIOS_DEBUG, "pte[%d] =%llx\n", index, pte[index]);
+		if ((pte[index] & DESC_MASK) != TABLE_DESC ||
+		    shift <= GRANULE_SIZE_SHIFT)
+			return pte[index];
+
+		pte = (uint64_t *)(uintptr_t)(pte[index] & XLAT_ADDR_MASK);
+		shift -= BITS_RESOLVED_PER_LVL;
+	}
+}
+
+/* Func : assert_correct_ttb_mapping
+ * Desc : Asserts that mapping for addr matches the access type used by the
+ * page table walk (i.e. addr is correctly mapped to be part of the TTB). */
+static void assert_correct_ttb_mapping(uint64_t addr)
+{
+	return;
+
+	uint64_t pte = get_pte(addr);
+	assert(((pte >> BLOCK_INDEX_SHIFT) & BLOCK_INDEX_MASK)
+	       == BLOCK_INDEX_MEM_NORMAL);
+}
+
+/* Func : mmu_config_range
+ * Desc : This function repeatedly calls init_xlat_table with the base
+ * address. Based on size returned from init_xlat_table, base_addr is updated
+ * and subsequent calls are made for initializing the xlat table until the whole
+ * region is initialized.
+ */
+void mmu_config_range(uint64_t start, uint64_t size, uint64_t tag)
+{
+	uint64_t base_addr = start;
+	uint64_t temp_size = size;
+
+	printk(BIOS_INFO, "Mapping address range [0x%llx:0x%llx) as ",
+	       start, start + size);
+	print_tag(BIOS_INFO, tag);
+
+	sanity_check(base_addr, temp_size);
+
+	while (temp_size)
+		temp_size -= init_xlat_table(base_addr + (size - temp_size),
+					     temp_size, tag);
+
+}
+
+/* Func : mmu_init
+ * Desc : Initialize MMU registers and page table memory region. This must be
+ * called exactly ONCE PER BOOT before trying to configure any mappings.
+ */
+void mmu_init(void)
+{
+	next_free_table = cbmem_find(CBMEM_ID_TTB);
+	if (!next_free_table)
+		next_free_table = cbmem_add(CBMEM_ID_TTB, CONFIG_TTB_SIZE_KB * 1024);
+	if (!next_free_table)
+		die("Could not allocate memory for TTB\n");
+
+	/* Initially mark all table slots unused (first PTE == UNUSED_DESC). */
+	uint64_t *table = (uint64_t *)ttb();
+	for (; ettb() - (u8 *)table > 0; table += GRANULE_SIZE/sizeof(*table))
+		table[0] = UNUSED_DESC;
+
+	printk(BIOS_DEBUG, "Initialize the root table (L0)\n");
+	/* Initialize the root table (L0) to be completely unmapped. */
+	uint64_t *root = setup_new_table(INVALID_DESC, L0_XLAT_SIZE);
+	assert((u8 *)root == ttb());
+}
+
+/* Func : mmu_install_pagetables
+ * Desc : Install page tables, enable PAE and enable long mode.
+ * It does not enable paging and thus does not activate long mode!
+ */
+void mmu_install_pagetables(void)
+{
+	assert_correct_ttb_mapping((uintptr_t)ttb());
+	assert_correct_ttb_mapping((uintptr_t)ettb() - 1);
+
+	unsigned long long i;
+	for (i = 0x407a0000; i < 0x408a0000; i += (1024 * 1024)) {
+		uint64_t pte = get_pte(i);
+		if (pte == 5)
+			break;
+	}
+	/* Load the page table address */
+	write_cr3((uintptr_t)cbmem_find(CBMEM_ID_TTB));
+
+	printk(BIOS_INFO, "MMU: installed page tables\n");
+
+	CRx_TYPE cr0;
+	CRx_TYPE cr4;
+
+	/* Disable Paging */
+	cr0 = read_cr0();
+	cr0 &= ~CR0_PG;
+	write_cr0(cr0);
+
+	/* Enable PAE */
+	cr4 = read_cr4();
+	cr4 |= CR4_PAE;
+	write_cr4(cr4);
+
+	printk(BIOS_INFO, "MMU: enabled PAE\n");
+
+	#define MSR_EFER		0xc0000080 /* extended feature register */
+
+	/* Set the LM-bit */
+	msr_t msr = rdmsr(MSR_EFER);
+	msr.lo |= (1 << 8);
+	wrmsr(MSR_EFER, msr);
+
+	printk(BIOS_INFO, "MMU: enabled long mode\n");
+
+	/*
+	 * Paging isn't enabled here!
+	 * c_start.S will enable it to enter long mode.
+	 */
+}
diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h
index 042ea6e..366cb3e 100644
--- a/src/commonlib/include/commonlib/cbmem_id.h
+++ b/src/commonlib/include/commonlib/cbmem_id.h
@@ -62,6 +62,7 @@
 #define CBMEM_ID_STAGEx_CACHE	0x57a9e100
 #define CBMEM_ID_STAGEx_RAW	0x57a9e200
 #define CBMEM_ID_STORAGE_DATA	0x53746f72
+#define CBMEM_ID_TTB		0x54544200
 #define CBMEM_ID_TCPA_LOG	0x54435041
 #define CBMEM_ID_TCPA_TCG_LOG	0x54445041
 #define CBMEM_ID_TIMESTAMP	0x54494d45
diff --git a/src/cpu/qemu-x86/Kconfig b/src/cpu/qemu-x86/Kconfig
index 70cce9b..a90acf6 100644
--- a/src/cpu/qemu-x86/Kconfig
+++ b/src/cpu/qemu-x86/Kconfig
@@ -18,7 +18,8 @@
 	select ARCH_BOOTBLOCK_X86_32
 	select ARCH_VERSTAGE_X86_32
 	select ARCH_ROMSTAGE_X86_32
-	select ARCH_RAMSTAGE_X86_32
+	#select ARCH_RAMSTAGE_X86_32
+	select ARCH_RAMSTAGE_X86_64
 	select SMP
 	select UDELAY_TSC
 	select C_ENVIRONMENT_BOOTBLOCK
diff --git a/src/cpu/x86/Makefile.inc b/src/cpu/x86/Makefile.inc
index 3e8a664..1c9b83e 100644
--- a/src/cpu/x86/Makefile.inc
+++ b/src/cpu/x86/Makefile.inc
@@ -4,7 +4,7 @@
 endif
 endif
 
-subdirs-y += pae
+#subdirs-y += pae
 subdirs-$(CONFIG_PARALLEL_MP) += name
 ramstage-$(CONFIG_PARALLEL_MP) += mp_init.c
 ramstage-$(CONFIG_MIRROR_PAYLOAD_TO_RAM_BEFORE_LOADING) += mirror_payload.c
diff --git a/src/lib/timestamp.c b/src/lib/timestamp.c
index 105b696..e2c7450 100644
--- a/src/lib/timestamp.c
+++ b/src/lib/timestamp.c
@@ -178,7 +178,7 @@
 	tse->entry_stamp = ts_time - ts_table->base_time;
 
 	if (IS_ENABLED(CONFIG_TIMESTAMPS_ON_CONSOLE))
-		printk(BIOS_SPEW, "Timestamp - %s: %" PRIu64 "\n",
+		printk(BIOS_SPEW, "Timestamp - %s: %llu\n",
 				timestamp_name(id), ts_time);
 
 	if (ts_table->num_entries == ts_table->max_entries)
diff --git a/src/mainboard/emulation/qemu-q35/Kconfig b/src/mainboard/emulation/qemu-q35/Kconfig
index 3be034a..f14867b 100644
--- a/src/mainboard/emulation/qemu-q35/Kconfig
+++ b/src/mainboard/emulation/qemu-q35/Kconfig
@@ -12,6 +12,7 @@
 	select MAINBOARD_HAS_NATIVE_VGA_INIT
 	select MAINBOARD_FORCE_NATIVE_VGA_INIT
 	select BOOTBLOCK_CONSOLE
+	select IDT_IN_EVERY_STAGE
 
 config MAINBOARD_DIR
 	string
diff --git a/src/mainboard/emulation/qemu-q35/Makefile.inc b/src/mainboard/emulation/qemu-q35/Makefile.inc
index 1503220..65b8e70 100644
--- a/src/mainboard/emulation/qemu-q35/Makefile.inc
+++ b/src/mainboard/emulation/qemu-q35/Makefile.inc
@@ -2,4 +2,6 @@
 ramstage-y += ../qemu-i440fx/memory.c
 ramstage-y += ../qemu-i440fx/fw_cfg.c
 romstage-y += ../qemu-i440fx/memory.c
+romstage-y += ../../../arch/x86/mmu.c
+
 bootblock-y += bootblock.c
diff --git a/src/mainboard/emulation/qemu-q35/romstage.c b/src/mainboard/emulation/qemu-q35/romstage.c
index 2b8d935..592d33d 100644
--- a/src/mainboard/emulation/qemu-q35/romstage.c
+++ b/src/mainboard/emulation/qemu-q35/romstage.c
@@ -21,15 +21,27 @@
 #include <timestamp.h>
 #include <southbridge/intel/i82801ix/i82801ix.h>
 #include <program_loading.h>
+#include <arch/mmu.h>
+#include <arch/exception.h>
+
+#include "../qemu-i440fx/memory.h"
 
 asmlinkage void car_stage_entry(void)
 {
 	i82801ix_early_init();
 	console_init();
+	exception_init();
 
-	cbmem_recovery(0);
+	cbmem_initialize_empty();
 
 	timestamp_add_now(TS_START_ROMSTAGE);
 
+	mmu_init();
+	mmu_config_range(0, 0x100000000ULL, PAT_WT);
+	mmu_config_range(0, (uint64_t)qemu_get_memory_size() * 1024ULL, PAT_WB);
+	if (qemu_get_high_memory_size() > 0)
+		mmu_config_range(0x100000000ULL, (uint64_t)qemu_get_high_memory_size() * 1024ULL, PAT_WB);
+	mmu_install_pagetables();
+
 	run_ramstage();
 }
diff --git a/src/southbridge/intel/common/smi.c b/src/southbridge/intel/common/smi.c
index 3c25556..b543b8b 100644
--- a/src/southbridge/intel/common/smi.c
+++ b/src/southbridge/intel/common/smi.c
@@ -150,7 +150,7 @@
 		"outb %%al, %%dx\n\t"
 		: /* ignore result */
 		: "a" (APM_CNT_GNVS_UPDATE),
-		  "b" ((u32)gnvs),
+		  "b" ((u32)(uintptr_t)gnvs),
 		  "d" (APM_CNT)
 	);
 }
diff --git a/src/southbridge/intel/i82801ix/hdaudio.c b/src/southbridge/intel/i82801ix/hdaudio.c
index 607604b..b4cee46 100644
--- a/src/southbridge/intel/i82801ix/hdaudio.c
+++ b/src/southbridge/intel/i82801ix/hdaudio.c
@@ -278,7 +278,7 @@
 	// NOTE this will break as soon as the Azalia get's a bar above
 	// 4G. Is there anything we can do about it?
 	base = res2mmio(res, 0, 0);
-	printk(BIOS_DEBUG, "Azalia: base = %08x\n", (u32)base);
+	printk(BIOS_DEBUG, "Azalia: base = %p\n", base);
 	codec_mask = codec_detect(base);
 
 	if (codec_mask) {
diff --git a/src/southbridge/intel/i82801ix/lpc.c b/src/southbridge/intel/i82801ix/lpc.c
index a69b879..5d7a226c 100644
--- a/src/southbridge/intel/i82801ix/lpc.c
+++ b/src/southbridge/intel/i82801ix/lpc.c
@@ -553,7 +553,7 @@
 
 		/* Add it to SSDT.  */
 		acpigen_write_scope("\\");
-		acpigen_write_name_dword("NVSA", (u32) gnvs);
+		acpigen_write_name_dword("NVSA", (u32) (uintptr_t)gnvs);
 		acpigen_pop_len();
 	}
 }
diff --git a/src/southbridge/intel/i82801ix/sata.c b/src/southbridge/intel/i82801ix/sata.c
index dcdeeb4..71030948 100644
--- a/src/southbridge/intel/i82801ix/sata.c
+++ b/src/southbridge/intel/i82801ix/sata.c
@@ -32,7 +32,7 @@
 	u32 reg32;
 
 	/* Initialize AHCI memory-mapped space */
-	u8 *abar = (u8 *)pci_read_config32(dev, PCI_BASE_ADDRESS_5);
+	u8 *abar = (u8 *)(uintptr_t)pci_read_config32(dev, PCI_BASE_ADDRESS_5);
 	printk(BIOS_DEBUG, "ABAR: %p\n", abar);
 
 	/* Set AHCI access mode.
diff --git a/util/cbfstool/elf.h b/util/cbfstool/elf.h
index a0bb35d..43fd7f3 100644
--- a/util/cbfstool/elf.h
+++ b/util/cbfstool/elf.h
@@ -1148,6 +1148,43 @@
 /* Keep this the last entry.  */
 #define R_386_NUM	   38
 
+/* AMD64 specific definitions. */
+#define	R_AMD64_NONE		0	/* relocation types */
+#define	R_AMD64_64		1
+#define	R_AMD64_PC32		2
+#define	R_AMD64_GOT32		3
+#define	R_AMD64_PLT32		4
+#define	R_AMD64_COPY		5
+#define	R_AMD64_GLOB_DAT	6
+#define	R_AMD64_JUMP_SLOT	7
+#define	R_AMD64_RELATIVE	8
+#define	R_AMD64_GOTPCREL	9
+#define	R_AMD64_32		10
+#define	R_AMD64_32S		11
+#define	R_AMD64_16		12
+#define	R_AMD64_PC16		13
+#define	R_AMD64_8		14
+#define	R_AMD64_PC8		15
+#define	R_AMD64_DTPMOD64	16
+#define	R_AMD64_DTPOFF64	17
+#define	R_AMD64_TPOFF64		18
+#define	R_AMD64_TLSGD		19
+#define	R_AMD64_TLSLD		20
+#define	R_AMD64_DTPOFF32	21
+#define	R_AMD64_GOTTPOFF	22
+#define	R_AMD64_TPOFF32		23
+#define	R_AMD64_PC64		24
+#define	R_AMD64_GOTOFF64	25
+#define	R_AMD64_GOTPC32		26
+#define	R_AMD64_GOT64		27	/* reserved for future expansion */
+#define	R_AMD64_GOTPCREL64	28	/* reserved for future expansion */
+#define	R_AMD64_GOTPC64		29	/* reserved for future expansion */
+#define	R_AMD64_GOTPLT64	30	/* reserved for future expansion */
+#define	R_AMD64_PLTOFF64	31	/* reserved for future expansion */
+#define	R_AMD64_SIZE32		32
+#define	R_AMD64_SIZE64		33
+#define	R_AMD64_NUM	34
+
 /* SUN SPARC specific definitions.  */
 
 /* Legal values for ST_TYPE subfield of st_info (symbol type).  */
diff --git a/util/cbfstool/elfheaders.c b/util/cbfstool/elfheaders.c
index 9d02c30..8da54d0 100644
--- a/util/cbfstool/elfheaders.c
+++ b/util/cbfstool/elfheaders.c
@@ -1072,6 +1072,9 @@
 	case EM_386:
 		type = R_386_32;
 		break;
+	case EM_X86_64:
+		type =  R_AMD64_64;
+		break;
 	case EM_ARM:
 		type = R_ARM_ABS32;
 		break;
diff --git a/util/cbfstool/rmodule.c b/util/cbfstool/rmodule.c
index 07957cb..b7969c9 100644
--- a/util/cbfstool/rmodule.c
+++ b/util/cbfstool/rmodule.c
@@ -43,6 +43,29 @@
 	return (type == R_386_32);
 }
 
+static int valid_reloc_amd64(Elf64_Rela *rel)
+{
+	int type;
+
+	type = ELF64_R_TYPE(rel->r_info);
+
+	/* Only these 2 relocations are expected to be found. */
+	return (type == R_AMD64_64 ||
+		type == R_AMD64_PC64 ||
+		type == R_AMD64_32S ||
+		type == R_AMD64_32 ||
+		type == R_AMD64_PC32);
+}
+
+static int should_emit_amd64(Elf64_Rela *rel)
+{
+	int type;
+
+	type = ELF64_R_TYPE(rel->r_info);
+
+	return (type == R_AMD64_64);
+}
+
 static int valid_reloc_arm(Elf64_Rela *rel)
 {
 	int type;
@@ -100,6 +123,11 @@
 		.should_emit = should_emit_386,
 	},
 	{
+		.arch = EM_X86_64,
+		.valid_type = valid_reloc_amd64,
+		.should_emit = should_emit_amd64,
+	},
+	{
 		.arch = EM_ARM,
 		.valid_type = valid_reloc_arm,
 		.should_emit = should_emit_arm,
diff --git a/util/xcompile/xcompile b/util/xcompile/xcompile
index 6d82a4d..60d8a39 100755
--- a/util/xcompile/xcompile
+++ b/util/xcompile/xcompile
@@ -236,7 +236,13 @@
 # The Quark processor doesn't support the instructions
 # introduced with the Pentium 6 architecture, so allow it
 # to use i586 instead.
-if [ "${TARCH}" = "x86_64" ] || [ "${TARCH}" = "x86_32" ]; then
+if [ "${TARCH}" = "x86_64" ]; then
+cat <<EOF
+        GCC_CFLAGS_${TARCH} += -march=core2
+EOF
+fi
+
+if [ "${TARCH}" = "x86_32" ]; then
 cat <<EOF
 
 ifneq (\$(CONFIG_USE_MARCH_586)\$(CONFIG_LP_USE_MARCH_586),)

-- 
To view, visit https://review.coreboot.org/29667
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: If2f02a95b2f91ab51043d4e81054354f4a6eb5d5
Gerrit-Change-Number: 29667
Gerrit-PatchSet: 1
Gerrit-Owner: Patrick Rudolph <patrick.rudolph at 9elements.com>
Gerrit-Reviewer: Patrick Rudolph <siro at das-labor.org>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20181117/eba871ed/attachment-0001.html>


More information about the coreboot-gerrit mailing list