Arm64架构-1-上下文切换-2-相关实验


一、内核线程变用户进程

基于msm-5.4

1. 简介

本实验想参考内核init线程变成用户init进程的做法,实现驱动中创建一个内核线程,然后其装载用户程序变成用户进程。

//创建init内核线程:
rest_init //init/main.c
    kernel_thread(kernel_init, NULL, CLONE_FS);

//内核线程变用户进程
kernel_init //init/main.c
    ret = run_init_process("/bin");
    if (!ret)
        return 0; //返回用户空间,成为init用户空间进程

load_elf_binary() 中会对硬件做一些初始化,比如设置 pt_regs 等,执行路径如下:

run_init_process //init/main.c
    do_execveat
        do_execveat_common //fs/exec.c
            __do_execve_file //fs/exec.c
                exec_binprm //fs/exec.c
                    search_binary_handler //fs/exec.c
                        fmt->load_binary(bprm);
                            load_elf_binary


2. 实验代码

(1) 内核代码

#define pr_fmt(fmt) "KTU_K: " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/delay.h>
#include <linux/sched/signal.h>
#include <linux/sched/task.h>

int g_val;

#define MAX_USER_ARGS CONFIG_INIT_ENV_ARG_LIMIT
#define MAX_USER_ENVS CONFIG_INIT_ENV_ARG_LIMIT

