mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-linus-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML updates from Richard Weinberger: "Mostly fixes for UML: - First round of fixes for PTRACE_GETRESET/SETREGSET - A printf vs printk cleanup - Minor improvements" * 'for-linus-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml: um: Correctly check for PTRACE_GETRESET/SETREGSET um: v2: Use generic NOTES macro um: Add kerneldoc for userspace_tramp() and start_userspace() um: Add kerneldoc for segv_handler um: stub-data.h: remove superfluous include um: userspace - be more verbose in ptrace set regs error um: add dummy ioremap and iounmap functions um: Allow building and running on older hosts um: Avoid longjmp/setjmp symbol clashes with libpthread.a um: console: Ignore console= option um: Use os_warn to print out pre-boot warning/error messages um: Add os_warn() for pre-boot warning/error messages um: Use os_info for the messages on normal path um: Add os_info() for pre-boot information messages um: Use printk instead of printf in make_uml_dir
This commit is contained in:
commit
4ecd4ff55a
|
@ -59,10 +59,14 @@ KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/um
|
||||||
# Same things for in6addr_loopback and mktime - found in libc. For these two we
|
# Same things for in6addr_loopback and mktime - found in libc. For these two we
|
||||||
# only get link-time error, luckily.
|
# only get link-time error, luckily.
|
||||||
#
|
#
|
||||||
|
# -Dlongjmp=kernel_longjmp prevents anything from referencing the libpthread.a
|
||||||
|
# embedded copy of longjmp, same thing for setjmp.
|
||||||
|
#
|
||||||
# These apply to USER_CFLAGS to.
|
# These apply to USER_CFLAGS to.
|
||||||
|
|
||||||
KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \
|
KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \
|
||||||
$(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \
|
$(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \
|
||||||
|
-Dlongjmp=kernel_longjmp -Dsetjmp=kernel_setjmp \
|
||||||
-Din6addr_loopback=kernel_in6addr_loopback \
|
-Din6addr_loopback=kernel_in6addr_loopback \
|
||||||
-Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr
|
-Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,9 @@ __uml_exitcall(console_exit);
|
||||||
|
|
||||||
static int console_chan_setup(char *str)
|
static int console_chan_setup(char *str)
|
||||||
{
|
{
|
||||||
|
if (!strncmp(str, "sole=", 5)) /* console= option specifies tty */
|
||||||
|
return 0;
|
||||||
|
|
||||||
line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console");
|
line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
PROVIDE (_unprotected_end = .);
|
PROVIDE (_unprotected_end = .);
|
||||||
|
|
||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
.note : { *(.note.*) }
|
NOTES
|
||||||
EXCEPTION_TABLE(0)
|
EXCEPTION_TABLE(0)
|
||||||
|
|
||||||
BUG_TABLE
|
BUG_TABLE
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef _ASM_UM_IO_H
|
||||||
|
#define _ASM_UM_IO_H
|
||||||
|
|
||||||
|
#define ioremap ioremap
|
||||||
|
static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
|
||||||
|
{
|
||||||
|
return (void __iomem *)(unsigned long)offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define iounmap iounmap
|
||||||
|
static inline void iounmap(void __iomem *addr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <asm-generic/io.h>
|
||||||
|
|
||||||
|
#endif
|
|
@ -242,6 +242,10 @@ extern void setup_hostinfo(char *buf, int len);
|
||||||
extern void os_dump_core(void) __attribute__ ((noreturn));
|
extern void os_dump_core(void) __attribute__ ((noreturn));
|
||||||
extern void um_early_printk(const char *s, unsigned int n);
|
extern void um_early_printk(const char *s, unsigned int n);
|
||||||
extern void os_fix_helper_signals(void);
|
extern void os_fix_helper_signals(void);
|
||||||
|
extern void os_info(const char *fmt, ...)
|
||||||
|
__attribute__ ((format (printf, 1, 2)));
|
||||||
|
extern void os_warn(const char *fmt, ...)
|
||||||
|
__attribute__ ((format (printf, 1, 2)));
|
||||||
|
|
||||||
/* time.c */
|
/* time.c */
|
||||||
extern void os_idle_sleep(unsigned long long nsecs);
|
extern void os_idle_sleep(unsigned long long nsecs);
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
#ifndef __STUB_DATA_H
|
#ifndef __STUB_DATA_H
|
||||||
#define __STUB_DATA_H
|
#define __STUB_DATA_H
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
struct stub_data {
|
struct stub_data {
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
|
@ -89,8 +89,8 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end,
|
||||||
offset = uml_reserved - uml_physmem;
|
offset = uml_reserved - uml_physmem;
|
||||||
map_size = len - offset;
|
map_size = len - offset;
|
||||||
if(map_size <= 0) {
|
if(map_size <= 0) {
|
||||||
printf("Too few physical memory! Needed=%d, given=%d\n",
|
os_warn("Too few physical memory! Needed=%lu, given=%lu\n",
|
||||||
offset, len);
|
offset, len);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,9 +99,9 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end,
|
||||||
err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
|
err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
|
||||||
map_size, 1, 1, 1);
|
map_size, 1, 1, 1);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
|
os_warn("setup_physmem - mapping %ld bytes of memory at 0x%p "
|
||||||
"failed - errno = %d\n", map_size,
|
"failed - errno = %d\n", map_size,
|
||||||
(void *) uml_reserved, err);
|
(void *) uml_reserved, err);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,16 @@ void fatal_sigsegv(void)
|
||||||
os_dump_core();
|
os_dump_core();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* segv_handler() - the SIGSEGV handler
|
||||||
|
* @sig: the signal number
|
||||||
|
* @unused_si: the signal info struct; unused in this handler
|
||||||
|
* @regs: the ptrace register information
|
||||||
|
*
|
||||||
|
* The handler first extracts the faultinfo from the UML ptrace regs struct.
|
||||||
|
* If the userfault did not happen in an UML userspace process, bad_segv is called.
|
||||||
|
* Otherwise the signal did happen in a cloned userspace process, handle it.
|
||||||
|
*/
|
||||||
void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
|
void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct faultinfo * fi = UPT_FAULTINFO(regs);
|
struct faultinfo * fi = UPT_FAULTINFO(regs);
|
||||||
|
|
|
@ -34,7 +34,7 @@ static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
|
||||||
static void __init add_arg(char *arg)
|
static void __init add_arg(char *arg)
|
||||||
{
|
{
|
||||||
if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
|
if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
|
||||||
printf("add_arg: Too many command line arguments!\n");
|
os_warn("add_arg: Too many command line arguments!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (strlen(command_line) > 0)
|
if (strlen(command_line) > 0)
|
||||||
|
@ -120,6 +120,7 @@ static const char *usage_string =
|
||||||
|
|
||||||
static int __init uml_version_setup(char *line, int *add)
|
static int __init uml_version_setup(char *line, int *add)
|
||||||
{
|
{
|
||||||
|
/* Explicitly use printf() to show version in stdout */
|
||||||
printf("%s\n", init_utsname()->release);
|
printf("%s\n", init_utsname()->release);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
|
@ -148,8 +149,8 @@ __uml_setup("root=", uml_root_setup,
|
||||||
|
|
||||||
static int __init no_skas_debug_setup(char *line, int *add)
|
static int __init no_skas_debug_setup(char *line, int *add)
|
||||||
{
|
{
|
||||||
printf("'debug' is not necessary to gdb UML in skas mode - run \n");
|
os_warn("'debug' is not necessary to gdb UML in skas mode - run\n");
|
||||||
printf("'gdb linux'\n");
|
os_warn("'gdb linux'\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -165,6 +166,7 @@ static int __init Usage(char *line, int *add)
|
||||||
|
|
||||||
printf(usage_string, init_utsname()->release);
|
printf(usage_string, init_utsname()->release);
|
||||||
p = &__uml_help_start;
|
p = &__uml_help_start;
|
||||||
|
/* Explicitly use printf() to show help in stdout */
|
||||||
while (p < &__uml_help_end) {
|
while (p < &__uml_help_end) {
|
||||||
printf("%s", *p);
|
printf("%s", *p);
|
||||||
p++;
|
p++;
|
||||||
|
@ -283,8 +285,8 @@ int __init linux_main(int argc, char **argv)
|
||||||
|
|
||||||
diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
|
diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
|
||||||
if (diff > 1024 * 1024) {
|
if (diff > 1024 * 1024) {
|
||||||
printf("Adding %ld bytes to physical memory to account for "
|
os_info("Adding %ld bytes to physical memory to account for "
|
||||||
"exec-shield gap\n", diff);
|
"exec-shield gap\n", diff);
|
||||||
physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
|
physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,8 +326,8 @@ int __init linux_main(int argc, char **argv)
|
||||||
end_vm = start_vm + virtmem_size;
|
end_vm = start_vm + virtmem_size;
|
||||||
|
|
||||||
if (virtmem_size < physmem_size)
|
if (virtmem_size < physmem_size)
|
||||||
printf("Kernel virtual memory size shrunk to %lu bytes\n",
|
os_info("Kernel virtual memory size shrunk to %lu bytes\n",
|
||||||
virtmem_size);
|
virtmem_size);
|
||||||
|
|
||||||
os_flush_stdout();
|
os_flush_stdout();
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,14 @@ static int __init set_umid_arg(char *name, int *add)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (umid_inited) {
|
if (umid_inited) {
|
||||||
printf("umid already set\n");
|
os_warn("umid already set\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*add = 0;
|
*add = 0;
|
||||||
err = set_umid(name);
|
err = set_umid(name);
|
||||||
if (err == -EEXIST)
|
if (err == -EEXIST)
|
||||||
printf("umid '%s' already in use\n", name);
|
os_warn("umid '%s' already in use\n", name);
|
||||||
else if (!err)
|
else if (!err)
|
||||||
umid_inited = 1;
|
umid_inited = 1;
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ int main(int argc, char**argv)
|
||||||
int ret;
|
int ret;
|
||||||
argc--;
|
argc--;
|
||||||
if (!argc) {
|
if (!argc) {
|
||||||
fprintf(stderr, "Not enough arguments\n");
|
os_warn("Not enough arguments\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
argv++;
|
argv++;
|
||||||
|
|
|
@ -74,8 +74,8 @@ static void install_fatal_handler(int sig)
|
||||||
action.sa_restorer = NULL;
|
action.sa_restorer = NULL;
|
||||||
action.sa_handler = last_ditch_exit;
|
action.sa_handler = last_ditch_exit;
|
||||||
if (sigaction(sig, &action, NULL) < 0) {
|
if (sigaction(sig, &action, NULL) < 0) {
|
||||||
printf("failed to install handler for signal %d - errno = %d\n",
|
os_warn("failed to install handler for signal %d "
|
||||||
sig, errno);
|
"- errno = %d\n", sig, errno);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ int __init main(int argc, char **argv, char **envp)
|
||||||
/* disable SIGIO for the fds and set SIGIO to be ignored */
|
/* disable SIGIO for the fds and set SIGIO to be ignored */
|
||||||
err = deactivate_all_fds();
|
err = deactivate_all_fds();
|
||||||
if (err)
|
if (err)
|
||||||
printf("deactivate_all_fds failed, errno = %d\n", -err);
|
os_warn("deactivate_all_fds failed, errno = %d\n", -err);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let any pending signals fire now. This ensures
|
* Let any pending signals fire now. This ensures
|
||||||
|
@ -184,14 +184,13 @@ int __init main(int argc, char **argv, char **envp)
|
||||||
*/
|
*/
|
||||||
unblock_signals();
|
unblock_signals();
|
||||||
|
|
||||||
|
os_info("\n");
|
||||||
/* Reboot */
|
/* Reboot */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("\n");
|
|
||||||
execvp(new_argv[0], new_argv);
|
execvp(new_argv[0], new_argv);
|
||||||
perror("Failed to exec kernel");
|
perror("Failed to exec kernel");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
printf("\n");
|
|
||||||
return uml_exitcode;
|
return uml_exitcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,13 @@ static int __init check_tmpfs(const char *dir)
|
||||||
{
|
{
|
||||||
struct statfs st;
|
struct statfs st;
|
||||||
|
|
||||||
printf("Checking if %s is on tmpfs...", dir);
|
os_info("Checking if %s is on tmpfs...", dir);
|
||||||
if (statfs(dir, &st) < 0) {
|
if (statfs(dir, &st) < 0) {
|
||||||
printf("%s\n", strerror(errno));
|
os_info("%s\n", strerror(errno));
|
||||||
} else if (st.f_type != TMPFS_MAGIC) {
|
} else if (st.f_type != TMPFS_MAGIC) {
|
||||||
printf("no\n");
|
os_info("no\n");
|
||||||
} else {
|
} else {
|
||||||
printf("OK\n");
|
os_info("OK\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -61,18 +61,18 @@ static char * __init choose_tempdir(void)
|
||||||
int i;
|
int i;
|
||||||
const char *dir;
|
const char *dir;
|
||||||
|
|
||||||
printf("Checking environment variables for a tempdir...");
|
os_info("Checking environment variables for a tempdir...");
|
||||||
for (i = 0; vars[i]; i++) {
|
for (i = 0; vars[i]; i++) {
|
||||||
dir = getenv(vars[i]);
|
dir = getenv(vars[i]);
|
||||||
if ((dir != NULL) && (*dir != '\0')) {
|
if ((dir != NULL) && (*dir != '\0')) {
|
||||||
printf("%s\n", dir);
|
os_info("%s\n", dir);
|
||||||
if (check_tmpfs(dir) >= 0)
|
if (check_tmpfs(dir) >= 0)
|
||||||
goto done;
|
goto done;
|
||||||
else
|
else
|
||||||
goto warn;
|
goto warn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("none found\n");
|
os_info("none found\n");
|
||||||
|
|
||||||
for (i = 0; tmpfs_dirs[i]; i++) {
|
for (i = 0; tmpfs_dirs[i]; i++) {
|
||||||
dir = tmpfs_dirs[i];
|
dir = tmpfs_dirs[i];
|
||||||
|
@ -82,7 +82,7 @@ static char * __init choose_tempdir(void)
|
||||||
|
|
||||||
dir = fallback_dir;
|
dir = fallback_dir;
|
||||||
warn:
|
warn:
|
||||||
printf("Warning: tempdir %s is not on tmpfs\n", dir);
|
os_warn("Warning: tempdir %s is not on tmpfs\n", dir);
|
||||||
done:
|
done:
|
||||||
/* Make a copy since getenv results may not remain valid forever. */
|
/* Make a copy since getenv results may not remain valid forever. */
|
||||||
return strdup(dir);
|
return strdup(dir);
|
||||||
|
@ -100,7 +100,7 @@ static int __init make_tempfile(const char *template)
|
||||||
if (tempdir == NULL) {
|
if (tempdir == NULL) {
|
||||||
tempdir = choose_tempdir();
|
tempdir = choose_tempdir();
|
||||||
if (tempdir == NULL) {
|
if (tempdir == NULL) {
|
||||||
fprintf(stderr, "Failed to choose tempdir: %s\n",
|
os_warn("Failed to choose tempdir: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ static int __init make_tempfile(const char *template)
|
||||||
strcat(tempname, template);
|
strcat(tempname, template);
|
||||||
fd = mkstemp(tempname);
|
fd = mkstemp(tempname);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, "open - cannot create %s: %s\n", tempname,
|
os_warn("open - cannot create %s: %s\n", tempname,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -194,16 +194,16 @@ void __init check_tmpexec(void)
|
||||||
|
|
||||||
addr = mmap(NULL, UM_KERN_PAGE_SIZE,
|
addr = mmap(NULL, UM_KERN_PAGE_SIZE,
|
||||||
PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
|
PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
|
||||||
printf("Checking PROT_EXEC mmap in %s...", tempdir);
|
os_info("Checking PROT_EXEC mmap in %s...", tempdir);
|
||||||
if (addr == MAP_FAILED) {
|
if (addr == MAP_FAILED) {
|
||||||
err = errno;
|
err = errno;
|
||||||
printf("%s\n", strerror(err));
|
os_warn("%s\n", strerror(err));
|
||||||
close(fd);
|
close(fd);
|
||||||
if (err == EPERM)
|
if (err == EPERM)
|
||||||
printf("%s must be not mounted noexec\n", tempdir);
|
os_warn("%s must be not mounted noexec\n", tempdir);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
printf("OK\n");
|
os_info("OK\n");
|
||||||
munmap(addr, UM_KERN_PAGE_SIZE);
|
munmap(addr, UM_KERN_PAGE_SIZE);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
|
@ -108,7 +108,7 @@ static void get_skas_faultinfo(int pid, struct faultinfo *fi)
|
||||||
wait_stub_done(pid);
|
wait_stub_done(pid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* faultinfo is prepared by the stub-segv-handler at start of
|
* faultinfo is prepared by the stub_segv_handler at start of
|
||||||
* the stub stack page. We just have to copy it.
|
* the stub stack page. We just have to copy it.
|
||||||
*/
|
*/
|
||||||
memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
|
memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
|
||||||
|
@ -175,6 +175,21 @@ static void handle_trap(int pid, struct uml_pt_regs *regs,
|
||||||
|
|
||||||
extern char __syscall_stub_start[];
|
extern char __syscall_stub_start[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* userspace_tramp() - userspace trampoline
|
||||||
|
* @stack: pointer to the new userspace stack page, can be NULL, if? FIXME:
|
||||||
|
*
|
||||||
|
* The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed.
|
||||||
|
* This function will run on a temporary stack page.
|
||||||
|
* It ptrace()'es itself, then
|
||||||
|
* Two pages are mapped into the userspace address space:
|
||||||
|
* - STUB_CODE (with EXEC), which contains the skas stub code
|
||||||
|
* - STUB_DATA (with R/W), which contains a data page that is used to transfer certain data between the UML userspace process and the UML kernel.
|
||||||
|
* Also for the userspace process a SIGSEGV handler is installed to catch pagefaults in the userspace process.
|
||||||
|
* And last the process stops itself to give control to the UML kernel for this userspace process.
|
||||||
|
*
|
||||||
|
* Return: Always zero, otherwise the current userspace process is ended with non null exit() call
|
||||||
|
*/
|
||||||
static int userspace_tramp(void *stack)
|
static int userspace_tramp(void *stack)
|
||||||
{
|
{
|
||||||
void *addr;
|
void *addr;
|
||||||
|
@ -236,12 +251,24 @@ static int userspace_tramp(void *stack)
|
||||||
|
|
||||||
int userspace_pid[NR_CPUS];
|
int userspace_pid[NR_CPUS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start_userspace() - prepare a new userspace process
|
||||||
|
* @stub_stack: pointer to the stub stack. Can be NULL, if? FIXME:
|
||||||
|
*
|
||||||
|
* Setups a new temporary stack page that is used while userspace_tramp() runs
|
||||||
|
* Clones the kernel process into a new userspace process, with FDs only.
|
||||||
|
*
|
||||||
|
* Return: When positive: the process id of the new userspace process,
|
||||||
|
* when negative: an error number.
|
||||||
|
* FIXME: can PIDs become negative?!
|
||||||
|
*/
|
||||||
int start_userspace(unsigned long stub_stack)
|
int start_userspace(unsigned long stub_stack)
|
||||||
{
|
{
|
||||||
void *stack;
|
void *stack;
|
||||||
unsigned long sp;
|
unsigned long sp;
|
||||||
int pid, status, n, flags, err;
|
int pid, status, n, flags, err;
|
||||||
|
|
||||||
|
/* setup a temporary stack page */
|
||||||
stack = mmap(NULL, UM_KERN_PAGE_SIZE,
|
stack = mmap(NULL, UM_KERN_PAGE_SIZE,
|
||||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
@ -252,10 +279,12 @@ int start_userspace(unsigned long stub_stack)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set stack pointer to the end of the stack page, so it can grow downwards */
|
||||||
sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *);
|
sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *);
|
||||||
|
|
||||||
flags = CLONE_FILES | SIGCHLD;
|
flags = CLONE_FILES | SIGCHLD;
|
||||||
|
|
||||||
|
/* clone into new userspace process */
|
||||||
pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
|
pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
|
@ -323,11 +352,17 @@ void userspace(struct uml_pt_regs *regs)
|
||||||
* fail. In this case, there is nothing to do but
|
* fail. In this case, there is nothing to do but
|
||||||
* just kill the process.
|
* just kill the process.
|
||||||
*/
|
*/
|
||||||
if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp))
|
if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) {
|
||||||
|
printk(UM_KERN_ERR "userspace - ptrace set regs "
|
||||||
|
"failed, errno = %d\n", errno);
|
||||||
fatal_sigsegv();
|
fatal_sigsegv();
|
||||||
|
}
|
||||||
|
|
||||||
if (put_fp_registers(pid, regs->fp))
|
if (put_fp_registers(pid, regs->fp)) {
|
||||||
|
printk(UM_KERN_ERR "userspace - ptrace set fp regs "
|
||||||
|
"failed, errno = %d\n", errno);
|
||||||
fatal_sigsegv();
|
fatal_sigsegv();
|
||||||
|
}
|
||||||
|
|
||||||
/* Now we set local_using_sysemu to be used for one loop */
|
/* Now we set local_using_sysemu to be used for one loop */
|
||||||
local_using_sysemu = get_using_sysemu();
|
local_using_sysemu = get_using_sysemu();
|
||||||
|
|
|
@ -166,7 +166,7 @@ static void __init check_sysemu(void)
|
||||||
unsigned long regs[MAX_REG_NR];
|
unsigned long regs[MAX_REG_NR];
|
||||||
int pid, n, status, count=0;
|
int pid, n, status, count=0;
|
||||||
|
|
||||||
non_fatal("Checking syscall emulation patch for ptrace...");
|
os_info("Checking syscall emulation patch for ptrace...");
|
||||||
sysemu_supported = 0;
|
sysemu_supported = 0;
|
||||||
pid = start_ptraced_child();
|
pid = start_ptraced_child();
|
||||||
|
|
||||||
|
@ -199,10 +199,10 @@ static void __init check_sysemu(void)
|
||||||
goto fail_stopped;
|
goto fail_stopped;
|
||||||
|
|
||||||
sysemu_supported = 1;
|
sysemu_supported = 1;
|
||||||
non_fatal("OK\n");
|
os_info("OK\n");
|
||||||
set_using_sysemu(!force_sysemu_disabled);
|
set_using_sysemu(!force_sysemu_disabled);
|
||||||
|
|
||||||
non_fatal("Checking advanced syscall emulation patch for ptrace...");
|
os_info("Checking advanced syscall emulation patch for ptrace...");
|
||||||
pid = start_ptraced_child();
|
pid = start_ptraced_child();
|
||||||
|
|
||||||
if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
||||||
|
@ -244,7 +244,7 @@ static void __init check_sysemu(void)
|
||||||
goto fail_stopped;
|
goto fail_stopped;
|
||||||
|
|
||||||
sysemu_supported = 2;
|
sysemu_supported = 2;
|
||||||
non_fatal("OK\n");
|
os_info("OK\n");
|
||||||
|
|
||||||
if (!force_sysemu_disabled)
|
if (!force_sysemu_disabled)
|
||||||
set_using_sysemu(sysemu_supported);
|
set_using_sysemu(sysemu_supported);
|
||||||
|
@ -260,7 +260,7 @@ static void __init check_ptrace(void)
|
||||||
{
|
{
|
||||||
int pid, syscall, n, status;
|
int pid, syscall, n, status;
|
||||||
|
|
||||||
non_fatal("Checking that ptrace can change system call numbers...");
|
os_info("Checking that ptrace can change system call numbers...");
|
||||||
pid = start_ptraced_child();
|
pid = start_ptraced_child();
|
||||||
|
|
||||||
if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
||||||
|
@ -292,7 +292,7 @@ static void __init check_ptrace(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stop_ptraced_child(pid, 0, 1);
|
stop_ptraced_child(pid, 0, 1);
|
||||||
non_fatal("OK\n");
|
os_info("OK\n");
|
||||||
check_sysemu();
|
check_sysemu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,15 +308,17 @@ static void __init check_coredump_limit(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Core dump limits :\n\tsoft - ");
|
os_info("Core dump limits :\n\tsoft - ");
|
||||||
if (lim.rlim_cur == RLIM_INFINITY)
|
if (lim.rlim_cur == RLIM_INFINITY)
|
||||||
printf("NONE\n");
|
os_info("NONE\n");
|
||||||
else printf("%lu\n", lim.rlim_cur);
|
else
|
||||||
|
os_info("%llu\n", (unsigned long long)lim.rlim_cur);
|
||||||
|
|
||||||
printf("\thard - ");
|
os_info("\thard - ");
|
||||||
if (lim.rlim_max == RLIM_INFINITY)
|
if (lim.rlim_max == RLIM_INFINITY)
|
||||||
printf("NONE\n");
|
os_info("NONE\n");
|
||||||
else printf("%lu\n", lim.rlim_max);
|
else
|
||||||
|
os_info("%llu\n", (unsigned long long)lim.rlim_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init os_early_checks(void)
|
void __init os_early_checks(void)
|
||||||
|
@ -349,7 +351,7 @@ int __init parse_iomem(char *str, int *add)
|
||||||
driver = str;
|
driver = str;
|
||||||
file = strchr(str,',');
|
file = strchr(str,',');
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
fprintf(stderr, "parse_iomem : failed to parse iomem\n");
|
os_warn("parse_iomem : failed to parse iomem\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
*file = '\0';
|
*file = '\0';
|
||||||
|
|
|
@ -35,8 +35,9 @@ static int __init make_uml_dir(void)
|
||||||
|
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
if (home == NULL) {
|
if (home == NULL) {
|
||||||
printk(UM_KERN_ERR "make_uml_dir : no value in "
|
printk(UM_KERN_ERR
|
||||||
"environment for $HOME\n");
|
"%s: no value in environment for $HOME\n",
|
||||||
|
__func__);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
strlcpy(dir, home, sizeof(dir));
|
strlcpy(dir, home, sizeof(dir));
|
||||||
|
@ -50,13 +51,15 @@ static int __init make_uml_dir(void)
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
uml_dir = malloc(strlen(dir) + 1);
|
uml_dir = malloc(strlen(dir) + 1);
|
||||||
if (uml_dir == NULL) {
|
if (uml_dir == NULL) {
|
||||||
printf("make_uml_dir : malloc failed, errno = %d\n", errno);
|
printk(UM_KERN_ERR "%s : malloc failed, errno = %d\n",
|
||||||
|
__func__, errno);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
strcpy(uml_dir, dir);
|
strcpy(uml_dir, dir);
|
||||||
|
|
||||||
if ((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)) {
|
if ((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)) {
|
||||||
printf("Failed to mkdir '%s': %s\n", uml_dir, strerror(errno));
|
printk(UM_KERN_ERR "Failed to mkdir '%s': %s\n",
|
||||||
|
uml_dir, strerror(errno));
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto err_free;
|
goto err_free;
|
||||||
}
|
}
|
||||||
|
@ -351,7 +354,7 @@ char *get_umid(void)
|
||||||
static int __init set_uml_dir(char *name, int *add)
|
static int __init set_uml_dir(char *name, int *add)
|
||||||
{
|
{
|
||||||
if (*name == '\0') {
|
if (*name == '\0') {
|
||||||
printf("uml_dir can't be an empty string\n");
|
os_warn("uml_dir can't be an empty string\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +365,7 @@ static int __init set_uml_dir(char *name, int *add)
|
||||||
|
|
||||||
uml_dir = malloc(strlen(name) + 2);
|
uml_dir = malloc(strlen(name) + 2);
|
||||||
if (uml_dir == NULL) {
|
if (uml_dir == NULL) {
|
||||||
printf("Failed to malloc uml_dir - error = %d\n", errno);
|
os_warn("Failed to malloc uml_dir - error = %d\n", errno);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return 0 here because do_initcalls doesn't look at
|
* Return 0 here because do_initcalls doesn't look at
|
||||||
|
@ -387,8 +390,8 @@ static void remove_umid_dir(void)
|
||||||
sprintf(dir, "%s%s", uml_dir, umid);
|
sprintf(dir, "%s%s", uml_dir, umid);
|
||||||
err = remove_files_and_dir(dir);
|
err = remove_files_and_dir(dir);
|
||||||
if (err)
|
if (err)
|
||||||
printf("remove_umid_dir - remove_files_and_dir failed with "
|
os_warn("%s - remove_files_and_dir failed with err = %d\n",
|
||||||
"err = %d\n", err);
|
__func__, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
__uml_exitcall(remove_umid_dir);
|
__uml_exitcall(remove_umid_dir);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <wait.h>
|
#include <wait.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
#include <init.h>
|
||||||
#include <os.h>
|
#include <os.h>
|
||||||
|
|
||||||
void stack_protections(unsigned long address)
|
void stack_protections(unsigned long address)
|
||||||
|
@ -152,3 +153,36 @@ void um_early_printk(const char *s, unsigned int n)
|
||||||
{
|
{
|
||||||
printf("%.*s", n, s);
|
printf("%.*s", n, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int quiet_info;
|
||||||
|
|
||||||
|
static int __init quiet_cmd_param(char *str, int *add)
|
||||||
|
{
|
||||||
|
quiet_info = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__uml_setup("quiet", quiet_cmd_param,
|
||||||
|
"quiet\n"
|
||||||
|
" Turns off information messages during boot.\n\n");
|
||||||
|
|
||||||
|
void os_info(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list list;
|
||||||
|
|
||||||
|
if (quiet_info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(list, fmt);
|
||||||
|
vfprintf(stderr, fmt, list);
|
||||||
|
va_end(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void os_warn(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list list;
|
||||||
|
|
||||||
|
va_start(list, fmt);
|
||||||
|
vfprintf(stderr, fmt, list);
|
||||||
|
va_end(list);
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ int save_i387_registers(int pid, unsigned long *fp_regs)
|
||||||
|
|
||||||
int save_fp_registers(int pid, unsigned long *fp_regs)
|
int save_fp_registers(int pid, unsigned long *fp_regs)
|
||||||
{
|
{
|
||||||
|
#ifdef PTRACE_GETREGSET
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
|
|
||||||
if (have_xstate_support) {
|
if (have_xstate_support) {
|
||||||
|
@ -34,9 +35,9 @@ int save_fp_registers(int pid, unsigned long *fp_regs)
|
||||||
if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
|
if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
return save_i387_registers(pid, fp_regs);
|
return save_i387_registers(pid, fp_regs);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int restore_i387_registers(int pid, unsigned long *fp_regs)
|
int restore_i387_registers(int pid, unsigned long *fp_regs)
|
||||||
|
@ -48,6 +49,7 @@ int restore_i387_registers(int pid, unsigned long *fp_regs)
|
||||||
|
|
||||||
int restore_fp_registers(int pid, unsigned long *fp_regs)
|
int restore_fp_registers(int pid, unsigned long *fp_regs)
|
||||||
{
|
{
|
||||||
|
#ifdef PTRACE_SETREGSET
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
|
|
||||||
if (have_xstate_support) {
|
if (have_xstate_support) {
|
||||||
|
@ -56,9 +58,9 @@ int restore_fp_registers(int pid, unsigned long *fp_regs)
|
||||||
if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
|
if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
return restore_i387_registers(pid, fp_regs);
|
return restore_i387_registers(pid, fp_regs);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
@ -122,6 +124,7 @@ int put_fp_registers(int pid, unsigned long *regs)
|
||||||
|
|
||||||
void arch_init_registers(int pid)
|
void arch_init_registers(int pid)
|
||||||
{
|
{
|
||||||
|
#ifdef PTRACE_GETREGSET
|
||||||
struct _xstate fp_regs;
|
struct _xstate fp_regs;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
|
|
||||||
|
@ -129,6 +132,7 @@ void arch_init_registers(int pid)
|
||||||
iov.iov_len = sizeof(struct _xstate);
|
iov.iov_len = sizeof(struct _xstate);
|
||||||
if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
|
if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
|
||||||
have_xstate_support = 1;
|
have_xstate_support = 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 4
|
.align 4
|
||||||
.globl setjmp
|
.globl kernel_setjmp
|
||||||
.type setjmp, @function
|
.type kernel_setjmp, @function
|
||||||
setjmp:
|
kernel_setjmp:
|
||||||
#ifdef _REGPARM
|
#ifdef _REGPARM
|
||||||
movl %eax,%edx
|
movl %eax,%edx
|
||||||
#else
|
#else
|
||||||
|
@ -35,13 +35,13 @@ setjmp:
|
||||||
movl %ecx,20(%edx) # Return address
|
movl %ecx,20(%edx) # Return address
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.size setjmp,.-setjmp
|
.size kernel_setjmp,.-kernel_setjmp
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 4
|
.align 4
|
||||||
.globl longjmp
|
.globl kernel_longjmp
|
||||||
.type longjmp, @function
|
.type kernel_longjmp, @function
|
||||||
longjmp:
|
kernel_longjmp:
|
||||||
#ifdef _REGPARM
|
#ifdef _REGPARM
|
||||||
xchgl %eax,%edx
|
xchgl %eax,%edx
|
||||||
#else
|
#else
|
||||||
|
@ -55,4 +55,4 @@ longjmp:
|
||||||
movl 16(%edx),%edi
|
movl 16(%edx),%edi
|
||||||
jmp *20(%edx)
|
jmp *20(%edx)
|
||||||
|
|
||||||
.size longjmp,.-longjmp
|
.size kernel_longjmp,.-kernel_longjmp
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 4
|
.align 4
|
||||||
.globl setjmp
|
.globl kernel_setjmp
|
||||||
.type setjmp, @function
|
.type kernel_setjmp, @function
|
||||||
setjmp:
|
kernel_setjmp:
|
||||||
pop %rsi # Return address, and adjust the stack
|
pop %rsi # Return address, and adjust the stack
|
||||||
xorl %eax,%eax # Return value
|
xorl %eax,%eax # Return value
|
||||||
movq %rbx,(%rdi)
|
movq %rbx,(%rdi)
|
||||||
|
@ -34,13 +34,13 @@ setjmp:
|
||||||
movq %rsi,56(%rdi) # Return address
|
movq %rsi,56(%rdi) # Return address
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.size setjmp,.-setjmp
|
.size kernel_setjmp,.-kernel_setjmp
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 4
|
.align 4
|
||||||
.globl longjmp
|
.globl kernel_longjmp
|
||||||
.type longjmp, @function
|
.type kernel_longjmp, @function
|
||||||
longjmp:
|
kernel_longjmp:
|
||||||
movl %esi,%eax # Return value (int)
|
movl %esi,%eax # Return value (int)
|
||||||
movq (%rdi),%rbx
|
movq (%rdi),%rbx
|
||||||
movq 8(%rdi),%rsp
|
movq 8(%rdi),%rsp
|
||||||
|
@ -51,4 +51,4 @@ longjmp:
|
||||||
movq 48(%rdi),%r15
|
movq 48(%rdi),%r15
|
||||||
jmp *56(%rdi)
|
jmp *56(%rdi)
|
||||||
|
|
||||||
.size longjmp,.-longjmp
|
.size kernel_longjmp,.-kernel_longjmp
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
#define __FRAME_OFFSETS
|
#define __FRAME_OFFSETS
|
||||||
#include <asm/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
@ -50,7 +50,11 @@ void foo(void)
|
||||||
DEFINE(HOST_GS, GS);
|
DEFINE(HOST_GS, GS);
|
||||||
DEFINE(HOST_ORIG_AX, ORIG_EAX);
|
DEFINE(HOST_ORIG_AX, ORIG_EAX);
|
||||||
#else
|
#else
|
||||||
|
#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET)
|
||||||
DEFINE(HOST_FP_SIZE, sizeof(struct _xstate) / sizeof(unsigned long));
|
DEFINE(HOST_FP_SIZE, sizeof(struct _xstate) / sizeof(unsigned long));
|
||||||
|
#else
|
||||||
|
DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long));
|
||||||
|
#endif
|
||||||
DEFINE_LONGS(HOST_BX, RBX);
|
DEFINE_LONGS(HOST_BX, RBX);
|
||||||
DEFINE_LONGS(HOST_CX, RCX);
|
DEFINE_LONGS(HOST_CX, RCX);
|
||||||
DEFINE_LONGS(HOST_DI, RDI);
|
DEFINE_LONGS(HOST_DI, RDI);
|
||||||
|
|
Loading…
Reference in New Issue