1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#define DEBUG
#include <common.h>
#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 <bootm.h>
#include <errno.h>
#include <restart.h>
#include <fs.h>
static struct fdt_header *bootm_relocate_fdt(struct image_data *data,
struct fdt_header *fdt)
{
void *os = (void *)data->os_address;
void *newfdt;
if (os < LINUX_TLB1_MAX_ADDR) {
/* The kernel is within the boot TLB mapping.
* Put the DTB above if there is no space
* below.
*/
if (os < (void *)fdt->totalsize) {
os = (void *)PAGE_ALIGN((phys_addr_t)os +
data->os->header.ih_size);
os += fdt->totalsize;
if (os < LINUX_TLB1_MAX_ADDR)
os = LINUX_TLB1_MAX_ADDR;
}
}
if (os > LINUX_TLB1_MAX_ADDR) {
pr_crit("Unable to relocate DTB to Linux TLB\n");
return NULL;
}
newfdt = (void *)PAGE_ALIGN_DOWN((phys_addr_t)os - fdt->totalsize);
memcpy(newfdt, fdt, fdt->totalsize);
free(fdt);
pr_info("Relocating device tree to 0x%p\n", newfdt);
return newfdt;
}
static int do_bootm_linux(struct image_data *data)
{
void (*kernel)(void *, void *, unsigned long,
unsigned long, unsigned long);
int ret;
struct fdt_header *fdt;
ret = bootm_load_os(data, data->os_address);
if (ret)
return ret;
fdt = of_get_fixed_tree(data->of_root_node);
if (!fdt) {
pr_err("bootm: No devicetree given.\n");
return -EINVAL;
}
if (data->dryrun)
return 0;
/* Relocate the device tree if outside the initial
* Linux mapped TLB.
*/
if (IS_ENABLED(CONFIG_MPC85xx)) {
if (((void *)fdt + fdt->totalsize) > LINUX_TLB1_MAX_ADDR) {
fdt = bootm_relocate_fdt(data, fdt);
if (!fdt)
goto error;
}
}
fdt_add_reserve_map(fdt);
kernel = (void *)(data->os_address + data->os_entry);
/*
* Linux Kernel Parameters (passing device tree):
* r3: ptr to OF flat tree, followed by the board info data
* r4: physical pointer to the kernel itself
* r5: NULL
* r6: NULL
* r7: NULL
*/
kernel(fdt, kernel, 0, 0, 0);
restart_machine();
error:
return -1;
}
static struct image_handler handler = {
.name = "PowerPC Linux",
.bootm = do_bootm_linux,
.filetype = filetype_uimage,
.ih_os = IH_OS_LINUX,
};
static int ppclinux_register_image_handler(void)
{
return register_image_handler(&handler);
}
late_initcall(ppclinux_register_image_handler);
|