📄 sched.h
字号:
/** 寻找第1 个TSS 在全局表中的入口。0-没有用nul,1-代码段cs,2-数据段ds,3-系统段syscall* 4-任务状态段TSS0,5-局部表LTD0,6-任务状态段TSS1,等。*/// 全局表中第1 个任务状态段(TSS)描述符的选择符索引号。#define FIRST_TSS_ENTRY 4// 全局表中第1 个局部描述符表(LDT)描述符的选择符索引号。#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)// 宏定义,计算在全局表中第n 个任务的TSS 描述符的索引号(选择符)。#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
// 宏定义,计算在全局表中第n 个任务的LDT 描述符的索引号。#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))// 宏定义,加载第n 个任务的任务寄存器tr。//#define ltr(n) __asm__( "ltr %%ax":: "a" (_TSS(n)))_inline void ltr(unsigned long n)
{
n=_TSS(n);
_asm{
ltr word ptr n
}
}
// 宏定义,加载第n 个任务的局部描述符表寄存器ldtr。//#define lldt(n) __asm__( "lldt %%ax":: "a" (_LDT(n)))_inline void lldt(unsigned long n)
{
n=_LDT(n);
_asm{
lldt word ptr n
}
}
// 取当前运行任务的任务号(是任务数组中的索引值,与进程号pid 不同)。// 返回:n - 当前任务号。用于( kernel/traps.c, 79)。#define str(n) _str((unsigned long)(&(n)))
_inline void _str(unsigned long n)
{ _asm{
xor eax,eax
str ax /* 将任务寄存器中TSS 段的有效地址 -> ax*/
sub eax,FIRST_TSS_ENTRY*8 /* (eax - FIRST_TSS_ENTRY*8) -> eax*/
shr eax,4 /* (eax/16)->eax = 当前任务号*/
mov ebx,n
mov [ebx],eax
}}
/*#define str(n) \
__asm__( "str %%ax\n\t" // 将任务寄存器中TSS 段的有效地址->ax \
"subl %2,%%eax\n\t" // (eax - FIRST_TSS_ENTRY*8)->eax \
"shrl $4,%%eax" // (eax/16)->eax = 当前任务号。 \
: "=a" (n):"a" (0), "i" (FIRST_TSS_ENTRY << 3))
*/
/** switch_to(n)将切换当前任务到任务nr,即n。首先检测任务n 是不是当前任务,* 如果是则什么也不做退出。如果我们切换到的任务最近(上次运行)使用过数学* 协处理器的话,则还需复位控制寄存器cr0 中的TS 标志。*/// 输入:%0 - 新TSS 的偏移地址(*&__tmp.a); %1 - 存放新TSS 的选择符值(*&__tmp.b);// dx - 新任务n 的选择符;ecx - 新任务指针task[n]。// 其中临时数据结构__tmp 中,a 的值是32 位偏移值,b 为新TSS 的选择符。在任务切换时,a 值// 没有用(忽略)。在判断新任务上次执行是否使用过协处理器时,是通过将新任务状态段的地址与// 保存在last_task_used_math 变量中的使用过协处理器的任务状态段的地址进行比较而作出的。extern _inline void switch_to(int n)
{ unsigned short __tmp;
__tmp = (unsigned short)_TSS(n);
_asm {
mov ebx, offset task
mov eax, n
mov ecx, [ebx+eax*4]
cmp ecx, current/* 任务n 是当前任务吗?(current ==task[n]?) */
je l1 /* 是,则什么都不做,退出。*/
xchg ecx,current/* current = task[n]; */
/*执行长跳转,造成任务切换 (头大了很长时间,多多包涵)*/
mov ax, __tmp
mov word ptr ds:[lcs],ax
_emit 0xea
_emit 0 // ip
_emit 0
_emit 0
_emit 0
lcs: _emit 0 // cs
_emit 0
// 在任务切换回来后才会继续执行下面的语句。
cmp last_task_used_math,ecx /* 新任务上次使用过协处理器吗?*/
jne l1
clts/* 新任务上次使用过协处理器,则清cr0 的TS 标志。*/
}
l1: ;
}
/*#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__( "cmpl %%ecx,_current\n\t" \ "je 1f\n\t" \ "movw %%dx,%1\n\t" \ "xchgl %%ecx,_current\n\t" \ 。 "ljmp %0\n\t" \ 。// 在任务切换回来后才会继续执行下面的语句。 "cmpl %%ecx,_last_task_used_math\n\t" \ "jne 1f\n\t" \ "clts\n" \ "1:"::"m" (*&__tmp.a), "m" (*&__tmp.b), "d" (_TSS (n)), "c" ((long) task[n]));}*/// 页面地址对准。(在内核代码中没有任何地方引用!!)#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000)// 设置位于地址addr 处描述符中的各基地址字段(基地址是base),参见列表后说明。// %0 - 地址addr 偏移2;%1 - 地址addr 偏移4;%2 - 地址addr 偏移7;edx - 基地址base。extern _inline
void _set_base(unsigned short *addr,unsigned long base)
{
/* addr[1] = base;
((char*)addr)[4] = base >> 16;
((char*)addr)[7] = base >> 8;*/
_asm mov ebx,addr
_asm mov edx,base
_asm mov word ptr [ebx+2],dx // 基址base 低16 位(位15-0)->[addr+2]。
_asm ror edx,16 // edx 中基址高16 位(位31-16) -> dx。
_asm mov byte ptr [ebx+4],dl // 基址高16 位中的低8 位(位23-16)->[addr+4]。
_asm mov byte ptr [ebx+7],dh // 基址高16 位中的高8 位(位31-24)->[addr+7]。
}
/*
__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")
*/// 设置位于地址addr 处描述符中的段限长字段(段长是limit)。// %0 - 地址addr;%1 - 地址addr 偏移6 处;edx - 段长值limit。extern _inline void _set_limit(unsigned short *addr,unsigned long limit)
{
/* addr[0] = limit;
((char*)addr)[6] = ((char*)addr)[6] & 0xf0 + (limit >> 16) & 0x0f;*/
_asm mov ebx,addr
_asm mov edx,limit
_asm mov word ptr [ebx],dx // 段长limit 低16 位(位15-0)->[addr]。
_asm ror edx,16 // edx 中的段长高4 位(位19-16)->dl。
_asm mov dh,byte ptr [ebx+6] // 取原[addr+6]字节->dh,其中高4 位是些标志。
_asm and dh,0f0h // 清dh 的低4 位(将存放段长的位19-16)。
_asm or dl,dh // 将原高4 位标志和段长的高4 位(位19-16)合成1 字节,
_asm mov byte ptr [ebx+6],dl // 并放回[addr+6]处。
}
/*#define _set_limit(addr,limit) \
__asm__( "movw %%dx,%0\n\t" \ "rorl $16,%%edx\n\t" \ "movb %1,%%dh\n\t" \ "andb $0xf0,%%dh\n\t" \ "orb %%dh,%%dl\n\t" \ "movb %%dl,%1" \ ::"m" (*(addr)), "m" (*((addr) + 6)), "d" (limit):"dx")*/
// 设置局部描述符表中ldt 描述符的基地址字段。#define set_base(ldt,base) \
_set_base( ((unsigned short *)&(ldt)), (unsigned long)(base) )// 设置局部描述符表中ldt 描述符的段长字段。#define set_limit(ldt,limit) \
_set_limit( ((unsigned short *)&(ldt)), (unsigned long)((limit)-1)>>12 )
// 取局部描述符表中ldt 所指段描述符中的基地址。
#define get_base(ldt) _get_base( ((void *)&(ldt)) )
// 从地址addr 处描述符中取段基地址。功能与_set_base()正好相反。// edx - 存放基地址(__base);%1 - 地址addr 偏移2;%2 - 地址addr 偏移4;%3 - addr 偏移7。extern _inline unsigned long _get_base(void *addr)
{
// unsigned long __base;
_asm {
_asm mov ebx,addr
_asm mov ah,byte ptr [ebx+7] // 取[addr+7]处基址高16 位的高8 位(位31-24)->dh。
_asm mov al,byte ptr [ebx+4] // 取[addr+4]处基址高16 位的低8 位(位23-16)->dl。
_asm shl eax,16 // 基地址高16 位移到edx 中高16 位处。
_asm mov ax,word ptr [ebx+2] // 取[addr+2]处基址低16 位(位15-0)->dx。
// _asm mov __base,eax
}
// return __base;
}
/*unsigned long __base; \__asm__( "movb %3,%%dh\n\t" \ "movb %2,%%dl\n\t" \ "shll $16,%%edx\n\t" \ "movw %1,%%dx" \ :"=d" (__base) \ // 从而edx 中含有32 位的段基地址。:"m" (*((addr) + 2)), "m" (*((addr) + 4)), "m" (*((addr) + 7))); \__base; \})
*/// 取段选择符segment 的段长值。// %0 - 存放段长值(字节数);%1 - 段选择符segment。extern _inline unsigned long get_limit(unsigned long segment) {
// unsigned long __limit;
_asm {
mov eax,segment
lsl eax,eax
// mov __limit,eax
}
// return __limit;
}
/*unsigned long __limit; \__asm__( "lsll %1,%0\n\tincl %0": "=r" (__limit): "r" (segment)); \__limit;})*/
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -