简介
操作系统开发到目前可以说已经掌握了相当多的知识体系了,是时候对相关代码作完善、美化的时候了,在开发中笔者发现了一些潜在的bug,正好作一些修复。以前都是农耕时代,现在将进入工业化生产阶段。
目标
1.代码功能模块化、扩展性强;
2.代码最好的注释就是代码(变量、函数名等见名知意);
3.隐藏该隐藏的,暴露该暴露的;
4.以后代码的添加将只会介绍新增的代码,避免大量重复的长篇博客;
5.每一文章末尾都会有整个文章的最终代码;
6.文中所有代码笔者都愿意把自己的思考开源给任何人使用,无需向笔者申请
说明
1.boot.s
;能用于操作内存的寄存器只能是bx、bp、si、di、sp,其中不指定段寄存器时bp、sp默认使用ss,其余使用ds
;0x7c00--0x7dff 这512字节用于启动区
;对内存的访问都必须指定段寄存器,没有显示指定时将使用ds作为段寄存器
org 0x7c00
LOAD_ADDR EQU 0x9000 ;内核加载偏移地址
mov ax,0
mov ss,ax
mov ds,ax
mov es,ax
mov bx,LOAD_ADDR
mov ch,1 ;柱面号
mov dh,0 ;磁头号
mov cl,1 ;扇区号
mov ah,0x02 ;0x02表示读盘操作
mov al,18 ;表示连续读取扇区数
mov dl,0 ;驱动器号,早期有多个软驱,一般只有一个写死0
int 0x13 ;调用BIOS实现磁盘读取
jc error ;读盘操作失败,flag标志寄存器cf 标志位被置1
jmp bx ;跳转到加载的内存地址开始执行代码
fin:
hlt
jmp fin
putloop:
mov al,[si]
inc si
cmp al,0
je fin
mov ah,0x0e ;中断调用参数
mov bx,15 ;字符颜色
int 0x10 ;中断调用号
jmp putloop
error:
mov si,errMsg
jmp putloop
errMsg:
db 'load floppy error'
db 0
2.floppy.h
//
// floppy.h
// os-test
//
// Created by vincent on 2018/10/29.
// Copyright © 2018年 vincent. All rights reserved.
//
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/**
*根据文件名创建一个3.5寸虚拟软盘
*3.5寸软盘结构:80个磁道,2个磁头,18个扇区。每个扇区512字节
*系统读取磁盘结构:0磁道0磁头1扇区,0磁道0磁头2扇区...,0磁道0磁头18扇区,0磁道1磁头1扇区,
*0磁道1磁头2扇区...,0磁道1磁头18扇区。再从1磁道0磁头1扇区....循环读取操作
*/
FILE* initFloppy(char *fileName);
/**
*读取软盘指定磁道,磁头,扇区数据
*@param c 磁道[0,79]
*@param h 磁头[0,1]
*@param s 扇区[1,18]
*@param fp 初始化的虚拟软盘文件
*@param buf 读取的磁盘数据,大小长度至少应该是512字节
*/
void readFloppy(int c,int h,int s,FILE *fp,char *buf);
/**
*写入软盘指定磁道,磁头,扇区数据
*@param c 磁道[0,79]
*@param h 磁头[0,1]
*@param s 扇区[1,18]
*@param fp 初始化的虚拟软盘文件
*@param buf 读取的磁盘数据,大小长度至多是512字节
*/
void writeFloppy(int c,int h,int s,FILE *fp,char *buf);
3.floppy.c
//
// floppy.c
// os-test
//
// Created by vincent on 2018/10/29.
// Copyright © 2018年 vincent. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE* initFloppy(char *fileName){
FILE *fp = fopen(fileName, "w");
char buf[512];
memset(buf, 0, 512);
for(int c=0;c<80;c++){//磁道
for(int h=0;h<2;h++){//磁头
for(int s=1;s<=18;s++){//扇区
fwrite(buf, 512, 1, fp);
}
}
}
return fp;
}
void readFloppy(int c,int h,int s,FILE *fp,char *buf){
//把虚拟软盘映射成线性偏移
int index = 18*2*512*c + h*18*512 + (s-1)*512;
int tmp = (int)ftell(fp);
fseek(fp, index, SEEK_SET);
fread(buf,512,1,fp);
fseek(fp, tmp, SEEK_SET);
}
void writeFloppy(int c,int h,int s,FILE *fp,char *buf){
//把虚拟软盘映射成线性偏移
int index = 18*2*512*c + h*18*512 + (s-1)*512;
int tmp = (int)ftell(fp);
fseek(fp, index, SEEK_SET);
fwrite(buf, 512, 1, fp);
fseek(fp, tmp, SEEK_SET);
}
4.main.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "floppy.h"
int main(int argc,char **argv){
FILE *fp = initFloppy("floppy.img");
if(fp == NULL) {
printf("初始化磁盘失败");
exit(0);
}
FILE *src = fopen("boot.bat", "r");
if(src == NULL) {
printf("文件打开失败:%s\n","boot.bat");
exit(0);
}
char buf[512];
memset(buf, 0, 512);
fread(buf, 512, 1, src);
buf[510] = 0x55;
buf[511] = 0xaa;
writeFloppy(0, 0, 1, fp, buf);
fclose(src);
src = fopen("kernel.bat", "r");
if(src == NULL) {
printf("文件打开失败:%s\n","kernel.bat");
exit(0);
}
//可正确处理18个扇区的数据内容
int c = 1,h = 0,s = 1;
int count = 0;
for(int i=0;!feof(src) && i < 18;i++){
memset(buf, 0, 512);
fread(buf, 512, 1, src);
writeFloppy(c, h,s, fp, buf);
count += 1;
s++;
if(s==19){
h++;
s = 1;
}
if(h==2){
h = 0;
c++;
}
}
fseek(src,0,SEEK_END);
long len = ftell(src);
if(len > 18*512){
printf("kernel.bat 文件长度%ldB,超过写入界限!!!\n",len);
}
else{
printf("读取了%dx512=%dB,floppy.img软盘文件制作成功\n",count,count*512);
}
fclose(src);
fclose(fp);
return 1;
}
5.kernel.s
;全局描述符结构 8字节
; byte7 byte6 byte5 byte4 byte3 byte2 byte1 byte0
; byte6低四位和 byte1 byte0 表示段偏移上限
; byte7 byte4 byte3 byte2 表示段基址
;定义全局描述符数据结构
;3 表示有3个参数分别用 %1、%2、%3引用参数
;%1:段基址 %2:段偏移上限 %3:段属性
%macro GDescriptor 3
dw %2 & 0xffff
dw %1 & 0xffff
db (%1>>16) & 0xff
dw ((%2>>8) & 0x0f00) | (%3 & 0xf0ff)
db (%1>>24) & 0xff
%endmacro
DA_32 EQU 4000h ; 32 位段
DA_C EQU 98h ; 存在的只执行代码段属性值
DA_DRW EQU 92h ; 存在的可读写数据段属性值
DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
;中断描述符表
;Gate selecotor, offset, DCount, Attr
%macro Gate 4
dw (%2 & 0xffff)
dw %1
dw (%3 & 0x1f) | ((%4 << 8) & 0xff00)
dw ((%2>>16) & 0xffff)
%endmacro
DA_386IGate EQU 8Eh ; 中断调用门
org 0x9000
jmp entry
[SECTION .gdt]
;定义全局描述符 段基址 段偏移上限 段属性
LABEL_GDT: GDescriptor 0, 0, 0
LABEL_DESC_CODE: GDescriptor 0, SegCodeLen-1, DA_C+DA_32
LABEL_DESC_VIDEO: GDescriptor 0xb8000, 0xffff, DA_DRW
LABEL_DESC_STACK: GDescriptor 0, STACK_TOP-1, DA_DRWA+DA_32
LABEL_DESC_VRAM: GDescriptor 0, 0xffffffff, DA_DRW
;gdt 表大小
GdtLen equ $-LABEL_GDT
;gdt表偏移上限和基地址
GdtPtr dw GdtLen-1
dd 0
;cpu开机进入实模式时使用的段寄存器 cs,ds,es,ss 和偏移地址组成内存地址,内存地址=段寄存器 * 16 + 偏移地址
;保护模式中段寄存器保存的是gdt 描述表中各个描述符的偏移,也叫选择子
SelectorCode32 EQU LABEL_DESC_CODE-LABEL_GDT
SelectorVideo EQU LABEL_DESC_VIDEO-LABEL_GDT
SelectorStack EQU LABEL_DESC_STACK-LABEL_GDT
SelectorVRAM EQU LABEL_DESC_VRAM-LABEL_GDT
;中断描述符表
LABEL_IDT:
%rep 0x21
Gate SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep
;键盘中断向量(8259A 键盘中断向量0x20,IRQ1 是键盘中断请求,0x20 + IRQ[n] = 0x21
.0x21:
Gate SelectorCode32, KeyboardHandler,0, DA_386IGate
%rep 10
Gate SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep
;从中断控制器8259A 中断向量0x28,IRQ4 是鼠标中断请求,0x28 + IRQ[n] = 0x2c
.0x2c:
Gate SelectorCode32, MouseHandler,0, DA_386IGate
IdtLen equ $ - LABEL_IDT
IdtPtr dw IdtLen - 1
dd 0
[SECTION .s16]
[BITS 16]
entry:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0x100
;检测系统内存
mov ebx, 0
mov di, LABEL_MEM_BUF
LABEL_MEM_CHK_LOOP:
mov eax, 0xE820
mov ecx, 20
mov edx, 0x534D4150
int 0x15
jc LABEL_MEM_CHK_FAIL
add di, 20
inc dword [LABEL_MEM_COUNT]
cmp ebx, 0
jne LABEL_MEM_CHK_LOOP
jmp LABEL_MEM_CHK_OK
LABEL_MEM_CHK_FAIL:
mov dword [LABEL_MEM_COUNT], 0
LABEL_MEM_CHK_OK:
;设置屏幕色彩模式
mov al,0x13
mov ah,0
int 0x10
;设置LABEL_DESC_CODE描述符段基址
mov eax,0
mov ax,cs
shl eax,4
add eax,SEG_CODE32
mov word [LABEL_DESC_CODE+2],ax
shr eax,16
mov [LABEL_DESC_CODE+4],al
mov [LABEL_DESC_CODE+7],ah
;设置栈空间
xor eax,eax
mov ax,cs
shl eax,4
add eax,LABEL_STACK
mov word [LABEL_DESC_STACK+2],ax
shr eax,16
mov byte [LABEL_DESC_STACK+4],al
mov byte [LABEL_DESC_STACK+7],ah
mov eax,0
mov ax,ds
shl eax,4
add eax,LABEL_GDT
mov dword [GdtPtr+2],eax
;设置GDTR 寄存器
lgdt [GdtPtr]
cli ;关闭可可屏蔽中断,如键盘中断
in al,0x92
or al,0x02
out 0x92,al
mov eax,cr0
or eax,1
mov cr0,eax
call init8259A
;加载中断描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_IDT
mov dword [IdtPtr + 2], eax
lidt [IdtPtr]
sti ;恢复中断
jmp dword SelectorCode32:0
;初始化8259A中断控制器
init8259A:
mov al, 0x11 ;向主8259A发送ICW1
out 0x20, al
call io_delay
out 0xa0, al ;向从8259A发送ICW1
call io_delay
;20h 分解成ICW2 是, ICW2[0,1,2] = 0, 这是强制要求的,
;也就是ICW2的值不能是0x21,0x22之类,只要前三位是0就行
;整个ICW2 = 0x20,这样的话,当主8259A对应的IRQ0管线向CPU发送信号时,
;CPU根据0x20这个值去查找要执行的代码,IRQ1管线向CPU发送信号时,
;CPU根据0x21这个值去查找要执行的代码,依次类推
mov al, 0x20 ;向主8259A发送ICW2
out 0x21, al ;
;
call io_delay
mov al, 0x28 ;向从8259A发送ICW2
out 0xa1, al
call io_delay
;04h 分解成ICW3 相当于ICW[2] = 1,
;这表示从8259A通过主IRQ2管线连接到主8259A控制器
mov al, 0x04 ; 向主8259A发送ICW3
out 0x21, al
call io_delay
mov al, 0x02 ;向从8259A 发送 ICW3
out 0xa1, al
call io_delay
mov al, 0x02
out 0x21, al
call io_delay
out 0xa1, al
call io_delay
;还需要再向两个芯片分别发送一个字节,叫OCW(operation control word),
;一个OCW是一字节数据, 也就是8bit,每一bit设置作用是,当OCW[i] = 1 时,
;屏蔽对应的IRQ(i)管线的信号,例如OCW[0]=1, 那么IRQ0管线的信号将不会被CPU接收,以此类推
;
mov al, 11111001b ;CPU只接收主8259A, IRQ1,IRQ2管线发送的信号,其他管线发送信号一概忽略
out 0x21, al ;IRQ1对应的是键盘产生的中断
call io_delay
mov al, 11101111b ;IRQ4 允许鼠标中断
out 0xa1, al ;鼠标是通过从8259A的IRQ4管线向CPU发送信号
call io_delay
ret
io_delay:
nop
nop
nop
nop
ret
;检测内存数据
LABEL_MEM_BUF: ;存放内存块
times 256 db 0
LABEL_MEM_COUNT: ;内存块数量
dd 0
[SECTION .s32]
[BITS 32]
SEG_CODE32:
mov ax,SelectorStack
mov ss,ax
mov esp,STACK_TOP
mov ax,SelectorVRAM
mov ds,ax
call init_main
fin:
hlt
jmp fin
;8259A中断控制器
LABEL_8259A:
SpuriousHandler equ LABEL_8259A - $$
iretd
;键盘中断程序
LabelKeyboardHandler:
KeyboardHandler equ LabelKeyboardHandler - $$
push es
push ds
pushad
mov eax, esp
push eax
call int_keyboard
pop eax
mov esp, eax
popad
pop ds
pop es
iretd
;鼠标中断程序
LabelMouseHandler:
MouseHandler equ LabelMouseHandler - $$
push es
push ds
pushad
mov eax, esp
push eax
call int_mouse
pop eax
mov esp, eax
popad
pop ds
pop es
iretd
;获取内存块数量
mem_block_count:
mov eax,dword [LABEL_MEM_COUNT]
ret
mem_block_buf:
mov eax,LABEL_MEM_BUF
ret
;导入io操作函数模块
%include "io.s"
;导入C语言编写的功能模块
%include "os.s"
;32位模式代码长度
SegCodeLen EQU $-SEG_CODE32
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
times 1024 db 0
STACK_TOP EQU $ - LABEL_STACK
6.kernel.h
//申明汇编的功能模块给C语言调用
//获取内存块数量
extern int mem_block_count();
//获取内存块信息保存地址
extern void* mem_block_buf();
7.io.s
;io 操作函数定义,给C语言调用
;根据C语言函数调用规则,eax 寄存器作为返回值,edx 在定义的汇编函数中没有保存到栈中
;
[SECTION .s32]
[BITS 32]
;实现hlt 功能
;void io_hlt();
io_hlt:
hlt
ret
;读取指定端口8位数据
;char io_in8(int port);
io_in8:
mov edx,[esp+4]
mov eax,0
in al,dx
ret
;读取指定端口16位数据
;int io_in16(int port);
io_in16:
mov edx,[esp+4]
mov eax,0
in ax,dx
ret
;读取指定端口32位数据
;int io_in32(int port);
_io_in32:
mov edx,[esp+4]
in eax,dx
ret
;指定端口写入8位数据
;void io_out8(int port,char value);
io_out8:
mov edx,[esp+4]
mov al,[esp+8]
out dx,al
ret
;指定端口写入16位数据
;void io_out16(int port,int value);
io_out16:
mov edx,[esp+4]
mov ax,[esp+8]
out dx,ax
ret
;指定端口写入32位数据
;void io_out32(int port,int value);
io_out32:
mov edx,[esp+4]
mov eax,[esp+8]
out dx,eax
ret
;关闭cpu可屏蔽中断
;void io_cli();
io_cli:
cli
ret
;打开cpu可屏蔽中断
;void io_sti();
io_sti:
sti
ret
;获取程序状态寄存器值
;int io_readFlag();
io_readFlag:
pushfd
pop eax
ret
;设置程序状态寄存器值
;void io_writeFlag(int value);
io_writeFlag:
mov edx,[esp+4]
push eax
popfd
ret
8.io.h
//
// io.h
// os-test
//
// Created by vincent on 2018/10/31.
// Copyright © 2018年 vincent. All rights reserved.
//
//实现hlt 功能
extern void io_hlt();
//读取指定端口8位数据
extern char io_in8(int port);
//读取指定端口16位数据
extern int io_in16(int port);
//读取指定端口32位数据
extern int io_in32(int port);
//指定端口写入8位数据
extern void io_out8(int port,char value);
//指定端口写入16位数据
extern void io_out16(int port,int value);
//指定端口写入32位数据
extern void io_out32(int port,int value);
//关闭cpu可屏蔽中断
extern void io_cli();
//打开cpu可屏蔽中断--在设置调色板时调用开启可屏蔽中断会奔溃
extern void io_sti();
//获取程序状态寄存器值
extern int io_readFlag();
//设置程序状态寄存器值
extern void io_writeFlag(int value);
9.ascii_font.h
//ascii 8x16点阵编码。每一行一个字节,共16行,为1表示显示
//每个字符的显示需要16个字节
//编码的都是可显示字符从ascii编码0x20-0x7f
//
static unsigned char ascii_array[] = {
// space 0x20
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// !
0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
// "
0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// #
0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00,
// $
0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00,
// %
0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00,
// &
0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00,
// '
0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// (
0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00,
// )
0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00,
// *
0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00,
// +
0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
// ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,
// -
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// .
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
// / (forward slash)
0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,
// 0 0x30
0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00,
// 1
0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00,
// 2
0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00,
// 3
0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00,
// 4
0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00,
// 5
0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00,
// 6
0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00,
// 7
0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
// 8
0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00,
// 9
0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00,
// :
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
// ;
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,
// <
0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,
// =
0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,
// >
0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
// ?
0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,
// @ 0x40
0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00,
// A
0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00,
// B
0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00,
// C
0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00,
// D
0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00,
// E
0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00,
// F
0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,
// G
0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00,
// H
0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00,
// I
0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
// J
0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,
// K
0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00,
// L
0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00,
// M
0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00,
// N
0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00,
// O
0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00,
// P 0x50
0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,
// Q
0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00,
// R
0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00,
// S
0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00,
// T
0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
// U
0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00,
// V
0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00,
// W
0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00,
// X
0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00,
// Y
0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
// Z
0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00,
// [
0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,
// \ (back slash)
0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00,
// ]
0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,
// ^
0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// _
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
// ` 0x60
0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// a
0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00,
// b
0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,
// c
0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00,
// d
0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00,
// e
0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00,
// f
0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,
// g
0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00,
// h
0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00,
// i
0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,
// j
0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,
// k
0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00,
// l
0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,
// m
0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00,
// n
0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00,
// o
0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00,
// p 0x70
0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00,
// q
0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00,
// r
0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,
// s
0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00,
// t
0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00,
// u
0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00,
// v
0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00,
// w
0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00,
// x
0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,
// y
0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00,
// z
0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00,
// {
0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,
// |
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,
// }
0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
// ~
0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// DEL
0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
10.os.h
//*******************************相关数据类型声明*************************
//定义调色板颜色
#define COL8_000000 0
#define COL8_FF0000 1
#define COL8_00FF00 2
#define COL8_FFFF00 3
#define COL8_0000FF 4
#define COL8_FF00FF 5
#define COL8_00FFFF 6
#define COL8_FFFFFF 7
#define COL8_C6C6C6 8
#define COL8_840000 9
#define COL8_008400 10
#define COL8_848400 11
#define COL8_000084 12
#define COL8_840084 13
#define COL8_008484 14
#define COL8_848484 15
#define true 1
#define false 0
typedef struct _VRAM{
//彩色屏幕显存地址
unsigned char *addr;
//平面宽度、高度
int screenW,screenH;
}VRAM;
//定义缓冲区
typedef struct _FIFO8{
//指向缓冲区
char* buf;
//r:读索引,w:写索引
//len:存储数据长度
int r, w, size, len, flag;
}FIFO8;
//定义鼠标移动处理模型
//鼠标处理需要连续处理3字节
//phase 表三处理的字节阶段
//offX,offY 表示当前鼠标的偏移
//x,y 表示鼠标当前所在的坐标位置
typedef struct _MouseDes{
char buf[3], phase;
int offX,offY;
int x, y, btn;
}MouseDes;
//*******************************函数声明*************************
//初始化调色板
void initPallet();
/**
*绘制矩形
*x 矩形左上角x坐标
*y 矩形左上角y坐标
*width 宽度
*height 高度
*colIndex pallet_color 类型调色板颜色索引,即矩形颜色
*/
void fillRect(int x,int y,int width,int height,char colIndex);
//绘制桌面背景
void drawBackground();
/**
*绘制字体
*@param addr 绘制的起始显存地址
*@param x 绘制的x坐标
*@param y 绘制的y坐标
*@param col 绘制颜色
*@param pch 绘制的字符数组8*16,每一行共8位,共16行
*@param screenWidth 屏幕宽度
*/
void putChar(unsigned char *addr,int x,int y,char col,unsigned char *ch,int screenWidth);
/*
*初始化鼠标指针
*@param vram 绘制的起始显存地址
*@param x 绘制鼠标指针最左上角x坐标
*@param y 绘制鼠标指针最左上角y坐标
*@param bc 绘制的矩形填充颜色,和背景色一样将能看到鼠标指针
*/
void drawMouseCursor(unsigned char *vram,int x,int y,char bc);
/*
*char 类型数据转换为16进制字符数据
*@param val 待转化为16进制的数值
*@return 返回的16进制字符数据(8位的整形数据变为16位的字符形似),获取时截取前两位即可
*/
short char2HexStr(unsigned char val);
//初始化鼠标中断硬件
void init_mouse_int();
//缓存初始化
void fifo8_init(FIFO8 *fifo,int size,char *buf);
//缓冲区存放数据
int fifo8_put(FIFO8 *fifo,char data);
//缓冲区读取数据
int fifo8_get(FIFO8 *fifo);
//鼠标移动处理
//@param mdec 鼠标移动处理模型
//@param bc 绘制鼠标的背景色
void mouseCursorMoved(MouseDes *mdec,char bc);
//如果是字符输出该字符,否则作为数据转换为16进制字符后输出
//buf 数据缓冲区
//len 字节数据长度
//isAscii 是否是ascii字符输出
void showString(unsigned char *buf,int len,char isAscii);
11.os.c
// !compile method
// clang -m32 -c os.c -o os.o
// objconv -fnasm os.o -o os.s
//
#include "os.h"
#include "io.h"
#include "kernel.h"
#include "ascii_font.h"
//************定义的全局变量前面加下划线防止和局部变量重名**************
//显存结构
static VRAM _vram;
//字体样式
static unsigned char *_ascii = ascii_array;
//数据临时内存区
static unsigned char _tempArr[64];
//键盘和鼠标缓存
static char _keybuf[32];
static char _mousebuf[128];
//键盘、鼠标中断信息
static FIFO8 _keybufInfo;
static FIFO8 _mousebufInfo;
//鼠标移动模型
static MouseDes _mouseDes;
static int _charCount = 0;
//操作系统C语言入口函数--可以指定为其他
void init_main() {
_vram.addr = (unsigned char *)0xa0000;
_vram.screenW = 320;
_vram.screenH = 200;
io_sti();
initPallet();
drawBackground();
_tempArr[0] = '0';
_tempArr[1] = 'x';
int memCount = mem_block_count();
short temp = char2HexStr(memCount);
_tempArr[2] = ((char *)&temp)[0];
_tempArr[3] = ((char *)&temp)[1];
showString(_tempArr,4,true);
fifo8_init(&_keybufInfo,32,_keybuf);
fifo8_init(&_mousebufInfo,128,_mousebuf);
_mouseDes.x = (320-16)/2;
_mouseDes.y = (200-16)/2;
_mouseDes.phase = 0;
drawMouseCursor(_vram.addr,_mouseDes.x,_mouseDes.y,COL8_008484);
init_mouse_int();
for(; ;){
if(_keybufInfo.len>0){
io_cli();
int len = _keybufInfo.len;
for(int t=0;t<len;t++){
char data = fifo8_get(&_keybufInfo);
short temp = char2HexStr(data);
_tempArr[2] = ((char *)&temp)[0];
_tempArr[3] = ((char *)&temp)[1];
showString(_tempArr,4,true);
}
io_sti();
}
else if(_mousebufInfo.len>0){
io_cli();
int len = _mousebufInfo.len;
for(int t=0;t<len;t++){
mouseCursorMoved(&_mouseDes,COL8_008484);
}
io_sti();
}
else{
io_hlt();
}
}
}
void initPallet(){
//定义调色板
static char table_rgb[16*3] = {
0x00, 0x00, 0x00, /* 0:黑色*/
0xff, 0x00, 0x00, /* 1:亮红*/
0x00, 0xff, 0x00, /* 2:亮绿*/
0xff, 0xff, 0x00, /* 3:亮黄*/
0x00, 0x00, 0xff, /* 4:亮蓝*/
0xff, 0x00, 0xff, /* 5:亮紫*/
0x00, 0xff, 0xff, /* 6:浅亮蓝*/
0xff, 0xff, 0xff, /* 7:白色*/
0xc6, 0xc6, 0xc6, /* 8:亮灰*/
0x84, 0x00, 0x00, /* 9:暗红*/
0x00, 0x84, 0x00, /* 10:暗绿*/
0x84, 0x84, 0x00, /* 11:暗黄*/
0x00, 0x00, 0x84, /* 12:暗青*/
0x84, 0x00, 0x84, /* 13:暗紫*/
0x00, 0x84, 0x84, /* 14:浅灰蓝*/
0x84, 0x84, 0x84, /* 15:暗灰*/
};
unsigned char *rgb = (unsigned char *)table_rgb;
int flag = io_readFlag();
io_cli();
io_out8(0x03c8, 0);
for(int i=0;i<16;i++){
io_out8(0x03c9,rgb[0] / 4);
io_out8(0x03c9,rgb[1] / 4);
io_out8(0x03c9,rgb[2] / 4);
rgb += 3;
}
io_writeFlag(flag);
}
void fillRect(int x,int y,int width,int height,char colIndex){
char *vram = (char *)_vram.addr;
for(int i=y;i<=y+height;i++){
for(int j=x;j<=x+width;j++){
vram[i*_vram.screenW+j] = colIndex;
}
}
}
void drawBackground(){
fillRect(0,0,_vram.screenW-1,_vram.screenH-29, COL8_008484);
fillRect(0,_vram.screenH-28,_vram.screenW-1,28, COL8_848484);
fillRect(0,_vram.screenH-27,_vram.screenW,1, COL8_848484);
fillRect(0,_vram.screenH-26,_vram.screenW,25, COL8_C6C6C6);
fillRect(3,_vram.screenH-24,56,1, COL8_FFFFFF);
fillRect(2,_vram.screenH-24,1,20, COL8_FFFFFF);
fillRect(3,_vram.screenH-4,56,1, COL8_848484);
fillRect(59,_vram.screenH-23,1,19, COL8_848484);
fillRect(2,_vram.screenH-3,57,0, COL8_000000);
fillRect(60,_vram.screenH-24,0,19, COL8_000000);
fillRect(_vram.screenW-47,_vram.screenH-24,43,1, COL8_848484);
fillRect(_vram.screenW-47,_vram.screenH-23,0,19, COL8_848484);
fillRect(_vram.screenW-47,_vram.screenH-3,43,0, COL8_FFFFFF);
fillRect(_vram.screenW-3,_vram.screenH-24,0,21, COL8_FFFFFF);
}
void putChar(unsigned char *addr,int x,int y,char col,unsigned char *pch,int screenWidth){
for(int i=0;i<16;i++){
unsigned char ch = pch[i];
int off = (y+i)*screenWidth;
//显示的字形最左边的是低地址,右侧的是高地址。例如:0x80,则高地址部分显示在内存的低地址,
//最低位的应该偏移7
if((ch & 0x01) != 0){
addr[off+x+7] = col;
}
if((ch & 0x02) != 0){
addr[off+x+6] = col;
}
if((ch & 0x04) != 0){
addr[off+x+5] = col;
}
if((ch & 0x08) != 0){
addr[off+x+4] = col;
}
if((ch & 0x10) != 0){
addr[off+x+3] = col;
}
if((ch & 0x20) != 0){
addr[off+x+2] = col;
}
if((ch & 0x40) != 0){
addr[off+x+1] = col;
}
if((ch & 0x80) != 0){
addr[off+x+0] = col;
}
}
}
void drawMouseCursor(unsigned char *vram,int x,int y,char bc){
//16*16 Mouse
//鼠标指针点阵
static char cursor[16][16] = {
"*...............",
"**..............",
"*O*.............",
"*OO*............",
"*OOO*...........",
"*OOOO*..........",
"*OOOOO*.........",
"*OOOOOO*........",
"*OOOOOOO*.......",
"*OOOO*****......",
"*OO*O*..........",
"*O*.*O*.........",
"**..*O*.........",
"*....*O*........",
".....*O*........",
"......*........."
};
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
int off = (i+y)*_vram.screenW+x+j;
if (cursor[i][j] == '*') {
vram[off] = COL8_000000;
}
if (cursor[i][j] == 'O') {
vram[off] = COL8_FFFFFF;
}
if (cursor[i][j] == '.') {
vram[off] = bc;
}
}
}
}
short char2HexStr(unsigned char val) {
short tmp = val >> 4;
short rst = 0;
if(tmp>=10){
((char*)&rst)[0] = 'a'+tmp-10;
}
else{
((char*)&rst)[0] = '0'+tmp;
}
tmp = val & 0x0f;
if(tmp>=10){
((char*)&rst)[1] = 'a'+tmp-10;
}
else{
((char*)&rst)[1] = '0'+tmp;
}
return rst;
}
/*
*8259A 键盘中断调用
*
*/
void int_keyboard(char *index){
//0x20是8259A控制端口
//0x21对应的是键盘的中断向量。当键盘中断被CPU执行后,下次键盘再向CPU发送信号时,
//CPU就不会接收,要想让CPU再次接收信号,必须向主PIC的端口再次发送键盘中断的中断向量号
io_out8(0x20,0x21);
//读取8259A 0x60端口键盘扫描码
char data = io_in8(0x60);
fifo8_put(&_keybufInfo,data);
}
#define PORT_KEYDAT 0x60
#define PORT_KEYSTA 0x64
#define PORT_KEYCMD 0x64
#define KEYCMD_WRITE_MODE 0x60
#define KBC_MODE 0x47
//鼠标电路对应的一个端口是 0x64, 通过读取这个端口的数据来检测鼠标电路的状态,
//内核会从这个端口读入一个字节的数据,如果该字节的第二个比特位为0,那表明鼠标电路可以
//接受来自内核的命令,因此,在给鼠标电路发送数据前,内核需要反复从0x64端口读取数据,
//并检测读到数据的第二个比特位,直到该比特位为0时,才发送控制信息
void waitKBCReady(){
for( ; ;){
if((io_in8(PORT_KEYSTA) & 0x02)==0){
break;
}
}
}
#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
//初始化键盘控制电路,鼠标控制电路是连接在键盘控制电路上,通过键盘电路实现初始化
void init_mouse_int(){
waitKBCReady();
//0x60让键盘电路进入数据接受状态
io_out8(PORT_KEYCMD,KEYCMD_WRITE_MODE);
waitKBCReady();
//数据0x47要求键盘电路启动鼠标模式,这样鼠标硬件所产生的数据信息,通过键盘电路端口0x60就可读到
io_out8(PORT_KEYDAT,KBC_MODE);
waitKBCReady();
io_out8(PORT_KEYCMD,KEYCMD_SENDTO_MOUSE);
waitKBCReady();
//0xf4数据激活鼠标电路,激活后将会给CPU发送中断信号
io_out8(PORT_KEYDAT,MOUSECMD_ENABLE);
}
/*
*8259A 鼠标中断调用
*
*/
void int_mouse(char *index){
//当中断处理后,要想再次接收中断信号,就必须向中断控制器发送一个字节的数据
io_out8(0x20,0x20);
io_out8(0xa0,0x20);
//读取鼠标数据
char data = io_in8(0x60);
fifo8_put(&_mousebufInfo,data);
}
void fifo8_init(FIFO8 *fifo, int size,char *buf){
fifo->buf = buf;
fifo->r = 0;
fifo->w = 0;
fifo->size = size;
fifo->len = 0;
fifo->flag = 0;
}
int fifo8_put(FIFO8 *fifo,char data){
if (fifo->len == fifo->size) {
return -1;
}
fifo->buf[fifo->w] = data;
fifo->w++;
if (fifo->w == fifo->size) {
fifo->w = 0;
}
fifo->len++;
return 0;
}
int fifo8_get(FIFO8 *fifo) {
if (fifo->len == 0) {
return -1;
}
int data = fifo->buf[fifo->r];
fifo->r++;
if (fifo->r == fifo->size) {
fifo->r = 0;
}
fifo->len--;
return data;
}
int mouse_decode(MouseDes *mdec,unsigned char dat){
int flag = -1;
if (mdec->phase == 0) {
if (dat == 0xfa) {
mdec->phase = 1;
}
flag = 0;
}
else if (mdec->phase == 1) {
if ((dat & 0xc8) == 0x08) {
mdec->buf[0] = dat;
mdec->phase = 2;
}
flag = 0;
}
else if (mdec->phase == 2) {
mdec->buf[1] = dat;
mdec->phase = 3;
flag = 0;
}
else if (mdec->phase == 3) {
mdec->buf[2] = dat;
mdec->phase = 1;
mdec->btn = mdec->buf[0] & 0x07;
mdec->offX = mdec->buf[1];
mdec->offY = mdec->buf[2];
if ((mdec->buf[0] & 0x10) != 0) {
mdec->offX |= 0xffffff00;
}
if ((mdec->buf[0] & 0x20) != 0) {
mdec->offY |= 0xffffff00;
}
//鼠标y坐标偏移和平面y坐标相反
mdec->offY = -mdec->offY;
flag = 1;
}
return flag;
}
//鼠标移动处理
void mouseCursorMoved(MouseDes *mdec,char bc){
unsigned char val = fifo8_get(&_mousebufInfo);
//表示处理到第3步,需要绘制鼠标光标
if(mouse_decode(mdec,val) == 1) {
fillRect(mdec->x,mdec->y,16,16,bc);
mdec->x += mdec->offX;
mdec->y += mdec->offY;
if(mdec->x < 0){
mdec->x = 0;
}
if(mdec->x > _vram.screenW-16/2){
mdec->x = _vram.screenW-16/2;
}
if(mdec->y < 0 ){
mdec->y = 0;
}
if(mdec->y > _vram.screenH - 16){
mdec->y = _vram.screenH - 16;
}
drawMouseCursor(_vram.addr,mdec->x,mdec->y,bc);
}
}
void showString(unsigned char *buf,int len,char isAscii){
for(int i=0;i<len;i++){
int ch = buf[i];
if(isAscii){
int x = (_charCount)%32*10;
int y = (_charCount)/32*20;
putChar(_vram.addr,x,y,COL8_FFFFFF,_ascii+(ch-0x20)*16,_vram.screenW);
_charCount++;
}
else{
ch = char2HexStr(buf[i]);
for(int j=0;j<2;j++){
int x = (_charCount)%32*10;
int y = (_charCount)/32*20;
putChar(_vram.addr,x,y,COL8_FFFFFF,_ascii+(((unsigned char *)&ch)[j]-0x20)*16,_vram.screenW);
_charCount++;
}
}
}
}
注意
开发操作系统过程中在引入C语言后特别需要注意数据类型的问题,笔者使用习惯高级开发语言,很少使用数据类型字节数比较小的char,大多都是int 型,导致在开发过程中是 unsigned char 类型的喜欢用char,这样导致的一个后果就是与预期不符,思来想去花费了大量时间才排查出问题。开发中很少设计有符号数运算,基本都是无符号类型,建议大家在遇到字节型数据类型时多留意是否是有符号数。
一、开发平台:Linux
图形界面的Ubuntu环境是一个非常不错的选择,安装各种工具都非常方便。
二、开发工具
1.需要使用苹果编译器clang编译C语言,非常容易安装(sudo apt-get install -y clang
);
2.反汇编器objconv,文章末尾有相关下载说明,运行相关命令生成objconv 反汇编器后不配置环境变量需要将objconv 复制到操作系统相关文件夹中(boot.s所在文件夹)。在ubuntu-18.04.1 中笔者编译objconv 时就失败,应该是版本相对较高或者相关编译环境的问题,但是这个完全不影响对操作系统的开发学习。后来在低版本Ubuntu环境中编译了objconv,为学者减少不必要的工具困难,笔者把64位Ubuntu下的objconv 也上传,对我们的操作系统开发的objconv 也在下载的代码中,编译都需要进入该文件夹中;
3.汇编器nasm也是非常容易安装(sudo apt-get install -y nasm
);
4.虚拟机VirtualBox加载运行生成的虚拟软盘文件floppy.img,下载链接: https://pan.baidu.com/s/1MN2-tY8lduQRRcLvbyJT-Q 提取码: w3ca
5.Ubuntu自带的gedit图形化文本编辑器非常不错,但是对于2进制就无法打开,对于操作系统开发我们希望能了解更多!Sublime就是一个非常不错的工具,对于无法以文本显示就会以16进制显示。虽然是商业软件,没有购买会有弹框弹出,但是关闭即可且没有使用期限限制,真心不错
安装如下:
sudo add-apt-repository ppa:webupd8team/sublime-text-2
sudo apt-get update
sudo apt-get install sublime-text
三、编译方式
1.clang生成软盘制作工具main:clang main.c floppy.c -o main
2.clang 编译器编译os.c为二进制:clang -c -m32 os.c -o os.o
3.objconv 反汇编os.o 为汇编文件os.s:./objconv -fnasm os.o -o os.s
,并去除os.s 中的global、extern、SECTION 等无用声明
4.编译内核加载器boot.s为二进制boot.bat:nasm boot.s -o boot.bat
5.编译kernel.s为二进制kernel.bat:nasm kernel.s -o kernel.bat
6.运行软盘制作工具生成虚拟软盘floppy.img: ./main
四、运行方式
先创建虚拟软盘控制器再加载运行虚拟软盘floppy.img
代码下载:链接:https://pan.baidu.com/s/1c9RTHu9Q3rYEoZfFlHmVkg 提取码: q9u2
开发工具链接: https://pan.baidu.com/s/1_rHVpqeuSeDV3YreEPXU1w 提取码: 2unk