diff options
Diffstat (limited to 'arch/x86/kernel/head_32.S')
-rw-r--r-- | arch/x86/kernel/head_32.S | 223 |
1 files changed, 129 insertions, 94 deletions
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index ce0be7cd085e..463c9797ca6a 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/msr-index.h> | 21 | #include <asm/msr-index.h> |
22 | #include <asm/cpufeature.h> | 22 | #include <asm/cpufeature.h> |
23 | #include <asm/percpu.h> | 23 | #include <asm/percpu.h> |
24 | #include <asm/nops.h> | ||
24 | 25 | ||
25 | /* Physical address */ | 26 | /* Physical address */ |
26 | #define pa(X) ((X) - __PAGE_OFFSET) | 27 | #define pa(X) ((X) - __PAGE_OFFSET) |
@@ -363,28 +364,23 @@ default_entry: | |||
363 | pushl $0 | 364 | pushl $0 |
364 | popfl | 365 | popfl |
365 | 366 | ||
366 | #ifdef CONFIG_SMP | ||
367 | cmpb $0, ready | ||
368 | jnz checkCPUtype | ||
369 | #endif /* CONFIG_SMP */ | ||
370 | |||
371 | /* | 367 | /* |
372 | * start system 32-bit setup. We need to re-do some of the things done | 368 | * start system 32-bit setup. We need to re-do some of the things done |
373 | * in 16-bit mode for the "real" operations. | 369 | * in 16-bit mode for the "real" operations. |
374 | */ | 370 | */ |
375 | call setup_idt | 371 | movl setup_once_ref,%eax |
376 | 372 | andl %eax,%eax | |
377 | checkCPUtype: | 373 | jz 1f # Did we do this already? |
378 | 374 | call *%eax | |
379 | movl $-1,X86_CPUID # -1 for no CPUID initially | 375 | 1: |
380 | 376 | ||
381 | /* check if it is 486 or 386. */ | 377 | /* check if it is 486 or 386. */ |
382 | /* | 378 | /* |
383 | * XXX - this does a lot of unnecessary setup. Alignment checks don't | 379 | * XXX - this does a lot of unnecessary setup. Alignment checks don't |
384 | * apply at our cpl of 0 and the stack ought to be aligned already, and | 380 | * apply at our cpl of 0 and the stack ought to be aligned already, and |
385 | * we don't need to preserve eflags. | 381 | * we don't need to preserve eflags. |
386 | */ | 382 | */ |
387 | 383 | movl $-1,X86_CPUID # -1 for no CPUID initially | |
388 | movb $3,X86 # at least 386 | 384 | movb $3,X86 # at least 386 |
389 | pushfl # push EFLAGS | 385 | pushfl # push EFLAGS |
390 | popl %eax # get EFLAGS | 386 | popl %eax # get EFLAGS |
@@ -450,21 +446,6 @@ is386: movl $2,%ecx # set MP | |||
450 | movl $(__KERNEL_PERCPU), %eax | 446 | movl $(__KERNEL_PERCPU), %eax |
451 | movl %eax,%fs # set this cpu's percpu | 447 | movl %eax,%fs # set this cpu's percpu |
452 | 448 | ||
453 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
454 | /* | ||
455 | * The linker can't handle this by relocation. Manually set | ||
456 | * base address in stack canary segment descriptor. | ||
457 | */ | ||
458 | cmpb $0,ready | ||
459 | jne 1f | ||
460 | movl $gdt_page,%eax | ||
461 | movl $stack_canary,%ecx | ||
462 | movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax) | ||
463 | shrl $16, %ecx | ||
464 | movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax) | ||
465 | movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax) | ||
466 | 1: | ||
467 | #endif | ||
468 | movl $(__KERNEL_STACK_CANARY),%eax | 449 | movl $(__KERNEL_STACK_CANARY),%eax |
469 | movl %eax,%gs | 450 | movl %eax,%gs |
470 | 451 | ||
@@ -473,7 +454,6 @@ is386: movl $2,%ecx # set MP | |||
473 | 454 | ||
474 | cld # gcc2 wants the direction flag cleared at all times | 455 | cld # gcc2 wants the direction flag cleared at all times |
475 | pushl $0 # fake return address for unwinder | 456 | pushl $0 # fake return address for unwinder |
476 | movb $1, ready | ||
477 | jmp *(initial_code) | 457 | jmp *(initial_code) |
478 | 458 | ||
479 | /* | 459 | /* |
@@ -495,81 +475,122 @@ check_x87: | |||
495 | .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ | 475 | .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ |
496 | ret | 476 | ret |
497 | 477 | ||
478 | |||
479 | #include "verify_cpu.S" | ||
480 | |||
498 | /* | 481 | /* |
499 | * setup_idt | 482 | * setup_once |
500 | * | 483 | * |
501 | * sets up a idt with 256 entries pointing to | 484 | * The setup work we only want to run on the BSP. |
502 | * ignore_int, interrupt gates. It doesn't actually load | ||
503 | * idt - that can be done only after paging has been enabled | ||
504 | * and the kernel moved to PAGE_OFFSET. Interrupts | ||
505 | * are enabled elsewhere, when we can be relatively | ||
506 | * sure everything is ok. | ||
507 | * | 485 | * |
508 | * Warning: %esi is live across this function. | 486 | * Warning: %esi is live across this function. |
509 | */ | 487 | */ |
510 | setup_idt: | 488 | __INIT |
511 | lea ignore_int,%edx | 489 | setup_once: |
512 | movl $(__KERNEL_CS << 16),%eax | 490 | /* |
513 | movw %dx,%ax /* selector = 0x0010 = cs */ | 491 | * Set up a idt with 256 entries pointing to ignore_int, |
514 | movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ | 492 | * interrupt gates. It doesn't actually load idt - that needs |
493 | * to be done on each CPU. Interrupts are enabled elsewhere, | ||
494 | * when we can be relatively sure everything is ok. | ||
495 | */ | ||
515 | 496 | ||
516 | lea idt_table,%edi | 497 | movl $idt_table,%edi |
517 | mov $256,%ecx | 498 | movl $early_idt_handlers,%eax |
518 | rp_sidt: | 499 | movl $NUM_EXCEPTION_VECTORS,%ecx |
500 | 1: | ||
519 | movl %eax,(%edi) | 501 | movl %eax,(%edi) |
520 | movl %edx,4(%edi) | 502 | movl %eax,4(%edi) |
503 | /* interrupt gate, dpl=0, present */ | ||
504 | movl $(0x8E000000 + __KERNEL_CS),2(%edi) | ||
505 | addl $9,%eax | ||
521 | addl $8,%edi | 506 | addl $8,%edi |
522 | dec %ecx | 507 | loop 1b |
523 | jne rp_sidt | ||
524 | 508 | ||
525 | .macro set_early_handler handler,trapno | 509 | movl $256 - NUM_EXCEPTION_VECTORS,%ecx |
526 | lea \handler,%edx | 510 | movl $ignore_int,%edx |
527 | movl $(__KERNEL_CS << 16),%eax | 511 | movl $(__KERNEL_CS << 16),%eax |
528 | movw %dx,%ax | 512 | movw %dx,%ax /* selector = 0x0010 = cs */ |
529 | movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ | 513 | movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ |
530 | lea idt_table,%edi | 514 | 2: |
531 | movl %eax,8*\trapno(%edi) | 515 | movl %eax,(%edi) |
532 | movl %edx,8*\trapno+4(%edi) | 516 | movl %edx,4(%edi) |
533 | .endm | 517 | addl $8,%edi |
518 | loop 2b | ||
534 | 519 | ||
535 | set_early_handler handler=early_divide_err,trapno=0 | 520 | #ifdef CONFIG_CC_STACKPROTECTOR |
536 | set_early_handler handler=early_illegal_opcode,trapno=6 | 521 | /* |
537 | set_early_handler handler=early_protection_fault,trapno=13 | 522 | * Configure the stack canary. The linker can't handle this by |
538 | set_early_handler handler=early_page_fault,trapno=14 | 523 | * relocation. Manually set base address in stack canary |
524 | * segment descriptor. | ||
525 | */ | ||
526 | movl $gdt_page,%eax | ||
527 | movl $stack_canary,%ecx | ||
528 | movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax) | ||
529 | shrl $16, %ecx | ||
530 | movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax) | ||
531 | movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax) | ||
532 | #endif | ||
539 | 533 | ||
534 | andl $0,setup_once_ref /* Once is enough, thanks */ | ||
540 | ret | 535 | ret |
541 | 536 | ||
542 | early_divide_err: | 537 | ENTRY(early_idt_handlers) |
543 | xor %edx,%edx | 538 | # 36(%esp) %eflags |
544 | pushl $0 /* fake errcode */ | 539 | # 32(%esp) %cs |
545 | jmp early_fault | 540 | # 28(%esp) %eip |
541 | # 24(%rsp) error code | ||
542 | i = 0 | ||
543 | .rept NUM_EXCEPTION_VECTORS | ||
544 | .if (EXCEPTION_ERRCODE_MASK >> i) & 1 | ||
545 | ASM_NOP2 | ||
546 | .else | ||
547 | pushl $0 # Dummy error code, to make stack frame uniform | ||
548 | .endif | ||
549 | pushl $i # 20(%esp) Vector number | ||
550 | jmp early_idt_handler | ||
551 | i = i + 1 | ||
552 | .endr | ||
553 | ENDPROC(early_idt_handlers) | ||
554 | |||
555 | /* This is global to keep gas from relaxing the jumps */ | ||
556 | ENTRY(early_idt_handler) | ||
557 | cld | ||
558 | cmpl $2,%ss:early_recursion_flag | ||
559 | je hlt_loop | ||
560 | incl %ss:early_recursion_flag | ||
546 | 561 | ||
547 | early_illegal_opcode: | 562 | push %eax # 16(%esp) |
548 | movl $6,%edx | 563 | push %ecx # 12(%esp) |
549 | pushl $0 /* fake errcode */ | 564 | push %edx # 8(%esp) |
550 | jmp early_fault | 565 | push %ds # 4(%esp) |
566 | push %es # 0(%esp) | ||
567 | movl $(__KERNEL_DS),%eax | ||
568 | movl %eax,%ds | ||
569 | movl %eax,%es | ||
551 | 570 | ||
552 | early_protection_fault: | 571 | cmpl $(__KERNEL_CS),32(%esp) |
553 | movl $13,%edx | 572 | jne 10f |
554 | jmp early_fault | ||
555 | 573 | ||
556 | early_page_fault: | 574 | leal 28(%esp),%eax # Pointer to %eip |
557 | movl $14,%edx | 575 | call early_fixup_exception |
558 | jmp early_fault | 576 | andl %eax,%eax |
577 | jnz ex_entry /* found an exception entry */ | ||
559 | 578 | ||
560 | early_fault: | 579 | 10: |
561 | cld | ||
562 | #ifdef CONFIG_PRINTK | 580 | #ifdef CONFIG_PRINTK |
563 | pusha | 581 | xorl %eax,%eax |
564 | movl $(__KERNEL_DS),%eax | 582 | movw %ax,2(%esp) /* clean up the segment values on some cpus */ |
565 | movl %eax,%ds | 583 | movw %ax,6(%esp) |
566 | movl %eax,%es | 584 | movw %ax,34(%esp) |
567 | cmpl $2,early_recursion_flag | 585 | leal 40(%esp),%eax |
568 | je hlt_loop | 586 | pushl %eax /* %esp before the exception */ |
569 | incl early_recursion_flag | 587 | pushl %ebx |
588 | pushl %ebp | ||
589 | pushl %esi | ||
590 | pushl %edi | ||
570 | movl %cr2,%eax | 591 | movl %cr2,%eax |
571 | pushl %eax | 592 | pushl %eax |
572 | pushl %edx /* trapno */ | 593 | pushl (20+6*4)(%esp) /* trapno */ |
573 | pushl $fault_msg | 594 | pushl $fault_msg |
574 | call printk | 595 | call printk |
575 | #endif | 596 | #endif |
@@ -578,6 +599,17 @@ hlt_loop: | |||
578 | hlt | 599 | hlt |
579 | jmp hlt_loop | 600 | jmp hlt_loop |
580 | 601 | ||
602 | ex_entry: | ||
603 | pop %es | ||
604 | pop %ds | ||
605 | pop %edx | ||
606 | pop %ecx | ||
607 | pop %eax | ||
608 | addl $8,%esp /* drop vector number and error code */ | ||
609 | decl %ss:early_recursion_flag | ||
610 | iret | ||
611 | ENDPROC(early_idt_handler) | ||
612 | |||
581 | /* This is the default interrupt "handler" :-) */ | 613 | /* This is the default interrupt "handler" :-) */ |
582 | ALIGN | 614 | ALIGN |
583 | ignore_int: | 615 | ignore_int: |
@@ -611,13 +643,18 @@ ignore_int: | |||
611 | popl %eax | 643 | popl %eax |
612 | #endif | 644 | #endif |
613 | iret | 645 | iret |
646 | ENDPROC(ignore_int) | ||
647 | __INITDATA | ||
648 | .align 4 | ||
649 | early_recursion_flag: | ||
650 | .long 0 | ||
614 | 651 | ||
615 | #include "verify_cpu.S" | 652 | __REFDATA |
616 | 653 | .align 4 | |
617 | __REFDATA | ||
618 | .align 4 | ||
619 | ENTRY(initial_code) | 654 | ENTRY(initial_code) |
620 | .long i386_start_kernel | 655 | .long i386_start_kernel |
656 | ENTRY(setup_once_ref) | ||
657 | .long setup_once | ||
621 | 658 | ||
622 | /* | 659 | /* |
623 | * BSS section | 660 | * BSS section |
@@ -670,22 +707,19 @@ ENTRY(initial_page_table) | |||
670 | ENTRY(stack_start) | 707 | ENTRY(stack_start) |
671 | .long init_thread_union+THREAD_SIZE | 708 | .long init_thread_union+THREAD_SIZE |
672 | 709 | ||
673 | early_recursion_flag: | 710 | __INITRODATA |
674 | .long 0 | ||
675 | |||
676 | ready: .byte 0 | ||
677 | |||
678 | int_msg: | 711 | int_msg: |
679 | .asciz "Unknown interrupt or fault at: %p %p %p\n" | 712 | .asciz "Unknown interrupt or fault at: %p %p %p\n" |
680 | 713 | ||
681 | fault_msg: | 714 | fault_msg: |
682 | /* fault info: */ | 715 | /* fault info: */ |
683 | .ascii "BUG: Int %d: CR2 %p\n" | 716 | .ascii "BUG: Int %d: CR2 %p\n" |
684 | /* pusha regs: */ | 717 | /* regs pushed in early_idt_handler: */ |
685 | .ascii " EDI %p ESI %p EBP %p ESP %p\n" | 718 | .ascii " EDI %p ESI %p EBP %p EBX %p\n" |
686 | .ascii " EBX %p EDX %p ECX %p EAX %p\n" | 719 | .ascii " ESP %p ES %p DS %p\n" |
720 | .ascii " EDX %p ECX %p EAX %p\n" | ||
687 | /* fault frame: */ | 721 | /* fault frame: */ |
688 | .ascii " err %p EIP %p CS %p flg %p\n" | 722 | .ascii " vec %p err %p EIP %p CS %p flg %p\n" |
689 | .ascii "Stack: %p %p %p %p %p %p %p %p\n" | 723 | .ascii "Stack: %p %p %p %p %p %p %p %p\n" |
690 | .ascii " %p %p %p %p %p %p %p %p\n" | 724 | .ascii " %p %p %p %p %p %p %p %p\n" |
691 | .asciz " %p %p %p %p %p %p %p %p\n" | 725 | .asciz " %p %p %p %p %p %p %p %p\n" |
@@ -699,6 +733,7 @@ fault_msg: | |||
699 | * segment size, and 32-bit linear address value: | 733 | * segment size, and 32-bit linear address value: |
700 | */ | 734 | */ |
701 | 735 | ||
736 | .data | ||
702 | .globl boot_gdt_descr | 737 | .globl boot_gdt_descr |
703 | .globl idt_descr | 738 | .globl idt_descr |
704 | 739 | ||