source: mainline/uspace/lib/c/generic/ddi.c@ 1abcf1d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1abcf1d was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35#include <assert.h>
36#include <atomic.h>
37#include <stdio.h>
38#include <errno.h>
39#include <abi/ddi/arg.h>
40#include <ddi.h>
41#include <libarch/ddi.h>
42#include <device/hw_res.h>
43#include <device/hw_res_parsed.h>
44#include <device/pio_window.h>
45#include <libc.h>
46#include <task.h>
47#include <as.h>
48#include <align.h>
49#include <libarch/config.h>
50#include "private/libc.h"
51
52
53/** Map a piece of physical memory to task.
54 *
55 * Caller of this function must have the PERM_MEM_MANAGER permission.
56 *
57 * @param phys Physical address of the starting frame.
58 * @param pages Number of pages to map.
59 * @param flags Flags for the new address space area.
60 * @param virt Virtual address of the starting page.
61 * If set to AS_AREA_ANY ((void *) -1), a suitable value
62 * is found by the kernel, otherwise the kernel tries to
63 * obey the desired value.
64 *
65 * @return EOK on success.
66 * @return EPERM if the caller lacks the PERM_MEM_MANAGER permission.
67 * @return ENOMEM if there was some problem in creating
68 * the address space area.
69 *
70 */
71errno_t physmem_map(uintptr_t phys, size_t pages, unsigned int flags, void **virt)
72{
73 return (errno_t) __SYSCALL5(SYS_PHYSMEM_MAP, (sysarg_t) phys,
74 pages, flags, (sysarg_t) virt, (sysarg_t) __entry);
75}
76
77/** Unmap a piece of physical memory to task.
78 *
79 * Caller of this function must have the PERM_MEM_MANAGER permission.
80 *
81 * @param virt Virtual address from the phys-mapped region.
82 *
83 * @return EOK on success.
84 * @return EPERM if the caller lacks the PERM_MEM_MANAGER permission.
85 *
86 */
87errno_t physmem_unmap(void *virt)
88{
89 return (errno_t) __SYSCALL1(SYS_PHYSMEM_UNMAP, (sysarg_t) virt);
90}
91
92/** Lock a piece physical memory for DMA transfers.
93 *
94 * The mapping of the specified virtual memory address
95 * to physical memory address is locked in order to
96 * make it safe for DMA transferts.
97 *
98 * Caller of this function must have the PERM_MEM_MANAGER permission.
99 *
100 * @param virt Virtual address of the memory to be locked.
101 * @param size Number of bytes to lock.
102 * @param map_flags Desired virtual memory area flags.
103 * @param flags Flags for the physical memory address.
104 * @param phys Locked physical memory address.
105 *
106 * @return EOK on success.
107 * @return EPERM if the caller lacks the PERM_MEM_MANAGER permission.
108 * @return ENOMEM if there was some problem in creating
109 * the address space area.
110 *
111 */
112errno_t dmamem_map(void *virt, size_t size, unsigned int map_flags,
113 unsigned int flags, uintptr_t *phys)
114{
115 return (errno_t) __SYSCALL6(SYS_DMAMEM_MAP, (sysarg_t) size,
116 (sysarg_t) map_flags, (sysarg_t) flags & ~DMAMEM_FLAGS_ANONYMOUS,
117 (sysarg_t) phys, (sysarg_t) virt, 0);
118}
119
120/** Map a piece of physical memory suitable for DMA transfers.
121 *
122 * Caller of this function must have the PERM_MEM_MANAGER permission.
123 *
124 * @param size Number of bytes to map.
125 * @param constraint Bit mask defining the contraint on the physical
126 * address to be mapped.
127 * @param map_flags Desired virtual memory area flags.
128 * @param flags Flags for the physical memory address.
129 * @param virt Virtual address of the starting page.
130 * If set to AS_AREA_ANY ((void *) -1), a suitable value
131 * is found by the kernel, otherwise the kernel tries to
132 * obey the desired value.
133 *
134 * @return EOK on success.
135 * @return EPERM if the caller lacks the PERM_MEM_MANAGER permission.
136 * @return ENOMEM if there was some problem in creating
137 * the address space area.
138 *
139 */
140errno_t dmamem_map_anonymous(size_t size, uintptr_t constraint,
141 unsigned int map_flags, unsigned int flags, uintptr_t *phys, void **virt)
142{
143 *phys = constraint;
144
145 return (errno_t) __SYSCALL6(SYS_DMAMEM_MAP, (sysarg_t) size,
146 (sysarg_t) map_flags, (sysarg_t) flags | DMAMEM_FLAGS_ANONYMOUS,
147 (sysarg_t) phys, (sysarg_t) virt, (sysarg_t) __entry);
148}
149
150errno_t dmamem_unmap(void *virt, size_t size)
151{
152 return (errno_t) __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, (sysarg_t) size, 0);
153}
154
155errno_t dmamem_unmap_anonymous(void *virt)
156{
157 return (errno_t) __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, 0,
158 DMAMEM_FLAGS_ANONYMOUS);
159}
160
161/** Enable I/O space range to task.
162 *
163 * Caller of this function must have the PERM_IO_MANAGER permission.
164 *
165 * @param id Task ID.
166 * @param ioaddr Starting address of the I/O range.
167 * @param size Size of the range.
168 *
169 * @return EOK on success
170 * @return EPERM if the caller lacks the PERM_IO_MANAGER permission
171 * @return ENOENT if there is no task with specified ID
172 * @return ENOMEM if there was some problem in allocating memory.
173 *
174 */
175static errno_t iospace_enable(task_id_t id, void *ioaddr, size_t size)
176{
177 const ddi_ioarg_t arg = {
178 .task_id = id,
179 .ioaddr = ioaddr,
180 .size = size
181 };
182
183 return (errno_t) __SYSCALL1(SYS_IOSPACE_ENABLE, (sysarg_t) &arg);
184}
185
186/** Disable I/O space range to task.
187 *
188 * Caller of this function must have the PERM_IO_MANAGER permission.
189 *
190 * @param id Task ID.
191 * @param ioaddr Starting address of the I/O range.
192 * @param size Size of the range.
193 *
194 * @return EOK on success
195 * @return EPERM if the caller lacks the PERM_IO_MANAGER permission
196 * @return ENOENT if there is no task with specified ID
197 *
198 */
199static errno_t iospace_disable(task_id_t id, void *ioaddr, size_t size)
200{
201 const ddi_ioarg_t arg = {
202 .task_id = id,
203 .ioaddr = ioaddr,
204 .size = size
205 };
206
207 return (errno_t) __SYSCALL1(SYS_IOSPACE_DISABLE, (sysarg_t) &arg);
208}
209
210/** Enable PIO for specified address range.
211 *
212 * @param range I/O range to be enable.
213 * @param virt Virtual address for application's PIO operations.
214 */
215errno_t pio_enable_range(addr_range_t *range, void **virt)
216{
217 return pio_enable(RNGABSPTR(*range), RNGSZ(*range), virt);
218}
219
220/** Enable PIO for specified HW resource wrt. to the PIO window.
221 *
222 * @param win PIO window. May be NULL if the resources are known to be
223 * absolute.
224 * @param res Resources specifying the I/O range wrt. to the PIO window.
225 * @param virt Virtual address for application's PIO operations.
226 *
227 * @return EOK on success.
228 * @return An error code on failure.
229 *
230 */
231errno_t pio_enable_resource(pio_window_t *win, hw_resource_t *res, void **virt)
232{
233 uintptr_t addr;
234 size_t size;
235
236 switch (res->type) {
237 case IO_RANGE:
238 addr = res->res.io_range.address;
239 if (res->res.io_range.relative) {
240 if (!win)
241 return EINVAL;
242 addr += win->io.base;
243 }
244 size = res->res.io_range.size;
245 break;
246 case MEM_RANGE:
247 addr = res->res.mem_range.address;
248 if (res->res.mem_range.relative) {
249 if (!win)
250 return EINVAL;
251 addr += win->mem.base;
252 }
253 size = res->res.mem_range.size;
254 break;
255 default:
256 return EINVAL;
257 }
258
259 return pio_enable((void *) addr, size, virt);
260}
261
262/** Enable PIO for specified I/O range.
263 *
264 * @param pio_addr I/O start address.
265 * @param size Size of the I/O region.
266 * @param virt Virtual address for application's
267 * PIO operations. Can be NULL for PMIO.
268 *
269 * @return EOK on success.
270 * @return An error code on failure.
271 *
272 */
273errno_t pio_enable(void *pio_addr, size_t size, void **virt)
274{
275#ifdef IO_SPACE_BOUNDARY
276 if (pio_addr < IO_SPACE_BOUNDARY) {
277 if (virt)
278 *virt = pio_addr;
279 return iospace_enable(task_get_id(), pio_addr, size);
280 }
281#else
282 (void) iospace_enable;
283#endif
284 if (!virt)
285 return EINVAL;
286
287 uintptr_t phys_frame =
288 ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE);
289 size_t offset = (uintptr_t) pio_addr - phys_frame;
290 size_t pages = SIZE2PAGES(offset + size);
291
292 void *virt_page = AS_AREA_ANY;
293 errno_t rc = physmem_map(phys_frame, pages,
294 AS_AREA_READ | AS_AREA_WRITE, &virt_page);
295 if (rc != EOK)
296 return rc;
297
298 *virt = virt_page + offset;
299 return EOK;
300}
301
302/** Disable PIO for specified I/O range.
303 *
304 * @param virt I/O start address.
305 * @param size Size of the I/O region.
306 *
307 * @return EOK on success.
308 * @return An error code on failure.
309 *
310 */
311errno_t pio_disable(void *virt, size_t size)
312{
313#ifdef IO_SPACE_BOUNDARY
314 if (virt < IO_SPACE_BOUNDARY)
315 return iospace_disable(task_get_id(), virt, size);
316#else
317 (void) iospace_disable;
318#endif
319 return physmem_unmap(virt);
320}
321
322void pio_write_8(ioport8_t *reg, uint8_t val)
323{
324 pio_trace_log(reg, val, true);
325 arch_pio_write_8(reg, val);
326}
327
328void pio_write_16(ioport16_t *reg, uint16_t val)
329{
330 pio_trace_log(reg, val, true);
331 arch_pio_write_16(reg, val);
332}
333
334void pio_write_32(ioport32_t *reg, uint32_t val)
335{
336 pio_trace_log(reg, val, true);
337 arch_pio_write_32(reg, val);
338}
339
340void pio_write_64(ioport64_t *reg, uint64_t val)
341{
342 pio_trace_log(reg, val, true);
343 arch_pio_write_64(reg, val);
344}
345
346uint8_t pio_read_8(const ioport8_t *reg)
347{
348 const uint8_t val = arch_pio_read_8(reg);
349 pio_trace_log(reg, val, false);
350 return val;
351}
352
353uint16_t pio_read_16(const ioport16_t *reg)
354{
355 const uint16_t val = arch_pio_read_16(reg);
356 pio_trace_log(reg, val, false);
357 return val;
358}
359
360uint32_t pio_read_32(const ioport32_t *reg)
361{
362 const uint32_t val = arch_pio_read_32(reg);
363 pio_trace_log(reg, val, false);
364 return val;
365}
366
367uint64_t pio_read_64(const ioport64_t *reg)
368{
369 const uint64_t val = arch_pio_read_64(reg);
370 pio_trace_log(reg, val, false);
371 return val;
372}
373
374/** @}
375 */
Note: See TracBrowser for help on using the repository browser.