?? 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 + -