free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
首先看下他调用的参数。
1、get_base(current->ldt[1])和get_base(current->ldt[2])
A.get_base()函数的定义:
#define get_base(ldt) _get_base( ((char *)&(ldt)) );
_get_base的代码如下:
#define _get_base(addr) ({\
unsigned long __base; \
__asm__(
//将基地址的24-31位保存在dh中
"movb %3,%%dh\n\t" \
//将基地址的16-23位保存在dl中
"movb %2,%%dl\n\t" \
//将edx的内容左移16位
//也就是将基地址的16-31位保存在edx的高16位中
"shll $16,%%edx\n\t" \
//将基地址的0-15位保存在dx
//也就是 edx的低16位中
"movw %1,%%dx" \
//将返回值保存在_base中
:"=d" (__base) \
//使用内存变量偏移2个字节作为%1
//也就是基地址的0-15位
:"m" (*((addr)+2)), \
//使用内存变量偏移4个字节作为%2
//也就是基地址的16-23位
"m" (*((addr)+4)), \
//使用内存变%E)��偏移7个字节作为%3
//也就是基地址的24-31位
"m" (*((addr)+7))); \
__base;})
因此get_base函数的作用就是取出段选择符指向的段描述符中的段基址。
B.current->ldt[1]
根据kernel/sched.c中的定义:struct task_struct *current=&(init_task,task);
而task_struct的定义:
struct task_struct {
long state;
long counter;
long priority;
long signal;
struct sigaction sigaction[32];
long blocked;
int exit_code;
unsigned long start_code,end_code,end_data,brk,start_stack;
long pid,father,pgrp,session,leader;
unsigned short uid,euid,suid;
&nbs`; unsigned short gid,egid,sgid;
long alarm;
long utime,stime,cutime,cstime,start_time;
unsigned short used_math;
int tty;
unsigned short umask;
struct m_inode * pwd;
struct m_inode * root;
struct m_inode * executable;
unsigned long close_on_exec;
struct file * filp[NR_OPEN];
struct desc_struct ldt[3];
struct tss_struct tss;
};
因此current->ldt[1]和current->ldt[2]分别指向当前任务的代码段CS局部表描述符和数据堆栈段DS&SS局部表描述符。
2、get_limit(0x0f)和get_limit(0x17)
#define get_limit(segment) ({ \
unsigned long __limit; \
__asm__(
//lsll为加载段界限的指令
//即把segment段描述符中的段界限字段装入寄存器
//这里指把segment所指的段选择符中的段限界字段装载到%0寄存器中
"lsll %1,%0\n\t"
//将段限界+1,因为0代表1B
"incl %0\n\t"
//将返回值存放在_limit中
:"=r" (__limit)
//将segment 作为参数
:"r" (segment));
__limit;})\
参数segment是段选择符,get_base函数的作用就是取得segment指向的段描述符中的Limit段限长。
而段选择符的结构前面已经看过。由三个部分组成Index(15-3)+TI(2)+RPL(1-0)。其中Index为段描述符在描述符表中的索引值,TI标志指向的描述符表,RPL标志优先级。
这里采用的两个参数0x0f即1111B,因此他指向的段优先级为3,存储在LDT表中,索引为1。也就是当前任务段的代码段描述符。
另外一个参数0x17即10111B,因此他指向的段优先级为3,存储在LDT表中,索引为2.也就是当前任务的数及堆栈段描述符。
这样,通过get_limit(0x0f)和get_limit(0x17)就得到了当前任务代码段和数据堆栈段的长度。
因此,
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));就释放了当前任务的代码段和数据堆栈段。