W1*OS自制操作系统

admin 2021年12月29日05:23:11评论72 views字数 3642阅读12分8秒阅读模式

前言

做一个自己的操作系统一定是很一件很酷的事。今天仔细读了下上面三篇文章,都非常不错,不过比较遗憾的是除了第一节的hello world之外,后面的数据结构的定义,各种模式的转换都非常脑坑疼。为了能尽快做出一个成品来获得正反馈(zhuangb),我将中间一系列过程能省则省掉了,最终能最简单展示一个helloworld的窗口程序,来增强一下满足感。

普通流程

虽然我力图精简大部分的流程,但是操作系统的制作流程还是需要明白的。

软盘读写

首先BIOS只能读取软盘512个字节,但是操作系统内核明显会超过它,所以一般这512字节都会写一个内核加载器,通过它来加载我们真正的内核。

内核加载器

内核加载器的作用是什么呢,它用来告诉BIOS,“来加载512字节之后的数据吧~”。同时我们还要注意我们编译出来的img的结构大小,前512字节是加载器的二进制代码,不足的用00来代替,后面是我们真正内核的代码。需要注意的是,内核加载器由于硬件(软盘)的结构限制,只能以512字节为单位加载内核,如果内核超出,需要及时修改加载器,告诉它“需要加载更多内核代码”。

保护模式32位寻址

计算机默认进入的实模式,但是它的功能有限,我们需要操作CPU来进入“保护模式”,上面的参考文章也会在一开始告诉你,如何进入保护模式。总之就是定义一堆看不懂的数据结构~

跨平台C语言的编译

进入到保护模式后,就可以访问到更大的内存空间了,接下来就是抛弃汇编,使用C语言编写内核。首先的问题是,C语言编写的程序如何让我们内核识别到?使用我们系统的gcc编译一个不带任何依赖的gcc即可(听起来有点好玩,就和go语言用go写的一样),然后在汇编种预留c语言的接口

[bits 32][extern main] ; Define calling point. Must have same name as kernel.c 'main' functioncall main ; Calls the C function. The linker will know where it is placed in memoryjmp $

之后用编译出来的gcc编译c语言代码,汇编编译汇编代码,将两个文件合起来即可。

绘制界面

如果要绘制界面,需要用汇编调用BIOS的中断,操作硬件打开显卡色彩功能(可以理解为用汇编操作BIOS的API)。

打开VGA显卡

mov  al, 13hmov  ah, 0x00int  0x10

画像素点

mov  ah,0chmov  al,10;颜色值 1~256mov  dx,1 ;x坐标mov  cx,1 ;y坐标mov  bh,0int  0x10

通过一个像素点,就可以画整个图形界面了(有点以前OpenGL写游戏的味道)

精简流程

为了最快自制一个带界面的操作系统,我精简了一个流程(虽然还是花了一天)。我们直接用汇编操作BIOS的显卡功能,什么加载器,什么GDT,统统不要。

直接上代码

org  0x7c00;
jmp entry
entry: mov ax, 0 mov ss, ax mov ds, ax mov es, ax mov si,font_X mov di,font_Y


putloop: mov al, 13h mov ah, 0x00 int 0x10
mov cx,0 mov dx,0 x: cmp cx,320 je y ; mov dx, 2 call draw add cx,1 jmp x y: add dx,1 mov cx,0 cmp dx,200 je draw_menu jmp x draw_menu: mov cx,0 mov dx,183 x2: cmp cx,320 je y2 call draw_greem add cx,1 jmp x2 y2: add dx,1 mov cx,0 cmp dx,200 je draw_hello jmp x2
draw_hello: mov cx,0 mov dx,0 _loop_x:
mov cl, [si] add si, 1 mov dl, [di] add di, 1 cmp cl, 0 je fin call draw_font ; mov ah, 0x0e ; mov bx, 15 ; int 0x10 jmp _loop_x ; _loop_y: jmp fin


draw: pusha mov ah,0ch mov al,8 mov bh,0 int 0x10 popa ret
font_X: DB 13,12,13,11,13,13,13,13,13,13,13,13,13,13,11,12,13,14,15,1,2,3,6,7,8,2,7,2,7,2,7,2,4,5,7,2,4,5,7,2,4,5,7,2,4,5,7,3,6,3,6,3,6,3,6,3,6,20,21,19,20,21,22,19,20,21,22,20,21,27,28,29,26,30,25,31,25,31,25,31,25,31,25,31,25,31,25,31,25,31,25,31,26,30,27,28,29,35,36,37,39,34,38,39,33,39,33,39,33,34,35,36,37,38,39,33,39,33,39,33,34,38,33,35,36,37,50,51,53,54,49,50,51,52,53,54,55,49,50,51,52,53,54,55,49,50,51,52,53,54,55,50,51,52,53,54,51,52,53,52 db 0
font_Y: DB 1,2,2,3,3,4,5,6,7,8,9,10,11,12,13,13,13,13,13,1,1,1,1,1,1,2,2,3,3,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,10,10,11,11,12,12,13,13,6,6,7,7,7,7,8,8,8,8,9,9,1,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,13,1,1,1,1,2,2,2,3,3,4,4,5,6,7,7,7,8,9,10,10,11,11,12,12,12,13,13,13,13,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,7,8,8,8,8,8,9,9,9,10 db 0draw_greem: ; pop dx ;坐标y ; pop cx ;坐标x pusha mov ah,0ch mov al,7 mov bh,0 int 0x10 popa ret
draw_font: ; pop dx ;坐标y ; pop cx ;坐标x pusha mov ah,0ch mov al,10 mov bh,0 int 0x10 popa ret
fin: HLT jmp fin
times 510-($-$$) db 0dw 0xaa55

通过nasm编译

nasm kernel.asm -f bin -o kernal.img

最终效果图

W1*OS自制操作系统

font_X,font_Y是什么呢,是文字的像素坐标,因为不会用汇编操作多维数组,只能自己用Python写个转换程序,将文字转换为坐标 - =

Python转换程序

def draw_font(chars, pianyi_x=0, pianyi_y=0):    chars = chars.strip().splitlines()    y = 0 + pianyi_y    x = 0 + pianyi_x    _x = []    _y = []    output = []    for line in chars:        x = 0 + pianyi_x        for i in line:            if i == '*':                output.append((x, y))            x += 1        y += 1    print(output)
s = "" for point in output: s += str(point[0]) + "," print("x:DB " + s.strip(","))
s = "" for point in output: s += str(point[1]) + "," print("y:DB " + s.strip(","))

charsH = '''.................................**.**..*******.*******.*******..*****....***......*............................................'''charW = '''
'''draw_font(charsH, 1 + 16 + 16 + 8 + 8)

它将输出

x:DB 50,51,53,54,49,50,51,52,53,54,55,49,50,51,52,53,54,55,49,50,51,52,53,54,55,50,51,52,53,54,51,52,53,52y:DB 4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,7,8,8,8,8,8,9,9,9,10

将这个数值放到那段代码中即可。最后,其实可以把界面画的更好看点,但是因为没有做内核加载器,我们的程序只能512字节的大小,我这段代码刚刚差不多。我明天可以试试做个内核加载器将界面完善一下~

本文始发于微信公众号(Hacking就是好玩):W1*OS自制操作系统

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月29日05:23:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   W1*OS自制操作系统https://cn-sec.com/archives/499859.html

发表评论

匿名网友 填写信息