Linux0.11 startup and initialization

Source: Internet
Author: User

The startup and initialization processes of linux0.11 are described in brief. When starting, you need to pay attention to the following data: IDT, GDT, LDT, TSS, page table, and stack. I. The code file for starting the startup process is bootsect. s, setup. s, head. s bootsect. s, that is, the code for starting the sector. This code mainly reads the content in setup. s and head. s into the corresponding area of the memory. Then run setup. s setup. s1: Use BIOS interruption to obtain related system information: memory size, hard disk partition information, display card information 2: Set head. s code is copied to the place where the memory address is 0X0000. 3: load the idt table and gdt table address 4: Enable the A20 address line. Only after enabling it can access the memory above 1 M address 5: reset the interrupt controller. After that, the previous BIOS interrupt number is useless. 6: Set the last digit of the CR0 register to the protection mode, and then use the jmpi 0 and 8 commands to jump to the address 0x08: 0x0000 to start execution, that is, head. s. All the idt tables set here are empty, that is, they do not process any interruptions. The gdt table has three descriptors: 0--NULL, 1 -- kernel code segment, and 2 -- kernel data segment descriptor. At this time, the kernel code segment and kernel data segment: The base address is 0x00000000, and the limit is 8 MB head. s1: Set the stack to static_stack. The stack size is 1 kb2: reset the IDT and GDT. At this time, all IDT are set to ignore_int, which means the interruption is ignored. GDT contains 256 descriptors. 0--NULL, 1 -- kernel code segment, 2 -- kernel data segment, 3 -- reserved, 4 -- TSS segment of process 0, 5 -- LDT segment of process 0, 6 -- TSS segment of process 1, 7 -- LDT segment of process 1 ...... the system sets a TSS and LDT segment for each process in GDT. Kernel code segment and kernel data segment: base address (0x00000000), limited length (16 MB) 3: Set the page (because the memory management part is not seen currently, therefore, we do not understand how to set the page table of the process. Here is the kernel page table.) store the "page Directory" on the first page at 0x00000000, and then four "page tables ", each page table corresponds to an item in the page Directory. The linear address must be equal to the physical address. The four page tables can map 16 MB physical space, so the 16 MB physical memory address is the same as the linear address. (The 0.11 kernel does not have PAGE_OFFSET) 4: Start to execute the main function in init/main. c. The method is as follows: pushl $ _ main # import the main function address to the stack jmp setup_paging # Start pagination ...... setup_paging :....... ret # After the paging is complete, use the ret command to pop up the main function entry address in the stack and start to execute the main function. It seems that this pop-up stack method is often used in kernel code to execute other function 2: After the main function is set to GDT and page table during startup, it starts to set other content in the main function. Mainly: Set IDT, device initialization, create process 0, fork output process 1, use process 1 to execute init main. the main initialization functions in c are: trap_init. In sched_inittrap_init, set_trap_gate is called to set the Interrupt Descriptor Table. The following example describes the implementation process of the 0 interrupt: 1. Call the macro set_trap_gate (0, & divide_error) to set the trap gate descriptor for the 0th items in the IDT table. # Define set_trap_gate (n, addr) _ set_gate (& idt [n], 15, 0, addr) in _ set_gate: & idt [n] indicates the address of the nth descriptor, 15 indicates the descriptor type (trap gate), and 0 indicates the descriptor permission (highest permission ), addr is the address of the Code to be called. The _ set_gate macro calls the corresponding Assembly command and writes an 8-byte descriptor AT & idt [n. 2: Implementation of divide_error this function is implemented in the form of assembly code. Corresponding to this function, there is a processing function do_divide_error (implemented in C Language). This is also true for most of the other traps. There is an assembly method and a C-language processing function. When the interrupt 0 occurs, call divide_error first. This function then calls do_divide_error. Void do_divide_error (long esp, long error_code) is a function prototype. The first parameter is the pointer to the Code address when an error occurs, and the second parameter is the error code. (If some interrupts do not generate error codes, the error code is set to 0.) In the divide_error assembly code, the main function is to pass the pointer and error code parameters of the error address to the do_divide_error function, set the current data segment to the kernel data segment. Sched_init function this function sets the TSS and LDT descriptors of process 0, and loads their selection sub into the TR and LDTR registers. In addition, this function sets the clock interruption and system call. Here we mainly describe the execution of the system call. The fork function is used as an example. 1: Initialize the system call set_system_gate (0x80, & system_call) # define set_system_gate (0x80, & system_call) _ set_gate (& idt [n], 15, 3. addr) it can be seen that system calling is also a trap. The difference is that the permission value is 3, so the user process can enter the kernel through the int 0x80 interrupt and execute the system call. 2: Each system call has a corresponding number. fork is the second system call, so fork's call number is 2. When the fork function is executed, it uses int 0x80 to call the system_call function. The call number of fork is put into the eax register. 3: All system call function pointers are saved in the array sys_call_table. In the system_call function, the command call _ sys_call_table (, % eax, 4) is executed to jump to the system function code specified by eax. fork is the sys_fork function. 4: system_calli) system_call first puts the corresponding register into the stack. Pushl % edxpushl % ecxpushl % ebx these three registers correspond to the three parameters of the function called by the system. Therefore, in 0.11, the system function can have up to three parameters. Ii) set ds and es to the kernel data segment and fs to the Data Segment of the user process. When user process data is required, use fs to access iii) use call _ sys_call_table (, % eax, 4) to execute system call iii) check whether the current process is executable, check whether the time slice of the current process is used up, and execute scheduleiv accordingly) finally, process signal processing. (Signal mechanism not completed) 3: after entering the user State in the initialization of the main function, main enters the user State as the process 0. Call the fork function, create process 1, and process 1 call the init function of the init function to load the root file system, run the Initialization Configuration command, and then run the shell program. Then, the command line window is displayed. In the 0.11 kernel, each process has a TSS segment and an LDT segment, which are stored in the strut task_struct structure of the process descriptor. The descriptor of the corresponding segment is saved in the GDT table. In the LDT segment, there are three LDT descriptors, 0--NULL, 1 -- Process Code segment, and 2 -- process data segment. Process n code segment and Data Segment: base address = n * 64 MB, limit = 64 MB. (The limit of process 0 and 1 is 640KB). Therefore, the maximum number of processes in the system is 64. The task_struct of process 0 is INIT_TASK, And the TSS and LDT descriptor of process 0 are set in sched_init. The main function calls the move_to_user_mode function to Execute Process 0 and enter the user State. 0.11 all processes in the kernel belong to the user State, unlike kernel threads in the Linux Kernel later. Move_to_user_mode function this function uses the method returned by iret to enter the user State from the kernel state. + ------------ ++ Ss + pushl $0x17 + ------------ ++ esp + pushl % eax # The esp + ------------ ++ eflags + pushfl + ---------- ++ cs + pushl $ 0x0f + ------------ ++ eip + pushl $ 1f # offset address of the target code + ------------ + use the above push command first, press related data into the stack and execute iret to bring them up. Therefore, process 0 starts to execute the code directed to cs: eip in the stack. 4. fork function process 0: Execute the fork function to create a process. 1.1: Call get_free_page to allocate memory for the process descriptor. P = (struct task_struct *) get_free_page (); memory for this page. The task_struct memory is saved in front of the page. The page ends with the kernel stack of the process. When a user program calls the system function to enter the kernel state, this is the stack used for system function execution. 2: Set the task_struct struct of the process. 3. Copy the memory of the parent process to the new process. 4: the most important thing about fork in setting the TSS and LDT descriptor of a new process in gdt is to figure out why it can be "Returned" twice. 1: When fork is called, the CPU automatically puts the return address of the parent process into the stack (that is, the eip register is in the stack) 2: After the task_struct of the child process is created, set the eax field in the TSS segment to 0 and the eip field to the return address of the parent process. 3: Set the sub-process status to TASK_RUNNING (ready state) 4: The fork function returns the sub-process pid. 5: Wait Until schedule is executed and scheduled to the sub-process. The TSS content of the sub-process is automatically loaded into the register. Therefore, the eax register value in the CPU is 0, and the eip is the return address of the parent process. Therefore, the sub-process starts to execute from the next instruction of the fork function. The returned value is 0 in eax.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.