9
0
Fork 0

ppc: bootm: relocate fdt to valid boot memory

For the MPC85xx family of SOCs Linux expects any boot firmware
information to be passed in the first 64MiB of memory. This adds support
to ensure that the device tree is relocated to a valid location if it is
outside that address range.

For the other SOC family currently present in the ppc architecture, the
default is not to relocate as at Linux startup the virtual address
equals the physical address.

Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Renaud Barbier 2013-09-06 11:53:12 +01:00 committed by Sascha Hauer
parent 91a68050e1
commit 9d2745425e
2 changed files with 51 additions and 1 deletions

View File

@ -966,8 +966,11 @@ struct cpu_type {
struct cpu_type *identify_cpu(u32 ver);
#if defined(CONFIG_MPC85xx)
#define LINUX_TLB1_MAX_ADDR ((void *)(64 << 20))
#define CPU_TYPE_ENTRY(n, v, nc) \
{ .name = #n, .soc_ver = SVR_##v, .num_cores = (nc), }
#else
#define LINUX_TLB1_MAX_ADDR ((void *)0xffffffff)
#endif
#ifndef CONFIG_MACH_SPECIFIC
extern int _machine;

View File

@ -4,12 +4,45 @@
#include <command.h>
#include <image.h>
#include <init.h>
#include <malloc.h>
#include <environment.h>
#include <asm/bitops.h>
#include <asm/processor.h>
#include <boot.h>
#include <errno.h>
#include <fs.h>
static int bootm_relocate_fdt(void *addr, struct image_data *data)
{
if (addr < LINUX_TLB1_MAX_ADDR) {
/* The kernel is within the boot TLB mapping.
* Put the DTB above if there is no space
* below.
*/
if (addr < (void *)data->oftree->totalsize) {
addr = (void *)PAGE_ALIGN((phys_addr_t)addr +
data->os->header.ih_size);
addr += data->oftree->totalsize;
if (addr < LINUX_TLB1_MAX_ADDR)
addr = LINUX_TLB1_MAX_ADDR;
}
}
if (addr > LINUX_TLB1_MAX_ADDR) {
pr_crit("Unable to relocate DTB to Linux TLB\n");
return 1;
}
addr = (void *)PAGE_ALIGN_DOWN((phys_addr_t)addr -
data->oftree->totalsize);
memcpy(addr, data->oftree, data->oftree->totalsize);
free(data->oftree);
data->oftree = addr;
pr_info("Relocating device tree to 0x%p\n", addr);
return 0;
}
static int do_bootm_linux(struct image_data *data)
{
void (*kernel)(void *, void *, unsigned long,
@ -24,6 +57,20 @@ static int do_bootm_linux(struct image_data *data)
return -EINVAL;
}
/* Relocate the device tree if outside the initial
* Linux mapped TLB.
*/
if (IS_ENABLED(CONFIG_MPC85xx)) {
void *addr = data->oftree;
if ((addr + data->oftree->totalsize) > LINUX_TLB1_MAX_ADDR) {
addr = (void *)data->os_address;
if (bootm_relocate_fdt(addr, data))
goto error;
}
}
fdt_add_reserve_map(data->oftree);
kernel = (void *)(data->os_address + data->os_entry);
@ -40,7 +87,7 @@ static int do_bootm_linux(struct image_data *data)
reset_cpu(0);
/* not reached */
error:
return -1;
}