static const char *argv_user[MAX_USER_ARGS+2] = { "user", NULL, };
const char *envp_user[MAX_USER_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
/* 参考 run_init_process */
static int run_user_process(const char *user_filename)
{
    argv_user[0] = user_filename;
    pr_info("Run %s as user process\n", user_filename);
    return do_execve(getname_kernel(user_filename),
        (const char __user *const __user *)argv_user,
        (const char __user *const __user *)envp_user);
}

int ktu_test_kernel_thread(void *arg)
{
    int ret;
    int val = (int)arg;

    ret = run_user_process("/data/local/tmp/ktu_user");
    if (ret < 0) {
        pr_info("run ktu_user fald");
    }
    if (val == 1) {
        pr_info("pid=%d enter msleep loop\n", current->pid);
        while(1) msleep(10);
    } else {
        pr_info("pid=%d returned\n", current->pid);
        return 0; //return user space
    }
}

static ssize_t ktu_test_write(struct file *file,
        const char __user *buf, size_t count, loff_t *ppos)
{
    char buffer[64] = {0};
    int ret, type, val;

    if (count > sizeof(buffer) - 1)
        count = sizeof(buffer) - 1;

    if (copy_from_user(buffer, buf, count))
        return -EFAULT;

    ret = sscanf(buffer, "%d %d", &type, &val);
    if (ret <= 0) {
        pr_err("sscanf failed\n");
          return -EINVAL;;
    }
    pr_info("set param: type=%d, val=%d\n", type, val);

    if (type == 1) {
        int pid = kernel_thread(ktu_test_kernel_thread, (void *)val, CLONE_FS);
        pr_info("cur pid=%d, kernel thread pid=%d\n", current->pid, pid);
    }

    for (;;) {
        if (signal_pending(current)) {
            pr_info("pid=%d interrupted by signal\n", current->pid);
            return -EINTR;
        }
        schedule_timeout_interruptible(25);
    }

    g_val = val;

    pr_info("pid=%d returned\n", current->pid);

    return count;
}

static ssize_t ktu_test_read(struct file *file,
        char __user *buf, size_t count, loff_t *ppos)
{
    char buffer[256];
    size_t len;

    len = snprintf(buffer, sizeof(buffer), "test pid=%d\n", g_val);

    return simple_read_from_buffer(buf, count, ppos, buffer, strlen(buffer));
}

static const struct file_operations proc_ktu_test_fops = {
    .write    = ktu_test_write,
    .read    = ktu_test_read,
};

static int __init ktu_test_init(void)
{
    pr_info("init.\n");

    proc_create("ktu_test", 0666, NULL, &proc_ktu_test_fops);

    return 0;
}

module_init(ktu_test_init);


(2) 用户代码

#define LOG_TAG "KTU_U"

#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/syscall.h>

#include <log/log.h>

int main(int argc, char *argv[])
{
    int i, cnt = 0;

    for (i = 0; i < argc; i++) {
        ALOGI("argv[%d]=%s", i, argv[i]);
    }

    while(1) {
        ALOGI("user cnt=%d", cnt++);
        usleep(200 * 1000);
    }
    
    return 0;
}

Android.bp:

cc_binary {
    name: "ktu_user",
    srcs: [
        "ktu_user.cpp",
    ],
    defaults: ["ktu_user_defaults"],
}

cc_defaults {
    name: "ktu_user_defaults",
    cflags: [
        "-Wall",
        "-Werror",
        "-Wno-unused-function",
        "-Wno-unused-parameter",
        "-Wno-unused-variable",
    ],
    static_libs: [
        "libc",
        "libcutils",
        "liblog",
   ],
   static_executable: true,
}


3. 实验数据

实验失败,执行报错如下:

# echo 1 0 > /proc/ktu_test
[363.576714] (1)[4595:sh]KTU_K: set param: type=1, val=0
[363.577035] (1)[4595:sh]KTU_K: cur pid=4595, kernel thread pid=4722
[363.577313] (0)[4722:sh]potentially unexpected fatal signal 11.
[363.577494] (0)[4722:sh]CPU: 0 PID: 4722 Comm: sh Tainted: G  W  O   5.4.219--dirty #32
[363.577737] (0)[4722:sh]Hardware name: Qualcomm Technologies, Inc. Direwolf Single LA Virtual Machine
[363.577952] (0)[4722:sh]pstate: 00001000 (nzcv daif -PAN -UAO)
[363.578091] (0)[4722:sh]pc : 0000005acb162970
[363.578200] (0)[4722:sh]lr : 0000005acb162984
[363.578359] (0)[4722:sh]sp : ffffffc0100a1430
[363.578490] (0)[4722:sh]x29: 0000007fcef1b1c0 x28: 0000007fcef1b180
[363.578637] (0)[4722:sh]x27: 0000005acb188310 x26: 00000078c8ca6000
[363.578797] (0)[4722:sh]x25: b40000773491d069 x24: 0000007fcef1b1a0
[363.578938] (0)[4722:sh]x23: 0000007fcef1b198 x22: 0000005acb165bf0
[363.579081] (0)[4722:sh]x21: 0000005acb187648 x20: b40000773491ce58
[363.579236] (0)[4722:sh]x19: 0000000000000004 x18: 00000078c9cea000
[363.579415] (0)[4722:sh]x17: 00000078c49af250 x16: 00000078c49d21c8
[363.579559] (0)[4722:sh]x15: 0000005acb187f00 x14: 0000000000000000
[363.579685] (0)[4722:sh]x13: 00000000108f6ff7 x12: 0000ffff00000eff
[363.579888] (0)[4722:sh]x11: 000000003491ceec x10: 000000003c2cd166
[363.580130] (0)[4722:sh]x9 : b40000773491ce58 x8 : 0000000000000040
[363.580312] (0)[4722:sh]x7 : 0000000000000000 x6 : 0000000000000030
[363.580511] (0)[4722:sh]x5 : b4000076d491822a x4 : ffffffffffffffff
[363.580644] (0)[4722:sh]x3 : ffffffffffffffff x2 : 0000000000000004
[363.580783] (0)[4722:sh]x1 : b40000773491ce58 x0 : 0000000000000000
[363.581061] (1)[4595:sh]KTU_K: pid=4595 interrupted by signal
[363.582931] (2)[1:init]init: Untracked pid 4722 received signal 11

用户空间一个打印也没有,根本没有得到执行。

注: init进程有 init_mm, init_task 全局变量结构, 需要进一步研究。

 

posted on 2026-01-20 16:45  Hello-World3  阅读(1)  评论(0)    收藏  举报

导航