|
|
1.1 ! root 1: /* ! 2: * Linux initialization. ! 3: * ! 4: * Copyright (C) 1996 The University of Utah and the Computer Systems ! 5: * Laboratory at the University of Utah (CSL) ! 6: * ! 7: * This program is free software; you can redistribute it and/or modify ! 8: * it under the terms of the GNU General Public License as published by ! 9: * the Free Software Foundation; either version 2, or (at your option) ! 10: * any later version. ! 11: * ! 12: * This program is distributed in the hope that it will be useful, ! 13: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: * GNU General Public License for more details. ! 16: * ! 17: * You should have received a copy of the GNU General Public License ! 18: * along with this program; if not, write to the Free Software ! 19: * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 20: * ! 21: * Author: Shantanu Goel, University of Utah CSL ! 22: */ ! 23: ! 24: /* ! 25: * linux/init/main.c ! 26: * ! 27: * Copyright (C) 1991, 1992 Linus Torvalds ! 28: */ ! 29: ! 30: #include <sys/types.h> ! 31: ! 32: #include <mach/vm_param.h> ! 33: #include <mach/vm_prot.h> ! 34: #include <mach/machine.h> ! 35: ! 36: #include <vm/vm_page.h> ! 37: ! 38: #include <i386/ipl.h> ! 39: #include <i386/pic.h> ! 40: #include <i386/pit.h> ! 41: #include <i386/machspl.h> ! 42: #include <i386/pmap.h> ! 43: #include <i386/vm_param.h> ! 44: ! 45: #include <i386at/gpl/linux/linux_emul.h> ! 46: ! 47: #define MACH_INCLUDE ! 48: #include <linux/sched.h> ! 49: #include <linux/mm.h> ! 50: #include <linux/interrupt.h> ! 51: #include <linux/delay.h> ! 52: #include <linux/ioport.h> ! 53: #include <linux/string.h> ! 54: ! 55: #include <asm/system.h> ! 56: ! 57: #include <i386/device-drivers.h> ! 58: ! 59: /* ! 60: * Set if the machine has an EISA bus. ! 61: */ ! 62: int EISA_bus = 0; ! 63: ! 64: /* ! 65: * Timing loop count. ! 66: */ ! 67: unsigned long loops_per_sec = 1; ! 68: ! 69: /* ! 70: * End of physical memory. ! 71: */ ! 72: unsigned long high_memory; ! 73: ! 74: /* ! 75: * Flag to indicate auto-configuration is in progress. ! 76: */ ! 77: int linux_auto_config = 1; ! 78: ! 79: /* ! 80: * Hard drive parameters obtained from the BIOS. ! 81: */ ! 82: struct drive_info_struct { ! 83: char dummy[32]; ! 84: } drive_info; ! 85: ! 86: /* ! 87: * Forward declarations. ! 88: */ ! 89: static void calibrate_delay(void); ! 90: ! 91: extern int hz; ! 92: extern vm_offset_t phys_last_addr; ! 93: ! 94: extern void timer_bh(void *); ! 95: extern void tqueue_bh(void *); ! 96: extern void startrtclock(void); ! 97: extern void linux_version_init(void); ! 98: extern void linux_kmem_init(void); ! 99: extern unsigned long pci_init(unsigned long, unsigned long); ! 100: extern void linux_net_emulation_init (void); ! 101: extern void device_setup(void); ! 102: extern void linux_printk(char *, ...); ! 103: extern int linux_timer_intr(); ! 104: ! 105: /* ! 106: * Amount of contiguous memory to allocate for initialization. ! 107: */ ! 108: #define CONTIG_ALLOC (512 * 1024) ! 109: ! 110: /* ! 111: * Initialize Linux drivers. ! 112: */ ! 113: void ! 114: linux_init() ! 115: { ! 116: char *p; ! 117: int i, addr; ! 118: int (*old_clock_handler)(), old_clock_pri; ! 119: unsigned memory_start, memory_end; ! 120: vm_page_t pages; ! 121: ! 122: /* ! 123: * Initialize memory size. ! 124: */ ! 125: high_memory = phys_last_addr; ! 126: ! 127: /* ! 128: * Ensure interrupts are disabled. ! 129: */ ! 130: (void) splhigh(); ! 131: ! 132: /* ! 133: * Program counter 0 of 8253 to interrupt hz times per second. ! 134: */ ! 135: outb(PITCTL_PORT, PIT_C0|PIT_SQUAREMODE|PIT_READMODE); ! 136: outb(PITCTR0_PORT, CLKNUM / hz); ! 137: outb(PITCTR0_PORT, (CLKNUM / hz) >> 8); ! 138: ! 139: /* ! 140: * Install our clock interrupt handler. ! 141: */ ! 142: old_clock_handler = ivect[0]; ! 143: old_clock_pri = intpri[0]; ! 144: ivect[0] = linux_timer_intr; ! 145: intpri[0] = SPLHI; ! 146: form_pic_mask(); ! 147: ! 148: /* ! 149: * Enable interrupts. ! 150: */ ! 151: (void) spl0(); ! 152: ! 153: /* ! 154: * Set Linux version. ! 155: */ ! 156: linux_version_init(); ! 157: ! 158: /* ! 159: * Check if the machine has an EISA bus. ! 160: */ ! 161: p = (char *)0x0FFFD9; ! 162: if (*p++ == 'E' && *p++ == 'I' && *p++ == 'S' && *p == 'A') ! 163: EISA_bus = 1; ! 164: ! 165: /* ! 166: * Permanently allocate standard device ports. ! 167: */ ! 168: request_region(0x00, 0x20, "dma1"); ! 169: request_region(0x40, 0x20, "timer"); ! 170: request_region(0x70, 0x10, "rtc"); ! 171: request_region(0x80, 0x20, "dma page reg"); ! 172: request_region(0xc0, 0x20, "dma2"); ! 173: request_region(0xf0, 0x02, "fpu"); ! 174: request_region(0xf8, 0x08, "fpu"); ! 175: ! 176: /* ! 177: * Install software interrupt handlers. ! 178: */ ! 179: bh_base[TIMER_BH].routine = timer_bh; ! 180: bh_base[TIMER_BH].data = 0; ! 181: enable_bh(TIMER_BH); ! 182: bh_base[TQUEUE_BH].routine = tqueue_bh; ! 183: bh_base[TQUEUE_BH].data = 0; ! 184: enable_bh(TQUEUE_BH); ! 185: ! 186: /* ! 187: * Set loop count. ! 188: */ ! 189: calibrate_delay(); ! 190: ! 191: /* ! 192: * Initialize drive info. ! 193: */ ! 194: addr = *((unsigned *)phystokv(0x104)); ! 195: memcpy (&drive_info, ! 196: (void *)((addr & 0xffff) + ((addr >> 12) & 0xffff0)), 16); ! 197: addr = *((unsigned *)phystokv(0x118)); ! 198: memcpy ((char *)&drive_info + 16, ! 199: (void *)((addr & 0xffff) + ((addr >> 12) & 0xffff0)), 16); ! 200: ! 201: /* ! 202: * Initialize Linux memory allocator. ! 203: */ ! 204: linux_kmem_init(); ! 205: ! 206: /* ! 207: * Allocate contiguous memory below 16 MB. ! 208: */ ! 209: memory_start = (unsigned long)alloc_contig_mem(CONTIG_ALLOC, ! 210: 16 * 1024 * 1024, ! 211: 0, &pages); ! 212: if (memory_start == 0) ! 213: panic("linux_init: alloc_contig_mem failed"); ! 214: memory_end = memory_start + CONTIG_ALLOC; ! 215: ! 216: /* ! 217: * Initialize PCI bus. ! 218: */ ! 219: memory_start = pci_init(memory_start, memory_end); ! 220: ! 221: if (memory_start > memory_end) ! 222: panic("linux_init: ran out memory"); ! 223: ! 224: /* ! 225: * Free unused memory. ! 226: */ ! 227: while (pages && pages->phys_addr < round_page(memory_start)) ! 228: pages = (vm_page_t)pages->pageq.next; ! 229: if (pages) ! 230: free_contig_mem(pages); ! 231: ! 232: /* ! 233: * Initialize devices. ! 234: */ ! 235: #ifdef CONFIG_INET ! 236: linux_net_emulation_init(); ! 237: #endif ! 238: cli(); ! 239: device_setup(); ! 240: ! 241: /* ! 242: * Disable interrupts. ! 243: */ ! 244: (void) splhigh(); ! 245: ! 246: /* ! 247: * Restore clock interrupt handler. ! 248: */ ! 249: ivect[0] = old_clock_handler; ! 250: intpri[0] = old_clock_pri; ! 251: form_pic_mask(); ! 252: ! 253: linux_auto_config = 0; ! 254: } ! 255: ! 256: #ifndef NBPW ! 257: #define NBPW 32 ! 258: #endif ! 259: ! 260: /* ! 261: * Allocate contiguous memory with the given constraints. ! 262: * This routine is horribly inefficient but it is presently ! 263: * only used during initialization so it's not that bad. ! 264: */ ! 265: void * ! 266: alloc_contig_mem(unsigned size, unsigned limit, ! 267: unsigned mask, vm_page_t *pages) ! 268: { ! 269: int i, j, bits_len; ! 270: unsigned *bits, len; ! 271: void *m; ! 272: vm_page_t p, page_list, tail, prev; ! 273: vm_offset_t addr, max_addr; ! 274: ! 275: if (size == 0) ! 276: return (NULL); ! 277: size = round_page(size); ! 278: if ((size >> PAGE_SHIFT) > vm_page_free_count) ! 279: return (NULL); ! 280: ! 281: /* Allocate bit array. */ ! 282: max_addr = phys_last_addr; ! 283: if (max_addr > limit) ! 284: max_addr = limit; ! 285: bits_len = ((((max_addr >> PAGE_SHIFT) + NBPW - 1) / NBPW) ! 286: * sizeof(unsigned)); ! 287: bits = (unsigned *)kalloc(bits_len); ! 288: if (!bits) ! 289: return (NULL); ! 290: memset (bits, 0, bits_len); ! 291: ! 292: /* ! 293: * Walk the page free list and set a bit for every usable page. ! 294: */ ! 295: simple_lock(&vm_page_queue_free_lock); ! 296: p = vm_page_queue_free; ! 297: while (p) { ! 298: if (p->phys_addr < limit) ! 299: (bits[(p->phys_addr >> PAGE_SHIFT) / NBPW] ! 300: |= 1 << ((p->phys_addr >> PAGE_SHIFT) % NBPW)); ! 301: p = (vm_page_t)p->pageq.next; ! 302: } ! 303: ! 304: /* ! 305: * Scan bit array for contiguous pages. ! 306: */ ! 307: len = 0; ! 308: m = NULL; ! 309: for (i = 0; len < size && i < bits_len / sizeof (unsigned); i++) ! 310: for (j = 0; len < size && j < NBPW; j++) ! 311: if (!(bits[i] & (1 << j))) { ! 312: len = 0; ! 313: m = NULL; ! 314: } else { ! 315: if (len == 0) { ! 316: addr = ((vm_offset_t)(i * NBPW + j) ! 317: << PAGE_SHIFT); ! 318: if ((addr & mask) == 0) { ! 319: len += PAGE_SIZE; ! 320: m = (void *) addr; ! 321: } ! 322: } else ! 323: len += PAGE_SIZE; ! 324: } ! 325: ! 326: if (len != size) { ! 327: simple_unlock(&vm_page_queue_free_lock); ! 328: kfree ((vm_offset_t)bits, bits_len); ! 329: return (NULL); ! 330: } ! 331: ! 332: /* ! 333: * Remove pages from free list ! 334: * and construct list to return to caller. ! 335: */ ! 336: page_list = NULL; ! 337: for (len = 0; len < size; len += PAGE_SIZE, addr += PAGE_SIZE) { ! 338: prev = NULL; ! 339: for (p = vm_page_queue_free; p; p = (vm_page_t)p->pageq.next) { ! 340: if (p->phys_addr == addr) ! 341: break; ! 342: prev = p; ! 343: } ! 344: if (!p) ! 345: panic("alloc_contig_mem: page not on free list"); ! 346: if (prev) ! 347: prev->pageq.next = p->pageq.next; ! 348: else ! 349: vm_page_queue_free = (vm_page_t)p->pageq.next; ! 350: p->free = FALSE; ! 351: p->pageq.next = NULL; ! 352: if (!page_list) ! 353: page_list = tail = p; ! 354: else { ! 355: tail->pageq.next = (queue_entry_t)p; ! 356: tail = p; ! 357: } ! 358: vm_page_free_count--; ! 359: } ! 360: ! 361: simple_unlock(&vm_page_queue_free_lock); ! 362: kfree((vm_offset_t)bits, bits_len); ! 363: if (pages) ! 364: *pages = page_list; ! 365: return (m); ! 366: } ! 367: ! 368: /* ! 369: * Free memory allocated by alloc_contig_mem. ! 370: */ ! 371: void ! 372: free_contig_mem(vm_page_t pages) ! 373: { ! 374: int i; ! 375: vm_page_t p; ! 376: ! 377: for (p = pages, i = 0; p->pageq.next; p = (vm_page_t)p->pageq.next, i++) ! 378: p->free = TRUE; ! 379: p->free = TRUE; ! 380: simple_lock(&vm_page_queue_free_lock); ! 381: vm_page_free_count += i + 1; ! 382: p->pageq.next = (queue_entry_t)vm_page_queue_free; ! 383: vm_page_queue_free = pages; ! 384: simple_unlock(&vm_page_queue_free_lock); ! 385: } ! 386: ! 387: /* ! 388: * Calibrate delay loop. ! 389: * Lifted straight from Linux. ! 390: */ ! 391: static void ! 392: calibrate_delay() ! 393: { ! 394: int ticks; ! 395: ! 396: /* printk("Calibrating delay loop.. "); */ ! 397: while (loops_per_sec <<= 1) { ! 398: /* Wait for "start of" clock tick. */ ! 399: ticks = jiffies; ! 400: while (ticks == jiffies) ! 401: /* nothing */; ! 402: /* Go .. */ ! 403: ticks = jiffies; ! 404: __delay(loops_per_sec); ! 405: ticks = jiffies - ticks; ! 406: if (ticks >= hz) { ! 407: loops_per_sec = muldiv(loops_per_sec, ! 408: hz, ticks); ! 409: /*printk("ok - %lu.%02lu BogoMips\n", ! 410: loops_per_sec / 500000, ! 411: (loops_per_sec / 5000) % 100);*/ ! 412: return; ! 413: } ! 414: } ! 415: /* printk("failed\n");*/ ! 416: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.