Changeset e49e234 in mainline for kernel/generic


Ignore:
Timestamp:
2009-02-27T11:32:31Z (17 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c1f7f6ea
Parents:
5f0f29ce
Message:

kernel memory management revisited (phase 2): map physical memory according to zones

  • ia32: register reserved and ACPI zones
  • pareas are now used only for mapping of present physical memory (hw_area() is gone)
  • firmware zones and physical addresses outside any zones are allowed to be mapped generally
  • fix nasty antient bug in zones_insert_zone()
Location:
kernel/generic
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/align.h

    r5f0f29ce re49e234  
    2727 */
    2828
    29 /** @addtogroup generic 
     29/** @addtogroup generic
    3030 * @ingroup others
    3131 * @{
     
    3333/**
    3434 * @file
    35  * @brief       Macros for making values and addresses aligned.
     35 * @brief Macros for making values and addresses aligned.
    3636 */
    3737
     
    4444 * @param a Size of alignment, must be power of 2.
    4545 */
    46 #define ALIGN_DOWN(s, a)        ((s) & ~((a) - 1))
     46#define ALIGN_DOWN(s, a)  ((s) & ~((a) - 1))
    4747
    4848
     
    5252 * @param a Size of alignment, must be power of 2.
    5353 */
    54 #define ALIGN_UP(s, a)          (((s) + ((a) - 1)) & ~((a) - 1))
     54#define ALIGN_UP(s, a)  (((s) + ((a) - 1)) & ~((a) - 1))
    5555
    5656#endif
  • kernel/generic/include/mm/frame.h

    r5f0f29ce re49e234  
    4040#include <adt/list.h>
    4141#include <mm/buddy.h>
     42#include <synch/spinlock.h>
    4243#include <arch/mm/page.h>
    4344#include <arch/mm/frame.h>
     
    6869typedef uint8_t zone_flags_t;
    6970
     71/** Available zone (free for allocation) */
     72#define ZONE_AVAILABLE  0x00
    7073/** Zone is reserved (not available for allocation) */
    71 #define ZONE_RESERVED  0x08
     74#define ZONE_RESERVED   0x08
    7275/** Zone is used by firmware (not available for allocation) */
    73 #define ZONE_FIRMWARE  0x10
     76#define ZONE_FIRMWARE   0x10
    7477
    7578/** Currently there is no equivalent zone flags
    7679    for frame flags */
    7780#define FRAME_TO_ZONE_FLAGS(frame_flags)  0
     81
     82typedef struct {
     83        count_t refcount;     /**< Tracking of shared frames */
     84        uint8_t buddy_order;  /**< Buddy system block order */
     85        link_t buddy_link;    /**< Link to the next free block inside
     86                               one order */
     87        void *parent;         /**< If allocated by slab, this points there */
     88} frame_t;
     89
     90typedef struct {
     91        pfn_t base;                    /**< Frame_no of the first frame
     92                                        in the frames array */
     93        count_t count;                 /**< Size of zone */
     94        count_t free_count;            /**< Number of free frame_t
     95                                        structures */
     96        count_t busy_count;            /**< Number of busy frame_t
     97                                        structures */
     98        zone_flags_t flags;            /**< Type of the zone */
     99       
     100        frame_t *frames;               /**< Array of frame_t structures
     101                                        in this zone */
     102        buddy_system_t *buddy_system;  /**< Buddy system for the zone */
     103} zone_t;
     104
     105/*
     106 * The zoneinfo.lock must be locked when accessing zoneinfo structure.
     107 * Some of the attributes in zone_t structures are 'read-only'
     108 */
     109typedef struct {
     110        SPINLOCK_DECLARE(lock);
     111        count_t count;
     112        zone_t info[ZONES_MAX];
     113} zones_t;
     114
     115extern zones_t zones;
    78116
    79117static inline uintptr_t PFN2ADDR(pfn_t frame)
     
    99137}
    100138
     139static inline bool zone_flags_available(zone_flags_t flags)
     140{
     141        return ((flags & (ZONE_RESERVED | ZONE_FIRMWARE)) == 0);
     142}
     143
    101144#define IS_BUDDY_ORDER_OK(index, order) \
    102145    ((~(((unative_t) -1) << (order)) & (index)) == 0)
     
    118161extern void frame_reference_add(pfn_t);
    119162
     163extern count_t find_zone(pfn_t frame, count_t count, count_t hint);
    120164extern count_t zone_create(pfn_t, count_t, pfn_t, zone_flags_t);
    121165extern void *frame_get_parent(pfn_t, count_t);
  • kernel/generic/include/mm/page.h

    r5f0f29ce re49e234  
    6262
    6363extern uintptr_t hw_map(uintptr_t physaddr, size_t size);
    64 extern void hw_area(void);
    6564
    6665#endif
  • kernel/generic/src/ddi/ddi.c

    r5f0f29ce re49e234  
    3030 * @{
    3131 */
    32  
     32
    3333/**
    3434 * @file
    35  * @brief       Device Driver Interface functions.
     35 * @brief Device Driver Interface functions.
    3636 *
    3737 * This file contains functions that comprise the Device Driver Interface.
     
    4848#include <synch/spinlock.h>
    4949#include <syscall/copy.h>
    50 #include <adt/list.h>
     50#include <adt/btree.h>
    5151#include <arch.h>
    5252#include <align.h>
     
    5656SPINLOCK_INITIALIZE(parea_lock);
    5757
    58 /** List with enabled physical memory areas. */
    59 static LIST_INITIALIZE(parea_head);
     58/** B+tree with enabled physical memory areas. */
     59static btree_t parea_btree;
    6060
    6161/** Initialize DDI. */
    6262void ddi_init(void)
    6363{
    64         hw_area();
     64        btree_create(&parea_btree);
    6565}
    6666
     
    6969 * @param parea Pointer to physical area structure.
    7070 *
    71  * @todo This function doesn't check for overlaps. It depends on the kernel to
    72  * create disjunct physical memory areas.
    7371 */
    7472void ddi_parea_register(parea_t *parea)
    7573{
    76         ipl_t ipl;
    77        
    78         ipl = interrupts_disable();
     74        ipl_t ipl = interrupts_disable();
    7975        spinlock_lock(&parea_lock);
    8076       
    8177        /*
    82          * TODO: we should really check for overlaps here.
    83          * However, we should be safe because the kernel is pretty sane.
    84          */
    85         link_initialize(&parea->link);
    86         list_append(&parea->link, &parea_head);
     78         * We don't check for overlaps here as the kernel is pretty sane.
     79         */
     80        btree_insert(&parea_btree, (btree_key_t) parea->pbase, parea, NULL);
    8781       
    8882        spinlock_unlock(&parea_lock);
     
    9286/** Map piece of physical memory into virtual address space of current task.
    9387 *
    94  * @param pf Physical address of the starting frame.
    95  * @param vp Virtual address of the starting page.
     88 * @param pf    Physical address of the starting frame.
     89 * @param vp    Virtual address of the starting page.
    9690 * @param pages Number of pages to map.
    9791 * @param flags Address space area flags for the mapping.
    9892 *
    9993 * @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  */
    104 static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, pfn_t pages, int flags)
    105 {
    106         ipl_t ipl;
    107         cap_t caps;
     94 *         syscall, EBADMEM if pf or vf is not page aligned, ENOENT if there
     95 *         is no task matching the specified ID or the physical address space
     96 *         is not enabled for mapping and ENOMEM if there was a problem in
     97 *         creating address space area.
     98 *
     99 */
     100static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, count_t pages, int flags)
     101{
     102        ASSERT(TASK);
     103        ASSERT((pf % FRAME_SIZE) == 0);
     104        ASSERT((vp % PAGE_SIZE) == 0);
     105       
     106        /*
     107         * Make sure the caller is authorised to make this syscall.
     108         */
     109        cap_t caps = cap_get(TASK);
     110        if (!(caps & CAP_MEM_MANAGER))
     111                return EPERM;
     112       
    108113        mem_backend_data_t backend_data;
    109        
    110114        backend_data.base = pf;
    111115        backend_data.frames = pages;
    112116       
    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          */
    125         spinlock_lock(&parea_lock);
    126        
    127         bool fnd = false;
    128         link_t *cur;
    129        
    130         for (cur = parea_head.next; cur != &parea_head; cur = cur->next) {
    131                 parea_t *parea = list_get_instance(cur, parea_t, link);
    132                 if ((parea->pbase <= pf) && (ADDR2PFN(pf - parea->pbase) + pages <= parea->frames)) {
    133                         fnd = true;
    134                         break;
    135                 }
    136         }
    137        
    138         spinlock_unlock(&parea_lock);
    139        
    140         if (!fnd) {
    141                 /*
    142                  * Physical memory area cannot be mapped.
    143                  */
    144                 interrupts_restore(ipl);
    145                 return ENOENT;
    146         }
    147        
     117        ipl_t ipl = interrupts_disable();
     118       
     119        /* Find the zone of the physical memory */
     120        spinlock_lock(&zones.lock);
     121        count_t znum = find_zone(ADDR2PFN(pf), pages, 0);
     122       
     123        if (znum == (count_t) -1) {
     124                /* Frames not found in any zones
     125                 * -> assume it is hardware device and allow mapping
     126                 */
     127                spinlock_unlock(&zones.lock);
     128                goto map;
     129        }
     130       
     131        if (zones.info[znum].flags & ZONE_FIRMWARE) {
     132                /* Frames are part of firmware */
     133                spinlock_unlock(&zones.lock);
     134                goto map;
     135        }
     136       
     137        if (zone_flags_available(zones.info[znum].flags)) {
     138                /* Frames are part of physical memory, check if the memory
     139                 * region is enabled for mapping.
     140                 */
     141                spinlock_unlock(&zones.lock);
     142               
     143                spinlock_lock(&parea_lock);
     144                btree_node_t *nodep;
     145                parea_t *parea = (parea_t *) btree_search(&parea_btree,
     146                    (btree_key_t) pf, &nodep);
     147               
     148                if ((!parea) || (parea->frames < pages))
     149                        goto err;
     150               
     151                spinlock_unlock(&parea_lock);
     152                goto map;
     153        }
     154       
     155err:
     156        spinlock_unlock(&zones.lock);
     157        interrupts_restore(ipl);
     158        return ENOENT;
     159       
     160map:
    148161        spinlock_lock(&TASK->lock);
    149162       
    150         if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp, AS_AREA_ATTR_NONE,
    151                 &phys_backend, &backend_data)) {
     163        if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp,
     164            AS_AREA_ATTR_NONE, &phys_backend, &backend_data)) {
    152165                /*
    153166                 * The address space area could not have been created.
     
    175188 *
    176189 * @return 0 on success, EPERM if the caller lacks capabilities to use this
    177  *      syscall, ENOENT if there is no task matching the specified ID.
     190 *           syscall, ENOENT if there is no task matching the specified ID.
     191 *
    178192 */
    179193static int ddi_iospace_enable(task_id_t id, uintptr_t ioaddr, size_t size)
    180194{
    181         ipl_t ipl;
    182         cap_t caps;
    183         task_t *t;
    184         int rc;
    185        
    186195        /*
    187196         * Make sure the caller is authorised to make this syscall.
    188197         */
    189         caps = cap_get(TASK);
     198        cap_t caps = cap_get(TASK);
    190199        if (!(caps & CAP_IO_MANAGER))
    191200                return EPERM;
    192201       
    193         ipl = interrupts_disable();
     202        ipl_t ipl = interrupts_disable();
    194203        spinlock_lock(&tasks_lock);
    195204       
    196         t = task_find_by_id(id);
    197        
    198         if ((!t) || (!context_check(CONTEXT, t->context))) {
     205        task_t *task = task_find_by_id(id);
     206       
     207        if ((!task) || (!context_check(CONTEXT, task->context))) {
    199208                /*
    200209                 * There is no task with the specified ID
     
    206215                return ENOENT;
    207216        }
    208 
     217       
    209218        /* Lock the task and release the lock protecting tasks_btree. */
    210         spinlock_lock(&t->lock);
     219        spinlock_lock(&task->lock);
    211220        spinlock_unlock(&tasks_lock);
    212 
    213         rc = ddi_iospace_enable_arch(t, ioaddr, size);
    214        
    215         spinlock_unlock(&t->lock);
    216         interrupts_restore(ipl);
     221       
     222        int rc = ddi_iospace_enable_arch(task, ioaddr, size);
     223       
     224        spinlock_unlock(&task->lock);
     225        interrupts_restore(ipl);
     226       
    217227        return rc;
    218228}
     
    226236 *
    227237 * @return 0 on success, otherwise it returns error code found in errno.h
    228  */
     238 *
     239 */
    229240unative_t sys_physmem_map(unative_t phys_base, unative_t virt_base,
    230241    unative_t pages, unative_t flags)
     
    232243        return (unative_t) ddi_physmem_map(ALIGN_DOWN((uintptr_t) phys_base,
    233244            FRAME_SIZE), ALIGN_DOWN((uintptr_t) virt_base, PAGE_SIZE),
    234             (pfn_t) pages, (int) flags);
     245            (count_t) pages, (int) flags);
    235246}
    236247
     
    240251 *
    241252 * @return 0 on success, otherwise it returns error code found in errno.h
    242  */
     253 *
     254 */
    243255unative_t sys_iospace_enable(ddi_ioarg_t *uspace_io_arg)
    244256{
    245257        ddi_ioarg_t arg;
    246         int rc;
    247        
    248         rc = copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
     258        int rc = copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
    249259        if (rc != 0)
    250260                return (unative_t) rc;
    251                
     261       
    252262        return (unative_t) ddi_iospace_enable((task_id_t) arg.task_id,
    253263            (uintptr_t) arg.ioaddr, (size_t) arg.size);
     
    257267 *
    258268 * @param enable If non-zero, the preemption counter will be decremented,
    259  *      leading to potential enabling of preemption. Otherwise the preemption
    260  *      counter will be incremented, preventing preemption from occurring.
     269 *               leading to potential enabling of preemption. Otherwise
     270 *               the preemption counter will be incremented, preventing
     271 *               preemption from occurring.
    261272 *
    262273 * @return Zero on success or EPERM if callers capabilities are not sufficient.
    263  */
     274 *
     275 */
    264276unative_t sys_preempt_control(int enable)
    265277{
    266278        if (!cap_get(TASK) & CAP_PREEMPT_CONTROL)
    267279                return EPERM;
     280       
    268281        if (enable)
    269282                preemption_enable();
    270283        else
    271284                preemption_disable();
     285       
    272286        return 0;
    273287}
  • kernel/generic/src/mm/frame.c

    r5f0f29ce re49e234  
    4949#include <debug.h>
    5050#include <adt/list.h>
    51 #include <synch/spinlock.h>
    5251#include <synch/mutex.h>
    5352#include <synch/condvar.h>
     
    6160#include <config.h>
    6261
    63 typedef struct {
    64         count_t refcount;     /**< Tracking of shared frames */
    65         uint8_t buddy_order;  /**< Buddy system block order */
    66         link_t buddy_link;    /**< Link to the next free block inside
    67                                one order */
    68         void *parent;         /**< If allocated by slab, this points there */
    69 } frame_t;
    70 
    71 typedef struct {
    72         pfn_t base;                    /**< Frame_no of the first frame
    73                                         in the frames array */
    74         count_t count;                 /**< Size of zone */
    75         count_t free_count;            /**< Number of free frame_t
    76                                         structures */
    77         count_t busy_count;            /**< Number of busy frame_t
    78                                         structures */
    79         zone_flags_t flags;            /**< Type of the zone */
    80        
    81         frame_t *frames;               /**< Array of frame_t structures
    82                                         in this zone */
    83         buddy_system_t *buddy_system;  /**< Buddy system for the zone */
    84 } zone_t;
    85 
    86 /*
    87  * The zoneinfo.lock must be locked when accessing zoneinfo structure.
    88  * Some of the attributes in zone_t structures are 'read-only'
    89  */
    90 typedef struct {
    91         SPINLOCK_DECLARE(lock);
    92         count_t count;
    93         zone_t info[ZONES_MAX];
    94 } zones_t;
    95 
    96 static zones_t zones;
     62zones_t zones;
    9763
    9864/*
     
    12793{
    12894        return (frame - zone->frames);
    129 }
    130 
    131 static inline bool zone_flags_available(zone_flags_t flags)
    132 {
    133         return ((flags & (ZONE_RESERVED | ZONE_FIRMWARE)) == 0);
    13495}
    13596
     
    181142        /* Move other zones up */
    182143        count_t j;
    183         for (j = i; j < zones.count; j++)
    184                 zones.info[j + 1] = zones.info[j];
     144        for (j = zones.count; j > i; j--) {
     145                zones.info[j] = zones.info[j - 1];
     146                zones.info[j].buddy_system->data =
     147                    (void *) &zones.info[j - 1];
     148        }
    185149       
    186150        zones.count++;
     
    207171}
    208172
    209 /** Find a zone with a given frame.
     173/** Find a zone with a given frames.
    210174 *
    211175 * Assume interrupts are disabled and zones lock is
     
    213177 *
    214178 * @param frame Frame number contained in zone.
     179 * @param count Number of frames to look for.
    215180 * @param hint  Used as zone hint.
    216181 *
     
    218183 *
    219184 */
    220 static count_t find_zone(pfn_t frame, count_t hint)
     185count_t find_zone(pfn_t frame, count_t count, count_t hint)
    221186{
    222187        if (hint >= zones.count)
     
    226191        do {
    227192                if ((zones.info[i].base <= frame)
    228                     && (zones.info[i].base + zones.info[i].count > frame))
     193                    && (zones.info[i].base + zones.info[i].count >= frame + count))
    229194                        return i;
    230195               
     
    766731            zones.info[z2].count);
    767732       
    768         /* Shift existing zones */
     733        /* Move zones down */
    769734        count_t i;
    770         for (i = z2 + 1; i < zones.count; i++)
     735        for (i = z2 + 1; i < zones.count; i++) {
    771736                zones.info[i - 1] = zones.info[i];
     737                zones.info[i - 1].buddy_system->data =
     738                    (void *) &zones.info[i - 1];
     739        }
     740       
    772741        zones.count--;
    773742       
     
    965934        spinlock_lock(&zones.lock);
    966935       
    967         count_t znum = find_zone(pfn, hint);
     936        count_t znum = find_zone(pfn, 1, hint);
    968937       
    969938        ASSERT(znum != (count_t) -1);
     
    981950        spinlock_lock(&zones.lock);
    982951       
    983         count_t znum = find_zone(pfn, hint);
     952        count_t znum = find_zone(pfn, 1, hint);
    984953       
    985954        ASSERT(znum != (count_t) -1);
     
    11121081         */
    11131082        pfn_t pfn = ADDR2PFN(frame);
    1114         count_t znum = find_zone(pfn, NULL);
     1083        count_t znum = find_zone(pfn, 1, NULL);
    11151084       
    11161085        ASSERT(znum != (count_t) -1);
     
    11511120         * First, find host frame zone for addr.
    11521121         */
    1153         count_t znum = find_zone(pfn, NULL);
     1122        count_t znum = find_zone(pfn, 1, NULL);
    11541123       
    11551124        ASSERT(znum != (count_t) -1);
     
    11691138        count_t i;
    11701139        for (i = 0; i < count; i++) {
    1171                 count_t znum = find_zone(start + i, 0);
     1140                count_t znum = find_zone(start + i, 1, 0);
    11721141                if (znum == (count_t) -1)  /* PFN not found */
    11731142                        continue;
     
    12381207{
    12391208#ifdef __32_BITS__
    1240         printf("#  base address flags    free frames  busy frames\n");
    1241         printf("-- ------------ -------- ------------ ------------\n");
     1209        printf("#  base address frames       flags    free frames  busy frames\n");
     1210        printf("-- ------------ ------------ -------- ------------ ------------\n");
    12421211#endif
    12431212
    12441213#ifdef __64_BITS__
    1245         printf("#  base address         flags    free frames  busy frames\n");
    1246         printf("-- -------------------- -------- ------------ ------------\n");
     1214        printf("#  base address          frames      flags    free frames  busy frames\n");
     1215        printf("-- -------------------- ------------ -------- ------------ ------------\n");
    12471216#endif
    12481217       
     
    12701239               
    12711240                uintptr_t base = PFN2ADDR(zones.info[i].base);
     1241                count_t count = zones.info[i].count;
    12721242                zone_flags_t flags = zones.info[i].flags;
    12731243                count_t free_count = zones.info[i].free_count;
     
    12791249                bool available = zone_flags_available(flags);
    12801250               
     1251                printf("%-2" PRIc, i);
     1252               
    12811253#ifdef __32_BITS__
    1282                 printf("%-2" PRIc "   %10p %c%c%c      ", i, base,
     1254                printf("   %10p", base);
     1255#endif
     1256               
     1257#ifdef __64_BITS__
     1258                printf("   %18p", base);
     1259#endif
     1260               
     1261                printf(" %12" PRIc " %c%c%c      ", count,
    12831262                    available ? 'A' : ' ',
    12841263                    (flags & ZONE_RESERVED) ? 'R' : ' ',
    12851264                    (flags & ZONE_FIRMWARE) ? 'F' : ' ');
    1286 #endif
    1287                
    1288 #ifdef __64_BITS__
    1289                 printf("%-2" PRIc "   %18p %c%c%c      ", i, base,
    1290                     available ? 'A' : ' ',
    1291                     (flags & ZONE_RESERVED) ? 'R' : ' ',
    1292                     (flags & ZONE_FIRMWARE) ? 'F' : ' ');
    1293 #endif
    12941265               
    12951266                if (available)
    12961267                        printf("%12" PRIc " %12" PRIc,
    12971268                            free_count, busy_count);
     1269               
    12981270                printf("\n");
    12991271        }
Note: See TracChangeset for help on using the changeset viewer.