自制操作系统Antz(7)——实现内核 (上)
Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html
Linux内核源码分析地址:https://www.cnblogs.com/LexMoon/category/1267413.html
在前几天的任务中,我们已经简单实现了MBR,直接操作显示器和硬盘操作来加载其他扇区的程序,如今已经可以进入保护模式了,简单引入了C语言,接下来我们编写自己的内核。
0. 汇编生成ELF
完成实模式到保护模式跳转的这一任务是由loader进行的,而我们不应该用loader做太多的事,loader只需要完成跳转就好了,剩下的工作交给内核。
为了加载内核到内存,需要使用ELF格式,如何编译这种格式呢?
来看看下面这个例子。
[section .data] strHello db "Hello, Antz !", 0Ah
STRLEN equ $ - strHello [section .text] global _start _start:
mov edx, STRLEN
mov ecx, strHello
mov ebx,
mov eax,
int 0x80
mov ebx,
mov eax,
int 0x80
global _start定义了程序的入口地址,相当于c/c++中main。
接下来使用NASM编译。
-f elf 指定了输出文件的格式为ELF格式。
编译完成之后要进行链接,链接指令如下:
(出现警告,在linux无警告,Windows下会有,可以无视)
-s是strip的简写,可以去掉符号表等内容,对生成的可执行代码进行减肥。
1. 汇编与C语言共同使用
我们已经可以生成一个支持载入内存的内核格式文件了,现在我们要学会把汇编程序和c语言程序链接在一起。这是我们编写内核的一大步。
先来看看c代码:
其中定义了一个choose函数,声明了一个myprint函数。
void myprint(char* msg, int len); int choose(int a, int b)
{
if(a >= b){
myprint("the 1st one\n", );
}
else{
myprint("the 2nd one\n", );
} return ;
}
再来看看汇编代码:
extern choose [section .data] ; 数据在此 num1st dd
num2nd dd [section .text] ; 代码在此 global _start
global myprint _start:
push num2nd
push num1st
call choose
add esp, mov ebx,
mov eax,
int 0x80 ; void myprint(char* msg, int len)
myprint:
mov edx, [esp + ] ; len
mov ecx, [esp + ] ; msg
mov ebx,
mov eax, ; sys_write
int 0x80
ret
如果你懂汇编,这个代码一定没有如何问题。
第一行的extern choose就是指c代码中定义的choose函数。
后面的global导出了函数入口,_start和在c文件中没有定义的myprint函数,myprint在汇编代码中完成了定义。
_start中调用了choose,choose中又调用了myprint函数。
这样这两个代码文件内容就很清晰了吧。
在Linux终端下查看结果:
nasm -f elf foo.asm -o foo.o
gcc -c bar.c -o bar.o
ld -s hello.o bar.o -o foobar
./foobar
2. 从Loader到内核
加载内核到内存和引导扇区的工作很相似,只是处理内核时我们要根据ELF文件结构中的值将内核中相应段放入相应位置。
fat12hdr.inc :
BS_OEMName DB 'Antz__Os' BPB_BytsPerSec DW
BPB_SecPerClus DB
BPB_RsvdSecCnt DW
BPB_NumFATs DB
BPB_RootEntCnt DW
BPB_TotSec16 DW
BPB_Media DB 0xF0
BPB_FATSz16 DW
BPB_SecPerTrk DW
BPB_NumHeads DW
BPB_HiddSec DD
BPB_TotSec32 DD BS_DrvNum DB
BS_Reserved1 DB
BS_BootSig DB 29h
BS_VolID DD
BS_VolLab DB 'Tinix0.01 '
BS_FileSysType DB 'FAT12 ' FATSz equ
RootDirSectors equ SectorNoOfRootDirectory equ
SectorNoOfFAT1 equ
DeltaSectorNo equ
boot.asm :
org 07c00h BaseOfStack equ 07c00h
BaseOfLoader equ 09000h
OffsetOfLoader equ 0100h jmp short LABEL_START
nop %include "fat12hdr.inc" LABEL_START:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack mov ax, 0600h
mov bx, 0700h
mov cx,
mov dx, 0184fh
int 10h mov dh,
call DispStr xor ah, ah
xor dl, dl
int 13h mov word [wSectorNo], SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word [wRootDirSizeForLoop],
jz LABEL_NO_LOADERBIN
dec word [wRootDirSizeForLoop]
mov ax, BaseOfLoader
mov es, ax
mov bx, OffsetOfLoader
mov ax, [wSectorNo]
mov cl,
call ReadSector mov si, LoaderFileName
mov di, OffsetOfLoader
cld
mov dx, 10h
LABEL_SEARCH_FOR_LOADERBIN:
cmp dx,
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR
dec dx
mov cx,
LABEL_CMP_FILENAME:
cmp cx,
jz LABEL_FILENAME_FOUND
dec cx
lodsb
cmp al, byte [es:di]
jz LABEL_GO_ON
jmp LABEL_DIFFERENT LABEL_GO_ON:
inc di
jmp LABEL_CMP_FILENAME LABEL_DIFFERENT:
and di, 0FFE0h
add di, 20h
mov si, LoaderFileName
jmp LABEL_SEARCH_FOR_LOADERBIN LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
add word [wSectorNo],
jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN LABEL_NO_LOADERBIN:
mov dh,
call DispStr
%ifdef _BOOT_DEBUG_
mov ax, 4c00h
int 21h
%else
jmp $
%endif LABEL_FILENAME_FOUND:
mov ax, RootDirSectors
and di, 0FFE0h
add di, 01Ah
mov cx, word [es:di]
push cx
add cx, ax
add cx, DeltaSectorNo
mov ax, BaseOfLoader
mov es, ax
mov bx, OffsetOfLoader
mov ax, cx LABEL_GOON_LOADING_FILE:
push ax
push bx
mov ah, 0Eh
mov al, '.'
mov bl, 0Fh
int 10h
pop bx
pop ax mov cl,
call ReadSector
pop ax
call GetFATEntry
cmp ax, 0FFFh
jz LABEL_FILE_LOADED
push ax
mov dx, RootDirSectors
add ax, dx
add ax, DeltaSectorNo
add bx, [BPB_BytsPerSec]
jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED: mov dh,
call DispStr jmp BaseOfLoader:OffsetOfLoader wRootDirSizeForLoop dw RootDirSectors
wSectorNo dw
bOdd db LoaderFileName db "LOADER BIN", MessageLength equ
BootMessage: db "Booting ";
Message1 db "Ready. ";
Message2 db "No LOADER"; DispStr:
mov ax, MessageLength
mul dh
add ax, BootMessage
mov bp, ax
mov ax, ds
mov es, ax
mov cx, MessageLength
mov ax, 01301h
mov bx, 0007h
mov dl,
int 10h
ret ReadSector:
push bp
mov bp, sp
sub esp, mov byte [bp-], cl
push bx
mov bl, [BPB_SecPerTrk]
div bl
inc ah
mov cl, ah
mov dh, al
shr al,
mov ch, al
and dh,
pop bx mov dl, [BS_DrvNum]
.GoOnReading:
mov ah,
mov al, byte [bp-]
int 13h
jc .GoOnReading add esp,
pop bp ret GetFATEntry:
push es
push bx
push ax
mov ax, BaseOfLoader
sub ax, 0100h
mov es, ax
pop ax
mov byte [bOdd],
mov bx,
mul bx
mov bx,
div bx
cmp dx,
jz LABEL_EVEN
mov byte [bOdd],
LABEL_EVEN:
xor dx, dx
mov bx, [BPB_BytsPerSec]
div bx push dx
mov bx,
add ax, SectorNoOfFAT1
mov cl,
call ReadSector
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [bOdd],
jnz LABEL_EVEN_2
shr ax,
LABEL_EVEN_2:
and ax, 0FFFh LABEL_GET_FAT_ENRY_OK: pop bx
pop es
ret times -($-$$) db
dw 0xaa55
loader.asm:
org 0100h BaseOfStack equ 0100h BaseOfKernelFile equ 08000h
OffsetOfKernelFile equ 0h jmp LABEL_START %include "fat12hdr.inc" LABEL_START:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack mov dh,
call DispStr mov word [wSectorNo], SectorNoOfRootDirectory
xor ah, ah
xor dl, dl
int 13h
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word [wRootDirSizeForLoop],
jz LABEL_NO_KERNELBIN
dec word [wRootDirSizeForLoop]
mov ax, BaseOfKernelFile
mov es, ax
mov bx, OffsetOfKernelFile mov ax, [wSectorNo]
mov cl,
call ReadSector mov si, KernelFileName
mov di, OffsetOfKernelFile
cld
mov dx, 10h
LABEL_SEARCH_FOR_KERNELBIN:
cmp dx,
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR
dec dx
mov cx,
LABEL_CMP_FILENAME:
cmp cx,
jz LABEL_FILENAME_FOUND
dec cx
lodsb
cmp al, byte [es:di]
jz LABEL_GO_ON
jmp LABEL_DIFFERENT
LABEL_GO_ON:
inc di
jmp LABEL_CMP_FILENAME LABEL_DIFFERENT:
and di, 0FFE0h
add di, 20h
mov si, KernelFileName
jmp LABEL_SEARCH_FOR_KERNELBIN LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
add word [wSectorNo],
jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN LABEL_NO_KERNELBIN:
mov dh,
call DispStr
%ifdef _LOADER_DEBUG_
mov ax, 4c00h
int 21h
%else
jmp $
%endif LABEL_FILENAME_FOUND:
mov ax, RootDirSectors
and di, 0FFF0h push eax
mov eax, [es : di + 01Ch]
mov dword [dwKernelSize], eax
pop eax add di, 01Ah
mov cx, word [es:di]
push cx
add cx, ax
add cx, DeltaSectorNo
mov ax, BaseOfKernelFile
mov es, ax
mov bx, OffsetOfKernelFile
mov ax, cx LABEL_GOON_LOADING_FILE:
push ax
push bx
mov ah, 0Eh
mov al, '.'
mov bl, 0Fh
int 10h
pop bx
pop ax mov cl,
call ReadSector
pop ax
call GetFATEntry
cmp ax, 0FFFh
jz LABEL_FILE_LOADED
push ax
mov dx, RootDirSectors
add ax, dx
add ax, DeltaSectorNo
add bx, [BPB_BytsPerSec]
jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED: call KillMotor mov dh,
call DispStr jmp $ wRootDirSizeForLoop dw RootDirSectors
wSectorNo dw
bOdd db
dwKernelSize dd KernelFileName db "KERNEL BIN",
MessageLength equ
LoadMessage: db "Loading "
Message1 db "Ready. "
Message2 db "No KERNEL" DispStr:
mov ax, MessageLength
mul dh
add ax, LoadMessage
mov bp, ax
mov ax, ds
mov es, ax
mov cx, MessageLength
mov ax, 01301h
mov bx, 0007h
mov dl,
add dh,
int 10h
ret ReadSector: push bp
mov bp, sp
sub esp, mov byte [bp-], cl
push bx
mov bl, [BPB_SecPerTrk]
div bl
inc ah
mov cl, ah
mov dh, al
shr al,
mov ch, al
and dh,
pop bx mov dl, [BS_DrvNum]
.GoOnReading:
mov ah,
mov al, byte [bp-]
int 13h
jc .GoOnReading add esp,
pop bp ret GetFATEntry:
push es
push bx
push ax
mov ax, BaseOfKernelFile
sub ax, 0100h
mov es, ax
pop ax
mov byte [bOdd],
mov bx,
mul bx
mov bx,
div bx
cmp dx,
jz LABEL_EVEN
mov byte [bOdd],
LABEL_EVEN:
xor dx, dx
mov bx, [BPB_BytsPerSec]
div bx push dx
mov bx,
add ax, SectorNoOfFAT1
mov cl,
call ReadSector
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [bOdd],
jnz LABEL_EVEN_2
shr ax,
LABEL_EVEN_2:
and ax, 0FFFh LABEL_GET_FAT_ENRY_OK: pop bx
pop es
ret KillMotor:
push dx
mov dx, 03F2h
mov al,
out dx, al
pop dx
ret
加载功能已经有了,但是还没有内核给以上程序拿来加载。
我们来实现一个最简单的内核,以后会基于此扩展。
kernel.asm :
此处的K不会打印,因为这里只是假设gs指向了显存。
[section .text] global _start _start:
mov ah, 0Fh ; 0000: 黑底 1111: 白字
mov al, 'K'
mov [gs:(( * + ) * )], ax ; 屏幕第 1 行, 第 39 列。
jmp $
出现了Ready,说明我们的kernel内核已经加载成功了。
自制操作系统Antz(7)——实现内核 (上)的更多相关文章
- 自制操作系统Antz(10)——实现shell(上)
我已经规范了系统代码风格,类似于按照linux分包,把各部分功能区分开了 Antz系统更新地址 Linux内核源码分析地址 Github项目地址 在之前的任务中,我们已经通过直接操作显卡驱动完成了简单 ...
- 自制操作系统Antz(9)——实现内核 (下) 实现图形化界面
Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html Linux内核源码分析地址:https://www.cnblogs. ...
- 自制操作系统Antz(8)——实现内核 (中) 扩展内核
Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html 在前几天的任务中,我们已经简单实现了MBR,直接操作显示器和硬盘操作 ...
- 自制操作系统Antz -- 系列文章
自制操作系统Antz day10——实现shell(上) AntzUhl 2018-10-10 16:25 阅读:192 评论:0 Linux内核源码分析 day01——内存寻址 AntzUhl ...
- 自制操作系统Antz(13) 显示图片
显示图片只是在多媒体课上看着bmp格式图片的突发奇想,然后就实现在了我自己的操作系统 Antz系统更新地址 Linux内核源码分析地址 Github项目地址 效果图: 显示图片的原理 在之前显卡操作时 ...
- 自制操作系统Antz(2)——进入保护模式 (上) jmp到保护模式
Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.htm Linux内核源码分析地址:https://www.cnblogs.c ...
- 自制操作系统Antz(6)——内核初步,引入c语言
Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html Linux内核源码分析地址:https://www.cnblogs. ...
- 自制操作系统Antz(4)——进入保护模式 (下) 实现内核并从硬盘载入
Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html Linux内核源码分析地址:https://www.cnblogs. ...
- 自制操作系统Antz(1)——Boot Sector
0.引子 最近在看操作系统底层方面的东西,最开始的为什么是07c00h这个问题就让我对操作系统有了很大的兴趣.所以准备在看书之余顺便写一个操作系统(Anz).至于为什么这个系统会被叫做Antz,可以参 ...
随机推荐
- dhtmlx Gantt知识点1
鼠标放在任务上显示信息框: <script src="../../codebase/ext/dhtmlxgantt_tooltip.js?v=5.2.0"></s ...
- 弄懂JDK、JRE和JVM到底是什么
首先是JDK JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK).在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bi ...
- Charles 使用
一.设置域名焦点 View->Focused Hosts…-> 二.抓包https:配置证书 1. 电脑安装SSL证书 选择 “Help” -> “SSL Proxying” -&g ...
- webpack.config.js配置遇到Error: Cannot find module '@babel/core'&&Cannot find module '@babel/plugin-transform-react-jsx' 问题
下文是网上找到的方法,是因为版本冲突的原因,参照后安装7版本解决 cnpm install -D babel-loader@ babel-core babel-preset-env 一. 问题描述 在 ...
- Applet学习教程(一):applet+dwr 实现
后台代码 import java.applet.Applet; import java.util.HashMap; import java.util.Map; import netscape.java ...
- 给opencart产品页添加额外信息
有时我们在开发opencart时需要给产品页添加一些额外的信息,第一种聪明的方法可以修改并调用已有字段,详细可以参考opencart3产品页调用upc/数量等信息:如果您的开发能力不错的话可以用第二种 ...
- 【Linux】Set CentOS no GUI default
[root@localhost ~]#vi /etc/inittab 重点看下面这部分代码 # 0 - halt (Do NOT set initdefault to this) ...
- ElasticSearch 随笔
1.如何用亚马逊S3存储一个ES服务索引.http://t.cn/R0fAJwK 2.ELK实战 - 利用Nginx日志分析API耗时.http://t.cn/R6sgQfU 3.Kibana中的地 ...
- reduce函数
python中的reduce python中的reduce内建函数是一个二元操作函数,他用来将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给reduce中的函数 func()(必须是 ...
- 实验一 C运行环境与最简单程序设计
#include<stdio.h> int main(){ int a,b,sum; a=123; b=456; sum=a+b; printf("sum is %d\n&quo ...