Zhao Jiong; Linux Kernel Full Notes 0.11 revision V3.0

After executing the head.s program in the boot/ directory, the system hands over execution to main.c — including all kernel initialization.

The main c program

  1. Set the system root file device number and some memory global variables according to the system parameters in setup.s.

  1. Hardware initialization: trap gate, block device, character device and TTY, manual setup of the first task;
  2. Open interrupt;
  3. Switch to task 0 — The CPU switches from privilege level 0 to privilege level 3, and the main program of main.c is in task 0. The first call to fork() creates init();

void main(void)		/* This really IS void, no error here. */
{			/* The startup routine assumes (well, ...) this */
/* * Interrupts are still disabled. Do necessary setups, then * enable them */
 	ROOT_DEV = ORIG_ROOT_DEV;
 	drive_info = DRIVE_INFO;
	memory_end = (1<<20) + (EXT_MEM_K<<10);
	memory_end &= 0xfffff000;
	if (memory_end > 16*1024*1024)
		memory_end = 16*1024*1024;
	if (memory_end > 12*1024*1024) 
		buffer_memory_end = 4*1024*1024;
	else if (memory_end > 6*1024*1024)
		buffer_memory_end = 2*1024*1024;
	else
		buffer_memory_end = 1*1024*1024;
	main_memory_start = buffer_memory_end;
#ifdef RAMDISK
	main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
#endif
	mem_init(main_memory_start,memory_end);
	trap_init();
	blk_dev_init();
	chr_dev_init();
	tty_init();
	time_init();
	sched_init();
	buffer_init(buffer_memory_end);
	hd_init();
	floppy_init();
	sti();
	move_to_user_mode();
	if(! fork()) {/* we count on this going ok */
		init();
	}
/* * NOTE!! For any other task 'pause()' would mean we have to get a * signal to awaken, but task0 is the sole exception (see 'schedule()') * as task 0 gets activated at every idle moment (when no other tasks * can run). For task0 'pause()' just means we go check if some other * task can run, and if not we return here. */
	for(;;) pause();
}
Copy the code

Main.c manually moves itself to process 0 and forks () to create process 1 for the first time, calling init() in which the program proceeds with application environment initialization and shell login, while the original process 0 is scheduled to execute when the system is idle. Process 0, also known as idle process, only performs pause system calls and also invokes the scheduling function.

Init () in process 1

  1. Install the root file system.

  2. Display system information;

  3. Run the commands in the rc initial resource configuration file.

  4. Execute user login shell program;

  5. Call the setup() system call to determine whether a virtual disk needs to be created (this is determined at compile time; if it exists, the kernel first tries to load the root file system into the virtual disk area of memory), collect the disk device partition table, and install the root file system;

  6. Init () opens a terminal device, tty0, and copies its file descriptor to produce stdin, stdout, and error stderr devices. The kernel then uses these descriptors to display some system information on the terminal.

  7. The kernel calls /bin/sh to run the commands set in /etc/rc. The kernel executes /bin/sh in a non-interactive manner to execute the commands set in /etc/rc. When the contents of the file are executed, process 2 terminates.

  8. Init () creates a new process, creates a new session in the process, and executes the program /bin/sh again in login shell mode to create a user interaction shell environment, and then the init process waits for the process. The login shell is different from previous non-interactive shells. The first character of the 0th command line parameter of the login shell must be a minus sign, indicating that /bin/sh is run as the login shell. If the user runs exit or logout on the cli, Then the system creates the login shell after displaying a message that the current login shell exits.

Create a new process by copying the code segment and data segment of the parent process. Therefore, in order to ensure that the user state of the new process is not redundant, process 0 should not use its user state stack until the first new process 1 is created. That is, task 0 is required not to call the function. This is done inline.

The user stacks of task 0 and task 1 become independent stacks only after a system call (using the kernel stack of the task instead of the user stack) has been performed from task 1. Since the kernel scheduler runs randomly, it is possible for task 0 to create task 1 and still allow task 0 first. Therefore, the subsequent pause() function after task 0 forks () must be embedded to prevent task 0 from using the user stack before task 1.

When a process in the system has executed execve(), the code and data area of the process will be located in the main memory area of the system, so the system can use COW technology to handle the creation and execution of other new processes.

For Linux, all tasks run in user mode, including many system applications, such as shell programs, network subsystem programs, and so on. The library files in the lib/ directory of the kernel source code are specifically designed to provide support for the newly created processes; the kernel code itself does not use these library functions.

CMOS information

CMOS memory is a battery-powered 64/128 byte block of memory, usually part of the system’s real clock chip RTC, used to store clock and date information, system configuration data.

CMOS’s address space is outside the base address space, so it does not include executable code. It is accessed through ports 0x70(address port), 0x71(data port). To read the byte at the specified offset, you must first send the specified byte’s offset value to address port 0x70 using the OUT instruction, and then read the specified byte information from 0x71 using the IN instruction. Write operations also need to first send the offset of the specified byte to address port 0x70, and then write the data to data port 0x71.

Call fork() to create a new process

Fork () is a system call that copies the current process and creates a new entry in the process table that is almost identical to the original process and executes the same code, but with its own data space and environment parameters. The main purpose of creating a new process is to use the excec() function in the new process to execute different programs.

At the return point of the fork() call, the parent process resumes execution and the child process begins execution. In the parent process, fork() returns the PID of the child process. In the child process, fork() returns 0.

Although the child inherits all of the parent’s resources, the two processes can run concurrently as long as they create programs and data that do not conflict.

The session session period

A program is an executable file, while a process is an instance of an executing program. In the kernel, each process is identified by a different positive integer greater than zero, called the process id PID, and a process can fork() to create one or more child processes that form a process group.

cat main.c | grep for | more

All commands belong to a process group. Each process group has a unique gid. Each process group has a process named group leader whose process ID PID is equal to gid.

A process can join an existing process group or create a new process group by calling setpid().

The most common use of process groups is to use Ctrl+C to terminate all processes in a process group at the same time.

Session period is a collection of one or more process group, usually, the user logged in the execution of all programs belong to a session, and during the period of the login shell session is the first process (session leader), and it is used by the terminal session control terminal, and therefore the session first process is usually referred to as the control process. When we log out, all processes that belong to our session will terminate. The setsid() function is used to set up a new session. A terminal can be used as a control terminal for only one session. The control terminal corresponds to the /dev/tty device file, so if a process needs to access the control terminal, it can read and write to the /dev/tty file directly.


For the 0.11 kernel, as long as the root file system is a MINIX file system, and it contains /etc/rc, /bin/sh, /dev/*, /etc, /dev, /bin, /home, /home/root, it can be the simplest root file system. Get Linux up and running.

The kernel schedules processes by executing sched.c program schedule() and system_call.s clock interrupt process _timer_interrupt. The kernel sets clock interrupt every 10ms. The next state of a process can be determined by calling do_timer() to check the current execution of all processes. During execution, a process can also call sleep_on() to indirectly call schedule() to give up CPU usage.