Annotation of Gnu-Mach/i386/i386at/model_dep.c, revision 1.1.1.3

1.1.1.3 ! root        1: /*
1.1       root        2:  * Mach Operating System
                      3:  * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University
                      4:  * All Rights Reserved.
1.1.1.3 ! root        5:  *
1.1       root        6:  * Permission to use, copy, modify and distribute this software and its
                      7:  * documentation is hereby granted, provided that both the copyright
                      8:  * notice and this permission notice appear in all copies of the
                      9:  * software, derivative works or modified versions, and any portions
                     10:  * thereof, and that both notices appear in supporting documentation.
1.1.1.3 ! root       11:  *
1.1       root       12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.3 ! root       15:  *
1.1       root       16:  * Carnegie Mellon requests users of this software to return to
1.1.1.3 ! root       17:  *
1.1       root       18:  *  Software Distribution Coordinator  or  [email protected]
                     19:  *  School of Computer Science
                     20:  *  Carnegie Mellon University
                     21:  *  Pittsburgh PA 15213-3890
1.1.1.3 ! root       22:  *
1.1       root       23:  * any improvements or extensions that they make and grant Carnegie Mellon
                     24:  * the rights to redistribute these changes.
                     25:  */
                     26: /*
                     27:  *     File:   model_dep.c
                     28:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
                     29:  *
                     30:  *     Copyright (C) 1986, Avadis Tevanian, Jr., Michael Wayne Young
                     31:  *
                     32:  *     Basic initialization for I386 - ISA bus machines.
                     33:  */
                     34: 
                     35: #include <platforms.h>
                     36: #include <mach_kdb.h>
                     37: 
                     38: #include <mach/vm_param.h>
                     39: #include <mach/vm_prot.h>
                     40: #include <mach/machine.h>
                     41: #include <mach/machine/multiboot.h>
                     42: 
                     43: #include "vm_param.h"
                     44: #include <kern/time_out.h>
1.1.1.3 ! root       45: #include <kern/assert.h>
        !            46: #include <kern/cpu_number.h>
1.1       root       47: #include <sys/time.h>
                     48: #include <vm/vm_page.h>
                     49: #include <i386/machspl.h>
                     50: #include <i386/pmap.h>
                     51: #include "proc_reg.h"
                     52: 
                     53: /* Location of the kernel's symbol table.
                     54:    Both of these are 0 if none is available.  */
                     55: #if MACH_KDB
                     56: static vm_offset_t kern_sym_start, kern_sym_end;
                     57: #else
                     58: #define kern_sym_start 0
                     59: #define kern_sym_end   0
                     60: #endif
                     61: 
                     62: /* These indicate the total extent of physical memory addresses we're using.
                     63:    They are page-aligned.  */
                     64: vm_offset_t phys_first_addr = 0;
                     65: vm_offset_t phys_last_addr;
                     66: 
                     67: /* Virtual address of physical memory, for the kvtophys/phystokv macros.  */
                     68: vm_offset_t phys_mem_va;
                     69: 
1.1.1.3 ! root       70: /* A copy of the multiboot info structure passed by the boot loader.  */
        !            71: struct multiboot_info boot_info;
1.1       root       72: 
                     73: /* Command line supplied to kernel.  */
                     74: char *kernel_cmdline = "";
                     75: 
                     76: /* This is used for memory initialization:
                     77:    it gets bumped up through physical memory
                     78:    that exists and is not occupied by boot gunk.
                     79:    It is not necessarily page-aligned.  */
                     80: static vm_offset_t avail_next = 0x1000; /* XX end of BIOS data area */
                     81: 
                     82: /* Possibly overestimated amount of available memory
                     83:    still remaining to be handed to the VM system.  */
                     84: static vm_size_t avail_remaining;
                     85: 
                     86: /* Configuration parameter:
                     87:    if zero, only use physical memory in the low 16MB of addresses.
                     88:    Only SCSI still has DMA problems.  */
                     89: #ifdef LINUX_DEV
