2 * Copyright © 1997 Pluto Technologies International, Inc. Boulder CO
3 * Copyright © 1997 interface business GmbH, Dresden.
6 * This code was written by Jörg Wunsch, Dresden.
7 * Direct comments to <joerg_wunsch@interface-business.de>.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * $FreeBSD: src/sys/i386/boot/cdboot/cdrom.c,v 1.4 1999/08/28 00:43:17 peter Exp $
31 * $DragonFly: src/sys/i386/boot/cdboot/Attic/cdrom.c,v 1.2 2003/06/17 04:28:34 dillon Exp $
37 #include <isofs/cd9660/iso.h>
39 #define BLKSIZE 2048 /* CD-ROM data block size */
40 #define BIOSSEC 512 /* BIOS sector size */
42 #define CD2LBA(rba) ((rba) << 2) /* CD-ROM relative block to BIOS LBA */
44 u_int32_t sessionstart;
46 static struct iso_primary_descriptor pdesc;
48 static char *rootdirbuf;
49 static size_t rootdirsize;
50 static char xbuf[BLKSIZE];
51 static u_int32_t curblk, startblk, filesize, offset;
53 static int bread(u_int32_t rba, size_t nblks, void *buf);
54 static void badread(const char *msg, u_int32_t blkno);
55 static struct iso_directory_record *find(const char *path, int list_only);
56 static char *get_rr_name(struct iso_directory_record *dirp, size_t *len_ret);
57 static int iread(u_char *buf, size_t len,
58 void (*copyfun)(const void *src, void *dst, size_t size));
60 static struct daddrpacket dpkt = { 0x10 };
63 devopen(u_int32_t session)
67 struct iso_directory_record *rootdirp;
69 if ((rv = bread(session + 16, 1, &pdesc)) != 0) {
70 printf("Error reading primary ISO descriptor: %d\n", rv);
73 rootdirp = (struct iso_directory_record *)pdesc.root_directory_record;
74 rootdirblk = isonum_733(rootdirp->extent);
75 rootdirsize = isonum_733(rootdirp->size);
77 /* just in case, round up */
78 rootdirsize = (rootdirsize + BLKSIZE - 1) & ~(BLKSIZE - 1);
80 if (rootdirbuf != NULL)
82 if ((rootdirbuf = malloc(rootdirsize)) == 0) {
83 printf("Cannot allocate memory for the root "
84 "directory buffer.\n");
87 if ((rv = bread(rootdirblk, rootdirsize / BLKSIZE, rootdirbuf))
89 printf("Error reading root directory: %d\n", rv);
93 DPRINTF(("Root directory is 0x%x bytes @ %d\n",
94 rootdirsize, rootdirblk));
100 bread(u_int32_t rba, size_t nblks, void *buf)
104 for (i = 0, rv = -1; rv != 0 && i < 3; i++) {
105 dpkt.nblocks = nblks * (BLKSIZE / BIOSSEC);
106 dpkt.boffs = (u_int16_t)((int)buf & 0xffff);
108 dpkt.lba = CD2LBA(rba);
111 DPRINTF(("Calling biosreadlba(%d blocks, lba %d) = ",
112 dpkt.nblocks, dpkt.lba));
115 rv = biosreadlba(&dpkt);
118 DPRINTF(("%d\n", rv));
132 badread(const char *msg, u_int32_t blkno)
134 printf("Error reading block %d from CD-ROM: %s\n",
138 static __inline size_t
139 minlen(size_t a, size_t b)
145 * Internal form of read()/xread().
148 iread(u_char *buf, size_t len,
149 void (*copyfun)(const void *src, void *dst, size_t size))
151 u_int32_t newblk, ptr;
154 newblk = offset / BLKSIZE + startblk;
156 if (newblk != curblk) {
157 if (offset + len >= filesize) {
158 badread("access beyond file limit", newblk);
161 if (bread(newblk, 1, xbuf)) {
162 badread("BIOS read error", newblk);
167 ptr = offset & (BLKSIZE - 1);
169 /* initial short transfer */
170 bsize = minlen(BLKSIZE - ptr, len);
171 copyfun(xbuf + ptr, buf, bsize);
176 for (; len > 0; len -= bsize) {
177 bsize = minlen(len, BLKSIZE);
178 newblk = offset / BLKSIZE + startblk;
180 if (newblk != curblk) {
181 if (offset + bsize > filesize) {
182 badread("access beyond file limit", newblk);
185 if (bread(newblk, 1, xbuf)) {
186 badread("BIOS read error", newblk);
191 copyfun(xbuf, buf, bsize);
199 read(u_char *buf, size_t len)
201 DPRINTF(("read(0x%x, %d)\n", (int)buf, len));
202 return iread(buf, len, bcopy);
206 xread(u_char *buf, size_t len)
208 DPRINTF(("xread(0x%x, %d)\n", (int)buf, len));
209 return iread(buf, len, pcpy);
213 get_rr_name(struct iso_directory_record *dirp, size_t *len_ret)
220 struct rr_nm_header {
221 struct rr_header rrh;
223 char name[0]; /* XXX -- using gcc extension */
227 cp = dirp->name + (u_char)dirp->name_len[0];
228 /* round up to 16-bit boundary; ugly */
229 cp = (char *)(((int)cp + 1) & ~1);
230 rrp = (struct rr_header *)cp;
232 if (rrp->type[0] != 'R' || rrp->type[1] != 'R') {
233 DPRINTF(("no RR, "));
237 DPRINTF(("RR attribs: "));
239 while (cp - (char *)dirp <= (u_char)dirp->length[0]) {
240 rrp = (struct rr_header *)cp;
241 DPRINTF(("%c%c ", rrp->type[0], rrp->type[1]));
242 if (rrp->type[0] == 'N' && rrp->type[1] == 'M') {
243 rrnmp = (struct rr_nm_header *)rrp;
244 *len_ret = rrp->len - sizeof(struct rr_nm_header);
253 static struct iso_directory_record *
254 find(const char *path, int list_only)
256 struct iso_directory_record *dirp;
258 size_t len, entrylen;
261 int (*comp)(const char *, const char *);
263 while (*path && *path == '/')
266 for (ptr = rootdirbuf, i = 1;
267 ptr < rootdirbuf + rootdirsize;
268 ptr += entrylen, i++) {
269 dirp = (struct iso_directory_record *)ptr;
270 entrylen = (u_char)dirp->length[0];
271 len = (u_char)dirp->name_len[0];
273 DPRINTF(("# %d: offset 0x%x, length 0x%x = %d, ",
274 i, (int)(ptr - rootdirbuf), entrylen, entrylen));
278 * Dir entry of length 0. That's the last
279 * entry in this block, advance to the next
280 * block (if any). In case we get beyond the
281 * end of the directory, we'll fall off the
282 * loop due to the rootdirsize condition in
283 * the `for' statement.
285 DPRINTF(("entrylen 0\n"));
286 entrylen = (~((ptr - rootdirbuf) + BLKSIZE - 1))
291 DPRINTF(("name_len 0\n"));
295 (dirp->name[0] == '\0' || dirp->name[1] == '\1')) {
296 DPRINTF(("dot/dot-dot entry\n"));
299 /* don't consider directories */
300 if (dirp->flags[0] & 2) {
301 DPRINTF(("directory\n"));
304 rrname = get_rr_name(dirp, &len);
305 comp = rrname? strcmp: strcasecmp;
307 bcopy(rrname? rrname: dirp->name, namebuf, len);
309 DPRINTF(("name `%s'\n", namebuf));
313 printf("%s ", namebuf);
315 } else if (comp(path, namebuf) == 0)
330 u_int32_t oldsession;
331 int session, list_only;
332 struct iso_directory_record *dirp;
338 * We accept the following boot string:
340 * [@sessionstart] name
342 for (cp = name; *cp; cp++)
344 /* we don't support filenames with spaces */
350 printf("Syntax error\n");
354 oldsession = sessionstart;
358 case '0': case '1': case '2':
359 case '3': case '4': case '5':
360 case '6': case '7': case '8':
364 sessionstart += *cp - '0';
375 if (session && devopen(sessionstart) == -1) {
376 (void)devopen(oldsession);
377 sessionstart = oldsession;
380 /* XXX no filename, only session arg */
383 list_only = fname[0] == '?' && fname[1] == 0;
385 DPRINTF(("Calling find(%s, %d):\n", fname, list_only));
386 dirp = find(fname, list_only);
387 DPRINTF(("find() returned 0x%x\n", (int)dirp));
394 startblk = isonum_733(dirp->extent);
395 filesize = isonum_733(dirp->size);
397 DPRINTF(("startblk = %d, filesize = %d\n", startblk, filesize));
399 curblk = 0; /* force a re-read, 0 is impossible file start */