实现自己的操作系统 第三部分
2008-03-31 12:59
549 查看
3-1
2006-1-9 23:43
实现了和C函数的整合。
ld -Ttext org之后的obj的顺序似乎有讲究。
call 命令对堆栈的影响:
16位的实模式中,会将cs和ip压栈,因此栈会减少4。
32位的保护模式中,如果是段内调用,只会将eip压栈;如果是段间调用,会将eip和cs入栈,不过目前还没遇到过这种情况。
C函数调用约定
参数从右向左入栈,在汇编中等调用完后,要手动将esp的值复位。
返回值是4字节时,通过eax传递;2字节通过ax传递;1字节通过al传递。
3-2
2006-1-12 23:47
将光标的行列值改成了全局变量。
在汇编中如果入栈一个符号变量,那入栈的会是指向这个变量的指针。
但在C语言中调用汇编中声明的全局变量时,得到的是这个变量本身而不是其指针。
汇编中用global声明全局变量时,应把该global声明放在它相应的data或bss段中。
3-3
2006-1-14 03:19
实现了中断函数的初始化。
中断函数和函数是不同的概念。
后者可以直接调用,而前者不能。
从汇编层次看,数组和指针是不一样的。
比如:
汇编:
global g_idtr
g_idtr:
%rep 256
dd 0
dd 0
%endrep
C语言中,如果如下声明:
extern long long g_idtr[256];
则可以正常操作。
但是如果使用
extern long long * g_idtr;
那么程序会出错。
究其原因,当使用的是指针时,程序会分配一个空间保存该指针本身的值,而当使用数组时,则不将此标号作为变量另外保存。
3-4
2006-1-14 23:28
实现了部分printf的功能,能够分辨%d和%x。
还没有在其中实现系统调用、/n/t、光标跟随移动等。
实现了一些字符串函数。
3-5
2006-1-15 23:01
完善了printf,当前拥有的功能包括
/t /n %x %d
已经能获取内存信息,目前暂不添加内存映射。
3-6
2006-1-16 22:03
完善了中断函数。
general_intr.c中的宏定义和中断的实现是值得好好研究的。
3-7
2006-1-17 20:38
操作了8259,实现了一个时钟中断。
保护模式下中断产生时,系统在通过中断门后自动关中断,并在iret中自动开中断。
在io.h中的outb等宏定义上面花了很多时间。
x86上指针和in、out等汇编指令是区分的,操作端口的时候不能使用指针,这与arm结构不同。
0xb8000开始的那一段内存由bios进行了映射,所以才可以用指针操作,这只是一个特例。
3-8
2006-1-18 3:09
实现了光标的跟随移动。
如果编译时指定了-O优化,那么使用asm嵌入式汇编的时候就要小心了。
即当指定汇编中参数为任意寄存器,同时汇编本身也用到寄存器的话,就可能会引起冲突。
如:
#define outb(port,value) /
__asm__ __volatile__ ( /
"movb %1, %%al /n" /
"movw %0, %%dx /n" /
"outb %%al, %%dx /n" /
: :"r"(port), "r"(value) /
)
当调用时参数是立即数的时候可以运行,但当参数是变量的话就出错。
原因:汇编内部和调用参数本身都使用了al存放数据。
如果把"r"指定为"m",那么也能成功,但不排除以后又会因为优化而产生问题,
所以目前的解决方法:不使用优化。
3-9
2006-1-18 7:26
实现了滚屏操作,但目前只支持一个控制台。
计划总共实现4个控制台,每个占一页。
所有控制台都可以映射到current console中,占4页。
3-10
2006-1-20 18:01
实现了键盘的读取。
inb等函数也已实现。
3-11
2006-1-24 11:02
实现了不同权限之间的切换。
注意ldt指令一定要在kernel中更换了gdtr之后才能使用,为此浪费了5个小时。
下一步是添加系统调用。
3-12
2006-1-24 22:22
实现了一个简单的陷阱门。
Linux中的0x80属于陷阱门,使用陷阱门来完成系统调用的操作,而不是使用调用门。
因此本系统中也将不实现调用门。
陷阱门和中断门一样,返回时也是使用iret。不同之处在于进入中断门的时候会自动cld。
从用户级进入到特权级时,仅仅cs和ss属于当前级,其他段寄存器仍然属于用户级,因此需要手动更改,
这在Linux中是由SAVEALL宏完成的。
需要注意的是,SAVEALL中只改变了ds和es,fs和gs保留原值,后两个似乎从来不需要。
目前中断不允许嵌套,但在陷阱门中可以进行中断。
3-13
2006-1-25 17:32
添加系统调用实现了write_console,目前暂时还没有控制台的概念。
此系统调用还实现了返回值的功能,比较有趣的。
3-14
2006-1-26 20:04
实现了进程切换。
进程切换最关键的地方,就是系统返回用户空间的时候内核态堆栈总是在同一个偏移处。
可以据此判断cpu现在究竟是返回用户空间,还是仅仅在系统空间中嵌套返回。
了解了这一点,切换进程就不是很困难了。
另外需要注意的是,系统进入内核空间的时候要使用到tss中的esp,这个值在切换进程时要预先设置好。
至此,操作系统的编写就告一段落了。
代码地址:
http://d.download.csdn.net/filedown2008/aHR0cDovL2RsMi5jc2RuLm5ldC9kb3duNC8yMDA4MDMzMC8zMDIxMzU0MTgyMi56aXA=!398454
2006-1-9 23:43
实现了和C函数的整合。
ld -Ttext org之后的obj的顺序似乎有讲究。
call 命令对堆栈的影响:
16位的实模式中,会将cs和ip压栈,因此栈会减少4。
32位的保护模式中,如果是段内调用,只会将eip压栈;如果是段间调用,会将eip和cs入栈,不过目前还没遇到过这种情况。
C函数调用约定
参数从右向左入栈,在汇编中等调用完后,要手动将esp的值复位。
返回值是4字节时,通过eax传递;2字节通过ax传递;1字节通过al传递。
3-2
2006-1-12 23:47
将光标的行列值改成了全局变量。
在汇编中如果入栈一个符号变量,那入栈的会是指向这个变量的指针。
但在C语言中调用汇编中声明的全局变量时,得到的是这个变量本身而不是其指针。
汇编中用global声明全局变量时,应把该global声明放在它相应的data或bss段中。
3-3
2006-1-14 03:19
实现了中断函数的初始化。
中断函数和函数是不同的概念。
后者可以直接调用,而前者不能。
从汇编层次看,数组和指针是不一样的。
比如:
汇编:
global g_idtr
g_idtr:
%rep 256
dd 0
dd 0
%endrep
C语言中,如果如下声明:
extern long long g_idtr[256];
则可以正常操作。
但是如果使用
extern long long * g_idtr;
那么程序会出错。
究其原因,当使用的是指针时,程序会分配一个空间保存该指针本身的值,而当使用数组时,则不将此标号作为变量另外保存。
3-4
2006-1-14 23:28
实现了部分printf的功能,能够分辨%d和%x。
还没有在其中实现系统调用、/n/t、光标跟随移动等。
实现了一些字符串函数。
3-5
2006-1-15 23:01
完善了printf,当前拥有的功能包括
/t /n %x %d
已经能获取内存信息,目前暂不添加内存映射。
3-6
2006-1-16 22:03
完善了中断函数。
general_intr.c中的宏定义和中断的实现是值得好好研究的。
3-7
2006-1-17 20:38
操作了8259,实现了一个时钟中断。
保护模式下中断产生时,系统在通过中断门后自动关中断,并在iret中自动开中断。
在io.h中的outb等宏定义上面花了很多时间。
x86上指针和in、out等汇编指令是区分的,操作端口的时候不能使用指针,这与arm结构不同。
0xb8000开始的那一段内存由bios进行了映射,所以才可以用指针操作,这只是一个特例。
3-8
2006-1-18 3:09
实现了光标的跟随移动。
如果编译时指定了-O优化,那么使用asm嵌入式汇编的时候就要小心了。
即当指定汇编中参数为任意寄存器,同时汇编本身也用到寄存器的话,就可能会引起冲突。
如:
#define outb(port,value) /
__asm__ __volatile__ ( /
"movb %1, %%al /n" /
"movw %0, %%dx /n" /
"outb %%al, %%dx /n" /
: :"r"(port), "r"(value) /
)
当调用时参数是立即数的时候可以运行,但当参数是变量的话就出错。
原因:汇编内部和调用参数本身都使用了al存放数据。
如果把"r"指定为"m",那么也能成功,但不排除以后又会因为优化而产生问题,
所以目前的解决方法:不使用优化。
3-9
2006-1-18 7:26
实现了滚屏操作,但目前只支持一个控制台。
计划总共实现4个控制台,每个占一页。
所有控制台都可以映射到current console中,占4页。
3-10
2006-1-20 18:01
实现了键盘的读取。
inb等函数也已实现。
3-11
2006-1-24 11:02
实现了不同权限之间的切换。
注意ldt指令一定要在kernel中更换了gdtr之后才能使用,为此浪费了5个小时。
下一步是添加系统调用。
3-12
2006-1-24 22:22
实现了一个简单的陷阱门。
Linux中的0x80属于陷阱门,使用陷阱门来完成系统调用的操作,而不是使用调用门。
因此本系统中也将不实现调用门。
陷阱门和中断门一样,返回时也是使用iret。不同之处在于进入中断门的时候会自动cld。
从用户级进入到特权级时,仅仅cs和ss属于当前级,其他段寄存器仍然属于用户级,因此需要手动更改,
这在Linux中是由SAVEALL宏完成的。
需要注意的是,SAVEALL中只改变了ds和es,fs和gs保留原值,后两个似乎从来不需要。
目前中断不允许嵌套,但在陷阱门中可以进行中断。
3-13
2006-1-25 17:32
添加系统调用实现了write_console,目前暂时还没有控制台的概念。
此系统调用还实现了返回值的功能,比较有趣的。
3-14
2006-1-26 20:04
实现了进程切换。
进程切换最关键的地方,就是系统返回用户空间的时候内核态堆栈总是在同一个偏移处。
可以据此判断cpu现在究竟是返回用户空间,还是仅仅在系统空间中嵌套返回。
了解了这一点,切换进程就不是很困难了。
另外需要注意的是,系统进入内核空间的时候要使用到tss中的esp,这个值在切换进程时要预先设置好。
至此,操作系统的编写就告一段落了。
代码地址:
http://d.download.csdn.net/filedown2008/aHR0cDovL2RsMi5jc2RuLm5ldC9kb3duNC8yMDA4MDMzMC8zMDIxMzU0MTgyMi56aXA=!398454
相关文章推荐
- 实现自己的操作系统 第二部分
- 实现自己的操作系统 第一部分
- 读书笔记之: 操作系统概念(第6版)-第三部分 存储管理2(文件系统接口, 文件系统实现)
- [操作系统概念]第三部分——CPU调度
- 实例一——为自己的操作系统中加入中断(中断机制的实现)
- SkyEye硬件模拟平台,第三部分: 硬件仿真实现之三
- 第三部分:如何实现分页,包括两个函数,两个调用
- 【NROS-00】自己实现一个简单操作系统
- Java EE集群技术初探——第三部分(Web层集群的实现)
- VMware 实现自己设计的最小操作系统
- 自己动手实现操作系统引导程序(OS bootloader)——借助QEMU/GDB/losetup/dd等工具
- OS learning 自己动手写操作系统 & Orange'S:一个操作系统的实现 leaning tips
- 淘宝diamond使用心得 服务端+客户端+部分自己实现的代码
- 合格前端系列第三弹-实现一个属于我们自己的简易MVVM库
- 裸机程序也可以写关于mmu程序,相当于实现操作系统的部分功能
- 自己动手实现操作系统引导程序(OS bootloader)——借助QEMU/GDB/losetup/dd等工具
- SkyEye硬件模拟平台,第三部分: 硬件仿真实现之四
- 第三部分:实现IDataObject(OLE drag&drop之旅)
- [转]SkyEye硬件模拟平台,第三部分: 硬件仿真实现之一
- 容器第三课,JDK源码分析,自己实现ArrayList数组扩容