30天自制操作系统第8天harib05c
第8天 鼠标控制与32位模式切换
鼠标解读(2)
harib05c
准备材料(windows环境)
- VMware Workstation
- Visual Studio Code
- 程序和源代码:https://pan.baidu.com/s/1bFGAYgnA0m9KB7tzFrMD5g
提取码:d210 - Makefile
- windows 批处理
开始实验
在tolset文件夹下创建子文件侠harib05c。
打开记事本,输入以下代码并另存为 !cons_nt.bat文件(windows 批处理),存放在harib05c文件夹中。
cmd.exe
ps:当然也可以直接使用 win + r 快捷键也可以,不过最好还是创建一个比较好。因为以后打开时不需要再麻烦了。
3. 打开vc code,输入以下代码并保存为 naskfunc.nas,存放在harib05c文件夹中。
; naskfunc
; TAB=4[FORMAT "WCOFF"] ; 制作目标文件的模式
[INSTRSET "i486p"] ; 要使用486指令的语句
[BITS 32] ; 制作32位模式用的机器语言
[FILE "naskfunc.nas"] ; 原文件名信息GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihltGLOBAL _io_in8, _io_in16, _io_in32GLOBAL _io_out8, _io_out16, _io_out32GLOBAL _io_load_eflags, _io_store_eflagsGLOBAL _load_gdtr, _load_idtrGLOBAL _asm_inthandler21, _asm_inthandler27, _asm_inthandler2cEXTERN _inthandler21, _inthandler27, _inthandler2c[SECTION .text] _io_hlt: ; void io_hlt(void);HLTRET_io_cli: ; void io_cli(void);CLIRET_io_sti: ; void io_sti(void);STIRET_io_stihlt: ; void io_stihlt(void);STIHLTRET_io_in8: ; int io_in8(int port);MOV EDX,[ESP+4] ; portMOV EAX,0IN AL,DXRET_io_in16: ; int io_in16(int port);MOV EDX,[ESP+4] ; portMOV EAX,0IN AX,DXRET_io_in32: ; int io_in32(int port);MOV EDX,[ESP+4] ; portIN EAX,DXRET_io_out8: ; void io_out8(int port, int data);MOV EDX,[ESP+4] ; portMOV AL,[ESP+8] ; dataOUT DX,ALRET_io_out16: ; void io_out16(int port, int data);MOV EDX,[ESP+4] ; portMOV EAX,[ESP+8] ; dataOUT DX,AXRET_io_out32: ; void io_out32(int port, int data);MOV EDX,[ESP+4] ; portMOV EAX,[ESP+8] ; dataOUT DX,EAXRET_io_load_eflags: ; int io_load_eflags(void);PUSHFD ; 指 PUSH EFLAGSPOP EAXRET_io_store_eflags: ; void io_store_eflags(int eflags);MOV EAX,[ESP+4]PUSH EAXPOPFD ; 指 POP EFLAGSRET_load_gdtr: ; void load_gdtr(int limit, int addr);MOV AX,[ESP+4] ; limitMOV [ESP+6],AXLGDT [ESP+6]RET_load_idtr: ; void load_idtr(int limit, int addr);MOV AX,[ESP+4] ; limitMOV [ESP+6],AXLIDT [ESP+6]RET_asm_inthandler21:PUSH ESPUSH DSPUSHADMOV EAX,ESPPUSH EAXMOV AX,SSMOV DS,AXMOV ES,AXCALL _inthandler21POP EAXPOPADPOP DSPOP ESIRETD_asm_inthandler27:PUSH ESPUSH DSPUSHADMOV EAX,ESPPUSH EAXMOV AX,SSMOV DS,AXMOV ES,AXCALL _inthandler27POP EAXPOPADPOP DSPOP ESIRETD_asm_inthandler2c:PUSH ESPUSH DSPUSHADMOV EAX,ESPPUSH EAXMOV AX,SSMOV DS,AXMOV ES,AXCALL _inthandler2cPOP EAXPOPADPOP DSPOP ESIRETD
- 打开vc code,输入以下代码并保存为 int.c 存放在haribooj文件夹中。
/* 与中断有关 */#include "bootpack.h"
#include <stdio.h>void init_pic(void)
/* PIC的初始化 */
{io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */io_out8(PIC0_ICW1, 0x11 ); /* 边沿触发模式 (edge trigger mode) */io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7 由 INT20-27 接收 */io_out8(PIC0_ICW3, 1 << 2); /* PIC1 由 IRQ2 连接 */io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */io_out8(PIC1_ICW1, 0x11 ); /* 边沿触发模式 (edge trigger mode) */io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15 由 INT28-2f 接收 */io_out8(PIC1_ICW3, 2 ); /* PIC1 由 IRQ2 连接 */io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区域 */io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1 以外全部禁止 */io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */return;
}#define PORT_KEYDAT 0x0060struct FIFO8 keyfifo;void inthandler21(int *esp)
{unsigned char data;io_out8(PIC0_OCW2, 0x61); /* 通知PIC“IRQ-01”已经受理完毕 */data = io_in8(PORT_KEYDAT);fifo8_put(&keyfifo, data);return;
}struct FIFO8 mousefifo;void inthandler2c(int *esp)
/* 来自PS/2键盘的中断 */
{unsigned char data;io_out8(PIC1_OCW2, 0x64); /* 通知PIC1 IRQ-12的受理已经完成 */io_out8(PIC0_OCW2, 0x62); /* 通知PIC0 IRQ-02的受理已经完成 */data = io_in8(PORT_KEYDAT);fifo8_put(&mousefifo, data);return;
}void inthandler27(int *esp)
/* 防止来自PIC0的不完整中断的措施 */
/* 在Athlon64X2机器等中,由于芯片组的便利性,该中断在PIC初始化时仅发生一次 */
/* 此中断处理功能不执行中断 */
/* 您为什么不做任何事情? */
/* 由于此中断是由PIC初始化期间的电气噪声产生的,*/
/* 您不需要认真做任何事情。 */
{io_out8(PIC0_OCW2, 0x67); /* 通知PIC IRQ-07已被接受(见7-1)*/return;
}
- 打开vc code,输入以下代码并保存为 bootpack.c 存放在haribooj文件夹中。
/* bootpack 其他处理 */#include "bootpack.h"
#include <stdio.h>struct MOUSE_DEC {unsigned char buf[3], phase;int x, y, btn;
};extern struct FIFO8 keyfifo, mousefifo;
void enable_mouse(struct MOUSE_DEC *mdec);
void init_keyboard(void);
int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat);void HariMain(void)
{struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;char s[40], mcursor[256], keybuf[32], mousebuf[128];int mx, my, i;struct MOUSE_DEC mdec;init_gdtidt();init_pic();io_sti(); /* 由于IDT / PIC的初始化已完成,因此请禁用CPU的中断。 */fifo8_init(&keyfifo, 32, keybuf);fifo8_init(&mousefifo, 128, mousebuf);io_out8(PIC0_IMR, 0xf9); /* 允许PIC1和键盘(11111001) */io_out8(PIC1_IMR, 0xef); /* 允许鼠标(11101111) */init_keyboard();init_palette();init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);mx = (binfo->scrnx - 16) / 2; /* 计算坐标在屏幕中心 */my = (binfo->scrny - 28 - 16) / 2;init_mouse_cursor8(mcursor, COL8_008484);putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);sprintf(s, "(%d, %d)", mx, my);putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);enable_mouse(&mdec);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) {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);}}}}
}#define PORT_KEYDAT 0x0060
#define PORT_KEYSTA 0x0064
#define PORT_KEYCMD 0x0064
#define KEYSTA_SEND_NOTREADY 0x02
#define KEYCMD_WRITE_MODE 0x60
#define KBC_MODE 0x47void wait_KBC_sendready(void)
{/* 等待键盘控制电路准备完毕 */for (;;) {if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {break;}}return;
}void init_keyboard(void)
{/* 初始化键盘控制电路 */wait_KBC_sendready();io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);wait_KBC_sendready();io_out8(PORT_KEYDAT, KBC_MODE);return;
}#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4void enable_mouse(struct MOUSE_DEC *mdec)
{/* 激活鼠标 */wait_KBC_sendready();io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);wait_KBC_sendready();io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);/* 顺利的话,ACK(0xfa)会被传送过来 */mdec->phase = 0; /* 等待0xfa的阶段 */return;
}int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
{if (mdec->phase == 0) {/* 等待鼠标的0xfa的阶段 */if (dat == 0xfa) {mdec->phase = 1;}return 0;}if (mdec->phase == 1) {/* 等待鼠标第一字节的阶段 */if ((dat & 0xc8) == 0x08) {/* 如果第一字节正确 */mdec->buf[0] = dat;mdec->phase = 2;}return 0;}if (mdec->phase == 2) {/* 等待鼠标第二字节的阶段 */mdec->buf[1] = dat;mdec->phase = 3;return 0;}if (mdec->phase == 3) {/* 等待鼠标第三字节的阶段 */mdec->buf[2] = dat;mdec->phase = 1;mdec->btn = mdec->buf[0] & 0x07;mdec->x = mdec->buf[1];mdec->y = mdec->buf[2];if ((mdec->buf[0] & 0x10) != 0) {mdec->x |= 0xffffff00;}if ((mdec->buf[0] & 0x20) != 0) {mdec->y |= 0xffffff00;}mdec->y = - mdec->y; /* 鼠标y方向与画面符号相反 */return 1;}return -1; /* 应该不可能到这里来 */
}
- 打开vc code,输入以下代码并保存为 bootpack.c 存放在haribooj文件夹中。
//* bootpack 其他处理 */#include "bootpack.h"
#include <stdio.h>extern struct FIFO8 keyfifo;void HariMain(void)
{struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;char s[40], mcursor[256], keybuf[32];int mx, my, i;init_gdtidt();init_pic();io_sti(); /* 由于IDT / PIC的初始化已完成,因此请禁用CPU的中断。 */fifo8_init(&keyfifo, 32, keybuf);io_out8(PIC0_IMR, 0xf9); /* 允许PIC1和键盘(11111001) */io_out8(PIC1_IMR, 0xef); /* 允许鼠标(11101111) */init_palette();init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);mx = (binfo->scrnx - 16) / 2; /* 计算坐标在屏幕中心 */my = (binfo->scrny - 28 - 16) / 2;init_mouse_cursor8(mcursor, COL8_008484);putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);sprintf(s, "(%d, %d)", mx, my);putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);for (;;) {io_cli();if (fifo8_status(&keyfifo) == 0) {io_stihlt();} else {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);}}
}
ps: 。
7. 打vc code,输入以下代码并保存为 bootpack.h,存放在harib05c文件夹中。
/* asmhead.nas */
struct BOOTINFO { /* 0xff0-0x0fff */char cyls; /* 启动区读硬盘读到何处为止 */char leds; /* 启动时键盘LED的状态 */char vmode; /* 显卡模式为多少位彩色 */char reserve;short scrnx, scrny; /* 画面分辨率 */char *vram;
};
#define ADR_BOOTINFO 0x00000ff0/* naskfunc.nas */
void io_hlt(void);
void io_cli(void);
void io_sti(void);
void io_stihlt(void);
int io_in8(int port);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);
void load_gdtr(int limit, int addr);
void load_idtr(int limit, int addr);
void asm_inthandler21(void);
void asm_inthandler27(void);
void asm_inthandler2c(void);/* fifo.c */
struct FIFO8 {unsigned char *buf;int p, q, size, free, flags;
};
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf);
int fifo8_put(struct FIFO8 *fifo, unsigned char data);
int fifo8_get(struct FIFO8 *fifo);
int fifo8_status(struct FIFO8 *fifo);/* graphic.c */
void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen8(char *vram, int x, int y);
void putfont8(char *vram, int xsize, int x, int y, char c, char *font);
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s);
void init_mouse_cursor8(char *mouse, char bc);
void putblock8_8(char *vram, int vxsize, int pxsize,int pysize, int px0, int py0, char *buf, int bxsize);
#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/* dsctbl.c */
struct SEGMENT_DESCRIPTOR {short limit_low, base_low;char base_mid, access_right;char limit_high, base_high;
};
struct GATE_DESCRIPTOR {short offset_low, selector;char dw_count, access_right;short offset_high;
};
void init_gdtidt(void);
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);
#define ADR_IDT 0x0026f800
#define LIMIT_IDT 0x000007ff
#define ADR_GDT 0x00270000
#define LIMIT_GDT 0x0000ffff
#define ADR_BOTPAK 0x00280000
#define LIMIT_BOTPAK 0x0007ffff
#define AR_DATA32_RW 0x4092
#define AR_CODE32_ER 0x409a
#define AR_INTGATE32 0x008e/* int.c */
void init_pic(void);
void inthandler21(int *esp);
void inthandler27(int *esp);
void inthandler2c(int *esp);
#define PIC0_ICW1 0x0020
#define PIC0_OCW2 0x0020
#define PIC0_IMR 0x0021
#define PIC0_ICW2 0x0021
#define PIC0_ICW3 0x0021
#define PIC0_ICW4 0x0021
#define PIC1_ICW1 0x00a0
#define PIC1_OCW2 0x00a0
#define PIC1_IMR 0x00a1
#define PIC1_ICW2 0x00a1
#define PIC1_ICW3 0x00a1
#define PIC1_ICW4 0x00a1
- 打vc code,输入以下代码并保存为 graphic.c,存放在harib05c文件夹中。
/* u关于描画的处理 */#include "bootpack.h"void init_palette(void)
{static unsigned 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, 0x00, 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 : 暗灰 */};set_palette(0, 15, table_rgb);return;/* C语言中的static char语句只能用于数据, 相当于汇编中的DB指令 */
}void set_palette(int start, int end, unsigned char *rgb)
{int i, eflags;eflags = io_load_eflags(); /* 记录中断许可标志的值 */io_cli(); /* 将中断许可标志置为0, 禁止中断 */io_out8(0x03c8, start);for (i = start; i <= end; i++) {io_out8(0x03c9, rgb[0] / 4);io_out8(0x03c9, rgb[1] / 4);io_out8(0x03c9, rgb[2] / 4);rgb += 3;}io_store_eflags(eflags); /* 复原中断许可标志 */return;
}void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{int x, y;for (y = y0; y <= y1; y++) {for (x = x0; x <= x1; x++)vram[y * xsize + x] = c;}return;
}void init_screen8(char *vram, int x, int y)
{boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29);boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28);boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27);boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1);boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24);boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4);boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4);boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5);boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3);boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3);boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24);boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4);boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3);boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3);return;
}void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{int i;char *p, d; /* date */for (i = 0; i < 16; i++) {p = vram + (y + i) * xsize + x;d = font[i];if ((d & 0x80) != 0) { p[0] = c; }if ((d & 0x40) != 0) { p[1] = c; }if ((d & 0x20) != 0) { p[2] = c; }if ((d & 0x10) != 0) { p[3] = c; }if ((d & 0x08) != 0) { p[4] = c; }if ((d & 0x04) != 0) { p[5] = c; }if ((d & 0x02) != 0) { p[6] = c; }if ((d & 0x01) != 0) { p[7] = c; }}return;
}void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
{extern char hankaku[4096];for (; *s != 0x00; s++) {putfont8(vram, xsize, x, y, c, hankaku + *s * 16);x += 8;}return;
}void init_mouse_cursor8(char *mouse, char bc)
/* 准备鼠标指标 (16 x 16) */
{static char cursor[16][16] = {"**************..","*OOOOOOOOOOO*...","*OOOOOOOOOO*....","*OOOOOOOOO*.....","*OOOOOOOO*......","*OOOOOOO*.......","*OOOOOOO*.......","*OOOOOOOO*......","*OOOO**OOO*.....","*OOO*..*OOO*....","*OO*....*OOO*...","*O*......*OOO*..","**........*OOO*.","*..........*OOO*","............*OO*",".............***"};int x, y;for (y = 0; y < 16; y++) {for (x = 0; x < 16; x++) {if (cursor[y][x] == '*') {mouse[y * 16 + x] = COL8_000000;}if (cursor[y][x] == 'O') {mouse[y * 16 + x] = COL8_FFFFFF;}if (cursor[y][x] == '.') {mouse[y * 16 + x] = bc;}}}return;
}void putblock8_8(char *vram, int vxsize, int pxsize,int pysize, int px0, int py0, char *buf, int bxsize)
{int x, y;for (y = 0; y < pysize; y++) {for (x = 0; x < pxsize; x++) {vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];}}return;
}
- 打vc code,输入以下代码并保存为 asmhead.nas,存放在harib05c文件夹中。
; haribote-os boot asm
; TAB=4BOTPAK EQU 0x00280000 ; bootpack装载处
DSKCAC EQU 0x00100000 ; 磁盘缓存的地方
DSKCAC0 EQU 0x00008000 ; 磁盘高速缓存的场所(实时模式); 有关BOOT_INFO
CYLS EQU 0x0ff0 ; 设定启动区
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 关于颜色数目的信息,颜色的位数
SCRNX EQU 0x0ff4 ; 分辨率的X(screen x)
SCRNY EQU 0x0ff6 ; 分辨率的Y(screen y)
VRAM EQU 0x0ff8 ; 图像缓冲区的开始地址ORG 0xc200 ; 这个程序要被装载到内存的什么地方呢?; 画面模式设定MOV AL,0x13 ; VGA显卡,320x200x8位彩色MOV AH,0x00INT 0x10MOV BYTE [VMODE],8 ; 记录画面模式(C语言参照)MOV WORD [SCRNX],320MOV WORD [SCRNY],200MOV DWORD [VRAM],0x000a0000; 用BIOS取得键盘各种LED指示灯的状态MOV AH,0x02INT 0x16 ; keyboard BIOSMOV [LEDS],AL; 使PIC不授受一切中断
; 如果要初始PIC的话,要在AT兼容的规范中,
; 如果不把这家伙放在CLI面前,我偶尔会举起来
; 稍后进行PIC的初始化MOV AL,0xffOUT 0x21,ALNOP ; 如果连续OUT命令的话,可能会有不太好的机型OUT 0xa1,ALCLI ; 甚至禁止CPU层面插队; cpu从1 mb以上的内存,a20gate设定CALL waitkbdoutMOV AL,0xd1OUT 0x64,ALCALL waitkbdoutMOV AL,0xdf ; enable A20OUT 0x60,ALCALL waitkbdout; 保护模式过渡[INSTRSET "i486p"] ; 用于记述想要使用的486命令LGDT [GDTR0] ; 暂定GDT设定MOV EAX,CR0AND EAX,0x7fffffff ; 使bit31为0(为子禁止寻乎)OR EAX,0x00000001 ; 使bit0为1(为子保护模式转移)MOV CR0,EAXJMP pipelineflush
pipelineflush:MOV AX,1*8 ; 可读区段32bitMOV DS,AXMOV ES,AXMOV FS,AXMOV GS,AXMOV SS,AX; bootpack的传送MOV ESI,bootpack ; 传输源MOV EDI,BOTPAK ; 传输目的地MOV ECX,512*1024/4CALL memcpy; 顺便磁盘数据也向原来的位置传送; 首先从引导扇区MOV ESI,0x7c00 ; 传输源MOV EDI,DSKCAC ; 传输目的地MOV ECX,512/4CALL memcpy; 剩下的全部MOV ESI,DSKCAC0+512 ; 传输源MOV EDI,DSKCAC+512 ; 传输目的地MOV ECX,0MOV CL,BYTE [CYLS]IMUL ECX,512*18*2/4 ; 从柱面数转换成字节数 /4SUB ECX,512/4 ; 通过IPL减去CALL memcpy; 我们已经完成了需要使用asmhead 进行的所有操作
; 放到bootpack中; 启动bootpackMOV EBX,BOTPAKMOV 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:0x0000001bwaitkbdout:IN AL,0x64AND AL,0x02JNZ waitkbdout ; 如果AND的结果不为0,请跳转至waitkbdouRETmemcpy:MOV EAX,[ESI]ADD ESI,4MOV [EDI],EAXADD EDI,4SUB ECX,1JNZ memcpy ; 如果减法不为0,则返回memcpyRET
; memcpy也可以用字符串指令编写,除非你忘记了地址大小写前缀ALIGNB 16
GDT0:RESB 8 ; 空选择器DW 0xffff,0x0000,0x9200,0x00cf ; 读/定段32bitDW 0xffff,0x0000,0x9a28,0x0047 ; 可执行段32bit(用于bootpack)DW 0
GDTR0:DW 8*3-1DD GDT0ALIGNB 16
bootpack:
- 打开 VC code 创建 ipl10.nas 文件,输入以下代码,也存放的harib05c中。
; haribote-ipl
; TAB=4CYLS EQU 10 ; 要读取到什么程度ORG 0x7c00 ; 启动装载程序; 以下记述用于标准FAT12格式软盘JMP entryDB 0x90DB "HARIBOTE" ; 磁盘名称(可以是任意字符串)DW 512 ; 每个扇区的大小(必须是512)DB 1 ; 簇的大小(必须为一个扇区)DW 1 ; FAT12的起始位置(一般从第一个扇区开始DB 2 ; FAT的个数(必须为2)DW 224 ; 根目录的大小(一般设成224项)DW 2880 ; 该磁盘的大小(必须是2880扇区)DB 0xf0 ; 该磁盘的种类(必须是0xf0DW 9 ; FAt的长度(必须是9扇区)DW 18 ; 一个磁道有几个扇区(必须是18)DW 2 ; 磁头数(必须是2)DD 0 ; 不使用分区,必须是0DD 2880 ; 磁盘大小DB 0,0,0x29 ; 意义不明固定DD 0xffffffff ; (可能是)卷标号码DB "HARIBOTEOS " ; 磁盘的名称(11字节)DB "FAT12 " ; 磁盘格式名称(8字节)RESB 18 ; 先空出18字节; 程序主体entry:MOV AX,0 ; 初始化寄存器MOV SS,AXMOV SP,0x7c00MOV DS,AX; 读磁盘MOV AX,0x0820MOV ES,AXMOV CH,0 ; 柱面 0MOV DH,0 ; 磁头 0MOV CL,2 ; 扇区 2
readloop:MOV SI,0 ; 记录失败次数的寄存器
retry:MOV AH,0x02 ; AH=0x02 : 读入磁盘MOV AL,1 ; 1 个扇区MOV BX,0MOV DL,0x00 ; A 驱动器INT 0x13 ; 调用磁盘BIOSJNC next ; 没出错时跳转到nextADD SI,1 ; SI 加 1CMP SI,5 ; 比较 SI 与 5JAE error ; SI >= 5 时,跳转到errorMOV AH,0x00MOV DL,0x00 ; A 驱动器INT 0x13 ; 重置驱动器JMP retry
next:MOV AX,ES ; 把内存地址后移0x200ADD AX,0x0020MOV ES,AX ; 因为没有 ADD ES,0x020 指令,所以这里稍微绕个弯ADD CL,1 ; CL 加 1CMP CL,18 ; 比较 CL 与 18JBE readloop ; 如果 CL <= 18,则跳转至readloop MOV CL,1ADD DH,1CMP DH,2JB readloop ; 如果 DH < 2, 则跳转到readloopMOV DH,0ADD CH,1CMP CH,CYLSJB readloop ; 如果 CH < CYLS,则跳转至readloop; 因为看完了实行haribote.sysMOV [0x0ff0],CH ; IPL读到什么地方结束JMP 0xc200error:MOV SI,msg
putloop:MOV AL,[SI]ADD SI,1 ; SI 加 1CMP AL,0JE finMOV AH,0x0e ; 显示一个文字MOV BX,15 ; 指定字符颜色INT 0x10 ; 调用显卡BIOSJMP putloop
fin:HLT ; 让CPu停止,等待指令JMP fin ; 无限循环
msg:DB 0x0a, 0x0a ; 换行两次DB "load error"DB 0x0a ; 换行DB 0RESB 0x7dfe-$ ; 重复0x00一直到0x7dfeDB 0x55, 0xaa
- 打开记事本,输入以下代码,另存为 make.bat, 同样放到harib05c中。
..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
- 创建 Makefile,并输入以下代码并存放到harib05c中。
OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \int.obj fifo.objTOOLPATH = ../z_tools/
INCPATH = ../z_tools/haribote/MAKE = $(TOOLPATH)make.exe -r
NASK = $(TOOLPATH)nask.exe
CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet
GAS2NASK = $(TOOLPATH)gas2nask.exe -a
OBJ2BIM = $(TOOLPATH)obj2bim.exe
MAKEFONT = $(TOOLPATH)makefont.exe
BIN2OBJ = $(TOOLPATH)bin2obj.exe
BIM2HRB = $(TOOLPATH)bim2hrb.exe
RULEFILE = $(TOOLPATH)haribote/haribote.rul
EDIMG = $(TOOLPATH)edimg.exe
IMGTOL = $(TOOLPATH)imgtol.com
COPY = copy
DEL = del# 默认default :$(MAKE) img# 文件生成规则ipl10.bin : ipl10.nas Makefile$(NASK) ipl10.nas ipl10.bin ipl10.lstasmhead.bin : asmhead.nas Makefile$(NASK) asmhead.nas asmhead.bin asmhead.lsthankaku.bin : hankaku.txt Makefile$(MAKEFONT) hankaku.txt hankaku.binhankaku.obj : hankaku.bin Makefile$(BIN2OBJ) hankaku.bin hankaku.obj _hankakubootpack.bim : $(OBJS_BOOTPACK) Makefile$(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \$(OBJS_BOOTPACK)
# 3MB+64KB=3136KBbootpack.hrb : bootpack.bim Makefile$(BIM2HRB) bootpack.bim bootpack.hrb 0haribote.sys : asmhead.bin bootpack.hrb Makefilecopy /B asmhead.bin+bootpack.hrb haribote.sysharibote.img : ipl10.bin haribote.sys Makefile$(EDIMG) imgin:../z_tools/fdimg0at.tek \wbinimg src:ipl10.bin len:512 from:0 to:0 \copy from:haribote.sys to:@: \imgout:haribote.img# 一般规则%.gas : %.c bootpack.h Makefile$(CC1) -o $*.gas $*.c%.nas : %.gas Makefile$(GAS2NASK) $*.gas $*.nas%.obj : %.nas Makefile$(NASK) $*.nas $*.obj $*.lst# 命令img :$(MAKE) haribote.imgrun :$(MAKE) img$(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin$(MAKE) -C ../z_tools/qemuinstall :$(MAKE) img$(IMGTOL) w a: haribote.imgclean :-$(DEL) *.bin-$(DEL) *.lst-$(DEL) *.obj-$(DEL) bootpack.map-$(DEL) bootpack.bim-$(DEL) bootpack.hrb-$(DEL) haribote.syssrc_only :$(MAKE) clean-$(DEL) haribote.img
- 打开记事本,复制以下内容并保存为 hankaku.txt,且存放在harib05c中;ps:建议这一段代码直接复制不要看。
这段代码过多,无法贴出来,请在网盘资源复制,projects/05_day/harib02f中hankaku.txt
编译及运行
- 双击 !cons_nt.bat,并在打开的命令行中输入 make run
- VMware中运行结果,如下图
ps: 结果就是这样,因为本次实验的目的是鼠标解读(2) (harib05c),可以试着移动鼠标看看,观察编码的变化。快要到鼠标画面移动了,以后会有更精彩。敬请期待!
好的今天到这里harib05c就张结束了,请大家多多支持!!!
30天自制操作系统第8天harib05c相关推荐
- 索骥馆-DIY操作系统之《30天自制操作系统》扫描版[PDF]
内容简介: <30天自制操作系统>是一本兼具趣味性.实用性与学习性的操作系统图书.作者从计算机的构造.汇编语言.C语言开始解说,让读者在实践中掌握算法.在这本书的指导下,从零编写所有代码, ...
- 为什么《30天自制操作系统》封面中的猫是两只尾巴
刚刚在一社区,发了一贴,被指出一问题,询一高人,得一答案.这便是我没有关注到的封面上的那只猫,我想这也是很多读者没有关注到的.因为在我微博的200转发贴中,并没有人提到封面中的猫为何有两只尾巴.于是咨 ...
- 发布在《30天自制操作系统》之前的帮助阅读贴
说明:这是8月15日即将上市的一本新书,本文的摘选也可以命名为<30天自制操作系统>上市之前必读.本书幽默,有趣,可以说是技术书里的幽默书,让您读起来绝对不会感到乏味.在本书上市之前,您一 ...
- 《30天自制操作系统》笔记(01)——hello bitzhuwei’s OS!
<30天自制操作系统>笔记(01)--hello bitzhuwei's OS! 最初的OS代码 1 ; hello-os 2 ; TAB=4 3 4 ORG 0x7c00 ; 指明程序的 ...
- 写在《30天自制操作系统》上市之前
这本<30天自制操作系统>马上就要在各大书店和网上商城全面上架了,作为本书的4位译者之一,我负责翻译了本书约三分之二的内容.这是我参与翻译的第一本译著,我感到很激动也很紧张,因为我知 ...
- 《30天自制操作系统》笔记(04)——显示器256色
<30天自制操作系统>笔记(04)--显示器256色 进度回顾 从最开始的(01)篇到上一篇为止,已经解决了开发环境问题和OS项目的顶层设计问题. 本篇做一个小练习:设置显卡显示256色. ...
- 《30天自制操作系统》学习笔记--第好多天
之前看<30天自制操作系统>,参考而成,和书中系统并不完全一致,是在原有基础上按照自己的习惯而成,由于水平和工作原因,未完成内存管理和文件系统,有兴趣者可以通过以下网址https://gi ...
- 由《30天自制操作系统》引发的漫画创作
大家可还记得<30天自制操作系统>的封面上的那只猫吗?记得当时,在果壳网有人问,为何这只猫长了两只尾巴呢,延着这条线,我把这本书捧上了展示的舞台.事隔四个多月,我又重提此书. 这本经我手宣 ...
- 30天自制操作系统——第二十三天窗口操作
窗口及输入切换 我们先来实现用键盘切换窗口,按下F11键,将最下面的窗口移动到最上面,这里F11按键的编码为0x57. bootpack.c节选: void HariMain(void) {(略)fo ...
- 30天自制操作系统-初体验
最近在图书馆翻阅关于操作系统的书籍,看到川和秀实的自制操作系统决定也动手尝试一下,这本书书名就叫做30天自制操作系统.首先还是附上光盘镜像的获取地址吧.30天自制操作系统光盘镜像ISO完整版下载 - ...
最新文章
- 数据中心的敏捷运维之路
- for惠普2013实习生
- 代码审计——命令执行
- 安川西格玛7驱动器手册_什么是伺服驱动器?选型的原则有哪些?
- CPU,内核,寄存器,缓存,RAM,ROM的知识
- H264/ACC数据使用librtmp推流到服务器
- http请求前后监听工具
- mysql geometry 维度_使用MySQL的geometry类型处理经纬度距离问题的方法
- less加管道tail_Linux-10 (CentOS)cat/more/less/ / 及echo/head /tail/的用法区别
- 拓端tecdat|R语言使用Rasch模型分析学生答题能力
- 【TWVRP】基于matlab遗传算法求解带时间窗的载重约束外卖配送车辆路径规划问题【含Matlab源码 1417期】
- 【图像分割】基于Matlab Tsallis熵算法灰度图像分割【含Matlab源码 715期】
- python基本快捷键
- 风吹雨PHP多应用授权系统【开源】
- C++转erlang后感想
- 谁是史上最强-用爬虫分析IMDB TOP250电影数据
- Oracle GoldenGate官档知识
- Arduino基础入门篇19—点阵屏
- 使用c语言实现三子棋游戏
- 内网渗透DC-1靶场通关(CTF)
热门文章
- 网吧服务器怎么加无线路由器,网吧路由器怎么设置 网吧路由器设置方法【详细步骤】...
- C#贪吃蛇游戏(全代码)
- Redis 使用 scan 命令代替 keys
- java根据指定字符开头_Java如何检查以特定单词开头的字符串?
- 收美之鸿蒙灵戒,顺网神戒之鸿蒙
- 【年终总结】—此生平凡,终不简单
- lol7月9日服务器维护,英雄联盟7月9日更新维护到几点结束_lol7月9日10.14版本更新维护结束时间介绍_咖绿茵手游站...
- C语言项目-后宫选妃系统-第三天-终结
- React从零到一Demo演练(上)
- html怎么直接修改,如何编辑运行HTML网页文件(HTML编辑工具使用介绍)