1// Copyright 2017 The Fuchsia Authors 2// 3// Use of this source code is governed by a MIT-style 4// license that can be found in the LICENSE file or at 5// https://opensource.org/licenses/MIT 6 7#include <arch/defines.h> 8#include <arch/x86/asm.h> 9#include <arch/x86/descriptor.h> 10#include <arch/x86/mmu.h> 11#include <arch/x86/registers.h> 12#include <asm.h> 13#include <zircon/tls.h> 14#include <mexec.h> 15 16#define CODE_SEGMENT_SELECTOR (1 << 3) 17#define DATA_SEGMENT_SELECTOR (2 << 3) 18 19.text 20FUNCTION_LABEL(mexec_asm) 21 // Make sure interrupts are disabled. 22 cli 23 24 /* Stash all the arguments passed in registers R8 - R13 */ 25 mov %r9, %r13 /* Unused Arg */ 26 mov %r8, %r12 /* Memmove Ops */ 27 mov %rcx, %r11 /* Unused Arg */ 28 mov %rdx, %r10 /* ENTRY64_ADDR */ 29 mov %rsi, %r9 /* CR3 for Safe page tables */ 30 mov %rdi, %r8 /* Bootimage Address */ 31 32 // The old SP is in the old kernel virtual address space, so don't use it. 33 xor %esp, %esp 34 35 // Make sure old PGE mappings from the kernel address space are not 36 // still in the TLB. Having them there masked the previous bug wherein 37 // this code relied on using the incoming stack pointer. 38 mov %cr4, %rax 39 and $~X86_CR4_PGE, %rax 40 mov %rax, %cr4 41 42 // Switch to the safe identity mapped page tables. 43 mov %r9, %cr3 44 45 // Load our little GDT defined below. The current GDT is somewhere 46 // that might be overwritten when we copy in the new kernel below. 47 lea mexec_gdt(%rip), %rax 48 mov %rax, mexec_gdt_pointer(%rip) 49 lgdt mexec_gdt_descriptor(%rip) 50 51 // Switch to the new data segment. 52 mov $DATA_SEGMENT_SELECTOR, %ax 53 mov %ax, %ds 54 mov %ax, %es 55 mov %ax, %ss 56 57 // Switch to the new code segment. 58 // Note that ljmp accepts only a 32-bit address (aka "offset"). 59 // That's fine here, since we know we're running in the low 4G here. 60 leal .Lnew_cs(%rip), %eax 61 movl %eax, mexec_ljmp_descriptor(%rip) 62 ljmp *mexec_ljmp_descriptor(%rip) 63.Lnew_cs: 64 65 /* Load the kernel relocation op into ram */ 66 mov MEMMOV_OPS_DST_OFFSET (%r12), %rdi 67 mov MEMMOV_OPS_SRC_OFFSET (%r12), %rsi 68 mov MEMMOV_OPS_LEN_OFFSET (%r12), %rcx 69 70 /* Move RCX bytes from RSI to RDI */ 71 cld /* Clear the direction flag so that we're copying forward */ 72 /* by default when we start */ 73 74 cmp %rsi, %rdi /* Compare the src and dst registers to see if we need to */ 75 /* copy forwards or backwards */ 76 77 jbe .Ldo_copy /* if dst is greater than src, go ahead and do the copy */ 78 /* forwards */ 79 80 mov %rcx, %rax /* rcx and rax contain the number of bytes to be copied */ 81 sub $1, %rax /* Move rsi and rdi to the end of their respective buffers */ 82 add %rax, %rdi 83 add %rax, %rsi 84 85 std /* Set the direction flag to 1. This will ensure that the */ 86 /* copy happens from the back of the buffers to the front */ 87 88.Ldo_copy: 89 90 rep movsb /* copy RCX bytes from RSI to RDI */ 91 92 cld /* Clear the direction flag since we may have polluted it */ 93 /* if we did a copy backwards */ 94 95 /* Move the address of the bootdata into the appropriate register */ 96 mov %r8, %rsi 97 98 /* Zero out some registers */ 99 xor %ebx, %ebx 100 xor %edi, %edi 101 xor %ebp, %ebp 102 103 /* Grab 64bit entrypoint from provided location */ 104 mov (%r10), %rax 105 106 /* See you on the other side! */ 107 jmp *%rax 108 109 /* Crash, we should never reach here */ 110 ud2 111 112END_DATA(mexec_asm) 113 114.balign 8 115LOCAL_DATA(mexec_gdt) 116 // Null entry. 117 .int 0 118 .int 0 119 120 // 64-bit code segment. 121 .short 0xffff // limit 15:00 122 .short 0x0000 // base 15:00 123 .byte 0x00 // base 23:16 124 .byte 0b10011010 // P(1) DPL(00) S(1) 1 C(0) R(1) A(0) 125 .byte 0b10101111 // G(1) D(0) L(1) AVL(0) limit 19:16 126 .byte 0x0 // base 31:24 127 128 // Data segment. 129 .short 0xffff // limit 15:00 130 .short 0x0000 // base 15:00 131 .byte 0x00 // base 23:16 132 .byte 0b10010010 // P(1) DPL(00) S(1) 0 E(0) W(1) A(0) 133 .byte 0b11001111 // G(1) B(1) 0 0 limit 19:16 134 .byte 0x0 // base 31:24 135END_DATA(mexec_gdt) 136DATA(mexec_gdt_end) 137 138.balign 8 139LOCAL_DATA(mexec_gdt_descriptor) 140 .short mexec_gdt_end - mexec_gdt - 1 141LOCAL_DATA(mexec_gdt_pointer) 142 .quad 0 // Filled in at runtime. 143END_DATA(mexec_gdt_descriptor) 144 145.balign 8 146LOCAL_DATA(mexec_ljmp_descriptor) 147 .long 0 // Filled in at runtime. 148 .short CODE_SEGMENT_SELECTOR 149END_DATA(mexec_ljmp_descriptor) 150 151DATA(mexec_asm_end) 152