操作系统篇-hello world(免系统运行程序)

  一、前言

今天起开始分享关于操作系统的相关知识,本人也是菜鸟一个,正处于学习阶段,这整个操作系统篇也是我边学习边总结的一些结果,希望能给正在学习或者有意向学习操作系统的童鞋带来帮助。

二、有关知识

在进入代码之前,先给大家普及一些硬件知识,如果你已经具备了这方面的知识,可以直接略过这部份。

1.计算机怎么启动操作系统的?

首先,我们思考一个问题,为什么一个硬盘安装系统之后打开计算机电源之后就能正常加载启动呢?这看起来似乎很智能,似乎计算机像活的一样会自动去硬盘中找系统代码并自行加载。其实不然,在计算机的世界里一切也都是离不开规则的。而基于这些硬件所定的规则或者协议,我们将启动代码放到协议规定的地方,这时候启动就会加载这部分代码。听起来好像有点乱,我们继续看。

2.主引导扇区

很多安装过系统的童鞋都应该知道引导盘这个东西,就是在我们启动电脑的时候可以通过bios来设定是通过U盘启动还是通过硬盘启动。对于硬盘来说,硬盘的第一个扇区是 0 面 0 道 1 扇区,或者说是 0 头 0 柱 1 扇区,这个扇区称为主引导扇区。如果计算机的设置是从硬盘启动,那么, ROM-BIOS 将读取硬盘主引导扇区的内容,将它加载到内存地址 0x0000:0x7c00 处(也就是物理地址 0x07C00),然后 jmp 跳到那里接着执行:

jmp 0x0000:0x7c00

  为什么偏偏是 0x7c00 这个地方?还不太清楚。反正当初定下这个方案的家伙已经被人说了很多坏话!!

  通常,主引导扇区的功能是继续从硬盘的其他部分读取更多的内容加以执行。像 Windows 这样的操作系统,就是采用这种接力的方法一步一步把自己运行起来的。

说到这里,我们可以想象,如果我们把自己编译好的程序写到主引导扇区,不也能够让处理器执行吗?

其实这就是我们寻找的答案,这几乎是在不依赖操作系统的情况下,让我们的程序可以执行的唯一方法。但这里要注意可别拿自己的电脑乱试,系统一下就瘫痪了,我们可以通过虚拟机来进行我们的代码运行与调试。

  三、配置

  1.nasm

首先安装nasm,方便编译我们的代码,为了大家方便,本文后面会附上相关的下载地址。

安装过程是直接安装,一直next:

  

  

  安装完成之后,我们可以启动nasm的shell,通过该shell进行相关编译工作。

  2.bochs

该软件可用于创建硬盘或软盘,同时也可模拟计算机启动,可以加载我们写好的启动盘。

  点击I Agree进入下面的界面:

  这个界面,大家看自己的需求选择,然后点击next:

  

  这里DLX Linux Demo是默认没选上的,安装Bochs时不妨选中“DLX Linux Demo”,便可直接参考它的配置文件。

  继续next:

选择好安装位置,install就行了。

3.dd

该工具用于将我们编译后的机器码写入到启动扇区中。我这里用的是dd-0.6beta3,将附件下载后解压,拿到里面的exe文件,在cmd下cd到该目录就可以使用dd命令进行写入操作。

  四、程序

说了这么多,还没见到代码,下面我们就一段代码了实现字符串的显示,由于代码是用汇编写的,所以没有汇编基础的童鞋可能需要先看看汇编的语法。

废话不多说了,直接上代码:

 1 org 07c00h ;告诉计算机将代码加载到内存的07c00h
 2 mov ax, cs
 3 mov ds, ax ;初始化数据段ds
 4 mov es, ax ;初始化附加段寄存器
 5 call DispStr ;调用DispStr来显示字符串
 6 jmp $  ;无限循环
 7 DispStr:
 8   mov ax, BootMessage ;将字符串地址传给寄存器ax
 9   mov bp, ax ; 通过ES:BP来指向显示的字符串
