call64.S 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /* SPDX-License-Identifier: GPL-2.0+ */
  2. /*
  3. * (C) Copyright 2014 Google, Inc
  4. * Copyright (C) 1991, 1992, 1993 Linus Torvalds
  5. *
  6. * Parts of this copied from Linux arch/x86/boot/compressed/head_64.S
  7. */
  8. #include <asm/global_data.h>
  9. #include <asm/msr-index.h>
  10. #include <asm/processor-flags.h>
  11. .code32
  12. .globl cpu_call64
  13. cpu_call64:
  14. /*
  15. * cpu_call64(ulong pgtable, ulong setup_base, ulong target)
  16. *
  17. * eax - pgtable
  18. * edx - setup_base
  19. * ecx - target
  20. */
  21. cli
  22. push %ecx /* arg2 = target */
  23. push %edx /* arg1 = setup_base */
  24. mov %eax, %ebx
  25. /* Load new GDT with the 64bit segments using 32bit descriptor */
  26. leal gdt, %eax
  27. movl %eax, gdt+2
  28. lgdt gdt
  29. /* Enable PAE mode */
  30. movl $(X86_CR4_PAE), %eax
  31. movl %eax, %cr4
  32. /* Enable the boot page tables */
  33. leal (%ebx), %eax
  34. movl %eax, %cr3
  35. /* Enable Long mode in EFER (Extended Feature Enable Register) */
  36. movl $MSR_EFER, %ecx
  37. rdmsr
  38. btsl $_EFER_LME, %eax
  39. wrmsr
  40. /* After gdt is loaded */
  41. xorl %eax, %eax
  42. lldt %ax
  43. movl $0x20, %eax
  44. ltr %ax
  45. /*
  46. * Setup for the jump to 64bit mode
  47. *
  48. * When the jump is performed we will be in long mode but
  49. * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
  50. * (and in turn EFER.LMA = 1). To jump into 64bit mode we use
  51. * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
  52. * We place all of the values on our mini stack so lret can
  53. * used to perform that far jump. See the gdt below.
  54. */
  55. pop %esi /* setup_base */
  56. pushl $0x10
  57. leal lret_target, %eax
  58. pushl %eax
  59. /* Enter paged protected Mode, activating Long Mode */
  60. movl $(X86_CR0_PG | X86_CR0_PE), %eax
  61. movl %eax, %cr0
  62. /* Jump from 32bit compatibility mode into 64bit mode. */
  63. lret
  64. code64:
  65. lret_target:
  66. pop %eax /* target */
  67. mov %eax, %eax /* Clear bits 63:32 */
  68. jmp *%eax /* Jump to the 64-bit target */
  69. .data
  70. .align 16
  71. .globl gdt64
  72. gdt64:
  73. gdt:
  74. .word gdt_end - gdt - 1
  75. .long gdt /* Fixed up by code above */
  76. .word 0
  77. .quad 0x0000000000000000 /* NULL descriptor */
  78. .quad 0x00af9a000000ffff /* __KERNEL_CS */
  79. .quad 0x00cf92000000ffff /* __KERNEL_DS */
  80. .quad 0x0080890000000000 /* TS descriptor */
  81. .quad 0x0000000000000000 /* TS continued */
  82. gdt_end: