1183651Sjhay/*-
2183651Sjhay * Copyright (c) 2008 John Hay
3183651Sjhay * Copyright (c) 1998 Robert Nordier
4183651Sjhay * All rights reserved.
5183651Sjhay *
6183651Sjhay * Redistribution and use in source and binary forms are freely
7183651Sjhay * permitted provided that the above copyright notice and this
8183651Sjhay * paragraph and the following disclaimer are duplicated in all
9183651Sjhay * such forms.
10183651Sjhay *
11183651Sjhay * This software is provided "AS IS" and without any express or
12183651Sjhay * implied warranties, including, without limitation, the implied
13183651Sjhay * warranties of merchantability and fitness for a particular
14183651Sjhay * purpose.
15183651Sjhay */
16183651Sjhay
17183651Sjhay#include <sys/cdefs.h>
18183651Sjhay__FBSDID("$FreeBSD$");
19183651Sjhay
20183651Sjhay#include <sys/param.h>
21183651Sjhay#include <sys/disklabel.h>
22183651Sjhay#include <sys/diskmbr.h>
23183651Sjhay#include <sys/dirent.h>
24183651Sjhay#include <sys/reboot.h>
25183651Sjhay
26183651Sjhay#include <machine/elf.h>
27183651Sjhay
28183651Sjhay#include <stdarg.h>
29183651Sjhay
30183651Sjhay#include "lib.h"
31183651Sjhay
32183651Sjhay#define RBX_ASKNAME	0x0	/* -a */
33183651Sjhay#define RBX_SINGLE	0x1	/* -s */
34183651Sjhay/* 0x2 is reserved for log2(RB_NOSYNC). */
35183651Sjhay/* 0x3 is reserved for log2(RB_HALT). */
36183651Sjhay/* 0x4 is reserved for log2(RB_INITNAME). */
37183651Sjhay#define RBX_DFLTROOT	0x5	/* -r */
38183651Sjhay/* #define RBX_KDB 	0x6	   -d */
39183651Sjhay/* 0x7 is reserved for log2(RB_RDONLY). */
40183651Sjhay/* 0x8 is reserved for log2(RB_DUMP). */
41183651Sjhay/* 0x9 is reserved for log2(RB_MINIROOT). */
42183651Sjhay#define RBX_CONFIG	0xa	/* -c */
43183651Sjhay#define RBX_VERBOSE	0xb	/* -v */
44183651Sjhay/* #define RBX_SERIAL	0xc	   -h */
45183651Sjhay/* #define RBX_CDROM	0xd	   -C */
46183651Sjhay/* 0xe is reserved for log2(RB_POWEROFF). */
47183651Sjhay#define RBX_GDB 	0xf	/* -g */
48183651Sjhay/* #define RBX_MUTE	0x10	   -m */
49183651Sjhay/* 0x11 is reserved for log2(RB_SELFTEST). */
50183651Sjhay/* 0x12 is reserved for boot programs. */
51183651Sjhay/* 0x13 is reserved for boot programs. */
52183651Sjhay/* #define RBX_PAUSE	0x14	   -p */
53183651Sjhay/* #define RBX_QUIET	0x15	   -q */
54183651Sjhay#define RBX_NOINTR	0x1c	/* -n */
55183651Sjhay/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */
56183651Sjhay/* #define RBX_DUAL	0x1d	   -D */
57183651Sjhay/* 0x1f is reserved for log2(RB_BOOTINFO). */
58183651Sjhay
59183651Sjhay/* pass: -a, -s, -r, -v, -g */
60183651Sjhay#define RBX_MASK	(OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \
61183651Sjhay			OPT_SET(RBX_DFLTROOT) | \
62183651Sjhay			OPT_SET(RBX_VERBOSE) | \
63183651Sjhay			OPT_SET(RBX_GDB))
64183651Sjhay
65226506Sdes#define PATH_DOTCONFIG	"/boot.config"
66226506Sdes#define PATH_CONFIG	"/boot/config"
67183651Sjhay#define PATH_KERNEL	"/boot/kernel/kernel"
68183651Sjhay
69183651Sjhayextern uint32_t _end;
70183651Sjhay
71183651Sjhay#define NOPT		6
72183651Sjhay
73183651Sjhay#define OPT_SET(opt)	(1 << (opt))
74183651Sjhay#define OPT_CHECK(opt)	((opts) & OPT_SET(opt))
75183651Sjhay
76183651Sjhaystatic const char optstr[NOPT] = "agnrsv";
77183651Sjhaystatic const unsigned char flags[NOPT] = {
78183651Sjhay	RBX_ASKNAME,
79183651Sjhay	RBX_GDB,
80183651Sjhay	RBX_NOINTR,
81183651Sjhay	RBX_DFLTROOT,
82183651Sjhay	RBX_SINGLE,
83183651Sjhay	RBX_VERBOSE
84183651Sjhay};
85183651Sjhay
86183651Sjhaystatic unsigned dsk_start;
87183651Sjhaystatic char cmd[512];
88183651Sjhaystatic char kname[1024];
89183651Sjhaystatic uint32_t opts;
90225955Sthompsastatic uint8_t dsk_meta;
91183651Sjhaystatic int bootslice;
92183651Sjhaystatic int bootpart;
93183651Sjhaystatic int disk_layout;
94183651Sjhay#define DL_UNKNOWN	0
95183651Sjhay#define DL_RAW		1	/* Dangerously dedicated */
96183651Sjhay#define	DL_SLICE	2	/* Use only slices (DOS partitions) */
97183651Sjhay#define DL_SLICEPART	3	/* Use slices and partitions */
98183651Sjhay
99183651Sjhaystatic void load(void);
100183651Sjhaystatic int parse(void);
101183651Sjhaystatic int dskread(void *, unsigned, unsigned);
102183651Sjhaystatic int drvread(void *, unsigned, unsigned);
103183651Sjhay#ifdef FIXUP_BOOT_DRV
104183651Sjhaystatic void fixup_boot_drv(caddr_t, int, int, int);
105183651Sjhay#endif
106183651Sjhay
107183651Sjhay#include "ufsread.c"
108183651Sjhay
109183651Sjhay#ifdef DEBUG
110183651Sjhay#define	DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
111183651Sjhay#else
112183651Sjhay#define	DPRINTF(fmt, ...)
113183651Sjhay#endif
114183651Sjhay
115183651Sjhaystatic inline int
116235988Sglebxfsread(ufs_ino_t inode, void *buf, size_t nbyte)
117183651Sjhay{
118183651Sjhay	if ((size_t)fsread(inode, buf, nbyte) != nbyte)
119183651Sjhay		return -1;
120183651Sjhay	return 0;
121183651Sjhay}
122183651Sjhay
123183651Sjhaystatic inline void
124183651Sjhaygetstr(int c)
125183651Sjhay{
126183651Sjhay	char *s;
127183651Sjhay
128183651Sjhay	s = cmd;
129183651Sjhay	if (c == 0)
130183651Sjhay		c = getc(10000);
131183651Sjhay	for (;;) {
132183651Sjhay		switch (c) {
133183651Sjhay		case 0:
134183651Sjhay			break;
135183651Sjhay		case '\177':
136183651Sjhay		case '\b':
137183651Sjhay			if (s > cmd) {
138183651Sjhay				s--;
139183651Sjhay				printf("\b \b");
140183651Sjhay			}
141183651Sjhay			break;
142183651Sjhay		case '\n':
143183651Sjhay		case '\r':
144183651Sjhay			*s = 0;
145183651Sjhay			return;
146183651Sjhay		default:
147183651Sjhay			if (s - cmd < sizeof(cmd) - 1)
148183651Sjhay				*s++ = c;
149183651Sjhay			xputchar(c);
150183651Sjhay		}
151183671Simp		c = getc(10000);
152183651Sjhay	}
153183651Sjhay}
154183651Sjhay
155183651Sjhayint
156183651Sjhaymain(void)
157183651Sjhay{
158183651Sjhay	const char *bt;
159183651Sjhay	int autoboot, c = 0;
160235988Sgleb	ufs_ino_t ino;
161183651Sjhay
162183651Sjhay	dmadat = (void *)(0x1c0000);
163183651Sjhay	p_memset((char *)dmadat, 0, 32 * 1024);
164183651Sjhay	bt = board_init();
165183651Sjhay
166186352Ssam	printf("FreeBSD ARM (%s) boot2 v%d.%d\n", bt, 0, 4);
167183651Sjhay
168183651Sjhay	autoboot = 1;
169183651Sjhay
170183651Sjhay	/* Process configuration file */
171226506Sdes	if ((ino = lookup(PATH_CONFIG)) ||
172226506Sdes	    (ino = lookup(PATH_DOTCONFIG)))
173183651Sjhay		fsread(ino, cmd, sizeof(cmd));
174183651Sjhay
175183651Sjhay	if (*cmd) {
176183651Sjhay		if (parse())
177183651Sjhay			autoboot = 0;
178183651Sjhay		printf("%s: %s\n", PATH_CONFIG, cmd);
179183651Sjhay		/* Do not process this command twice */
180183651Sjhay		*cmd = 0;
181183651Sjhay	}
182183651Sjhay
183183651Sjhay	if (*kname == '\0')
184183651Sjhay		strcpy(kname, PATH_KERNEL);
185183651Sjhay
186183651Sjhay	/* Present the user with the boot2 prompt. */
187183651Sjhay	for (;;) {
188183651Sjhay		printf("\nDefault: %s\nboot: ", kname);
189183651Sjhay		if (!autoboot ||
190183651Sjhay		    (OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0))
191183651Sjhay			getstr(c);
192183651Sjhay		xputchar('\n');
193183651Sjhay		autoboot = 0;
194183651Sjhay		c = 0;
195183651Sjhay		DPRINTF("cmd is '%s'\n", cmd);
196183651Sjhay		if (parse())
197183651Sjhay			xputchar('\a');
198183651Sjhay		else
199183651Sjhay			load();
200183651Sjhay	}
201183651Sjhay}
202183651Sjhay
203183651Sjhaystatic void
204183651Sjhayload(void)
205183651Sjhay{
206183651Sjhay	Elf32_Ehdr eh;
207183651Sjhay	static Elf32_Phdr ep[2];
208183651Sjhay	caddr_t p;
209235988Sgleb	ufs_ino_t ino;
210183651Sjhay	uint32_t addr;
211183651Sjhay	int i, j;
212183651Sjhay#ifdef FIXUP_BOOT_DRV
213183651Sjhay	caddr_t staddr;
214183651Sjhay	int klen;
215183651Sjhay
216183651Sjhay	staddr = (caddr_t)0xffffffff;
217183651Sjhay	klen = 0;
218183651Sjhay#endif
219183651Sjhay	if (!(ino = lookup(kname))) {
220183651Sjhay		if (!ls)
221183651Sjhay			printf("No %s\n", kname);
222183651Sjhay		return;
223183651Sjhay	}
224183651Sjhay	DPRINTF("Found %s\n", kname);
225183651Sjhay	if (xfsread(ino, &eh, sizeof(eh)))
226183651Sjhay		return;
227183651Sjhay	if (!IS_ELF(eh)) {
228183651Sjhay		printf("Invalid %s\n", "format");
229183651Sjhay		return;
230183651Sjhay	}
231183651Sjhay	fs_off = eh.e_phoff;
232183651Sjhay	for (j = i = 0; i < eh.e_phnum && j < 2; i++) {
233183651Sjhay		if (xfsread(ino, ep + j, sizeof(ep[0])))
234183651Sjhay			return;
235183651Sjhay		if (ep[j].p_type == PT_LOAD)
236183651Sjhay			j++;
237183651Sjhay	}
238183651Sjhay	for (i = 0; i < 2; i++) {
239183651Sjhay		p = (caddr_t)(ep[i].p_paddr & 0x0fffffff);
240183651Sjhay		fs_off = ep[i].p_offset;
241183651Sjhay#ifdef FIXUP_BOOT_DRV
242183651Sjhay		if (staddr == (caddr_t)0xffffffff)
243183651Sjhay			staddr = p;
244183651Sjhay		klen += ep[i].p_filesz;
245183651Sjhay#endif
246183651Sjhay		if (xfsread(ino, p, ep[i].p_filesz))
247183651Sjhay			return;
248183651Sjhay	}
249183651Sjhay	addr = eh.e_entry & 0x0fffffff;
250183651Sjhay	DPRINTF("Entry point %x for %s\n", addr, kname);
251183651Sjhay	clr_board();
252183651Sjhay#ifdef FIXUP_BOOT_DRV
253183651Sjhay	fixup_boot_drv(staddr, klen, bootslice, bootpart);
254183651Sjhay#endif
255183651Sjhay	((void(*)(int))addr)(RB_BOOTINFO /* XXX | (opts & RBX_MASK) */);
256183651Sjhay}
257183651Sjhay
258183651Sjhaystatic int
259183651Sjhayparse()
260183651Sjhay{
261183651Sjhay	char *arg = cmd;
262183651Sjhay	char *ep, *p;
263183651Sjhay	int c, i;
264183651Sjhay
265183651Sjhay	while ((c = *arg++)) {
266183651Sjhay		if (c == ' ' || c == '\t' || c == '\n')
267183651Sjhay			continue;
268183651Sjhay		for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
269183651Sjhay		ep = p;
270183651Sjhay		if (*p)
271183651Sjhay			*p++ = 0;
272183651Sjhay		if (c == '-') {
273183651Sjhay			while ((c = *arg++)) {
274183651Sjhay				for (i = 0; c != optstr[i]; i++)
275183651Sjhay					if (i == NOPT - 1)
276183651Sjhay						return -1;
277183651Sjhay				opts ^= OPT_SET(flags[i]);
278183651Sjhay			}
279183651Sjhay		} else {
280183651Sjhay			arg--;
281183651Sjhay			/* look for ad0s1a:... | ad0s1:... */
282183651Sjhay			if (strlen(arg) > 6 && arg[0] == 'a' &&
283183651Sjhay			    arg[1] == 'd' && arg[3] == 's' &&
284183651Sjhay			    (arg[5] == ':' || arg[6] == ':')) {
285183651Sjhay				/* XXX Should also handle disk. */
286183651Sjhay				bootslice = arg[4] - '0';
287183651Sjhay				if (bootslice < 1 || bootslice > 4)
288183651Sjhay					return (-1);
289183651Sjhay				bootpart = 0;
290183651Sjhay				if (arg[5] != ':')
291183651Sjhay					bootpart = arg[5] - 'a';
292183651Sjhay				if (bootpart < 0 || bootpart > 7)
293183651Sjhay					return (-1);
294183651Sjhay				dsk_meta = 0;
295183651Sjhay				if (arg[5] == ':')
296183651Sjhay					arg += 6;
297183651Sjhay				else
298183651Sjhay					arg += 7;
299183651Sjhay	    		/* look for ad0a:... */
300183651Sjhay			} else if (strlen(arg) > 4 && arg[0] == 'a' &&
301183651Sjhay			    arg[1] == 'd' && arg[2] == '0' && arg[4] == ':') {
302183651Sjhay				bootslice = 0;
303183651Sjhay				bootpart = arg[3] - 'a';
304183651Sjhay				if (bootpart < 0 || bootpart > 7)
305183651Sjhay					return (-1);
306183651Sjhay				dsk_meta = 0;
307183651Sjhay				arg += 5;
308183651Sjhay			}
309183651Sjhay			if ((i = ep - arg)) {
310183651Sjhay				if ((size_t)i >= sizeof(kname))
311183651Sjhay					return -1;
312183651Sjhay				memcpy(kname, arg, i + 1);
313183651Sjhay			}
314183651Sjhay		}
315183651Sjhay		arg = p;
316183651Sjhay	}
317183651Sjhay	return 0;
318183651Sjhay}
319183651Sjhay
320183651Sjhay/*
321183651Sjhay * dskread() will try to handle the disk layouts that are typically
322183651Sjhay * encountered.
323183651Sjhay * - raw or "Dangerously Dedicated" mode. No real slice table, just the
324183651Sjhay *   default one that is included with bsdlabel -B. Typically this is
325183651Sjhay *   used with ROOTDEVNAME=\"ufs:ad0a\".
326183651Sjhay * - slice only. Only a slice table is installed with no bsd label or
327183651Sjhay *   bsd partition table. This is typically used with
328183651Sjhay *   ROOTDEVNAME=\"ufs:ad0s1\".
329183651Sjhay * - slice + bsd label + partition table. This is typically done with
330183651Sjhay *   with fdisk + bsdlabel and is used with ROOTDEVNAME=\"ufs:ad0s1a\".
331183651Sjhay */
332183651Sjhaystatic int
333183651Sjhaydskread(void *buf, unsigned lba, unsigned nblk)
334183651Sjhay{
335183651Sjhay	struct dos_partition *dp;
336183651Sjhay	struct disklabel *d;
337183651Sjhay	char *sec;
338183651Sjhay	int i;
339183651Sjhay
340183651Sjhay	if (!dsk_meta) {
341183651Sjhay		sec = dmadat->secbuf;
342183651Sjhay		dsk_start = 0;
343183651Sjhay		if (drvread(sec, DOSBBSECTOR, 1))
344183651Sjhay			return -1;
345183651Sjhay		dp = (void *)(sec + DOSPARTOFF);
346183651Sjhay		if (bootslice != 0) {
347183651Sjhay			i = bootslice - 1;
348183651Sjhay			if (dp[i].dp_typ != DOSPTYP_386BSD)
349183651Sjhay				return -1;
350183651Sjhay		} else {
351183651Sjhay			for (i = 0; i < NDOSPART; i++) {
352183651Sjhay				if ((dp[i].dp_typ == DOSPTYP_386BSD) &&
353183651Sjhay				    (dp[i].dp_flag == 0x80))
354183651Sjhay					break;
355183651Sjhay			}
356183651Sjhay		}
357183651Sjhay		if (i != NDOSPART) {
358183651Sjhay			bootslice = i + 1;
359183651Sjhay			DPRINTF("Found an active fbsd slice. (%d)\n", i + 1);
360183651Sjhay			/*
361183651Sjhay		 	 * Although dp_start is aligned within the disk
362183651Sjhay			 * partition structure, DOSPARTOFF is 446, which
363183651Sjhay			 * is only word (2) aligned, not longword (4)
364183651Sjhay			 * aligned. Cope by using memcpy to fetch the
365183651Sjhay			 * start of this partition.
366183651Sjhay			 */
367183651Sjhay			memcpy(&dsk_start, &dp[i].dp_start, 4);
368183651Sjhay			dsk_start = swap32(dsk_start);
369183651Sjhay			DPRINTF("dsk_start %x\n", dsk_start);
370183651Sjhay			if ((bootslice == 4) && (dsk_start == 0)) {
371183651Sjhay				disk_layout = DL_RAW;
372183651Sjhay				bootslice = 0;
373183651Sjhay			}
374183651Sjhay		}
375183651Sjhay		if (drvread(sec, dsk_start + LABELSECTOR, 1))
376183651Sjhay			return -1;
377183651Sjhay		d = (void *)(sec + LABELOFFSET);
378183651Sjhay		if ((d->d_magic == DISKMAGIC && d->d_magic2 == DISKMAGIC) ||
379183651Sjhay		    (swap32(d->d_magic) == DISKMAGIC &&
380183651Sjhay		    swap32(d->d_magic2) == DISKMAGIC)) {
381183651Sjhay			DPRINTF("p_size = %x\n",
382183651Sjhay			    !d->d_partitions[bootpart].p_size);
383183651Sjhay			if (!d->d_partitions[bootpart].p_size) {
384183651Sjhay				printf("Invalid partition\n");
385183651Sjhay				return -1;
386183651Sjhay			}
387183651Sjhay			DPRINTF("p_offset %x, RAW %x\n",
388183651Sjhay			    swap32(d->d_partitions[bootpart].p_offset),
389183651Sjhay			    swap32(d->d_partitions[RAW_PART].p_offset));
390183651Sjhay			dsk_start += swap32(d->d_partitions[bootpart].p_offset);
391183651Sjhay			dsk_start -= swap32(d->d_partitions[RAW_PART].p_offset);
392183651Sjhay			if ((disk_layout == DL_UNKNOWN) && (bootslice == 0))
393183651Sjhay				disk_layout = DL_RAW;
394183651Sjhay			else if (disk_layout == DL_UNKNOWN)
395183651Sjhay				disk_layout = DL_SLICEPART;
396183651Sjhay		} else {
397183651Sjhay			disk_layout = DL_SLICE;
398183651Sjhay			DPRINTF("Invalid %s\n", "label");
399183651Sjhay		}
400183651Sjhay		DPRINTF("bootslice %d, bootpart %d, dsk_start %u\n", bootslice,
401183651Sjhay		    bootpart, dsk_start);
402183651Sjhay		dsk_meta++;
403183651Sjhay	}
404183651Sjhay	return drvread(buf, dsk_start + lba, nblk);
405183651Sjhay}
406183651Sjhay
407183651Sjhaystatic int
408183651Sjhaydrvread(void *buf, unsigned lba, unsigned nblk)
409183651Sjhay{
410183651Sjhay	static unsigned c = 0x2d5c7c2f;
411183651Sjhay
412183651Sjhay	printf("%c\b", c = c << 8 | c >> 24);
413183651Sjhay	return (avila_read((char *)buf, lba, nblk));
414183651Sjhay}
415183651Sjhay
416183651Sjhay#ifdef FIXUP_BOOT_DRV
417183651Sjhay/*
418183651Sjhay * fixup_boot_drv() will try to find the ROOTDEVNAME spec in the kernel
419183651Sjhay * and change it to what was specified on the comandline or /boot.conf
420183651Sjhay * file or to what was encountered on the disk. It will try to handle 3
421183651Sjhay * different disk layouts, raw (dangerously dedicated), slice only and
422183651Sjhay * slice + partition. It will look for the following strings in the
423183651Sjhay * kernel, but if it is one of the first three, the string in the kernel
424183651Sjhay * must use the correct form to match the actual disk layout:
425183651Sjhay * - ufs:ad0a
426183651Sjhay * - ufs:ad0s1
427183651Sjhay * - ufs:ad0s1a
428183651Sjhay * - ufs:ROOTDEVNAME
429183651Sjhay * In the case of the first three strings, only the "a" at the end and
430183651Sjhay * the "1" after the "s" will be modified, if they exist. The string
431183651Sjhay * length will not be changed. In the case of the last string, the
432183651Sjhay * whole string will be built up and nul, '\0' terminated.
433183651Sjhay */
434183651Sjhaystatic void
435183651Sjhayfixup_boot_drv(caddr_t addr, int klen, int bs, int bp)
436183651Sjhay{
437183651Sjhay	const u_int8_t op[] = "ufs:ROOTDEVNAME";
438183651Sjhay	const u_int8_t op2[] = "ufs:ad0";
439183651Sjhay	u_int8_t *p, *ps;
440183651Sjhay
441183651Sjhay	DPRINTF("fixup_boot_drv: 0x%x, %d, slice %d, partition %d\n",
442183651Sjhay	    (int)addr, klen, bs, bp);
443183651Sjhay	if (bs > 4)
444183651Sjhay		return;
445183651Sjhay	if (bp > 7)
446183651Sjhay		return;
447183651Sjhay	ps = memmem(addr, klen, op, sizeof(op));
448183651Sjhay	if (ps != NULL) {
449183651Sjhay		p = ps + 4;	/* past ufs: */
450183651Sjhay		DPRINTF("Found it at 0x%x\n", (int)ps);
451183651Sjhay		p[0] = 'a'; p[1] = 'd'; p[2] = '0';	/* ad0 */
452183651Sjhay		p += 3;
453183651Sjhay		if (bs > 0) {
454183651Sjhay			/* append slice */
455183651Sjhay			*p++ = 's';
456183651Sjhay			*p++ = bs + '0';
457183651Sjhay		}
458183651Sjhay		if (disk_layout != DL_SLICE) {
459183651Sjhay			/* append partition */
460183651Sjhay			*p++ = bp + 'a';
461183651Sjhay		}
462183651Sjhay		*p = '\0';
463183651Sjhay	} else {
464183651Sjhay		ps = memmem(addr, klen, op2, sizeof(op2) - 1);
465183651Sjhay		if (ps != NULL) {
466183651Sjhay			p = ps + sizeof(op2) - 1;
467183651Sjhay			DPRINTF("Found it at 0x%x\n", (int)ps);
468183651Sjhay			if (*p == 's') {
469183651Sjhay				/* fix slice */
470183651Sjhay				p++;
471183651Sjhay				*p++ = bs + '0';
472183651Sjhay			}
473183651Sjhay			if (*p == 'a')
474183651Sjhay				*p = bp + 'a';
475183651Sjhay		}
476183651Sjhay	}
477183651Sjhay	if (ps == NULL) {
478183651Sjhay		printf("Could not locate \"%s\" to fix kernel boot device, "
479183651Sjhay		     "check ROOTDEVNAME is set\n", op);
480183651Sjhay		return;
481183651Sjhay	}
482183651Sjhay	DPRINTF("Changed boot device to %s\n", ps);
483183651Sjhay}
484183651Sjhay#endif
485