|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52:
53: #include <platforms.h>
54: #include <cpus.h>
55: #include <mach_kdb.h>
56:
57: #include <i386/asm.h>
58: #include <i386/proc_reg.h>
59: #include <assym.s>
60:
61: #if NCPUS > 1
62:
63: #define CX(addr,reg) addr(,reg,4)
64:
65: #else
66:
67: #define CPU_NUMBER(reg)
68: #define CX(addr,reg) addr
69:
70: #endif /* NCPUS > 1 */
71:
72: #include <i386/AT386/mp/mp.h>
73:
74: /*
75: * GAS won't handle an intersegment jump with a relocatable offset.
76: */
77: #define LJMP(segment,address) \
78: .byte 0xea ;\
79: .long address ;\
80: .word segment
81:
82:
83:
84: #define KVTOPHYS (-KERNELBASE)
85: #define KVTOLINEAR LINEAR_KERNELBASE
86:
87:
88: #define PA(addr) (addr)+KVTOPHYS
89: #define VA(addr) (addr)-KVTOPHYS
90:
91: .data
92: .align 2
93: .globl EXT(_kick_buffer_)
94: EXT(_kick_buffer_):
95: .long 1
96: .long 3
97: .set .,.+16836
98: /*
99: * Interrupt and bootup stack for initial processor.
100: */
101: .align ALIGN
102: .globl EXT(intstack)
103: EXT(intstack):
104: .set ., .+INTSTACK_SIZE
105: .globl EXT(eintstack)
106: EXT(eintstack:)
107:
108: #if NCPUS == 1
109: .globl EXT(int_stack_high) /* all interrupt stacks */
110: EXT(int_stack_high): /* must lie below this */
111: .long EXT(eintstack) /* address */
112:
113: .globl EXT(int_stack_top) /* top of interrupt stack */
114: EXT(int_stack_top):
115: .long EXT(eintstack)
116: #endif
117:
118: #if MACH_KDB
119: /*
120: * Kernel debugger stack for each processor.
121: */
122: .align ALIGN
123: .globl EXT(db_stack_store)
124: EXT(db_stack_store):
125: .set ., .+(INTSTACK_SIZE*NCPUS)
126:
127: /*
128: * Stack for last-ditch debugger task for each processor.
129: */
130: .align ALIGN
131: .globl EXT(db_task_stack_store)
132: EXT(db_task_stack_store):
133: .set ., .+(INTSTACK_SIZE*NCPUS)
134: #endif /* MACH_KDB */
135:
136: /*
137: * per-processor kernel debugger stacks
138: */
139: .align ALIGN
140: .globl EXT(kgdb_stack_store)
141: EXT(kgdb_stack_store):
142: .set ., .+(INTSTACK_SIZE*NCPUS)
143:
144:
145: /*
146: * Pointers to GDT and IDT. These contain linear addresses.
147: */
148: .align ALIGN
149: .globl EXT(gdtptr)
150: LEXT(gdtptr)
151: .word Times(8,GDTSZ)-1
152: .long EXT(gdt)+KVTOLINEAR
153:
154: .align ALIGN
155: .globl EXT(idtptr)
156: LEXT(idtptr)
157: .word Times(8,IDTSZ)-1
158: .long EXT(idt)+KVTOLINEAR
159:
160: #if NCPUS > 1
161: .data
162: /*
163: * start_lock is very special. We initialize the
164: * lock at allocation time rather than at run-time.
165: * Although start_lock should be an instance of a
166: * hw_lock, we hand-code all manipulation of the lock
167: * because the hw_lock code may require function calls;
168: * and we'd rather not introduce another dependency on
169: * a working stack at this point.
170: */
171: .globl EXT(start_lock)
172: EXT(start_lock):
173: .long 0 /* synchronizes processor startup */
174:
175: .globl EXT(master_is_up)
176: EXT(master_is_up):
177: .long 0 /* 1 when OK for other processors */
178: /* to start */
179: .globl EXT(mp_boot_pde)
180: EXT(mp_boot_pde):
181: .long 0
182: #endif /* NCPUS > 1 */
183:
184: /*
185: * All CPUs start here.
186: *
187: * Environment:
188: * protected mode, no paging, flat 32-bit address space.
189: * (Code/data/stack segments have base == 0, limit == 4G)
190: */
191: .text
192: .align ALIGN
193: .globl EXT(pstart)
194: .globl EXT(_start)
195: LEXT(_start)
196: LEXT(pstart)
197: mov $0,%ax /* fs must be zeroed; */
198: mov %ax,%fs /* some bootstrappers don`t do this */
199: mov %ax,%gs
200:
201: #if NCPUS > 1
202: jmp 1f
203: 0: cmpl $0,PA(EXT(start_lock))
204: jne 0b
205: 1: movb $1,%eax
206: xchgl %eax,PA(EXT(start_lock)) /* locked */
207: testl %eax,%eax
208: jnz 0b
209:
210: cmpl $0,PA(EXT(master_is_up)) /* are we first? */
211: jne EXT(slave_start) /* no -- system already up. */
212: movl $1,PA(EXT(master_is_up)) /* others become slaves */
213: #endif /* NCPUS > 1 */
214:
215: /*
216: * Get startup parameters.
217: */
218:
219: #include <i386/AT386/asm_startup.h>
220:
221: /*
222: * Build initial page table directory and page tables.
223: * %ebx holds first available physical address.
224: */
225:
226: addl $(NBPG-1),%ebx /* round first avail physical addr */
227: andl $(-NBPG),%ebx /* to machine page size */
228: leal -KVTOPHYS(%ebx),%eax /* convert to virtual address */
229: movl %eax,PA(EXT(kpde)) /* save as kernel page table directory */
230: movl %ebx,%cr3 /* set physical address in CR3 now */
231:
232: movl %ebx,%edi /* clear page table directory */
233: movl $(PTES_PER_PAGE),%ecx /* one page of ptes */
234: xorl %eax,%eax
235: cld
236: rep
237: stosl /* edi now points to next page */
238:
239: /*
240: * Use next few pages for page tables.
241: */
242: addl $(KERNELBASEPDE),%ebx /* point to pde for kernel base */
243: movl %edi,%esi /* point to end of current pte page */
244:
245: /*
246: * Enter 1-1 mappings for kernel and for kernel page tables.
247: */
248: movl $(INTEL_PTE_KERNEL),%eax /* set up pte prototype */
249: 0:
250: cmpl %esi,%edi /* at end of pte page? */
251: jb 1f /* if so: */
252: movl %edi,%edx /* get pte address (physical) */
253: andl $(-NBPG),%edx /* mask out offset in page */
254: orl $(INTEL_PTE_KERNEL),%edx /* add pte bits */
255: movl %edx,(%ebx) /* set pde */
256: addl $4,%ebx /* point to next pde */
257: movl %edi,%esi /* point to */
258: addl $(NBPG),%esi /* end of new pte page */
259: 1:
260: movl %eax,(%edi) /* set pte */
261: addl $4,%edi /* advance to next pte */
262: addl $(NBPG),%eax /* advance to next phys page */
263: cmpl %edi,%eax /* have we mapped this pte page yet? */
264: jb 0b /* loop if not */
265:
266: /*
267: * Zero rest of last pte page.
268: */
269: xor %eax,%eax /* don`t map yet */
270: 2: cmpl %esi,%edi /* at end of pte page? */
271: jae 3f
272: movl %eax,(%edi) /* zero mapping */
273: addl $4,%edi
274: jmp 2b
275: 3:
276:
277: #if NCPUS > 1
278: /*
279: * Grab (waste?) another page for a bootstrap page directory
280: * for the other CPUs. We don't want the running CPUs to see
281: * addresses 0..3fffff mapped 1-1.
282: */
283: movl %edi,PA(EXT(mp_boot_pde)) /* save its physical address */
284: movl $(PTES_PER_PAGE),%ecx /* and clear it */
285: rep
286: stosl
287: #endif /* NCPUS > 1 */
288: movl %edi,PA(EXT(first_avail)) /* save first available phys addr */
289:
290: /*
291: * pmap_bootstrap will enter rest of mappings.
292: */
293:
294: /*
295: * Fix initial descriptor tables.
296: */
297: lea PA(EXT(idt)),%esi /* fix IDT */
298: movl $(IDTSZ),%ecx
299: movl $(PA(fix_idt_ret)),%ebx
300: jmp fix_desc_common /* (cannot use stack) */
301: fix_idt_ret:
302:
303: lea PA(EXT(gdt)),%esi /* fix GDT */
304: movl $(GDTSZ),%ecx
305: movl $(PA(fix_gdt_ret)),%ebx
306: jmp fix_desc_common /* (cannot use stack) */
307: fix_gdt_ret:
308:
309: lea PA(EXT(ldt)),%esi /* fix LDT */
310: movl $(LDTSZ),%ecx
311: movl $(PA(fix_ldt_ret)),%ebx
312: jmp fix_desc_common /* (cannot use stack) */
313: fix_ldt_ret:
314:
315: /*
316: * Turn on paging.
317: */
318: movl %cr3,%eax /* retrieve kernel PDE phys address */
319: movl KERNELBASEPDE(%eax),%ecx
320: movl %ecx,(%eax) /* set it also as pte for location */
321: /* 0..3fffff, so that the code */
322: /* that enters paged mode is mapped */
323: /* to identical addresses after */
324: /* paged mode is enabled */
325:
326: movl $EXT(pag_start),%ebx /* first paged code address */
327:
328: movl %cr0,%eax
329: orl $(CR0_PG),%eax /* set PG bit in CR0 */
330: orl $(CR0_WP),%eax
331: movl %eax,%cr0 /* to enable paging */
332:
333: jmp *%ebx /* flush prefetch queue */
334:
335: /*
336: * We are now paging, and can run with correct addresses.
337: */
338: LEXT(pag_start)
339: lgdt EXT(gdtptr) /* load GDT */
340: lidt EXT(idtptr) /* load IDT */
341: LJMP(KERNEL_CS,EXT(vstart)) /* switch to kernel code segment */
342:
343: /*
344: * Master is now running with correct addresses.
345: */
346: LEXT(vstart)
347: mov $(KERNEL_DS),%ax /* set kernel data segment */
348: mov %ax,%ds
349: mov %ax,%es
350: mov %ax,%ss
351: mov %ax,EXT(ktss)+TSS_SS0 /* set kernel stack segment */
352: /* for traps to kernel */
353: #if MACH_KDB
354: mov %ax,EXT(dbtss)+TSS_SS0 /* likewise for debug task switch */
355: mov %cr3,%eax /* get PDBR into debug TSS */
356: mov %eax,EXT(dbtss)+TSS_PDBR
357: mov $0,%eax
358: #endif
359:
360: movw $(KERNEL_LDT),%ax /* get LDT segment */
361: lldt %ax /* load LDT */
362: #if MACH_KDB
363: mov %ax,EXT(ktss)+TSS_LDT /* store LDT in two TSS, as well... */
364: mov %ax,EXT(dbtss)+TSS_LDT /* ...matters if we switch tasks */
365: #endif
366: movw $(KERNEL_TSS),%ax
367: ltr %ax /* set up KTSS */
368:
369: mov $CPU_DATA,%ax
370: mov %ax,%gs
371:
372: lea EXT(eintstack),%esp /* switch to the bootup stack */
373: call EXT(machine_startup) /* run C code */
374: /*NOTREACHED*/
375: hlt
376:
377: #if NCPUS > 1
378: /*
379: * master_up is used by the master cpu to signify that it is done
380: * with the interrupt stack, etc. See the code in pstart and svstart
381: * that this interlocks with.
382: */
383: .align ALIGN
384: .globl EXT(master_up)
385: LEXT(master_up)
386: pushl %ebp /* set up */
387: movl %esp,%ebp /* stack frame */
388: movl $0,%ecx /* unlock start_lock */
389: xchgl %ecx,EXT(start_lock) /* since we are no longer using */
390: /* bootstrap stack */
391: leave /* pop stack frame */
392: ret
393:
394: /*
395: * We aren't the first. Call slave_main to initialize the processor
396: * and get Mach going on it.
397: */
398: .align ALIGN
399: .globl EXT(slave_start)
400: LEXT(slave_start)
401: cli /* disable interrupts, so we don`t */
402: /* need IDT for a while */
403: movl EXT(kpde)+KVTOPHYS,%ebx /* get PDE virtual address */
404: addl $(KVTOPHYS),%ebx /* convert to physical address */
405:
406: movl PA(EXT(mp_boot_pde)),%edx /* point to the bootstrap PDE */
407: movl KERNELBASEPDE(%ebx),%eax
408: /* point to pte for KERNELBASE */
409: movl %eax,KERNELBASEPDE(%edx)
410: /* set in bootstrap PDE */
411: movl %eax,(%edx) /* set it also as pte for location */
412: /* 0..3fffff, so that the code */
413: /* that enters paged mode is mapped */
414: /* to identical addresses after */
415: /* paged mode is enabled */
416: movl %edx,%cr3 /* use bootstrap PDE to enable paging */
417:
418: movl $EXT(spag_start),%edx /* first paged code address */
419:
420: movl %cr0,%eax
421: orl $(CR0_PG),%eax /* set PG bit in CR0 */
422: orl $(CR0_WP),%eax
423: movl %eax,%cr0 /* to enable paging */
424:
425: jmp *%edx /* flush prefetch queue. */
426:
427: /*
428: * We are now paging, and can run with correct addresses.
429: */
430: LEXT(spag_start)
431:
432: lgdt EXT(gdtptr) /* load GDT */
433: lidt EXT(idtptr) /* load IDT */
434: LJMP(KERNEL_CS,EXT(svstart)) /* switch to kernel code segment */
435:
436: /*
437: * Slave is now running with correct addresses.
438: */
439: LEXT(svstart)
440: mov $(KERNEL_DS),%ax /* set kernel data segment */
441: mov %ax,%ds
442: mov %ax,%es
443: mov %ax,%ss
444:
445: movl %ebx,%cr3 /* switch to the real kernel PDE */
446:
447: CPU_NUMBER(%eax)
448: movl CX(EXT(interrupt_stack),%eax),%esp /* get stack */
449: addl $(INTSTACK_SIZE),%esp /* point to top */
450: xorl %ebp,%ebp /* for completeness */
451:
452: movl $0,%ecx /* unlock start_lock */
453: xchgl %ecx,EXT(start_lock) /* since we are no longer using */
454: /* bootstrap stack */
455:
456: /*
457: * switch to the per-cpu descriptor tables
458: */
459:
460: pushl %eax /* pass CPU number */
461: call EXT(mp_desc_init) /* set up local table */
462: /* pointer returned in %eax */
463: subl $4,%esp /* get space to build pseudo-descriptors */
464:
465: CPU_NUMBER(%eax)
466: movw $(GDTSZ*8-1),0(%esp) /* set GDT size in GDT descriptor */
467: movl CX(EXT(mp_gdt),%eax),%edx
468: addl $KVTOLINEAR,%edx
469: movl %edx,2(%esp) /* point to local GDT (linear address) */
470: lgdt 0(%esp) /* load new GDT */
471:
472: movw $(IDTSZ*8-1),0(%esp) /* set IDT size in IDT descriptor */
473: movl CX(EXT(mp_idt),%eax),%edx
474: addl $KVTOLINEAR,%edx
475: movl %edx,2(%esp) /* point to local IDT (linear address) */
476: lidt 0(%esp) /* load new IDT */
477:
478: movw $(KERNEL_LDT),%ax
479: lldt %ax /* load new LDT */
480:
481: movw $(KERNEL_TSS),%ax
482: ltr %ax /* load new KTSS */
483:
484: mov $CPU_DATA,%ax
485: mov %ax,%gs
486:
487: call EXT(slave_main) /* start MACH */
488: /*NOTREACHED*/
489: hlt
490: #endif /* NCPUS > 1 */
491:
492: /*
493: * Convert a descriptor from fake to real format.
494: *
495: * Calls from assembly code:
496: * %ebx = return address (physical) CANNOT USE STACK
497: * %esi = descriptor table address (physical)
498: * %ecx = number of descriptors
499: *
500: * Calls from C:
501: * 0(%esp) = return address
502: * 4(%esp) = descriptor table address (physical)
503: * 8(%esp) = number of descriptors
504: *
505: * Fake descriptor format:
506: * bytes 0..3 base 31..0
507: * bytes 4..5 limit 15..0
508: * byte 6 access byte 2 | limit 19..16
509: * byte 7 access byte 1
510: *
511: * Real descriptor format:
512: * bytes 0..1 limit 15..0
513: * bytes 2..3 base 15..0
514: * byte 4 base 23..16
515: * byte 5 access byte 1
516: * byte 6 access byte 2 | limit 19..16
517: * byte 7 base 31..24
518: *
519: * Fake gate format:
520: * bytes 0..3 offset
521: * bytes 4..5 selector
522: * byte 6 word count << 4 (to match fake descriptor)
523: * byte 7 access byte 1
524: *
525: * Real gate format:
526: * bytes 0..1 offset 15..0
527: * bytes 2..3 selector
528: * byte 4 word count
529: * byte 5 access byte 1
530: * bytes 6..7 offset 31..16
531: */
532: .globl EXT(fix_desc)
533: LEXT(fix_desc)
534: pushl %ebp /* set up */
535: movl %esp,%ebp /* stack frame */
536: pushl %esi /* save registers */
537: pushl %ebx
538: movl B_ARG0,%esi /* point to first descriptor */
539: movl B_ARG1,%ecx /* get number of descriptors */
540: lea 0f,%ebx /* get return address */
541: jmp fix_desc_common /* call internal routine */
542: 0: popl %ebx /* restore registers */
543: popl %esi
544: leave /* pop stack frame */
545: ret /* return */
546:
547: fix_desc_common:
548: 0:
549: movw 6(%esi),%dx /* get access byte */
550: movb %dh,%al
551: andb $0x14,%al
552: cmpb $0x04,%al /* gate or descriptor? */
553: je 1f
554:
555: /* descriptor */
556: movl 0(%esi),%eax /* get base in eax */
557: rol $16,%eax /* swap 15..0 with 31..16 */
558: /* (15..0 in correct place) */
559: movb %al,%dl /* combine bits 23..16 with ACC1 */
560: /* in dh/dl */
561: movb %ah,7(%esi) /* store bits 31..24 in correct place */
562: movw 4(%esi),%ax /* move limit bits 0..15 to word 0 */
563: movl %eax,0(%esi) /* store (bytes 0..3 correct) */
564: movw %dx,4(%esi) /* store bytes 4..5 */
565: jmp 2f
566:
567: /* gate */
568: 1:
569: movw 4(%esi),%ax /* get selector */
570: shrb $4,%dl /* shift word count to proper place */
571: movw %dx,4(%esi) /* store word count / ACC1 */
572: movw 2(%esi),%dx /* get offset 16..31 */
573: movw %dx,6(%esi) /* store in correct place */
574: movw %ax,2(%esi) /* store selector in correct place */
575: 2:
576: addl $8,%esi /* bump to next descriptor */
577: loop 0b /* repeat */
578: jmp *%ebx /* all done */
579:
580: /*
581: * put arg in kbd leds and spin a while
582: * eats eax, ecx, edx
583: */
584: #define K_RDWR 0x60
585: #define K_CMD_LEDS 0xed
586: #define K_STATUS 0x64
587: #define K_IBUF_FULL 0x02 /* input (to kbd) buffer full */
588: #define K_OBUF_FULL 0x01 /* output (from kbd) buffer full */
589:
590: ENTRY(set_kbd_leds)
591: mov S_ARG0,%cl /* save led value */
592:
593: 0: inb $(K_STATUS),%al /* get kbd status */
594: testb $(K_IBUF_FULL),%al /* input busy? */
595: jne 0b /* loop until not */
596:
597: mov $(K_CMD_LEDS),%al /* K_CMD_LEDS */
598: outb %al,$(K_RDWR) /* to kbd */
599:
600: 0: inb $(K_STATUS),%al /* get kbd status */
601: testb $(K_OBUF_FULL),%al /* output present? */
602: je 0b /* loop if not */
603:
604: inb $(K_RDWR),%al /* read status (and discard) */
605:
606: 0: inb $(K_STATUS),%al /* get kbd status */
607: testb $(K_IBUF_FULL),%al /* input busy? */
608: jne 0b /* loop until not */
609:
610: mov %cl,%al /* move led value */
611: outb %al,$(K_RDWR) /* to kbd */
612:
613: movl $10000000,%ecx /* spin */
614: 0: nop
615: nop
616: loop 0b /* a while */
617:
618: ret
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.