1 /*-
2 * Copyright (c) 2009
3 * Thorsten Glaser <tg@mirbsd.org>
4 *
5 * Provided that these terms and disclaimer and all copyright notices
6 * are retained or reproduced in an accompanying document, permission
7 * is granted to deal in this work without restriction, including un-
8 * limited rights to use, publicly perform, distribute, sell, modify,
9 * merge, give away, or sublicence.
10 *
11 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
12 * the utmost extent permitted by applicable law, neither express nor
13 * implied; without malicious intent or gross negligence. In no event
14 * may a licensor, author or contributor be held liable for indirect,
15 * direct, other damage, loss, or other issues arising in any way out
16 * of dealing in the work, even if advised of the possibility of such
17 * damage or existence of a defect, except proven that it results out
18 * of said person's immediate fault when using the work as intended.
19 */
20
21 #include <sys/param.h>
22 #include <sys/time.h>
23 #include <sys/stat.h>
24 #include <sys/slibkern.h>
25 #include <lib/libsa/stand.h>
26 #include <lib/libsa/lmbmfs.h>
27
28 __RCSID("$MirOS: src/sys/lib/libsa/lmbmfs.c,v 1.5 2010/01/10 17:47:52 tg Exp $");
29
30 extern struct lmbm_modinfo {
31 void *mod_start;
32 void *mod_end;
33 char *mod_string;
34 void *mod_reserved;
35 } *lmbm_ofs;
36
37 static struct lmbm_item {
38 char *name;
39 char *data;
40 size_t size;
41 } *allitems;
42
43 struct lmbmfs_file {
44 struct open_file *open_file; /* our "parent" structure */
45 struct lmbm_item *item;
46 size_t nodeseekp; /* current node: file offset */
47 };
48
49 /**
50 * We need to move the modules passed to us by the Multiboot loader
51 * out of the way. We just assume that, when we are loaded by a
52 * Multiboot bootloader and be passed modules, that the modules are
53 * loaded past us (so at a little above 1 MiB in RAM), and that the
54 * area from 20 MiB in RAM and up is unused, and that the kernel is
55 * loaded below that (MirBSD kernels are currently loaded to a lit-
56 * tle past 1 MiB; recent OpenBSD kernels a little past 2 MiB).
57 */
58
59 /* where modules are moved to */
60 #define STARTADDR ((char *)(20 * 1048576))
61
62 int
lmbmfs_init(void)63 lmbmfs_init(void)
64 {
65 uint32_t i = lmbm_num;
66 char *dstaddr = STARTADDR;
67 static int initialised = 0;
68
69 if (!lmbm_num)
70 return (ENXIO);
71 if (initialised)
72 goto init_ok;
73 initialised = 1;
74
75 allitems = alloc(lmbm_num * sizeof(struct lmbm_item));
76
77 for (i = 0; i < lmbm_num; ++i) {
78 char *cp, *bp;
79
80 bp = cp = lmbm_ofs[i].mod_string;
81 while (*cp && *cp != ' ')
82 if (*cp++ == '/')
83 bp = cp;
84 *cp = '\0';
85 if (cp++ - bp) {
86 allitems[i].name = alloc(cp - bp);
87 memcpy(allitems[i].name, bp, cp - bp);
88 } else {
89 allitems[i].name = alloc(8);
90 snprintf(allitems[i].name, 8, "%X", i);
91 }
92 allitems[i].data = dstaddr;
93 allitems[i].size = lmbm_ofs[i].mod_end - lmbm_ofs[i].mod_start;
94 memcpy(dstaddr, lmbm_ofs[i].mod_start, allitems[i].size);
95 dstaddr += allitems[i].size;
96 }
97 init_ok:
98 printf(" lmbm(%u=%u bytes)", i, dstaddr - STARTADDR);
99 return (0);
100 }
101
102
103 int
lmbmfs_open(char * path,struct open_file * f)104 lmbmfs_open(char *path, struct open_file *f)
105 {
106 struct lmbmfs_file *ff;
107 char *bp = path, *cp = path;
108 uint32_t i = 0;
109
110 twiddle();
111 /* find file */
112 while (*cp)
113 if (*cp++ == '/')
114 bp = cp;
115 if (!*bp || !strcmp(bp, "."))
116 bp = NULL;
117 if (bp) {
118 /* not the (root) directory */
119
120 while (i < lmbm_num) {
121 twiddle();
122 if (!strcmp(bp, allitems[i].name))
123 break;
124 else
125 ++i;
126 }
127 if (i == lmbm_num)
128 return (ENOENT);
129 }
130
131 /* allocate fs specific data structure */
132 ff = alloc(sizeof(struct lmbmfs_file));
133 f->f_fsdata = ff;
134 ff->open_file = f;
135 ff->item = bp ? &allitems[i] : NULL;
136 ff->nodeseekp = 0;
137
138 return (0);
139 }
140
141 int
lmbmfs_close(struct open_file * f)142 lmbmfs_close(struct open_file *f)
143 {
144 if (f)
145 free(f->f_fsdata, sizeof(struct lmbmfs_file));
146
147 return (0);
148 }
149
150 int
lmbmfs_read(struct open_file * f,void * buf,size_t size,size_t * resid)151 lmbmfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
152 {
153 struct lmbmfs_file *ff = f->f_fsdata;
154 size_t n;
155
156 if (!ff->item)
157 return (EISDIR);
158
159 twiddle();
160 if (ff->nodeseekp >= ff->item->size)
161 n = 0;
162 else if ((n = ff->item->size - ff->nodeseekp) > size)
163 n = size;
164 if (n) {
165 memcpy(buf, ff->item->data + ff->nodeseekp, n);
166 ff->nodeseekp += n;
167 }
168 if (resid)
169 *resid = size - n;
170 return (0);
171 }
172
173 int
lmbmfs_write(struct open_file * f,void * buf,size_t size,size_t * resid)174 lmbmfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
175 {
176 return (EROFS);
177 }
178
179 off_t
lmbmfs_seek(struct open_file * f,off_t offset,int where)180 lmbmfs_seek(struct open_file *f, off_t offset, int where)
181 {
182 if (!((struct lmbmfs_file *)f->f_fsdata)->item)
183 return (EISDIR);
184
185 switch (where) {
186 case SEEK_SET:
187 ((struct lmbmfs_file *)f->f_fsdata)->nodeseekp = offset;
188 break;
189 case SEEK_CUR:
190 ((struct lmbmfs_file *)f->f_fsdata)->nodeseekp += offset;
191 break;
192 case SEEK_END:
193 ((struct lmbmfs_file *)f->f_fsdata)->nodeseekp =
194 ((struct lmbmfs_file *)f->f_fsdata)->item->size + offset;
195 break;
196 default:
197 return (-1);
198 }
199 return (((struct lmbmfs_file *)f->f_fsdata)->nodeseekp);
200 }
201
202 int
lmbmfs_stat(struct open_file * f,struct stat * sb)203 lmbmfs_stat(struct open_file *f, struct stat *sb)
204 {
205 /* quick and dirty */
206 bzero(sb, sizeof(struct stat));
207 if (((struct lmbmfs_file *)f->f_fsdata)->item == NULL) {
208 sb->st_mode = 040555;
209 sb->st_size = 1;
210 } else {
211 sb->st_mode = 0444;
212 sb->st_size = ((struct lmbmfs_file *)f->f_fsdata)->item->size;
213 }
214
215 return (0);
216 }
217
218 int
lmbmfs_readdir(struct open_file * f,char * name)219 lmbmfs_readdir(struct open_file *f, char *name)
220 {
221 struct lmbmfs_file *ff = f->f_fsdata;
222
223 if (ff->item)
224 return (ENOTDIR);
225
226 /* reset? */
227 if (name == NULL) {
228 ff->nodeseekp = 0;
229 return (0);
230 }
231
232 if (ff->nodeseekp == lmbm_num) {
233 *name = '\0';
234 return (ENOENT);
235 }
236 strlcpy(name, allitems[ff->nodeseekp++].name, PATH_MAX);
237 return (0);
238 }
239