summaryrefslogtreecommitdiff
path: root/arch/kvx/lib/bootm.c
blob: 198eef798090cb411034adcc102555d5176c84a6 (plain)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// SPDX-License-Identifier: GPL-2.0
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2019 Kalray Inc.
 */

#include <elf.h>
#include <boot.h>
#include <init.h>
#include <bootm.h>
#include <binfmt.h>
#include <common.h>
#include <libfile.h>
#include <linux/kernel.h>

#include <asm/cache.h>
#include <asm/bootm.h>

typedef void __noreturn (*boot_func_entry)(unsigned long, void *);

static int do_boot_entry(struct image_data *data, boot_func_entry entry,
			 void *fdt_load_addr)
{
	printf("starting elf (entry at %p)\n", entry);

	if (data->dryrun)
		return 0;

	shutdown_barebox();

	/* Synchronize I-cache with D-cache */
	sync_caches_for_execution();

	/**
	 * Parameters passing
	 * r0: boot magic
	 * r1: device tree pointer
	 */
	entry(LINUX_BOOT_PARAM_MAGIC, (void *) fdt_load_addr);

	/* should never return ! */
	panic("Returned from boot program !\n");

	return -EINVAL;
}

static int do_boot_elf(struct image_data *data, struct elf_image *elf)
{
	int ret;
	void *fdt;
	boot_func_entry entry;
	unsigned long load_addr, initrd_address;

	/* load initrd after the elf */
	load_addr = PAGE_ALIGN((unsigned long) elf->high_addr);
	if (bootm_has_initrd(data)) {
		if (data->initrd_address != UIMAGE_INVALID_ADDRESS)
			initrd_address = data->initrd_address;
		else
			initrd_address = load_addr;

		printf("Loading initrd at 0x%lx\n", initrd_address);
		ret = bootm_load_initrd(data, initrd_address);
		if (ret) {
			printf("Failed to load initrd\n");
			return ret;
		}

		if (data->initrd_address == UIMAGE_INVALID_ADDRESS) {
			load_addr += resource_size(data->initrd_res);
			load_addr = PAGE_ALIGN(load_addr);
		}
	}

	fdt = bootm_get_devicetree(data);
	if (IS_ERR(fdt)) {
		printf("Failed to load dtb\n");
		return PTR_ERR(fdt);
	}

	printf("Loading device tree at %lx\n", load_addr);
	/* load device tree after the initrd if any */
	ret = bootm_load_devicetree(data, fdt, load_addr);
	if (ret) {
		printf("Failed to load device tree: %d\n", ret);
		goto err_free_fdt;
	}

	entry = (boot_func_entry) data->os_address;

	ret = do_boot_entry(data, entry, fdt);

err_free_fdt:
	free(fdt);

	return ret;
}

static int do_bootm_elf(struct image_data *data)
{
	int ret;

	ret = bootm_load_os(data, data->os_address);
	if (ret)
		return ret;

	return do_boot_elf(data, data->elf);
}

static struct image_handler elf_handler = {
	.name = "ELF",
	.bootm = do_bootm_elf,
	.filetype = filetype_elf,
};

static struct binfmt_hook binfmt_elf_hook = {
	.type = filetype_elf,
	.exec = "bootm",
};

static int kvx_register_image_handler(void)
{
	register_image_handler(&elf_handler);

	binfmt_register(&binfmt_elf_hook);

	return 0;
}

late_initcall(kvx_register_image_handler);