summaryrefslogtreecommitdiffstats
path: root/arch/arm/lib/bootz.c
blob: 377f18a3acdabf0cf393487978b9d8059ce78487 (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
134
135
136
#include <common.h>
#include <command.h>
#include <fs.h>
#include <of.h>
#include <fcntl.h>
#include <errno.h>
#include <malloc.h>
#include <sizes.h>
#include <asm/byteorder.h>
#include <asm/armlinux.h>
#include <asm/system.h>
#include <asm-generic/memory_layout.h>
#include <memory.h>

struct zimage_header {
	u32	unused[9];
	u32	magic;
	u32	start;
	u32	end;
};

#define ZIMAGE_MAGIC 0x016F2818

static int do_bootz(int argc, char *argv[])
{
	int fd, ret, swap = 0;
	struct zimage_header __header, *header;
	void *zimage;
	void *oftree = NULL;
	u32 end;
	int usemap = 0;
	struct memory_bank *bank = list_first_entry(&memory_banks, struct memory_bank, list);
	struct resource *res = NULL;

	if (argc != 2)
		return COMMAND_ERROR_USAGE;

	fd = open(argv[1], O_RDONLY);
	if (fd < 0) {
		perror("open");
		return 1;
	}

	/*
	 * We can save the memcpy of the zImage if it already is in
	 * the first 128MB of SDRAM.
	 */
	zimage = memmap(fd, PROT_READ);
	if (zimage && (unsigned long)zimage  >= bank->start &&
			(unsigned long)zimage < bank->start + SZ_128M) {
		usemap = 1;
		header = zimage;
	}

	if (!usemap) {
		header = &__header;
		ret = read(fd, header, sizeof(*header));
		if (ret < sizeof(*header)) {
			printf("could not read %s\n", argv[1]);
			goto err_out;
		}
	}

	switch (header->magic) {
#ifdef CONFIG_BOOT_ENDIANNESS_SWITCH
	case swab32(ZIMAGE_MAGIC):
		swap = 1;
		/* fall through */
#endif
	case ZIMAGE_MAGIC:
		break;
	default:
		printf("invalid magic 0x%08x\n", header->magic);
		goto err_out;
	}

	end = header->end;

	if (swap)
		end = swab32(end);

	if (!usemap) {
		if (bank->size <= SZ_128M) {
			zimage = xmalloc(end);
		} else {
			zimage = (void *)bank->start + SZ_8M;
			res = request_sdram_region("zimage",
					bank->start + SZ_8M, end);
			if (!res) {
				printf("can't request region for kernel\n");
				goto err_out1;
			}
		}

		memcpy(zimage, header, sizeof(*header));

		ret = read(fd, zimage + sizeof(*header), end - sizeof(*header));
		if (ret < end - sizeof(*header)) {
			printf("could not read %s\n", argv[1]);
			goto err_out2;
		}
	}

	if (swap) {
		void *ptr;
		for (ptr = zimage; ptr < zimage + end; ptr += 4)
			*(u32 *)ptr = swab32(*(u32 *)ptr);
	}

	printf("loaded zImage from %s with size %d\n", argv[1], end);
#ifdef CONFIG_OFTREE
	oftree = of_get_fixed_tree(NULL);
#endif

	start_linux(zimage, swap, 0, 0, oftree);

	return 0;

err_out2:
	if (res)
		release_sdram_region(res);
err_out1:
	free(zimage);
err_out:
	close(fd);

	return 1;
}

BAREBOX_CMD_START(bootz)
	.cmd            = do_bootz,
	BAREBOX_CMD_DESC("boot Linux zImage")
	BAREBOX_CMD_OPTS("FILE")
	BAREBOX_CMD_GROUP(CMD_GRP_BOOT)
BAREBOX_CMD_END