📄 head_32.s
字号:
/* check if it is 486 or 386. *//* * XXX - this does a lot of unnecessary setup. Alignment checks don't * apply at our cpl of 0 and the stack ought to be aligned already, and * we don't need to preserve eflags. */ movb $3,X86 # at least 386 pushfl # push EFLAGS popl %eax # get EFLAGS movl %eax,%ecx # save original EFLAGS xorl $0x240000,%eax # flip AC and ID bits in EFLAGS pushl %eax # copy to EFLAGS popfl # set EFLAGS pushfl # get new EFLAGS popl %eax # put it in eax xorl %ecx,%eax # change in flags pushl %ecx # restore original EFLAGS popfl testl $0x40000,%eax # check if AC bit changed je is386 movb $4,X86 # at least 486 testl $0x200000,%eax # check if ID bit changed je is486 /* get vendor info */ xorl %eax,%eax # call CPUID with 0 -> return vendor ID cpuid movl %eax,X86_CPUID # save CPUID level movl %ebx,X86_VENDOR_ID # lo 4 chars movl %edx,X86_VENDOR_ID+4 # next 4 chars movl %ecx,X86_VENDOR_ID+8 # last 4 chars orl %eax,%eax # do we have processor info as well? je is486 movl $1,%eax # Use the CPUID instruction to get CPU type cpuid movb %al,%cl # save reg for future use andb $0x0f,%ah # mask processor family movb %ah,X86 andb $0xf0,%al # mask model shrb $4,%al movb %al,X86_MODEL andb $0x0f,%cl # mask mask revision movb %cl,X86_MASK movl %edx,X86_CAPABILITYis486: movl $0x50022,%ecx # set AM, WP, NE and MP jmp 2fis386: movl $2,%ecx # set MP2: movl %cr0,%eax andl $0x80000011,%eax # Save PG,PE,ET orl %ecx,%eax movl %eax,%cr0 call check_x87 lgdt early_gdt_descr lidt idt_descr ljmp $(__KERNEL_CS),$1f1: movl $(__KERNEL_DS),%eax # reload all the segment registers movl %eax,%ss # after changing gdt. movl %eax,%fs # gets reset once there's real percpu movl $(__USER_DS),%eax # DS/ES contains default USER segment movl %eax,%ds movl %eax,%es xorl %eax,%eax # Clear GS and LDT movl %eax,%gs lldt %ax cld # gcc2 wants the direction flag cleared at all times pushl $0 # fake return address for unwinder#ifdef CONFIG_SMP movb ready, %cl movb $1, ready cmpb $0,%cl # the first CPU calls start_kernel je 1f movl $(__KERNEL_PERCPU), %eax movl %eax,%fs # set this cpu's percpu jmp initialize_secondary # all other CPUs call initialize_secondary1:#endif /* CONFIG_SMP */ jmp start_kernel/* * We depend on ET to be correct. This checks for 287/387. */check_x87: movb $0,X86_HARD_MATH clts fninit fstsw %ax cmpb $0,%al je 1f movl %cr0,%eax /* no coprocessor: have to set bits */ xorl $4,%eax /* set EM */ movl %eax,%cr0 ret ALIGN1: movb $1,X86_HARD_MATH .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ ret/* * setup_idt * * sets up a idt with 256 entries pointing to * ignore_int, interrupt gates. It doesn't actually load * idt - that can be done only after paging has been enabled * and the kernel moved to PAGE_OFFSET. Interrupts * are enabled elsewhere, when we can be relatively * sure everything is ok. * * Warning: %esi is live across this function. */setup_idt: lea ignore_int,%edx movl $(__KERNEL_CS << 16),%eax movw %dx,%ax /* selector = 0x0010 = cs */ movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ lea idt_table,%edi mov $256,%ecxrp_sidt: movl %eax,(%edi) movl %edx,4(%edi) addl $8,%edi dec %ecx jne rp_sidt.macro set_early_handler handler,trapno lea \handler,%edx movl $(__KERNEL_CS << 16),%eax movw %dx,%ax movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ lea idt_table,%edi movl %eax,8*\trapno(%edi) movl %edx,8*\trapno+4(%edi).endm set_early_handler handler=early_divide_err,trapno=0 set_early_handler handler=early_illegal_opcode,trapno=6 set_early_handler handler=early_protection_fault,trapno=13 set_early_handler handler=early_page_fault,trapno=14 retearly_divide_err: xor %edx,%edx pushl $0 /* fake errcode */ jmp early_faultearly_illegal_opcode: movl $6,%edx pushl $0 /* fake errcode */ jmp early_faultearly_protection_fault: movl $13,%edx jmp early_faultearly_page_fault: movl $14,%edx jmp early_faultearly_fault: cld#ifdef CONFIG_PRINTK pusha movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es cmpl $2,early_recursion_flag je hlt_loop incl early_recursion_flag movl %cr2,%eax pushl %eax pushl %edx /* trapno */ pushl $fault_msg#ifdef CONFIG_EARLY_PRINTK call early_printk#else call printk#endif#endifhlt_loop: hlt jmp hlt_loop/* This is the default interrupt "handler" :-) */ ALIGNignore_int: cld#ifdef CONFIG_PRINTK pushl %eax pushl %ecx pushl %edx pushl %es pushl %ds movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es cmpl $2,early_recursion_flag je hlt_loop incl early_recursion_flag pushl 16(%esp) pushl 24(%esp) pushl 32(%esp) pushl 40(%esp) pushl $int_msg#ifdef CONFIG_EARLY_PRINTK call early_printk#else call printk#endif addl $(5*4),%esp popl %ds popl %es popl %edx popl %ecx popl %eax#endif iret.section .text/* * Real beginning of normal "text" segment */ENTRY(stext)ENTRY(_stext)/* * BSS section */.section ".bss.page_aligned","wa" .align PAGE_SIZE_asmENTRY(swapper_pg_dir) .fill 1024,4,0ENTRY(swapper_pg_pmd) .fill 1024,4,0ENTRY(empty_zero_page) .fill 4096,1,0/* * This starts the data section. */.dataENTRY(stack_start) .long init_thread_union+THREAD_SIZE .long __BOOT_DSready: .byte 0early_recursion_flag: .long 0int_msg: .asciz "Unknown interrupt or fault at EIP %p %p %p\n"fault_msg: .ascii \/* fault info: */ "BUG: Int %d: CR2 %p\n" \/* pusha regs: */ " EDI %p ESI %p EBP %p ESP %p\n" \ " EBX %p EDX %p ECX %p EAX %p\n" \/* fault frame: */ " err %p EIP %p CS %p flg %p\n" \ \ "Stack: %p %p %p %p %p %p %p %p\n" \ " %p %p %p %p %p %p %p %p\n" \ " %p %p %p %p %p %p %p %p\n"#include "../../x86/xen/xen-head.S"/* * The IDT and GDT 'descriptors' are a strange 48-bit object * only used by the lidt and lgdt instructions. They are not * like usual segment descriptors - they consist of a 16-bit * segment size, and 32-bit linear address value: */.globl boot_gdt_descr.globl idt_descr ALIGN# early boot GDT descriptor (must use 1:1 address mapping) .word 0 # 32 bit align gdt_desc.addressboot_gdt_descr: .word __BOOT_DS+7 .long boot_gdt - __PAGE_OFFSET .word 0 # 32-bit align idt_desc.addressidt_descr: .word IDT_ENTRIES*8-1 # idt contains 256 entries .long idt_table# boot GDT descriptor (later on used by CPU#0): .word 0 # 32 bit align gdt_desc.addressENTRY(early_gdt_descr) .word GDT_ENTRIES*8-1 .long per_cpu__gdt_page /* Overwritten for secondary CPUs *//* * The boot_gdt must mirror the equivalent in setup.S and is * used only for booting. */ .align L1_CACHE_BYTESENTRY(boot_gdt) .fill GDT_ENTRY_BOOT_CS,8,0 .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -