时隔很多年,重新学一遍汇编。觉得这个大灰狼学汇编的视频很好。
仔细的听,仔细的做了笔记、实验。感觉很不错!
继续加油!!
-------------------12-----------------------------
;;;;;;;;;;;;;boot.asm;;;;;;;;;;;;;;;;;;
;我们的启动程序实现很简单的功能,在屏幕中央打印一行字符串即可
org 07c00h ;org指令明确告诉编译器我程序的段地址是7C00h,而不是原来的0000
;int汇编指令 “int 10h”调用bois里的中断程序:显示字符串
mov ax,cs
mov es,ax
mov bp,msgstr ;es:bp 指向的内容就是我们要显示的字符串地址了
mov cx,12 ;显示的字符串长度
mov dh,12 ;显示的行号
mov dl,36 ;显示的列号
mov bh,0 ;显示的页数
mov al,1 ;显示的是串结构
mov bl,0ch ;显示的字符属性
mov ah,13h ;明确调用13h子程序
msgstr: db "hello my os!"
int 10h
times 510-($-$$) db 0 ;重复n次每次填充值为0
dw 55aah
jmp $ ;不断跳转到当前位置,是个死循环
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
/////////////////write_image.c//////////////////////
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc,char *argv[])
{
int fd_source;
int fd_dest;
int read_count=0;
char buffer[512]={0};
fd_source=open("boot.bin",O_RDONLY);
if(fd_source<0)
{
perror("open boot.bin error:");
return 0;
}
fd_dest=open("v1.vfd",O_WRONLY);
while((read_count=read(fd_source,buffer,512))>0)
{
write(fd_dest,buffer,read_count);
memset(buffer,0,512);
}
printf("write image ok!");
return 0;
}
////////////////////////////////////////////
-----------------13--------------------------------
主要内容
实模式概念
保护模式概念
选择子
段描述符
系统地址寄存器
实模式概念
计算机加电后,cpu就默认属于real-model(实模式)下
实模式只能访问地址在1M以下的内存称为常规内存,我们把地址在1M以上的内存称为扩展内存。
seg:offset 20位地址,只能访问1M空间
通过这种组合指向的内存地址就是实际的物理内存地址
32位cpu
intel退出32位cpu时完全兼容了16位cpu。
所谓兼容其中很重要的一点就是可以继续使用16位的内存寻址方式。
大家都知道16cpu内存寻址是通过段寄存器:通用寄存器来表示实际的内存地址。
32位cpu地址线32根,最大内存为4GB,如何利用原来的seg:offset(实现20根地址线)表示方式,来表示32根地址线?
保护模式
在保护模式下cpu依然使用段寄存器和通用寄存器来表示内存地址,但如何用20位地址来实现32位地址线寻址能力?
有张表,纪录段地址 开始地址 大小(段界限) 属性
16位段寄存器纪录表的【【索引】】
新的内容访问思路
在实模式下,我们把内存分成一个个内存段来表示,那么在保护模式下内存也被分为一个个内存段表示。
那么我们就把实现分好的内存段信息存入一张表格中,然后段寄存器中保存你要访问内存段所在的这张表格的索引。
保存表中索引的段寄存器,我们称为段选择子。
表中每个表示32位内存段信息我们称之为段描述符。
整张表称之为【【段描述符表】】。
段选择子
段选择子16位(段寄存器16位),其中高13位存放描述符表中的索引,其低3位用来表示段描述符表中所指向的段描述符的属性。
因此表中段描述符最大个数为2^13=8096个。
TI(Table Indicator):用来表示是从全局描述符表中读取描述符还是从局部描述符表中读取描述符。
RPL(Request Priviledge Level):用于特权检查.
形成物理地址
段寄存器-(索引号)-->段描述符表--->段描述符A--->线性地址空间(物理地址) 不考虑分页时,线性地址=物理地址
段描述符结构
既然段描述符包含了段的开始地址和段的界限,那么了解该结构至关重要
段描述符共8个字节,每个字节都具有具体含义
段界限(segment limit)20位被分为两个部分,第一部分保存在1,2字节中,第二部分保存在7
段基地址(segment base)32位被分成两个部分,第一部分23个字节被存放在3,4,5字节中,第二部分放在8
段属性(attributes)包含了该段属性和段界限的第二部分
段基地址剩余部分(base)包含了段界限剩余的8位
内存分配
由于我们现在编写的在裸机上编写程序,因此内存必须我们自己在4GB内存中进行分配
-----------------14--------------------------
段属性
段属性位于段描述符的第6和第7个字节,用来描述该段是数据段还是代码段或者堆栈段,对于数据段或者堆栈段来说是否可读是否可写,
对于代码段来说是否可执行以及段描述符所指定的内存段在物理内存中是否存在。
从左往右
0~3 TYPE :说明存储段描述符所描述的存储段的具体属性。是属于代码段还是数据段,可读可写还是可执行。
4 DT :说明了该描述符所指定的系统端描述符海华丝存储段描述符。
5~6 DPL :表示描述符特权级别。
7 P :表示描述符对地址的转换是否有效。
第二个字节
0~3 Limit :段界限第二部分剩余的4位。
4 AVL :软件可利用完,80386对该位未做规定
5 :0
6 D :表示如果该段是代码段,是否是16位还是32位代码段,如果该段是数据段是否是16还是32位,1表示32位
7 G :段界限粒度位G=0表示段边界64k,G=1表示段边界4GB
段界限
我们既然分了8M的内存段,那么段界限就是8M,那么8M占用多少字节,怎样用16进制表示并争取填充到段描述符中呢?
8M=2^23=800000H
不能直接把800000这个16进制直接写段描述符的相应位置中,并且20位的段界限 23位二进制数如何解决?
段界限公式
段界限=limit*4k+0FFFH
800000=limit*4k+0FFFH
limit就是要填写到段描述符中的段界限位置
limit=(800000-0FFFH)/4k=7FFH
段描述符的填写
我们的偏移地址都是通过8M通过公式得出段界限为7FF
我们第一个内存的段从内存00000处开始,所以段基地址全为0
那么我们创建的段位数据段并且是可读可写的,那么就必须在attributes字段中填写相应的数据。
base attributes segment base segment limit
0000 000000000000 07FF
TYPE :我们定义的是数据段并且我们要求该段可读可写那么tpye值填为0010,如果我们创建的是代码段可读可执行,那么为1010
DT :DT用来区别系统段还是存储段,我们这边都是存储段。
DPL :表示内存段的权限,这里为00表示
P :表示描述符对地址转换是否有效,1表示有效
Limit:表示剩余4位段界限描述符 0000
AVL :保留为0
D :1 我们编写的是保护模式,32位
G :1
数据段描述符
根据以上内容我们可以定义符合数据段描述符的汇编代码
dw 07FFh ;段界限
dw 0h ;段基地址0~18位
db 0h ;段基地址19~23位
db 10010010b ;段描述符的第6个字节属性(数据段可读可写)
db 11000000b ;段描述符的第7个字节属性
db 0 ;段描述符的最后一个字节也就是段基地址的第二部分
代码段描述符
代码段描述符和数据段描述符基本一致,不同在于段基地址和段属性
dw 07FFh ;段界限(保持不变)
dw 1h ;段基地址0~18位