Changeset fbcdeb8 in mainline for uspace/lib/c


Ignore:
Timestamp:
2011-12-19T17:30:39Z (14 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
58f6229
Parents:
24cf31f1
Message:

Remove the two-phase way of creating virtual memory areas (first asking for a mappable address and then mapping it) which was prone to race conditions when two or more calls to as_get_mappable_page() and as_area_create() were interleaved. This for example caused the e1k driver to randomly fail.

The memory area related syscalls and IPC calls have all been altered to accept a special value (void *) -1, representing a demand to atomically search for a mappable address space "hole" and map to it.

Individual changes:

  • IPC_M_SHARE_OUT: the destination address space area is supplied by the kernel, the callee only specifies the lower bound

(the address is returned to the callee via a pointer in an IPC reply argument)

  • IPC_M_SHARE_IN: the destination address space ares is supplied by the kernel, the callee only specifies the lower bound

(the address is returned to the caller as usual via an IPC argument)

  • SYS_AS_GET_UNMAPPED_AREA was removed
  • dummy implementations of SYS_PHYSMEM_UNMAP and SYS_IOSPACE_DISABLE were added for the sake of symmetry (they do nothing yet)
  • SYS_PHYSMEM_MAP and SYS_DMAMEM_MAP were altered to accept (void *) -1 as address space area base and a lower bound
  • kernel as_area_create() and as_area_share() were altered to accept (void *) -1 as address space area base and a lower bound
  • uspace libraries and programs were altered to reflect the new API
Location:
uspace/lib/c
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/as.c

    r24cf31f1 rfbcdeb8  
    4545/** Create address space area.
    4646 *
    47  * @param address Virtual address where to place new address space area.
    48  * @param size    Size of the area.
    49  * @param flags   Flags describing type of the area.
     47 * @param base  Starting virtual address of the area.
     48 *              If set to (void *) -1, the kernel finds
     49 *              a mappable area.
     50 * @param size  Size of the area.
     51 * @param flags Flags describing type of the area.
    5052 *
    51  * @return address on success, (void *) -1 otherwise.
     53 * @return Starting virtual address of the created area on success.
     54 * @return (void *) -1 otherwise.
    5255 *
    5356 */
    54 void *as_area_create(void *address, size_t size, unsigned int flags)
     57void *as_area_create(void *base, size_t size, unsigned int flags)
    5558{
    56         return (void *) __SYSCALL3(SYS_AS_AREA_CREATE, (sysarg_t) address,
    57             (sysarg_t) size, (sysarg_t) flags);
     59        return (void *) __SYSCALL4(SYS_AS_AREA_CREATE, (sysarg_t) base,
     60            (sysarg_t) size, (sysarg_t) flags, (sysarg_t) __entry);
    5861}
    5962
     
    102105}
    103106
    104 /** Return pointer to unmapped address space area
    105  *
    106  * @param size Requested size of the allocation.
    107  *
    108  * @return Pointer to the beginning of unmapped address space area.
    109  *
    110  */
    111 void *as_get_mappable_page(size_t size)
    112 {
    113         return (void *) __SYSCALL2(SYS_AS_GET_UNMAPPED_AREA,
    114             (sysarg_t) __entry, (sysarg_t) size);
    115 }
    116 
    117107/** Find mapping to physical address.
    118108 *
  • uspace/lib/c/generic/async.c

    r24cf31f1 rfbcdeb8  
    19981998 *
    19991999 * @param exch  Exchange for sending the message.
    2000  * @param dst   Destination address space area base.
    20012000 * @param size  Size of the destination address space area.
    20022001 * @param arg   User defined argument.
    20032002 * @param flags Storage for the received flags. Can be NULL.
     2003 * @param dst   Destination address space area base. Cannot be NULL.
    20042004 *
    20052005 * @return Zero on success or a negative error code from errno.h.
    20062006 *
    20072007 */
    2008 int async_share_in_start(async_exch_t *exch, void *dst, size_t size,
    2009     sysarg_t arg, unsigned int *flags)
     2008int async_share_in_start(async_exch_t *exch, size_t size, sysarg_t arg,
     2009    unsigned int *flags, void **dst)
    20102010{
    20112011        if (exch == NULL)
    20122012                return ENOENT;
    20132013       
    2014         sysarg_t tmp_flags;
    2015         int res = async_req_3_2(exch, IPC_M_SHARE_IN, (sysarg_t) dst,
    2016             (sysarg_t) size, arg, NULL, &tmp_flags);
     2014        sysarg_t _flags = 0;
     2015        sysarg_t _dst = (sysarg_t) -1;
     2016        int res = async_req_2_4(exch, IPC_M_SHARE_IN, (sysarg_t) size,
     2017            arg, NULL, &_flags, NULL, &_dst);
    20172018       
    20182019        if (flags)
    2019                 *flags = (unsigned int) tmp_flags;
    2020        
     2020                *flags = (unsigned int) _flags;
     2021       
     2022        *dst = (void *) _dst;
    20212023        return res;
    20222024}
     
    20472049                return false;
    20482050       
    2049         *size = (size_t) IPC_GET_ARG2(data);
     2051        *size = (size_t) IPC_GET_ARG1(data);
    20502052        return true;
    20512053}
     
    20532055/** Wrapper for answering the IPC_M_SHARE_IN calls using the async framework.
    20542056 *
    2055  * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
     2057 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_IN
    20562058 * calls so that the user doesn't have to remember the meaning of each IPC
    20572059 * argument.
     
    21312133 *
    21322134 */
    2133 int async_share_out_finalize(ipc_callid_t callid, void *dst)
     2135int async_share_out_finalize(ipc_callid_t callid, void **dst)
    21342136{
    21352137        return ipc_share_out_finalize(callid, dst);
  • uspace/lib/c/generic/ddi.c

    r24cf31f1 rfbcdeb8  
    4545#include <align.h>
    4646#include <libarch/config.h>
     47#include "private/libc.h"
    4748
    4849/** Return unique device number.
     
    6162 *
    6263 * @param phys  Physical address of the starting frame.
    63  * @param virt  Virtual address of the starting page.
    6464 * @param pages Number of pages to map.
    6565 * @param flags Flags for the new address space area.
     66 * @param virt  Virtual address of the starting page.
    6667 *
    6768 * @return EOK on success
     
    7273 *
    7374 */
    74 int physmem_map(void *phys, void *virt, size_t pages, unsigned int flags)
     75int physmem_map(void *phys, size_t pages, unsigned int flags, void **virt)
    7576{
    76         return __SYSCALL4(SYS_PHYSMEM_MAP, (sysarg_t) phys,
    77             (sysarg_t) virt, pages, flags);
     77        return __SYSCALL5(SYS_PHYSMEM_MAP, (sysarg_t) phys,
     78            pages, flags, (sysarg_t) virt, (sysarg_t) __entry);
    7879}
    7980
     
    8182    unsigned int flags, void **phys)
    8283{
    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);
     84        return (int) __SYSCALL6(SYS_DMAMEM_MAP, (sysarg_t) size,
     85            (sysarg_t) map_flags, (sysarg_t) flags & ~DMAMEM_FLAGS_ANONYMOUS,
     86            (sysarg_t) phys, (sysarg_t) virt, 0);
    8687}
    8788
     
    8990    unsigned int flags, void **phys, void **virt)
    9091{
    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);
     92        return (int) __SYSCALL6(SYS_DMAMEM_MAP, (sysarg_t) size,
     93            (sysarg_t) map_flags, (sysarg_t) flags | DMAMEM_FLAGS_ANONYMOUS,
     94            (sysarg_t) phys, (sysarg_t) virt, (sysarg_t) __entry);
    9795}
    9896
    99 int dmamem_unmap(void *virt, size_t size, unsigned int flags)
     97int dmamem_unmap(void *virt, size_t size)
    10098{
    101         return __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, (sysarg_t) size,
    102             (sysarg_t) flags);
     99        return __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, (sysarg_t) size, 0);
    103100}
    104101
     
    138135 * @param pio_addr I/O start address.
    139136 * @param size     Size of the I/O region.
    140  * @param use_addr Address where the final address for
    141  *                 application's PIO will be stored.
     137 * @param virt     Virtual address for application's
     138 *                 PIO operations.
    142139 *
    143  * @return Zero on success or negative error code.
     140 * @return EOK on success.
     141 * @return Negative error code on failure.
    144142 *
    145143 */
    146 int pio_enable(void *pio_addr, size_t size, void **use_addr)
     144int pio_enable(void *pio_addr, size_t size, void **virt)
    147145{
    148         void *phys;
    149         void *virt;
    150         size_t offset;
    151         unsigned int pages;
    152        
    153146#ifdef IO_SPACE_BOUNDARY
    154147        if (pio_addr < IO_SPACE_BOUNDARY) {
    155                 *use_addr = pio_addr;
     148                *virt = pio_addr;
    156149                return iospace_enable(task_get_id(), pio_addr, size);
    157150        }
    158151#endif
    159152       
    160         phys = (void *) ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE);
    161         offset = pio_addr - phys;
    162         pages = ALIGN_UP(offset + size, PAGE_SIZE) >> PAGE_WIDTH;
    163         virt = as_get_mappable_page(pages << PAGE_WIDTH);
    164         *use_addr = virt + offset;
    165         return physmem_map(phys, virt, pages, AS_AREA_READ | AS_AREA_WRITE);
     153        void *phys_frame =
     154            (void *) ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE);
     155        size_t offset = pio_addr - phys_frame;
     156        size_t pages = SIZE2PAGES(offset + size);
     157       
     158        void *virt_page;
     159        int rc = physmem_map(phys_frame, pages,
     160            AS_AREA_READ | AS_AREA_WRITE, &virt_page);
     161        if (rc != EOK)
     162                return rc;
     163       
     164        *virt = virt_page + offset;
     165        return EOK;
    166166}
    167167
  • uspace/lib/c/generic/ipc.c

    r24cf31f1 rfbcdeb8  
    4848#include <fibril.h>
    4949#include <macros.h>
     50#include "private/libc.h"
    5051
    5152/**
     
    760761 *
    761762 * @param phoneid Phone that will be used to contact the receiving side.
    762  * @param dst     Destination address space area base.
    763763 * @param size    Size of the destination address space area.
    764764 * @param arg     User defined argument.
    765765 * @param flags   Storage for received flags. Can be NULL.
     766 * @param dst     Destination address space area base. Cannot be NULL.
    766767 *
    767768 * @return Zero on success or a negative error code from errno.h.
    768769 *
    769770 */
    770 int ipc_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
    771     unsigned int *flags)
    772 {
    773         sysarg_t tmp_flags = 0;
    774         int res = ipc_call_sync_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
    775             (sysarg_t) size, arg, NULL, &tmp_flags);
     771int ipc_share_in_start(int phoneid, size_t size, sysarg_t arg,
     772    unsigned int *flags, void **dst)
     773{
     774        sysarg_t _flags = 0;
     775        sysarg_t _dst = (sysarg_t) -1;
     776        int res = ipc_call_sync_2_4(phoneid, IPC_M_SHARE_IN, (sysarg_t) size,
     777            arg, NULL, &_flags, NULL, &_dst);
    776778       
    777779        if (flags)
    778                 *flags = (unsigned int) tmp_flags;
    779        
     780                *flags = (unsigned int) _flags;
     781       
     782        *dst = (void *) _dst;
    780783        return res;
    781784}
     
    783786/** Wrapper for answering the IPC_M_SHARE_IN calls.
    784787 *
    785  * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
     788 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_IN
    786789 * calls so that the user doesn't have to remember the meaning of each
    787790 * IPC argument.
     
    796799int ipc_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)
    797800{
    798         return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) flags);
     801        return ipc_answer_3(callid, EOK, (sysarg_t) src, (sysarg_t) flags,
     802            (sysarg_t) __entry);
    799803}
    800804
     
    826830 *
    827831 */
    828 int ipc_share_out_finalize(ipc_callid_t callid, void *dst)
    829 {
    830         return ipc_answer_1(callid, EOK, (sysarg_t) dst);
     832int ipc_share_out_finalize(ipc_callid_t callid, void **dst)
     833{
     834        return ipc_answer_2(callid, EOK, (sysarg_t) __entry, (sysarg_t) dst);
    831835}
    832836
  • uspace/lib/c/generic/malloc.c

    r24cf31f1 rfbcdeb8  
    283283static bool area_create(size_t size)
    284284{
    285         void *start = as_get_mappable_page(size);
    286         if (start == NULL)
    287                 return false;
    288        
    289         /* Align the heap area on page boundary */
    290         void *astart = (void *) ALIGN_UP((uintptr_t) start, PAGE_SIZE);
     285        /* Align the heap area size on page boundary */
    291286        size_t asize = ALIGN_UP(size, PAGE_SIZE);
    292        
    293         astart = as_area_create(astart, asize, AS_AREA_WRITE | AS_AREA_READ);
     287        void *astart = as_area_create((void *) -1, asize,
     288            AS_AREA_WRITE | AS_AREA_READ);
    294289        if (astart == (void *) -1)
    295290                return false;
  • uspace/lib/c/generic/mman.c

    r24cf31f1 rfbcdeb8  
    4242{
    4343        if (!start)
    44                 start = as_get_mappable_page(length);
     44                start = (void *) -1;
    4545       
    4646//      if (!((flags & MAP_SHARED) ^ (flags & MAP_PRIVATE)))
  • uspace/lib/c/generic/time.c

    r24cf31f1 rfbcdeb8  
    147147                }
    148148               
    149                 void *addr = as_get_mappable_page(PAGE_SIZE);
    150                 if (addr == NULL) {
    151                         errno = ENOMEM;
    152                         return -1;
    153                 }
    154                
    155                 rc = physmem_map((void *) faddr, addr, 1,
    156                     AS_AREA_READ | AS_AREA_CACHEABLE);
     149                void *addr;
     150                rc = physmem_map((void *) faddr, 1,
     151                    AS_AREA_READ | AS_AREA_CACHEABLE, &addr);
    157152                if (rc != EOK) {
    158153                        as_area_destroy(addr);
  • uspace/lib/c/include/as.h

    r24cf31f1 rfbcdeb8  
    5959extern int as_area_destroy(void *);
    6060extern void *set_maxheapsize(size_t);
    61 extern void *as_get_mappable_page(size_t);
    6261extern int as_get_physical_mapping(const void *, uintptr_t *);
    6362
  • uspace/lib/c/include/async.h

    r24cf31f1 rfbcdeb8  
    346346 */
    347347
    348 #define async_share_in_start_0_0(exch, dst, size) \
    349         async_share_in_start(exch, dst, size, 0, NULL)
    350 #define async_share_in_start_0_1(exch, dst, size, flags) \
    351         async_share_in_start(exch, dst, size, 0, flags)
    352 #define async_share_in_start_1_0(exch, dst, size, arg) \
    353         async_share_in_start(exch, dst, size, arg, NULL)
    354 #define async_share_in_start_1_1(exch, dst, size, arg, flags) \
    355         async_share_in_start(exch, dst, size, arg, flags)
    356 
    357 extern int async_share_in_start(async_exch_t *, void *, size_t, sysarg_t,
    358     unsigned int *);
     348#define async_share_in_start_0_0(exch, size, dst) \
     349        async_share_in_start(exch, size, 0, NULL, dst)
     350#define async_share_in_start_0_1(exch, size, flags, dst) \
     351        async_share_in_start(exch, size, 0, flags, dst)
     352#define async_share_in_start_1_0(exch, size, arg, dst) \
     353        async_share_in_start(exch, size, arg, NULL, dst)
     354#define async_share_in_start_1_1(exch, size, arg, flags, dst) \
     355        async_share_in_start(exch, size, arg, flags, dst)
     356
     357extern int async_share_in_start(async_exch_t *, size_t, sysarg_t,
     358    unsigned int *, void **);
    359359extern bool async_share_in_receive(ipc_callid_t *, size_t *);
    360360extern int async_share_in_finalize(ipc_callid_t, void *, unsigned int);
     
    362362extern int async_share_out_start(async_exch_t *, void *, unsigned int);
    363363extern bool async_share_out_receive(ipc_callid_t *, size_t *, unsigned int *);
    364 extern int async_share_out_finalize(ipc_callid_t, void *);
     364extern int async_share_out_finalize(ipc_callid_t, void **);
    365365
    366366/*
  • uspace/lib/c/include/ddi.h

    r24cf31f1 rfbcdeb8  
    4242extern int device_assign_devno(void);
    4343
    44 extern int physmem_map(void *, void *, size_t, unsigned int);
     44extern int physmem_map(void *, size_t, unsigned int, void **);
    4545
    4646extern int dmamem_map(void *, size_t, unsigned int, unsigned int, void **);
    4747extern int dmamem_map_anonymous(size_t, unsigned int, unsigned int, void **,
    4848    void **);
    49 extern int dmamem_unmap(void *, size_t, unsigned int);
     49extern int dmamem_unmap(void *, size_t);
    5050extern int dmamem_unmap_anonymous(void *);
    5151
  • uspace/lib/c/include/ipc/ipc.h

    r24cf31f1 rfbcdeb8  
    271271 */
    272272
    273 #define ipc_share_in_start_0_0(phoneid, dst, size) \
    274         ipc_share_in_start((phoneid), (dst), (size), 0, NULL)
    275 #define ipc_share_in_start_0_1(phoneid, dst, size, flags) \
    276         ipc_share_in_start((phoneid), (dst), (size), 0, (flags))
    277 #define ipc_share_in_start_1_0(phoneid, dst, size, arg) \
    278         ipc_share_in_start((phoneid), (dst), (size), (arg), NULL)
    279 #define ipc_share_in_start_1_1(phoneid, dst, size, arg, flags) \
    280         ipc_share_in_start((phoneid), (dst), (size), (arg), (flags))
    281 
    282 extern int ipc_share_in_start(int, void *, size_t, sysarg_t, unsigned int *);
     273#define ipc_share_in_start_0_0(phoneid, size, dst) \
     274        ipc_share_in_start((phoneid), (size), 0, NULL, (dst))
     275#define ipc_share_in_start_0_1(phoneid, size, flags, dst) \
     276        ipc_share_in_start((phoneid), (size), 0, (flags), (dst))
     277#define ipc_share_in_start_1_0(phoneid, size, arg, dst) \
     278        ipc_share_in_start((phoneid), (size), (arg), NULL, (dst))
     279#define ipc_share_in_start_1_1(phoneid, size, arg, flags, dst) \
     280        ipc_share_in_start((phoneid), (size), (arg), (flags), (dst))
     281
     282extern int ipc_share_in_start(int, size_t, sysarg_t, unsigned int *, void **);
    283283extern int ipc_share_in_finalize(ipc_callid_t, void *, unsigned int);
    284284extern int ipc_share_out_start(int, void *, unsigned int);
    285 extern int ipc_share_out_finalize(ipc_callid_t, void *);
     285extern int ipc_share_out_finalize(ipc_callid_t, void **);
    286286extern int ipc_data_read_start(int, void *, size_t);
    287287extern int ipc_data_read_finalize(ipc_callid_t, const void *, size_t);
Note: See TracChangeset for help on using the changeset viewer.