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 <unistd.h> 98c2ecf20Sopenharmony_ci#include <errno.h> 108c2ecf20Sopenharmony_ci#include <signal.h> 118c2ecf20Sopenharmony_ci#include <string.h> 128c2ecf20Sopenharmony_ci#include <termios.h> 138c2ecf20Sopenharmony_ci#include <sys/wait.h> 148c2ecf20Sopenharmony_ci#include <sys/mman.h> 158c2ecf20Sopenharmony_ci#include <sys/utsname.h> 168c2ecf20Sopenharmony_ci#include <init.h> 178c2ecf20Sopenharmony_ci#include <os.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_civoid stack_protections(unsigned long address) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci if (mprotect((void *) address, UM_THREAD_SIZE, 228c2ecf20Sopenharmony_ci PROT_READ | PROT_WRITE | PROT_EXEC) < 0) 238c2ecf20Sopenharmony_ci panic("protecting stack failed, errno = %d", errno); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciint raw(int fd) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct termios tt; 298c2ecf20Sopenharmony_ci int err; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci CATCH_EINTR(err = tcgetattr(fd, &tt)); 328c2ecf20Sopenharmony_ci if (err < 0) 338c2ecf20Sopenharmony_ci return -errno; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci cfmakeraw(&tt); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); 388c2ecf20Sopenharmony_ci if (err < 0) 398c2ecf20Sopenharmony_ci return -errno; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* 428c2ecf20Sopenharmony_ci * XXX tcsetattr could have applied only some changes 438c2ecf20Sopenharmony_ci * (and cfmakeraw() is a set of changes) 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_civoid setup_machinename(char *machine_out) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct utsname host; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci uname(&host); 538c2ecf20Sopenharmony_ci#ifdef UML_CONFIG_UML_X86 548c2ecf20Sopenharmony_ci# ifndef UML_CONFIG_64BIT 558c2ecf20Sopenharmony_ci if (!strcmp(host.machine, "x86_64")) { 568c2ecf20Sopenharmony_ci strcpy(machine_out, "i686"); 578c2ecf20Sopenharmony_ci return; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci# else 608c2ecf20Sopenharmony_ci if (!strcmp(host.machine, "i686")) { 618c2ecf20Sopenharmony_ci strcpy(machine_out, "x86_64"); 628c2ecf20Sopenharmony_ci return; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci# endif 658c2ecf20Sopenharmony_ci#endif 668c2ecf20Sopenharmony_ci strcpy(machine_out, host.machine); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid setup_hostinfo(char *buf, int len) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct utsname host; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci uname(&host); 748c2ecf20Sopenharmony_ci snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename, 758c2ecf20Sopenharmony_ci host.release, host.version, host.machine); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * We cannot use glibc's abort(). It makes use of tgkill() which 808c2ecf20Sopenharmony_ci * has no effect within UML's kernel threads. 818c2ecf20Sopenharmony_ci * After that glibc would execute an invalid instruction to kill 828c2ecf20Sopenharmony_ci * the calling process and UML crashes with SIGSEGV. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_cistatic inline void __attribute__ ((noreturn)) uml_abort(void) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci sigset_t sig; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci fflush(NULL); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT)) 918c2ecf20Sopenharmony_ci sigprocmask(SIG_UNBLOCK, &sig, 0); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci for (;;) 948c2ecf20Sopenharmony_ci if (kill(getpid(), SIGABRT) < 0) 958c2ecf20Sopenharmony_ci exit(127); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* 998c2ecf20Sopenharmony_ci * UML helper threads must not handle SIGWINCH/INT/TERM 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_civoid os_fix_helper_signals(void) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci signal(SIGWINCH, SIG_IGN); 1048c2ecf20Sopenharmony_ci signal(SIGINT, SIG_DFL); 1058c2ecf20Sopenharmony_ci signal(SIGTERM, SIG_DFL); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_civoid os_dump_core(void) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int pid; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci signal(SIGSEGV, SIG_DFL); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* 1158c2ecf20Sopenharmony_ci * We are about to SIGTERM this entire process group to ensure that 1168c2ecf20Sopenharmony_ci * nothing is around to run after the kernel exits. The 1178c2ecf20Sopenharmony_ci * kernel wants to abort, not die through SIGTERM, so we 1188c2ecf20Sopenharmony_ci * ignore it here. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci signal(SIGTERM, SIG_IGN); 1228c2ecf20Sopenharmony_ci kill(0, SIGTERM); 1238c2ecf20Sopenharmony_ci /* 1248c2ecf20Sopenharmony_ci * Most of the other processes associated with this UML are 1258c2ecf20Sopenharmony_ci * likely sTopped, so give them a SIGCONT so they see the 1268c2ecf20Sopenharmony_ci * SIGTERM. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci kill(0, SIGCONT); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * Now, having sent signals to everyone but us, make sure they 1328c2ecf20Sopenharmony_ci * die by ptrace. Processes can survive what's been done to 1338c2ecf20Sopenharmony_ci * them so far - the mechanism I understand is receiving a 1348c2ecf20Sopenharmony_ci * SIGSEGV and segfaulting immediately upon return. There is 1358c2ecf20Sopenharmony_ci * always a SIGSEGV pending, and (I'm guessing) signals are 1368c2ecf20Sopenharmony_ci * processed in numeric order so the SIGTERM (signal 15 vs 1378c2ecf20Sopenharmony_ci * SIGSEGV being signal 11) is never handled. 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * Run a waitpid loop until we get some kind of error. 1408c2ecf20Sopenharmony_ci * Hopefully, it's ECHILD, but there's not a lot we can do if 1418c2ecf20Sopenharmony_ci * it's something else. Tell os_kill_ptraced_process not to 1428c2ecf20Sopenharmony_ci * wait for the child to report its death because there's 1438c2ecf20Sopenharmony_ci * nothing reasonable to do if that fails. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0) 1478c2ecf20Sopenharmony_ci os_kill_ptraced_process(pid, 0); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci uml_abort(); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_civoid um_early_printk(const char *s, unsigned int n) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci printf("%.*s", n, s); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int quiet_info; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int __init quiet_cmd_param(char *str, int *add) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci quiet_info = 1; 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci__uml_setup("quiet", quiet_cmd_param, 1668c2ecf20Sopenharmony_ci"quiet\n" 1678c2ecf20Sopenharmony_ci" Turns off information messages during boot.\n\n"); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* 1708c2ecf20Sopenharmony_ci * The os_info/os_warn functions will be called by helper threads. These 1718c2ecf20Sopenharmony_ci * have a very limited stack size and using the libc formatting functions 1728c2ecf20Sopenharmony_ci * may overflow the stack. 1738c2ecf20Sopenharmony_ci * So pull in the kernel vscnprintf and use that instead with a fixed 1748c2ecf20Sopenharmony_ci * on-stack buffer. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ciint vscnprintf(char *buf, size_t size, const char *fmt, va_list args); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_civoid os_info(const char *fmt, ...) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci char buf[256]; 1818c2ecf20Sopenharmony_ci va_list list; 1828c2ecf20Sopenharmony_ci int len; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (quiet_info) 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci va_start(list, fmt); 1888c2ecf20Sopenharmony_ci len = vscnprintf(buf, sizeof(buf), fmt, list); 1898c2ecf20Sopenharmony_ci fwrite(buf, len, 1, stderr); 1908c2ecf20Sopenharmony_ci va_end(list); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_civoid os_warn(const char *fmt, ...) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci char buf[256]; 1968c2ecf20Sopenharmony_ci va_list list; 1978c2ecf20Sopenharmony_ci int len; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci va_start(list, fmt); 2008c2ecf20Sopenharmony_ci len = vscnprintf(buf, sizeof(buf), fmt, list); 2018c2ecf20Sopenharmony_ci fwrite(buf, len, 1, stderr); 2028c2ecf20Sopenharmony_ci va_end(list); 2038c2ecf20Sopenharmony_ci} 204