8、鼠标控制与32位模式切换
鼠标解读
bootpack.c节选
mouse_phase = 0; /* 进入到等待鼠标的0xfa的状态 */for (;;) {io_cli();if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) io_stihlt();else {if (fifo8_status(&keyfifo) != 0) {i = fifo8_get(&keyfifo);io_sti();sprintf(s, "%02X", i);boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);} else if (fifo8_status(&mousefifo) != 0) {i = fifo8_get(&mousefifo);io_sti();if (mouse_phase == 0) //把最初读到的0xfa舍弃掉{/* 等待鼠标的0xfa的状态 */if (i == 0xfa) mouse_phase = 1;} else if (mouse_phase == 1) {/* 等待鼠标的第一字节 */mouse_dbuf[0] = i;mouse_phase = 2;} else if (mouse_phase == 2) {/* 等待鼠标的第二字节 */mouse_dbuf[1] = i;mouse_phase = 3;} else if (mouse_phase == 3) {/* 等待鼠标的第三字节 */mouse_dbuf[2] = i;mouse_phase = 1;/* 鼠标的3个字节都齐了,显示处来 */sprintf(s, "%02X %02X %02X", mouse_dbuf[0], mouse_dbuf[1], mouse_dbuf[2]);boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 8 * 8 - 1, 31);putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);}}}}
1、如果移动鼠标,08 中的0会在0~3的范围变化,如果仅仅移动鼠标,08中的8不变,如果按鼠标左键或右键,会在8~F变化
2、当鼠标左右移动时,00会变化
3、当鼠标上下移动是,01会变化
移动鼠标指针
bootpack.c节选
for (;;) {io_cli();if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) io_stihlt();else {if (fifo8_status(&keyfifo) != 0) {i = fifo8_get(&keyfifo);io_sti();sprintf(s, "%02X", i);boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);} else if (fifo8_status(&mousefifo) != 0) {i = fifo8_get(&mousefifo);io_sti();if (mouse_decode(&mdec, i) != 0) {/* 数据的3个字节都齐了,显示处来 */sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);if ((mdec.btn & 0x01) != 0) //如果第一位是1,说明按下左键s[1] = 'L';if ((mdec.btn & 0x02) != 0) s[3] = 'R';if ((mdec.btn & 0x04) != 0) s[2] = 'C';boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);/* 鼠标指针的移动 */boxfill8(binfo->vram, binfo->scrnx, COL8_008484, mx, my, mx + 15, my + 15); mx += mdec.x;my += mdec.y;if (mx < 0) mx = 0;if (my < 0) my = 0;if (mx > binfo->scrnx - 16) mx = binfo->scrnx - 16;if (my > binfo->scrny - 16) my = binfo->scrny - 16;sprintf(s, "(%3d, %3d)", mx, my);boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 0, 79, 15); /* 隐藏坐标*/putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s); /* 显示坐标 */putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16); /* 描画鼠标 */}}}}
make run之后可以看到鼠标可以移动了。
通往32位模式之路
asmhead.nas
; haribote-os boot asm
; TAB=4BOTPAK EQU 0x00280000 ; bootpack.hrb(512KB)的开始地址
DSKCAC EQU 0x00100000 ; 用于保存软盘内容(1440KB)的开始地址
DSKCAC0 EQU 0x00008000 ; 有关BOOT_INFO
CYLS EQU 0x0ff0 ;设定启动区
LEDS EQU 0x0ff1 ;键盘上各种LED指示灯的状态
VMODE EQU 0x0ff2 ;有关颜色数目的信息
SCRNX EQU 0x0ff4 ;分辨率的x
SCRNY EQU 0x0ff6 ;分辨率的y
VRAM EQU 0x0ff8 ;图像缓冲区的开始地址ORG 0xc200 ;程序要装载的地方MOV AL,0x13 ;VGA显卡,32x00x8位颜色MOV AH,0x00 ;设置AH=0x00,调用显卡BIOS函数,就可以切换显示模式了,AL中设置模式INT 0x10 MOV BYTE [VMODE],8 ; 记录画面模式MOV WORD [SCRNX],320MOV WORD [SCRNY],200MOV DWORD [VRAM],0x000a0000; 用BIOS取得键盘上各种LED指示灯的状态MOV AH,0x02INT 0x16 ; keyboard BIOSMOV [LEDS],AL; PIC关闭一切中断
; 根据AT兼容机的规格,如果要初始化PIC,
; 必须在CLT之前进行,否则有时会挂起
; 随后进行PIC的初始化MOV AL,0xffOUT 0x21,AL ; 禁止主PIC的全部中断NOP ; 什么也不做,让CPU休息一个时钟的时间。如果连续执行OUT指令,有些机种会无法正常进行OUT 0xa1,AL ; 禁止从PIC的全部中断CLI ; 禁止CPU级别的中断; 为了让CPU能够访问1MB以上的内存空间,设定A20GAECALL waitkbdout ; 等待KBC准备好MOV AL,0xd1OUT 0x64,ALCALL waitkbdout MOV AL,0xdf ; 0xdf是让A20GATE信号线变成ON的状态,使内存1MB以上的部分变成可使用状态OUT 0x60,ALCALL waitkbdout; 切换到保护模式。应用程序既不能随意改变段的设定,也不能使用操作系统专用的段,操作系统受CPU保护。[INSTRSET "i486p"] ; “想要使用486指令”的叙述。INSTRSET指令,是为了能使用386以后的LGDT,EAX,CR0等LGDT [GDTR0] ; 设定临时GDTMOV EAX,CR0 ; 将CR0这一特殊的32位寄存器的值代入EAX。CR0 control register0 只有操作系统可使用AND EAX,0x7fffffff ; 设bit31为0(为了禁止分页)OR EAX,0x00000001 ; 设bit0为1(为了切换到保护模式)MOV CR0,EAX ; 完成模式转换JMP pipelineflush ; 当CPU切换到保护模式后时,要马上执行JMP指令。因为切换到保护模式后,
;机器语言的解释要发生变化,为了加快指令的执行而采用了管道机制。
pipelineflush:MOV AX,1*8 ; 可读写的段32bitMOV DS,AX ; 进入保护模式后,除CS外,所有的段寄存器的值都从0x0000变成了0x0008,相当于gdt+1段MOV ES,AXMOV FS,AXMOV GS,AXMOV SS,AX; bootpack的转送
; 相当于memcpy(bootpack, BOTPAK, 512*1024/4),将bootpack.hrb复制到0x00280000号地址MOV ESI,bootpack ; 转送源MOV EDI,BOTPAK ; 转送目的地 MOV ECX,512*1024/4 ; 传送数据的大小以双字节大小为单位,所以要/4CALL memcpy; 磁盘数据最终转送到它本来的位置去; 首先从启动区开始; 相当于memcpy(0x7c00, DSKCAC, 512/4)MOV ESI,0x7c00 ; 转送源MOV EDI,DSKCAC ; 转送目的地,0x00100000MOV ECX,512/4CALL memcpy; 所有剩下的; 相当于memcpy(DSKCAC0+512, DSKCAC+512, cyls*512*18*2/4-512/4)MOV ESI,DSKCAC0+512 ; 转送源, 0x00008200MOV EDI,DSKCAC+512 ; 转送目的地, 0x00100200MOV ECX,0MOV CL, BYTE [CYLS]IMUL ECX,512*18*2/4 ; 从柱面数变成字节数. IMUL是整数乘法SUB ECX,512/4 ; 减去IPLCALL memcpy; 必须由asmhead来完成的工作,至此全部完毕
; 以后就由bootpack来完成; bootpack的启动。对bootpack.hrb的header部分进行解析,将执行所必需的数据传送过去。MOV EBX,BOTPAK ; q MOV ECX,[EBX+16]ADD ECX,3 ; ECX += 3;SHR ECX,2 ; ECX /= 4;JZ skip ; 没有要传送的东西时MOV ESI,[EBX+20] ; 转送源ADD ESI,EBXMOV EDI,[EBX+12] ; 转送目的地CALL memcpy
skip:MOV ESP,[EBX+12] ; 栈初始值JMP DWORD 2*8:0x0000001b ; 将2*8代入到CS中,同时移动到0x1b号地址。waitkbdout: ; 与wait_KBC_sendready相同IN AL,0x64AND AL,0x02IN AL,0x60 ; 空读,为了清空数据接收缓冲区中的垃圾数据JNZ waitkbdout ; AND结果如果不是0,就跳到waitkbdoutRETmemcpy:MOV EAX,[ESI]ADD ESI,4MOV [EDI],EAXADD EDI,4SUB ECX,1JNZ memcpy ; 减法运算的结果如果不是0,就跳转到memcypRETALIGNB 16 ; 一直添加DBO,直到地址能被16整除的时候。如果标签GDT0的地址不是8的倍数,向段; 寄存器复制的MOV指令就会慢一些,所以加入了ALIGN指令
GDT0: ;GDT0是一种特定的GDT。0号是空区域,不能在那里定义段。RESB 8 ; NULL selectorDW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段32bit。set_segmdesc(gdt+1, 0xffffffff, 0x00000000, AR_DATA32_RW)DW 0xffff,0x0000,0x9a28,0x0047 ; 可以执行的段32bit(bootpack用)。set_segmdesc(gdt+1, 0xffffffff, 0x00000000, AR_DATA32_RW)DW 0
GDTR0: ; 是LGDT指令,意思是通知GDT0,有了GDTDW 8*3-1 ; 写入16位段上限DD GDT0 ; 写入32位段起始地址ALIGNB 16
bootpack:
HariMain节选
struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;char s[40], mcursor[256], keybuf[32], mousebuf[128];int mx, my, i;struct MOUSE_DEC mdec;init_gdtidt(); //GDT和IDT的初始化init_pic(); //PIC初始化io_sti(); //仅执行STI命令,IF变为1,CPU接收来自外部设备的中断fifo8_init(&keyfifo, 32, keybuf); fifo8_init(&mousefifo, 128, mousebuf);//PIC属于外部设备,用IN OUT指令进行操作io_out8(PIC0_IMR, 0xf9); /* 开放PIC1和键盘中断(11111001) */io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) */init_keyboard(); //准备好鼠标控制电路init_palette(); //设置调色板init_screen(binfo->vram, binfo->scrnx, binfo->scrny); //设置背景
总结一下切换到32位模式过程
1、初始化PIC,屏蔽所有中断,防止模式切换的过程中发生中断。
2、设定A20GATE,使CPU能访问1M以上的内存空间。
3、切换模式,设定临时GDT,将CR0最低一位设为1。
4、执行JMP指令,因为模式切换后要马上执行JMP指令,跳转到piplineflush段中,将除了CS以外的所有段寄存器都加8,相当于gdt+1段,因为进入保护模式后,段寄存器的解释不再是16倍,而是能够使用GDT
5、bootpack传送。
6、在主函数中重新创建GDT和IDT,初始化PIC后,开中断。
8、鼠标控制与32位模式切换相关推荐
- 第8天 鼠标控制与32位模式切换
第8天 鼠标控制与32位模式切换 2020.4.2 1. 鼠标解读(1)(harib05a) 现在,我们让鼠标动起来. 先对bootpack.c中的HariMain函数进行修改. unsigned c ...
- 30天自制操作系统:第8天:鼠标控制与32位模式切换
今天前半部分都是如何控制鼠标移动,将每次传送的三个字节处理成位置信息,最后指导鼠标指针移动. 后面的部分,是关于一段一直未讲解的汇编代码的讲解. 32位保护模式 书中用一连串汇编代码完成了从实模式进入 ...
- 30天自制操作系统——第八天鼠标控制与32位模式切换
今天的任务是让鼠标真正移动起来,之前的路走的真是艰辛呀.终于到走到这里啦,下面正式开始了-- 鼠标解读(harib05a) 昨天我们已经能从鼠标取得数据了,接着要读取这些数据,看看鼠标是怎么移动的,在 ...
- 第8天:鼠标控制与32位模式切换
8.1.鼠标解读 for (;;) {io_cli();if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {io_ ...
- 分享一款电机控制国产32位单片机MM32SPIN360C
国产32位单片机MM32SPIN360C拥有M0内核的高性能32位微控制器,5V输出的LDO稳压器.三组具备有自举二极管的N通道半桥栅极驱动器.MCU最高工作频率可达96MHz,并内置SRAM高速存储 ...
- 相比32位, 64位的优势是什么?
64 位和 32 位比较有哪些优势? (1)如果说的是64 位宽 CPU,那么有 2 个优势: 可以执行更大数字的运算,这个优势在普通应用上不明显,但是对于数值计算较多的应用就非常明显. 64 位 ...
- Intel 64/x86_64/x86/IA-32处理器标志寄存器详解(4) - 32位EFLAGS - 状态标志与控制标志
Status Flags 状态标志位(比特位0,2,4,6,7和11)指示了算术指令的结果,例如ADD,SUB,MUL,与DIV指令. 标志位 描述 CF(bit 0) 进位/借位Carry.如果算术 ...
- 计算机视觉课程第六讲-带你简单快速学习2021年春晚背后刘德华与背景分离切换到另一场景视觉算法(上集):OpenCV4鼠标控制图像和视频任意位置放大和缩小
计算机视觉课程第六讲-带你简单快速学习2021年春晚背后刘德华与背景分离切换到另一场景视觉算法(上集):OpenCV4鼠标控制图像和视频任意位置放大和缩小 本专栏将会带大家学习 <计算机视觉与图 ...
- 一步一步学ROP之Android ARM 32位篇
蒸米 · 2015/12/17 9:41 0x00 序 ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术,可以用来绕过现代操作系统的各种 ...
- 思科模拟器32位_三款另类的68k Mac模拟器
之前说过两个主流的68k Mac模拟器,Mini vMac和BasiliskII.不过它们都没有真正的硬盘模拟,都是通过外置的软驱接口连接的"硬盘".那么这篇文章将介绍三款非主流的 ...
最新文章
- Linux磁盘配额(一)
- DataSource绑定DataTable.Select()显示system.data.DataRow问题解决的方法
- Unity协程(Coroutine)原理深入剖析再续
- oracle回滚事务的关键字,Oracle ROLLBACK语句(回滚事务)
- BIOS中的分区工具
- 我眼中的Visual Studio 2010架“.NET研究”构工具
- Linux文本处理(grep,sed)
- eclipse Dynamic web module相关问题
- mac 查看进程及杀进程
- 跳槽的5个误区,冷静一下
- Android ListView焦点事件冲突问题与解决
- Python中随机漫步的实现
- 亚马逊账号被关联能申诉得回来吗
- 聊下git merge --squash
- jquery实现新闻消息滚动
- 得到《三体》听书笔记
- web服务r oauth_通过OAuth访问社交网站,第3部分,将Web Twitter客户端部署到Google App Engine...
- Java小农养成记第四十天
- 有人用python抢到过吗_过年了,用Python抢到回家的车票,so easy!
- 七言.毕业12周年祭
热门文章
- 博科查看光功率_博科系交换机光模块信号强度查看
- win10怎么更新显卡驱动_win10系统AMD显卡驱动安装失败的解决方法
- qq出示测试软件语音聊天,腾讯qq语音聊天麦克风的[qq语音语音测试]解决方案
- 计算机综合应用技能,系统测评计算机综合应用技能期末作业题稿.doc
- R语言之导入数据源(二)
- 获取设备Mac地址和IP地址
- 设置Google连接burpsuite
- 安科瑞ACTB-6互感器二次侧开路保护装置
- twitter_关于Twitter和激进化的警告
- 斯坦福 计算机音乐 访问学者,韩宝强