1.1.1.3 ! root       90: #define use_all_mem 1
1.1       root       91: #else
                     92: #include "nscsi.h"
                     93: #if    NSCSI > 0
1.1.1.3 ! root       94: #define use_all_mem 0
1.1       root       95: #else
1.1.1.3 ! root       96: #define use_all_mem 1
1.1       root       97: #endif
                     98: #endif
                     99: 
                    100: extern char    version[];
                    101: 
                    102: extern void    setup_main();
                    103: 
1.1.1.3 ! root      104: void           halt_all_cpu (boolean_t reboot) __attribute__ ((noreturn));
        !           105: void           halt_cpu (void) __attribute__ ((noreturn));
        !           106: 
1.1       root      107: void           inittodr();     /* forward */
                    108: 
                    109: int            rebootflag = 0; /* exported to kdintr */
                    110: 
                    111: /* XX interrupt stack pointer and highwater mark, for locore.S.  */
                    112: vm_offset_t int_stack_top, int_stack_high;
                    113: 
                    114: #ifdef LINUX_DEV
                    115: extern void linux_init(void);
                    116: #endif
                    117: 
                    118: /*
                    119:  * Find devices.  The system is alive.
                    120:  */
                    121: void machine_init()
                    122: {
                    123:        /*
                    124:         * Initialize the console.
                    125:         */
                    126:        cninit();
                    127: 
                    128:        /*
                    129:         * Set up to use floating point.
                    130:         */
                    131:        init_fpu();
                    132: 
                    133: #ifdef LINUX_DEV
                    134:        /*
                    135:         * Initialize Linux drivers.
                    136:         */
                    137:        linux_init();
                    138: #endif
                    139: 
                    140:        /*
                    141:         * Find the devices
                    142:         */
                    143:        probeio();
                    144: 
                    145:        /*
                    146:         * Get the time
                    147:         */
                    148:        inittodr();
                    149: 
                    150:        /*
                    151:         * Tell the BIOS not to clear and test memory.
                    152:         */
                    153:        *(unsigned short *)phystokv(0x472) = 0x1234;
                    154: 
                    155:        /*
                    156:         * Unmap page 0 to trap NULL references.
                    157:         */
                    158:        pmap_unmap_page_zero();
                    159: }
                    160: 
1.1.1.3 ! root      161: /* Conserve power on processor CPU.  */
        !           162: void machine_idle (int cpu)
        !           163: {
        !           164:   assert (cpu == cpu_number ());
        !           165:   asm volatile ("hlt" : : : "memory");
        !           166: }
        !           167: 
1.1       root      168: /*
                    169:  * Halt a cpu.
                    170:  */
1.1.1.3 ! root      171: void halt_cpu(void)
1.1       root      172: {
                    173:        asm volatile("cli");
                    174:        while(1);
                    175: }
                    176: 
                    177: /*
                    178:  * Halt the system or reboot.
                    179:  */
