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

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

文章分类

全部博文(80)

文章存档

2017年(1)

2015年(2)

2014年(18)

2013年(59)

分类: 其他平台

2013-02-06 15:09:36

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

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

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

               2.开启A20Gate

               3.初始化GDT

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

               4.跳转啦

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

代码为

 mov AL,0xff

 out 0x21,AL                 ;pic0的端口

 NOP                            ;等会儿嘛,太快了,可能出问题

 out 0xal,al                    ;pic1的端口

 cli                                ;禁用可屏蔽中断

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

 

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

 ;开启A20管脚
  CALL waitkbdout
  MOV  AL,0xd1
  OUT  0x64,AL         ;其实管脚的控制在键盘的芯片里面
  CALL waitkbdout
  MOV  AL,0xdf         ;enable A20
  OUT  0x60,AL      
  CALL waitkbdout

waitkbdout:
  IN   AL,0x64
  AND   AL,0x02
  JNZ  waitkbdout  ;
  RET

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

  LGDT [GDTR0]   ; 加载gd
  MOV  EAX,CR0
  AND  EAX,0x7fffffff ;禁止分页
  OR  EAX,0x00000001 ; 开启保护模式
  MOV  CR0,EAX

  ALIGNB 16
GDT0:
  RESB 8    ;第一项为0,规定这样

    
  DW  0xffff,0x0000,0x9200,0x00cf ; 数据
  DW  0xffff,0x0000,0x9a28,0x0047 ; 可执行

  DW  0
GDTR0:
  DW  8*3-1;gdt的大小
  DD  GDT0;起始地址

  ALIGNB 16

大家度过linux内核源码的估计会记得置位CR0的保护位用的是lmsw,那是古老的方式啦。

然后我决定可以把我们的程序移位到另一个地址,在此之前先刷新一下段寄存器吧

  MOV  AX,1*8   ;  段偏移量
  MOV  DS,AX
  MOV  ES,AX
  MOV  FS,AX
  MOV  GS,AX
  mov     ax,AX
  MOV  SS,AX

然后是移位啦

 BOTPAK EQU  0x00280000  ; 我们主程序load地址
DSKCAC EQU  0x00100000  ;
DSKCAC0 EQU  0x00008000  ;

MOV  ESI,bootpack ; 把我们的主程序加载到0x280000,我们会把32位的代码放到bootpack后边
  MOV  EDI,BOTPAK  ;
  MOV  ECX,512*1024/4
  CALL memcpy
  
  MOV  ESI,0x7c00  ;把boot程序加载到DSKCAC
  MOV  EDI,DSKCAC  ;
  MOV  ECX,512/4
  CALL memcpy
  
  MOV  ESI,DSKCAC0+512 ; 把其余的也加载进来
  MOV  EDI,DSKCAC+512 ;
  MOV  ECX,0
  MOV  CL,BYTE [CYLS]
  IMUL ECX,512*18*2/4 ;
  SUB  ECX,512/4  ;
  CALL memcpy

 

memcpy:
  cld     ;清方向
  a32 rep movsd
  RET 

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

[bits 32]
hah:
  MOV  eAX,1*8   ;  段偏移量 ,还是在这再初始化一次吧
  MOV  DS,AX
  MOV  ES,AX
  MOV  FS,AX
  MOV  SS,AX
  mov esp,0x280000;把栈地址放到这把
  mov eax ,0xa0000
loops:
  mov byte [eax],14
  inc eax
  cmp eax, 0xaffff
  jbe loops
  jmp loo
  
loo:
  hlt
    jmp loo

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

rem 我们的bootloader

nasm -o .\bin\begin.bin begin.asm 

rem 我们的入口

nasm -o haribote.o haribote.asm

rem 我们的32位入口

nasm  -o kernelFunc.o kernelfunc.asm

rem copy二进制内容到一个地方

copy /B haribote.o+kernelFunc.o kernel

 

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

 

; haribote-os boot asm
; TAB=4

