📄 start32.s
字号:
andq $0xffffffff, %rdx /* Get the argument pointer */ movl 24(%rbx), %ebx andq $0xffffffff, %rbx /* Jump to the 64bit code */ call *%rdx /* Preserve the result */ movl %eax, %edx /* Fixup %eflags */ cli cld /* Switch to 32bit compatibility mode */ ljmp *end_lm_addr(%rip) .code32end_lm: /* Disable paging */ movl %cr0, %eax andl $~CR0_PG, %eax movl %eax, %cr0 /* Disable long mode */ movl $MSR_K6_EFER, %ecx rdmsr andl $~EFER_LME, %eax wrmsr /* Disable PAE */ movl %cr4, %eax andl $~X86_CR4_PAE, %eax movl %eax, %cr4 /* Compute virt_offset */ popl %ebp /* Compute the original stack pointer + 16 */ popl %ebx movl %ebx, %esp /* Enable the virtual addresses */ leal _phys_to_virt(%ebp), %eax call *%eax /* Restore the callee save registers */ popl %ebx popl %esi popl %edi popl %ebp /* Get the C return value */ movl %edx, %eax /* Return */ ret .arch i386#endif /* CONFIG_X86_64 *//**************************************************************************SETJMP - Save stack context for non-local goto**************************************************************************/ .globl setjmpsetjmp: movl 4(%esp),%ecx /* jmpbuf */ movl 0(%esp),%edx /* return address */ movl %edx,0(%ecx) movl %ebx,4(%ecx) movl %esp,8(%ecx) movl %ebp,12(%ecx) movl %esi,16(%ecx) movl %edi,20(%ecx) movl $0,%eax ret/**************************************************************************LONGJMP - Non-local jump to a saved stack context**************************************************************************/ .globl longjmplongjmp: movl 4(%esp),%edx /* jumpbuf */ movl 8(%esp),%eax /* result */ movl 0(%edx),%ecx movl 4(%edx),%ebx movl 8(%edx),%esp movl 12(%edx),%ebp movl 16(%edx),%esi movl 20(%edx),%edi cmpl $0,%eax jne 1f movl $1,%eax1: movl %ecx,0(%esp) ret/**************************************************************************_VIRT_TO_PHYS - Transition from virtual to physical addresses**************************************************************************/ .globl _virt_to_phys_virt_to_phys: movl virt_offset, %ebp /* Load virt_offset */ addl %ebp, 0(%esp) /* Adjust the return address */ /* reload the code segment */ pushl $FLAT_CODE_SEG leal 1f(%ebp), %eax pushl %eax lret1: /* reload other segment registers */ movl $FLAT_DATA_SEG, %eax movl %eax, %ds movl %eax, %es movl %eax, %ss movl %eax, %fs movl %eax, %gs /* Adjust the stack pointer, after we have reloaded the stack segment */ addl %ebp, %esp ret/**************************************************************************_PHYS_TO_VIRT - Transition from using physical to virtual addresses**************************************************************************/ .globl _phys_to_virt_phys_to_virt: /* virt_offset is in %ebp */ subl %ebp, 0(%esp) /* Adjust the return address */ subl %ebp, %esp /* Adjust the stack pointer */ ljmp $KERN_CODE_SEG, $1f1: /* reload other segment regsters */ movl $KERN_DATA_SEG, %eax movl %eax, %ds movl %eax, %es movl %eax, %ss movl %eax, %fs movl %eax, %gs ret /**************************************************************************SET_SEG_BASE - Set the base address of a segment register**************************************************************************/ .globl set_seg_baseset_seg_base: /* Low half of the gdt base */ movl 4(%esp), %eax shll $16, %eax /* High half of the gdt base */ movl 4(%esp), %ecx shrl $16, %ecx andl $0xff, %ecx movl 4(%esp), %edx andl $0xff000000, %edx orl %edx, %ecx movl 8(%esp), %edx /* Fixup the code segment */ andl $0x0000ffff, 0(%edx) orl %eax , 0(%edx) andl $0x00ffff00, 4(%edx) orl %ecx , 4(%edx) /* Fixup the data segment */ andl $0x0000ffff, 8(%edx) orl %eax , 8(%edx) andl $0x00ffff00, 12(%edx) orl %ecx , 12(%edx) ret#ifdef CODE16/**************************************************************************_REAL_CALL - Run some code in real mode.**************************************************************************/ /* MAX_REAL_MODE_STACK is carefully tuned to work * with the stack bottom at 0x7c00 while not chancing * overwriting data below 0x500. */#define MAX_REAL_MODE_STACK 29696#define RADDR(sym) (((sym) - _end16) + MAX_REAL_MODE_STACK) .balign 4 .globl real_mode_stackreal_mode_stack: .long 0x7c00 /* Put the stack just below the dos load address */real_stack_top: .long 0_save_esp: .long 0 .globl _real_call_real_call: /* Save the original %esp value */ movl %esp, _save_esp /* Save the temporary registers I use */ pushl $0 pushl %ebx pushl %ecx pushl %edx pushl %esi pushl %edi pushl %ebp /* Load up the registers */ movl 32(%esp), %ecx /* The 16bit code len */ movl 36(%esp), %esi /* The 16bit code start */ movl virt_offset, %ebp /* The virtual offset */ /* stack top = phys_to_virt(real_mode_stack - MAX_REAL_MODE_STACK) */ movl real_mode_stack, %ebx /* The stack top */ subl $MAX_REAL_MODE_STACK, %ebx movl %ebx, real_stack_top subl %ebp, %ebx /* Save the real mode stack top */ movl %ebx, 24(%esp) /* Compute where the copied code goes */ leal RADDR(__real_call)(%ebx), %edi subl %ecx, %edi andl $0xfffffffc, %edi /* 4 byte aligned */ /* Remember where the code is executed */ movl %edi, %eax subl %ebx, %eax movw %ax, real_ip /* Copy the user code onto the real mode stack */ rep movsb /* Copy the trampoline onto the stack */ movl $__real_call, %esi movl $_end16 - __real_call, %ecx leal RADDR(__real_call)(%ebx), %edi rep movsb /* Fixup real_gdtarg */ leal _gdt(%ebp), %eax movl %eax, RADDR(real_gdtarg +2)(%ebx) /* Fixup the gdt */ pushl $_rmcs leal 0(%ebx, %ebp), %eax pushl %eax call set_seg_base addl $8, %esp /* Restore the saved registers */ popl %ebp popl %edi popl %esi popl %edx popl %ecx popl %ebx /* And switch stacks */ popl %esp movzwl RADDR(real_ip)(%esp), %eax addl %eax, %esp /* Setup for jump to real mode */ movl real_stack_top, %eax shrl $4, %eax pushw %ax pushw $RADDR(real16) /* Switch stack from %esp 32bit virtual to %sp 16bit physical */ addl virt_offset, %esp subl real_stack_top, %esp /* Jump to 16bit code */ ljmp $REAL_CODE_SEG, $RADDR(code16) /* jump to a 16 bit segment */_real_call_ret: /* reload segment registers */ movl $KERN_DATA_SEG,%eax movl %eax,%ds movl %eax,%es movl %eax,%ss movl %eax,%fs movl %eax,%gs /* Restore the stack */ movl _save_esp, %esp /* Restore the direction flag */ cld /* Get the real mode stack pointer */ movl real_stack_top, %eax subl virt_offset, %eax pushl %eax movzwl RADDR(real_sp)(%eax), %eax addl 0(%esp), %eax addl $4, %esp /* Return to my caller */ ret $8 .balign 16__real_call:real_sp: .word 0real_ip: .word 0real_gdtarg: .word _gdt_end - _gdt - 1 /* limit */ .long _gdt /* addr */ .code16code16: /* Load 16bit segment descriptors to force 16bit segment limit */ movw $REAL_DATA_SEG, %ax movw %ax,%ds movw %ax,%es movw %ax,%ss movw %ax,%fs movw %ax,%gs /* clear the PE bit of CR0 */ movl %cr0,%eax andb $0!CR0_PE,%al movl %eax,%cr0 /* make intersegment jmp to flush the processor pipeline * and reload %cs:%eip (to clear upper 16 bits of %eip). */ lretreal16: /* we are in real mode now * set up the real mode segment registers : %ds, $ss, %es */ movw %cs, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss movw %ax, %fs movw %ax, %gs /* Enable interrupts */ sti /* Call the user supplied code */ call *RADDR(real_ip) /* Disable interrupts */ cli /* Reload %ds */ movw %cs, %ax movw %ax, %ds /* Save the stack pointer */ movw %sp, RADDR(real_sp) /* Switch back to protected mode */ DATA32 lgdt RADDR(real_gdtarg) movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 /* turn on protected mode */ /* flush prefetch queue, and reload %cs:%eip */ DATA32 ljmp $KERN_CODE_SEG, $_real_call_ret .code32__end16: .balign 16_end16: .code32#endif /* CODE16 *//**************************************************************************GLOBAL DESCRIPTOR TABLE**************************************************************************/ .data .align 4_gdt:gdtarg: .word _gdt_end - _gdt - 1 /* limit */ .long _gdt /* addr */ .word 0_pmcs: /* 32 bit protected mode code segment */ .word 0xffff,0 .byte 0,0x9f,0xcf,0_pmds: /* 32 bit protected mode data segment */ .word 0xffff,0 .byte 0,0x93,0xcf,0_rmcs: /* 16 bit real mode code segment */ .word 0xffff,(0&0xffff) .byte (0>>16),0x9b,0x00,(0>>24)_rmds: /* 16 bit real mode data segment */ .word 0xffff,(0&0xffff) .byte (0>>16),0x93,0x00,(0>>24)_pmcs2: /* 32 bit protected mode code segment, base 0 */ .word 0xffff,0 .byte 0,0x9f,0xcf,0_pmds2: /* 32 bit protected mode data segment, base 0 */ .word 0xffff,0 .byte 0,0x93,0xcf,0#ifdef CONFIG_X86_64_lmcs: /* 64bit long mode code segment, base 0 */ .word 0xffff, 0 .byte 0x00, 0x9f, 0xaf , 0x00_lmds: /* 64bit long mode data segment, base 0 */ .word 0xffff, 0 .byte 0x00, 0x93, 0xcf, 0x00#endif_gdt_end: /* The initial register contents */ .balign 4 .globl initial_regsinitial_regs: .fill 8, 4, 0 /* The virtual address offset */ .globl virt_offsetvirt_offset: .long 0 .section ".stack" .p2align 3 /* allocate a 4K stack in the stack segment */_stack: .space 4096_estack:#ifdef CONFIG_X86_64 .section ".bss" .p2align 12 /* Include a dummy space in case we are loaded badly aligned */ .space 4096 /* Reserve enough space for a page table convering 4GB with 2MB pages */pgt_level4: .space 4096pgt_level3: .space 4096pgt_level2: .space 16384start_lm_addr: .space 8end_lm_addr: .space 8#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -