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