1/*	$NetBSD: setnetimage.c,v 1.7 2009/03/14 14:46:05 dsl Exp $	*/
2
3/*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Simon Burge.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/mman.h>
34#include <sys/stat.h>
35#include <sys/exec_elf.h>
36
37#include <err.h>
38#include <fcntl.h>
39#include <nlist.h>
40#include <limits.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <unistd.h>
44#include <zlib.h>
45
46#include "extern.h"
47
48#define MAX_SEGMENTS		10	/* We can load up to 10 segments */
49
50struct nlist nl[] = {
51#define	X_KERNEL_ENTRY		0
52	{ "_kernel_entry" },
53#define	X_KERNEL_IMAGE		1
54	{ "_kernel_image" },
55#define	X_KERNEL_LOADADDR	2
56	{ "_kernel_loadaddr" },
57#define	X_KERNEL_SIZE		3
58	{ "_kernel_size" },
59#define	X_MAXKERNEL_SIZE	4
60	{ "_maxkernel_size" },
61	{ NULL }
62};
63#define X_NSYMS			((sizeof(nl) / sizeof(struct nlist)) - 1)
64
65struct seglist {
66	Elf32_Addr addr;
67	Elf32_Off f_offset;
68	Elf32_Word f_size;
69};
70
71#define NLADDR(x)	(mappedbfile + offsets[(x)])
72#define NLVAR(x)	(*(u_long *)(NLADDR(x)))
73
74int main(int, char **);
75
76int
77main(int argc, char **argv)
78{
79	int ifd, ofd, i, nsegs;
80	size_t offsets[X_NSYMS];
81	const char *kernel, *bootfile;
82	char *mappedbfile;
83	char *uncomp_kernel, *comp_kernel;
84	Elf32_Addr lowaddr, highaddr;
85	Elf32_Ehdr ehdr;
86	Elf32_Phdr phdr;
87	uLongf destlen;
88	struct stat osb;
89	struct seglist seglist[MAX_SEGMENTS];
90
91	if (argc != 3) {
92		fprintf(stderr, "usage: %s kernel bootfile\n", getprogname());
93		exit(1);
94	}
95
96	kernel = argv[1];
97	bootfile = argv[2];
98
99	if ((ifd = open(kernel, O_RDONLY)) < 0)
100		err(1, "%s", kernel);
101
102	if ((ofd = open(bootfile, O_RDWR)) < 0)
103		err(1, "%s", bootfile);
104
105	if (nlist(bootfile, nl) != 0)
106		errx(1, "Could not find symbols in %s", bootfile);
107
108	if (fstat(ofd, &osb) == -1)
109		err(1, "fstat %s", bootfile);
110	if (osb.st_size > SIZE_T_MAX)
111		errx(1, "%s too big to map", bootfile);
112
113	if ((mappedbfile = mmap(NULL, osb.st_size, PROT_READ | PROT_WRITE,
114	    MAP_FILE | MAP_SHARED, ofd, 0)) == (void *)-1)
115		err(1, "mmap %s", bootfile);
116	printf("mapped %s\n", bootfile);
117
118	if (check_elf32(mappedbfile, osb.st_size) != 0)
119		errx(1, "No ELF header in %s", bootfile);
120
121	for (i = 0; i < X_NSYMS; i++) {
122		if (findoff_elf32(mappedbfile, osb.st_size, nl[i].n_value, &offsets[i]) != 0)
123			errx(1, "Couldn't find offset for %s in %s", nl[i].n_name, bootfile);
124#ifdef DEBUG
125		printf("%s is at offset %#x in %s\n", nl[i].n_name, offsets[i], bootfile);
126#endif
127	}
128
129	/* read the exec header */
130	i = read(ifd, (char *)&ehdr, sizeof(ehdr));
131	if ((i != sizeof(ehdr)) ||
132	    (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) ||
133	    (ehdr.e_ident[EI_CLASS] != ELFCLASS32)) {
134		errx(1, "No ELF header in %s", kernel);
135	}
136
137	nsegs = highaddr = 0;
138	lowaddr = UINT_MAX;
139	for (i = 0; i < ehdr.e_phnum; i++) {
140		if (lseek(ifd, (off_t) ehdr.e_phoff + i * sizeof(phdr), 0) < 0)
141			err(1, "%s", kernel);
142		if (read(ifd, &phdr, sizeof(phdr)) != sizeof(phdr))
143			err(1, "%s", kernel);
144		if (phdr.p_type != PT_LOAD)
145			continue;
146
147		printf("load section %d at addr 0x%08x, file offset %8d, length %8d\n",
148		    i, phdr.p_paddr, phdr.p_offset, phdr.p_filesz);
149
150		seglist[nsegs].addr = phdr.p_paddr;
151		seglist[nsegs].f_offset = phdr.p_offset;
152		seglist[nsegs].f_size = phdr.p_filesz;
153		nsegs++;
154
155		if (phdr.p_paddr < lowaddr)
156			lowaddr = phdr.p_paddr;
157		if (phdr.p_paddr + phdr.p_filesz > highaddr)
158			highaddr = phdr.p_paddr + phdr.p_filesz;
159
160	}
161
162#ifdef DEBUG
163	printf("lowaddr =  0x%08x, highaddr = 0x%08x\n", lowaddr, highaddr);
164#endif
165	printf("load address: 0x%08x\n", lowaddr);
166	printf("entry point:  0x%08x\n", ehdr.e_entry);
167
168	destlen = highaddr - lowaddr;
169
170	uncomp_kernel = (char *)malloc(destlen);
171	comp_kernel = (char *)malloc(destlen);		/* Worst case... */
172	for (i = 0; i < nsegs; i++) {
173#ifdef DEBUG
174		printf("lseek(ifd, %d, 0)\n", seglist[i].f_offset);
175#endif
176		if (lseek(ifd, (off_t)seglist[i].f_offset, 0) < 0)
177			err(1, "%s", kernel);
178#ifdef DEBUG
179		printf("read(ifd, %p, %d)\n", \
180		    uncomp_kernel + seglist[i].addr - lowaddr,
181		    seglist[i].f_size);
182#endif
183		if (read(ifd, uncomp_kernel + seglist[i].addr - lowaddr,
184		    seglist[i].f_size) != seglist[i].f_size)
185			err(1, "%s", kernel);
186	}
187	close(ifd);
188
189	printf("Compressing %d bytes...", highaddr - lowaddr); fflush(stdout);
190	i = compress2(comp_kernel, &destlen, uncomp_kernel, \
191	    highaddr - lowaddr, Z_BEST_COMPRESSION);
192	if (i != Z_OK) {
193		printf("\n");
194		errx(1, "%s compression error %d", kernel, i);
195	}
196	printf("done.\n"); fflush(stdout);
197
198	printf("max kernelsize = %ld\n", NLVAR(X_MAXKERNEL_SIZE));
199	printf("compressed size = %ld\n", destlen);
200	if (destlen > NLVAR(X_MAXKERNEL_SIZE))
201		errx(1, "kernel %s is too big, "
202		    "increase KERNELSIZE to at least %ld",
203		    kernel, destlen);
204
205	NLVAR(X_KERNEL_SIZE) = destlen;
206	NLVAR(X_KERNEL_LOADADDR) = lowaddr;
207	NLVAR(X_KERNEL_ENTRY) = ehdr.e_entry;
208	memcpy(NLADDR(X_KERNEL_IMAGE), comp_kernel, destlen);
209	munmap(mappedbfile, osb.st_size);
210	printf("unmapped %s\n", bootfile);
211	close(ofd);
212
213	exit(0);
214}
215