1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31/* 32 * Mach Operating System 33 * Copyright (c) 1991,1990 Carnegie Mellon University 34 * All Rights Reserved. 35 * 36 * Permission to use, copy, modify and distribute this software and its 37 * documentation is hereby granted, provided that both the copyright 38 * notice and this permission notice appear in all copies of the 39 * software, derivative works or modified versions, and any portions 40 * thereof, and that both notices appear in supporting documentation. 41 * 42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56/* 57 */ 58 59#include <platforms.h> 60#include <mach_kdb.h> 61 62#include <i386/asm.h> 63#include <i386/proc_reg.h> 64#include <i386/postcode.h> 65#include <assym.s> 66 67#define CX(addr,reg) addr(,reg,4) 68 69#include <i386/lapic.h> 70#include <i386/mp_slave_boot.h> 71#include <i386/cpuid.h> 72 73/* 74 * GAS won't handle an intersegment jump with a relocatable offset. 75 */ 76#define LJMP(segment,address) \ 77 .byte 0xea ;\ 78 .long address ;\ 79 .word segment 80 81 82 83#define PA(addr) (addr) 84#define VA(addr) (addr) 85 86/* 87 * Interrupt and bootup stack for initial processor. 88 */ 89 90 /* in the __HIB section since the hibernate restore code uses this stack. */ 91 .section __HIB, __data 92 .align 12 93 94 .globl EXT(low_intstack) 95EXT(low_intstack): 96 .globl EXT(gIOHibernateRestoreStack) 97EXT(gIOHibernateRestoreStack): 98 99 .set ., .+INTSTACK_SIZE 100 101 .globl EXT(low_eintstack) 102EXT(low_eintstack:) 103 .globl EXT(gIOHibernateRestoreStackEnd) 104EXT(gIOHibernateRestoreStackEnd): 105 106/* 107 * Pointers to GDT and IDT. These contain linear addresses. 108 */ 109 .align ALIGN 110 .globl EXT(gdtptr) 111 /* align below properly */ 112 .word 0 113LEXT(gdtptr) 114 .word Times(8,GDTSZ)-1 115 .long EXT(master_gdt) 116 117 .align ALIGN 118 .globl EXT(idtptr) 119 /* align below properly */ 120 .word 0 121LEXT(idtptr) 122 .word Times(8,IDTSZ)-1 123 .long EXT(master_idt) 124 125 /* back to the regular __DATA section. */ 126 127 .section __DATA, __data 128 129/* 130 * Stack for last-gasp double-fault handler. 131 */ 132 .align 12 133 .globl EXT(df_task_stack) 134EXT(df_task_stack): 135 .set ., .+INTSTACK_SIZE 136 .globl EXT(df_task_stack_end) 137EXT(df_task_stack_end): 138 139 140/* 141 * Stack for machine-check handler. 142 */ 143 .align 12 144 .globl EXT(mc_task_stack) 145EXT(mc_task_stack): 146 .set ., .+INTSTACK_SIZE 147 .globl EXT(mc_task_stack_end) 148EXT(mc_task_stack_end): 149 150 151#if MACH_KDB 152/* 153 * Kernel debugger stack for each processor. 154 */ 155 .align 12 156 .globl EXT(db_stack_store) 157EXT(db_stack_store): 158 .set ., .+(INTSTACK_SIZE*MAX_CPUS) 159 160/* 161 * Stack for last-ditch debugger task for each processor. 162 */ 163 .align 12 164 .globl EXT(db_task_stack_store) 165EXT(db_task_stack_store): 166 .set ., .+(INTSTACK_SIZE*MAX_CPUS) 167 168/* 169 * per-processor kernel debugger stacks 170 */ 171 .align ALIGN 172 .globl EXT(kgdb_stack_store) 173EXT(kgdb_stack_store): 174 .set ., .+(INTSTACK_SIZE*MAX_CPUS) 175#endif /* MACH_KDB */ 176 177 .data 178physfree: 179 .long 0 /* phys addr of next free page */ 180 181 .globl EXT(IdlePTD) 182EXT(IdlePTD): 183 .long 0 /* phys addr of kernel PTD */ 184#ifdef PAE 185 .globl EXT(IdlePDPT) 186EXT(IdlePDPT): 187 .long 0 /* phys addr of kernel PDPT */ 188#endif 189#ifdef X86_64 190 .globl EXT(IdlePML4) 191EXT(IdlePML4): 192 .long 0 193 .globl EXT(IdlePDPT64) 194EXT(IdlePDPT64): 195 .long 0 196#endif 197 198KPTphys: 199 .long 0 /* phys addr of kernel page tables */ 200 201 .globl EXT(KernelRelocOffset) 202EXT(KernelRelocOffset): 203 .long 0 /* Kernel relocation offset */ 204 205 206/* Some handy macros */ 207 208#define ALLOCPAGES(npages) \ 209 movl PA(physfree), %esi ; \ 210 movl $((npages) * PAGE_SIZE), %eax ; \ 211 addl %esi, %eax ; \ 212 movl %eax, PA(physfree) ; \ 213 movl %esi, %edi ; \ 214 movl $((npages) * PAGE_SIZE / 4),%ecx ; \ 215 xorl %eax,%eax ; \ 216 cld ; \ 217 rep ; \ 218 stosl 219 220/* 221 * fillkpt 222 * eax = page frame address 223 * ebx = index into page table 224 * ecx = how many pages to map 225 * base = base address of page dir/table 226 * prot = protection bits 227 */ 228#define fillkpt(base, prot) \ 229 shll $(PTEINDX),%ebx ; \ 230 addl base,%ebx ; \ 231 orl $(PTE_V) ,%eax ; \ 232 orl prot,%eax ; \ 2331: movl %eax,(%ebx) ; \ 234 addl $(PAGE_SIZE),%eax ; /* increment physical address */ \ 235 addl $(PTESIZE),%ebx ; /* next pte */ \ 236 loop 1b 237 238/* 239 * fillkptphys(prot) 240 * eax = physical address 241 * ecx = how many pages to map 242 * prot = protection bits 243 */ 244#define fillkptphys(prot) \ 245 movl %eax, %ebx ; \ 246 shrl $(PAGE_SHIFT), %ebx ; \ 247 fillkpt(PA(KPTphys), prot) 248 249/* 250 * BSP CPU start here. 251 * eax points to kernbootstruct 252 * 253 * Environment: 254 * protected mode, no paging, flat 32-bit address space. 255 * (Code/data/stack segments have base == 0, limit == 4G) 256 */ 257 .text 258 .align ALIGN 259 .globl EXT(_start) 260 .globl EXT(_pstart) 261LEXT(_start) 262LEXT(_pstart) 263 mov %ds, %bx 264 mov %bx, %es 265 mov %eax, %ebp // Move kernbootstruct to ebp 266 POSTCODE(_PSTART_ENTRY) 267 movl KADDR(%ebp), %ebx // Load boot image phys addr 268 movl %ebx, %edx // Set edx with boot load phys addr 269 addl KSIZE(%ebp), %edx // Add boot image size 270 addl $(NBPG-1), %edx // Round to a page size 271 andl $(-NBPG), %edx // Set edx to first free page 272 movl %edx, %esp // Set temporay stack 273 addl $(NBPG), %esp // add page size 274 call Ls1 275Ls1: popl %esi // Get return address 276 cmpl $(PA(Ls1)), %esi // Compare with static physicall addr 277 je EXT(pstart) // Branch if equal 278 subl $(PA(Ls1)), %esi // Extract relocation offset 279 movl %esi, %esp // Store relocation offset in esp 280 leal (PA(Lreloc_start))(%esp),%esi 281 // Set esi to reloc_start boot phys addr 282 movl %edx, %edi // Set edi to first free page 283 movl $(Lreloc_end-Lreloc_start), %ecx 284 // Set ecx to copy code size 285 cld // count up 286 rep 287 movsb // copy reloc copy code 288 wbinvd // Write back and Invalidate cache 289 movl %ebx, %esi // Set esi to kernbootstruct kaddr 290 movl KADDR(%ebp), %edi // Load boot image phys addr 291 subl %esp, %edi // Adjust to static phys addr 292 movl KSIZE(%ebp), %ecx // Set ecx to kernbootstruct ksize 293 addl $(NBPG-1), %ecx // Add NBPG-1 to ecx 294 andl $(-NBPG), %ecx // Truncate ecx to a page aligned addr 295 shrl $2, %ecx // Divide ecx by 4 296 movl %esp, (PA(EXT(KernelRelocOffset)))(%esp) 297 // Store relocation offset 298 movl %edi, KADDR(%ebp) // Relocate kaddr in kernbootstruct 299 subl %esp, MEMORYMAP(%ebp) // And relocate MemoryMap 300 subl %esp, DEVICETREEP(%ebp) // And relocate deviceTreeP 301 subl %esp, %ebp // Set ebp with relocated phys addr 302 jmp *%edx // Branch to relocated copy code 303Lreloc_start: 304 POSTCODE(_PSTART_RELOC) 305 rep 306 movsl // Copy boot image at BASE_KERNEL_PADDR 307 wbinvd // Write back and Invalidate cache 308 movl $(PA(EXT(pstart))), %edx // Set branch target 309 jmp *%edx // Far jmp to pstart phys addr 310Lreloc_end: 311 /* NOTREACHED */ 312 hlt 313 314 .text 315 .globl __start 316 .set __start, PA(EXT(_pstart)) 317 318/* 319 * BSP CPU continues here after possible relocation. 320 * ebp points to kernbootstruct 321 */ 322 .align ALIGN 323 .globl EXT(pstart) 324LEXT(pstart) 325 mov %ebp, %ebx /* get pointer to kernbootstruct */ 326 327 POSTCODE(PSTART_ENTRY) 328 329 mov $0,%ax /* fs must be zeroed; */ 330 mov %ax,%fs /* some bootstrappers don`t do this */ 331 mov %ax,%gs 332 333/* 334 * Get startup parameters. 335 */ 336 movl KADDR(%ebx), %eax 337 addl KSIZE(%ebx), %eax 338 addl $(NBPG-1),%eax 339 andl $(-NBPG), %eax 340 movl %eax, PA(physfree) 341 cld 342 343/* allocate kernel page table pages */ 344 ALLOCPAGES(NKPT) 345 movl %esi,PA(KPTphys) 346 347#ifdef X86_64 348/* allocate PML4 page */ 349 ALLOCPAGES(1) 350 movl %esi,EXT(IdlePML4) 351/* allocate new 3rd level directory page */ 352 ALLOCPAGES(1) 353 movl %esi,EXT(IdlePDPT64) 354#endif 355 356#ifdef PAE 357/* allocate Page Table Directory Page */ 358 ALLOCPAGES(1) 359 movl %esi,PA(EXT(IdlePDPT)) 360#endif 361 362/* allocate kernel page directory page */ 363 ALLOCPAGES(NPGPTD) 364 movl %esi,PA(EXT(IdlePTD)) 365 366/* map from zero to end of kernel */ 367 xorl %eax,%eax 368 movl PA(physfree),%ecx 369 shrl $(PAGE_SHIFT),%ecx 370 fillkptphys( $(PTE_W) ) 371 372/* map page directory */ 373#ifdef PAE 374 movl PA(EXT(IdlePDPT)), %eax 375 movl $1, %ecx 376 fillkptphys( $(PTE_W) ) 377 378 movl PA(EXT(IdlePDPT64)), %eax 379 movl $1, %ecx 380 fillkptphys( $(PTE_W) ) 381#endif 382 movl PA(EXT(IdlePTD)),%eax 383 movl $(NPGPTD), %ecx 384 fillkptphys( $(PTE_W) ) 385 386/* install a pde for temp double map of bottom of VA */ 387 movl PA(KPTphys),%eax 388 xorl %ebx,%ebx 389 movl $(NKPT), %ecx 390 fillkpt(PA(EXT(IdlePTD)), $(PTE_W)) 391 392/* install pde's for page tables */ 393 movl PA(KPTphys),%eax 394 movl $(KPTDI),%ebx 395 movl $(NKPT),%ecx 396 fillkpt(PA(EXT(IdlePTD)), $(PTE_W)) 397 398/* install a pde recursively mapping page directory as a page table */ 399 movl PA(EXT(IdlePTD)),%eax 400 movl $(PTDPTDI),%ebx 401 movl $(NPGPTD),%ecx 402 fillkpt(PA(EXT(IdlePTD)), $(PTE_W)) 403 404#ifdef PAE 405 movl PA(EXT(IdlePTD)), %eax 406 xorl %ebx, %ebx 407 movl $(NPGPTD), %ecx 408 fillkpt(PA(EXT(IdlePDPT)), $0) 409#endif 410 411/* install a pde page for commpage use up in high memory */ 412 413 movl PA(physfree),%eax /* grab next phys page */ 414 movl %eax,%ebx 415 addl $(PAGE_SIZE),%ebx 416 movl %ebx,PA(physfree) /* show next free phys pg */ 417 movl $(COMM_PAGE_BASE_ADDR),%ebx 418 shrl $(PDESHIFT),%ebx /* index into pde page */ 419 movl $(1), %ecx /* # pdes to store */ 420 fillkpt(PA(EXT(IdlePTD)), $(PTE_W|PTE_U)) /* user has access! */ 421 422 movl PA(physfree),%edi 423 movl %edi,PA(EXT(first_avail)) /* save first available phys addr */ 424 425#ifdef PAE 426/* 427 * We steal 0x4000 for a temp pdpt and 0x5000-0x8000 428 * for temp pde pages in the PAE case. Once we are 429 * running at the proper virtual address we switch to 430 * the PDPT/PDE's the master is using */ 431 432 /* clear pdpt page to be safe */ 433 xorl %eax, %eax 434 movl $(PAGE_SIZE),%ecx 435 movl $(0x4000),%edi 436 cld 437 rep 438 stosb 439 440 /* build temp pdpt */ 441 movl $(0x5000), %eax 442 xorl %ebx, %ebx 443 movl $(NPGPTD), %ecx 444 fillkpt($(0x4000), $0) 445 446 /* copy the NPGPTD pages of pdes */ 447 movl PA(EXT(IdlePTD)),%eax 448 movl $0x5000,%ebx 449 movl $((PTEMASK+1)*NPGPTD),%ecx 4501: movl 0(%eax),%edx 451 movl %edx,0(%ebx) 452 movl 4(%eax),%edx 453 movl %edx,4(%ebx) 454 addl $(PTESIZE),%eax 455 addl $(PTESIZE),%ebx 456 loop 1b 457#else 458/* create temp pde for slaves to use 459 use unused lomem page and copy in IdlePTD */ 460 movl PA(EXT(IdlePTD)),%eax 461 movl $0x4000,%ebx 462 movl $(PTEMASK+1),%ecx 4631: movl 0(%eax),%edx 464 movl %edx,0(%ebx) 465 addl $(PTESIZE),%eax 466 addl $(PTESIZE),%ebx 467 loop 1b 468#endif 469 470 POSTCODE(PSTART_PAGE_TABLES) 471 472/* 473 * Fix initial descriptor tables. 474 */ 475 lea PA(EXT(master_idt)),%esi /* fix IDT */ 476 movl $(IDTSZ),%ecx 477 movl $(PA(fix_idt_ret)),%ebx 478 jmp fix_desc_common /* (cannot use stack) */ 479fix_idt_ret: 480 481 lea PA(EXT(master_gdt)),%esi /* fix GDT */ 482 movl $(GDTSZ),%ecx 483 movl $(PA(fix_gdt_ret)),%ebx 484 jmp fix_desc_common /* (cannot use stack) */ 485fix_gdt_ret: 486 487 lea PA(EXT(master_ldt)),%esi /* fix LDT */ 488 movl $(LDTSZ),%ecx 489 movl $(PA(fix_ldt_ret)),%ebx 490 jmp fix_desc_common /* (cannot use stack) */ 491fix_ldt_ret: 492 493/* 494 * 495 */ 496 497 lgdt PA(EXT(gdtptr)) /* load GDT */ 498 lidt PA(EXT(idtptr)) /* load IDT */ 499 500 POSTCODE(PSTART_BEFORE_PAGING) 501 502/* 503 * Turn on paging. 504 */ 505#ifdef PAE 506 movl PA(EXT(IdlePDPT)), %eax 507 movl %eax, %cr3 508 509 movl %cr4, %eax 510 orl $(CR4_PAE), %eax 511 movl %eax, %cr4 512 513 movl $0x80000001, %eax 514 cpuid 515 and $(CPUID_EXTFEATURE_XD), %edx /* clear all but bit 20 */ 516 cmp $0, %edx /* skip setting NXE if 20 is not set */ 517 je 1f 518 519 movl $(MSR_IA32_EFER), %ecx /* MSR number in ecx */ 520 rdmsr /* MSR value return in edx: eax */ 521 orl $(MSR_IA32_EFER_NXE), %eax /* Set NXE bit in low 32-bits */ 522 wrmsr /* Update Extended Feature Enable reg */ 5231: 524 525#else 526 movl PA(EXT(IdlePTD)), %eax 527 movl %eax,%cr3 528#endif 529 530 movl %cr0,%eax 531 orl $(CR0_PG|CR0_WP|CR0_PE),%eax 532 movl %eax,%cr0 /* to enable paging */ 533 534 LJMP(KERNEL_CS,EXT(vstart)) /* switch to kernel code segment */ 535 536/* 537 * BSP is now running with correct addresses. 538 */ 539LEXT(vstart) 540 POSTCODE(VSTART_ENTRY) ; 541 542 mov $(KERNEL_DS),%ax /* set kernel data segment */ 543 mov %ax,%ds 544 mov %ax,%es 545 mov %ax,%ss 546 mov %ax,EXT(master_ktss)+TSS_SS0 /* set kernel stack segment */ 547 /* for traps to kernel */ 548 549#if MACH_KDB 550 mov %ax,EXT(master_dbtss)+TSS_SS0 /* likewise for debug task switch */ 551 mov %cr3,%eax /* get PDBR into debug TSS */ 552 mov %eax,EXT(master_dbtss)+TSS_PDBR 553 mov $0,%eax 554#endif 555 mov %cr3,%eax /* get PDBR into DF TSS */ 556 mov %eax,EXT(master_dftss)+TSS_PDBR 557 mov %eax,EXT(master_mctss)+TSS_PDBR 558 559 movw $(KERNEL_LDT),%ax /* get LDT segment */ 560 lldt %ax /* load LDT */ 561#if MACH_KDB 562 mov %ax,EXT(master_ktss)+TSS_LDT /* store LDT in two TSS, as well... */ 563 mov %ax,EXT(master_dbtss)+TSS_LDT /* ...matters if we switch tasks */ 564#endif 565 movw $(KERNEL_TSS),%ax 566 ltr %ax /* set up KTSS */ 567 568 mov $(CPU_DATA_GS),%ax 569 mov %ax,%gs 570 571 POSTCODE(VSTART_STACK_SWITCH) 572 573 lea EXT(low_eintstack),%esp /* switch to the bootup stack */ 574 pushl %ebp /* push boot args addr */ 575 xorl %ebp,%ebp /* clear stack frame ptr */ 576 577 POSTCODE(VSTART_EXIT) 578 579 call EXT(i386_init) /* run C code */ 580 /*NOTREACHED*/ 581 hlt 582 583 584/* 585 * AP (slave) CPUs enter here. 586 * 587 * Environment: 588 * protected mode, no paging, flat 32-bit address space. 589 * (Code/data/stack segments have base == 0, limit == 4G) 590 */ 591 .align ALIGN 592 .globl EXT(slave_pstart) 593LEXT(slave_pstart) 594 cli /* disable interrupts, so we don`t */ 595 /* need IDT for a while */ 596 597 POSTCODE(SLAVE_PSTART_ENTRY) 598/* 599 * Turn on paging. 600 */ 601#ifdef PAE 602 movl %cr4, %eax 603 orl $(CR4_PAE), %eax 604 movl %eax, %cr4 605 606 movl $(MSR_IA32_EFER), %ecx /* MSR number in ecx */ 607 rdmsr /* MSR value return in edx: eax */ 608 orl $(MSR_IA32_EFER_NXE), %eax /* Set NXE bit in low 32-bits */ 609 wrmsr /* Update Extended Feature Enable reg */ 610#endif 611 movl $(0x4000),%eax /* tmp until we get mapped */ 612 movl %eax,%cr3 613 614 movl %cr0,%eax 615 orl $(CR0_PG|CR0_WP|CR0_PE),%eax 616 movl %eax,%cr0 /* to enable paging */ 617 618 POSTCODE(SLAVE_PSTART_EXIT) 619 620 movl $(EXT(spag_start)),%edx /* first paged code address */ 621 jmp *%edx /* flush prefetch queue */ 622 623/* 624 * We are now paging, and can run with correct addresses. 625 */ 626LEXT(spag_start) 627 628 lgdt PA(EXT(gdtptr)) /* load GDT */ 629 lidt PA(EXT(idtptr)) /* load IDT */ 630 631 LJMP(KERNEL_CS,EXT(slave_vstart)) /* switch to kernel code segment */ 632 633 634/* 635 * Slave is now running with correct addresses. 636 */ 637LEXT(slave_vstart) 638 639 POSTCODE(SLAVE_VSTART_ENTRY) 640 641#ifdef PAE 642 movl PA(EXT(IdlePDPT)), %eax 643 movl %eax, %cr3 644#else 645 movl PA(EXT(IdlePTD)), %eax 646 movl %eax, %cr3 647#endif 648 649 mov $(KERNEL_DS),%ax /* set kernel data segment */ 650 mov %ax,%ds 651 mov %ax,%es 652 mov %ax,%ss 653 654 /* 655 * We're not quite through with the boot stack 656 * but we need to reset the stack pointer to the correct virtual 657 * address. 658 * And we need to offset above the address of pstart. 659 */ 660 movl $(VA(MP_BOOTSTACK+MP_BOOT+4)), %esp 661 662/* 663 * Switch to the per-cpu descriptor tables 664 */ 665 POSTCODE(SLAVE_VSTART_DESC_INIT) 666 667 CPU_NUMBER_FROM_LAPIC(%eax) 668 movl CX(EXT(cpu_data_ptr),%eax),%ecx 669 670 movw $(GDTSZ*8-1),0(%esp) /* set GDT size in GDT descriptor */ 671 movl CPU_DESC_INDEX+CDI_GDT(%ecx),%edx 672 movl %edx,2(%esp) /* point to local GDT (linear addr) */ 673 lgdt 0(%esp) /* load new GDT */ 674 675 movw $(IDTSZ*8-1),0(%esp) /* set IDT size in IDT descriptor */ 676 movl CPU_DESC_INDEX+CDI_IDT(%ecx),%edx 677 movl %edx,2(%esp) /* point to local IDT (linear addr) */ 678 lidt 0(%esp) /* load new IDT */ 679 680 movw $(KERNEL_LDT),%ax /* get LDT segment */ 681 lldt %ax /* load LDT */ 682 683 movw $(KERNEL_TSS),%ax 684 ltr %ax /* load new KTSS */ 685 686 mov $(CPU_DATA_GS),%ax 687 mov %ax,%gs 688 689/* 690 * Get stack top from pre-cpu data and switch 691 */ 692 POSTCODE(SLAVE_VSTART_STACK_SWITCH) 693 694 movl %gs:CPU_INT_STACK_TOP,%esp 695 xorl %ebp,%ebp /* for completeness */ 696 697 POSTCODE(SLAVE_VSTART_EXIT) 698 699 call EXT(i386_init_slave) /* start MACH */ 700 /*NOTREACHED*/ 701 hlt 702 703/* 704 * Convert a descriptor from fake to real format. 705 * 706 * Calls from assembly code: 707 * %ebx = return address (physical) CANNOT USE STACK 708 * %esi = descriptor table address (physical) 709 * %ecx = number of descriptors 710 * 711 * Calls from C: 712 * 0(%esp) = return address 713 * 4(%esp) = descriptor table address (physical) 714 * 8(%esp) = number of descriptors 715 * 716 * Fake descriptor format: 717 * bytes 0..3 base 31..0 718 * bytes 4..5 limit 15..0 719 * byte 6 access byte 2 | limit 19..16 720 * byte 7 access byte 1 721 * 722 * Real descriptor format: 723 * bytes 0..1 limit 15..0 724 * bytes 2..3 base 15..0 725 * byte 4 base 23..16 726 * byte 5 access byte 1 727 * byte 6 access byte 2 | limit 19..16 728 * byte 7 base 31..24 729 * 730 * Fake gate format: 731 * bytes 0..3 offset 732 * bytes 4..5 selector 733 * byte 6 word count << 4 (to match fake descriptor) 734 * byte 7 access byte 1 735 * 736 * Real gate format: 737 * bytes 0..1 offset 15..0 738 * bytes 2..3 selector 739 * byte 4 word count 740 * byte 5 access byte 1 741 * bytes 6..7 offset 31..16 742 */ 743 .globl EXT(fix_desc) 744LEXT(fix_desc) 745 pushl %ebp /* set up */ 746 movl %esp,%ebp /* stack frame */ 747 pushl %esi /* save registers */ 748 pushl %ebx 749 movl B_ARG0,%esi /* point to first descriptor */ 750 movl B_ARG1,%ecx /* get number of descriptors */ 751 lea 0f,%ebx /* get return address */ 752 jmp fix_desc_common /* call internal routine */ 7530: popl %ebx /* restore registers */ 754 popl %esi 755 leave /* pop stack frame */ 756 ret /* return */ 757 758fix_desc_common: 7590: 760 movw 6(%esi),%dx /* get access byte */ 761 movb %dh,%al 762 andb $0x14,%al 763 cmpb $0x04,%al /* gate or descriptor? */ 764 je 1f 765 766/* descriptor */ 767 movl 0(%esi),%eax /* get base in eax */ 768 rol $16,%eax /* swap 15..0 with 31..16 */ 769 /* (15..0 in correct place) */ 770 movb %al,%dl /* combine bits 23..16 with ACC1 */ 771 /* in dh/dl */ 772 movb %ah,7(%esi) /* store bits 31..24 in correct place */ 773 movw 4(%esi),%ax /* move limit bits 0..15 to word 0 */ 774 movl %eax,0(%esi) /* store (bytes 0..3 correct) */ 775 movw %dx,4(%esi) /* store bytes 4..5 */ 776 jmp 2f 777 778/* gate */ 7791: 780 movw 4(%esi),%ax /* get selector */ 781 shrb $4,%dl /* shift word count to proper place */ 782 movw %dx,4(%esi) /* store word count / ACC1 */ 783 movw 2(%esi),%dx /* get offset 16..31 */ 784 movw %dx,6(%esi) /* store in correct place */ 785 movw %ax,2(%esi) /* store selector in correct place */ 7862: 787 addl $8,%esi /* bump to next descriptor */ 788 loop 0b /* repeat */ 789 jmp *%ebx /* all done */ 790 791/* 792 * put arg in kbd leds and spin a while 793 * eats eax, ecx, edx 794 */ 795#define K_RDWR 0x60 796#define K_CMD_LEDS 0xed 797#define K_STATUS 0x64 798#define K_IBUF_FULL 0x02 /* input (to kbd) buffer full */ 799#define K_OBUF_FULL 0x01 /* output (from kbd) buffer full */ 800 801ENTRY(set_kbd_leds) 802 mov S_ARG0,%cl /* save led value */ 803 8040: inb $(K_STATUS),%al /* get kbd status */ 805 testb $(K_IBUF_FULL),%al /* input busy? */ 806 jne 0b /* loop until not */ 807 808 mov $(K_CMD_LEDS),%al /* K_CMD_LEDS */ 809 outb %al,$(K_RDWR) /* to kbd */ 810 8110: inb $(K_STATUS),%al /* get kbd status */ 812 testb $(K_OBUF_FULL),%al /* output present? */ 813 je 0b /* loop if not */ 814 815 inb $(K_RDWR),%al /* read status (and discard) */ 816 8170: inb $(K_STATUS),%al /* get kbd status */ 818 testb $(K_IBUF_FULL),%al /* input busy? */ 819 jne 0b /* loop until not */ 820 821 mov %cl,%al /* move led value */ 822 outb %al,$(K_RDWR) /* to kbd */ 823 824 movl $10000000,%ecx /* spin */ 8250: nop 826 nop 827 loop 0b /* a while */ 828 829 ret 830