1/* 2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. 3 * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. 4 * Copyright 2012, Rene Gollent, rene@gollent.com. 5 * Distributed under the terms of the MIT License. 6 * 7 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 8 * Copyright 2002, Michael Noisternig. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 13#include <asm_defs.h> 14 15#include "asm_offsets.h" 16#include "syscall_numbers.h" 17 18 19.text 20 21 22/* void x86_fxsave(void* fpuState); */ 23FUNCTION(x86_fxsave): 24 fxsave (%rdi) 25 ret 26FUNCTION_END(x86_fxsave) 27 28 29/* void x86_fxrstor(const void* fpuState); */ 30FUNCTION(x86_fxrstor): 31 fxrstor (%rdi) 32 ret 33FUNCTION_END(x86_fxrstor) 34 35 36/* void x86_noop_swap(void *oldFpuState, const void *newFpuState); */ 37FUNCTION(x86_noop_swap): 38 nop 39 ret 40FUNCTION_END(x86_noop_swap) 41 42 43/* void x86_fxsave_swap(void* oldFpuState, const void* newFpuState); */ 44FUNCTION(x86_fxsave_swap): 45 fxsave (%rdi) 46 fxrstor (%rsi) 47 ret 48FUNCTION_END(x86_fxsave_swap) 49 50 51/* addr_t x86_get_stack_frame(); */ 52FUNCTION(x86_get_stack_frame): 53 mov %rbp, %rax 54 ret 55FUNCTION_END(x86_get_stack_frame) 56 57 58/* uint64 x86_read_msr(uint32 register); */ 59FUNCTION(x86_read_msr): 60 mov %edi, %ecx 61 rdmsr 62 shl $32, %rdx 63 mov %eax, %eax 64 or %rdx, %rax 65 ret 66FUNCTION_END(x86_read_msr) 67 68 69/* void x86_write_msr(uint32 register, uint64 value); */ 70FUNCTION(x86_write_msr): 71 mov %rsi, %rdx 72 mov %esi, %eax 73 mov %edi, %ecx 74 shr $32, %rdx 75 wrmsr 76 ret 77FUNCTION_END(x86_write_msr) 78 79 80/* void x86_64_thread_entry(); */ 81FUNCTION(x86_64_thread_entry): 82 movq %r15, %rdi 83 jmp *%r14 84FUNCTION_END(x86_64_thread_entry) 85 86 87/* void x86_context_switch(struct arch_thread* oldState, 88 struct arch_thread* newState); */ 89FUNCTION(x86_context_switch): 90 // Just need to save callee-save registers: RBP, RBX, R12-15. 91 push %r15 92 push %r14 93 push %r13 94 push %r12 95 push %rbp 96 push %rbx 97 98 // Swap the stack pointers. 99 movq %rsp, ARCH_THREAD_current_stack(%rdi) 100 movq ARCH_THREAD_current_stack(%rsi), %rsp 101 102 // Restore callee-save registers. 103 pop %rbx 104 pop %rbp 105 pop %r12 106 pop %r13 107 pop %r14 108 pop %r15 109 110 ret 111FUNCTION_END(x86_context_switch) 112 113 114/* void x86_swap_pgdir(uint64 newPageDir); */ 115FUNCTION(x86_swap_pgdir): 116 movq %rdi, %cr3 117 ret 118FUNCTION_END(x86_swap_pgdir) 119 120 121/* thread exit stub - copied to the userspace stack in arch_thread_enter_uspace() */ 122.align 8 123FUNCTION(x86_userspace_thread_exit): 124 movq %rax, %rdi 125 movq $SYSCALL_EXIT_THREAD, %rax 126 syscall 127.align 8 128FUNCTION_END(x86_userspace_thread_exit) 129SYMBOL(x86_end_userspace_thread_exit): 130 131 132null_idt_descr: 133 .word 0 134 .quad 0 135 136FUNCTION(x86_reboot): 137 lidt null_idt_descr 138 int $0 139done: 140 jmp done 141FUNCTION_END(x86_reboot) 142 143 144/* status_t arch_cpu_user_memcpy(void* to, const void* from, size_t size, 145 addr_t* faultHandler) */ 146FUNCTION(arch_cpu_user_memcpy): 147 // faultHandler -> r8, size -> rcx. 148 movq %rcx, %r8 149 movq %rdx, %rcx 150 151 // Set the fault handler, preserve old in rax. 152 movq (%r8), %rax 153 movq $.L_user_memcpy_error, (%r8) 154 155 // Move by quadwords. 156 cld 157 movq %rcx, %r9 158 shrq $3, %rcx 159 rep 160 movsq 161 162 // Move any remaining data by bytes. 163 movq %r9, %rcx 164 andq $7, %rcx 165 rep 166 movsb 167 168 // Restore the old fault handler and return. 169 movq %rax, (%r8) 170 xorl %eax, %eax 171 ret 172 173.L_user_memcpy_error: 174 // Restore the old fault handler. Return a generic error, the wrapper 175 // routine will deal with it. 176 movq %rax, (%r8) 177 movl $-1, %eax 178 ret 179FUNCTION_END(arch_cpu_user_memcpy) 180 181 182/* status_t arch_cpu_user_memset(void* to, char c, size_t count, 183 addr_t* faultHandler) */ 184FUNCTION(arch_cpu_user_memset): 185 // c -> al, faultHandler -> r8, size -> rcx. 186 movw %si, %ax 187 movq %rcx, %r8 188 movq %rdx, %rcx 189 190 // Set the fault handler, preserve old in rdx. 191 movq (%r8), %rdx 192 movq $.L_user_memset_error, (%r8) 193 194 rep 195 stosb 196 197 // Restore the old fault handler and return. 198 movq %rdx, (%r8) 199 xorl %eax, %eax 200 ret 201 202.L_user_memset_error: 203 // Restore the old fault handler. Return a generic error, the wrapper 204 // routine will deal with it. 205 movq %rdx, (%r8) 206 movl $-1, %eax 207 ret 208FUNCTION_END(arch_cpu_user_memset) 209 210 211/* ssize_t arch_cpu_user_strlcpy(void* to, const void* from, size_t size, 212 addr_t* faultHandler) */ 213FUNCTION(arch_cpu_user_strlcpy): 214 // faultHandler -> r8, size -> rcx, source -> r9 (original value needed to 215 // calculate return value). 216 movq %rcx, %r8 217 movq %rdx, %rcx 218 movq %rsi, %r9 219 220 // Set the fault handler, preserve old in rax. 221 movq (%r8), %rax 222 movq $.L_user_strlcpy_error, (%r8) 223 224 // Check for 0 length. 225 cmp $0, %rcx 226 je .L_user_strlcpy_source_count 227 228 // Copy at most count - 1 bytes. 229 dec %rcx 230 231 // If count is now 0, skip straight to null terminating as our loop will 232 // otherwise overflow. 233 jnz .L_user_strlcpy_copy_begin 234 movb $0, (%rdi) 235 jmp .L_user_strlcpy_source_count 236 237.L_user_strlcpy_copy_begin: 238 cld 239.L_user_strlcpy_copy_loop: 240 // Move data by bytes. 241 lodsb 242 stosb 243 test %al, %al 244 jz .L_user_strlcpy_source_done 245 loop .L_user_strlcpy_copy_loop 246 247 // Null terminate string. 248 movb $0, (%rdi) 249 dec %rsi 250 251.L_user_strlcpy_source_count: 252 // Count remaining bytes in src 253 not %rcx 254 xor %al, %al 255 repnz 256 scasb 257 258.L_user_strlcpy_source_done: 259 // Restore the old fault handler 260 movq %rax, (%r8) 261 262 // Calculate total string length and return. 263 movq %rsi, %rax 264 subq %r9, %rax 265 dec %rax 266 ret 267 268.L_user_strlcpy_error: 269 // Restore the old fault handler. Return a generic error, the wrapper 270 // routine will deal with it. 271 movq %rax, (%r8) 272 movq $-1, %rax 273 ret 274FUNCTION_END(arch_cpu_user_strlcpy) 275 276 277/*! \fn void arch_debug_call_with_fault_handler(cpu_ent* cpu, 278 jmp_buf jumpBuffer, void (*function)(void*), void* parameter) 279 280 Called by debug_call_with_fault_handler() to do the dirty work of setting 281 the fault handler and calling the function. If the function causes a page 282 fault, the arch_debug_call_with_fault_handler() calls longjmp() with the 283 given \a jumpBuffer. Otherwise it returns normally. 284 285 debug_call_with_fault_handler() has already saved the CPU's fault_handler 286 and fault_handler_stack_pointer and will reset them later, so 287 arch_debug_call_with_fault_handler() doesn't need to care about it. 288 289 \param cpu The \c cpu_ent for the current CPU. 290 \param jumpBuffer Buffer to be used for longjmp(). 291 \param function The function to be called. 292 \param parameter The parameter to be passed to the function to be called. 293*/ 294FUNCTION(arch_debug_call_with_fault_handler): 295 push %rbp 296 movq %rsp, %rbp 297 298 // Preserve the jump buffer address for the fault return. 299 push %rsi 300 301 // Set fault handler address, and fault handler stack pointer address. We 302 // don't need to save the previous values, since that's done by the caller. 303 movq $.L_debug_call_fault_handler, CPU_ENT_fault_handler(%rdi) 304 movq %rbp, CPU_ENT_fault_handler_stack_pointer(%rdi) 305 306 // Call the function. 307 movq %rcx, %rdi 308 call *%rdx 309 310 // Regular return. 311 movq %rbp, %rsp 312 pop %rbp 313 ret 314 315.L_debug_call_fault_handler: 316 // Fault -- return via longjmp(jumpBuffer, 1) 317 movq %rbp, %rsp 318 movq -8(%rsp), %rdi 319 movq $1, %rsi 320 call longjmp 321FUNCTION_END(arch_debug_call_with_fault_handler) 322