10   mov cx, 16 ; 表示字符串的长度
11   mov ax, 01301h ;10h的13号中断,此时通过AH=13传入,AL=1,表示目标字符串仅仅包含字符,属性在BL中包含,移动光标
12   mov bx, 000ch  ;BH表示视频区页数
13   mov dl, 0 ;DL表示在第几列显示(0为第一列)
14   int 10h ;10H中断
15   ret
16 BootMessage:  db "Hello,OS World!"
17 times 510-($-$$) db 0  ;用times来创建字节0
18 dw 0xaa55 ;扇区结尾,写入引导程序标志位

  上面的代码注释比较清晰的解释了程序的意思,这里我们在详细分析一下。

  在前面我们讲到因为硬件设计的原因,在充电的时候,回去内存的07c00h处读取指令,因此,我们通过org 0700ch来讲程序加载到该地址。接着初始化了段寄存器,然后调用字符串的显示的代码部分从而将字符串显示在显示器上面。

  在DispStr中,相关寄存器的操作都是为了后面的10H中断做准备,int 10h这条指令的触发将会使得ES:BP所指向的字符串进行显示。

  显示完成后,原则上整个程序就结束了,但对处理器来说,它并不知道。对它来说,取指令、执行是永无止境的。程序有大小,执行无停息,它这么做的结果,就是会执行到后面非指令的数据上,然后……

  问题在于我们现在的确无事可做。为避免发生问题,源程序第 6 行,安排了一个无限循环:jmp $。其中$等同于标号,你可以把它看成是一个隐藏在当前行行首的标号。

说到这里就只剩下最后两行代码了,其实这里也是可以算是一个协议来的。因为主引导扇区在系统启动过程中扮演着承上启下的角色,但并非是唯一的选择。如果硬盘的主引导扇区不可用,系统还有其他选择,比如可以从光盘和 U 盘启动。

然而,如果不试试水的深浅就一个猛子扎下池塘,这并非一个明智之举。同样地,如果主引导扇区是无效的,上面并非是一些处理器可以识别的指令,而处理器又不加鉴别地执行了它, 其结果是陷入宕机状态,更不要提从其他设备启动了。

为此,计算机的设计者们决定,一个有效的主引导扇区,其最后两个字节的数据必须是 0x55和 0xAA。否则,这个扇区里保存的就不是一些有意而为的数据。这就是最后一行代码的解释:dw 0xaa55。

  根据上面的说法,这里还要解决另外的一个问题,就是如何使这两个字节正好位于 512 字节的最后。前面的代码有多少个字节我们不知道,那是由 NASM 编译器计算和跟踪的。这时倒数第二行代码就起作用了,这里通过创建数值为0的字节来补充余下的空间,其中$$是 NASM编译器提供的另一个标记,代表当前汇编节(段)的起始汇编地址。

 到此,我们对于代码的分析完毕了。

  五、编译与运行

  这时候打开我们前面安装好的nasm shell,cd定位到我们的boot.asm的位置,然后执行nasm boot.asm -o boot.bin

  然后,我们通过bochs来创建一个软盘,通过软盘来做启动盘从而启动执行我们的程序。

  首先,打开bochs安装目录的bximage.exe文件

  下面是打开后的界面:

  然后输入1并回车,选择创建一个软盘或硬盘,进入下面的界面:

  这时候会询问要创建的类型是hd还是fd,我们输入fd回车,进入下面的界面:

这个提示是要我们选择要创建的盘符的大小,我们直接回车选择默认的1.44M就行了:

  到这里可以为创建的镜像输入名称,也可以用a.img作为默认名。回车后,这时会在bochs安装的目录下面多了一个a.img的文件,这个就是我们刚刚创建的镜像文件:

  到此,我们创建好了软盘,下面就是将程序写入到软盘的第一个扇区,这时,我们dd工具就派上用场了,我们启动命令行,cd到dd的根目录,然后执行写入的命令:

dd  if=boot.bin  of=a.img  bs=512  count=1  conv=notrunc

  注意这里我把编译好的boot.bin文件与镜像a.img跟dd放在同一目录,不是同一目录的同学请自行修改路径。

  执行完后,a.img就是我们要的启动盘了。

  六、运行

运行的时候是肯定不能在真机上面运行的,这时就要用到虚拟机了,我用的是vm ware。

