Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/ddi/ddi.c

    rc0699467 r3164e3b  
    4545#include <mm/frame.h>
    4646#include <mm/as.h>
     47#include <mm/page.h>
    4748#include <synch/mutex.h>
    4849#include <syscall/copy.h>
     
    5253#include <errno.h>
    5354#include <trace.h>
     55#include <bitops.h>
    5456
    5557/** This lock protects the parea_btree. */
     
    8789/** Map piece of physical memory into virtual address space of current task.
    8890 *
    89  * @param pf    Physical address of the starting frame.
    90  * @param vp    Virtual address of the starting page.
     91 * @param phys  Physical address of the starting frame.
    9192 * @param pages Number of pages to map.
    9293 * @param flags Address space area flags for the mapping.
    93  *
    94  * @return 0 on success, EPERM if the caller lacks capabilities to use this
    95  *         syscall, EBADMEM if pf or vf is not page aligned, ENOENT if there
    96  *         is no task matching the specified ID or the physical address space
    97  *         is not enabled for mapping and ENOMEM if there was a problem in
    98  *         creating address space area.
    99  *
    100  */
    101 NO_TRACE static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, size_t pages,
    102     unsigned int flags)
     94 * @param virt  Virtual address of the starting page.
     95 * @param bound Lowest virtual address bound.
     96 *
     97 * @return EOK on success.
     98 * @return EPERM if the caller lacks capabilities to use this syscall.
     99 * @return EBADMEM if phys is not page aligned.
     100 * @return ENOENT if there is no task matching the specified ID or
     101 *         the physical address space is not enabled for mapping.
     102 * @return ENOMEM if there was a problem in creating address space area.
     103 *
     104 */
     105NO_TRACE static int physmem_map(uintptr_t phys, size_t pages,
     106    unsigned int flags, uintptr_t *virt, uintptr_t bound)
    103107{
    104108        ASSERT(TASK);
    105109       
    106         if ((pf % FRAME_SIZE) != 0)
    107                 return EBADMEM;
    108        
    109         if ((vp % PAGE_SIZE) != 0)
     110        if ((phys % FRAME_SIZE) != 0)
    110111                return EBADMEM;
    111112       
     
    118119       
    119120        mem_backend_data_t backend_data;
    120         backend_data.base = pf;
     121        backend_data.base = phys;
    121122        backend_data.frames = pages;
    122123       
     
    129130        btree_node_t *nodep;
    130131        parea_t *parea = (parea_t *) btree_search(&parea_btree,
    131             (btree_key_t) pf, &nodep);
     132            (btree_key_t) phys, &nodep);
    132133       
    133134        if ((parea != NULL) && (parea->frames >= pages)) {
     
    149150       
    150151        irq_spinlock_lock(&zones.lock, true);
    151         size_t znum = find_zone(ADDR2PFN(pf), pages, 0);
     152        size_t znum = find_zone(ADDR2PFN(phys), pages, 0);
    152153       
    153154        if (znum == (size_t) -1) {
     
    165166        }
    166167       
    167         if (zones.info[znum].flags & ZONE_FIRMWARE) {
    168                 /*
    169                  * Frames are part of firmware
     168        if (zones.info[znum].flags & (ZONE_FIRMWARE | ZONE_RESERVED)) {
     169                /*
     170                 * Frames are part of firmware or reserved zone
    170171                 * -> allow mapping for privileged tasks.
    171172                 */
     
    182183       
    183184map:
    184         if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp,
    185             AS_AREA_ATTR_NONE, &phys_backend, &backend_data)) {
     185        if (!as_area_create(TASK->as, flags, FRAMES2SIZE(pages),
     186            AS_AREA_ATTR_NONE, &phys_backend, &backend_data, virt, bound)) {
    186187                /*
    187188                 * The address space area was not created.
     
    207208}
    208209
     210NO_TRACE static int physmem_unmap(uintptr_t virt)
     211{
     212        // TODO: implement unmap
     213        return EOK;
     214}
     215
     216/** Wrapper for SYS_PHYSMEM_MAP syscall.
     217 *
     218 * @param phys     Physical base address to map
     219 * @param pages    Number of pages
     220 * @param flags    Flags of newly mapped pages
     221 * @param virt_ptr Destination virtual address
     222 * @param bound    Lowest virtual address bound.
     223 *
     224 * @return 0 on success, otherwise it returns error code found in errno.h
     225 *
     226 */
     227sysarg_t sys_physmem_map(uintptr_t phys, size_t pages, unsigned int flags,
     228    void *virt_ptr, uintptr_t bound)
     229{
     230        uintptr_t virt = (uintptr_t) -1;
     231        int rc = physmem_map(ALIGN_DOWN(phys, FRAME_SIZE), pages, flags,
     232            &virt, bound);
     233        if (rc != EOK)
     234                return rc;
     235       
     236        rc = copy_to_uspace(virt_ptr, &virt, sizeof(virt));
     237        if (rc != EOK) {
     238                physmem_unmap((uintptr_t) virt);
     239                return rc;
     240        }
     241       
     242        return EOK;
     243}
     244
     245sysarg_t sys_physmem_unmap(uintptr_t virt)
     246{
     247        return physmem_unmap(virt);
     248}
     249
    209250/** Enable range of I/O space for task.
    210251 *
     
    217258 *
    218259 */
    219 NO_TRACE static int ddi_iospace_enable(task_id_t id, uintptr_t ioaddr,
    220     size_t size)
     260NO_TRACE static int iospace_enable(task_id_t id, uintptr_t ioaddr, size_t size)
    221261{
    222262        /*
     
    243283        /* Lock the task and release the lock protecting tasks_btree. */
    244284        irq_spinlock_exchange(&tasks_lock, &task->lock);
    245        
    246285        int rc = ddi_iospace_enable_arch(task, ioaddr, size);
    247        
    248286        irq_spinlock_unlock(&task->lock, true);
    249287       
    250288        return rc;
    251 }
    252 
    253 /** Wrapper for SYS_PHYSMEM_MAP syscall.
    254  *
    255  * @param phys_base Physical base address to map
    256  * @param virt_base Destination virtual address
    257  * @param pages Number of pages
    258  * @param flags Flags of newly mapped pages
    259  *
    260  * @return 0 on success, otherwise it returns error code found in errno.h
    261  *
    262  */
    263 sysarg_t sys_physmem_map(sysarg_t phys_base, sysarg_t virt_base,
    264     sysarg_t pages, sysarg_t flags)
    265 {
    266         return (sysarg_t) ddi_physmem_map(ALIGN_DOWN((uintptr_t) phys_base,
    267             FRAME_SIZE), ALIGN_DOWN((uintptr_t) virt_base, PAGE_SIZE),
    268             (size_t) pages, (int) flags);
    269289}
    270290
     
    283303                return (sysarg_t) rc;
    284304       
    285         return (sysarg_t) ddi_iospace_enable((task_id_t) arg.task_id,
     305        return (sysarg_t) iospace_enable((task_id_t) arg.task_id,
    286306            (uintptr_t) arg.ioaddr, (size_t) arg.size);
    287307}
    288308
     309sysarg_t sys_iospace_disable(ddi_ioarg_t *uspace_io_arg)
     310{
     311        // TODO: implement
     312        return ENOTSUP;
     313}
     314
     315NO_TRACE static int dmamem_map(uintptr_t virt, size_t size, unsigned int map_flags,
     316    unsigned int flags, void **phys)
     317{
     318        ASSERT(TASK);
     319       
     320        // TODO: implement locking of non-anonymous mapping
     321        return page_find_mapping(virt, phys);
     322}
     323
     324NO_TRACE static int dmamem_map_anonymous(size_t size, unsigned int map_flags,
     325    unsigned int flags, void **phys, uintptr_t *virt, uintptr_t bound)
     326{
     327        ASSERT(TASK);
     328       
     329        size_t pages = SIZE2FRAMES(size);
     330        uint8_t order;
     331       
     332        /* We need the 2^order >= pages */
     333        if (pages == 1)
     334                order = 0;
     335        else
     336                order = fnzb(pages - 1) + 1;
     337       
     338        *phys = frame_alloc_noreserve(order, 0);
     339        if (*phys == NULL)
     340                return ENOMEM;
     341       
     342        mem_backend_data_t backend_data;
     343        backend_data.base = (uintptr_t) *phys;
     344        backend_data.frames = pages;
     345       
     346        if (!as_area_create(TASK->as, map_flags, size,
     347            AS_AREA_ATTR_NONE, &phys_backend, &backend_data, virt, bound)) {
     348                frame_free_noreserve((uintptr_t) *phys);
     349                return ENOMEM;
     350        }
     351       
     352        return EOK;
     353}
     354
     355NO_TRACE static int dmamem_unmap(uintptr_t virt, size_t size)
     356{
     357        // TODO: implement unlocking & unmap
     358        return EOK;
     359}
     360
     361NO_TRACE static int dmamem_unmap_anonymous(uintptr_t virt)
     362{
     363        // TODO: implement unlocking & unmap
     364        return EOK;
     365}
     366
     367sysarg_t sys_dmamem_map(size_t size, unsigned int map_flags, unsigned int flags,
     368    void *phys_ptr, void *virt_ptr, uintptr_t bound)
     369{
     370        if ((flags & DMAMEM_FLAGS_ANONYMOUS) == 0) {
     371                /*
     372                 * Non-anonymous DMA mapping
     373                 */
     374               
     375                void *phys;
     376                int rc = dmamem_map((uintptr_t) virt_ptr, size, map_flags,
     377                    flags, &phys);
     378               
     379                if (rc != EOK)
     380                        return rc;
     381               
     382                rc = copy_to_uspace(phys_ptr, &phys, sizeof(phys));
     383                if (rc != EOK) {
     384                        dmamem_unmap((uintptr_t) virt_ptr, size);
     385                        return rc;
     386                }
     387        } else {
     388                /*
     389                 * Anonymous DMA mapping
     390                 */
     391               
     392                void *phys;
     393                uintptr_t virt = (uintptr_t) -1;
     394                int rc = dmamem_map_anonymous(size, map_flags, flags,
     395                    &phys, &virt, bound);
     396                if (rc != EOK)
     397                        return rc;
     398               
     399                rc = copy_to_uspace(phys_ptr, &phys, sizeof(phys));
     400                if (rc != EOK) {
     401                        dmamem_unmap_anonymous((uintptr_t) virt);
     402                        return rc;
     403                }
     404               
     405                rc = copy_to_uspace(virt_ptr, &virt, sizeof(virt));
     406                if (rc != EOK) {
     407                        dmamem_unmap_anonymous((uintptr_t) virt);
     408                        return rc;
     409                }
     410        }
     411       
     412        return EOK;
     413}
     414
     415sysarg_t sys_dmamem_unmap(uintptr_t virt, size_t size, unsigned int flags)
     416{
     417        if ((flags & DMAMEM_FLAGS_ANONYMOUS) == 0)
     418                return dmamem_unmap(virt, size);
     419        else
     420                return dmamem_unmap_anonymous(virt);
     421}
     422
    289423/** @}
    290424 */
Note: See TracChangeset for help on using the changeset viewer.