1.1.1.3 ! root      180: void halt_all_cpus(reboot)
1.1       root      181:        boolean_t       reboot;
                    182: {
                    183:        if (reboot) {
                    184:            kdreboot();
                    185:        }
                    186:        else {
                    187:            rebootflag = 1;
                    188:            printf("In tight loop: hit ctl-alt-del to reboot\n");
                    189:            (void) spl0();
                    190:        }
                    191:        for (;;)
                    192:            continue;
                    193: }
                    194: 
                    195: void exit(int rc)
                    196: {
                    197:        halt_all_cpus(0);
                    198: }
                    199: 
                    200: void db_reset_cpu()
                    201: {
                    202:        halt_all_cpus(1);
                    203: }
                    204: 
                    205: 
                    206: /*
                    207:  * Compute physical memory size and other parameters.
                    208:  */
                    209: void
                    210: mem_size_init()
                    211: {
                    212:        /* Physical memory on all PCs starts at physical address 0.
                    213:           XX make it a constant.  */
                    214:        phys_first_addr = 0;
                    215: 
1.1.1.3 ! root      216:        phys_last_addr = 0x100000 + (boot_info.mem_upper * 0x400);
1.1       root      217:        avail_remaining
1.1.1.3 ! root      218:          = phys_last_addr - (0x100000 - (boot_info.mem_lower * 0x400)
1.1       root      219:                              - 0x1000);
                    220: 
                    221:        printf("AT386 boot: physical memory from 0x%x to 0x%x\n",
                    222:               phys_first_addr, phys_last_addr);
                    223: 
                    224:        if ((!use_all_mem) && phys_last_addr > 16 * 1024*1024) {
                    225:                printf("** Limiting useable memory to 16 Meg to avoid DMA problems.\n");
                    226:                /* This is actually enforced below, in init_alloc_aligned.  */
                    227:        }
                    228: 
                    229:        phys_first_addr = round_page(phys_first_addr);
                    230:        phys_last_addr = trunc_page(phys_last_addr);
                    231: }
                    232: 
                    233: /*
                    234:  * Basic PC VM initialization.
                    235:  * Turns on paging and changes the kernel segments to use high linear addresses.
                    236:  */
                    237: i386at_init()
                    238: {
                    239:        /* XXX move to intel/pmap.h */
                    240:        extern pt_entry_t *kernel_page_dir;
                    241: 
                    242:        /*
                    243:         * Initialize the PIC prior to any possible call to an spl.
                    244:         */
                    245:        picinit();
                    246: 
                    247:        /*
                    248:         * Find memory size parameters.
                    249:         */
                    250:        mem_size_init();
                    251: 
                    252:        /*
                    253:         *      Initialize kernel physical map, mapping the
                    254:         *      region from loadpt to avail_start.
                    255:         *      Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS.
                    256:         *      XXX make the BIOS page (page 0) read-only.
                    257:         */
                    258:        pmap_bootstrap();
                    259: 
                    260:        /*
                    261:         * Turn paging on.
                    262:         * We'll have to temporarily install a direct mapping
                    263:         * between physical memory and low linear memory,
                    264:         * until we start using our new kernel segment descriptors.
                    265:         * One page table (4MB) should do the trick.
                    266:         * Also, set the WP bit so that on 486 or better processors
                    267:         * page-level write protection works in kernel mode.
                    268:         */
                    269:        kernel_page_dir[lin2pdenum(0)] =
                    270:                kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)];
                    271:        set_cr3((unsigned)kernel_page_dir);
                    272:        set_cr0(get_cr0() | CR0_PG | CR0_WP);
                    273:        flush_instr_queue();
                    274: 
                    275:        /*
                    276:         * Initialize and activate the real i386 protected-mode structures.
                    277:         */
                    278:        gdt_init();
                    279:        idt_init();
                    280:        int_init();
                    281:        ldt_init();
                    282:        ktss_init();
                    283: 
                    284:        /* Get rid of the temporary direct mapping and flush it out of the TLB.  */
                    285:        kernel_page_dir[lin2pdenum(0)] = 0;
                    286:        set_cr3((unsigned)kernel_page_dir);
                    287: 
                    288: 
                    289: 
                    290:        /* XXX We'll just use the initialization stack we're already running on
                    291:           as the interrupt stack for now.  Later this will have to change,
                    292:           because the init stack will get freed after bootup.  */
                    293:        asm("movl %%esp,%0" : "=m" (int_stack_top));
                    294: 
                    295:        /* Interrupt stacks are allocated in physical memory,
                    296:           while kernel stacks are allocated in kernel virtual memory,
                    297:           so phys_last_addr serves as a convenient dividing point.  */
                    298:        int_stack_high = phys_last_addr;
                    299: }
                    300: 
                    301: /*
                    302:  *     C boot entrypoint - called by boot_entry in boothdr.S.
                    303:  *     Running in 32-bit flat mode, but without paging yet.
                    304:  */
                    305: void c_boot_entry(vm_offset_t bi)
                    306: {
                    307:        /* Stash the boot_image_info pointer.  */
1.1.1.3 ! root      308:        boot_info = *(struct multiboot_info*)phystokv(bi);
1.1       root      309: 
                    310:        /* XXX we currently assume phys_mem_va is always 0 here -
                    311:           if it isn't, we must tweak the pointers in the boot_info.  */
                    312: 
                    313:        /* Before we do _anything_ else, print the hello message.
                    314:           If there are no initialized console devices yet,
                    315:           it will be stored and printed at the first opportunity.  */
                    316:        printf(version);
                    317:        printf("\n");
                    318: 
                    319:        /* Find the kernel command line, if there is one.  */
1.1.1.3 ! root      320:        if (boot_info.flags & MULTIBOOT_CMDLINE)
        !           321:                kernel_cmdline = (char*)phystokv(boot_info.cmdline);
1.1       root      322: 
                    323: #if    MACH_KDB
                    324:        /*
                    325:         * Locate the kernel's symbol table, if the boot loader provided it.
                    326:         * We need to do this before i386at_init()
                    327:         * so that the symbol table's memory won't be stomped on.
                    328:         */
1.1.1.3 ! root      329:        if ((boot_info.flags & MULTIBOOT_AOUT_SYMS)
        !           330:            && boot_info.syms.a.addr)
1.1       root      331:        {
                    332:                vm_size_t symtab_size, strtab_size;
                    333: 
1.1.1.3 ! root      334:                kern_sym_start = (vm_offset_t)phystokv(boot_info.syms.a.addr);
        !           335:                symtab_size = (vm_offset_t)phystokv(boot_info.syms.a.tabsize);
        !           336:                strtab_size = (vm_offset_t)phystokv(boot_info.syms.a.strsize);
1.1       root      337:                kern_sym_end = kern_sym_start + 4 + symtab_size + strtab_size;
                    338: 
                    339:                printf("kernel symbol table at %08x-%08x (%d,%d)\n",
                    340:                       kern_sym_start, kern_sym_end,
                    341:                       symtab_size, strtab_size);
                    342:        }
1.1.1.3 ! root      343: #endif /* MACH_KDB */
1.1       root      344: 
                    345:        /*
                    346:         * Do basic VM initialization
                    347:         */
                    348:        i386at_init();
                    349: 
                    350: #if    MACH_KDB
                    351:        /*
                    352:         * Initialize the kernel debugger's kernel symbol table.
                    353:         */
                    354:        if (kern_sym_start)
                    355:        {
                    356:                aout_db_sym_init(kern_sym_start, kern_sym_end, "mach", 0);
                    357:        }
                    358: 
                    359:        /*
                    360:         * Cause a breakpoint trap to the debugger before proceeding
                    361:         * any further if the proper option flag was specified
                    362:         * on the kernel's command line.
                    363:         * XXX check for surrounding spaces.
                    364:         */
                    365:        if (strstr(kernel_cmdline, "-d ")) {
                    366:                cninit();               /* need console for debugger */
                    367:                Debugger();
                    368:        }
1.1.1.3 ! root      369: #endif /* MACH_KDB */
1.1       root      370: 
                    371:        machine_slot[0].is_cpu = TRUE;
                    372:        machine_slot[0].running = TRUE;
                    373:        machine_slot[0].cpu_subtype = CPU_SUBTYPE_AT386;
                    374: 
1.1.1.2   root      375: #if 0
                    376:        switch (discover_x86_cpu_type ())
                    377:          {
                    378:          case 3:
                    379:          default:
                    380:            machine_slot[0].cpu_type = CPU_TYPE_I386;
                    381:            break;
                    382:          case 4:
                    383:            machine_slot[0].cpu_type = CPU_TYPE_I486;
                    384:            break;
                    385:          case 5:
                    386:            machine_slot[0].cpu_type = CPU_TYPE_PENTIUM;
                    387:            break;
                    388:          case 6:
                    389:            machine_slot[0].cpu_type = CPU_TYPE_PENTIUMPRO;
                    390:            break;
                    391:          }
                    392: #else
                    393:        machine_slot[0].cpu_type = CPU_TYPE_I386;
1.1.1.3 ! root      394: #endif
1.1.1.2   root      395: 
                    396: 
1.1       root      397:        /*
                    398:         * Start the system.
                    399:         */
                    400:        setup_main();
                    401: 
                    402: }
                    403: 
                    404: #include <mach/vm_prot.h>
                    405: #include <vm/pmap.h>
                    406: #include <mach/time_value.h>
                    407: 
                    408: timemmap(dev,off,prot)
                    409:        vm_prot_t prot;
                    410: {
                    411:        extern time_value_t *mtime;
                    412: 
                    413: #ifdef lint
                    414:        dev++; off++;
1.1.1.3 ! root      415: #endif /* lint */
1.1       root      416: 
                    417:        if (prot & VM_PROT_WRITE) return (-1);
                    418: 
                    419:        return (i386_btop(pmap_extract(pmap_kernel(), (vm_offset_t) mtime)));
                    420: }
                    421: 
                    422: startrtclock()
                    423: {
                    424:        clkstart();
                    425: }
                    426: 
                    427: void
                    428: inittodr()
                    429: {
                    430:        time_value_t    new_time;
                    431: 
                    432:        new_time.seconds = 0;
                    433:        new_time.microseconds = 0;
                    434: 
                    435:        (void) readtodc(&new_time.seconds);
                    436: 
                    437:        {
                    438:            spl_t       s = splhigh();
                    439:            time = new_time;
                    440:            splx(s);
                    441:        }
                    442: }
                    443: 
                    444: void
                    445: resettodr()
                    446: {
                    447:        writetodc();
                    448: }
                    449: 
                    450: unsigned int pmap_free_pages()
                    451: {
                    452:        return atop(avail_remaining);
                    453: }
                    454: 
                    455: /* Always returns page-aligned regions.  */