首先,我们需要创建一个新的虚拟机,主要的步骤如下:

  

  选择自定义,单击下一步进入下一个界面:

  

  

  这里默认就可以了,直接单击下一步:

  

  这里选择稍后安装操作系统,下一步:

  

  这里选择其他,然后下一步:

  

  这里是处理器的配置,因为我们的程序都很简单,而不是玩游戏,所以选择最低配置就可以了:

  

  选择好内存,单击下一步:

  

  关于网络就随意选都行,反正我们暂时不会涉及网络方面的东西,单击下一步:

  

  IO控制器,直接默认就行,下一步:

  

  虚拟磁盘类型,选择IDE,单击下一步:

  

  创建磁盘,单击下一步:

  

  这里尽量选小一点的磁盘,因为我们用不上的,我们这里是通过软盘来启动的:

  

  选择磁盘文件的位置,然后单击下一步:

  

  单击完成,此时我们的虚拟机就创建好了。

这个时候不要急于去启动它,因为我们还有将我们刚刚做好的启动盘配置进来,作为虚拟机的启动盘。下面我们继续通过截图来说明,这样会直观一些:

  

  这里我们选择图中红色圈住的地方,来我们刚刚创建好的虚拟机:

  

  选择添加,来添加我们刚刚制作好的软盘:

  

  选择软盘驱动器,单击下一步:

  

  选择使用软盘镜像,单击下一步:

  

  选择我们刚刚的a.img,并勾选启动时连接,单击完成。

  这时候我们的准备工作就结束了,可以启动虚拟机来看看我们的工作成果了:

  

  

  可以看到我们字符串Hello,OS World!显示在上面。

  这个时候,心细的同学可能有疑问了,为什么显示的字符串是红色的,为什么不是白色或者其他颜色呢?要显示其他颜色也是可以的,这其实是我们写在了程序里面的,这其实是有AL与BL寄存器来决定的。

  如果AL的BIT1为1,则BL表示显示属性。属性为:

  |BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0| BL

  BIT7:背景是否闪烁。0不闪烁,1闪烁

  BIT6~BIT4为背景色,分别为RGB,000为黑色,111为白色

  BIT3为1,则前景色加亮,为0则不加亮

  BIT2-BIT0为前景色,意义同背景色

  有兴趣的同学可以尝试修改代码运行试试,这里就不一一列举 了。

  七、总结

回顾上面所讲的内容,我们主要讲解了以下几点的内容:

1.如何免系统运行程序:由于硬件设计的原因,在计算机充电启动的时候会去内存的0x07c00h处读取指令,因此我们通过指令org 0x07c00h将代码加载到内存的该位置。

2.计算机如何知道要我们制作的软盘就是启动盘呢?因为在软盘的第一扇区最后的两个字节是计算机识别启动盘的位置,我们通过将这两个字节设置成0xaa55,从而告诉计算机,该软盘就是启动盘。

3.如何通过代码将字符串显示到显示器上?我们利用10H中断,该中断会去ES:BP所指向的内存地址读取内容并显示。

4.显示是样式如何设定?将AX的低八位AL的BIT1设置为1,表示要显示的是字符串,而且样式包含在BL中,而在BL中我们设置的值为0x0c,也就是二进制的0000_1100,从上面 对BL的各个位的讲解,我们知道该内容是将字符串设置为红色。

5.同时,我们也学会了利用bochs来制作镜像,另外bochs也可以用来调试,以后的文章也会用到,希望大家多多关注。

6.通过dd工具将程序写入镜像。

  下面是本文中用到的相关工具的下载地址

时间: 2024-08-03 21:14:18

操作系统篇-hello world(免系统运行程序)的相关文章

Android中插件开发篇之----动态加载Activity(免安装运行程序)

一.前言 又到周末了,时间过的很快,今天我们来看一下Android中插件开发篇的最后一篇文章的内容:动态加载Activity(免安装运行程序),在上一篇文章中说道了,如何动态加载资源(应用换肤原理解析),没看过的同学,可以转战: http://blog.csdn.NET/jiangwei0910410003/article/details/47679843 当然,今天说道的内容还这这篇文章有关系.关于动态加载Activity的内容,网上也是有很多文章介绍了.但是他们可能大部分都是介绍通过代理的方

程序员的自我修养——操作系统篇

转:http://kb.cnblogs.com/page/211181/ 也许,只需这一篇文章,便能让你全面的认识操作系统! 在阅读本文之前,推荐阅读“自己动手制作4位计算机”. 目录: 1. 进程的有哪几种状态,状态转换图,及导致转换的事件. 2. 进程与线程的区别. 3. 进程通信的几种方式. 4. 线程同步几种方式. 5. 线程的实现方式. (用户线程与内核线程的区别) 6. 用户态和核心态的区别. 7. 用户栈和内核栈的区别. 8. 内存池.进程池.线程池. 9. 死锁的概念,导致死锁的

