|
|
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.