Subversion Repositories HelenOS-historic

Rev

Rev 1424 | Rev 1429 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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. /**
  30.  * @file    ddi.c
  31.  * @brief   Device Driver Interface functions.
  32.  *
  33.  * This file contains functions that comprise the Device Driver Interface.
  34.  * These are the functions for mapping physical memory and enabling I/O
  35.  * space to tasks.
  36.  */
  37.  
  38. #include <ddi/ddi.h>
  39. #include <ddi/ddi_arg.h>
  40. #include <proc/task.h>
  41. #include <security/cap.h>
  42. #include <mm/frame.h>
  43. #include <mm/as.h>
  44. #include <synch/spinlock.h>
  45. #include <syscall/copy.h>
  46. #include <arch.h>
  47. #include <align.h>
  48. #include <errno.h>
  49.  
  50. /** Map piece of physical memory into virtual address space of specified task.
  51.  *
  52.  * @param id Task ID of the destination task.
  53.  * @param pf Physical frame address of the starting frame.
  54.  * @param vp Virtual page address of the starting page.
  55.  * @param pages Number of pages to map.
  56.  * @param writable If true, the mapping will be created writable.
  57.  *
  58.  * @return 0 on success, EPERM if the caller lacks capabilities to use this syscall,
  59.  *     ENOENT if there is no task matching the specified ID and ENOMEM if
  60.  *     there was a problem in creating address space area.
  61.  */
  62. static int ddi_physmem_map(task_id_t id, __address pf, __address vp, count_t pages, bool writable)
  63. {
  64.     ipl_t ipl;
  65.     cap_t caps;
  66.     task_t *t;
  67.     int flags;
  68.     mem_backend_data_t backend_data;
  69.  
  70.     backend_data.base = pf;
  71.     backend_data.frames = pages;
  72.    
  73.     /*
  74.      * Make sure the caller is authorised to make this syscall.
  75.      */
  76.     caps = cap_get(TASK);
  77.     if (!(caps & CAP_MEM_MANAGER))
  78.         return EPERM;
  79.    
  80.     ipl = interrupts_disable();
  81.     spinlock_lock(&tasks_lock);
  82.    
  83.     t = task_find_by_id(id);
  84.    
  85.     if (!t) {
  86.         /*
  87.          * There is no task with the specified ID.
  88.          */
  89.         spinlock_unlock(&tasks_lock);
  90.         interrupts_restore(ipl);
  91.         return ENOENT;
  92.     }
  93.  
  94.     /*
  95.      * TODO: We are currently lacking support for task destroying.
  96.      * Once it is added to the kernel, we must take care to
  97.      * synchronize in a way that prevents race conditions here.
  98.      */
  99.    
  100.     /* Lock the task and release the lock protecting tasks_btree. */
  101.     spinlock_lock(&t->lock);
  102.     spinlock_unlock(&tasks_lock);
  103.    
  104.     flags = AS_AREA_READ;
  105.     if (writable)
  106.         flags |= AS_AREA_WRITE;
  107.     if (!as_area_create(t->as, flags, pages * PAGE_SIZE, vp, AS_AREA_ATTR_NONE,
  108.         &phys_backend, &backend_data)) {
  109.         /*
  110.          * The address space area could not have been created.
  111.          * We report it using ENOMEM.
  112.          */
  113.         spinlock_unlock(&t->lock);
  114.         interrupts_restore(ipl);
  115.         return ENOMEM;
  116.     }
  117.    
  118.     /*
  119.      * Mapping is created on-demand during page fault.
  120.      */
  121.    
  122.     spinlock_unlock(&t->lock);
  123.     interrupts_restore(ipl);
  124.     return 0;
  125. }
  126.  
  127. /** Enable range of I/O space for task.
  128.  *
  129.  * @param id Task ID of the destination task.
  130.  * @param ioaddr Starting I/O address.
  131.  * @param size Size of the enabled I/O space..
  132.  *
  133.  * @return 0 on success, EPERM if the caller lacks capabilities to use this syscall,
  134.  *     ENOENT if there is no task matching the specified ID.
  135.  */
  136. static int ddi_iospace_enable(task_id_t id, __address ioaddr, size_t size)
  137. {
  138.     ipl_t ipl;
  139.     cap_t caps;
  140.     task_t *t;
  141.     int rc;
  142.    
  143.     /*
  144.      * Make sure the caller is authorised to make this syscall.
  145.      */
  146.     caps = cap_get(TASK);
  147.     if (!(caps & CAP_IO_MANAGER))
  148.         return EPERM;
  149.    
  150.     ipl = interrupts_disable();
  151.     spinlock_lock(&tasks_lock);
  152.    
  153.     t = task_find_by_id(id);
  154.    
  155.     if (!t) {
  156.         /*
  157.          * There is no task with the specified ID.
  158.          */
  159.         spinlock_unlock(&tasks_lock);
  160.         interrupts_restore(ipl);
  161.         return ENOENT;
  162.     }
  163.  
  164.     /*
  165.      * TODO: We are currently lacking support for task destroying.
  166.      * Once it is added to the kernel, we must take care to
  167.      * synchronize in a way that prevents race conditions here.
  168.      */
  169.    
  170.     /* Lock the task and release the lock protecting tasks_btree. */
  171.     spinlock_lock(&t->lock);
  172.     spinlock_unlock(&tasks_lock);
  173.  
  174.     rc = ddi_iospace_enable_arch(t, ioaddr, size);
  175.    
  176.     spinlock_unlock(&t->lock);
  177.     interrupts_restore(ipl);
  178.     return rc;
  179. }
  180.  
  181. /** Wrapper for SYS_MAP_PHYSMEM syscall.
  182.  *
  183.  * @param User space address of memory DDI argument structure.
  184.  *
  185.  * @return 0 on success, otherwise it returns error code found in errno.h
  186.  */
  187. __native sys_physmem_map(ddi_memarg_t *uspace_mem_arg)
  188. {
  189.     ddi_memarg_t arg;
  190.     int rc;
  191.    
  192.     rc = copy_from_uspace(&arg, uspace_mem_arg, sizeof(ddi_memarg_t));
  193.     if (rc != 0)
  194.         return (__native) rc;
  195.        
  196.     return (__native) ddi_physmem_map((task_id_t) arg.task_id, ALIGN_DOWN((__address) arg.phys_base, FRAME_SIZE),
  197.                       ALIGN_DOWN((__address) arg.virt_base, PAGE_SIZE), (count_t) arg.pages,
  198.                       (bool) arg.writable);
  199. }
  200.  
  201. /** Wrapper for SYS_ENABLE_IOSPACE syscall.
  202.  *
  203.  * @param User space address of DDI argument structure.
  204.  *
  205.  * @return 0 on success, otherwise it returns error code found in errno.h
  206.  */
  207. __native sys_iospace_enable(ddi_ioarg_t *uspace_io_arg)
  208. {
  209.     ddi_ioarg_t arg;
  210.     int rc;
  211.    
  212.     rc = copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
  213.     if (rc != 0)
  214.         return (__native) rc;
  215.        
  216.     return (__native) ddi_iospace_enable((task_id_t) arg.task_id, (__address) arg.ioaddr, (size_t) arg.size);
  217. }
  218.  
  219. /** Disable or enable preemption.
  220.  *
  221.  * @param enable If non-zero, the preemption counter will be decremented, leading to potential
  222.  *       enabling of preemption. Otherwise the preemption counter will be incremented,
  223.  *       preventing preemption from occurring.
  224.  *
  225.  * @return Zero on success or EPERM if callers capabilities are not sufficient.
  226.  */
  227. __native sys_preempt_control(int enable)
  228. {
  229.         if (! cap_get(TASK) & CAP_PREEMPT_CONTROL)
  230.                 return EPERM;
  231.         if (enable)
  232.                 preemption_enable();
  233.         else
  234.                 preemption_disable();
  235.         return 0;
  236. }
  237.