1个人开发操作系统之C语言的开始

1个人开发操作系统之初篇

本文任务是读取软盘18Sector,编写video.s显示8bit320*200黑屏,并进入32bit保护模式,编写func.s bootpack.c显示白屏,并用编写Makefile编译源文件。

1. boot.s读入18sector

reading:

mov ax,0x0820

mov es,ax ;0x0820(es) * 16=0x8200 ;第二个Sector的数据读入到内存的0x8200地址。

mov ch,0 ;track/cylinder number

mov dh,0 ;head number

mov cl,2 ;sector number

readloop:

mov si,0 ; count failure times

retry:

;http://en.wikipedia.org/wiki/BIOS_interrupt_call#INT_13h_AH.3D02h:_Read_Sectors_From_Drive

mov ah,0x02 ;status of reading disk sector

mov al,1 ;number of sectors read

mov bx,0 ;0x0820(es) * 16 + 0(bx)=0x8200, 0x7e00~0x9fbff之间

mov dl,0x00 ;A drive

int 0x13 ;Read

jnc next ;no error goto next

add si,1 ;si +1

cmp si,5 ;compare 5

jae error ;goto error

mov ah,0x00 ;

mov dl,0x00 ; a drive

int 0x13 ; drive reset

jmp retry

next:

mov ax,es ; add 0x200(512)

add ax,0x20

mov es,ax

add cl,1 ;cl+1

cmp cl,18 ;compare 18,18 sectors

jbe readloop ;<18,continue

mov cl,1

add dh,1

cmp dh,2 ;读完正面18Sector后,读反面18

jb readloop ;dh<2 goto readloop

mov dh,0

add ch,1

cmp ch,CYLS

jb readloop ;ch<CYLS goto readloop

2. 调到video.s

;读完所有数据后,调到0x8200位置

fin:

mov [0x0ff0],ch ;remember the position of cylinder

JMP 0x8200 ;jump to video.s

hlt ;cpu停止

jmp fin

3. video.s

Colimas Simple OS的内存分布:

0x00000000-0x000fffff:启动时使用

0x00100000-0x00267fff:软盘数据备份

0x00268000-0x<chmetcnv w:st="on" unitname="F" sourcevalue="26" hasspace="False" negative="False" numbertype="1" tcsc="0">0026f</chmetcnv>7ff:空

0x<chmetcnv w:st="on" unitname="F" sourcevalue="26" hasspace="False" negative="False" numbertype="1" tcsc="0">0026f</chmetcnv>800-0x0026ffffIDT

0x00270000-0x0027ffffGDT

0x00280000-0x002ffffffbootpack.img

0x00300000-0x003fffffStack以及其他

0x00400000- :空

;video.s

;Colimas Simple OS

BOTPAK EQU 0x00280000 ; the address of bootpack

DSKCAC EQU 0x00100000 ; Disk Cache Address of 32 mode address

DSKCAC0 EQU 0x00008000 ; Disk Cache of Real mode address

;Save the BOOT INFO to 0x0ff0

CYLS EQU 0x0ff0 ;save the boot info

LEDS EQU 0x0ff1

VMODE EQU 0x0ff2 ;color info

SCRNX EQU 0x0ff4 ;pixel x

SCRNY EQU 0x0ff6 ;pixel y

VRAM EQU 0x0ff8 ;graphic buffer

org 0x8200

;http://en.wikipedia.org/wiki/BIOS_interrupt_call

mov al,0x13 ;video bios int, vga graphics,320*200*8bit color

mov ah,0x00

int 0x10 ;黑屏

mov BYTE [VMODE],8 ; save screen mode

mov WORD [SCRNX],320

mov WORD [SCRNY],200 ;8bit 320*200

mov DWORD [VRAM],0xa0000

;the led status of keybroad

mov ah,0x02

int 0x16 ; keybroad BIOS:Read Keyboard Shift Status

mov [LEDS],al

;block PIC

mov al,0xff

out 0x21,al

nop

out 0xa1,al

cli ;block cpu interrupt

;use >1mb memory set a20gate

call waitkbdout

mov al,0xd1

out 0x64,al ;write out port

call waitkbdout

mov al,0xdf ;enable a20

out 0x60,al

call waitkbdout

;enter protected mode

lgdt [GDTR0] ; init GDTR

mov eax,CR0

