mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-06 01:11:46 +00:00
Do not start and stop idle ticking within the timer interrupt routine, but do it around the whole Lx_kit scheduling, which is always called when Linux code gets active again, either because of backend signals, interrupts, or timing signals. This commit implicitly reverts the (incomplete) solution of issue #4550 Ref genodelabs/genode#4778
194 lines
4.0 KiB
C
194 lines
4.0 KiB
C
/*
|
|
* \brief Linux Kernel initialization
|
|
* \author Stefan Kalkowski
|
|
* \date 2021-03-16
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2021 Genode Labs GmbH
|
|
*
|
|
* This file is distributed under the terms of the GNU General Public License
|
|
* version 2.
|
|
*/
|
|
|
|
#include <lx_emul/init.h>
|
|
#include <lx_emul/page_virt.h>
|
|
#include <lx_emul/time.h>
|
|
#include <lx_user/init.h>
|
|
|
|
#include <asm/irq_regs.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/init_task.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/irqchip.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/tick.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_clk.h>
|
|
#include <linux/of_fdt.h>
|
|
|
|
/* definitions in drivers/base/base.h */
|
|
extern int devices_init(void);
|
|
extern int buses_init(void);
|
|
extern int classes_init(void);
|
|
extern int platform_bus_init(void);
|
|
|
|
/* definition from kernel/main.c implemented architecture specific */
|
|
extern void time_init(void);
|
|
|
|
enum system_states system_state;
|
|
|
|
static __initdata DECLARE_COMPLETION(kthreadd_done);
|
|
|
|
static int kernel_init(void * args)
|
|
{
|
|
struct task_struct *tsk = current;
|
|
set_task_comm(tsk, "init");
|
|
|
|
wait_for_completion(&kthreadd_done);
|
|
|
|
workqueue_init();
|
|
|
|
/* the following calls are from driver_init() of drivers/base/init.c */
|
|
devices_init();
|
|
buses_init();
|
|
classes_init();
|
|
of_core_init();
|
|
platform_bus_init();
|
|
|
|
lx_emul_initcalls();
|
|
|
|
system_state = SYSTEM_RUNNING;
|
|
|
|
lx_user_init();
|
|
lx_emul_task_schedule(true);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int kernel_idle(void * args)
|
|
{
|
|
struct task_struct *tsk = current;
|
|
set_task_comm(tsk, "idle");
|
|
|
|
/* set this current task to be the idle task */
|
|
lx_emul_task_set_idle();
|
|
|
|
/*
|
|
* Idle task always gets run in the end of each schedule
|
|
* and again at the beginning of each schedule
|
|
*/
|
|
for (;;) {
|
|
lx_emul_task_schedule(true);
|
|
|
|
tick_nohz_idle_enter();
|
|
tick_nohz_idle_stop_tick();
|
|
|
|
lx_emul_task_schedule(true);
|
|
|
|
tick_nohz_idle_restart_tick();
|
|
tick_nohz_idle_exit();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void timer_loop(void)
|
|
{
|
|
for (;;) {
|
|
lx_emul_task_schedule(true);
|
|
lx_emul_time_handle();
|
|
}
|
|
}
|
|
|
|
|
|
int lx_emul_init_task_function(void * dtb)
|
|
{
|
|
int pid;
|
|
|
|
/* Set dummy task registers used in IRQ and time handling */
|
|
static struct pt_regs regs;
|
|
set_irq_regs(®s);
|
|
|
|
/* Run emulation library self-tests before starting kernel */
|
|
lx_emul_associate_page_selftest();
|
|
|
|
/**
|
|
* Here we do the minimum normally done start_kernel() of init/main.c
|
|
*/
|
|
|
|
lx_emul_setup_arch(dtb);
|
|
|
|
jump_label_init();
|
|
kmem_cache_init();
|
|
wait_bit_init();
|
|
radix_tree_init();
|
|
workqueue_init_early();
|
|
|
|
early_irq_init();
|
|
irqchip_init();
|
|
|
|
tick_init();
|
|
init_timers();
|
|
hrtimers_init();
|
|
softirq_init();
|
|
timekeeping_init();
|
|
|
|
time_init();
|
|
|
|
sched_clock_init();
|
|
|
|
kernel_thread(kernel_init, NULL, CLONE_FS);
|
|
kernel_thread(kernel_idle, NULL, CLONE_FS);
|
|
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
|
|
kthreadd_task = find_task_by_pid_ns(pid, NULL);;
|
|
|
|
system_state = SYSTEM_SCHEDULING;
|
|
|
|
complete(&kthreadd_done);
|
|
|
|
lx_emul_task_schedule(false);
|
|
|
|
timer_loop();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static struct cred _init_task_cred;
|
|
|
|
|
|
struct task_struct init_task = {
|
|
.__state = 0,
|
|
.usage = REFCOUNT_INIT(2),
|
|
.flags = PF_KTHREAD,
|
|
.prio = MAX_PRIO - 20,
|
|
.static_prio = MAX_PRIO - 20,
|
|
.normal_prio = MAX_PRIO - 20,
|
|
.policy = SCHED_NORMAL,
|
|
.cpus_ptr = &init_task.cpus_mask,
|
|
.cpus_mask = CPU_MASK_ALL,
|
|
.nr_cpus_allowed = 1,
|
|
.mm = NULL,
|
|
.active_mm = NULL,
|
|
.tasks = LIST_HEAD_INIT(init_task.tasks),
|
|
.real_parent = &init_task,
|
|
.parent = &init_task,
|
|
.children = LIST_HEAD_INIT(init_task.children),
|
|
.sibling = LIST_HEAD_INIT(init_task.sibling),
|
|
.group_leader = &init_task,
|
|
.comm = INIT_TASK_COMM,
|
|
.thread = INIT_THREAD,
|
|
.pending = {
|
|
.list = LIST_HEAD_INIT(init_task.pending.list),
|
|
.signal = {{0}}
|
|
},
|
|
.blocked = {{0}},
|
|
.cred = &_init_task_cred,
|
|
};
|
|
void * lx_emul_init_task_struct = &init_task;
|