18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <stdio.h> 78c2ecf20Sopenharmony_ci#include <stdlib.h> 88c2ecf20Sopenharmony_ci#include <stdarg.h> 98c2ecf20Sopenharmony_ci#include <unistd.h> 108c2ecf20Sopenharmony_ci#include <errno.h> 118c2ecf20Sopenharmony_ci#include <fcntl.h> 128c2ecf20Sopenharmony_ci#include <sched.h> 138c2ecf20Sopenharmony_ci#include <signal.h> 148c2ecf20Sopenharmony_ci#include <string.h> 158c2ecf20Sopenharmony_ci#include <sys/mman.h> 168c2ecf20Sopenharmony_ci#include <sys/stat.h> 178c2ecf20Sopenharmony_ci#include <sys/wait.h> 188c2ecf20Sopenharmony_ci#include <sys/time.h> 198c2ecf20Sopenharmony_ci#include <sys/resource.h> 208c2ecf20Sopenharmony_ci#include <asm/unistd.h> 218c2ecf20Sopenharmony_ci#include <init.h> 228c2ecf20Sopenharmony_ci#include <os.h> 238c2ecf20Sopenharmony_ci#include <mem_user.h> 248c2ecf20Sopenharmony_ci#include <ptrace_user.h> 258c2ecf20Sopenharmony_ci#include <registers.h> 268c2ecf20Sopenharmony_ci#include <skas.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void ptrace_child(void) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci int ret; 318c2ecf20Sopenharmony_ci /* Calling os_getpid because some libcs cached getpid incorrectly */ 328c2ecf20Sopenharmony_ci int pid = os_getpid(), ppid = getppid(); 338c2ecf20Sopenharmony_ci int sc_result; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (change_sig(SIGWINCH, 0) < 0 || 368c2ecf20Sopenharmony_ci ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { 378c2ecf20Sopenharmony_ci perror("ptrace"); 388c2ecf20Sopenharmony_ci kill(pid, SIGKILL); 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci kill(pid, SIGSTOP); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* 438c2ecf20Sopenharmony_ci * This syscall will be intercepted by the parent. Don't call more than 448c2ecf20Sopenharmony_ci * once, please. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci sc_result = os_getpid(); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (sc_result == pid) 498c2ecf20Sopenharmony_ci /* Nothing modified by the parent, we are running normally. */ 508c2ecf20Sopenharmony_ci ret = 1; 518c2ecf20Sopenharmony_ci else if (sc_result == ppid) 528c2ecf20Sopenharmony_ci /* 538c2ecf20Sopenharmony_ci * Expected in check_ptrace and check_sysemu when they succeed 548c2ecf20Sopenharmony_ci * in modifying the stack frame 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci ret = 0; 578c2ecf20Sopenharmony_ci else 588c2ecf20Sopenharmony_ci /* Serious trouble! This could be caused by a bug in host 2.6 598c2ecf20Sopenharmony_ci * SKAS3/2.6 patch before release -V6, together with a bug in 608c2ecf20Sopenharmony_ci * the UML code itself. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci ret = 2; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci exit(ret); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void fatal_perror(const char *str) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci perror(str); 708c2ecf20Sopenharmony_ci exit(1); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void fatal(char *fmt, ...) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci va_list list; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci va_start(list, fmt); 788c2ecf20Sopenharmony_ci vfprintf(stderr, fmt, list); 798c2ecf20Sopenharmony_ci va_end(list); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci exit(1); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void non_fatal(char *fmt, ...) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci va_list list; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci va_start(list, fmt); 898c2ecf20Sopenharmony_ci vfprintf(stderr, fmt, list); 908c2ecf20Sopenharmony_ci va_end(list); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int start_ptraced_child(void) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci int pid, n, status; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci fflush(stdout); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci pid = fork(); 1008c2ecf20Sopenharmony_ci if (pid == 0) 1018c2ecf20Sopenharmony_ci ptrace_child(); 1028c2ecf20Sopenharmony_ci else if (pid < 0) 1038c2ecf20Sopenharmony_ci fatal_perror("start_ptraced_child : fork failed"); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 1068c2ecf20Sopenharmony_ci if (n < 0) 1078c2ecf20Sopenharmony_ci fatal_perror("check_ptrace : waitpid failed"); 1088c2ecf20Sopenharmony_ci if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) 1098c2ecf20Sopenharmony_ci fatal("check_ptrace : expected SIGSTOP, got status = %d", 1108c2ecf20Sopenharmony_ci status); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return pid; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* When testing for SYSEMU support, if it is one of the broken versions, we 1168c2ecf20Sopenharmony_ci * must just avoid using sysemu, not panic, but only if SYSEMU features are 1178c2ecf20Sopenharmony_ci * broken. 1188c2ecf20Sopenharmony_ci * So only for SYSEMU features we test mustpanic, while normal host features 1198c2ecf20Sopenharmony_ci * must work anyway! 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_cistatic int stop_ptraced_child(int pid, int exitcode, int mustexit) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int status, n, ret = 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { 1268c2ecf20Sopenharmony_ci perror("stop_ptraced_child : ptrace failed"); 1278c2ecf20Sopenharmony_ci return -1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, 0)); 1308c2ecf20Sopenharmony_ci if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { 1318c2ecf20Sopenharmony_ci int exit_with = WEXITSTATUS(status); 1328c2ecf20Sopenharmony_ci if (exit_with == 2) 1338c2ecf20Sopenharmony_ci non_fatal("check_ptrace : child exited with status 2. " 1348c2ecf20Sopenharmony_ci "\nDisabling SYSEMU support.\n"); 1358c2ecf20Sopenharmony_ci non_fatal("check_ptrace : child exited with exitcode %d, while " 1368c2ecf20Sopenharmony_ci "expecting %d; status 0x%x\n", exit_with, 1378c2ecf20Sopenharmony_ci exitcode, status); 1388c2ecf20Sopenharmony_ci if (mustexit) 1398c2ecf20Sopenharmony_ci exit(1); 1408c2ecf20Sopenharmony_ci ret = -1; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return ret; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* Changed only during early boot */ 1478c2ecf20Sopenharmony_cistatic int force_sysemu_disabled = 0; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int __init nosysemu_cmd_param(char *str, int* add) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci force_sysemu_disabled = 1; 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci__uml_setup("nosysemu", nosysemu_cmd_param, 1568c2ecf20Sopenharmony_ci"nosysemu\n" 1578c2ecf20Sopenharmony_ci" Turns off syscall emulation patch for ptrace (SYSEMU).\n" 1588c2ecf20Sopenharmony_ci" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" 1598c2ecf20Sopenharmony_ci" behaviour of ptrace() and helps reduce host context switch rates.\n" 1608c2ecf20Sopenharmony_ci" To make it work, you need a kernel patch for your host, too.\n" 1618c2ecf20Sopenharmony_ci" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n" 1628c2ecf20Sopenharmony_ci" information.\n\n"); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void __init check_sysemu(void) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci unsigned long regs[MAX_REG_NR]; 1678c2ecf20Sopenharmony_ci int pid, n, status, count=0; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci os_info("Checking syscall emulation patch for ptrace..."); 1708c2ecf20Sopenharmony_ci sysemu_supported = 0; 1718c2ecf20Sopenharmony_ci pid = start_ptraced_child(); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) 1748c2ecf20Sopenharmony_ci goto fail; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 1778c2ecf20Sopenharmony_ci if (n < 0) 1788c2ecf20Sopenharmony_ci fatal_perror("check_sysemu : wait failed"); 1798c2ecf20Sopenharmony_ci if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) 1808c2ecf20Sopenharmony_ci fatal("check_sysemu : expected SIGTRAP, got status = %d\n", 1818c2ecf20Sopenharmony_ci status); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) 1848c2ecf20Sopenharmony_ci fatal_perror("check_sysemu : PTRACE_GETREGS failed"); 1858c2ecf20Sopenharmony_ci if (PT_SYSCALL_NR(regs) != __NR_getpid) { 1868c2ecf20Sopenharmony_ci non_fatal("check_sysemu got system call number %d, " 1878c2ecf20Sopenharmony_ci "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid); 1888c2ecf20Sopenharmony_ci goto fail; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); 1928c2ecf20Sopenharmony_ci if (n < 0) { 1938c2ecf20Sopenharmony_ci non_fatal("check_sysemu : failed to modify system call " 1948c2ecf20Sopenharmony_ci "return"); 1958c2ecf20Sopenharmony_ci goto fail; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (stop_ptraced_child(pid, 0, 0) < 0) 1998c2ecf20Sopenharmony_ci goto fail_stopped; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci sysemu_supported = 1; 2028c2ecf20Sopenharmony_ci os_info("OK\n"); 2038c2ecf20Sopenharmony_ci set_using_sysemu(!force_sysemu_disabled); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci os_info("Checking advanced syscall emulation patch for ptrace..."); 2068c2ecf20Sopenharmony_ci pid = start_ptraced_child(); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, 2098c2ecf20Sopenharmony_ci (void *) PTRACE_O_TRACESYSGOOD) < 0)) 2108c2ecf20Sopenharmony_ci fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci while (1) { 2138c2ecf20Sopenharmony_ci count++; 2148c2ecf20Sopenharmony_ci if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) 2158c2ecf20Sopenharmony_ci goto fail; 2168c2ecf20Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 2178c2ecf20Sopenharmony_ci if (n < 0) 2188c2ecf20Sopenharmony_ci fatal_perror("check_sysemu: wait failed"); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (WIFSTOPPED(status) && 2218c2ecf20Sopenharmony_ci (WSTOPSIG(status) == (SIGTRAP|0x80))) { 2228c2ecf20Sopenharmony_ci if (!count) { 2238c2ecf20Sopenharmony_ci non_fatal("check_sysemu: SYSEMU_SINGLESTEP " 2248c2ecf20Sopenharmony_ci "doesn't singlestep"); 2258c2ecf20Sopenharmony_ci goto fail; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, 2288c2ecf20Sopenharmony_ci os_getpid()); 2298c2ecf20Sopenharmony_ci if (n < 0) 2308c2ecf20Sopenharmony_ci fatal_perror("check_sysemu : failed to modify " 2318c2ecf20Sopenharmony_ci "system call return"); 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) 2358c2ecf20Sopenharmony_ci count++; 2368c2ecf20Sopenharmony_ci else { 2378c2ecf20Sopenharmony_ci non_fatal("check_sysemu: expected SIGTRAP or " 2388c2ecf20Sopenharmony_ci "(SIGTRAP | 0x80), got status = %d\n", 2398c2ecf20Sopenharmony_ci status); 2408c2ecf20Sopenharmony_ci goto fail; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci if (stop_ptraced_child(pid, 0, 0) < 0) 2448c2ecf20Sopenharmony_ci goto fail_stopped; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci sysemu_supported = 2; 2478c2ecf20Sopenharmony_ci os_info("OK\n"); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (!force_sysemu_disabled) 2508c2ecf20Sopenharmony_ci set_using_sysemu(sysemu_supported); 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cifail: 2548c2ecf20Sopenharmony_ci stop_ptraced_child(pid, 1, 0); 2558c2ecf20Sopenharmony_cifail_stopped: 2568c2ecf20Sopenharmony_ci non_fatal("missing\n"); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void __init check_ptrace(void) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci int pid, syscall, n, status; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci os_info("Checking that ptrace can change system call numbers..."); 2648c2ecf20Sopenharmony_ci pid = start_ptraced_child(); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, 2678c2ecf20Sopenharmony_ci (void *) PTRACE_O_TRACESYSGOOD) < 0)) 2688c2ecf20Sopenharmony_ci fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci while (1) { 2718c2ecf20Sopenharmony_ci if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) 2728c2ecf20Sopenharmony_ci fatal_perror("check_ptrace : ptrace failed"); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 2758c2ecf20Sopenharmony_ci if (n < 0) 2768c2ecf20Sopenharmony_ci fatal_perror("check_ptrace : wait failed"); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!WIFSTOPPED(status) || 2798c2ecf20Sopenharmony_ci (WSTOPSIG(status) != (SIGTRAP | 0x80))) 2808c2ecf20Sopenharmony_ci fatal("check_ptrace : expected (SIGTRAP|0x80), " 2818c2ecf20Sopenharmony_ci "got status = %d", status); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 2848c2ecf20Sopenharmony_ci 0); 2858c2ecf20Sopenharmony_ci if (syscall == __NR_getpid) { 2868c2ecf20Sopenharmony_ci n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 2878c2ecf20Sopenharmony_ci __NR_getppid); 2888c2ecf20Sopenharmony_ci if (n < 0) 2898c2ecf20Sopenharmony_ci fatal_perror("check_ptrace : failed to modify " 2908c2ecf20Sopenharmony_ci "system call"); 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci stop_ptraced_child(pid, 0, 1); 2958c2ecf20Sopenharmony_ci os_info("OK\n"); 2968c2ecf20Sopenharmony_ci check_sysemu(); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ciextern void check_tmpexec(void); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void __init check_coredump_limit(void) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct rlimit lim; 3048c2ecf20Sopenharmony_ci int err = getrlimit(RLIMIT_CORE, &lim); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (err) { 3078c2ecf20Sopenharmony_ci perror("Getting core dump limit"); 3088c2ecf20Sopenharmony_ci return; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci os_info("Core dump limits :\n\tsoft - "); 3128c2ecf20Sopenharmony_ci if (lim.rlim_cur == RLIM_INFINITY) 3138c2ecf20Sopenharmony_ci os_info("NONE\n"); 3148c2ecf20Sopenharmony_ci else 3158c2ecf20Sopenharmony_ci os_info("%llu\n", (unsigned long long)lim.rlim_cur); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci os_info("\thard - "); 3188c2ecf20Sopenharmony_ci if (lim.rlim_max == RLIM_INFINITY) 3198c2ecf20Sopenharmony_ci os_info("NONE\n"); 3208c2ecf20Sopenharmony_ci else 3218c2ecf20Sopenharmony_ci os_info("%llu\n", (unsigned long long)lim.rlim_max); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_civoid __init os_early_checks(void) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci int pid; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Print out the core dump limits early */ 3298c2ecf20Sopenharmony_ci check_coredump_limit(); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci check_ptrace(); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Need to check this early because mmapping happens before the 3348c2ecf20Sopenharmony_ci * kernel is running. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci check_tmpexec(); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci pid = start_ptraced_child(); 3398c2ecf20Sopenharmony_ci if (init_pid_registers(pid)) 3408c2ecf20Sopenharmony_ci fatal("Failed to initialize default registers"); 3418c2ecf20Sopenharmony_ci stop_ptraced_child(pid, 1, 1); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ciint __init parse_iomem(char *str, int *add) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct iomem_region *new; 3478c2ecf20Sopenharmony_ci struct stat64 buf; 3488c2ecf20Sopenharmony_ci char *file, *driver; 3498c2ecf20Sopenharmony_ci int fd, size; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci driver = str; 3528c2ecf20Sopenharmony_ci file = strchr(str,','); 3538c2ecf20Sopenharmony_ci if (file == NULL) { 3548c2ecf20Sopenharmony_ci os_warn("parse_iomem : failed to parse iomem\n"); 3558c2ecf20Sopenharmony_ci goto out; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci *file = '\0'; 3588c2ecf20Sopenharmony_ci file++; 3598c2ecf20Sopenharmony_ci fd = open(file, O_RDWR, 0); 3608c2ecf20Sopenharmony_ci if (fd < 0) { 3618c2ecf20Sopenharmony_ci perror("parse_iomem - Couldn't open io file"); 3628c2ecf20Sopenharmony_ci goto out; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (fstat64(fd, &buf) < 0) { 3668c2ecf20Sopenharmony_ci perror("parse_iomem - cannot stat_fd file"); 3678c2ecf20Sopenharmony_ci goto out_close; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci new = malloc(sizeof(*new)); 3718c2ecf20Sopenharmony_ci if (new == NULL) { 3728c2ecf20Sopenharmony_ci perror("Couldn't allocate iomem_region struct"); 3738c2ecf20Sopenharmony_ci goto out_close; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci *new = ((struct iomem_region) { .next = iomem_regions, 3798c2ecf20Sopenharmony_ci .driver = driver, 3808c2ecf20Sopenharmony_ci .fd = fd, 3818c2ecf20Sopenharmony_ci .size = size, 3828c2ecf20Sopenharmony_ci .phys = 0, 3838c2ecf20Sopenharmony_ci .virt = 0 }); 3848c2ecf20Sopenharmony_ci iomem_regions = new; 3858c2ecf20Sopenharmony_ci iomem_size += new->size + UM_KERN_PAGE_SIZE; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci out_close: 3898c2ecf20Sopenharmony_ci close(fd); 3908c2ecf20Sopenharmony_ci out: 3918c2ecf20Sopenharmony_ci return 1; 3928c2ecf20Sopenharmony_ci} 393