1.1.1.3 ! root      456: static boolean_t
1.1       root      457: init_alloc_aligned(vm_size_t size, vm_offset_t *addrp)
                    458: {
                    459:        vm_offset_t addr;
                    460:        extern char start[], end[];
                    461:        int i;
1.1.1.3 ! root      462:        static int wrapped = 0;
1.1       root      463: 
                    464:        /* Memory regions to skip.  */
1.1.1.3 ! root      465:        vm_offset_t cmdline_start_pa = boot_info.flags & MULTIBOOT_CMDLINE
        !           466:                ? boot_info.cmdline : 0;
1.1       root      467:        vm_offset_t cmdline_end_pa = cmdline_start_pa
                    468:                ? cmdline_start_pa+strlen((char*)phystokv(cmdline_start_pa))+1
                    469:                : 0;
1.1.1.3 ! root      470:        vm_offset_t mods_start_pa = boot_info.flags & MULTIBOOT_MODS
        !           471:                ? boot_info.mods_addr : 0;
1.1       root      472:        vm_offset_t mods_end_pa = mods_start_pa
                    473:                ? mods_start_pa
1.1.1.3 ! root      474:                  + boot_info.mods_count * sizeof(struct multiboot_module)
1.1       root      475:                : 0;
                    476: 
                    477:        retry:
                    478: 
                    479:        /* Page-align the start address.  */
                    480:        avail_next = round_page(avail_next);
                    481: 
1.1.1.3 ! root      482:        /* Start with memory above 16MB, reserving the low memory for later. */
        !           483:        if (use_all_mem && !wrapped && phys_last_addr > 16 * 1024*1024)
        !           484:          {
        !           485:            if (avail_next < 16 * 1024*1024)
        !           486:              avail_next = 16 * 1024*1024;
        !           487:            else if (avail_next == phys_last_addr)
        !           488:              {
        !           489:                /* We have used all the memory above 16MB, so now start on
        !           490:                   the low memory.  This will wind up at the end of the list
        !           491:                   of free pages, so it should not have been allocated to any
        !           492:                   other use in early initialization before the Linux driver
        !           493:                   glue initialization needs to allocate low memory.  */
        !           494:                avail_next = 0x1000;
        !           495:                wrapped = 1;
        !           496:              }
        !           497:          }
        !           498: 
1.1       root      499:        /* Check if we have reached the end of memory.  */
1.1.1.3 ! root      500:         if (avail_next == (wrapped ? 16 * 1024*1024 : phys_last_addr))
1.1       root      501:                return FALSE;
                    502: 
                    503:        /* Tentatively assign the current location to the caller.  */
                    504:        addr = avail_next;
                    505: 
                    506:        /* Bump the pointer past the newly allocated region
                    507:           and see where that puts us.  */
                    508:        avail_next += size;
                    509: 
                    510:        /* Skip past the I/O and ROM area.  */
1.1.1.3 ! root      511:        if ((avail_next > (boot_info.mem_lower * 0x400)) && (addr < 0x100000))
1.1       root      512:        {
                    513:                avail_next = 0x100000;
                    514:                goto retry;
                    515:        }
                    516: 
                    517:        /* If we're only supposed to use the low 16 megs, enforce that.  */
                    518:        if ((!use_all_mem) && (addr >= 16 * 1024*1024)) {
                    519:                return FALSE;
                    520:        }
                    521: 
                    522:        /* Skip our own kernel code, data, and bss.  */
1.1.1.3 ! root      523:        if ((avail_next > (vm_offset_t)start) && (addr < (vm_offset_t)end))
1.1       root      524:        {
                    525:                avail_next = (vm_offset_t)end;
                    526:                goto retry;
                    527:        }
                    528: 
                    529:        /* Skip any areas occupied by valuable boot_info data.  */
                    530:        if ((avail_next > cmdline_start_pa) && (addr < cmdline_end_pa))
                    531:        {
                    532:                avail_next = cmdline_end_pa;
                    533:                goto retry;
                    534:        }
                    535:        if ((avail_next > mods_start_pa) && (addr < mods_end_pa))
                    536:        {
                    537:                avail_next = mods_end_pa;
                    538:                goto retry;
                    539:        }
                    540:        if ((avail_next > kern_sym_start) && (addr < kern_sym_end))
                    541:        {
                    542:                avail_next = kern_sym_end;
                    543:                goto retry;
                    544:        }
1.1.1.3 ! root      545:        if (boot_info.flags & MULTIBOOT_MODS)
1.1       root      546:        {
                    547:                struct multiboot_module *m = (struct multiboot_module *)
1.1.1.3 ! root      548:                        phystokv(boot_info.mods_addr);
        !           549:                for (i = 0; i < boot_info.mods_count; i++)
1.1       root      550:                {
                    551:                        if ((avail_next > m[i].mod_start)
                    552:                            && (addr < m[i].mod_end))
                    553:                        {
                    554:                                avail_next = m[i].mod_end;
                    555:                                goto retry;
                    556:                        }
                    557:                        /* XXX string */
                    558:                }
                    559:        }
                    560: 
                    561:        avail_remaining -= size;
                    562: 
                    563:        *addrp = addr;
                    564:        return TRUE;
                    565: }
                    566: 
                    567: boolean_t pmap_next_page(addrp)
                    568:        vm_offset_t *addrp;
                    569: {
                    570:        return init_alloc_aligned(PAGE_SIZE, addrp);
                    571: }
                    572: 
                    573: /* Grab a physical page:
                    574:    the standard memory allocation mechanism
                    575:    during system initialization.  */
                    576: vm_offset_t
                    577: pmap_grab_page()
                    578: {
                    579:        vm_offset_t addr;
                    580:        if (!pmap_next_page(&addr))
                    581:                panic("Not enough memory to initialize Mach");
                    582:        return addr;
                    583: }
                    584: 
                    585: boolean_t pmap_valid_page(x)
                    586:        vm_offset_t x;
                    587: {
                    588:        /* XXX is this OK?  What does it matter for?  */
                    589:        return (((phys_first_addr <= x) && (x < phys_last_addr)) &&
1.1.1.3 ! root      590:                !(((boot_info.mem_lower * 1024) <= x) && (x < 1024*1024)));
1.1       root      591: }
                    592: 
                    593: #ifndef NBBY
                    594: #define NBBY   8
                    595: #endif
                    596: #ifndef NBPW
                    597: #define NBPW   (NBBY * sizeof(int))
                    598: #endif
                    599: #define DMA_MAX        (16*1024*1024)
                    600: 
                    601: /*
                    602:  * Allocate contiguous pages below 16 MB
                    603:  * starting at specified boundary for DMA.
                    604:  */
                    605: vm_offset_t
                    606: alloc_dma_mem(size, align)
                    607:        vm_size_t size;
                    608:        vm_offset_t align;
                    609: {
                    610:        int *bits, i, j, k, n;
                    611:        int npages, count, bit, mask;
                    612:        int first_page, last_page;
                    613:        vm_offset_t addr;
                    614:        vm_page_t p, prevp;
                    615: 
                    616:        npages = round_page(size) / PAGE_SIZE;
                    617:        mask = align ? (align - 1) / PAGE_SIZE : 0;
                    618: 
                    619:        /*
                    620:         * Allocate bit array.
                    621:         */
                    622:        n = ((DMA_MAX / PAGE_SIZE) + NBPW - 1) / NBPW;
                    623:        i = n * NBPW;
                    624:        bits = (unsigned *)kalloc(i);
                    625:        if (bits == 0) {
                    626:                printf("alloc_dma_mem: unable alloc bit array\n");
                    627:                return (0);
                    628:        }
                    629:        bzero((char *)bits, i);
                    630: 
                    631:        /*
                    632:         * Walk the page free list and set a bit for
                    633:         * every usable page in bit array.
                    634:         */
                    635:        simple_lock(&vm_page_queue_free_lock);
                    636:        for (p = vm_page_queue_free; p; p = (vm_page_t)p->pageq.next) {
                    637:                if (p->phys_addr < DMA_MAX) {
                    638:                        i = p->phys_addr / PAGE_SIZE;
                    639:                        bits[i / NBPW] |= 1 << (i % NBPW);
                    640:                }
                    641:        }
                    642: 
                    643:        /*
                    644:         * Search for contiguous pages by scanning bit array.
                    645:         */
                    646:        for (i = 0, first_page = -1; i < n; i++) {
                    647:                for (bit = 1, j = 0; j < NBPW; j++, bit <<= 1) {
                    648:                        if (bits[i] & bit) {
                    649:                                if (first_page < 0) {
                    650:                                        k = i * NBPW + j;
                    651:                                        if (!mask
                    652:                                            || (((k & mask) + npages)
                    653:                                                <= mask + 1)) {
                    654:                                                first_page = k;
                    655:                                                if (npages == 1)
                    656:                                                        goto found;
                    657:                                                count = 1;
                    658:                                        }
                    659:                                } else if (++count == npages)
                    660:                                        goto found;
                    661:                        } else
                    662:                                first_page = -1;
                    663:                }
                    664:        }
                    665:        addr = 0;
                    666:        goto out;
                    667: 
                    668:  found:
                    669:        /*
                    670:         * Remove pages from the free list.
                    671:         */
                    672:        addr = first_page * PAGE_SIZE;
                    673:        last_page = first_page + npages;
                    674:        vm_page_free_count -= npages;
                    675:        p = vm_page_queue_free;
                    676:        prevp = 0;
                    677:        while (1) {
                    678:                i = p->phys_addr / PAGE_SIZE;
                    679:                if (i >= first_page && i < last_page) {
                    680:                        if (prevp)
                    681:                                prevp->pageq.next = p->pageq.next;
                    682:                        else
                    683:                                vm_page_queue_free = (vm_page_t)p->pageq.next;
                    684:                        p->free = FALSE;
                    685:                        if (--npages == 0)
                    686:                                break;
                    687:                } else
                    688:                        prevp = p;
                    689:                p = (vm_page_t)p->pageq.next;
                    690:        }
                    691: 
                    692:  out:
                    693:        simple_unlock(&vm_page_queue_free_lock);
                    694:        kfree((vm_offset_t)bits, n * NBPW);
                    695:        return (addr);
                    696: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.