diff options
Diffstat (limited to 'arch/x86/lib')
| -rw-r--r-- | arch/x86/lib/Makefile | 5 | ||||
| -rw-r--r-- | arch/x86/lib/board.c | 10 | ||||
| -rw-r--r-- | arch/x86/lib/init_helpers.c | 48 | ||||
| -rw-r--r-- | arch/x86/lib/init_wrappers.c | 28 | ||||
| -rw-r--r-- | arch/x86/lib/physmem.c | 228 | ||||
| -rw-r--r-- | arch/x86/lib/relocate.c | 4 | ||||
| -rw-r--r-- | arch/x86/lib/timer.c | 17 | ||||
| -rw-r--r-- | arch/x86/lib/zimage.c | 23 | 
8 files changed, 351 insertions, 12 deletions
| diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 4325b2502..0a52cc896 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -32,7 +32,7 @@ COBJS-y	+= realmode.o  SOBJS-y	+= realmode_switch.o  COBJS-$(CONFIG_SYS_PC_BIOS)	+= bios_setup.o -COBJS-$(CONFIG_VIDEO)	+= video_bios.o +COBJS-$(CONFIG_VIDEO_VGA)	+= video_bios.o  endif  COBJS-y	+= board.o @@ -47,9 +47,10 @@ COBJS-$(CONFIG_SYS_GENERIC_TIMER) += pcat_timer.o  COBJS-$(CONFIG_PCI) += pci.o  COBJS-$(CONFIG_PCI) += pci_type1.o  COBJS-y	+= relocate.o +COBJS-y += physmem.o  COBJS-y	+= string.o  COBJS-$(CONFIG_SYS_X86_ISR_TIMER)	+= timer.o -COBJS-$(CONFIG_VIDEO)	+= video.o +COBJS-$(CONFIG_VIDEO_VGA)	+= video.o  COBJS-$(CONFIG_CMD_ZBOOT)	+= zimage.o  SRCS	:= $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index c7d89604c..22bc26dde 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -99,10 +99,17 @@ typedef int (init_fnc_t) (void);  init_fnc_t *init_sequence_f[] = {  	cpu_init_f,  	board_early_init_f, +#ifdef CONFIG_OF_CONTROL +	find_fdt, +	fdtdec_check_fdt, +#endif  	env_init,  	init_baudrate_f,  	serial_init,  	console_init_f, +#ifdef CONFIG_OF_CONTROL +	prepare_fdt, +#endif  	dram_init_f,  	calculate_relocation_address, @@ -154,6 +161,9 @@ init_fnc_t *init_sequence_r[] = {  #ifndef CONFIG_SYS_NO_FLASH  	flash_init_r,  #endif +#ifdef CONFIG_SPI +	init_func_spi; +#endif  	env_relocate_r,  #ifdef CONFIG_PCI  	pci_init_r, diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c index 87c7263fc..3eec9a61d 100644 --- a/arch/x86/lib/init_helpers.c +++ b/arch/x86/lib/init_helpers.c @@ -28,9 +28,11 @@  #include <net.h>  #include <ide.h>  #include <serial.h> +#include <spi.h>  #include <status_led.h>  #include <asm/processor.h>  #include <asm/u-boot-x86.h> +#include <linux/compiler.h>  #include <asm/init_helpers.h> @@ -71,7 +73,7 @@ int init_baudrate_f(void)  	return 0;  } -int calculate_relocation_address(void) +__weak int calculate_relocation_address(void)  {  	ulong text_start = (ulong)&__text_start;  	ulong bss_end = (ulong)&__bss_end; @@ -85,15 +87,16 @@ int calculate_relocation_address(void)  	/* Stack is at top of available memory */  	dest_addr = gd->ram_size; -	gd->start_addr_sp = dest_addr; -	/* U-Boot is below the stack */ -	dest_addr -= CONFIG_SYS_STACK_SIZE; +	/* U-Boot is at the top */  	dest_addr -= (bss_end - text_start);  	dest_addr &= ~15;  	gd->relocaddr = dest_addr;  	gd->reloc_off = (dest_addr - text_start); +	/* Stack is at the bottom, so it can grow down */ +	gd->start_addr_sp = dest_addr - CONFIG_SYS_MALLOC_LEN; +  	return 0;  } @@ -160,3 +163,40 @@ int set_load_addr_r(void)  	return 0;  } + +int init_func_spi(void) +{ +	puts("SPI:   "); +	spi_init(); +	puts("ready\n"); +	return 0; +} + +#ifdef CONFIG_OF_CONTROL +int find_fdt(void) +{ +#ifdef CONFIG_OF_EMBED +	/* Get a pointer to the FDT */ +	gd->fdt_blob = _binary_dt_dtb_start; +#elif defined CONFIG_OF_SEPARATE +	/* FDT is at end of image */ +	gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE); +#endif +	/* Allow the early environment to override the fdt address */ +	gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, +						(uintptr_t)gd->fdt_blob); + +	return 0; +} + +int prepare_fdt(void) +{ +	/* For now, put this check after the console is ready */ +	if (fdtdec_prepare_fdt()) { +		panic("** CONFIG_OF_CONTROL defined but no FDT - please see " +			"doc/README.fdt-control"); +	} + +	return 0; +} +#endif diff --git a/arch/x86/lib/init_wrappers.c b/arch/x86/lib/init_wrappers.c index 71449fe6f..cca018fa9 100644 --- a/arch/x86/lib/init_wrappers.c +++ b/arch/x86/lib/init_wrappers.c @@ -21,6 +21,7 @@   * MA 02111-1307 USA   */  #include <common.h> +#include <environment.h>  #include <serial.h>  #include <kgdb.h>  #include <scsi.h> @@ -36,10 +37,35 @@ int serial_initialize_r(void)  	return 0;  } +/* + * Tell if it's OK to load the environment early in boot. + * + * If CONFIG_OF_CONFIG is defined, we'll check with the FDT to see + * if this is OK (defaulting to saying it's not OK). + * + * NOTE: Loading the environment early can be a bad idea if security is + *       important, since no verification is done on the environment. + * + * @return 0 if environment should not be loaded, !=0 if it is ok to load + */ +static int should_load_env(void) +{ +#ifdef CONFIG_OF_CONTROL +	return fdtdec_get_config_int(gd->fdt_blob, "load-environment", 0); +#elif defined CONFIG_DELAY_ENVIRONMENT +	return 0; +#else +	return 1; +#endif +} +  int env_relocate_r(void)  {  	/* initialize environment */ -	env_relocate(); +	if (should_load_env()) +		env_relocate(); +	else +		set_default_env(NULL);  	return 0;  } diff --git a/arch/x86/lib/physmem.c b/arch/x86/lib/physmem.c new file mode 100644 index 000000000..18f0e62ac --- /dev/null +++ b/arch/x86/lib/physmem.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#include <common.h> +#include <physmem.h> +#include <linux/compiler.h> + +/* Large pages are 2MB. */ +#define LARGE_PAGE_SIZE ((1 << 20) * 2) + +/* + * Paging data structures. + */ + +struct pdpe { +	uint64_t p:1; +	uint64_t mbz_0:2; +	uint64_t pwt:1; +	uint64_t pcd:1; +	uint64_t mbz_1:4; +	uint64_t avl:3; +	uint64_t base:40; +	uint64_t mbz_2:12; +}; + +typedef struct pdpe pdpt_t[512]; + +struct pde { +	uint64_t p:1;      /* present */ +	uint64_t rw:1;     /* read/write */ +	uint64_t us:1;     /* user/supervisor */ +	uint64_t pwt:1;    /* page-level writethrough */ +	uint64_t pcd:1;    /* page-level cache disable */ +	uint64_t a:1;      /* accessed */ +	uint64_t d:1;      /* dirty */ +	uint64_t ps:1;     /* page size */ +	uint64_t g:1;      /* global page */ +	uint64_t avl:3;    /* available to software */ +	uint64_t pat:1;    /* page-attribute table */ +	uint64_t mbz_0:8;  /* must be zero */ +	uint64_t base:31;  /* base address */ +}; + +typedef struct pde pdt_t[512]; + +static pdpt_t pdpt __aligned(4096); +static pdt_t pdts[4] __aligned(4096); + +/* + * Map a virtual address to a physical address and optionally invalidate any + * old mapping. + * + * @param virt		The virtual address to use. + * @param phys		The physical address to use. + * @param invlpg	Whether to use invlpg to clear any old mappings. + */ +static void x86_phys_map_page(uintptr_t virt, phys_addr_t phys, int invlpg) +{ +	/* Extract the two bit PDPT index and the 9 bit PDT index. */ +	uintptr_t pdpt_idx = (virt >> 30) & 0x3; +	uintptr_t pdt_idx = (virt >> 21) & 0x1ff; + +	/* Set up a handy pointer to the appropriate PDE. */ +	struct pde *pde = &(pdts[pdpt_idx][pdt_idx]); + +	memset(pde, 0, sizeof(struct pde)); +	pde->p = 1; +	pde->rw = 1; +	pde->us = 1; +	pde->ps = 1; +	pde->base = phys >> 21; + +	if (invlpg) { +		/* Flush any stale mapping out of the TLBs. */ +		__asm__ __volatile__( +			"invlpg %0\n\t" +			: +			: "m" (*(uint8_t *)virt) +		); +	} +} + +/* Identity map the lower 4GB and turn on paging with PAE. */ +static void x86_phys_enter_paging(void) +{ +	phys_addr_t page_addr; +	unsigned i; + +	/* Zero out the page tables. */ +	memset(pdpt, 0, sizeof(pdpt)); +	memset(pdts, 0, sizeof(pdts)); + +	/* Set up the PDPT. */ +	for (i = 0; i < ARRAY_SIZE(pdts); i++) { +		pdpt[i].p = 1; +		pdpt[i].base = ((uintptr_t)&pdts[i]) >> 12; +	} + +	/* Identity map everything up to 4GB. */ +	for (page_addr = 0; page_addr < (1ULL << 32); +			page_addr += LARGE_PAGE_SIZE) { +		/* There's no reason to invalidate the TLB with paging off. */ +		x86_phys_map_page(page_addr, page_addr, 0); +	} + +	/* Turn on paging */ +	__asm__ __volatile__( +		/* Load the page table address */ +		"movl	%0, %%cr3\n\t" +		/* Enable pae */ +		"movl	%%cr4, %%eax\n\t" +		"orl	$0x00000020, %%eax\n\t" +		"movl	%%eax, %%cr4\n\t" +		/* Enable paging */ +		"movl	%%cr0, %%eax\n\t" +		"orl	$0x80000000, %%eax\n\t" +		"movl	%%eax, %%cr0\n\t" +		: +		: "r" (pdpt) +		: "eax" +	); +} + +/* Disable paging and PAE mode. */ +static void x86_phys_exit_paging(void) +{ +	/* Turn off paging */ +	__asm__ __volatile__ ( +		/* Disable paging */ +		"movl	%%cr0, %%eax\n\t" +		"andl	$0x7fffffff, %%eax\n\t" +		"movl	%%eax, %%cr0\n\t" +		/* Disable pae */ +		"movl	%%cr4, %%eax\n\t" +		"andl	$0xffffffdf, %%eax\n\t" +		"movl	%%eax, %%cr4\n\t" +		: +		: +		: "eax" +	); +} + +/* + * Set physical memory to a particular value when the whole region fits on one + * page. + * + * @param map_addr	The address that starts the physical page. + * @param offset	How far into that page to start setting a value. + * @param c		The value to set memory to. + * @param size		The size in bytes of the area to set. + */ +static void x86_phys_memset_page(phys_addr_t map_addr, uintptr_t offset, int c, +				 unsigned size) +{ +	/* +	 * U-Boot should be far away from the beginning of memory, so that's a +	 * good place to map our window on top of. +	 */ +	const uintptr_t window = LARGE_PAGE_SIZE; + +	/* Make sure the window is below U-Boot. */ +	assert(window + LARGE_PAGE_SIZE < +	       gd->relocaddr - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_STACK_SIZE); +	/* Map the page into the window and then memset the appropriate part. */ +	x86_phys_map_page(window, map_addr, 1); +	memset((void *)(window + offset), c, size); +} + +/* + * A physical memory anologue to memset with matching parameters and return + * value. + */ +phys_addr_t arch_phys_memset(phys_addr_t start, int c, phys_size_t size) +{ +	const phys_addr_t max_addr = (phys_addr_t)~(uintptr_t)0; +	const phys_addr_t orig_start = start; + +	if (!size) +		return orig_start; + +	/* Handle memory below 4GB. */ +	if (start <= max_addr) { +		phys_size_t low_size = MIN(max_addr + 1 - start, size); +		void *start_ptr = (void *)(uintptr_t)start; + +		assert(((phys_addr_t)(uintptr_t)start) == start); +		memset(start_ptr, c, low_size); +		start += low_size; +		size -= low_size; +	} + +	/* Use paging and PAE to handle memory above 4GB up to 64GB. */ +	if (size) { +		phys_addr_t map_addr = start & ~(LARGE_PAGE_SIZE - 1); +		phys_addr_t offset = start - map_addr; + +		x86_phys_enter_paging(); + +		/* Handle the first partial page. */ +		if (offset) { +			phys_addr_t end = +				MIN(map_addr + LARGE_PAGE_SIZE, start + size); +			phys_size_t cur_size = end - start; +			x86_phys_memset_page(map_addr, offset, c, cur_size); +			size -= cur_size; +			map_addr += LARGE_PAGE_SIZE; +		} +		/* Handle the complete pages. */ +		while (size > LARGE_PAGE_SIZE) { +			x86_phys_memset_page(map_addr, 0, c, LARGE_PAGE_SIZE); +			size -= LARGE_PAGE_SIZE; +			map_addr += LARGE_PAGE_SIZE; +		} +		/* Handle the last partial page. */ +		if (size) +			x86_phys_memset_page(map_addr, 0, c, size); + +		x86_phys_exit_paging(); +	} +	return orig_start; +} diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 200baaba6..23edca952 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -80,12 +80,12 @@ int do_elf_reloc_fixups(void)  			/* Check that the target points into .text */  			if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE && -					*offset_ptr_ram < +					*offset_ptr_ram <=  					(CONFIG_SYS_TEXT_BASE + size)) {  				*offset_ptr_ram += gd->reloc_off;  			}  		} -	} while (re_src++ < re_end); +	} while (++re_src < re_end);  	return 0;  } diff --git a/arch/x86/lib/timer.c b/arch/x86/lib/timer.c index fd7032e92..a13424b3e 100644 --- a/arch/x86/lib/timer.c +++ b/arch/x86/lib/timer.c @@ -37,6 +37,7 @@ struct timer_isr_function {  static struct timer_isr_function *first_timer_isr;  static unsigned long system_ticks; +static uint64_t base_value;  /*   * register_timer_isr() allows multiple architecture and board specific @@ -98,3 +99,19 @@ ulong get_timer(ulong base)  {  	return system_ticks - base;  } + +void timer_set_tsc_base(uint64_t new_base) +{ +	base_value = new_base; +} + +uint64_t timer_get_tsc(void) +{ +	uint64_t time_now; + +	time_now = rdtsc(); +	if (!base_value) +		base_value = time_now; + +	return time_now - base_value; +} diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index b8c672bab..46af391f2 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -36,6 +36,10 @@  #include <asm/realmode.h>  #include <asm/byteorder.h>  #include <asm/bootparam.h> +#ifdef CONFIG_SYS_COREBOOT +#include <asm/arch/timestamp.h> +#endif +#include <linux/compiler.h>  /*   * Memory lay-out: @@ -279,10 +283,23 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,  	return 0;  } +/* + * Implement a weak default function for boards that optionally + * need to clean up the system before jumping to the kernel. + */ +__weak void board_final_cleanup(void) +{ +} +  void boot_zimage(void *setup_base, void *load_address)  { +	board_final_cleanup(); +  	printf("\nStarting kernel ...\n\n"); +#ifdef CONFIG_SYS_COREBOOT +	timestamp_add_now(TS_U_BOOT_START_KERNEL); +#endif  #if defined CONFIG_ZBOOT_32  	/*  	 * Set %ebx, %ebp, and %edi to 0, %esi to point to the boot_params @@ -292,9 +309,9 @@ void boot_zimage(void *setup_base, void *load_address)  	 * itself in arch/i386/cpu/cpu.c.  	 */  	__asm__ __volatile__ ( -	"movl $0, %%ebp		\n" -	"cli			\n" -	"jmp %[kernel_entry]	\n" +	"movl $0, %%ebp\n" +	"cli\n" +	"jmp *%[kernel_entry]\n"  	:: [kernel_entry]"a"(load_address),  	   [boot_params] "S"(setup_base),  	   "b"(0), "D"(0) |