Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset c6ae4c2 in mainline


Ignore:
Timestamp:
2011-12-16T21:12:52Z (10 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master
Children:
c8751452
Parents:
e2718e1
Message:

implement basic DMA memory mapping routines
no persistent locking (pinning) of the DMA memory is currently implemented (this can be dangerous)
no unmapping is implemented
special allocations (< 16 MB, < 4 GB) are not supported yet

Files:
11 edited

Legend:

Unmodified
Added
Removed
  • abi/include/ddi/arg.h

    re2718e1 rc6ae4c2  
    3636#define ABI_DDI_ARG_H_
    3737
     38#define DMAMEM_FLAGS_ANONYMOUS  0x01
     39
    3840/** Structure encapsulating arguments for SYS_PHYSMEM_MAP syscall. */
    3941typedef struct {
  • abi/include/syscall.h

    re2718e1 rc6ae4c2  
    8585        SYS_DEVICE_ASSIGN_DEVNO,
    8686        SYS_PHYSMEM_MAP,
     87        SYS_DMAMEM_MAP,
     88        SYS_DMAMEM_UNMAP,
    8789        SYS_IOSPACE_ENABLE,
    8890        SYS_REGISTER_IRQ,
  • kernel/generic/include/ddi/ddi.h

    re2718e1 rc6ae4c2  
    5555extern void ddi_parea_register(parea_t *);
    5656
    57 extern sysarg_t sys_physmem_map(sysarg_t, sysarg_t, sysarg_t, sysarg_t);
     57extern sysarg_t sys_physmem_map(uintptr_t, uintptr_t, size_t, unsigned int);
     58
     59extern sysarg_t sys_dmamem_map(uintptr_t, size_t, unsigned int, unsigned int,
     60    void *);
     61extern sysarg_t sys_dmamem_unmap(uintptr_t, size_t, unsigned int);
     62
    5863extern sysarg_t sys_iospace_enable(ddi_ioarg_t *);
    5964
  • kernel/generic/include/mm/page.h

    re2718e1 rc6ae4c2  
    6666extern uintptr_t hw_map(uintptr_t, size_t);
    6767
    68 extern sysarg_t sys_page_find_mapping(uintptr_t, uintptr_t *);
     68extern int page_find_mapping(uintptr_t, void **);
     69extern sysarg_t sys_page_find_mapping(uintptr_t, void *);
    6970
    7071#endif
  • kernel/generic/src/ddi/ddi.c

    re2718e1 rc6ae4c2  
    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 p  Physical address of the starting frame.
    90  * @param v  Virtual address of the starting page.
     91 * @param phys  Physical address of the starting frame.
     92 * @param virt  Virtual address of the starting page.
    9193 * @param pages Number of pages to map.
    9294 * @param flags Address space area flags for the mapping.
    9395 *
    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,
     96 * @return EOK on success.
     97 * @return EPERM if the caller lacks capabilities to use this syscall.
     98 * @return EBADMEM if phys or virt is not page aligned.
     99 * @return ENOENT if there is no task matching the specified ID or
     100 *         the physical address space is not enabled for mapping.
     101 * @return ENOMEM if there was a problem in creating address space area.
     102 *
     103 */
     104NO_TRACE static int ddi_physmem_map(uintptr_t phys, uintptr_t virt, size_t pages,
    102105    unsigned int flags)
    103106{
    104107        ASSERT(TASK);
    105108       
    106         if ((pf % FRAME_SIZE) != 0)
     109        if ((phys % FRAME_SIZE) != 0)
    107110                return EBADMEM;
    108111       
    109         if ((vp % PAGE_SIZE) != 0)
     112        if ((virt % PAGE_SIZE) != 0)
    110113                return EBADMEM;
    111114       
     
    118121       
    119122        mem_backend_data_t backend_data;
    120         backend_data.base = pf;
     123        backend_data.base = phys;
    121124        backend_data.frames = pages;
    122125       
     
    129132        btree_node_t *nodep;
    130133        parea_t *parea = (parea_t *) btree_search(&parea_btree,
    131             (btree_key_t) pf, &nodep);
     134            (btree_key_t) phys, &nodep);
    132135       
    133136        if ((parea != NULL) && (parea->frames >= pages)) {
     
    149152       
    150153        irq_spinlock_lock(&zones.lock, true);
    151         size_t znum = find_zone(ADDR2PFN(pf), pages, 0);
     154        size_t znum = find_zone(ADDR2PFN(phys), pages, 0);
    152155       
    153156        if (znum == (size_t) -1) {
     
    182185       
    183186map:
    184         if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp,
     187        if (!as_area_create(TASK->as, flags, FRAMES2SIZE(pages), virt,
    185188            AS_AREA_ATTR_NONE, &phys_backend, &backend_data)) {
    186189                /*
     
    253256/** Wrapper for SYS_PHYSMEM_MAP syscall.
    254257 *
    255  * @param phys_base Physical base address to map
    256  * @param virt_base Destination virtual address
     258 * @param phys  Physical base address to map
     259 * @param virt  Destination virtual address
    257260 * @param pages Number of pages
    258261 * @param flags Flags of newly mapped pages
     
    261264 *
    262265 */
    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);
     266sysarg_t sys_physmem_map(uintptr_t phys, uintptr_t virt,
     267    size_t pages, unsigned int flags)
     268{
     269        return (sysarg_t)
     270            ddi_physmem_map(ALIGN_DOWN(phys, FRAME_SIZE),
     271            ALIGN_DOWN(virt, PAGE_SIZE), pages, flags);
    269272}
    270273
     
    287290}
    288291
     292NO_TRACE static int dmamem_map(uintptr_t virt, size_t size,
     293    unsigned int map_flags, unsigned int flags, void **phys)
     294{
     295        ASSERT(TASK);
     296       
     297        if ((flags & DMAMEM_FLAGS_ANONYMOUS) == 0) {
     298                // TODO: implement locking of non-anonymous mapping
     299                return page_find_mapping(virt, phys);
     300        } else {
     301                // TODO: implement locking
     302               
     303                if ((virt % PAGE_SIZE) != 0)
     304                        return EBADMEM;
     305               
     306                size_t pages = SIZE2FRAMES(size);
     307                uint8_t order;
     308               
     309                /* We need the 2^order >= pages */
     310                if (pages == 1)
     311                        order = 0;
     312                else
     313                        order = fnzb(pages - 1) + 1;
     314               
     315                *phys = frame_alloc_noreserve(order, 0);
     316                if (*phys == NULL)
     317                        return ENOMEM;
     318               
     319                mem_backend_data_t backend_data;
     320                backend_data.base = (uintptr_t) *phys;
     321                backend_data.frames = pages;
     322               
     323                if (!as_area_create(TASK->as, map_flags, size, virt,
     324                    AS_AREA_ATTR_NONE, &phys_backend, &backend_data)) {
     325                        frame_free_noreserve((uintptr_t) *phys);
     326                        return ENOMEM;
     327                }
     328               
     329                return EOK;
     330        }
     331}
     332
     333NO_TRACE static int dmamem_unmap(uintptr_t virt, size_t size,
     334    unsigned int flags)
     335{
     336        // TODO: implement unlocking & unmap
     337        return EOK;
     338}
     339
     340sysarg_t sys_dmamem_map(uintptr_t virt, size_t size, unsigned int map_flags,
     341    unsigned int flags, void *phys_ptr)
     342{
     343        void *phys;
     344        int rc = dmamem_map(virt, size, map_flags, flags, &phys);
     345        if (rc != EOK)
     346                return rc;
     347       
     348        rc = copy_to_uspace(phys_ptr, &phys, sizeof(phys));
     349        if (rc != EOK) {
     350                dmamem_unmap(virt, size, flags);
     351                return rc;
     352        }
     353       
     354        return EOK;
     355}
     356
     357sysarg_t sys_dmamem_unmap(uintptr_t virt, size_t size, unsigned int flags)
     358{
     359        return dmamem_unmap(virt, size, flags);
     360}
     361
    289362/** @}
    290363 */
  • kernel/generic/src/syscall/syscall.c

    re2718e1 rc6ae4c2  
    176176        (syshandler_t) sys_device_assign_devno,
    177177        (syshandler_t) sys_physmem_map,
     178        (syshandler_t) sys_dmamem_map,
     179        (syshandler_t) sys_dmamem_unmap,
    178180        (syshandler_t) sys_iospace_enable,
    179181        (syshandler_t) sys_register_irq,
  • uspace/lib/c/generic/as.c

    re2718e1 rc6ae4c2  
    117117/** Find mapping to physical address.
    118118 *
    119  * @param address Virtual address in question (virtual).
    120  * @param[out] frame Frame address (physical).
    121  * @return Error code.
    122  * @retval EOK No error, @p frame holds the translation.
    123  * @retval ENOENT Mapping not found.
     119 * @param      virt Virtual address to find mapping for.
     120 * @param[out] phys Physical adress.
     121 *
     122 * @return EOK on no error.
     123 * @retval ENOENT if no mapping was found.
     124 *
    124125 */
    125 int as_get_physical_mapping(const void *address, uintptr_t *frame)
     126int as_get_physical_mapping(const void *virt, uintptr_t *phys)
    126127{
    127         uintptr_t tmp_frame;
    128         uintptr_t virt = (uintptr_t) address;
    129        
    130         int rc = (int) __SYSCALL2(SYS_PAGE_FIND_MAPPING,
    131             (sysarg_t) virt, (sysarg_t) &tmp_frame);
    132         if (rc != EOK) {
    133                 return rc;
    134         }
    135        
    136         if (frame != NULL) {
    137                 *frame = tmp_frame;
    138         }
    139        
    140         return EOK;
     128        return (int) __SYSCALL2(SYS_PAGE_FIND_MAPPING, (sysarg_t) virt,
     129            (sysarg_t) phys);
    141130}
    142131
  • uspace/lib/c/generic/ddi.c

    re2718e1 rc6ae4c2  
    3333 */
    3434
     35#include <assert.h>
     36#include <unistd.h>
     37#include <errno.h>
    3538#include <sys/types.h>
    3639#include <abi/ddi/arg.h>
     
    5760 * Caller of this function must have the CAP_MEM_MANAGER capability.
    5861 *
    59  * @param p  Physical address of the starting frame.
    60  * @param v  Virtual address of the starting page.
     62 * @param phys  Physical address of the starting frame.
     63 * @param virt  Virtual address of the starting page.
    6164 * @param pages Number of pages to map.
    6265 * @param flags Flags for the new address space area.
     
    6972 *
    7073 */
    71 int physmem_map(void *pf, void *vp, size_t pages, unsigned int flags)
     74int physmem_map(void *phys, void *virt, size_t pages, unsigned int flags)
    7275{
    73         return __SYSCALL4(SYS_PHYSMEM_MAP, (sysarg_t) pf, (sysarg_t) vp,
    74             pages, flags);
     76        return __SYSCALL4(SYS_PHYSMEM_MAP, (sysarg_t) phys,
     77            (sysarg_t) virt, pages, flags);
    7578}
    7679
    77 int dmamem_map(dmamem_t *dmamem, size_t pages, unsigned int map_flags,
    78     unsigned int dma_flags)
     80int dmamem_map(void *virt, size_t size, unsigned int map_flags,
     81    unsigned int flags, void **phys)
    7982{
    80         // FIXME TODO
    81         return -1;
     83        return (int) __SYSCALL5(SYS_DMAMEM_MAP, (sysarg_t) virt,
     84            (sysarg_t) size, (sysarg_t) map_flags, (sysarg_t) flags,
     85            (sysarg_t) phys);
    8286}
    8387
    84 int dmamem_unmap(dmamem_t *dmamem)
     88int dmamem_map_anonymous(size_t size, unsigned int map_flags,
     89    unsigned int flags, void **phys, void **virt)
    8590{
    86         // FIXME TODO
    87         return -1;
     91        *virt = as_get_mappable_page(size);
     92        if (*virt == NULL)
     93                return ENOMEM;
     94       
     95        return dmamem_map(*virt, size, map_flags,
     96            flags | DMAMEM_FLAGS_ANONYMOUS, phys);
    8897}
    8998
    90 int dmamem_lock(void *virt, void **phys, size_t pages)
     99int dmamem_unmap(void *virt, size_t size, unsigned int flags)
    91100{
    92         // FIXME TODO
    93         return -1;
     101        return __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, (sysarg_t) size,
     102            (sysarg_t) flags);
    94103}
    95104
    96 int dmamem_unlock(void *virt, size_t pages)
     105int dmamem_unmap_anonymous(void *virt)
    97106{
    98         // FIXME TODO
    99         return -1;
     107        return __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, 0,
     108            DMAMEM_FLAGS_ANONYMOUS);
    100109}
    101110
  • uspace/lib/c/include/ddi.h

    re2718e1 rc6ae4c2  
    4040#include <task.h>
    4141
    42 typedef struct {
    43         /** Physical memory */
    44         void *phys;
    45        
    46         /** Virtual memory */
    47         void *virt;
    48        
    49         /** Size in pages */
    50         size_t size;
    51        
    52         /** Mapping flags */
    53         unsigned int flags;
    54 } dmamem_t;
     42extern int device_assign_devno(void);
    5543
    56 extern int device_assign_devno(void);
    5744extern int physmem_map(void *, void *, size_t, unsigned int);
    58 extern int dmamem_map(dmamem_t *, size_t, unsigned int, unsigned int);
    59 extern int dmamem_unmap(dmamem_t *);
    60 extern int dmamem_lock(void *, void **, size_t);
    61 extern int dmamem_unlock(void *, size_t);
     45
     46extern int dmamem_map(void *, size_t, unsigned int, unsigned int, void **);
     47extern int dmamem_map_anonymous(size_t, unsigned int, unsigned int, void **,
     48    void **);
     49extern int dmamem_unmap(void *, size_t, unsigned int);
     50extern int dmamem_unmap_anonymous(void *);
     51
    6252extern int iospace_enable(task_id_t, void *, unsigned long);
    6353extern int pio_enable(void *, size_t, void **);
     54
    6455extern int register_irq(int, int, int, irq_code_t *);
    6556extern int unregister_irq(int, int);
  • uspace/lib/nic/include/nic.h

    re2718e1 rc6ae4c2  
    275275
    276276/* Packet DMA lock */
    277 extern void *nic_dma_lock_packet(packet_t *);
    278 extern int nic_dma_unlock_packet(packet_t *);
     277extern int nic_dma_lock_packet(packet_t *, size_t, void **);
     278extern int nic_dma_unlock_packet(packet_t *, size_t);
    279279
    280280#endif // __NIC_H__
  • uspace/lib/nic/src/nic_driver.c

    re2718e1 rc6ae4c2  
    4646#include <ipc/irc.h>
    4747#include <sysinfo.h>
    48 
     48#include <as.h>
    4949#include <devman.h>
    5050#include <ddf/interrupt.h>
     
    13341334 * @return physical address of packet
    13351335 */
    1336 void *nic_dma_lock_packet(packet_t *packet)
    1337 {
    1338         void *phys_addr;
    1339         int rc = dmamem_lock(packet, &phys_addr, 1);
    1340         if (rc != EOK)
    1341                 return NULL;
    1342        
    1343         return phys_addr;
     1336int nic_dma_lock_packet(packet_t *packet, size_t size, void **phys)
     1337{
     1338        return dmamem_map(packet, SIZE2PAGES(size), 0, 0, phys);
    13441339}
    13451340
     
    13481343 * @param packet
    13491344 */
    1350 int nic_dma_unlock_packet(packet_t *packet)
    1351 {
    1352         return dmamem_unlock(packet, 1);
     1345int nic_dma_unlock_packet(packet_t *packet, size_t size)
     1346{
     1347        return dmamem_unmap(packet, size, 0);
    13531348}
    13541349
Note: See TracChangeset for help on using the changeset viewer.