1/*	$NetBSD$	*/
2
3/*
4 * Copyright (c) 2009 NONAKA Kimihiro <nonaka@netbsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/types.h>
29#include <sys/bootblock.h>
30
31#include "boot.h"
32#include "bootinfo.h"
33#include "disk.h"
34#include "unixdev.h"
35#include "pathnames.h"
36
37#include <lib/libsa/loadfile.h>
38
39#include "compat_linux.h"
40
41static int fdloadfile_zboot(int fd, u_long *marks, int flags);
42static int zboot_exec(int fd, u_long *marks, int flags);
43
44int
45loadfile_zboot(const char *fname, u_long *marks, int flags)
46{
47	int fd, error;
48
49	/* Open the file. */
50	if ((fd = open(fname, 0)) < 0) {
51		WARN(("open %s", fname ? fname : "<default>"));
52		return -1;
53	}
54
55	/* Load it; save the value of errno across the close() call */
56	if ((error = fdloadfile_zboot(fd, marks, flags)) != 0) {
57		(void)close(fd);
58		errno = error;
59		return -1;
60	}
61
62	return fd;
63}
64
65static int
66fdloadfile_zboot(int fd, u_long *marks, int flags)
67{
68	Elf32_Ehdr elf32;
69	ssize_t nr;
70	int rval;
71
72	/* Read the exec header. */
73	if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
74		goto err;
75	nr = read(fd, &elf32, sizeof(elf32));
76	if (nr == -1) {
77		WARN(("read header failed"));
78		goto err;
79	}
80	if (nr != sizeof(elf32)) {
81		WARN(("read header short"));
82		errno = EFTYPE;
83		goto err;
84	}
85
86	if (memcmp(elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
87	    elf32.e_ident[EI_CLASS] == ELFCLASS32) {
88		rval = zboot_exec(fd, marks, flags);
89	} else {
90		rval = 1;
91		errno = EFTYPE;
92	}
93
94	if (rval == 0)
95		return 0;
96err:
97	return errno;
98}
99
100static int
101zboot_exec(int fd, u_long *marks, int flags)
102{
103	static char bibuf[BOOTINFO_MAXSIZE];
104	char buf[512];
105	struct btinfo_common *help;
106	char *p;
107	int tofd;
108	int sz;
109	int i;
110
111	/*
112	 * set bootargs
113	 */
114	p = bibuf;
115	memcpy(p, &bootinfo->nentries, sizeof(bootinfo->nentries));
116	p += sizeof(bootinfo->nentries);
117	for (i = 0; i < bootinfo->nentries; i++) {
118		help = (struct btinfo_common *)(bootinfo->entry[i]);
119		if ((p - bibuf) + help->len > BOOTINFO_MAXSIZE)
120			break;
121
122		memcpy(p, help, help->len);
123		p += help->len;
124	}
125
126	tofd = uopen(_PATH_ZBOOT, LINUX_O_WRONLY);
127	if (tofd == -1) {
128		printf("%s: can't open (errno %d)\n", _PATH_ZBOOT, errno);
129		return 1;
130	}
131
132	if (uwrite(tofd, bibuf, p - bibuf) != p - bibuf)
133		printf("setbootargs: argument write error\n");
134
135	/* Commit boot arguments. */
136	uclose(tofd);
137
138	/*
139	 * load kernel
140	 */
141	tofd = uopen(_PATH_ZBOOT, LINUX_O_WRONLY);
142	if (tofd == -1) {
143		printf("%s: can't open (errno %d)\n", _PATH_ZBOOT, errno);
144		return 1;
145	}
146
147	if (lseek(fd, 0, SEEK_SET) != 0) {
148		printf("%s: seek error\n", _PATH_ZBOOT);
149		goto err;
150	}
151
152	while ((sz = read(fd, buf, sizeof(buf))) == sizeof(buf)) {
153		if ((sz = uwrite(tofd, buf, sz)) != sizeof(buf)) {
154			printf("%s: write error\n", _PATH_ZBOOT);
155			goto err;
156		}
157	}
158
159	if (sz < 0) {
160		printf("zboot_exec: read error\n");
161		goto err;
162	}
163
164	if (sz >= 0 && uwrite(tofd, buf, sz) != sz) {
165		printf("zboot_exec: write error\n");
166		goto err;
167	}
168
169	uclose(tofd);
170	/*NOTREACHED*/
171	return 0;
172
173err:
174	uclose(tofd);
175	return 1;
176}
177