Merge branch 'for-next/bootm'
This commit is contained in:
commit
ca10989374
|
@ -22,45 +22,61 @@
|
|||
#include <asm/armlinux.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
static int __do_bootm_linux(struct image_data *data, int swap)
|
||||
/*
|
||||
* sdram_start_and_size() - determine place for putting the kernel/oftree/initrd
|
||||
*
|
||||
* @start: returns the start address of the first RAM bank
|
||||
* @size: returns the usable space at the beginning of the first RAM bank
|
||||
*
|
||||
* This function returns the base address of the first RAM bank and the free
|
||||
* space found there.
|
||||
*
|
||||
* return: 0 for success, negative error code otherwise
|
||||
*/
|
||||
static int sdram_start_and_size(unsigned long *start, unsigned long *size)
|
||||
{
|
||||
struct memory_bank *bank;
|
||||
struct resource *res;
|
||||
|
||||
/*
|
||||
* We use the first memory bank for the kernel and other resources
|
||||
*/
|
||||
bank = list_first_entry_or_null(&memory_banks, struct memory_bank,
|
||||
list);
|
||||
if (!bank) {
|
||||
printf("cannot find first memory bank\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the first memory bank has child resources we can use the bank up
|
||||
* to the beginning of the first child resource, otherwise we can use
|
||||
* the whole bank.
|
||||
*/
|
||||
res = list_first_entry_or_null(&bank->res->children, struct resource,
|
||||
sibling);
|
||||
if (res)
|
||||
*size = res->start - bank->start;
|
||||
else
|
||||
*size = bank->size;
|
||||
|
||||
*start = bank->start;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int swap)
|
||||
{
|
||||
unsigned long kernel;
|
||||
unsigned long initrd_start = 0, initrd_size = 0, initrd_end = 0;
|
||||
struct memory_bank *bank;
|
||||
unsigned long load_address;
|
||||
|
||||
if (data->os_res) {
|
||||
load_address = data->os_res->start;
|
||||
} else if (data->os_address != UIMAGE_INVALID_ADDRESS) {
|
||||
load_address = data->os_address;
|
||||
} else {
|
||||
bank = list_first_entry(&memory_banks,
|
||||
struct memory_bank, list);
|
||||
load_address = bank->start + SZ_32K;
|
||||
if (bootm_verbose(data))
|
||||
printf("no os load address, defaulting to 0x%08lx\n",
|
||||
load_address);
|
||||
}
|
||||
|
||||
if (!data->os_res && data->os) {
|
||||
data->os_res = uimage_load_to_sdram(data->os,
|
||||
data->os_num, load_address);
|
||||
if (!data->os_res)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!data->os_res) {
|
||||
data->os_res = file_to_sdram(data->os_file, load_address);
|
||||
if (!data->os_res)
|
||||
return -ENOMEM;
|
||||
}
|
||||
int ret;
|
||||
|
||||
kernel = data->os_res->start + data->os_entry;
|
||||
|
||||
initrd_start = data->initrd_address;
|
||||
|
||||
if (data->initrd_file && initrd_start == UIMAGE_INVALID_ADDRESS) {
|
||||
initrd_start = data->os_res->start + SZ_8M;
|
||||
if (initrd_start == UIMAGE_INVALID_ADDRESS) {
|
||||
initrd_start = PAGE_ALIGN(free_mem);
|
||||
|
||||
if (bootm_verbose(data)) {
|
||||
printf("no initrd load address, defaulting to 0x%08lx\n",
|
||||
|
@ -68,33 +84,20 @@ static int __do_bootm_linux(struct image_data *data, int swap)
|
|||
}
|
||||
}
|
||||
|
||||
if (data->initrd) {
|
||||
data->initrd_res = uimage_load_to_sdram(data->initrd,
|
||||
data->initrd_num, initrd_start);
|
||||
if (!data->initrd_res)
|
||||
return -ENOMEM;
|
||||
} else if (data->initrd_file) {
|
||||
data->initrd_res = file_to_sdram(data->initrd_file, initrd_start);
|
||||
if (!data->initrd_res)
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = bootm_load_initrd(data, initrd_start);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (data->initrd_res) {
|
||||
initrd_start = data->initrd_res->start;
|
||||
initrd_end = data->initrd_res->end;
|
||||
initrd_size = resource_size(data->initrd_res);
|
||||
free_mem = PAGE_ALIGN(initrd_end);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_OFTREE) && data->of_root_node) {
|
||||
of_add_initrd(data->of_root_node, initrd_start, initrd_end);
|
||||
if (initrd_end)
|
||||
of_add_reserve_entry(initrd_start, initrd_end);
|
||||
data->oftree = of_get_fixed_tree(data->of_root_node);
|
||||
fdt_add_reserve_map(data->oftree);
|
||||
of_print_cmdline(data->of_root_node);
|
||||
if (bootm_verbose(data) > 1)
|
||||
of_print_nodes(data->of_root_node, 0);
|
||||
}
|
||||
ret = bootm_load_devicetree(data, free_mem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (bootm_verbose(data)) {
|
||||
printf("\nStarting kernel at 0x%08lx", kernel);
|
||||
|
@ -114,7 +117,36 @@ static int __do_bootm_linux(struct image_data *data, int swap)
|
|||
|
||||
static int do_bootm_linux(struct image_data *data)
|
||||
{
|
||||
return __do_bootm_linux(data, 0);
|
||||
unsigned long load_address, mem_start, mem_size, mem_free;
|
||||
int ret;
|
||||
|
||||
ret = sdram_start_and_size(&mem_start, &mem_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
load_address = data->os_address;
|
||||
|
||||
if (load_address == UIMAGE_INVALID_ADDRESS) {
|
||||
load_address = mem_start + SZ_32K;
|
||||
if (bootm_verbose(data))
|
||||
printf("no os load address, defaulting to 0x%08lx\n",
|
||||
load_address);
|
||||
}
|
||||
|
||||
ret = bootm_load_os(data, load_address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Put devicetree/initrd at maximum to 128MiB into RAM to not
|
||||
* risk to put it outside of lowmem.
|
||||
*/
|
||||
if (mem_size > SZ_256M)
|
||||
mem_free = mem_start + SZ_128M;
|
||||
else
|
||||
mem_free = PAGE_ALIGN(data->os_res->end + SZ_1M);
|
||||
|
||||
return __do_bootm_linux(data, mem_free, 0);
|
||||
}
|
||||
|
||||
static struct image_handler uimage_handler = {
|
||||
|
@ -207,11 +239,23 @@ static int do_bootz_linux(struct image_data *data)
|
|||
void *zimage;
|
||||
u32 end;
|
||||
unsigned long load_address = data->os_address;
|
||||
unsigned long mem_start, mem_size, mem_free;
|
||||
|
||||
ret = sdram_start_and_size(&mem_start, &mem_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (load_address == UIMAGE_INVALID_ADDRESS) {
|
||||
struct memory_bank *bank = list_first_entry(&memory_banks,
|
||||
struct memory_bank, list);
|
||||
data->os_address = bank->start + SZ_8M;
|
||||
/*
|
||||
* The kernel should stay in the first 128MiB of RAM, recommended
|
||||
* is 32MiB into RAM so that relocation prior to decompression
|
||||
* can be avoided.
|
||||
*/
|
||||
if (mem_size > SZ_64M)
|
||||
data->os_address = mem_start + SZ_32M;
|
||||
else
|
||||
data->os_address = mem_start + SZ_8M;
|
||||
|
||||
load_address = data->os_address;
|
||||
if (bootm_verbose(data))
|
||||
printf("no os load address, defaulting to 0x%08lx\n",
|
||||
|
@ -280,7 +324,17 @@ static int do_bootz_linux(struct image_data *data)
|
|||
goto err_out;
|
||||
|
||||
close(fd);
|
||||
return __do_bootm_linux(data, swap);
|
||||
|
||||
/*
|
||||
* Put devicetree/initrd at maximum to 128MiB into RAM to not
|
||||
* risk to put it outside of lowmem.
|
||||
*/
|
||||
if (mem_size > SZ_256M)
|
||||
mem_free = mem_start + SZ_128M;
|
||||
else
|
||||
mem_free = PAGE_ALIGN(data->os_res->end + SZ_1M);
|
||||
|
||||
return __do_bootm_linux(data, mem_free, swap);
|
||||
|
||||
err_out:
|
||||
close(fd);
|
||||
|
@ -355,6 +409,7 @@ static int do_bootm_aimage(struct image_data *data)
|
|||
void *buf;
|
||||
int to_read;
|
||||
struct android_header_comp *cmp;
|
||||
unsigned long mem_free;
|
||||
|
||||
fd = open(data->os_file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
|
@ -448,7 +503,17 @@ static int do_bootm_aimage(struct image_data *data)
|
|||
}
|
||||
|
||||
close(fd);
|
||||
return __do_bootm_linux(data, 0);
|
||||
|
||||
/*
|
||||
* Put devicetree right after initrd if present or after the kernel
|
||||
* if not.
|
||||
*/
|
||||
if (data->initrd_res)
|
||||
mem_free = PAGE_ALIGN(data->initrd_res->end);
|
||||
else
|
||||
mem_free = PAGE_ALIGN(data->os_res->end + SZ_1M);
|
||||
|
||||
return __do_bootm_linux(data, mem_free, 0);
|
||||
|
||||
err_out:
|
||||
linux_bootargs_overwrite(NULL);
|
||||
|
|
|
@ -41,9 +41,11 @@ static int do_bootm_linux(struct image_data *idata)
|
|||
int (*appl)(char *cmdline);
|
||||
const char *cmdline = linux_bootargs_get();
|
||||
char *cmdlinedest = (char *) CMD_LINE_ADDR;
|
||||
int ret;
|
||||
|
||||
if (!idata->os_res)
|
||||
return -EINVAL;
|
||||
ret = bootm_load_os(idata, idata->os_address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
appl = (void *)(idata->os_address + idata->os_entry);
|
||||
printf("Starting Kernel at 0x%p\n", appl);
|
||||
|
|
|
@ -36,9 +36,11 @@ static int do_bootm_linux(struct image_data *idata)
|
|||
{
|
||||
void (*kernel)(int, int, int, const char *);
|
||||
const char *commandline = linux_bootargs_get();
|
||||
int ret;
|
||||
|
||||
if (!idata->os_res)
|
||||
return -EINVAL;
|
||||
ret = bootm_load_os(idata, idata->os_address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
kernel = (void *)(idata->os_address + idata->os_entry);
|
||||
|
||||
|
|
|
@ -47,9 +47,11 @@ static int do_bootm_linux(struct image_data *data)
|
|||
{
|
||||
void (*kernel)(void *, void *, unsigned long,
|
||||
unsigned long, unsigned long);
|
||||
int ret;
|
||||
|
||||
if (!data->os_res)
|
||||
return -EINVAL;
|
||||
ret = bootm_load_os(data, data->os_address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->oftree = of_get_fixed_tree(data->of_root_node);
|
||||
if (!data->oftree) {
|
||||
|
|
150
common/bootm.c
150
common/bootm.c
|
@ -45,6 +45,145 @@ static struct image_handler *bootm_find_handler(enum filetype filetype,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* bootm_load_os() - load OS to RAM
|
||||
*
|
||||
* @data: image data context
|
||||
* @load_address: The address where the OS should be loaded to
|
||||
*
|
||||
* This loads the OS to a RAM location. load_address must be a valid
|
||||
* address. If the image_data doesn't have a OS specified it's considered
|
||||
* an error.
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise
|
||||
*/
|
||||
int bootm_load_os(struct image_data *data, unsigned long load_address)
|
||||
{
|
||||
if (data->os_res)
|
||||
return 0;
|
||||
|
||||
if (load_address == UIMAGE_INVALID_ADDRESS)
|
||||
return -EINVAL;
|
||||
|
||||
if (data->os) {
|
||||
data->os_res = uimage_load_to_sdram(data->os,
|
||||
data->os_num, load_address);
|
||||
if (!data->os_res)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data->os_file) {
|
||||
data->os_res = file_to_sdram(data->os_file, load_address);
|
||||
if (!data->os_res)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* bootm_load_initrd() - load initrd to RAM
|
||||
*
|
||||
* @data: image data context
|
||||
* @load_address: The address where the initrd should be loaded to
|
||||
*
|
||||
* This loads the initrd to a RAM location. load_address must be a valid
|
||||
* address. If the image_data doesn't have a initrd specified this function
|
||||
* still returns successful as an initrd is optional. Check data->initrd_res
|
||||
* to see if an initrd has been loaded.
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise
|
||||
*/
|
||||
int bootm_load_initrd(struct image_data *data, unsigned long load_address)
|
||||
{
|
||||
if (data->initrd_res)
|
||||
return 0;
|
||||
|
||||
if (data->initrd) {
|
||||
data->initrd_res = uimage_load_to_sdram(data->initrd,
|
||||
data->initrd_num, load_address);
|
||||
if (!data->initrd_res)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data->initrd_file) {
|
||||
data->initrd_res = file_to_sdram(data->initrd_file, load_address);
|
||||
if (!data->initrd_res)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* bootm_load_devicetree() - load devicetree
|
||||
*
|
||||
* @data: image data context
|
||||
* @load_address: The address where the devicetree should be loaded to
|
||||
*
|
||||
* This loads the devicetree to a RAM location. load_address must be a valid
|
||||
* address. The resulting devicetree will be found at data->oftree.
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise
|
||||
*/
|
||||
int bootm_load_devicetree(struct image_data *data, unsigned long load_address)
|
||||
{
|
||||
int fdt_size;
|
||||
struct fdt_header *oftree;
|
||||
|
||||
if (data->oftree)
|
||||
return 0;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OFTREE))
|
||||
return 0;
|
||||
|
||||
if (!data->of_root_node)
|
||||
return 0;
|
||||
|
||||
if (data->initrd_res) {
|
||||
of_add_initrd(data->of_root_node, data->initrd_res->start,
|
||||
data->initrd_res->end);
|
||||
of_add_reserve_entry(data->initrd_res->start, data->initrd_res->end);
|
||||
}
|
||||
|
||||
oftree = of_get_fixed_tree(data->of_root_node);
|
||||
if (!oftree)
|
||||
return -EINVAL;
|
||||
|
||||
fdt_size = be32_to_cpu(oftree->totalsize);
|
||||
|
||||
data->oftree_res = request_sdram_region("oftree", load_address,
|
||||
fdt_size);
|
||||
if (!data->oftree_res) {
|
||||
free(oftree);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy((void *)data->oftree_res->start, oftree, fdt_size);
|
||||
|
||||
free(oftree);
|
||||
|
||||
oftree = (void *)data->oftree_res->start;
|
||||
|
||||
fdt_add_reserve_map(oftree);
|
||||
|
||||
of_print_cmdline(data->of_root_node);
|
||||
if (bootm_verbose(data) > 1)
|
||||
of_print_nodes(data->of_root_node, 0);
|
||||
|
||||
data->oftree = oftree;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bootm_open_os_uimage(struct image_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
@ -75,15 +214,6 @@ static int bootm_open_os_uimage(struct image_data *data)
|
|||
if (data->os_address == UIMAGE_SOME_ADDRESS)
|
||||
data->os_address = data->os->header.ih_load;
|
||||
|
||||
if (data->os_address != UIMAGE_INVALID_ADDRESS) {
|
||||
data->os_res = uimage_load_to_sdram(data->os, 0,
|
||||
data->os_address);
|
||||
if (!data->os_res) {
|
||||
uimage_close(data->os);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -343,6 +473,8 @@ err_out:
|
|||
release_sdram_region(data->os_res);
|
||||
if (data->initrd_res)
|
||||
release_sdram_region(data->initrd_res);
|
||||
if (data->oftree_res)
|
||||
release_sdram_region(data->oftree_res);
|
||||
if (data->initrd && data->initrd != data->os)
|
||||
uimage_close(data->initrd);
|
||||
if (data->os)
|
||||
|
|
|
@ -61,6 +61,7 @@ struct image_data {
|
|||
|
||||
struct device_node *of_root_node;
|
||||
struct fdt_header *oftree;
|
||||
struct resource *oftree_res;
|
||||
|
||||
int verify;
|
||||
int verbose;
|
||||
|
@ -108,6 +109,10 @@ static inline int linux_bootargs_overwrite(const char *bootargs)
|
|||
}
|
||||
#endif
|
||||
|
||||
int bootm_load_os(struct image_data *data, unsigned long load_address);
|
||||
int bootm_load_initrd(struct image_data *data, unsigned long load_address);
|
||||
int bootm_load_devicetree(struct image_data *data, unsigned long load_address);
|
||||
|
||||
#define UIMAGE_SOME_ADDRESS (UIMAGE_INVALID_ADDRESS - 1)
|
||||
|
||||
#endif /* __BOOT_H */
|
||||
|
|
|
@ -291,6 +291,17 @@ static inline void list_splice_init(struct list_head *list,
|
|||
#define list_last_entry(head, type, member) \
|
||||
list_entry((head)->prev, type, member)
|
||||
|
||||
/**
|
||||
* list_first_entry_or_null - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Note that if the list is empty, it returns NULL.
|
||||
*/
|
||||
#define list_first_entry_or_null(ptr, type, member) \
|
||||
(!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
|
|
Loading…
Reference in New Issue