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