自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(24)
  • 收藏
  • 关注

原创 30天自制操作系统day28

allocaC语言编译器规定, 如果栈的大小超过4KB,则会调用__alloca()这个函数来获取栈的空间。为了能够使用更大的栈空间,我们需要简单地实现这个函数。__alloca: ADD EAX,-4 SUB ESP,EAX JMP DWORD [ESP+EAX]EAX是要分配的栈大小。因为call这个函数会push返回地址,

2015-08-02 12:19:31 602

原创 30天自制操作系统day27

LDT之前通过设置段时将权限+0x60的方法防止应用程序访问操作系统内存空间。但是现在应用程序还是可以修改别的应用程序的内存。为了防止应用程序被攻击,需要使用LDT。 LDT是只对一个应用程序有效的,容量也是64KB。因为现在我们每个程序只需要2个段(数据段,代码段),所以只用了里面的16字节。LDT每个程序一个,放在task结构中。 要使用LDT,需要在GDT表中注册一个LDT段。每个程序注册

2015-07-31 14:41:20 652

原创 30天自制操作系统day23

编写malloc昨天的带窗口的应用程序,窗口的buffer是全局数组,导致生成的可执行文件很大。如果可以在运行时动态分配就可以解决这个问题。但是直接使用操作系统的memman_alloc()也不行,因为分配到的内存空间不属于应用程序的段。临时的解决方法是在编译时就把数据段开大一点,然后再用memman管理这段内存。因为分配的数据段大小不会对可执行文件的大小产生影响,所以是可行的。 malloc用的

2015-07-28 13:20:26 657

原创 30天自制操作系统day22

栈异常的处理当在应用程序中访问一个数组时,如果index超过数组的大小,可能会引起栈异常,因为只有访问到位置超过应用程序数据段的范围时才会导致异常。栈异常会触发0x0c中断。 处理异常时,最好能够显示发生异常的指令地址。因为中断时,CPU自动PUSH应用程序的EIP,CS,ESP,SS等,可以从栈上获得EIP。 中断后又执行了 PUSH ES PUSH DS P

2015-07-27 13:54:22 614

原创 30天自制操作系统day21

用C语言编写应用程序要调用API,需要将参数放到寄存器中然后中断,C语言中没有这样的指令,所以写一个汇编函数:_api_putchar: ; void api_putchar(int c); MOV EDX,1 MOV AL,[ESP+4] ; c INT 0x40 RET将函数参数放到AL中,然

2015-07-26 12:07:29 953

原创 30天自制操作系统day20

上一章讲到可以运行磁盘上的应用程序了,但只是非常简单的程序。操作系统应该为应用程序提供系统调用(system call、API),供应用程序调用。这一章讲到了显示字符的API。显示字符APIvoid cons_putchar() 在系统程序中,接受的参数是命令行窗口结构cons和字符。为了简化调用过程,外面包装了一个asm_cons_putchar 函数:_asm_cons_putchar:

2015-07-25 15:38:09 893

原创 30天自制操作系统day18&day19

