第8天 鼠标控制与32位模式切换

鼠标解读(2)

harib05c

准备材料(windows环境)
  • VMware Workstation
  • Visual Studio Code
  • 程序和源代码:https://pan.baidu.com/s/1bFGAYgnA0m9KB7tzFrMD5g
    提取码:d210
  • Makefile
  • windows 批处理
开始实验
  1. 在tolset文件夹下创建子文件侠harib05c。

  2. 打开记事本,输入以下代码并另存为 !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
  1. 打开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;
}
  1. 打开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; /* 应该不可能到这里来 */
}
  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
  1. 打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;
}
  1. 打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:
  1. 打开 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
  1. 打开记事本,输入以下代码,另存为 make.bat, 同样放到harib05c中。
..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
  1. 创建 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
  1. 打开记事本,复制以下内容并保存为 hankaku.txt,且存放在harib05c中;ps:建议这一段代码直接复制不要看
这段代码过多,无法贴出来,请在网盘资源复制,projects/05_day/harib02f中hankaku.txt
编译及运行
  1. 双击 !cons_nt.bat,并在打开的命令行中输入 make run
  2. VMware中运行结果,如下图

    ps: 结果就是这样,因为本次实验的目的是鼠标解读(2) (harib05c),可以试着移动鼠标看看,观察编码的变化。快要到鼠标画面移动了,以后会有更精彩。敬请期待!
    好的今天到这里harib05c就张结束了,请大家多多支持!!!

30天自制操作系统第8天harib05c相关推荐

  1. 索骥馆-DIY操作系统之《30天自制操作系统》扫描版[PDF]

    内容简介: <30天自制操作系统>是一本兼具趣味性.实用性与学习性的操作系统图书.作者从计算机的构造.汇编语言.C语言开始解说,让读者在实践中掌握算法.在这本书的指导下,从零编写所有代码, ...

  2. 为什么《30天自制操作系统》封面中的猫是两只尾巴

    刚刚在一社区,发了一贴,被指出一问题,询一高人,得一答案.这便是我没有关注到的封面上的那只猫,我想这也是很多读者没有关注到的.因为在我微博的200转发贴中,并没有人提到封面中的猫为何有两只尾巴.于是咨 ...

  3. 发布在《30天自制操作系统》之前的帮助阅读贴

    说明:这是8月15日即将上市的一本新书,本文的摘选也可以命名为<30天自制操作系统>上市之前必读.本书幽默,有趣,可以说是技术书里的幽默书,让您读起来绝对不会感到乏味.在本书上市之前,您一 ...

  4. 《30天自制操作系统》笔记(01)——hello bitzhuwei’s OS!

    <30天自制操作系统>笔记(01)--hello bitzhuwei's OS! 最初的OS代码 1 ; hello-os 2 ; TAB=4 3 4 ORG 0x7c00 ; 指明程序的 ...

  5. 写在《30天自制操作系统》上市之前

       这本<30天自制操作系统>马上就要在各大书店和网上商城全面上架了,作为本书的4位译者之一,我负责翻译了本书约三分之二的内容.这是我参与翻译的第一本译著,我感到很激动也很紧张,因为我知 ...

  6. 《30天自制操作系统》笔记(04)——显示器256色

    <30天自制操作系统>笔记(04)--显示器256色 进度回顾 从最开始的(01)篇到上一篇为止,已经解决了开发环境问题和OS项目的顶层设计问题. 本篇做一个小练习:设置显卡显示256色. ...

  7. 《30天自制操作系统》学习笔记--第好多天

    之前看<30天自制操作系统>,参考而成,和书中系统并不完全一致,是在原有基础上按照自己的习惯而成,由于水平和工作原因,未完成内存管理和文件系统,有兴趣者可以通过以下网址https://gi ...

  8. 由《30天自制操作系统》引发的漫画创作

    大家可还记得<30天自制操作系统>的封面上的那只猫吗?记得当时,在果壳网有人问,为何这只猫长了两只尾巴呢,延着这条线,我把这本书捧上了展示的舞台.事隔四个多月,我又重提此书. 这本经我手宣 ...

  9. 30天自制操作系统——第二十三天窗口操作

    窗口及输入切换 我们先来实现用键盘切换窗口,按下F11键,将最下面的窗口移动到最上面,这里F11按键的编码为0x57. bootpack.c节选: void HariMain(void) {(略)fo ...

  10. 30天自制操作系统-初体验

    最近在图书馆翻阅关于操作系统的书籍,看到川和秀实的自制操作系统决定也动手尝试一下,这本书书名就叫做30天自制操作系统.首先还是附上光盘镜像的获取地址吧.30天自制操作系统光盘镜像ISO完整版下载 - ...

最新文章

  1. 数据中心的敏捷运维之路
  2. for惠普2013实习生
  3. 代码审计——命令执行
  4. 安川西格玛7驱动器手册_什么是伺服驱动器?选型的原则有哪些?
  5. CPU,内核,寄存器,缓存,RAM,ROM的知识
  6. H264/ACC数据使用librtmp推流到服务器
  7. http请求前后监听工具
  8. mysql geometry 维度_使用MySQL的geometry类型处理经纬度距离问题的方法
  9. less加管道tail_Linux-10 (CentOS)cat/more/less/ / 及echo/head /tail/的用法区别
  10. 拓端tecdat|R语言使用Rasch模型分析学生答题能力
  11. 【TWVRP】基于matlab遗传算法求解带时间窗的载重约束外卖配送车辆路径规划问题【含Matlab源码 1417期】
  12. 【图像分割】基于Matlab Tsallis熵算法灰度图像分割【含Matlab源码 715期】
  13. python基本快捷键
  14. 风吹雨PHP多应用授权系统【开源】
  15. C++转erlang后感想
  16. 谁是史上最强-用爬虫分析IMDB TOP250电影数据
  17. Oracle GoldenGate官档知识
  18. Arduino基础入门篇19—点阵屏
  19. 使用c语言实现三子棋游戏
  20. 内网渗透DC-1靶场通关(CTF)

热门文章

  1. 网吧服务器怎么加无线路由器,网吧路由器怎么设置 网吧路由器设置方法【详细步骤】...
  2. C#贪吃蛇游戏(全代码)
  3. Redis 使用 scan 命令代替 keys
  4. java根据指定字符开头_Java如何检查以特定单词开头的字符串?
  5. 收美之鸿蒙灵戒,顺网神戒之鸿蒙
  6. 【年终总结】—此生平凡,终不简单
  7. lol7月9日服务器维护,英雄联盟7月9日更新维护到几点结束_lol7月9日10.14版本更新维护结束时间介绍_咖绿茵手游站...
  8. C语言项目-后宫选妃系统-第三天-终结
  9. React从零到一Demo演练(上)
  10. html怎么直接修改,如何编辑运行HTML网页文件(HTML编辑工具使用介绍)