Set the Page Management of Process 1

Một phần của tài liệu The art of linux kernel design (Trang 113 - 118)

3. Creation and Execution of Process 1 85

3.1.4 Set the Page Management of Process 1

The paging mechanism in the architecture of Intel 80x86 is based on the protection mode, which means pe should be opened before opening pg. Since the protection mode is based on segment, setting the segments of process 1 should be done before setting the page management.

The page that task_struct of process 1 resides

ROM BIOS and VGA

Kernel

Enable interrupt

0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF

task_struct of process 1

The page that task_struct of process 1 resides

Process status

Adjust every management number of process 1

Process 0 Process 1

Uninterruptible Ready

Current process

After copying task_struct of process 1 Before copying task_struct of process 1

Figure 3.6 Adjusting the task_struct of process 1.

Generally speaking, each process has to load its own code and data, of which the addressing mode is the algorithm of segment address plus offset, namely, the logical address. The hardware will automatically convert the logical address to the linear address, which will be converted automatically again to the physical address in pages, according to the settings of the page directory table and page table. Through this technical route, the OS sets the code and data segment in the 64 MB linear address space of process 1 and then in the page directory table and page table.

3.1.4.1 Set the Code Segment and Data Segment in the Linear Address Space of Process 1

By calling copy_mem(), the system sets the segment base address and segment limit length of the segment and data segment of process 1 at first. Extract information on the code segment, data segment, and segment limit length of the current process (process 0);

meanwhile, set the base address of the segment and data segment of process 1, which is its process number, nr*64MB, and set the base address in the segment descriptor in the local descriptor tables of the new process. It is shown as the first step in Figure 3.7.

The code is as follows:

//Code path:kernel/fork.c:

int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, long ebx,long ecx,long edx,

long fs,long es,long ds, //

long eip,long cs,long eflags,long esp,long ss) {

……

if (last_task_used_math == current)

__asm__(“clts ; fnsave%0”::“m” (p->tss.i387));

if (copy_mem(nr,p)) { //set code segment and data segment of child process, //create and copy the first page

//table of child process

task[nr] = NULL; //now this situation doesn’t happen free_page((long) p);

return -EAGAIN;

}

for (i = 0; i<NR_OPEN;i++) //reference count of file corresponding to parent //process is plused by 1

//showing that parent and child process share the //same file

……

}

//Code path:include/linux/sched.h:

……

#define _set_base(addr,base) \ //set addr by base.Referring to 2.9.1 __asm__(“movw%%dx,%0\n\t” \

“rorl $16,%%edx\n\t” \

“movb%%dl,%1\n\t” \

“movb%%dh,%2” \ ::“m” (*((addr)+2)), \

“m” (*((addr)+4)), \

“m” (*((addr)+7)), \

“d” (base) \ :“dx”)

……

#define set_base(ldt,base) _set_base(((char *)&(ldt)), base)

……

#define _get_base(addr) ({\ //obtain base address addr. Referring to _set_base //and 2.9.1

unsigned long __base; \ __asm__(“movb%3,%%dh\n\t” \

“movb%2,%%dl\n\t” \

“shll $16,%%edx\n\t” \

“movw%1,%%dx” \ :“=d” (__base) \ :“m” (*((addr)+2)), \

“m” (*((addr)+4)), \

“m” (*((addr)+7))); \ __base;})

Kernel

Enable interrupt

0 64M 128M 192M 256M

Step 1:

set base address of code segment and data segment

Step 2: copy page table Step 3: set page directory item

CPU 4G-1

Segment limit: 640 K

0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF

16 0 159 1023

0 159 1023

task_struct of process 1

The page that task_struct of process 1 resides ROM BIOS

and VGA

Page table Page table Page table

Page table

Page table 1 page directory table

4 page tables

Page table of process 0:

the first 160 items valid

Step 4:

flush TLB cache

Process status

Process 0 Process 1

Uninterruptible Ready

Before setting page directory and page table of process 1 After setting page directory and page table of process 1 Current process

Pagedirectory Page table

0 159 1023

Figure 3.7 Set the linear address space of process 1.

3.1.4.2 Create the First Page Table for Process 1 and Set the Corresponding Page Directory Entry

In Linux 0.11, when the program code of every process is executed, its address needs to be specified based on its linear address and it needs to be mapped to the physical memory.

