Chinaunix首页 | 论坛 | 博客
  • 博客访问: 372618
  • 博文数量: 80
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1767
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-24 16:18
个人简介

为啥不能追求自己的爱好一辈子呢

文章分类

全部博文(80)

文章存档

2017年(1)

2015年(2)

2014年(18)

2013年(59)

分类: LINUX

2017-10-11 16:59:19

  上一段时间碰到一个问题,摸索了好长时间,原来是ld链接器对地址的定位,与我把程序的加载地址冲突,所以访问不到正确的位置,引起的。等碰到这个问题再说啦。

  到达这里我们基本上已经完成了操作系统内核之前的准备了。我们就准备跳转到32位模式下啦。ok,让我们先考虑下进入32位模式之前需要做些什么

               1.应该禁用pic(Programmable Interrupt Controller)中断,以避免有问题(虽然不禁用,暂时没发现什么问题)

               2.开启A20Gate

               3.初始化GDT

               4.置CR0寄存器保护模式位

               4.跳转啦

解释:为什么要禁用中断呢,嘿嘿,我也不知道。不过据说是:根据AT兼容机的规格,   初始化PIC必须在CLI之前进行,否则有时候会被挂起,随后进行PIC的初始化

代码为

点击(此处)折叠或打开

  1. mov AL,0xff
  2.  out 0x21,AL ;pic0的端口
  3.  NOP ;等会儿嘛,太快了,可能出问题
  4.  out 0xal,al ;pic1的端口
  5.  cli ;禁用可屏蔽中断



pic有两个芯片的,一个是master一个slave在这里就不做详细的讨论啦。给个网址大家去看 http://wiki.osdev.org/PIC


然后是开启A20啦,因为之前只能访问1M的内存嘛(2的20次方),请参照  http://wiki.osdev.org/A20.

点击(此处)折叠或打开

  1. ;开启A20管脚 初始化GDT和CR0,我们开始初始化两个段,一个代码段一个数据段。看之前请参照 
  2. CALL waitkbdout
  3. MOV AL,0xd1
  4. OUT 0x64,AL ;其实管脚的控制在键盘的芯片里面
  5. CALL waitkbdout
  6. MOV AL,0xdf ;enable A20
  7. OUT 0x60,AL
  8. CALL waitkbdout
  9. waitkbdout:
  10.  IN AL,0x64
  11.  AND AL,0x02
  12.  JNZ waitkbdout ;
  13.  RET


   初始化GDT和CR0,我们开始初始化两个段,一个代码段一个数据段。看之前请参照 http://wiki.osdev.org/GDT,我们以后还会讲的

点击(此处)折叠或打开

  1. LGDT [GDTR0] ; 加载gd
  2.   MOV EAX,CR0
  3.   AND EAX,0x7fffffff ;禁止分页
  4.   OR EAX,0x00000001 ; 开启保护模式
  5.   MOV CR0,EAX
  6.   ALIGNB 16
  7. GDT0:
  8.   RESB 8 ;第一项为0,规定这样
  9.     
  10.   DW 0xffff,0x0000,0x9200,0x00cf ; 数据
  11.   DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行
  12.   DW 0
  13. GDTR0:
  14.   DW 8*3-1;gdt的大小
  15.   DD GDT0;起始地址
  16.   ALIGNB 16


   然后我决定可以把我们的程序移位到另一个地址,在此之前先刷新一下段寄存器吧大家读过linux内核源码的估计会记得置位CR0的保护位用的是lmsw,那是古老的方式啦。

点击(此处)折叠或打开

  1. MOV AX,1*8 ; 段偏移量
  2.   MOV DS,AX
  3.   MOV ES,AX
  4.   MOV FS,AX
  5.   MOV GS,AX
  6.   mov ax,AX
  7.   MOV SS,AX



然后是移位啦

点击(此处)折叠或打开

  1. BOTPAK EQU 0x00280000 ; 我们主程序load地址
  2. DSKCAC EQU 0x00100000 ;
  3. DSKCAC0 EQU 0x00008000 ;
  4. MOV ESI,bootpack ; 把我们的主程序加载到0x280000,我们会把32位的代码放到bootpack后边
  5.   MOV EDI,BOTPAK ;
  6.   MOV ECX,512*1024/4
  7.   CALL memcpy
  8.   
  9.   MOV ESI,0x7c00 ;把boot程序加载到DSKCAC
  10.   MOV EDI,DSKCAC ;
  11.   MOV ECX,512/4
  12.   CALL memcpy
  13.   
  14.   MOV ESI,DSKCAC0+512 ; 把其余的也加载进来
  15.   MOV EDI,DSKCAC+512 ;
  16.   MOV ECX,0
  17.   MOV CL,BYTE [CYLS]
  18.   IMUL ECX,512*18*2/4 ;
  19.   SUB ECX,512/4 ;
  20.   CALL memcpy

  21. memcpy:
  22.   cld ;清方向
  23.   a32 rep movsd
  24.   RET


  最后先写一个32位的汇编会跳到这里kernelFunc.asm,我们会让屏幕变个颜色的

