自制操作系统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,可以参 ...
随机推荐
- 基于STM32的USB枚举过程学习笔记(转)
之前使用ST官方的库以及网络的资料,完成了使用USB HID类进行STM32和PC机的通讯.由于其他原因并没有深入的分析,虽然实现了功能,但是关于USB设备的枚举,以及具体的通讯方式都没有清晰的概念, ...
- windows创建定时任务执行python脚本
一.创建定时任务 \ [程序或脚本]文本框中填的是Python编译器的名称,一般就是python.exe, [起始于]文本框中填的是Python编译器的目录,上图中假设你的Python编译器的完整路径 ...
- Fiddler抓包请求前设置断点
1. 开启抓包 file--->capture traffic2. 在页面底部黑框输入bpu http://www.runoob.com/?s=mysql3. 在浏览器URL输入http://w ...
- SQL的几种连接:内连接、外连接(左连接、右连接、全连接)
表结构见前面博客 1.内连接 1.1.等值连接:在连接条件中使用等于号(=)运算符比较被连接列的列值,其查询结果中列出被连接表中的所有列,包括其中的重复列. 三种写法: select * from t ...
- flask基础二
内容有:1.配置文件处理,2.路由系统,3.视图,4.请求,5.响应,6.模板渲染,7.session,8.flash,9.中间件,10特殊装饰器 一:一个简单知识点 通过路径构成的字符串1.动态导入 ...
- 操作系统与cpu
- 转载:Android RecyclerView 使用完全解析 体验艺术般的控件
转自:https://blog.csdn.net/lmj623565791/article/details/45059587
- HRY and codefire
传送门: 设 dp[i][j]为第一个号i等级,第二个号j等级的期望值 a[i]存每个等级上分的概率 dp[i][j]=a[i]*dp[i+1][j]+(1-a[i])*dp[j][i]+1 dp[j ...
- php----------linux下安装php的swoole扩展
1.首先你已经安装好了php环境,这里就不介绍php环境的安装了.如果你是编译安装记得将php加入环境变量,以便于方便查看扩展是否安装成功. 2.我安装的php环境缺少了要给东西,详细看下图 如果你没 ...
- Java之.jdk卸载-Linux
Java之.jdk卸载-Linux 卸载Linux自带的jdk 首先查询: # rpm -qa | grep jdk 使用root账户,进行卸载: # yum -y remove xxxxxxxx( ...