source: mainline/kernel/generic/src/ddi/ddi.c@ 8ccd2ea

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8ccd2ea was 2057572, checked in by Jakub Jermar <jakub@…>, 18 years ago

The Ultimate Solution To Illegal Virtual Aliases.
It is better to avoid them completely than to fight them.
Switch the sparc64 port to 16K pages. The TLBs and TSBs
continue to operate with 8K pages only. Page tables and
other generic parts operate with 16K pages.

Because the MMU doesn't support 16K directly, each 16K
page is emulated by a pair of 8K pages. With 16K pages,
illegal aliases cannot be created in 16K D-cache.

  • Property mode set to 100644
File size: 7.7 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 genericddi
30 * @{
31 */
32
33/**
34 * @file
35 * @brief Device Driver Interface functions.
36 *
37 * This file contains functions that comprise the Device Driver Interface.
38 * These are the functions for mapping physical memory and enabling I/O
39 * space to tasks.
40 */
41
42#include <ddi/ddi.h>
43#include <ddi/ddi_arg.h>
44#include <proc/task.h>
45#include <security/cap.h>
46#include <mm/frame.h>
47#include <mm/as.h>
48#include <synch/spinlock.h>
49#include <syscall/copy.h>
50#include <adt/btree.h>
51#include <arch.h>
52#include <align.h>
53#include <errno.h>
54
55/** This lock protects the parea_btree. */
56SPINLOCK_INITIALIZE(parea_lock);
57
58/** B+tree with enabled physical memory areas. */
59static btree_t parea_btree;
60
61/** Initialize DDI. */
62void ddi_init(void)
63{
64 btree_create(&parea_btree);
65}
66
67/** Enable piece of physical memory for mapping by physmem_map().
68 *
69 * @param parea Pointer to physical area structure.
70 *
71 * @todo This function doesn't check for overlaps. It depends on the kernel to
72 * create disjunct physical memory areas.
73 */
74void ddi_parea_register(parea_t *parea)
75{
76 ipl_t ipl;
77
78 ipl = interrupts_disable();
79 spinlock_lock(&parea_lock);
80
81 /*
82 * TODO: we should really check for overlaps here.
83 * However, we should be safe because the kernel is pretty sane and
84 * memory of different devices doesn't overlap.
85 */
86 btree_insert(&parea_btree, (btree_key_t) parea->pbase, parea, NULL);
87
88 spinlock_unlock(&parea_lock);
89 interrupts_restore(ipl);
90}
91
92/** Map piece of physical memory into virtual address space of current task.
93 *
94 * @param pf Physical address of the starting frame.
95 * @param vp Virtual address of the starting page.
96 * @param pages Number of pages to map.
97 * @param flags Address space area flags for the mapping.
98 *
99 * @return 0 on success, EPERM if the caller lacks capabilities to use this
100 * syscall, ENOENT if there is no task matching the specified ID or the
101 * physical address space is not enabled for mapping and ENOMEM if there
102 * was a problem in creating address space area.
103 */
104static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, count_t pages, int flags)
105{
106 ipl_t ipl;
107 cap_t caps;
108 mem_backend_data_t backend_data;
109
110 backend_data.base = pf;
111 backend_data.frames = pages;
112
113 /*
114 * Make sure the caller is authorised to make this syscall.
115 */
116 caps = cap_get(TASK);
117 if (!(caps & CAP_MEM_MANAGER))
118 return EPERM;
119
120 ipl = interrupts_disable();
121
122 /*
123 * Check if the physical memory area is enabled for mapping.
124 * If the architecture supports virtually indexed caches, intercept
125 * attempts to create an illegal address alias.
126 */
127 spinlock_lock(&parea_lock);
128 parea_t *parea;
129 btree_node_t *nodep;
130 parea = (parea_t *) btree_search(&parea_btree, (btree_key_t) pf, &nodep);
131 if (!parea || parea->frames < pages || ((flags & AS_AREA_CACHEABLE) &&
132 !parea->cacheable) || (!(flags & AS_AREA_CACHEABLE) &&
133 parea->cacheable)) {
134 /*
135 * This physical memory area cannot be mapped.
136 */
137 spinlock_unlock(&parea_lock);
138 interrupts_restore(ipl);
139 return ENOENT;
140 }
141 spinlock_unlock(&parea_lock);
142
143 spinlock_lock(&TASK->lock);
144
145 if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp, AS_AREA_ATTR_NONE,
146 &phys_backend, &backend_data)) {
147 /*
148 * The address space area could not have been created.
149 * We report it using ENOMEM.
150 */
151 spinlock_unlock(&TASK->lock);
152 interrupts_restore(ipl);
153 return ENOMEM;
154 }
155
156 /*
157 * Mapping is created on-demand during page fault.
158 */
159
160 spinlock_unlock(&TASK->lock);
161 interrupts_restore(ipl);
162 return 0;
163}
164
165/** Enable range of I/O space for task.
166 *
167 * @param id Task ID of the destination task.
168 * @param ioaddr Starting I/O address.
169 * @param size Size of the enabled I/O space..
170 *
171 * @return 0 on success, EPERM if the caller lacks capabilities to use this
172 * syscall, ENOENT if there is no task matching the specified ID.
173 */
174static int ddi_iospace_enable(task_id_t id, uintptr_t ioaddr, size_t size)
175{
176 ipl_t ipl;
177 cap_t caps;
178 task_t *t;
179 int rc;
180
181 /*
182 * Make sure the caller is authorised to make this syscall.
183 */
184 caps = cap_get(TASK);
185 if (!(caps & CAP_IO_MANAGER))
186 return EPERM;
187
188 ipl = interrupts_disable();
189 spinlock_lock(&tasks_lock);
190
191 t = task_find_by_id(id);
192
193 if ((!t) || (!context_check(CONTEXT, t->context))) {
194 /*
195 * There is no task with the specified ID
196 * or the task belongs to a different security
197 * context.
198 */
199 spinlock_unlock(&tasks_lock);
200 interrupts_restore(ipl);
201 return ENOENT;
202 }
203
204 /* Lock the task and release the lock protecting tasks_btree. */
205 spinlock_lock(&t->lock);
206 spinlock_unlock(&tasks_lock);
207
208 rc = ddi_iospace_enable_arch(t, ioaddr, size);
209
210 spinlock_unlock(&t->lock);
211 interrupts_restore(ipl);
212 return rc;
213}
214
215/** Wrapper for SYS_PHYSMEM_MAP syscall.
216 *
217 * @param phys_base Physical base address to map
218 * @param virt_base Destination virtual address
219 * @param pages Number of pages
220 * @param flags Flags of newly mapped pages
221 *
222 * @return 0 on success, otherwise it returns error code found in errno.h
223 */
224unative_t sys_physmem_map(unative_t phys_base, unative_t virt_base,
225 unative_t pages, unative_t flags)
226{
227 return (unative_t) ddi_physmem_map(ALIGN_DOWN((uintptr_t) phys_base,
228 FRAME_SIZE), ALIGN_DOWN((uintptr_t) virt_base, PAGE_SIZE),
229 (count_t) pages, (int) flags);
230}
231
232/** Wrapper for SYS_ENABLE_IOSPACE syscall.
233 *
234 * @param uspace_io_arg User space address of DDI argument structure.
235 *
236 * @return 0 on success, otherwise it returns error code found in errno.h
237 */
238unative_t sys_iospace_enable(ddi_ioarg_t *uspace_io_arg)
239{
240 ddi_ioarg_t arg;
241 int rc;
242
243 rc = copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
244 if (rc != 0)
245 return (unative_t) rc;
246
247 return (unative_t) ddi_iospace_enable((task_id_t) arg.task_id,
248 (uintptr_t) arg.ioaddr, (size_t) arg.size);
249}
250
251/** Disable or enable preemption.
252 *
253 * @param enable If non-zero, the preemption counter will be decremented,
254 * leading to potential enabling of preemption. Otherwise the preemption
255 * counter will be incremented, preventing preemption from occurring.
256 *
257 * @return Zero on success or EPERM if callers capabilities are not sufficient.
258 */
259unative_t sys_preempt_control(int enable)
260{
261 if (!cap_get(TASK) & CAP_PREEMPT_CONTROL)
262 return EPERM;
263 if (enable)
264 preemption_enable();
265 else
266 preemption_disable();
267 return 0;
268}
269
270/** @}
271 */
Note: See TracBrowser for help on using the repository browser.