0x04_自制操作系统My-OS实现自定义颜色

发布时间 2023-03-22 19:12:02作者: Z_Chan

前言:

0x03我们提到:

把12(红色)用循环写入显存,每个像素点怎么显示都要看对应的显存地址,比如0xa0000到0xaffff就是每一个像素点的显存

你问为什么12就是红色,这些东西在主板出厂的时候就是规定好的,就是有点调用主板api的味道,这是我的猜测,具体为什么还要你们来查

你会发现12是红色,11就是另一种颜色,有没有办法可以自定义颜色呢

 

自定义颜色的原因是:

  颜色丰富度不够,因此使用调色板功能来增强颜色显示,使用RGB模式,表示一个RGB颜色需要24位数

修改class01名字为class02,把我给出的代码对原来的内容进行替换,当然你也可以找不同,如果你有这个耐心的话

代码:

naskfunc.asm

; naskfunc
; TAB=4

[FORMAT "WCOFF"]                ; 制作目标文件的模式    
[INSTRSET "i486p"]                ; 使用到486为止的指令
[BITS 32]                        ; 3制作32位模式用的机器语言
[FILE "naskfunc.asm"]            ; 文件名
    GLOBAL _io_hlt,_write_mem8,_io_cli,_io_sti,_io_get8,_io_set8,_io_stihlt
    GLOBAL _io_load_eflags,_io_store_eflags
        

[SECTION .text]

_io_hlt:    ; void io_hlt(void);
        HLT
        RET

_io_cli:    ; void io_cli(void);
        CLI
        RET

_io_sti:    ; void io_sti(void);
        STI
        RET

_io_get8:    ; int io_get8(int port);
        MOV        EDX,[ESP+4]        ; port
        MOV        EAX,0
        IN        AL,DX
        RET

_io_set8:    ; void io_set8(int port, int data);
        MOV        EDX,[ESP+4]        ; port
        MOV        AL,[ESP+8]        ; data
        OUT        DX,AL
        RET

_io_stihlt:    ; void io_stihlt(void);
        STI
        HLT
        RET

_write_mem8: ; void write_mem8(int addr, int data);
        MOV ECX,[ESP+4] ; taking content of add
        MOV AL,[ESP+8] ; taking content of data
        MOV [ECX],AL ; *ecx=al
        RET
_io_load_eflags:    ; int io_load_eflags(void);
        PUSHFD        ; PUSH EFLAGS 
        POP        EAX
        RET

_io_store_eflags:    ; void io_store_eflags(int eflags);
        MOV        EAX,[ESP+4]
        PUSH    EAX
        POPFD        ; POP EFLAGS 
        RET

 

这里增加了一些函数,看不懂没关系,我等下调用他们的时候讲一下是干嘛的

新建一个文件graphic.c

#include "include/head.h"


void init_palette(void)
{
    static unsigned char table_rgb[18 * 3] = {
        0x24, 0x86, 0xb9,    /*  0:宝石蓝(#2486b9) */
        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:暗紫 */
        0x33, 0x33, 0x33,    /* 14:浅暗蓝 */
        0x84, 0x84, 0x84,    /* 15:暗灰 */
        0xD0, 0xD0, 0xD0,
        0x20, 0x20, 0x20
    };
    set_palette(0, 17, 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_set8(0x03c8, start);
    for (i = start; i <= end; i++) {
        io_set8(0x03c9, rgb[0] / 4);
        io_set8(0x03c9, rgb[1] / 4);
        io_set8(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;
}

前两个函数是用来实现调色板的,具体原理我解释不了,Ctrl+CV大佬不需要知道原理,你懂我意思吧,里面调用了很多asm里的函数

第三个函数是绘制方块的参数意思分别是:显存地址,显示宽度,颜色代号,从x0到x1,y0到y1进行绘制一个矩形

head.h

/*naskfunc.asm*/
void io_stihlt();
void io_hlt(void);
void io_cli(void);
void io_sti(void);
int io_get8(int port);
void io_set8(int port, int data);
void write_mem8(int addr, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

/* asmhead.nas */
struct BOOTINFO { /* 0x0ff0-0x0fff */
    char cyls; /* 启动区读磁盘读到此为止 */
    char leds; /* 启动时键盘的LED的状态 */
    char vmode; /* 显卡模式为多少位彩色 */
    char reserve;
    short scrnx, scrny; /* 画面分辨率 */
    char *vram;
};
#define ADR_BOOTINFO 0x00000ff0

/*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);

我们主要看第二个asmhead.asm的函数声明,这个BOOTINFO结构体,是涵盖了显示器的信息,信息的位置在0x0ff0-0x0ffff

main.c

#include "include/head.h"

struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;

void Main(void){
    int i;
    init_palette();
    boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny);
    for (;;) {
        io_hlt();
    }
}

第一句是获取这个显示器信息的结构体,调用boxfill8填充整个屏幕,颜色代号是调色板中的0号宝石蓝

最后在make脚本中增加graphic.obj

 运行:

cd class02
..\z_tools\make.exe run

自制操作系统合集
原文地址:https://www.cnblogs.com/Frank-dev-blog/category/2249116.html
项目github地址rick521/My-OS (github.com)给我点颗star