and eax,0x7fffffff ;set bit31 to 0( block paging

or eax,0x00000001 ;set bit1 to 1( enable protect mode

mov cr0,EAX

jmp pipelineflash

pipelineflash:

mov ax,1*8 ; reinit all the register from 0x0000 to 0x0008

mov ds,ax

mov es,ax

mov fs,ax

mov gs,ax

mov ss,ax

; mov bootpack

mov esi,bootpack ; source

mov edi,BOTPAK ; destination

mov ecx,512*1024/4

call memcpy

;move boot sector

mov esi,0x<chmetcnv w:st="on" unitname="C" sourcevalue="7" hasspace="False" negative="False" numbertype="1" tcsc="0">7c</chmetcnv>00 ; source

mov edi,DSKCAC ; destination

mov ecx,512/4

call memcpy

;move others

mov esi,DSKCAC0+512 ;source

mov edi,DSKCAC+512 ;destination

mov ecx,0

mov cl,BYTE [CYLS]

imul ecx,512*18*2/4

sub ecx,512/4

call memcpy

;start bootpack

skip:

MOV ESP,0x00300000 ; init stack pointer

JMP DWORD 2*8:0x00

waitkbdout:

in al,0x64

and al,0x02

in al,0x60

jnz waitkbdout ; if result of and is not 0 goto waitkbdout

ret

memcpy:

mov eax,[esi]

add esi,4

mov [edi],eax

add edi,4

sub ecx,1

jnz memcpy

ret

alignb 16

GDT0: ;init gdtr

RESB 8 ; null sector

DW 0xffff,0x0000,0x9200,0x00cf ;

DW 0xffff,0x0000,0x<chmetcnv w:st="on" unitname="a" sourcevalue="9" hasspace="False" negative="False" numbertype="1" tcsc="0">9a</chmetcnv>28,0x0047 ;for bootpack

DW 0

GDTR0:

DW 8*3-1

DD GDT0

alignb 16

bootpack:

其中:

;use >1mb memory set a20gate

call waitkbdout

mov al,0xd1

out 0x64,al ;write out port

call waitkbdout

mov al,0xdf ;enable a20

out 0x60,al

call waitkbdout

代码的目的是屏蔽键盘和鼠标,并使CPU使用1MB以上的内存。60h64h端口是向Keyboardmouse发送和接收指令。

lgdt [GDTR0] ; init GDTR

初始化GDTR,为了使用32Bit模式,并防止多任务处理时内存访问冲突,提出Segmentation,就是将内存分割为块,每块称为Segment,其初始地址都为0,这样一来,程序就不再需要ORG指令,来指定运行程序的内存初始位置了。

每个Segment需要以下信息:

l Segment大小

l Segment地址

l Segment属性(禁止写,禁止执行,或者系统专用等)

本程序初始化2Segment,第一个为只读Segment,地址为0x000000,

第二个为可执行Segment,用来执行bootpack.c程序,地址为0x280000

DW 0xffff,0x0000,0x9200,0x00cf ;

DW 0xffff,0x0000,0x<chmetcnv w:st="on" unitname="a" sourcevalue="9" hasspace="False" negative="False" numbertype="1" tcsc="0">9a</chmetcnv>28,0x0047 ;for bootpack

mov eax,CR0

and eax,0x7fffffff ;set bit31 to 0( block paging

or eax,0x00000001 ;set bit1 to 1( enable protect mode

mov cr0,EAX

设置CR0寄存器,进入保护模式。

mov ax,1*8 ; reinit all the register from 0x0000 to 0x0008

mov ds,ax

mov es,ax

mov fs,ax

mov gs,ax

mov ss,ax

是将所有寄存器都进入第二个Segement

下面程序之前的代码都是将软盘的数据都保存到内存中。

;start bootpack

skip:

MOV ESP,0x00300000 ; init stack pointer

JMP DWORD 2*8:0x00

程序调到0x280000位置执行bootpack.c的程序。

4bootpack.cfunc.s,进入C语言

/*Colimas Simple OS*/

void io_hlt(void);

void write_mem8(int addr, int data);

//entry

void ColimasMain(void)

{

int i;

for(i=0xa0000;i<=0xaffff;i++){

write_mem8(i,15);

}

for(;;)

io_hlt();

}

//0xa00000xaffff是显卡内存地址。15代表白色。函数write_mem8功能是将0xa00000xaffff地址间的内存赋赋值为15,即白色。

for(i=0xa0000;i<=0xaffff;i++){

write_mem8(i,15);

}

for(;;)

io_hlt();

为死循环

func.s内实现write_mem8io_hlt函数。

;func.s

;Colimas Simple OS

[BITS 32]

segment .text

GLOBAL _io_hlt,_write_mem8

_io_hlt:

hlt

ret

_write_mem8: ;void write_mem8(int addr,int data);

mov ecx,[esp+4] ;addr

mov al,[esp+8] ;data

mov [ecx],al

RET

5. Makefile

MAKE = make -r

NASM = nasm

COPY = cp

LINK = olink

LD = ld

CAT = cat

<state w:st="on"><place w:st="on"><span lang="EN-US" style="mso-fareast-font-family: SimSun; mso-fareast-language: ZH-CN">DEL</span></place></state> = rm

CC = gcc

OBJCOPY = objcopy

default :

$(MAKE) img

bin : boot.s Makefile

$(NASM) boot.s -o boot.bin

sys : video.s objcopy Makefile

$(NASM) video.s -o video.sys

$(CAT) video.sys bootpack.img > video.img

bootpack : bootpack.c Makefile

$(CC) -c bootpack.c

func :func.s Makefile

$(NASM) -f coff func.s -l func.lst

objcopy : bootpack func Makefile

$(LD) bootpack.o func.o -o bootpack.bin

$(OBJCOPY) bootpack.bin -O binary bootpack.img

img : bin sys Makefile

$(LINK) -m boot.bin video.img -o boot.img

compile :

$(MAKE) img

run :

$(MAKE) compile

$(COPY) boot.img ../qemu/

clean :

-$(<state w:st="on"><place w:st="on">DEL</place></state>) *.bin

-$(<state w:st="on"><place w:st="on">DEL</place></state>) *.sys

-$(<state w:st="on"><place w:st="on">DEL</place></state>) *.img

-$(<state w:st="on"><place w:st="on">DEL</place></state>) *.o

汇编编译器Nasm

C语言编译器为GCC

连接器为ld

纯二进制转换器为objcopy

运行make命令后,编译生成boot.img,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值