As shown in Figure 3.8, the linear address is 32 bits and the CPU parses this address into

#define get_base(ldt) _get_base(((char *)&(ldt)))

#define get_limit(segment) ({\

unsigned long __limit; \

__asm__(“lsll%1,%0\n\t //obtain segment limit length and pass it to __limit incl%0”

:“=r” (__limit) :“r” (segment)); \ __limit;})

//Code path:kernel/fork.c:

int copy_mem(int nr,struct task_struct * p)//set code segment and data segment of child //process, create and copy the first table of // child process

{

unsigned long old_data_base,new_data_base,data_limit;

unsigned long old_code_base,new_code_base,code_limit;

//obtain limit length of code and data segment of child process

code_limit = get_limit(0x0f); //0x0f is 1111:code segment, ldt, 3 privilege level data_limit = get_limit(0x17); //0x17 is 10111:data segment, ldt, 3 privilege level //obtain base address of code and data segment of parent process(Process 0) old_code_base = get_base(current->ldt[1]);

old_data_base = get_base(current->ldt[2]);

if (old_data_base ! = old_code_base)

panic(“We don’t support separate I&D”);

if (data_limit < code_limit) panic(“Bad data_limit”);

new_data_base = new_code_base = nr * 0x4000000; //now nr is 1, 0x4000000 means 64MB p->start_code = new_code_base;

set_base(p->ldt[1],new_code_base); //set base address of code segment of child //process

set_base(p->ldt[2],new_data_base); //set base address of data segment of child //process

if (copy_page_tables(old_data_base,new_data_base,data_limit)) { free_page_tables(new_data_base,data_limit);

return -ENOMEM;

} return 0;

}

Linear address Page directory item

Page directory item

Page table item

Page table item

CR3

Page directory table Page table Page

The physical address mapped

31 22 21 12 11 0

Page offset

Figure 3.8 Mapping process from linear address to physical address.

three parts: page directory entry, page table entry, and offset within page. The page direc- tory entry is in the page directory table and is used to manage the page table. The page table entry is in the page table and is used to manage the page and ultimately find the spec- ified address in the physical memory. There is only one page directory table in Linux 0.11.

We can find the corresponding page directory entry in the page directory table based on the data “page directory entry” provided by the linear address. Then, find the correspond- ing page table entry in the page table according to the data “page table entry” provided by the linear address. Then, find the corresponding physical page according to this page table item. Finally, find the actual value of the physical address based on the data “offset within page” provided by the linear address.

Calling the function copy_page_tables, setting the page directory table, and copying the page table are as shown in the second and third steps in Figure 3.7. The position where the page directory entry lies should be noticed.

The code is as follows:

Entering the function copy_page_tables, apply a free page for the new page table at first and copy the first 160 page table items in the first page table of process 0 to this page (1 page table entry manages a memory space of about 4 KB of a page, and 160 page table items manage a memory space of about 640 KB). Then, both process 0 and process 1 point to the same page, meaning that process 1 can manage the page of process 0. After that, set the page directory table of process 1. Last, refresh page transforming cache by resetting CR3. The setting of the page table and page directory table of process 1 is completed.

The code is as follows:

//Code path:kernel/fork.c:

int copy_mem(int nr,struct task_struct * p) {

……

set_base(p->ldt[1],new_code_base); //set base address of code segment of child //process

set_base(p->ldt[2],new_data_base); //set base address of data segment of child //process

//create first page table and copy page table of Process 0 for Process 1. Set page //directory entry of Process 1

if (copy_page_tables(old_data_base,new_data_base,data_limit)) { free_page_tables(new_data_base,data_limit);

return -ENOMEM;

} return 0;

}

//Code path:mm/memory.c:

……

#define invalidate() \

__asm__(“movl%%eax,%%cr3”::“a” (0)) //reset CR3 as 0

……

int copy_page_tables(unsigned long from,unsigned long to,long size) {

unsigned long * from_page_table;

unsigned long * to_page_table;

unsigned long this_page;

Now, process 1 is empty, and its page tables are copied from process 0. Hence, they have the same page and share the same managing structure of memory page temporarily, as shown in Figure 3.9.

When process 1 has its programs, the relation will be ceased and process 1 organizes its managing structure of memory.

Một phần của tài liệu The art of linux kernel design (Trang 113 - 118)

Tải bản đầy đủ (PDF)

(524 trang)