实现命令行第18章实现了命令行任务,且实现了几个命令。主要是dir命令可以讲一讲。dir命令用于显示目录下的文件信息。 由于磁盘的数据已经全部读取到内存中了,所以这里可以直接访问到。由前面可知,磁盘数据放在0x00100000~0x00267fff,根目录的文件信息存放在磁盘开始的0x2600处。FAT文件目录项的格式为:struct FILEINFO { unsigned

2015-07-24 13:04:15 576

原创 30天自制操作系统day17

创建命令行窗口创建一个带窗口的任务,需要在主程序中创建窗口,再通过参数传给这个任务的main函数。因为要处理窗口重叠关系等,需要在统一的地方进行管理。 如果有多个任务能够接受键盘输入,则应该创建一个变量key_to,表示输入到哪个任务中。 为了让每个任务都能够接受键盘输入,可以把FIFO放在TASK结构中。在主程序的for循环中,根据key_to的值将键盘数据传到指定的FIFO中。然后在这个任务

2015-07-21 09:58:01 473

原创 30天自制操作系统day16

任务自动化今天要实现任务切换的自动化。最好能够有一个任务数组,每次定时器timeout就切换到下一个,这样就不用写很复杂的taskswitch()了。 首先执行task_init(),这里创建TASKCTL结构,为task数组的每一个TASK在段表中注册。最后设置当前的任务,也就是把调用task_init()函数的这个程序变成一个任务。之后便可进行任务切换了。 task_run()只是将任

2015-07-20 09:42:04 635

原创 30天自制操作系统day15

这章讲到多任务了。多任务实际就是多个任务来回切换。切换时把上一个任务的寄存器写入内存,读入下一个任务的寄存器,保证程序能够从被中断的地方继续执行。 保存的寄存器用一个结构体表示:struct TSS32 { int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; int eip, eflags, eax, ecx, edx, ebx,

2015-07-19 12:32:16 574

原创 30天自制操作系统day14

提高分辨率。在asmhead.nas中,设置画面模式的参数:MOV BX,0x4101MOV AX,0x4f02其中0x101表示640*480彩色模式。如果要真机运行的话,需要检测是否支持VBE。以及VBE版本是否够高,是否支持要设置的分辨率等。键盘输入 输入比较简单。因为已经能够接受到键盘中断传来的值了,只需要存一个对应的字符数组就可以显示输入。追记内容也没什么难的,如果是普

2015-07-15 10:10:56 484

原创 30天自制操作系统day13

这一章继续讲定时器的优化。上一章中,每个定时器都有一个FIFO,判断时钟中断时需要判断每个FIFO的状态。其实可以让它们共用一个FIFO,通过向FIFO中传入不同的值来区别是哪个定时器超时了。继续优化,可以把鼠标和键盘的FIFO也加进来,这样每次循环就只需要检测一个FIFO的状态。同时需要让键盘鼠标中断时向FIFO中传入不同的值,与定时器区别开来。然后是在inthandler20()和timer_s

2015-07-14 09:46:50 478

原创 30天自制操作系统day12

定时器 定时器硬件与IRQ0连接,中断会触发IRQ0的处理函数。初始化的方法是写入分频数(0-65535),如果写入0表示分频66536。最终获得的定时器周期为主频/分频数。 写好中断函数,在初始化时enable,就能实现计时功能了。之后又实现了一个超时(timeout)功能,也就是定时器计时到某一时刻触发一个事件。这里完全是软件实现的。为timeout设置一个FIFO,定时器超时之后向F

2015-07-13 18:45:12 451

原创 30天自制操作系统day11

这一章对多图层显示进行了进一步优化。在原先的绘制方法中,每次绘制都是从最低一层到最高一层全部绘制。如果要绘制一个不断变化的图层,如本章的计数器,则绘制函数会一直执行。我们肉眼看到的就是各个图层不断交替,也就是闪烁。消除闪烁的一个方法是只绘制变化的图层及以上的图层。因为下面的图层被遮挡,本来也没必要绘制。但这样只是减少了绘制的图层数而已。变化的图层和在它上面的图层(如鼠标)仍会闪烁。根本的解决方法是创

2015-05-18 23:30:48 432

原创 30天自制操作系统day10

这一章讲到了多图层的显示问题。 首先将图层作为一个数据结构:struct SHEET{ unsigned char *buf; int bxsize,bysize,vx0,vy0,col_inv,height,flags;};其中,buf指向该图层所描绘的内容,应该是一个像素的数组。bxsize和bysize是图层大小。vx0,vy0是图层在屏幕的位置坐标,height表示图层高

2015-05-18 21:44:58 538

原创 30天自制操作系统day9

这一章讲到了内存管理。首先要获取内存容量。方法是从头到尾向内存中存,取数据,看前后是否一样。如果不是内存,前后数据将不一致。由此得到内存的大小。接下来是内存管理的策略。1.bitmap 假设有0x08000000的内存空间,以0x1000为单位进行管理,则可以使用一块0x8000=32768bit的空间,每个位写入0或1表示对应的一个单位内存被使用或空闲。 该方法优点是管理起来简单,但效率较差。

2015-05-10 19:46:20 580

原创 30天自制操作系统day8

鼠标解读鼠标初始化完成后,会自动中断一次,发送0xfa。之后每次鼠标事件发生会中断3次,发送3个字节,需要一步一步读取。伪代码如下:if(mouse_phase==0){ 等待鼠标的0xfa的状态}else if(mouse_phase==1){ 等待鼠标的第一个字节}else if(mouse_phase==1){ 等待鼠标的第二个字节}else if(

2015-05-07 12:30:48 640

原创 30天自制操作系统day7

io_out8(PIC0_OCW2,0x61);这句话是指通知PIC已经接收到IQR1中断。具体是将”0x60+IQR number”发送到PIC0_OCW2。data = io_in8(0x0060);这句话是获取地址为0x0060的设备的8位数据,该设备为键盘,获取到的是按下的键的编码。制作FIFO缓冲区之前的缓冲区大小是1,当大量键盘按下发生时,有可能丢失。这里用FIFO的队列制作一个缓冲区。

2015-05-06 23:25:57 522

原创 30天自制操作系统day5

这章主要讲如何显示字符,以及段表、中断向量表的初始化方法。字符的显示实际上是显示一组像素。书中的方法是,事先为每个字符对应一个16*8的像素数组,每个数组元素代表该位置有没有像素。这样便可以把一个字符表示为一串16Byte的二进制数。 显示一个字符的函数:void putfont8(char *vram, int xsize, int x, int y, char c, char *font){

2015-04-19 17:07:03 519

原创 30天自制操作系统day4

这章主要讲如何在屏幕上进行绘制。由于一些功能无法用C语言完成,所以这章用到了许多C和汇编的混合编程。基本上是在汇编里定义函数,label比函数名前面多一个下划线”_”。函数的参数压入栈中,可以用[ESP+OFFSET]获得,如果是带有返回值的函数,在RET前使用POP EAX。返回值默认是放在EAX中的。 传参数的例子:_io_in32: ;void io_in32(int port) 从端口

2015-04-19 14:58:03 505

原创 30天自制操作系统day3

第三章主要讲了启动区和从启动区载入操作系统程序。书中一个装载磁盘数据的代码示例:MOV AX, 0x0820MOV ES, AXMOV CH, 0MOV DH, 0MOV CL, 2MOV AH, 0x02MOV AL, 1MOV BX, 0MOV DL, 0x00INT 0x130x13就是触发读写磁盘操作的中断序号,它需要的参数如下(部分):AH: 0x02(读盘),0x03(写

2015-04-18 23:08:29 885

原创 30天自制操作系统day2

这一章主要讲解汇编基础知识和Makefile的使用ORG指令:指定开始执行程序的时候,把程序装载到内存的哪个地址。如果不指定,则默认从0x0开始,会与BIOS程序发生冲突。程序helloos.nas中,指定的是0x7c00。这是因为规定的启动区内容装载地址是0x00007c00-0x00007dff。AX,CX,BX等寄存器,在源代码中使用时看不出差别,但本质上是不一样的。AX适合用来计算。例如:A

2015-04-18 10:36:42 528

原创 Ubuntu14.04下安装Android Studio 1.0

在Linux下安装Android Studio按理说应该比在Windows下简单。但是由于GFW和许多不明原因,使得我不管在windows下还是linux下总会遇到各种各样的坑。现在把整个流程整理一下,以便以后不会再掉到坑里。1.安装JDKjdk直接到oracle上下载就行,速度够快的。我的linux是64位的,所以选择x64。下载下来后,移动到某个目录下,解压,然后添加环境变量,

2015-03-12 20:04:26 836

原创 LINUX下GCC的动态与静态编译

假设当前目录下有文件:hello.hhello.cmain.c其中hello.h为头文件,hello.c实现头文件中声明的函数,main.c为主程序,调用了头文件中的函数。动态编译:1.生成.so动态库文件gcc -fpic -shared hello.c -o libhello.so2.加载动态库生成可执行文件gcc main.c libhello.so

2015-03-08 23:05:23 364

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除