1
/* CD-SILO : SILO CDROM (ISO-9660) boot block
3
Copyright (C) 1996 Jakub Jelinek
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22
#include <sys/types.h>
23
#include <linux/iso_fs.h>
27
#include <stringops.h>
30
#define SECOND_BLK "/boot/second.b"
31
#define SILO_CONF "/boot/silo.conf"
32
#define LOAD_ADDR 0x10000
48
static struct isofs_inode root_ino;
49
static int link_count;
50
static char silo_conf[] = SILO_CONF;
53
static int open_namei(const char *pathname, struct isofs_inode *res_inode,
54
struct isofs_inode *base);
57
static int cd_init (void)
59
char iso_bootdevice[1024];
60
char *s = iso_bootdevice;
62
if (prom_vers == PROM_V0) {
63
struct linux_arguments_v0 *ap = *romvec->pv_v0bootargs;
65
*s++ = ap->boot_dev[0];
66
*s++ = ap->boot_dev[1];
68
*s++ = (ap->boot_dev_ctrl & 07) + '0';
70
// Hopefully it's never > 10
71
*s++ = (ap->boot_dev_unit & 07) + '0';
77
fd = (*romvec->pv_v0devops.v0_devopen) (iso_bootdevice);
79
if (prom_vers == PROM_P1275)
80
prom_getproperty (prom_chosen, "bootpath", iso_bootdevice, sizeof(iso_bootdevice));
82
strcpy(iso_bootdevice, *romvec->pv_v2bootargs.bootpath);
84
for (; *s && *s != ':'; s++)
88
*s++ = ':'; *s++ = 'a'; *s = 0;
89
} else if (s[1] >= 'a' && s[1] <= 'z' && !s[2])
92
if (prom_vers == PROM_P1275)
93
fd = p1275_cmd ("open", 1, iso_bootdevice);
95
fd = (*romvec->pv_v2devops.v2_dev_open) (iso_bootdevice);
98
if (fd == 0 || fd == -1)
104
static void cd_fini(void)
108
romvec->pv_v0devops.v0_devclose(fd);
113
romvec->pv_v2devops.v2_dev_close(fd);
117
p1275_cmd("close", 1, fd);
122
static int cd_read_block(unsigned long long offset, int size, void *data)
129
if (prom_vers == PROM_V0) {
130
/* ISOFS_BLOCK_SIZE / 512 == 4 */
134
ret = (*romvec->pv_v0devops.v0_rdblkdev)
135
(fd, size, (unsigned)offset, data);
137
static unsigned long long seekp = 0xffffffffffffffffULL;
139
size <<= ISOFS_BLOCK_BITS;
140
offset <<= ISOFS_BLOCK_BITS;
142
if (seekp != offset) {
143
if (prom_vers == PROM_P1275) {
144
if (p1275_cmd("seek", P1275_ARG_64B(2) | 3, fd, 0, offset) == -1)
147
if ((*romvec->pv_v2devops.v2_dev_seek)
148
(fd, (unsigned)(offset >> 32), (unsigned)offset) == -1)
154
if (prom_vers == PROM_P1275)
155
ret = p1275_cmd ("read", 3, fd, data, size);
157
ret = (*romvec->pv_v2devops.v2_dev_read) (fd, data, size);
168
static int isonum_733 (char * p)
170
return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)
171
| ((p[2] & 0xff) << 16) | ((p[3] & 0xff) << 24));
175
static int isofs_read_super(void)
177
struct iso_primary_descriptor iso;
179
if (cd_read_block(16, 1, &iso) < 0)
182
if (memcmp(iso.id, ISO_STANDARD_ID, sizeof (iso.id)))
185
root_ino.extent = isonum_733 (((struct iso_directory_record *)
186
(iso.root_directory_record))->extent);
187
root_ino.size = isonum_733 (((struct iso_directory_record *)
188
(iso.root_directory_record))->size);
194
static void parse_rr (unsigned char *chr, unsigned char *end,
195
char *name, char *symlink)
197
int cont_extent = 0, cont_offset = 0, cont_size = 0;
198
struct rock_ridge *rr;
206
rr = (struct rock_ridge *)chr;
210
sig = (chr[0] << 8) + chr[1];
215
if ((rr->u.RR.flags[0] &
216
(RR_PX | RR_TF | RR_SL | RR_CL | RR_NM | RR_PX | RR_TF)) == 0)
220
if (truncate || rr->u.NM.flags & ~1)
223
if ((strlen(name) + rr->len - 5) >= 254) {
227
strncat(name, rr->u.NM.name, rr->len - 5);
232
struct SL_component * slp;
233
struct SL_component * oldslp;
236
slp = &rr->u.SL.link;
240
switch (slp->flags & ~1) {
242
strncat(symlink, slp->text, slp->len);
245
strcat(symlink, ".");
248
strcat(symlink, "..");
252
strcat(symlink, "/");
258
slen -= slp->len + 2;
260
slp = (struct SL_component *) (((char *) slp) +
266
if (!rootflag && (oldslp->flags & 1) == 0)
267
strcat (symlink, "/");
279
if (chr >= end && cont_extent) {
280
char sect_buf[ISOFS_BLOCK_SIZE];
282
if (cd_read_block(cont_extent, 1, sect_buf) < 0)
284
parse_rr((unsigned char *)(§_buf[cont_offset]),
285
(unsigned char *)(§_buf[cont_offset +
286
cont_size - 3]), name, symlink);
295
static int isofs_lookup (struct isofs_inode *dir, const char *name,
296
int len, struct isofs_inode *result)
298
char buffer [ISOFS_BLOCK_SIZE];
302
struct iso_directory_record *idr;
311
if (cd_read_block(block, 1, buffer) < 0)
314
size -= ISOFS_BLOCK_SIZE;
318
idr = (struct iso_directory_record *) (buffer + i);
323
i += (unsigned char)idr->length[0];
324
memcpy(namebuf, idr->name, (unsigned char)idr->name_len[0]);
325
namebuf[(unsigned char)idr->name_len[0]] = 0;
327
rr = (unsigned char *)(idr + 1);
328
rr += ((unsigned char)idr->name_len[0]) - sizeof(idr->name);
330
if (!(idr->name_len[0] & 1))
334
parse_rr(rr, (unsigned char *)(&buffer[i-3]), namebuf, symlink);
336
if (idr->name_len[0] == 1 && !idr->name[0]) {
339
} else if (idr->name_len[0] == 1 && idr->name[0] == 1) {
340
namebuf[0] = namebuf[1] = '.';
344
if (strlen(namebuf) == len && !memcmp(name, namebuf, len)) {
349
return -1; /* Looping */
352
error = open_namei(symlink, result, dir);
358
result->extent = isonum_733 (idr->extent);
359
result->size = isonum_733 (idr->size);
363
if (i >= ISOFS_BLOCK_SIZE - sizeof(struct iso_directory_record) +
373
static int dir_namei(const char *pathname, int *namelen, const char **name,
374
struct isofs_inode *base, struct isofs_inode *res_inode)
377
const char *thisname;
379
struct isofs_inode this_inode;
381
if ((c = *pathname) == '/') {
389
for (len = 0; (c = *(pathname++)) && (c != '/'); len++)
395
if (isofs_lookup (base, thisname, len, &this_inode))
409
static int open_namei(const char *pathname,
410
struct isofs_inode *res_inode,
411
struct isofs_inode *base)
413
struct isofs_inode dir;
414
const char *basename;
417
if (dir_namei(pathname, &namelen, &basename, base, &dir))
420
if (isofs_lookup(&dir, basename, namelen, res_inode))
427
char *cd_main (struct linux_romvec *promvec, void *cifh, void *cifs)
429
struct isofs_inode inode;
430
unsigned char *dest = (unsigned char *)LOAD_ADDR;
431
struct silo_info *sinfo;
433
prom_init(promvec, cifh, cifs);
440
if (isofs_read_super())
445
if (open_namei(SECOND_BLK, &inode, &root_ino))
450
if (cd_read_block(inode.extent, (inode.size + (ISOFS_BLOCK_SIZE - 1)) /
451
ISOFS_BLOCK_SIZE, dest) < 0)
456
sinfo = (struct silo_info *)&dest[0x08];
458
if (sinfo->id != 'L')
461
memset(sinfo, 0, sizeof(*sinfo));
463
sinfo->conf_part = 1;
464
strcpy(sinfo->conf_file, silo_conf);
468
prom_putchar(sinfo->id);
474
/* Utility functions */
475
int memcmp(const void *cs, const void *ct, size_t count)
477
const unsigned char *su1, *su2;
480
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
481
if ((res = *su1 - *su2) != 0)
486
void *memcpy(void *dest, const void *src, size_t count)
488
char *tmp = (char *) dest, *s = (char *) src;
494
int strlen(const char *s)
497
for (sc = s; *sc != '\0'; ++sc)
502
char *strcat(char *dest, const char *src)
505
while (*dest) dest++;
506
while ((*dest++ = *src++) != '\0');
510
char *strncat(char *dest, const char *src, size_t n)
513
while (*dest) dest++;
514
while (n && (*dest++ = *src++) != '\0') n--;
519
int strcmp(const char *cs, const char *ct)
521
register signed char __res;
523
if ((__res = *cs - *ct++) != 0 || !*cs++)
528
void *memset(void *s,int c,size_t count)
530
char *xs = (char *) s;
536
char *strcpy(char *dest, const char *src)
539
while ((*dest++ = *src++) != '\0');