1*0181461bSKeith M Wesolowski /*
2*0181461bSKeith M Wesolowski * This file and its contents are supplied under the terms of the
3*0181461bSKeith M Wesolowski * Common Development and Distribution License ("CDDL"), version 1.0.
4*0181461bSKeith M Wesolowski * You may only use this file in accordance with the terms of version
5*0181461bSKeith M Wesolowski * 1.0 of the CDDL.
6*0181461bSKeith M Wesolowski *
7*0181461bSKeith M Wesolowski * A full copy of the text of the CDDL should have accompanied this
8*0181461bSKeith M Wesolowski * source. A copy of the CDDL is also available via the Internet at
9*0181461bSKeith M Wesolowski * http://www.illumos.org/license/CDDL.
10*0181461bSKeith M Wesolowski */
11*0181461bSKeith M Wesolowski
12*0181461bSKeith M Wesolowski /*
13*0181461bSKeith M Wesolowski * Copyright 2013 Joyent, Inc. All rights reserved.
14*0181461bSKeith M Wesolowski */
15*0181461bSKeith M Wesolowski
16*0181461bSKeith M Wesolowski #include <sys/bootconf.h>
17*0181461bSKeith M Wesolowski #include <sys/types.h>
18*0181461bSKeith M Wesolowski #include <sys/param.h>
19*0181461bSKeith M Wesolowski #include <sys/vnode.h>
20*0181461bSKeith M Wesolowski #include <sys/fs/ufs_fsdir.h>
21*0181461bSKeith M Wesolowski #include <sys/fs/ufs_fs.h>
22*0181461bSKeith M Wesolowski #include <sys/fs/ufs_inode.h>
23*0181461bSKeith M Wesolowski #include <sys/sysmacros.h>
24*0181461bSKeith M Wesolowski #include <sys/bootvfs.h>
25*0181461bSKeith M Wesolowski #include <sys/bootinfo.h>
26*0181461bSKeith M Wesolowski #include <sys/filep.h>
27*0181461bSKeith M Wesolowski
28*0181461bSKeith M Wesolowski #ifdef _BOOT
29*0181461bSKeith M Wesolowski #include "../common/util.h"
30*0181461bSKeith M Wesolowski #else
31*0181461bSKeith M Wesolowski #include <sys/sunddi.h>
32*0181461bSKeith M Wesolowski #endif
33*0181461bSKeith M Wesolowski
34*0181461bSKeith M Wesolowski #define MAX_FILES MAX_BOOT_MODULES
35*0181461bSKeith M Wesolowski #define MAX_FDS 256
36*0181461bSKeith M Wesolowski
37*0181461bSKeith M Wesolowski extern void *bkmem_alloc(size_t);
38*0181461bSKeith M Wesolowski extern void bkmem_free(void *, size_t);
39*0181461bSKeith M Wesolowski
40*0181461bSKeith M Wesolowski /*
41*0181461bSKeith M Wesolowski * TODO: Replace these declarations with inclusion of the ordinary userland
42*0181461bSKeith M Wesolowski * bootfs headers once they're available.
43*0181461bSKeith M Wesolowski */
44*0181461bSKeith M Wesolowski typedef struct bfile {
45*0181461bSKeith M Wesolowski char bf_name[MAXPATHLEN];
46*0181461bSKeith M Wesolowski caddr_t bf_addr;
47*0181461bSKeith M Wesolowski size_t bf_size;
48*0181461bSKeith M Wesolowski struct bfile *bf_next;
49*0181461bSKeith M Wesolowski uint64_t bf_ino;
50*0181461bSKeith M Wesolowski } bfile_t;
51*0181461bSKeith M Wesolowski
52*0181461bSKeith M Wesolowski typedef struct bf_fd {
53*0181461bSKeith M Wesolowski bfile_t *fd_file;
54*0181461bSKeith M Wesolowski off_t fd_pos;
55*0181461bSKeith M Wesolowski } bf_fd_t;
56*0181461bSKeith M Wesolowski
57*0181461bSKeith M Wesolowski static bfile_t *head;
58*0181461bSKeith M Wesolowski static uint_t init_done;
59*0181461bSKeith M Wesolowski static bf_fd_t fds[MAX_FDS];
60*0181461bSKeith M Wesolowski
61*0181461bSKeith M Wesolowski static char cpath[MAXPATHLEN]; /* For canonicalising filenames */
62*0181461bSKeith M Wesolowski
63*0181461bSKeith M Wesolowski static void bbootfs_closeall(int);
64*0181461bSKeith M Wesolowski
65*0181461bSKeith M Wesolowski static void
canonicalise(const char * fn,char * out)66*0181461bSKeith M Wesolowski canonicalise(const char *fn, char *out)
67*0181461bSKeith M Wesolowski {
68*0181461bSKeith M Wesolowski const char *p;
69*0181461bSKeith M Wesolowski char *q, *s;
70*0181461bSKeith M Wesolowski char *last;
71*0181461bSKeith M Wesolowski char *oc;
72*0181461bSKeith M Wesolowski int is_slash = 0;
73*0181461bSKeith M Wesolowski static char scratch[MAXPATHLEN];
74*0181461bSKeith M Wesolowski
75*0181461bSKeith M Wesolowski if (fn == NULL) {
76*0181461bSKeith M Wesolowski *out = '\0';
77*0181461bSKeith M Wesolowski return;
78*0181461bSKeith M Wesolowski }
79*0181461bSKeith M Wesolowski
80*0181461bSKeith M Wesolowski /*
81*0181461bSKeith M Wesolowski * Remove leading slashes and condense all multiple slashes into one.
82*0181461bSKeith M Wesolowski */
83*0181461bSKeith M Wesolowski p = fn;
84*0181461bSKeith M Wesolowski while (*p == '/')
85*0181461bSKeith M Wesolowski ++p;
86*0181461bSKeith M Wesolowski
87*0181461bSKeith M Wesolowski for (q = scratch; *p != '\0'; p++) {
88*0181461bSKeith M Wesolowski if (*p == '/' && !is_slash) {
89*0181461bSKeith M Wesolowski *q++ = '/';
90*0181461bSKeith M Wesolowski is_slash = 1;
91*0181461bSKeith M Wesolowski } else if (*p != '/') {
92*0181461bSKeith M Wesolowski *q++ = *p;
93*0181461bSKeith M Wesolowski is_slash = 0;
94*0181461bSKeith M Wesolowski }
95*0181461bSKeith M Wesolowski }
96*0181461bSKeith M Wesolowski *q = '\0';
97*0181461bSKeith M Wesolowski
98*0181461bSKeith M Wesolowski if (strncmp(scratch, "system/boot/", 12) == 0 ||
99*0181461bSKeith M Wesolowski strcmp(scratch, "system/boot") == 0) {
100*0181461bSKeith M Wesolowski s = scratch + 12;
101*0181461bSKeith M Wesolowski } else {
102*0181461bSKeith M Wesolowski s = scratch;
103*0181461bSKeith M Wesolowski }
104*0181461bSKeith M Wesolowski
105*0181461bSKeith M Wesolowski for (last = strsep(&s, "/"), q = oc = out; last != NULL;
106*0181461bSKeith M Wesolowski last = strsep(&s, "/")) {
107*0181461bSKeith M Wesolowski if (strcmp(last, ".") == 0)
108*0181461bSKeith M Wesolowski continue;
109*0181461bSKeith M Wesolowski if (strcmp(last, "..") == 0) {
110*0181461bSKeith M Wesolowski for (oc = q; oc > out && *oc != '/'; oc--)
111*0181461bSKeith M Wesolowski ;
112*0181461bSKeith M Wesolowski q = oc;
113*0181461bSKeith M Wesolowski continue;
114*0181461bSKeith M Wesolowski }
115*0181461bSKeith M Wesolowski if (q > out)
116*0181461bSKeith M Wesolowski *q++ = '/';
117*0181461bSKeith M Wesolowski q += snprintf(q, MAXPATHLEN - (q - out), "%s", last);
118*0181461bSKeith M Wesolowski }
119*0181461bSKeith M Wesolowski
120*0181461bSKeith M Wesolowski *q = '\0';
121*0181461bSKeith M Wesolowski }
122*0181461bSKeith M Wesolowski
123*0181461bSKeith M Wesolowski /* ARGSUSED */
124*0181461bSKeith M Wesolowski static int
bbootfs_mountroot(char * str)125*0181461bSKeith M Wesolowski bbootfs_mountroot(char *str)
126*0181461bSKeith M Wesolowski {
127*0181461bSKeith M Wesolowski return (-1);
128*0181461bSKeith M Wesolowski }
129*0181461bSKeith M Wesolowski
130*0181461bSKeith M Wesolowski static int
bbootfs_unmountroot(void)131*0181461bSKeith M Wesolowski bbootfs_unmountroot(void)
132*0181461bSKeith M Wesolowski {
133*0181461bSKeith M Wesolowski return (-1);
134*0181461bSKeith M Wesolowski }
135*0181461bSKeith M Wesolowski
136*0181461bSKeith M Wesolowski static int
bbootfs_init(void)137*0181461bSKeith M Wesolowski bbootfs_init(void)
138*0181461bSKeith M Wesolowski {
139*0181461bSKeith M Wesolowski bfile_t *fp;
140*0181461bSKeith M Wesolowski char propname[32];
141*0181461bSKeith M Wesolowski uint64_t propval;
142*0181461bSKeith M Wesolowski uint_t i;
143*0181461bSKeith M Wesolowski
144*0181461bSKeith M Wesolowski for (i = 0; i < MAX_FILES; i++) {
145*0181461bSKeith M Wesolowski (void) snprintf(propname, sizeof (propname),
146*0181461bSKeith M Wesolowski "module-name-%u", i);
147*0181461bSKeith M Wesolowski if (do_bsys_getproplen(NULL, propname) < 0)
148*0181461bSKeith M Wesolowski break;
149*0181461bSKeith M Wesolowski
150*0181461bSKeith M Wesolowski if ((fp = bkmem_alloc(sizeof (bfile_t))) == NULL) {
151*0181461bSKeith M Wesolowski bbootfs_closeall(1);
152*0181461bSKeith M Wesolowski return (-1);
153*0181461bSKeith M Wesolowski }
154*0181461bSKeith M Wesolowski
155*0181461bSKeith M Wesolowski (void) do_bsys_getprop(NULL, propname, cpath);
156*0181461bSKeith M Wesolowski canonicalise(cpath, fp->bf_name);
157*0181461bSKeith M Wesolowski
158*0181461bSKeith M Wesolowski (void) snprintf(propname, sizeof (propname),
159*0181461bSKeith M Wesolowski "module-addr-%u", i);
160*0181461bSKeith M Wesolowski if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) {
161*0181461bSKeith M Wesolowski bkmem_free(fp, sizeof (bfile_t));
162*0181461bSKeith M Wesolowski continue;
163*0181461bSKeith M Wesolowski }
164*0181461bSKeith M Wesolowski (void) do_bsys_getprop(NULL, propname, &propval);
165*0181461bSKeith M Wesolowski fp->bf_addr = (void *)(uintptr_t)propval;
166*0181461bSKeith M Wesolowski
167*0181461bSKeith M Wesolowski (void) snprintf(propname, sizeof (propname),
168*0181461bSKeith M Wesolowski "module-size-%u", i);
169*0181461bSKeith M Wesolowski if (do_bsys_getproplen(NULL, propname) != sizeof (uint64_t)) {
170*0181461bSKeith M Wesolowski bkmem_free(fp, sizeof (bfile_t));
171*0181461bSKeith M Wesolowski continue;
172*0181461bSKeith M Wesolowski }
173*0181461bSKeith M Wesolowski (void) do_bsys_getprop(NULL, propname, &propval);
174*0181461bSKeith M Wesolowski fp->bf_size = (size_t)propval;
175*0181461bSKeith M Wesolowski fp->bf_ino = i;
176*0181461bSKeith M Wesolowski
177*0181461bSKeith M Wesolowski fp->bf_next = head;
178*0181461bSKeith M Wesolowski head = fp;
179*0181461bSKeith M Wesolowski }
180*0181461bSKeith M Wesolowski
181*0181461bSKeith M Wesolowski return (0);
182*0181461bSKeith M Wesolowski }
183*0181461bSKeith M Wesolowski
184*0181461bSKeith M Wesolowski /*ARGSUSED*/
185*0181461bSKeith M Wesolowski static int
bbootfs_open(char * fn,int flags)186*0181461bSKeith M Wesolowski bbootfs_open(char *fn, int flags)
187*0181461bSKeith M Wesolowski {
188*0181461bSKeith M Wesolowski uint_t i;
189*0181461bSKeith M Wesolowski bfile_t *fp;
190*0181461bSKeith M Wesolowski
191*0181461bSKeith M Wesolowski if (!init_done) {
192*0181461bSKeith M Wesolowski if (bbootfs_init() != 0)
193*0181461bSKeith M Wesolowski return (-1);
194*0181461bSKeith M Wesolowski
195*0181461bSKeith M Wesolowski init_done = 1;
196*0181461bSKeith M Wesolowski }
197*0181461bSKeith M Wesolowski
198*0181461bSKeith M Wesolowski canonicalise(fn, cpath);
199*0181461bSKeith M Wesolowski
200*0181461bSKeith M Wesolowski for (fp = head; fp != NULL; fp = fp->bf_next) {
201*0181461bSKeith M Wesolowski if (strcmp(fp->bf_name, cpath) == 0)
202*0181461bSKeith M Wesolowski break;
203*0181461bSKeith M Wesolowski }
204*0181461bSKeith M Wesolowski
205*0181461bSKeith M Wesolowski if (fp == NULL)
206*0181461bSKeith M Wesolowski return (-1);
207*0181461bSKeith M Wesolowski
208*0181461bSKeith M Wesolowski for (i = 0; i < MAX_FDS; i++) {
209*0181461bSKeith M Wesolowski if (fds[i].fd_file == NULL) {
210*0181461bSKeith M Wesolowski fds[i].fd_file = fp;
211*0181461bSKeith M Wesolowski fds[i].fd_pos = 0;
212*0181461bSKeith M Wesolowski return (i);
213*0181461bSKeith M Wesolowski }
214*0181461bSKeith M Wesolowski }
215*0181461bSKeith M Wesolowski
216*0181461bSKeith M Wesolowski return (-1);
217*0181461bSKeith M Wesolowski }
218*0181461bSKeith M Wesolowski
219*0181461bSKeith M Wesolowski static int
bbootfs_close(int fd)220*0181461bSKeith M Wesolowski bbootfs_close(int fd)
221*0181461bSKeith M Wesolowski {
222*0181461bSKeith M Wesolowski if (fds[fd].fd_file == NULL)
223*0181461bSKeith M Wesolowski return (-1);
224*0181461bSKeith M Wesolowski
225*0181461bSKeith M Wesolowski fds[fd].fd_file = NULL;
226*0181461bSKeith M Wesolowski fds[fd].fd_pos = 0;
227*0181461bSKeith M Wesolowski
228*0181461bSKeith M Wesolowski return (0);
229*0181461bSKeith M Wesolowski }
230*0181461bSKeith M Wesolowski
231*0181461bSKeith M Wesolowski static ssize_t
bbootfs_read(int fd,caddr_t buf,size_t size)232*0181461bSKeith M Wesolowski bbootfs_read(int fd, caddr_t buf, size_t size)
233*0181461bSKeith M Wesolowski {
234*0181461bSKeith M Wesolowski ssize_t len;
235*0181461bSKeith M Wesolowski bf_fd_t *fdp = &fds[fd];
236*0181461bSKeith M Wesolowski
237*0181461bSKeith M Wesolowski if (fdp->fd_file == NULL)
238*0181461bSKeith M Wesolowski return (-1);
239*0181461bSKeith M Wesolowski
240*0181461bSKeith M Wesolowski if (fdp->fd_pos >= fdp->fd_file->bf_size)
241*0181461bSKeith M Wesolowski return (-1);
242*0181461bSKeith M Wesolowski
243*0181461bSKeith M Wesolowski if (fdp->fd_pos + size > fdp->fd_file->bf_size)
244*0181461bSKeith M Wesolowski len = fdp->fd_file->bf_size - fdp->fd_pos;
245*0181461bSKeith M Wesolowski else
246*0181461bSKeith M Wesolowski len = size;
247*0181461bSKeith M Wesolowski
248*0181461bSKeith M Wesolowski bcopy(fdp->fd_file->bf_addr + fdp->fd_pos, buf, len);
249*0181461bSKeith M Wesolowski
250*0181461bSKeith M Wesolowski fdp->fd_pos += len;
251*0181461bSKeith M Wesolowski
252*0181461bSKeith M Wesolowski return (len);
253*0181461bSKeith M Wesolowski }
254*0181461bSKeith M Wesolowski
255*0181461bSKeith M Wesolowski static off_t
bbootfs_lseek(int fd,off_t addr,int whence)256*0181461bSKeith M Wesolowski bbootfs_lseek(int fd, off_t addr, int whence)
257*0181461bSKeith M Wesolowski {
258*0181461bSKeith M Wesolowski bf_fd_t *fdp = &fds[fd];
259*0181461bSKeith M Wesolowski
260*0181461bSKeith M Wesolowski if (fdp->fd_file == NULL)
261*0181461bSKeith M Wesolowski return (-1);
262*0181461bSKeith M Wesolowski
263*0181461bSKeith M Wesolowski switch (whence) {
264*0181461bSKeith M Wesolowski case SEEK_CUR:
265*0181461bSKeith M Wesolowski fdp->fd_pos += addr;
266*0181461bSKeith M Wesolowski break;
267*0181461bSKeith M Wesolowski case SEEK_SET:
268*0181461bSKeith M Wesolowski fdp->fd_pos = addr;
269*0181461bSKeith M Wesolowski break;
270*0181461bSKeith M Wesolowski case SEEK_END:
271*0181461bSKeith M Wesolowski fdp->fd_pos = fdp->fd_file->bf_size;
272*0181461bSKeith M Wesolowski break;
273*0181461bSKeith M Wesolowski default:
274*0181461bSKeith M Wesolowski return (-1);
275*0181461bSKeith M Wesolowski }
276*0181461bSKeith M Wesolowski
277*0181461bSKeith M Wesolowski return (0);
278*0181461bSKeith M Wesolowski }
279*0181461bSKeith M Wesolowski
280*0181461bSKeith M Wesolowski static int
bbootfs_fstat(int fd,struct bootstat * bsp)281*0181461bSKeith M Wesolowski bbootfs_fstat(int fd, struct bootstat *bsp)
282*0181461bSKeith M Wesolowski {
283*0181461bSKeith M Wesolowski bf_fd_t *fdp = &fds[fd];
284*0181461bSKeith M Wesolowski
285*0181461bSKeith M Wesolowski if (fdp->fd_file == NULL)
286*0181461bSKeith M Wesolowski return (-1);
287*0181461bSKeith M Wesolowski
288*0181461bSKeith M Wesolowski bsp->st_dev = 1;
289*0181461bSKeith M Wesolowski bsp->st_ino = fdp->fd_file->bf_ino;
290*0181461bSKeith M Wesolowski bsp->st_mode = 0444;
291*0181461bSKeith M Wesolowski bsp->st_nlink = 1;
292*0181461bSKeith M Wesolowski bsp->st_uid = bsp->st_gid = 0;
293*0181461bSKeith M Wesolowski bsp->st_rdev = 0;
294*0181461bSKeith M Wesolowski bsp->st_size = fdp->fd_file->bf_size;
295*0181461bSKeith M Wesolowski bsp->st_blksize = 1;
296*0181461bSKeith M Wesolowski bsp->st_blocks = fdp->fd_file->bf_size;
297*0181461bSKeith M Wesolowski (void) strcpy(bsp->st_fstype, "bootfs");
298*0181461bSKeith M Wesolowski
299*0181461bSKeith M Wesolowski return (0);
300*0181461bSKeith M Wesolowski }
301*0181461bSKeith M Wesolowski
302*0181461bSKeith M Wesolowski /* ARGSUSED */
303*0181461bSKeith M Wesolowski static void
bbootfs_closeall(int flag)304*0181461bSKeith M Wesolowski bbootfs_closeall(int flag)
305*0181461bSKeith M Wesolowski {
306*0181461bSKeith M Wesolowski bfile_t *fp;
307*0181461bSKeith M Wesolowski
308*0181461bSKeith M Wesolowski while (head != NULL) {
309*0181461bSKeith M Wesolowski fp = head;
310*0181461bSKeith M Wesolowski head = head->bf_next;
311*0181461bSKeith M Wesolowski
312*0181461bSKeith M Wesolowski bkmem_free(fp, sizeof (bfile_t));
313*0181461bSKeith M Wesolowski }
314*0181461bSKeith M Wesolowski
315*0181461bSKeith M Wesolowski init_done = 0;
316*0181461bSKeith M Wesolowski }
317*0181461bSKeith M Wesolowski
318*0181461bSKeith M Wesolowski struct boot_fs_ops bbootfs_ops = {
319*0181461bSKeith M Wesolowski "bootfs",
320*0181461bSKeith M Wesolowski bbootfs_mountroot,
321*0181461bSKeith M Wesolowski bbootfs_unmountroot,
322*0181461bSKeith M Wesolowski bbootfs_open,
323*0181461bSKeith M Wesolowski bbootfs_close,
324*0181461bSKeith M Wesolowski bbootfs_read,
325*0181461bSKeith M Wesolowski bbootfs_lseek,
326*0181461bSKeith M Wesolowski bbootfs_fstat,
327*0181461bSKeith M Wesolowski bbootfs_closeall,
328*0181461bSKeith M Wesolowski NULL
329*0181461bSKeith M Wesolowski };
330