BOTPAK EQU  0x00280000  ; 我们主程序load地址
DSKCAC EQU  0x00100000  ;
DSKCAC0 EQU  0x00008000  ;


CYLS EQU  0x0ff0   ; 柱面数
LEDS EQU  0x0ff1    ;le灯
VMODE EQU  0x0ff2   ; 模式
SCRNX EQU  0x0ff4   ; x的分辨率
SCRNY EQU  0x0ff6   ; y的分辨率
VRAM EQU  0x0ff8   ;起始地址

  ORG  0xc200   ;程序开始的地址

  MOV  AL,0x13   ;
  MOV  AH,0x00
  INT  0x10      ;转化成图像模式的320*200*8bit
  MOV  BYTE [VMODE],8 ;
  MOV  WORD [SCRNX],320
  MOV  WORD [SCRNY],200
  MOV  DWORD [VRAM],0x000a0000

;

  MOV  AH,0x02
  INT  0x16    ; keyboard BIOS
  MOV  [LEDS],AL

 

  ;禁用pic中断
  MOV  AL,0xff
  OUT  0x21,AL
  NOP      ;
  OUT  0xa1,AL

  CLI      ; 禁用可屏蔽中断


  ;开启A20管脚
  CALL waitkbdout
  MOV  AL,0xd1
  OUT  0x64,AL
  CALL waitkbdout
  MOV  AL,0xdf   ; enable A20
  OUT  0x60,AL
  CALL waitkbdout

  LGDT [GDTR0]   ;
  MOV  EAX,CR0
  AND  EAX,0x7fffffff ;禁止分页
  OR  EAX,0x00000001 ; 开启保护模式
  MOV  CR0,EAX
  MOV  AX,1*8   ;  段偏移量
  MOV  DS,AX
  MOV  ES,AX
  MOV  FS,AX
  MOV  GS,AX
  mov     ax,AX
  MOV  SS,AX

  
  MOV  ESI,bootpack ; 把我们的主程序加载到0x280000
  MOV  EDI,BOTPAK  ;
  MOV  ECX,512*1024/4
  CALL memcpy
  
  MOV  ESI,0x7c00  ;把boot程序加载到DSKCAC
  MOV  EDI,DSKCAC  ;
  MOV  ECX,512/4
  CALL memcpy
  
  MOV  ESI,DSKCAC0+512 ; 把其余的也加载进来
  MOV  EDI,DSKCAC+512 ;
  MOV  ECX,0
  MOV  CL,BYTE [CYLS]
  IMUL ECX,512*18*2/4 ;
  SUB  ECX,512/4  ;
  CALL memcpy
  
  MOV  esp,0x000280000
  
  JMP  dword 16:0x00000000;dword必须的,表示段间转移


waitkbdout:
  IN   AL,0x64
  AND   AL,0x02
  JNZ  waitkbdout  ;
  RET

memcpy:
  cld
  a32 rep movsd
  RET


  ALIGNB 16
GDT0:
  RESB 8    ;
  DW  0xffff,0x0000,0x9200,0x00cf ; 数据
  DW  0xffff,0x0000,0x9a28,0x004f ; 可执行

  DW  0
GDTR0:
  DW  8*3-1
  DD  GDT0

  ALIGNB 16
bootpack:

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

阅读(3222) | 评论(3) | 转发(0) |
给主人留下些什么吧!~~

doggeral2013-06-30 14:20:23

anqiu1987:行啊。。共同学习。644104436

加不上 我到qq是343902891 谢谢啦! 我在linux下重写30的内容 在链接方面遇到一些问题 还请博主帮忙

回复 | 举报

anqiu19872013-06-28 13:44:36

doggeral:你好 我想请教博主一个问题 我最近也在linux下重写30天自制操作系统 有些问题想问问博主 能否留下个qq 多谢博主啦

行啊。。共同学习。644104436

回复 | 举报

doggeral2013-06-26 07:57:08

你好 我想请教博主一个问题 我最近也在linux下重写30天自制操作系统 有些问题想问问博主 能否留下个qq 多谢博主啦