18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <stddef.h> 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <errno.h> 98c2ecf20Sopenharmony_ci#include <string.h> 108c2ecf20Sopenharmony_ci#include <sys/mman.h> 118c2ecf20Sopenharmony_ci#include <init.h> 128c2ecf20Sopenharmony_ci#include <as-layout.h> 138c2ecf20Sopenharmony_ci#include <mm_id.h> 148c2ecf20Sopenharmony_ci#include <os.h> 158c2ecf20Sopenharmony_ci#include <ptrace_user.h> 168c2ecf20Sopenharmony_ci#include <registers.h> 178c2ecf20Sopenharmony_ci#include <skas.h> 188c2ecf20Sopenharmony_ci#include <sysdep/ptrace.h> 198c2ecf20Sopenharmony_ci#include <sysdep/stub.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciextern char batch_syscall_stub[], __syscall_stub_start[]; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciextern void wait_stub_done(int pid); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic inline unsigned long *check_init_stack(struct mm_id * mm_idp, 268c2ecf20Sopenharmony_ci unsigned long *stack) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci if (stack == NULL) { 298c2ecf20Sopenharmony_ci stack = (unsigned long *) mm_idp->stack + 2; 308c2ecf20Sopenharmony_ci *stack = 0; 318c2ecf20Sopenharmony_ci } 328c2ecf20Sopenharmony_ci return stack; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic unsigned long syscall_regs[MAX_REG_NR]; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int __init init_syscall_regs(void) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci get_safe_registers(syscall_regs, NULL); 408c2ecf20Sopenharmony_ci syscall_regs[REGS_IP_INDEX] = STUB_CODE + 418c2ecf20Sopenharmony_ci ((unsigned long) batch_syscall_stub - 428c2ecf20Sopenharmony_ci (unsigned long) __syscall_stub_start); 438c2ecf20Sopenharmony_ci return 0; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci__initcall(init_syscall_regs); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci int n, i; 518c2ecf20Sopenharmony_ci long ret, offset; 528c2ecf20Sopenharmony_ci unsigned long * data; 538c2ecf20Sopenharmony_ci unsigned long * syscall; 548c2ecf20Sopenharmony_ci int err, pid = mm_idp->u.pid; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci n = ptrace_setregs(pid, syscall_regs); 578c2ecf20Sopenharmony_ci if (n < 0) { 588c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "Registers - \n"); 598c2ecf20Sopenharmony_ci for (i = 0; i < MAX_REG_NR; i++) 608c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "\t%d\t0x%lx\n", i, syscall_regs[i]); 618c2ecf20Sopenharmony_ci panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", 628c2ecf20Sopenharmony_ci -n); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci err = ptrace(PTRACE_CONT, pid, 0, 0); 668c2ecf20Sopenharmony_ci if (err) 678c2ecf20Sopenharmony_ci panic("Failed to continue stub, pid = %d, errno = %d\n", pid, 688c2ecf20Sopenharmony_ci errno); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci wait_stub_done(pid); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* 738c2ecf20Sopenharmony_ci * When the stub stops, we find the following values on the 748c2ecf20Sopenharmony_ci * beginning of the stack: 758c2ecf20Sopenharmony_ci * (long )return_value 768c2ecf20Sopenharmony_ci * (long )offset to failed sycall-data (0, if no error) 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci ret = *((unsigned long *) mm_idp->stack); 798c2ecf20Sopenharmony_ci offset = *((unsigned long *) mm_idp->stack + 1); 808c2ecf20Sopenharmony_ci if (offset) { 818c2ecf20Sopenharmony_ci data = (unsigned long *)(mm_idp->stack + offset - STUB_DATA); 828c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "do_syscall_stub : ret = %ld, offset = %ld, " 838c2ecf20Sopenharmony_ci "data = %p\n", ret, offset, data); 848c2ecf20Sopenharmony_ci syscall = (unsigned long *)((unsigned long)data + data[0]); 858c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "do_syscall_stub: syscall %ld failed, " 868c2ecf20Sopenharmony_ci "return value = 0x%lx, expected return value = 0x%lx\n", 878c2ecf20Sopenharmony_ci syscall[0], ret, syscall[7]); 888c2ecf20Sopenharmony_ci printk(UM_KERN_ERR " syscall parameters: " 898c2ecf20Sopenharmony_ci "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 908c2ecf20Sopenharmony_ci syscall[1], syscall[2], syscall[3], 918c2ecf20Sopenharmony_ci syscall[4], syscall[5], syscall[6]); 928c2ecf20Sopenharmony_ci for (n = 1; n < data[0]/sizeof(long); n++) { 938c2ecf20Sopenharmony_ci if (n == 1) 948c2ecf20Sopenharmony_ci printk(UM_KERN_ERR " additional syscall " 958c2ecf20Sopenharmony_ci "data:"); 968c2ecf20Sopenharmony_ci if (n % 4 == 1) 978c2ecf20Sopenharmony_ci printk("\n" UM_KERN_ERR " "); 988c2ecf20Sopenharmony_ci printk(" 0x%lx", data[n]); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci if (n > 1) 1018c2ecf20Sopenharmony_ci printk("\n"); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci else ret = 0; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci *addr = check_init_stack(mm_idp, NULL); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cilong run_syscall_stub(struct mm_id * mm_idp, int syscall, 1118c2ecf20Sopenharmony_ci unsigned long *args, long expected, void **addr, 1128c2ecf20Sopenharmony_ci int done) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci unsigned long *stack = check_init_stack(mm_idp, *addr); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci *stack += sizeof(long); 1178c2ecf20Sopenharmony_ci stack += *stack / sizeof(long); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci *stack++ = syscall; 1208c2ecf20Sopenharmony_ci *stack++ = args[0]; 1218c2ecf20Sopenharmony_ci *stack++ = args[1]; 1228c2ecf20Sopenharmony_ci *stack++ = args[2]; 1238c2ecf20Sopenharmony_ci *stack++ = args[3]; 1248c2ecf20Sopenharmony_ci *stack++ = args[4]; 1258c2ecf20Sopenharmony_ci *stack++ = args[5]; 1268c2ecf20Sopenharmony_ci *stack++ = expected; 1278c2ecf20Sopenharmony_ci *stack = 0; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) < 1308c2ecf20Sopenharmony_ci UM_KERN_PAGE_SIZE - 10 * sizeof(long))) { 1318c2ecf20Sopenharmony_ci *addr = stack; 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return do_syscall_stub(mm_idp, addr); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cilong syscall_stub_data(struct mm_id * mm_idp, 1398c2ecf20Sopenharmony_ci unsigned long *data, int data_count, 1408c2ecf20Sopenharmony_ci void **addr, void **stub_addr) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci unsigned long *stack; 1438c2ecf20Sopenharmony_ci int ret = 0; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * If *addr still is uninitialized, it *must* contain NULL. 1478c2ecf20Sopenharmony_ci * Thus in this case do_syscall_stub correctly won't be called. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci if ((((unsigned long) *addr) & ~UM_KERN_PAGE_MASK) >= 1508c2ecf20Sopenharmony_ci UM_KERN_PAGE_SIZE - (10 + data_count) * sizeof(long)) { 1518c2ecf20Sopenharmony_ci ret = do_syscall_stub(mm_idp, addr); 1528c2ecf20Sopenharmony_ci /* in case of error, don't overwrite data on stack */ 1538c2ecf20Sopenharmony_ci if (ret) 1548c2ecf20Sopenharmony_ci return ret; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci stack = check_init_stack(mm_idp, *addr); 1588c2ecf20Sopenharmony_ci *addr = stack; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci *stack = data_count * sizeof(long); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci memcpy(stack + 1, data, data_count * sizeof(long)); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci *stub_addr = (void *)(((unsigned long)(stack + 1) & 1658c2ecf20Sopenharmony_ci ~UM_KERN_PAGE_MASK) + STUB_DATA); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot, 1718c2ecf20Sopenharmony_ci int phys_fd, unsigned long long offset, int done, void **data) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci int ret; 1748c2ecf20Sopenharmony_ci unsigned long args[] = { virt, len, prot, 1758c2ecf20Sopenharmony_ci MAP_SHARED | MAP_FIXED, phys_fd, 1768c2ecf20Sopenharmony_ci MMAP_OFFSET(offset) }; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, 1798c2ecf20Sopenharmony_ci data, done); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciint unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 1858c2ecf20Sopenharmony_ci int done, void **data) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci int ret; 1888c2ecf20Sopenharmony_ci unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, 1898c2ecf20Sopenharmony_ci 0 }; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, 1928c2ecf20Sopenharmony_ci data, done); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ciint protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 1988c2ecf20Sopenharmony_ci unsigned int prot, int done, void **data) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci int ret; 2018c2ecf20Sopenharmony_ci unsigned long args[] = { addr, len, prot, 0, 0, 0 }; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, 2048c2ecf20Sopenharmony_ci data, done); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return ret; 2078c2ecf20Sopenharmony_ci} 208