提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
在B栈有李治军老师的视频:操作系统(哈工大李治军老师)32讲(全)超清
其中李老师讲的是Linux0.11源码
linux 0.11源码(含注释)—无需积分:https://blog.csdn.net/m0_37984066/article/details/108881812
BIOS系统服务 —— 直接磁盘服务(int 0x13):https://blog.csdn.net/cherisegege/article/details/79835737
《Linux内核设计的艺术》学习笔记(五)INT 0x10中断:https://www.bbsmax.com/A/A2dmMxjbde/
实验二:
https://codetd.com/ja/article/13499331
提示:以下是本篇文章正文内容,下面案例可供参考
一、IDT中断描述符表
IDT 表中可以存放三种类型的门描述符:
- 中断门描述符
- 陷阱门描述符
- 任务门描述符
#define _syscall3(type, name, atype a, btype, b, ctype c) \
type name(atype a, btype b, ctype c) \
{ long __res; \
__asm__ volatile("int 0x80":"=a"(__res):""(__NR_##name), \ /* "=a"(__res)表明输出__res = %eax,""(__NR_##name)表明输入movl __NR_##name, %eax */
"b"((long)(a)), \ /* 输入: movl a, %ebx,a即为atype a */
"c"((long)(b)), \ /* 输入: movl b, %ecx,b即为btype b */
"d"((long)(c))); \ /* 输入: movl c, %edx,c即为ctype c */
if (__res >= 0) \
return (type)__res; \
errno = -__res; \
return -1; \
}
32位cpu的系统调用:
- %eax表用系统调用表序号,unistd.h
- 传递参数使用寄存器的顺序:%ebx, %ecx, %edx, %esi,%edi;多于5个参数使用其他方式传递
对于write系统函数调用,宏展开后为:
/* 0ff_t表示文件偏移量,一般是long类型 */
int write(int fd, const char *buf, off_t count)
{
long __res;
__asm__ volatile("int 0x80":"=a"(__res):""(__NR_##write), \/* 在32位CPU中宏__NR_write等于4,64为CPU中__NR_write等于1 */
"b"((long)(fd)), \
"c"((long)(buf)), \
"d"((long)(count)));
......
}
int 0x80中断的处理
void sched_init(void)
{
set_system_gate(0x80, &system_call);
......
显然,set_system_gate用来设置0x80的中断处理
在linux/include/asm/system.h中
#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ ("movw %%dx,%%ax\n\t" \
"movw %0,%%dx\n\t" \
"movl %%eax,%1\n\t" \
"movl %%edx,%2" \
: \
: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ // %0, "i":输入
"o" (*((char *) (gate_addr))), \ // %1,"o":输出
"o" (*(4+(char *) (gate_addr))), \ // %2,"o":输出
"d" ((char *) (addr)), \// %3,"d":%edx初始值
"a" (0x00080000)) // %4,"a":%eax初始值
#define set_system_gate(n, addr) _set_gate(&idt[n],15,3,addr)
汇编注释:
- mov :为寄存器移动指令,例如movw dx,ax 即为dx-〉ax,mov为移动指令。“w”为长度的指定w=word=16位=2个字节;相应的“l”=long=32位=4字节。
- % :AT&T汇编在引用寄存器时要在前面加1个%,%%是因为GCC在编译时会将%视为特殊字符,拥有特殊意义,%%仅仅是为了汇编的%不被GCC全部转译掉
- ax 与 eax :ax与eax之间是有联系的,他们并不是孤立的,eax为32位寄存器,ax为16位寄存器,而ax就是eax的低16位。dx与edx具有相同的关系。
- %0、%1、%2、%3:0、1、2、3可以看作变量,这些变量在程序的":“之后,程序的两个”:",是定义输入、输出项的。针对这段程序这些变量的前面都加了明确的限定,例如"i"(输入项)、“o”(输出项),剩下的"d"(edx的初始值),“a”(eax的初始值)。而0、1、2、3的概念就是指第几个变量,这里输入项、输出向、寄存器初始混合编号;相应的0(“i”((short)(0x8000+(dpl<<13)+(type<<8)))));1((*((char )(gate_addr))));2(((4+(char *)(gate_addr))));3(“d”((char *)(addr)));4(“a”(0x00080000))
- <<:这是个运算符,如果大家觉得<<不好理解可以用乘2的次方来实现相同的效果,例如14<<13=14*2的13次方
- \n\t:这是嵌入式汇编一种书写格式