点击(此处)折叠或打开

  1. [bits 32]
  2. hah:
  3.   MOV eAX,1*8 ; 段偏移量 ,还是在这再初始化一次吧
  4.   MOV DS,AX
  5.   MOV ES,AX
  6.   MOV FS,AX
  7.   MOV SS,AX
  8.   mov esp,0x280000;把栈地址放到这把
  9.   mov eax ,0xa0000
  10. loops:
  11.   mov byte [eax],14
  12.   inc eax
  13.   cmp eax, 0xaffff
  14.   jbe loops
  15.   jmp loo
  16.   
  17. loo:
  18.   hlt
  19.     jmp loo


然后写一个脚本吧 build.bat如在linux请先安装nasm,然后自己写一个makefile

点击(此处)折叠或打开

  1. rem 我们的bootloader
  2. nasm -o .\bin\begin.bin begin.asm
  3. rem 我们的入口
  4. nasm -o haribote.o haribote.asm
  5. rem 我们的32位入口
  6. nasm -o kernelFunc.o kernelfunc.asm
  7. rem copy二进制内容到一个地方
  8. copy /B haribote.o+kernelFunc.o kernel



至此全部haribote.asm的内容如下:

点击(此处)折叠或打开

  1. ; haribote-os boot asm
  2. ; TAB=4
  3. BOTPAK EQU 0x00280000 ; 我们主程序load地址
  4. DSKCAC EQU 0x00100000 ;
  5. DSKCAC0 EQU 0x00008000 ;

  6. CYLS EQU 0x0ff0 ; 柱面数
  7. LEDS EQU 0x0ff1 ;le灯
  8. VMODE EQU 0x0ff2 ; 模式
  9. SCRNX EQU 0x0ff4 ; x的分辨率
  10. SCRNY EQU 0x0ff6 ; y的分辨率
  11. VRAM EQU 0x0ff8 ;起始地址
  12.   ORG 0xc200 ;程序开始的地址
  13.   MOV AL,0x13 ;
  14.   MOV AH,0x00
  15.   INT 0x10 ;转化成图像模式的320*200*8bit
  16.   MOV BYTE [VMODE],8 ;
  17.   MOV WORD [SCRNX],320
  18.   MOV WORD [SCRNY],200
  19.   MOV DWORD [VRAM],0x000a0000
  20. ;
  21.   MOV AH,0x02
  22.   INT 0x16 ; keyboard BIOS
  23.   MOV [LEDS],AL

  24.   ;禁用pic中断
  25.   MOV AL,0xff
  26.   OUT 0x21,AL
  27.   NOP ;
  28.   OUT 0xa1,AL
  29.   CLI ; 禁用可屏蔽中断

  30.   ;开启A20管脚
  31.   CALL waitkbdout
  32.   MOV AL,0xd1
  33.   OUT 0x64,AL
  34.   CALL waitkbdout
  35.   MOV AL,0xdf ; enable A20
  36.   OUT 0x60,AL
  37.   CALL waitkbdout
  38.   LGDT [GDTR0] ;
  39.   MOV EAX,CR0
  40.   AND EAX,0x7fffffff ;禁止分页
  41.   OR EAX,0x00000001 ; 开启保护模式
  42.   MOV CR0,EAX
  43.   MOV AX,1*8 ; 段偏移量
  44.   MOV DS,AX
  45.   MOV ES,AX
  46.   MOV FS,AX
  47.   MOV GS,AX
  48.   mov ax,AX
  49.   MOV SS,AX
  50.   
  51.   MOV ESI,bootpack ; 把我们的主程序加载到0x280000
  52.   MOV EDI,BOTPAK ;
  53.   MOV ECX,512*1024/4
  54.   CALL memcpy
  55.   
  56.   MOV ESI,0x7c00 ;把boot程序加载到DSKCAC
  57.   MOV EDI,DSKCAC ;
  58.   MOV ECX,512/4
  59.   CALL memcpy
  60.   
  61.   MOV ESI,DSKCAC0+512 ; 把其余的也加载进来
  62.   MOV EDI,DSKCAC+512 ;
  63.   MOV ECX,0
  64.   MOV CL,BYTE [CYLS]
  65.   IMUL ECX,512*18*2/4 ;
  66.   SUB ECX,512/4 ;
  67.   CALL memcpy
  68.   
  69.   MOV esp,0x000280000
  70.   
  71.   JMP dword 16:0x00000000;dword必须的,表示段间转移

  72. waitkbdout:
  73.   IN AL,0x64
  74.   AND AL,0x02
  75.   JNZ waitkbdout ;
  76.   RET
  77. memcpy:
  78.   cld
  79.   a32 rep movsd
  80.   RET

  81.   ALIGNB 16
  82. GDT0:
  83.   RESB 8 ;
  84.   DW 0xffff,0x0000,0x9200,0x00cf ; 数据
  85.   DW 0xffff,0x0000,0x9a28,0x004f ; 可执行
  86.   DW 0
  87. GDTR0:
  88.   DW 8*3-1
  89.   DD GDT0
  90.   ALIGNB 16
  91. bootpack:


然后用winImage把boot加载进去,然后选择Image下面的Inject把我们的 kernel注入进去,用虚拟机加载一把吧,会有奇迹发生的。嘿嘿。今天就到这里吧。有问题请提问哈。

阅读(1091) | 评论(0) | 转发(0) |
1

上一篇:Sphinx学习之sphinx的安装篇

下一篇:没有了

给主人留下些什么吧!~~