1 /*
2  * vrl4 format generator
3  *
4  * Copyright (C) 2010 Simon Horman
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10 
11 /*
12  * usage: vrl4 < zImage > out
13  *	  dd if=out of=/dev/sdx bs=512 seek=1 # Write the image to sector 1
14  *
15  * Reads a zImage from stdin and writes a vrl4 image to stdout.
16  * In practice this means writing a padded vrl4 header to stdout followed
17  * by the zImage.
18  *
19  * The padding places the zImage at ALIGN bytes into the output.
20  * The vrl4 uses ALIGN + START_BASE as the start_address.
21  * This is where the mask ROM will jump to after verifying the header.
22  *
23  * The header sets copy_size to min(sizeof(zImage), MAX_BOOT_PROG_LEN) + ALIGN.
24  * That is, the mask ROM will load the padded header (ALIGN bytes)
25  * And then MAX_BOOT_PROG_LEN bytes of the image, or the entire image,
26  * whichever is smaller.
27  *
28  * The zImage is not modified in any way.
29  */
30 
31 #define _BSD_SOURCE
32 #include <endian.h>
33 #include <unistd.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <errno.h>
37 
38 struct hdr {
39 	uint32_t magic1;
40 	uint32_t reserved1;
41 	uint32_t magic2;
42 	uint32_t reserved2;
43 	uint16_t copy_size;
44 	uint16_t boot_options;
45 	uint32_t reserved3;
46 	uint32_t start_address;
47 	uint32_t reserved4;
48 	uint32_t reserved5;
49 	char     reserved6[308];
50 };
51 
52 #define DECLARE_HDR(h)					\
53 	struct hdr (h) = {				\
54 		.magic1 =	htole32(0xea000000),	\
55 		.reserved1 =	htole32(0x56),		\
56 		.magic2 =	htole32(0xe59ff008),	\
57 		.reserved3 =	htole16(0x1) }
58 
59 /* Align to 512 bytes, the MMCIF sector size */
60 #define ALIGN_BITS	9
61 #define ALIGN		(1 << ALIGN_BITS)
62 
63 #define START_BASE	0xe55b0000
64 
65 /*
66  * With an alignment of 512 the header uses the first sector.
67  * There is a 128 sector (64kbyte) limit on the data loaded by the mask ROM.
68  * So there are 127 sectors left for the boot programme. But in practice
69  * Only a small portion of a zImage is needed, 16 sectors should be more
70  * than enough.
71  *
72  * Note that this sets how much of the zImage is copied by the mask ROM.
73  * The entire zImage is present after the header and is loaded
74  * by the code in the boot program (which is the first portion of the zImage).
75  */
76 #define	MAX_BOOT_PROG_LEN (16 * 512)
77 
78 #define ROUND_UP(x)	((x + ALIGN - 1) & ~(ALIGN - 1))
79 
do_read(int fd,void * buf,size_t count)80 ssize_t do_read(int fd, void *buf, size_t count)
81 {
82 	size_t offset = 0;
83 	ssize_t l;
84 
85 	while (offset < count) {
86 		l = read(fd, buf + offset, count - offset);
87 		if (!l)
88 			break;
89 		if (l < 0) {
90 			if (errno == EAGAIN || errno == EWOULDBLOCK)
91 				continue;
92 			perror("read");
93 			return -1;
94 		}
95 		offset += l;
96 	}
97 
98 	return offset;
99 }
100 
do_write(int fd,const void * buf,size_t count)101 ssize_t do_write(int fd, const void *buf, size_t count)
102 {
103 	size_t offset = 0;
104 	ssize_t l;
105 
106 	while (offset < count) {
107 		l = write(fd, buf + offset, count - offset);
108 		if (l < 0) {
109 			if (errno == EAGAIN || errno == EWOULDBLOCK)
110 				continue;
111 			perror("write");
112 			return -1;
113 		}
114 		offset += l;
115 	}
116 
117 	return offset;
118 }
119 
write_zero(int fd,size_t len)120 ssize_t write_zero(int fd, size_t len)
121 {
122 	size_t i = len;
123 
124 	while (i--) {
125 		const char x = 0;
126 		if (do_write(fd, &x, 1) < 0)
127 			return -1;
128 	}
129 
130 	return len;
131 }
132 
main(void)133 int main(void)
134 {
135 	DECLARE_HDR(hdr);
136 	char boot_program[MAX_BOOT_PROG_LEN];
137 	size_t aligned_hdr_len, alligned_prog_len;
138 	ssize_t prog_len;
139 
140 	prog_len = do_read(0, boot_program, sizeof(boot_program));
141 	if (prog_len <= 0)
142 		return -1;
143 
144 	aligned_hdr_len = ROUND_UP(sizeof(hdr));
145 	hdr.start_address = htole32(START_BASE + aligned_hdr_len);
146 	alligned_prog_len = ROUND_UP(prog_len);
147 	hdr.copy_size = htole16(aligned_hdr_len + alligned_prog_len);
148 
149 	if (do_write(1, &hdr, sizeof(hdr)) < 0)
150 		return -1;
151 	if (write_zero(1, aligned_hdr_len - sizeof(hdr)) < 0)
152 		return -1;
153 
154 	if (do_write(1, boot_program, prog_len) < 0)
155 		return 1;
156 
157 	/* Write out the rest of the kernel */
158 	while (1) {
159 		prog_len = do_read(0, boot_program, sizeof(boot_program));
160 		if (prog_len < 0)
161 			return 1;
162 		if (prog_len == 0)
163 			break;
164 		if (do_write(1, boot_program, prog_len) < 0)
165 			return 1;
166 	}
167 
168 	return 0;
169 }
170