The main function mainly does some initialization, such as the initialization of memory, block devices, character devices, etc., and then creates a child process to open bin/sh
mem_init(main_memory_start,memory_end);
trap_init(); // Initialize the trap gate (hardware interrupt vector). (Kernel/traps.c)
blk_dev_init(); // Block device initialization. (Kernel/blk_dev/ll_rw_blk.c)
chr_dev_init(); // Character device initialization. (Kernel/chr_dev/tty_io.c) is empty to prepare for future expansion.
tty_init(); // tty initialization. (Kernel/chr_dev/tty_io.c)
time_init(); // Set startup time -> startup_time.
sched_init(); // Scheduler initialization (loaded tr, ldtr of task 0) (kernel/sched.c)
buffer_init(buffer_memory_end); // Initialize buffer management, build memory linked list, etc. (Fs/buffer.c)
hd_init(); // Initialize the hard disk. (Kernel/blk_dev/hd.c)
floppy_init(); // Initialize the floppy drive. (Kernel/blk_dev/floppy.c)
Create task 1 in task 0
if (!fork()) { /* we count on this going ok */
init();
}
init function: initialize the shell environment, execute bin/sh
void init(void)
{ int pid,i;
// Read hard disk parameters including partition table information and create virtual disks and install root file system devices.
// This function is defined by the macro on line 25, and the corresponding function is sys_setup(), in kernel/blk_drv/hd.c.
setup((void *) &drive_info);
(void) open("/dev/tty0",O_RDWR,0); // Open the device "/dev/tty0" with read-write access,
// here corresponds to the terminal console.
// The returned handle number 0 - stdin standard input device.
(void) dup(0); // Duplicate the handle and generate handle No. 1 - stdout standard output device.
(void) dup(0); // Duplicate the handle and generate handle No. 2 - stderr standard error output device.
printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, \
NR_BUFFERS*BLOCK_SIZE); // Print buffer blocks and total bytes, 1024 bytes each.
printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);//The number of free memory bytes.
// The following fork() is used to create a subprocess (subtask). For the created child process, fork() will return a value of 0,
// for the original (parent process) it will return the process number of the child process. So if (!(pid=fork())) {...} is the content executed by the child process.
// The child process closes handle 0 (stdin), opens the /etc/rc file in read-only mode, and executes the /bin/sh program. The parameters and
// environment variables are given by the argv_rc and envp_rc arrays respectively. See the description below.
if (!(pid=fork())) { close(0); if (open("/etc/rc",O_RDONLY,0)) _exit(1); // If opening the file fails, exit (/lib /_exit.c). execve("/bin/sh",argv_rc,envp_rc); // Load the /bin/sh program and execute it. (/lib/execve.c) _exit(2); // If execve() fails to execute, exit (error code 2, "File or directory does not exist"). }
// Below is the statement executed by the parent process. wait() is to wait for the child process to stop or terminate, and its return value should be the child process
// process number (pid). The function of these three sentences is that the parent process waits for the end of the child process. &i is the
// location where the returned status information is stored . If the return value of wait() is not equal to the child process number, continue to wait.
if (pid>0)
while (pid != wait(&i))
{/* nothing */;}
// -
// If the execution ends here, it means that the execution of the newly created child process has stopped or terminated. In the following loop, first create
a child process. If an error occurs, the message "The initialization program failed to create the child process" will be displayed and the execution will continue. To
// create a child process to close all previously also left handle (stdin, stdout, stderr), a newly created
// session and set process group number, and then re-open / dev / tty0 as stdin, stdout and copy to And stderr.
// Execute the system interpreter /bin/sh again. However, another set of parameters and environment arrays were selected for this execution (see above).
// Then the parent process runs wait() again to wait. If the child process stops executing again, an error message is displayed on the standard output
// "The child process pid stopped running, the return code is i",
// and then continue to try again..., forming a "big" endless loop.
while (1) { if ((pid=fork())<0) { printf("Fork failed in init\r\n"); continue; } if (!pid) { close(0);close(1) ;close(2); setsid(); (void) open("/dev/tty0",O_RDWR,0);
(void) dup(0);
(void) dup(0);
_exit(execve("/bin/sh",argv,envp));
}
while (1)
if (pid == wait(&i))
break;
printf("\n\rchild %d died with code %04x\n\r",pid,i);
sync();
}
_exit(0); /* NOTE! _exit, not exit() */
}