程序员的自我修养——操作系统篇(转)

也许,只需这一篇文章,便能让你全面的认识操作系统! 在阅读本文之前,推荐阅读“自己动手制作4位计算机”. 目录: 1. 进程的有哪几种状态,状态转换图,及导致转换的事件. 2. 进程与线程的区别. 3. 进程通信的几种方式. 4. 线程同步几种方式. 5. 线程的实现方式. (用户线程与内核线程的区别) 6. 用户态和核心态的区别. 7. 用户栈和内核栈的区别. 8. 内存池.进程池.线程池. 9. 死锁的概念,导致死锁的原因,导致死锁的四个必要条件,处理死锁的四个方式,预防死锁的方法.避免死锁

Android应用程序框架层和系统运行库层日志系统源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6598703 在开发Android应用程序时,少不了使用Log来监控和调试程序的执行.在上一篇文章Android日志系统驱动程序Logger源代码分析中,我们分析了驱动程序Logger的源代码,在前面的文章浅谈Android系统开发中Log的使用一文,我们也简单介绍在应用程序中使Log的方法,在这篇文章中,我们将详细介绍Android应用程序框架

Linux系统下程序后台运行nohup,&,screen等

"nohup" 在用户ssh终端断开或者网络端口时,终端没有HUP信号则会关闭所有子进程. nohup则会让进程忽略HUP信号,不受终端断开限制 一般在结尾加上"&"将命令同时放到中断后台运行 nohup标准输出和标准错误输出会被重定向到nohup.out文件中 [[email protected] ~]# nohup ping www.ibm.com & [1] 3059 nohup: appending output to `nohup.out'

在开发系统时候运行程序突然报出“WebDev.WebServer40.exe已停止工作”的错误的解决办法

问题描述:在开发系统时候运行程序突然报出“WebDev.WebServer40.exe已停止工作”的错误,程序调试运行,发现程序在打开数据库时候报错,也就是Connection.Open()处. 但是发现程序连接本地数据库正常,连接内网服务器数据库会报错,但是Sqlserver是可以直接连接到内网服务器数据库,所以排除了程序问题和数据库远程设置问题. 解决方法:经过查找和试验,最后发现是的Winsock协议配置有问题,导致网络连接出现异常,有资料说是因为360安全卫士拦截网络访问通道导致的. 解

开发系统时候运行程序突然报出“WebDev.WebServer40.exe已停止工作”的错误

已经解决,问题描述:在开发系统时候运行程序突然报出“WebDev.WebServer40.exe已停止工作”的错误,程序调试运行,发现程序在打开数据库时候报错,也就是Connection.Open()处. 但是发现程序连接本地数据库正常,连接内网服务器数据库会报错,但是Sqlserver是可以直接连接到内网服务器数据库,所以排除了程序问题和数据库远程设置问题. 解决方法:经过几个星期断断续续的查找和试验,最后发现是的Winsock协议配置有问题,导致网络连接出现异常,有资料说是因为360安全卫士

如何在Windows下使用Linux系统来编译和运行程序?

很多开发人员都有这样的疑问:自己平时是在Windows下面办公的,而自己编写的程序的运行环境又是Linux的,如何从Windows切换到Linux呢?是不是要专门到Linux机器上去编写代码呢? 实际上,只要在Windows下安装一个叫做SecureCRT的软件和一个叫做FileZilla的软件,便可轻松解决问题. SecureCRT和FileZilla简介 SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录Linux服务器主机的软件. Fil

Thinkphp3.2新手篇之系统运行流程1

如果公司使用的tp框架,那么作为新人在首先会被要求了解tp的系统运行流程,本文章意在帮助新童鞋快速了解tp系统流程.流程说明按照tp手册给出的进行(序号也相同,方便大家查看): 1.用户URL请求,2.调用应用入口文件(这里以index.php为例) 大部分网站是利用url重写隐藏了index.php的,这里的方法请查看tp手册.首先执行index.php, 1 // 应用入口文件 2 3 // 检测PHP环境 4 if(version_compare(PHP_VERSION,'5.3.0','