162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <stdio.h> 762306a36Sopenharmony_ci#include <stdlib.h> 862306a36Sopenharmony_ci#include <stdarg.h> 962306a36Sopenharmony_ci#include <unistd.h> 1062306a36Sopenharmony_ci#include <errno.h> 1162306a36Sopenharmony_ci#include <fcntl.h> 1262306a36Sopenharmony_ci#include <sched.h> 1362306a36Sopenharmony_ci#include <signal.h> 1462306a36Sopenharmony_ci#include <string.h> 1562306a36Sopenharmony_ci#include <sys/mman.h> 1662306a36Sopenharmony_ci#include <sys/stat.h> 1762306a36Sopenharmony_ci#include <sys/wait.h> 1862306a36Sopenharmony_ci#include <sys/time.h> 1962306a36Sopenharmony_ci#include <sys/resource.h> 2062306a36Sopenharmony_ci#include <asm/unistd.h> 2162306a36Sopenharmony_ci#include <init.h> 2262306a36Sopenharmony_ci#include <os.h> 2362306a36Sopenharmony_ci#include <mem_user.h> 2462306a36Sopenharmony_ci#include <ptrace_user.h> 2562306a36Sopenharmony_ci#include <registers.h> 2662306a36Sopenharmony_ci#include <skas.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void ptrace_child(void) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci int ret; 3162306a36Sopenharmony_ci /* Calling os_getpid because some libcs cached getpid incorrectly */ 3262306a36Sopenharmony_ci int pid = os_getpid(), ppid = getppid(); 3362306a36Sopenharmony_ci int sc_result; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (change_sig(SIGWINCH, 0) < 0 || 3662306a36Sopenharmony_ci ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { 3762306a36Sopenharmony_ci perror("ptrace"); 3862306a36Sopenharmony_ci kill(pid, SIGKILL); 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci kill(pid, SIGSTOP); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* 4362306a36Sopenharmony_ci * This syscall will be intercepted by the parent. Don't call more than 4462306a36Sopenharmony_ci * once, please. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci sc_result = os_getpid(); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (sc_result == pid) 4962306a36Sopenharmony_ci /* Nothing modified by the parent, we are running normally. */ 5062306a36Sopenharmony_ci ret = 1; 5162306a36Sopenharmony_ci else if (sc_result == ppid) 5262306a36Sopenharmony_ci /* 5362306a36Sopenharmony_ci * Expected in check_ptrace and check_sysemu when they succeed 5462306a36Sopenharmony_ci * in modifying the stack frame 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ci ret = 0; 5762306a36Sopenharmony_ci else 5862306a36Sopenharmony_ci /* Serious trouble! This could be caused by a bug in host 2.6 5962306a36Sopenharmony_ci * SKAS3/2.6 patch before release -V6, together with a bug in 6062306a36Sopenharmony_ci * the UML code itself. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci ret = 2; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci exit(ret); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void fatal_perror(const char *str) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci perror(str); 7062306a36Sopenharmony_ci exit(1); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void fatal(char *fmt, ...) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci va_list list; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci va_start(list, fmt); 7862306a36Sopenharmony_ci vfprintf(stderr, fmt, list); 7962306a36Sopenharmony_ci va_end(list); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci exit(1); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void non_fatal(char *fmt, ...) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci va_list list; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci va_start(list, fmt); 8962306a36Sopenharmony_ci vfprintf(stderr, fmt, list); 9062306a36Sopenharmony_ci va_end(list); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int start_ptraced_child(void) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci int pid, n, status; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci fflush(stdout); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci pid = fork(); 10062306a36Sopenharmony_ci if (pid == 0) 10162306a36Sopenharmony_ci ptrace_child(); 10262306a36Sopenharmony_ci else if (pid < 0) 10362306a36Sopenharmony_ci fatal_perror("start_ptraced_child : fork failed"); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 10662306a36Sopenharmony_ci if (n < 0) 10762306a36Sopenharmony_ci fatal_perror("check_ptrace : waitpid failed"); 10862306a36Sopenharmony_ci if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) 10962306a36Sopenharmony_ci fatal("check_ptrace : expected SIGSTOP, got status = %d", 11062306a36Sopenharmony_ci status); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return pid; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* When testing for SYSEMU support, if it is one of the broken versions, we 11662306a36Sopenharmony_ci * must just avoid using sysemu, not panic, but only if SYSEMU features are 11762306a36Sopenharmony_ci * broken. 11862306a36Sopenharmony_ci * So only for SYSEMU features we test mustpanic, while normal host features 11962306a36Sopenharmony_ci * must work anyway! 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_cistatic int stop_ptraced_child(int pid, int exitcode, int mustexit) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int status, n, ret = 0; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { 12662306a36Sopenharmony_ci perror("stop_ptraced_child : ptrace failed"); 12762306a36Sopenharmony_ci return -1; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, 0)); 13062306a36Sopenharmony_ci if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { 13162306a36Sopenharmony_ci int exit_with = WEXITSTATUS(status); 13262306a36Sopenharmony_ci if (exit_with == 2) 13362306a36Sopenharmony_ci non_fatal("check_ptrace : child exited with status 2. " 13462306a36Sopenharmony_ci "\nDisabling SYSEMU support.\n"); 13562306a36Sopenharmony_ci non_fatal("check_ptrace : child exited with exitcode %d, while " 13662306a36Sopenharmony_ci "expecting %d; status 0x%x\n", exit_with, 13762306a36Sopenharmony_ci exitcode, status); 13862306a36Sopenharmony_ci if (mustexit) 13962306a36Sopenharmony_ci exit(1); 14062306a36Sopenharmony_ci ret = -1; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return ret; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* Changed only during early boot */ 14762306a36Sopenharmony_cistatic int force_sysemu_disabled = 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int __init nosysemu_cmd_param(char *str, int* add) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci force_sysemu_disabled = 1; 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci__uml_setup("nosysemu", nosysemu_cmd_param, 15662306a36Sopenharmony_ci"nosysemu\n" 15762306a36Sopenharmony_ci" Turns off syscall emulation patch for ptrace (SYSEMU).\n" 15862306a36Sopenharmony_ci" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" 15962306a36Sopenharmony_ci" behaviour of ptrace() and helps reduce host context switch rates.\n" 16062306a36Sopenharmony_ci" To make it work, you need a kernel patch for your host, too.\n" 16162306a36Sopenharmony_ci" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n" 16262306a36Sopenharmony_ci" information.\n\n"); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void __init check_sysemu(void) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci unsigned long regs[MAX_REG_NR]; 16762306a36Sopenharmony_ci int pid, n, status, count=0; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci os_info("Checking syscall emulation patch for ptrace..."); 17062306a36Sopenharmony_ci sysemu_supported = 0; 17162306a36Sopenharmony_ci pid = start_ptraced_child(); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) 17462306a36Sopenharmony_ci goto fail; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 17762306a36Sopenharmony_ci if (n < 0) 17862306a36Sopenharmony_ci fatal_perror("check_sysemu : wait failed"); 17962306a36Sopenharmony_ci if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) 18062306a36Sopenharmony_ci fatal("check_sysemu : expected SIGTRAP, got status = %d\n", 18162306a36Sopenharmony_ci status); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) 18462306a36Sopenharmony_ci fatal_perror("check_sysemu : PTRACE_GETREGS failed"); 18562306a36Sopenharmony_ci if (PT_SYSCALL_NR(regs) != __NR_getpid) { 18662306a36Sopenharmony_ci non_fatal("check_sysemu got system call number %d, " 18762306a36Sopenharmony_ci "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid); 18862306a36Sopenharmony_ci goto fail; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); 19262306a36Sopenharmony_ci if (n < 0) { 19362306a36Sopenharmony_ci non_fatal("check_sysemu : failed to modify system call " 19462306a36Sopenharmony_ci "return"); 19562306a36Sopenharmony_ci goto fail; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (stop_ptraced_child(pid, 0, 0) < 0) 19962306a36Sopenharmony_ci goto fail_stopped; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci sysemu_supported = 1; 20262306a36Sopenharmony_ci os_info("OK\n"); 20362306a36Sopenharmony_ci set_using_sysemu(!force_sysemu_disabled); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci os_info("Checking advanced syscall emulation patch for ptrace..."); 20662306a36Sopenharmony_ci pid = start_ptraced_child(); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, 20962306a36Sopenharmony_ci (void *) PTRACE_O_TRACESYSGOOD) < 0)) 21062306a36Sopenharmony_ci fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci while (1) { 21362306a36Sopenharmony_ci count++; 21462306a36Sopenharmony_ci if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) 21562306a36Sopenharmony_ci goto fail; 21662306a36Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 21762306a36Sopenharmony_ci if (n < 0) 21862306a36Sopenharmony_ci fatal_perror("check_sysemu: wait failed"); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (WIFSTOPPED(status) && 22162306a36Sopenharmony_ci (WSTOPSIG(status) == (SIGTRAP|0x80))) { 22262306a36Sopenharmony_ci if (!count) { 22362306a36Sopenharmony_ci non_fatal("check_sysemu: SYSEMU_SINGLESTEP " 22462306a36Sopenharmony_ci "doesn't singlestep"); 22562306a36Sopenharmony_ci goto fail; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, 22862306a36Sopenharmony_ci os_getpid()); 22962306a36Sopenharmony_ci if (n < 0) 23062306a36Sopenharmony_ci fatal_perror("check_sysemu : failed to modify " 23162306a36Sopenharmony_ci "system call return"); 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) 23562306a36Sopenharmony_ci count++; 23662306a36Sopenharmony_ci else { 23762306a36Sopenharmony_ci non_fatal("check_sysemu: expected SIGTRAP or " 23862306a36Sopenharmony_ci "(SIGTRAP | 0x80), got status = %d\n", 23962306a36Sopenharmony_ci status); 24062306a36Sopenharmony_ci goto fail; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci if (stop_ptraced_child(pid, 0, 0) < 0) 24462306a36Sopenharmony_ci goto fail_stopped; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci sysemu_supported = 2; 24762306a36Sopenharmony_ci os_info("OK\n"); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!force_sysemu_disabled) 25062306a36Sopenharmony_ci set_using_sysemu(sysemu_supported); 25162306a36Sopenharmony_ci return; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cifail: 25462306a36Sopenharmony_ci stop_ptraced_child(pid, 1, 0); 25562306a36Sopenharmony_cifail_stopped: 25662306a36Sopenharmony_ci non_fatal("missing\n"); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void __init check_ptrace(void) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci int pid, syscall, n, status; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci os_info("Checking that ptrace can change system call numbers..."); 26462306a36Sopenharmony_ci pid = start_ptraced_child(); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, 26762306a36Sopenharmony_ci (void *) PTRACE_O_TRACESYSGOOD) < 0)) 26862306a36Sopenharmony_ci fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci while (1) { 27162306a36Sopenharmony_ci if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) 27262306a36Sopenharmony_ci fatal_perror("check_ptrace : ptrace failed"); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 27562306a36Sopenharmony_ci if (n < 0) 27662306a36Sopenharmony_ci fatal_perror("check_ptrace : wait failed"); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!WIFSTOPPED(status) || 27962306a36Sopenharmony_ci (WSTOPSIG(status) != (SIGTRAP | 0x80))) 28062306a36Sopenharmony_ci fatal("check_ptrace : expected (SIGTRAP|0x80), " 28162306a36Sopenharmony_ci "got status = %d", status); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 28462306a36Sopenharmony_ci 0); 28562306a36Sopenharmony_ci if (syscall == __NR_getpid) { 28662306a36Sopenharmony_ci n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 28762306a36Sopenharmony_ci __NR_getppid); 28862306a36Sopenharmony_ci if (n < 0) 28962306a36Sopenharmony_ci fatal_perror("check_ptrace : failed to modify " 29062306a36Sopenharmony_ci "system call"); 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci stop_ptraced_child(pid, 0, 1); 29562306a36Sopenharmony_ci os_info("OK\n"); 29662306a36Sopenharmony_ci check_sysemu(); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ciextern void check_tmpexec(void); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void __init check_coredump_limit(void) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct rlimit lim; 30462306a36Sopenharmony_ci int err = getrlimit(RLIMIT_CORE, &lim); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (err) { 30762306a36Sopenharmony_ci perror("Getting core dump limit"); 30862306a36Sopenharmony_ci return; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci os_info("Core dump limits :\n\tsoft - "); 31262306a36Sopenharmony_ci if (lim.rlim_cur == RLIM_INFINITY) 31362306a36Sopenharmony_ci os_info("NONE\n"); 31462306a36Sopenharmony_ci else 31562306a36Sopenharmony_ci os_info("%llu\n", (unsigned long long)lim.rlim_cur); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci os_info("\thard - "); 31862306a36Sopenharmony_ci if (lim.rlim_max == RLIM_INFINITY) 31962306a36Sopenharmony_ci os_info("NONE\n"); 32062306a36Sopenharmony_ci else 32162306a36Sopenharmony_ci os_info("%llu\n", (unsigned long long)lim.rlim_max); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_civoid __init get_host_cpu_features( 32562306a36Sopenharmony_ci void (*flags_helper_func)(char *line), 32662306a36Sopenharmony_ci void (*cache_helper_func)(char *line)) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci FILE *cpuinfo; 32962306a36Sopenharmony_ci char *line = NULL; 33062306a36Sopenharmony_ci size_t len = 0; 33162306a36Sopenharmony_ci int done_parsing = 0; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci cpuinfo = fopen("/proc/cpuinfo", "r"); 33462306a36Sopenharmony_ci if (cpuinfo == NULL) { 33562306a36Sopenharmony_ci os_info("Failed to get host CPU features\n"); 33662306a36Sopenharmony_ci } else { 33762306a36Sopenharmony_ci while ((getline(&line, &len, cpuinfo)) != -1) { 33862306a36Sopenharmony_ci if (strstr(line, "flags")) { 33962306a36Sopenharmony_ci flags_helper_func(line); 34062306a36Sopenharmony_ci done_parsing++; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci if (strstr(line, "cache_alignment")) { 34362306a36Sopenharmony_ci cache_helper_func(line); 34462306a36Sopenharmony_ci done_parsing++; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci free(line); 34762306a36Sopenharmony_ci line = NULL; 34862306a36Sopenharmony_ci if (done_parsing > 1) 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci fclose(cpuinfo); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_civoid __init os_early_checks(void) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci int pid; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Print out the core dump limits early */ 36162306a36Sopenharmony_ci check_coredump_limit(); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci check_ptrace(); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Need to check this early because mmapping happens before the 36662306a36Sopenharmony_ci * kernel is running. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci check_tmpexec(); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci pid = start_ptraced_child(); 37162306a36Sopenharmony_ci if (init_pid_registers(pid)) 37262306a36Sopenharmony_ci fatal("Failed to initialize default registers"); 37362306a36Sopenharmony_ci stop_ptraced_child(pid, 1, 1); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ciint __init parse_iomem(char *str, int *add) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct iomem_region *new; 37962306a36Sopenharmony_ci struct stat64 buf; 38062306a36Sopenharmony_ci char *file, *driver; 38162306a36Sopenharmony_ci int fd, size; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci driver = str; 38462306a36Sopenharmony_ci file = strchr(str,','); 38562306a36Sopenharmony_ci if (file == NULL) { 38662306a36Sopenharmony_ci os_warn("parse_iomem : failed to parse iomem\n"); 38762306a36Sopenharmony_ci goto out; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci *file = '\0'; 39062306a36Sopenharmony_ci file++; 39162306a36Sopenharmony_ci fd = open(file, O_RDWR, 0); 39262306a36Sopenharmony_ci if (fd < 0) { 39362306a36Sopenharmony_ci perror("parse_iomem - Couldn't open io file"); 39462306a36Sopenharmony_ci goto out; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (fstat64(fd, &buf) < 0) { 39862306a36Sopenharmony_ci perror("parse_iomem - cannot stat_fd file"); 39962306a36Sopenharmony_ci goto out_close; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci new = malloc(sizeof(*new)); 40362306a36Sopenharmony_ci if (new == NULL) { 40462306a36Sopenharmony_ci perror("Couldn't allocate iomem_region struct"); 40562306a36Sopenharmony_ci goto out_close; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci *new = ((struct iomem_region) { .next = iomem_regions, 41162306a36Sopenharmony_ci .driver = driver, 41262306a36Sopenharmony_ci .fd = fd, 41362306a36Sopenharmony_ci .size = size, 41462306a36Sopenharmony_ci .phys = 0, 41562306a36Sopenharmony_ci .virt = 0 }); 41662306a36Sopenharmony_ci iomem_regions = new; 41762306a36Sopenharmony_ci iomem_size += new->size + UM_KERN_PAGE_SIZE; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci out_close: 42162306a36Sopenharmony_ci close(fd); 42262306a36Sopenharmony_ci out: 42362306a36Sopenharmony_ci return 1; 42462306a36Sopenharmony_ci} 425