[BACK]Return to page.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / mem

Annotation of prex-old/sys/mem/page.c, Revision 1.1

1.1     ! nbrk        1: /*-
        !             2:  * Copyright (c) 2005-2006, Kohsuke Ohtani
        !             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:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. Neither the name of the author nor the names of any co-contributors
        !            14:  *    may be used to endorse or promote products derived from this software
        !            15:  *    without specific prior written permission.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  */
        !            29:
        !            30: /*
        !            31:  * page.c - physical page allocator
        !            32:  */
        !            33:
        !            34: /*
        !            35:  * This is a simple list-based page allocator.
        !            36:  *
        !            37:  * When the remaining page is exhausted, what should we do ?
        !            38:  * If the system can stop with panic() here, the error check of many
        !            39:  * portions in kernel is not necessary, and kernel code can become
        !            40:  * more simple. But, in general, even if a page is exhausted,
        !            41:  * a kernel can not be stopped but it should return an error and
        !            42:  * continue processing.
        !            43:  * If the memory becomes short during boot time, kernel and drivers
        !            44:  * can use panic() in that case.
        !            45:  */
        !            46:
        !            47: #include <kernel.h>
        !            48: #include <page.h>
        !            49: #include <sched.h>
        !            50:
        !            51: /*
        !            52:  * page_block is put on the head of the first page of
        !            53:  * each free block.
        !            54:  */
        !            55: struct page_block {
        !            56:        struct  page_block *next;
        !            57:        struct  page_block *prev;
        !            58:        size_t  size;           /* number of bytes of this block */
        !            59: };
        !            60:
        !            61: static struct page_block page_head;    /* first free block */
        !            62:
        !            63: static size_t total_bytes;
        !            64: static size_t used_bytes;
        !            65:
        !            66: /*
        !            67:  * page_alloc - allocate continuous pages of the specified size.
        !            68:  * @size: number of bytes to allocate
        !            69:  *
        !            70:  * This routine returns the physical address of a new free page block,
        !            71:  * or returns NULL on failure. The requested size is automatically
        !            72:  * round up to the page boundary.
        !            73:  * The allocated memory is _not_ filled with 0.
        !            74:  */
        !            75: void *
        !            76: page_alloc(size_t size)
        !            77: {
        !            78:        struct page_block *blk, *tmp;
        !            79:
        !            80:        ASSERT(size != 0);
        !            81:
        !            82:        sched_lock();
        !            83:
        !            84:        /*
        !            85:         * Find the free block that has enough size.
        !            86:         */
        !            87:        size = (size_t)PAGE_ALIGN(size);
        !            88:        blk = &page_head;
        !            89:        do {
        !            90:                blk = blk->next;
        !            91:                if (blk == &page_head) {
        !            92:                        sched_unlock();
        !            93:                        printk("page_alloc: out of memory\n");
        !            94:                        return NULL;    /* Not found. */
        !            95:                }
        !            96:        } while (blk->size < size);
        !            97:
        !            98:        /*
        !            99:         * If found block size is exactly same with requested,
        !           100:         * just remove it from a free list. Otherwise, the
        !           101:         * found block is divided into two and first half is
        !           102:         * used for allocation.
        !           103:         */
        !           104:        if (blk->size == size) {
        !           105:                blk->prev->next = blk->next;
        !           106:                blk->next->prev = blk->prev;
        !           107:        } else {
        !           108:                tmp = (struct page_block *)((u_long)blk + size);
        !           109:                tmp->size = blk->size - size;
        !           110:                tmp->prev = blk->prev;
        !           111:                tmp->next = blk->next;
        !           112:                blk->prev->next = tmp;
        !           113:                blk->next->prev = tmp;
        !           114:        }
        !           115:        used_bytes += size;
        !           116:        sched_unlock();
        !           117:
        !           118:        return virt_to_phys(blk);
        !           119: }
        !           120:
        !           121: /*
        !           122:  * Free page block.
        !           123:  *
        !           124:  * This allocator does not maintain the size of allocated page block.
        !           125:  * The caller must provide the size information of the block.
        !           126:  */
        !           127: void
        !           128: page_free(void *addr, size_t size)
        !           129: {
        !           130:        struct page_block *blk, *prev;
        !           131:
        !           132:        ASSERT(addr != NULL);
        !           133:        ASSERT(size != 0);
        !           134:
        !           135:        sched_lock();
        !           136:
        !           137:        size = (size_t)PAGE_ALIGN(size);
        !           138:        blk = phys_to_virt(addr);
        !           139:
        !           140:        /*
        !           141:         * Find the target position in list.
        !           142:         */
        !           143:        for (prev = &page_head; prev->next < blk; prev = prev->next) {
        !           144:                if (prev->next == &page_head)
        !           145:                        break;
        !           146:        }
        !           147: #ifdef DEBUG
        !           148:        if (prev != &page_head)
        !           149:                ASSERT((u_long)prev + prev->size <= (u_long)blk);
        !           150:        if (prev->next != &page_head)
        !           151:                ASSERT((u_long)blk + size <= (u_long)prev->next);
        !           152: #endif /* DEBUG */
        !           153:
        !           154:        /*
        !           155:         * Insert new block into list.
        !           156:         */
        !           157:        blk->size = size;
        !           158:        blk->prev = prev;
        !           159:        blk->next = prev->next;
        !           160:        prev->next->prev = blk;
        !           161:        prev->next = blk;
        !           162:
        !           163:        /*
        !           164:         * If the adjoining block is free, it combines and
        !           165:         * is made on block.
        !           166:         */
        !           167:        if (blk->next != &page_head &&
        !           168:            ((u_long)blk + blk->size) == (u_long)blk->next) {
        !           169:                blk->size += blk->next->size;
        !           170:                blk->next = blk->next->next;
        !           171:                blk->next->prev = blk;
        !           172:        }
        !           173:        if (blk->prev != &page_head &&
        !           174:            (u_long)blk->prev + blk->prev->size == (u_long)blk) {
        !           175:                blk->prev->size += blk->size;
        !           176:                blk->prev->next = blk->next;
        !           177:                blk->next->prev = blk->prev;
        !           178:        }
        !           179:        used_bytes -= size;
        !           180:        sched_unlock();
        !           181: }
        !           182:
        !           183: /*
        !           184:  * The function to reserve pages in specific address.
        !           185:  * Return 0 on success, or -1 on failure
        !           186:  */
        !           187: int
        !           188: page_reserve(void *addr, size_t size)
        !           189: {
        !           190:        struct page_block *blk, *tmp;
        !           191:        u_long end;
        !           192:
        !           193:        if (size == 0)
        !           194:                return 0;
        !           195:
        !           196:        addr = phys_to_virt(addr);
        !           197:        end = PAGE_ALIGN((u_long)addr + size);
        !           198:        addr = (void *)PAGE_TRUNC(addr);
        !           199:        size = (size_t)(end - (u_long)addr);
        !           200:
        !           201:        /*
        !           202:         * Find the block which includes specified block.
        !           203:         */
        !           204:        blk = page_head.next;
        !           205:        for (;;) {
        !           206:                if (blk == &page_head)
        !           207:                        panic("page_reserve");
        !           208:                if ((u_long)blk <= (u_long)addr
        !           209:                    && end <= (u_long)blk + blk->size)
        !           210:                        break;
        !           211:                blk = blk->next;
        !           212:        }
        !           213:        if ((u_long)blk == (u_long)addr && blk->size == size) {
        !           214:                /*
        !           215:                 * Unlink the block from free list.
        !           216:                 */
        !           217:                blk->prev->next = blk->next;
        !           218:                blk->next->prev = blk->prev;
        !           219:        } else {
        !           220:                /*
        !           221:                 * Split this block.
        !           222:                 */
        !           223:                if ((u_long)blk + blk->size != end) {
        !           224:                        tmp = (struct page_block *)end;
        !           225:                        tmp->size = (size_t)((u_long)blk + blk->size - end);
        !           226:                        tmp->next = blk->next;
        !           227:                        tmp->prev = blk;
        !           228:
        !           229:                        blk->size -= tmp->size;
        !           230:                        blk->next->prev = tmp;
        !           231:                        blk->next = tmp;
        !           232:                }
        !           233:                if ((u_long)blk == (u_long)addr) {
        !           234:                        blk->prev->next = blk->next;
        !           235:                        blk->next->prev = blk->prev;
        !           236:                } else
        !           237:                        blk->size = (size_t)((u_long)addr - (u_long)blk);
        !           238:        }
        !           239:        used_bytes += size;
        !           240:        return 0;
        !           241: }
        !           242:
        !           243: void
        !           244: page_info(size_t *total, size_t *free)
        !           245: {
        !           246:
        !           247:        *total = total_bytes;
        !           248:        *free = total_bytes - used_bytes;
        !           249: }
        !           250:
        !           251: #if defined(DEBUG) && defined(CONFIG_KDUMP)
        !           252: void
        !           253: page_dump(void)
        !           254: {
        !           255:        struct page_block *blk;
        !           256:        void *addr;
        !           257:        struct mem_map *mem;
        !           258:        struct module *img;
        !           259:        int i;
        !           260:
        !           261:        printk("Page dump:\n");
        !           262:        printk(" free pages:\n");
        !           263:        printk(" start      end      size\n");
        !           264:        printk(" --------   -------- --------\n");
        !           265:
        !           266:        blk = page_head.next;
        !           267:        do {
        !           268:                addr = virt_to_phys(blk);
        !           269:                printk(" %08x - %08x %8x\n", addr, (u_long)addr + blk->size,
        !           270:                       blk->size);
        !           271:                blk = blk->next;
        !           272:        } while (blk != &page_head);
        !           273:        printk(" used=%dK free=%dK total=%dK\n\n",
        !           274:               used_bytes / 1024, (total_bytes - used_bytes) / 1024,
        !           275:               total_bytes / 1024);
        !           276:
        !           277:        img = (struct module *)&boot_info->kernel;
        !           278:        printk(" kernel:   %08x - %08x (%dK)\n",
        !           279:               img->phys, img->phys + img->size, img->size / 1024);
        !           280:
        !           281:        img = (struct module *)&boot_info->driver;
        !           282:        printk(" driver:   %08x - %08x (%dK)\n",
        !           283:               img->phys, img->phys + img->size, img->size / 1024);
        !           284:
        !           285:        for (i = 0; i < NRESMEM; i++) {
        !           286:                mem = &boot_info->reserved[i];
        !           287:                if (mem->size != 0) {
        !           288:                        printk(" reserved: %08x - %08x (%dK)\n",
        !           289:                               mem->start, mem->start + mem->size,
        !           290:                               mem->size / 1024);
        !           291:                }
        !           292:        }
        !           293: #ifdef CONFIG_RAMDISK
        !           294:        mem = (struct mem_map *)&boot_info->ram_disk;
        !           295:        printk(" RAM disk: %08x - %08x (%dK)\n",
        !           296:               mem->start, mem->start + mem->size, mem->size / 1024);
        !           297: #endif
        !           298: }
        !           299: #endif
        !           300:
        !           301: /*
        !           302:  * Initialize page allocator.
        !           303:  * page_init() must be called prior to other memory manager's
        !           304:  * initializations.
        !           305:  */
        !           306: void
        !           307: page_init(void)
        !           308: {
        !           309:        struct page_block *blk;
        !           310:        struct mem_map *mem;
        !           311:        int i;
        !           312:
        !           313:        printk("Memory: base=%x size=%dK\n", boot_info->main_mem.start,
        !           314:               boot_info->main_mem.size / 1024);
        !           315:
        !           316:        /*
        !           317:         * First, create one block containing all memory pages.
        !           318:         */
        !           319:        blk = (struct page_block *)boot_info->main_mem.start;
        !           320:        blk = phys_to_virt(blk);
        !           321:        blk->size = boot_info->main_mem.size;
        !           322:        if (blk->size == 0)
        !           323:                panic("page_init: no pages");
        !           324:        blk->prev = blk->next = &page_head;
        !           325:        page_head.next = page_head.prev = blk;
        !           326:
        !           327:        /*
        !           328:         * Then, the system reserved pages are marked as a used block.
        !           329:         */
        !           330:        for (i = 0; i < NRESMEM; i++) {
        !           331:                mem = &boot_info->reserved[i];
        !           332:                if (mem->size != 0)
        !           333:                        page_reserve((void *)mem->start, mem->size);
        !           334:        }
        !           335:        total_bytes = boot_info->main_mem.size - used_bytes;
        !           336:        used_bytes = 0;
        !           337:
        !           338:        /*
        !           339:         * Reserve pages for all boot modules.
        !           340:         */
        !           341:        mem = &boot_info->modules;
        !           342:        page_reserve((void *)mem->start, mem->size);
        !           343: }

CVSweb