1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos/mm/mm.h" |
4 | #include "mos/platform/platform.h" |
5 | |
6 | #include <mos/io/io.h> |
7 | #include <mos/io/io_types.h> |
8 | #include <mos/mm/mm_types.h> |
9 | #include <mos/mos_global.h> |
10 | #include <mos/syslog/printk.h> |
11 | #include <mos_stdio.h> |
12 | |
13 | static size_t _null_read(io_t *io, void *buffer, size_t size) |
14 | { |
15 | (void) io; |
16 | (void) buffer; |
17 | (void) size; |
18 | return 0; |
19 | } |
20 | |
21 | static size_t _null_write(io_t *io, const void *buffer, size_t size) |
22 | { |
23 | (void) io; |
24 | (void) buffer; |
25 | (void) size; |
26 | return 0; |
27 | } |
28 | |
29 | static io_t io_null_impl = { |
30 | .refcount = 1, // never gets closed |
31 | .type = IO_NULL, |
32 | .flags = IO_READABLE | IO_WRITABLE, |
33 | .ops = |
34 | &(io_op_t){ |
35 | .read = _null_read, |
36 | .write = _null_write, |
37 | .seek = NULL, |
38 | .close = NULL, |
39 | }, |
40 | }; |
41 | |
42 | io_t *const io_null = &io_null_impl; |
43 | |
44 | void io_init(io_t *io, io_type_t type, io_flags_t flags, const io_op_t *ops) |
45 | { |
46 | pr_dinfo2(io, "io_init(%p, %d, %d, %p)" , (void *) io, type, flags, (void *) ops); |
47 | |
48 | if (unlikely(!io)) |
49 | mos_warn("io is NULL" ); |
50 | |
51 | if (unlikely(!ops)) |
52 | mos_warn("io->ops is NULL" ); |
53 | |
54 | if (flags & IO_READABLE) |
55 | if (unlikely(!ops->read)) |
56 | mos_warn("ops->read is NULL for readable io" ); |
57 | |
58 | if (flags & IO_WRITABLE) |
59 | if (unlikely(!ops->write)) |
60 | mos_warn("ops->write is NULL for writable io" ); |
61 | |
62 | if (flags & IO_SEEKABLE) |
63 | if (unlikely(!ops->seek)) |
64 | mos_warn("io->ops->seek is NULL for seekable io" ); |
65 | |
66 | io->flags = flags; |
67 | io->type = type; |
68 | io->ops = ops; |
69 | io->closed = false; |
70 | io->refcount = 0; |
71 | } |
72 | |
73 | io_t *io_ref(io_t *io) |
74 | { |
75 | pr_dinfo2(io, "io_ref(%p)" , (void *) io); |
76 | if (unlikely(!io)) |
77 | { |
78 | mos_warn("io is NULL" ); |
79 | return NULL; |
80 | } |
81 | |
82 | if (unlikely(io->closed)) |
83 | { |
84 | mos_warn("%p is already closed" , (void *) io); |
85 | return 0; |
86 | } |
87 | |
88 | io->refcount++; |
89 | return io; |
90 | } |
91 | |
92 | io_t *io_unref(io_t *io) |
93 | { |
94 | pr_dinfo2(io, "io_unref(%p)" , (void *) io); |
95 | if (unlikely(io->closed)) |
96 | { |
97 | mos_warn("%p is already closed" , (void *) io); |
98 | return NULL; |
99 | } |
100 | |
101 | if (unlikely(io->refcount == 0)) |
102 | { |
103 | mos_warn("%p has refcount 0" , (void *) io); |
104 | return NULL; |
105 | } |
106 | |
107 | io->refcount--; |
108 | |
109 | if (io->refcount == 0) |
110 | { |
111 | if (io->ops->close) |
112 | { |
113 | pr_dinfo2(io, "closing %p" , (void *) io); |
114 | io->closed = true; |
115 | io->ops->close(io); |
116 | } |
117 | else |
118 | { |
119 | pr_dinfo2(io, "%p is not closeable" , (void *) io); |
120 | } |
121 | return NULL; |
122 | } |
123 | |
124 | return io; |
125 | } |
126 | |
127 | bool io_valid(const io_t *io) |
128 | { |
129 | return io && !io->closed && io->refcount > 0 && io->ops; |
130 | } |
131 | |
132 | size_t io_read(io_t *io, void *buf, size_t count) |
133 | { |
134 | pr_dinfo2(io, "io_read(%p, %p, %zu)" , (void *) io, buf, count); |
135 | |
136 | if (unlikely(io->closed)) |
137 | { |
138 | mos_warn("%p is already closed" , (void *) io); |
139 | return 0; |
140 | } |
141 | |
142 | if (!(io->flags & IO_READABLE)) |
143 | { |
144 | pr_info2("%p is not readable\n" , (void *) io); |
145 | return 0; |
146 | } |
147 | |
148 | return io->ops->read(io, buf, count); |
149 | } |
150 | |
151 | size_t io_pread(io_t *io, void *buf, size_t count, off_t offset) |
152 | { |
153 | pr_dinfo2(io, "io_pread(%p, %p, %zu, %lu)" , (void *) io, buf, count, offset); |
154 | |
155 | if (unlikely(io->closed)) |
156 | { |
157 | mos_warn("%p is already closed" , (void *) io); |
158 | return 0; |
159 | } |
160 | |
161 | if (!(io->flags & IO_READABLE)) |
162 | { |
163 | pr_info2("%p is not readable\n" , (void *) io); |
164 | return 0; |
165 | } |
166 | |
167 | if (!(io->flags & IO_SEEKABLE)) |
168 | { |
169 | pr_info2("%p is not seekable\n" , (void *) io); |
170 | return 0; |
171 | } |
172 | |
173 | const off_t old_offset = io_tell(io); |
174 | io_seek(io, offset, whence: IO_SEEK_SET); |
175 | const size_t ret = io_read(io, buf, count); |
176 | io_seek(io, offset: old_offset, whence: IO_SEEK_SET); |
177 | return ret; |
178 | } |
179 | |
180 | size_t io_write(io_t *io, const void *buf, size_t count) |
181 | { |
182 | pr_dinfo2(io, "io_write(%p, %p, %zu)" , (void *) io, buf, count); |
183 | |
184 | if (unlikely(io->closed)) |
185 | { |
186 | mos_warn("%p is already closed" , (void *) io); |
187 | return 0; |
188 | } |
189 | |
190 | if (!(io->flags & IO_WRITABLE)) |
191 | { |
192 | pr_info2("%p is not writable" , (void *) io); |
193 | return 0; |
194 | } |
195 | |
196 | return io->ops->write(io, buf, count); |
197 | } |
198 | |
199 | off_t io_seek(io_t *io, off_t offset, io_seek_whence_t whence) |
200 | { |
201 | pr_dinfo2(io, "io_seek(%p, %lu, %d)" , (void *) io, offset, whence); |
202 | |
203 | if (unlikely(io->closed)) |
204 | { |
205 | mos_warn("%p is already closed" , (void *) io); |
206 | return 0; |
207 | } |
208 | |
209 | if (!(io->flags & IO_SEEKABLE)) |
210 | { |
211 | pr_info2("%p is not seekable" , (void *) io); |
212 | return 0; |
213 | } |
214 | |
215 | return io->ops->seek(io, offset, whence); |
216 | } |
217 | |
218 | off_t io_tell(io_t *io) |
219 | { |
220 | pr_dinfo2(io, "io_tell(%p)" , (void *) io); |
221 | return io_seek(io, offset: 0, whence: IO_SEEK_CURRENT); |
222 | } |
223 | |
224 | bool io_mmap_perm_check(io_t *io, vm_flags flags, bool is_private) |
225 | { |
226 | if (unlikely(io->closed)) |
227 | { |
228 | mos_warn("%p is already closed" , (void *) io); |
229 | return false; |
230 | } |
231 | |
232 | if (!(io->flags & IO_MMAPABLE)) |
233 | { |
234 | pr_info2("%p is not mmapable" , (void *) io); |
235 | return false; |
236 | } |
237 | |
238 | if (!(io->flags & IO_READABLE)) |
239 | return false; // can't mmap if io is not readable |
240 | |
241 | if (flags & VM_WRITE) |
242 | { |
243 | const bool may_mmap_writeable = is_private || io->flags & IO_WRITABLE; |
244 | if (!may_mmap_writeable) |
245 | return false; // can't mmap writable if io is not writable and not private |
246 | } |
247 | |
248 | // if (flags & VM_EXEC && !(io->flags & IO_EXECUTABLE)) |
249 | // return false; // can't mmap executable if io is not executable |
250 | |
251 | return true; |
252 | } |
253 | |
254 | bool io_mmap(io_t *io, vmap_t *vmap, off_t offset) |
255 | { |
256 | pr_dinfo2(io, "io_mmap(%p, %p, %lu)" , (void *) io, (void *) vmap, offset); |
257 | if (!io_mmap_perm_check(io, flags: vmap->vmflags, is_private: vmap->type == VMAP_TYPE_PRIVATE)) |
258 | return false; |
259 | |
260 | vmap->io = io; |
261 | vmap->io_offset = offset; |
262 | |
263 | if (!io->ops->mmap(io, vmap, offset)) |
264 | return false; |
265 | |
266 | if (unlikely(!vmap->on_fault)) |
267 | mos_panic("vmap->on_fault is NULL, possibly buggy io->ops->mmap() implementation" ); |
268 | |
269 | io_ref(io); // mmap increases refcount |
270 | return true; |
271 | } |
272 | |
273 | bool io_munmap(io_t *io, vmap_t *vmap, bool *unmapped) |
274 | { |
275 | pr_dinfo2(io, "io_unmap(%p, %p, %p)" , (void *) io, (void *) vmap, (void *) unmapped); |
276 | if (unlikely(io->closed)) |
277 | { |
278 | mos_warn("%p is already closed" , (void *) io); |
279 | return false; |
280 | } |
281 | |
282 | if (unlikely(!vmap->io)) |
283 | { |
284 | mos_warn("vmap->io is NULL" ); |
285 | return false; |
286 | } |
287 | |
288 | if (unlikely(vmap->io != io)) |
289 | { |
290 | mos_warn("vmap->io != io" ); |
291 | return false; |
292 | } |
293 | |
294 | if (vmap->io->ops->munmap) |
295 | { |
296 | if (unlikely(!vmap->io->ops->munmap(vmap->io, vmap, unmapped))) |
297 | { |
298 | mos_warn("vmap->io->ops->unmap() failed" ); |
299 | return false; |
300 | } |
301 | } |
302 | |
303 | io_unref(io); // unmap decreases refcount |
304 | return true; |
305 | } |
306 | |
307 | void io_get_name(const io_t *io, char *buf, size_t size) |
308 | { |
309 | if (io == NULL || io->ops == NULL || io->ops->get_name == NULL) |
310 | { |
311 | snprintf(str: buf, size, format: "<invalid io %p>" , (void *) io); |
312 | return; |
313 | } |
314 | |
315 | if (io->ops->get_name) |
316 | io->ops->get_name(io, buf, size); |
317 | else |
318 | snprintf(str: buf, size, format: "<unnamed io %p>" , (void *) io); |
319 | } |
320 | |