Back to home page

LXR

 
 

    


0001 /*
0002  *
0003  *  Trampoline.S    Derived from Setup.S by Linus Torvalds
0004  *
0005  *  4 Jan 1997 Michael Chastain: changed to gnu as.
0006  *  15 Sept 2005 Eric Biederman: 64bit PIC support
0007  *
0008  *  Entry: CS:IP point to the start of our code, we are
0009  *  in real mode with no stack, but the rest of the
0010  *  trampoline page to make our stack and everything else
0011  *  is a mystery.
0012  *
0013  *  On entry to trampoline_start, the processor is in real mode
0014  *  with 16-bit addressing and 16-bit data.  CS has some value
0015  *  and IP is zero.  Thus, data addresses need to be absolute
0016  *  (no relocation) and are taken with regard to r_base.
0017  *
0018  *  With the addition of trampoline_level4_pgt this code can
0019  *  now enter a 64bit kernel that lives at arbitrary 64bit
0020  *  physical addresses.
0021  *
0022  *  If you work on this file, check the object module with objdump
0023  *  --full-contents --reloc to make sure there are no relocation
0024  *  entries.
0025  */
0026 
0027 #include <linux/linkage.h>
0028 #include <asm/pgtable_types.h>
0029 #include <asm/page_types.h>
0030 #include <asm/msr.h>
0031 #include <asm/segment.h>
0032 #include <asm/processor-flags.h>
0033 #include "realmode.h"
0034 
0035     .text
0036     .code16
0037 
0038     .balign PAGE_SIZE
0039 ENTRY(trampoline_start)
0040     cli         # We should be safe anyway
0041     wbinvd
0042 
0043     LJMPW_RM(1f)
0044 1:
0045     mov %cs, %ax    # Code and data in the same place
0046     mov %ax, %ds
0047     mov %ax, %es
0048     mov %ax, %ss
0049 
0050     movl    $0xA5A5A5A5, trampoline_status
0051     # write marker for master knows we're running
0052 
0053     # Setup stack
0054     movl    $rm_stack_end, %esp
0055 
0056     call    verify_cpu      # Verify the cpu supports long mode
0057     testl   %eax, %eax      # Check for return code
0058     jnz no_longmode
0059 
0060     /*
0061      * GDT tables in non default location kernel can be beyond 16MB and
0062      * lgdt will not be able to load the address as in real mode default
0063      * operand size is 16bit. Use lgdtl instead to force operand size
0064      * to 32 bit.
0065      */
0066 
0067     lidtl   tr_idt  # load idt with 0, 0
0068     lgdtl   tr_gdt  # load gdt with whatever is appropriate
0069 
0070     movw    $__KERNEL_DS, %dx   # Data segment descriptor
0071 
0072     # Enable protected mode
0073     movl    $X86_CR0_PE, %eax   # protected mode (PE) bit
0074     movl    %eax, %cr0      # into protected mode
0075 
0076     # flush prefetch and jump to startup_32
0077     ljmpl   $__KERNEL32_CS, $pa_startup_32
0078 
0079 no_longmode:
0080     hlt
0081     jmp no_longmode
0082 #include "../kernel/verify_cpu.S"
0083 
0084     .section ".text32","ax"
0085     .code32
0086     .balign 4
0087 ENTRY(startup_32)
0088     movl    %edx, %ss
0089     addl    $pa_real_mode_base, %esp
0090     movl    %edx, %ds
0091     movl    %edx, %es
0092     movl    %edx, %fs
0093     movl    %edx, %gs
0094 
0095     movl    pa_tr_cr4, %eax
0096     movl    %eax, %cr4      # Enable PAE mode
0097 
0098     # Setup trampoline 4 level pagetables
0099     movl    $pa_trampoline_pgd, %eax
0100     movl    %eax, %cr3
0101 
0102     # Set up EFER
0103     movl    pa_tr_efer, %eax
0104     movl    pa_tr_efer + 4, %edx
0105     movl    $MSR_EFER, %ecx
0106     wrmsr
0107 
0108     # Enable paging and in turn activate Long Mode
0109     movl    $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax
0110     movl    %eax, %cr0
0111 
0112     /*
0113      * At this point we're in long mode but in 32bit compatibility mode
0114      * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
0115      * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
0116      * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
0117      */
0118     ljmpl   $__KERNEL_CS, $pa_startup_64
0119 
0120     .section ".text64","ax"
0121     .code64
0122     .balign 4
0123 ENTRY(startup_64)
0124     # Now jump into the kernel using virtual addresses
0125     jmpq    *tr_start(%rip)
0126 
0127     .section ".rodata","a"
0128     # Duplicate the global descriptor table
0129     # so the kernel can live anywhere
0130     .balign 16
0131     .globl tr_gdt
0132 tr_gdt:
0133     .short  tr_gdt_end - tr_gdt - 1 # gdt limit
0134     .long   pa_tr_gdt
0135     .short  0
0136     .quad   0x00cf9b000000ffff  # __KERNEL32_CS
0137     .quad   0x00af9b000000ffff  # __KERNEL_CS
0138     .quad   0x00cf93000000ffff  # __KERNEL_DS
0139 tr_gdt_end:
0140 
0141     .bss
0142     .balign PAGE_SIZE
0143 GLOBAL(trampoline_pgd)      .space  PAGE_SIZE
0144 
0145     .balign 8
0146 GLOBAL(trampoline_header)
0147     tr_start:       .space  8
0148     GLOBAL(tr_efer)     .space  8
0149     GLOBAL(tr_cr4)      .space  4
0150 END(trampoline_header)
0151 
0152 #include "trampoline_common.S"