Porting Linux to a new processor architecture, part 3: To the finish line

发布于:2025-05-16 ⋅ 阅读:(20) ⋅ 点赞:(0)

This series of articles provides an overview of the procedure one can follow when porting the Linux kernel to a new processor architecture. Part 1 and part 2 focused on the non-code-related groundwork and the early code, from the assembly boot code to the creation of the first kernel thread. Following on from those, the series concludes by looking at the last portion of the procedure. As will be seen, most of the remaining work for launching the init process deals with thread and process management.
本系列文章概述了在将 Linux 内核移植到一个新处理器架构时可以遵循的流程。第一部分和第二部分聚焦于非代码相关的准备工作以及早期代码的实现,从汇编启动代码到创建第一个内核线程。本文则承接前两部分,介绍剩余的最后阶段。可以看到,为了启动 init 进程,大部分剩余工作都与线程和进程管理有关。

Spawning kernel threads
生成内核线程

When start_kernel() performs its last function call (to rest_init()), the memory-management subsystem is fully operational, the boot processor is running and able to process both exceptions and interrupts, and the system has a notion of time.
start_kernel() 执行其最后一个函数调用(即调用 rest_init())时,内存管理子系统已经完全就绪,引导处理器正在运行并能够处理异常和中断,系统也已经具备了时间感知。

While the execution flow has so far been sequential and mono-threaded, the main job handled by rest_init() before turning into the boot idle thread is to create two kernel threads: kernel_init, which will be discussed in the next section, and kthreadd. As one can imagine, creating these kernel threads (and any other kinds of threads for that matter, from user threads within the same process to actual processes) implies the existence of a complex process-management infrastructure. Most of the infrastructure to create a new thread is not architecture-specific: operations such as copying the task_struct structure or the credentials, setting up the scheduler, and so on do not usually need any architecture-specific code. However, the process-management code must define a few architecture-specific parts, mainly for setting up the stack for each new thread and for switching between threads.
虽然当前的执行流程仍是顺序的、单线程的,但 rest_init() 在转换为启动空闲线程之前的主要任务是创建两个内核线程:kernel_init(将在下一节讨论)和 kthreadd。可以想见,创建这些内核线程(以及其他类型的线程,从同一进程中的用户线程到真正的进程)依赖于一个复杂的进程管理基础设施。创建新线程的大多数基础设施并不特定于体系结构:如复制 task_struct 结构、凭据,设置调度器等操作通常不需要特定于架构的代码。然而,进程管理代码仍需定义一些架构相关的部分,主要是为每个新线程设置堆栈以及在线程之间进行切换。

Linux always avoids creating new resources from scratch, especially new threads. With the exception of the initial thread (the one that has so far been booting the system and that we have implicitly been discussing), the kernel always duplicates an existing thread and modifies the copy to make it into the desired new thread. The same principle applies after thread creation, when the new thread's execution begins for the first time, as it is easier to resume the execution of a thread than to start it from scratch. This mainly means that the newly allocated stack must be initialized such that when switching to the new thread for the first time, the thread looks like it is resuming its execution—as if it had simply been stopped earlier.
Linux 总是避免从零


网站公告

今日签到

点亮在社区的每一天
去签到