162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) 462306a36Sopenharmony_ci * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <stdio.h> 862306a36Sopenharmony_ci#include <stdlib.h> 962306a36Sopenharmony_ci#include <unistd.h> 1062306a36Sopenharmony_ci#include <errno.h> 1162306a36Sopenharmony_ci#include <signal.h> 1262306a36Sopenharmony_ci#include <fcntl.h> 1362306a36Sopenharmony_ci#include <sys/mman.h> 1462306a36Sopenharmony_ci#include <sys/ptrace.h> 1562306a36Sopenharmony_ci#include <sys/wait.h> 1662306a36Sopenharmony_ci#include <asm/unistd.h> 1762306a36Sopenharmony_ci#include <init.h> 1862306a36Sopenharmony_ci#include <longjmp.h> 1962306a36Sopenharmony_ci#include <os.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define ARBITRARY_ADDR -1 2262306a36Sopenharmony_ci#define FAILURE_PID -1 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define STAT_PATH_LEN sizeof("/proc/#######/stat\0") 2562306a36Sopenharmony_ci#define COMM_SCANF "%*[^)])" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciunsigned long os_process_pc(int pid) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci char proc_stat[STAT_PATH_LEN], buf[256]; 3062306a36Sopenharmony_ci unsigned long pc = ARBITRARY_ADDR; 3162306a36Sopenharmony_ci int fd, err; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci sprintf(proc_stat, "/proc/%d/stat", pid); 3462306a36Sopenharmony_ci fd = open(proc_stat, O_RDONLY, 0); 3562306a36Sopenharmony_ci if (fd < 0) { 3662306a36Sopenharmony_ci printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', " 3762306a36Sopenharmony_ci "errno = %d\n", proc_stat, errno); 3862306a36Sopenharmony_ci goto out; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci CATCH_EINTR(err = read(fd, buf, sizeof(buf))); 4162306a36Sopenharmony_ci if (err < 0) { 4262306a36Sopenharmony_ci printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', " 4362306a36Sopenharmony_ci "err = %d\n", proc_stat, errno); 4462306a36Sopenharmony_ci goto out_close; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci os_close_file(fd); 4762306a36Sopenharmony_ci pc = ARBITRARY_ADDR; 4862306a36Sopenharmony_ci if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d " 4962306a36Sopenharmony_ci "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " 5062306a36Sopenharmony_ci "%*d %*d %*d %*d %*d %lu", &pc) != 1) 5162306a36Sopenharmony_ci printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n", 5262306a36Sopenharmony_ci buf); 5362306a36Sopenharmony_ci out_close: 5462306a36Sopenharmony_ci close(fd); 5562306a36Sopenharmony_ci out: 5662306a36Sopenharmony_ci return pc; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciint os_process_parent(int pid) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci char stat[STAT_PATH_LEN]; 6262306a36Sopenharmony_ci char data[256]; 6362306a36Sopenharmony_ci int parent = FAILURE_PID, n, fd; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (pid == -1) 6662306a36Sopenharmony_ci return parent; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); 6962306a36Sopenharmony_ci fd = open(stat, O_RDONLY, 0); 7062306a36Sopenharmony_ci if (fd < 0) { 7162306a36Sopenharmony_ci printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat, 7262306a36Sopenharmony_ci errno); 7362306a36Sopenharmony_ci return parent; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci CATCH_EINTR(n = read(fd, data, sizeof(data))); 7762306a36Sopenharmony_ci close(fd); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (n < 0) { 8062306a36Sopenharmony_ci printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat, 8162306a36Sopenharmony_ci errno); 8262306a36Sopenharmony_ci return parent; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci parent = FAILURE_PID; 8662306a36Sopenharmony_ci n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent); 8762306a36Sopenharmony_ci if (n != 1) 8862306a36Sopenharmony_ci printk(UM_KERN_ERR "Failed to scan '%s'\n", data); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return parent; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_civoid os_alarm_process(int pid) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci kill(pid, SIGALRM); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid os_stop_process(int pid) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci kill(pid, SIGSTOP); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_civoid os_kill_process(int pid, int reap_child) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci kill(pid, SIGKILL); 10662306a36Sopenharmony_ci if (reap_child) 10762306a36Sopenharmony_ci CATCH_EINTR(waitpid(pid, NULL, __WALL)); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* Kill off a ptraced child by all means available. kill it normally first, 11162306a36Sopenharmony_ci * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from 11262306a36Sopenharmony_ci * which it can't exit directly. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_civoid os_kill_ptraced_process(int pid, int reap_child) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci kill(pid, SIGKILL); 11862306a36Sopenharmony_ci ptrace(PTRACE_KILL, pid); 11962306a36Sopenharmony_ci ptrace(PTRACE_CONT, pid); 12062306a36Sopenharmony_ci if (reap_child) 12162306a36Sopenharmony_ci CATCH_EINTR(waitpid(pid, NULL, __WALL)); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* Don't use the glibc version, which caches the result in TLS. It misses some 12562306a36Sopenharmony_ci * syscalls, and also breaks with clone(), which does not unshare the TLS. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciint os_getpid(void) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci return syscall(__NR_getpid); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ciint os_getpgrp(void) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci return getpgrp(); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciint os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, 13962306a36Sopenharmony_ci int r, int w, int x) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci void *loc; 14262306a36Sopenharmony_ci int prot; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 14562306a36Sopenharmony_ci (x ? PROT_EXEC : 0); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, 14862306a36Sopenharmony_ci fd, off); 14962306a36Sopenharmony_ci if (loc == MAP_FAILED) 15062306a36Sopenharmony_ci return -errno; 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciint os_protect_memory(void *addr, unsigned long len, int r, int w, int x) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 15762306a36Sopenharmony_ci (x ? PROT_EXEC : 0)); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (mprotect(addr, len, prot) < 0) 16062306a36Sopenharmony_ci return -errno; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ciint os_unmap_memory(void *addr, int len) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci int err; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci err = munmap(addr, len); 17062306a36Sopenharmony_ci if (err < 0) 17162306a36Sopenharmony_ci return -errno; 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#ifndef MADV_REMOVE 17662306a36Sopenharmony_ci#define MADV_REMOVE KERNEL_MADV_REMOVE 17762306a36Sopenharmony_ci#endif 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciint os_drop_memory(void *addr, int length) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci int err; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci err = madvise(addr, length, MADV_REMOVE); 18462306a36Sopenharmony_ci if (err < 0) 18562306a36Sopenharmony_ci err = -errno; 18662306a36Sopenharmony_ci return err; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ciint __init can_drop_memory(void) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci void *addr; 19262306a36Sopenharmony_ci int fd, ok = 0; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci printk(UM_KERN_INFO "Checking host MADV_REMOVE support..."); 19562306a36Sopenharmony_ci fd = create_mem_file(UM_KERN_PAGE_SIZE); 19662306a36Sopenharmony_ci if (fd < 0) { 19762306a36Sopenharmony_ci printk(UM_KERN_ERR "Creating test memory file failed, " 19862306a36Sopenharmony_ci "err = %d\n", -fd); 19962306a36Sopenharmony_ci goto out; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, 20362306a36Sopenharmony_ci MAP_SHARED, fd, 0); 20462306a36Sopenharmony_ci if (addr == MAP_FAILED) { 20562306a36Sopenharmony_ci printk(UM_KERN_ERR "Mapping test memory file failed, " 20662306a36Sopenharmony_ci "err = %d\n", -errno); 20762306a36Sopenharmony_ci goto out_close; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0) { 21162306a36Sopenharmony_ci printk(UM_KERN_ERR "MADV_REMOVE failed, err = %d\n", -errno); 21262306a36Sopenharmony_ci goto out_unmap; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci printk(UM_KERN_CONT "OK\n"); 21662306a36Sopenharmony_ci ok = 1; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciout_unmap: 21962306a36Sopenharmony_ci munmap(addr, UM_KERN_PAGE_SIZE); 22062306a36Sopenharmony_ciout_close: 22162306a36Sopenharmony_ci close(fd); 22262306a36Sopenharmony_ciout: 22362306a36Sopenharmony_ci return ok; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int os_page_mincore(void *addr) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci char vec[2]; 22962306a36Sopenharmony_ci int ret; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); 23262306a36Sopenharmony_ci if (ret < 0) { 23362306a36Sopenharmony_ci if (errno == ENOMEM || errno == EINVAL) 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci return -errno; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return vec[0] & 1; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciint os_mincore(void *addr, unsigned long len) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci char *vec; 24562306a36Sopenharmony_ci int ret, i; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (len <= UM_KERN_PAGE_SIZE) 24862306a36Sopenharmony_ci return os_page_mincore(addr); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); 25162306a36Sopenharmony_ci if (!vec) 25262306a36Sopenharmony_ci return -ENOMEM; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); 25562306a36Sopenharmony_ci if (ret < 0) { 25662306a36Sopenharmony_ci if (errno == ENOMEM || errno == EINVAL) 25762306a36Sopenharmony_ci ret = 0; 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci ret = -errno; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci goto out; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) { 26562306a36Sopenharmony_ci if (!(vec[i] & 1)) { 26662306a36Sopenharmony_ci ret = 0; 26762306a36Sopenharmony_ci goto out; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci ret = 1; 27262306a36Sopenharmony_ciout: 27362306a36Sopenharmony_ci free(vec); 27462306a36Sopenharmony_ci return ret; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_civoid init_new_thread_signals(void) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci set_handler(SIGSEGV); 28062306a36Sopenharmony_ci set_handler(SIGTRAP); 28162306a36Sopenharmony_ci set_handler(SIGFPE); 28262306a36Sopenharmony_ci set_handler(SIGILL); 28362306a36Sopenharmony_ci set_handler(SIGBUS); 28462306a36Sopenharmony_ci signal(SIGHUP, SIG_IGN); 28562306a36Sopenharmony_ci set_handler(SIGIO); 28662306a36Sopenharmony_ci signal(SIGWINCH, SIG_IGN); 28762306a36Sopenharmony_ci} 288