switcher.S 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /* This code sits at 0xFFC00000 to do the low-level guest<->host switch.
  2. There is are two pages above us for this CPU (struct lguest_pages).
  3. The second page (struct lguest_ro_state) becomes read-only after the
  4. context switch. The first page (the stack for traps) remains writable,
  5. but while we're in here, the guest cannot be running.
  6. */
  7. #include <linux/linkage.h>
  8. #include <asm/asm-offsets.h>
  9. #include "lg.h"
  10. .text
  11. ENTRY(start_switcher_text)
  12. /* %eax points to lguest pages for this CPU. %ebx contains cr3 value.
  13. All normal registers can be clobbered! */
  14. ENTRY(switch_to_guest)
  15. /* Save host segments on host stack. */
  16. pushl %es
  17. pushl %ds
  18. pushl %gs
  19. pushl %fs
  20. /* With CONFIG_FRAME_POINTER, gcc doesn't let us clobber this! */
  21. pushl %ebp
  22. /* Save host stack. */
  23. movl %esp, LGUEST_PAGES_host_sp(%eax)
  24. /* Switch to guest stack: if we get NMI we expect to be there. */
  25. movl %eax, %edx
  26. addl $LGUEST_PAGES_regs, %edx
  27. movl %edx, %esp
  28. /* Switch to guest's GDT, IDT. */
  29. lgdt LGUEST_PAGES_guest_gdt_desc(%eax)
  30. lidt LGUEST_PAGES_guest_idt_desc(%eax)
  31. /* Switch to guest's TSS while GDT still writable. */
  32. movl $(GDT_ENTRY_TSS*8), %edx
  33. ltr %dx
  34. /* Set host's TSS GDT entry to available (clear byte 5 bit 2). */
  35. movl (LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx
  36. andb $0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx)
  37. /* Switch to guest page tables: lguest_pages->state now read-only. */
  38. movl %ebx, %cr3
  39. /* Restore guest regs */
  40. popl %ebx
  41. popl %ecx
  42. popl %edx
  43. popl %esi
  44. popl %edi
  45. popl %ebp
  46. popl %gs
  47. popl %eax
  48. popl %fs
  49. popl %ds
  50. popl %es
  51. /* Skip error code and trap number */
  52. addl $8, %esp
  53. iret
  54. #define SWITCH_TO_HOST \
  55. /* Save guest state */ \
  56. pushl %es; \
  57. pushl %ds; \
  58. pushl %fs; \
  59. pushl %eax; \
  60. pushl %gs; \
  61. pushl %ebp; \
  62. pushl %edi; \
  63. pushl %esi; \
  64. pushl %edx; \
  65. pushl %ecx; \
  66. pushl %ebx; \
  67. /* Load lguest ds segment for convenience. */ \
  68. movl $(LGUEST_DS), %eax; \
  69. movl %eax, %ds; \
  70. /* Figure out where we are, based on stack (at top of regs). */ \
  71. movl %esp, %eax; \
  72. subl $LGUEST_PAGES_regs, %eax; \
  73. /* Put trap number in %ebx before we switch cr3 and lose it. */ \
  74. movl LGUEST_PAGES_regs_trapnum(%eax), %ebx; \
  75. /* Switch to host page tables (host GDT, IDT and stack are in host \
  76. mem, so need this first) */ \
  77. movl LGUEST_PAGES_host_cr3(%eax), %edx; \
  78. movl %edx, %cr3; \
  79. /* Set guest's TSS to available (clear byte 5 bit 2). */ \
  80. andb $0xFD, (LGUEST_PAGES_guest_gdt+GDT_ENTRY_TSS*8+5)(%eax); \
  81. /* Switch to host's GDT & IDT. */ \
  82. lgdt LGUEST_PAGES_host_gdt_desc(%eax); \
  83. lidt LGUEST_PAGES_host_idt_desc(%eax); \
  84. /* Switch to host's stack. */ \
  85. movl LGUEST_PAGES_host_sp(%eax), %esp; \
  86. /* Switch to host's TSS */ \
  87. movl $(GDT_ENTRY_TSS*8), %edx; \
  88. ltr %dx; \
  89. popl %ebp; \
  90. popl %fs; \
  91. popl %gs; \
  92. popl %ds; \
  93. popl %es
  94. /* Return to run_guest_once. */
  95. return_to_host:
  96. SWITCH_TO_HOST
  97. iret
  98. deliver_to_host:
  99. SWITCH_TO_HOST
  100. /* Decode IDT and jump to hosts' irq handler. When that does iret, it
  101. * will return to run_guest_once. This is a feature. */
  102. movl (LGUEST_PAGES_host_idt_desc+2)(%eax), %edx
  103. leal (%edx,%ebx,8), %eax
  104. movzwl (%eax),%edx
  105. movl 4(%eax), %eax
  106. xorw %ax, %ax
  107. orl %eax, %edx
  108. jmp *%edx
  109. /* Real hardware interrupts are delivered straight to the host. Others
  110. cause us to return to run_guest_once so it can decide what to do. Note
  111. that some of these are overridden by the guest to deliver directly, and
  112. never enter here (see load_guest_idt_entry). */
  113. .macro IRQ_STUB N TARGET
  114. .data; .long 1f; .text; 1:
  115. /* Make an error number for most traps, which don't have one. */
  116. .if (\N <> 8) && (\N < 10 || \N > 14) && (\N <> 17)
  117. pushl $0
  118. .endif
  119. pushl $\N
  120. jmp \TARGET
  121. ALIGN
  122. .endm
  123. .macro IRQ_STUBS FIRST LAST TARGET
  124. irq=\FIRST
  125. .rept \LAST-\FIRST+1
  126. IRQ_STUB irq \TARGET
  127. irq=irq+1
  128. .endr
  129. .endm
  130. /* We intercept every interrupt, because we may need to switch back to
  131. * host. Unfortunately we can't tell them apart except by entry
  132. * point, so we need 256 entry points.
  133. */
  134. .data
  135. .global default_idt_entries
  136. default_idt_entries:
  137. .text
  138. IRQ_STUBS 0 1 return_to_host /* First two traps */
  139. IRQ_STUB 2 handle_nmi /* NMI */
  140. IRQ_STUBS 3 31 return_to_host /* Rest of traps */
  141. IRQ_STUBS 32 127 deliver_to_host /* Real interrupts */
  142. IRQ_STUB 128 return_to_host /* System call (overridden) */
  143. IRQ_STUBS 129 255 deliver_to_host /* Other real interrupts */
  144. /* We ignore NMI and return. */
  145. handle_nmi:
  146. addl $8, %esp
  147. iret
  148. ENTRY(end_switcher_text)