zoukankan      html  css  js  c++  java
  • 《30天自制操作系统》05_day_学习笔记

    //bootpack.c  完整代码
    #include <stdio.h>
    
    void io_hlt(void);
    void io_cli(void);
    void io_out8(int port, int data);
    int io_load_eflags(void);
    void io_store_eflags(int eflags);
    
    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
    
    //接受启动信息写成结构体的形式  P89.接着从asmhead.nas中读取启动信息数据(启动地址和内容)
    //注意在第一天中,我们已经把asmhead.nas中的信息写到了镜像中。每次系统启动时,首先载入镜像,然后读到asmhead.nas中的内容启动
    struct BOOTINFO {  
        char cyls, leds, vmode, reserve;
        short scrnx, scrny;
        char *vram;
    };
    
    struct SEGMENT_DESCRIPTOR {  //GDT的内容;8字节
        short limit_low, base_low;
        char base_mid, access_right;
        char limit_high, base_high;
    };
    
    struct GATE_DESCRIPTOR {    //IDT的内容,8字节
        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);
    void load_gdtr(int limit, int addr);
    void load_idtr(int limit, int addr);
    
    void HariMain(void)
    {
        struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
        char s[40], mcursor[256];
        int mx, my;
    
        init_gdtidt();
        init_palette();
        init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);  //所谓的使用箭头记号->
        mx = (binfo->scrnx - 16) / 2;   /* 启动信息结构体BOOTINFO 从asmhead.nas中读取启动信息数据*/
        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);  //显示变量,先把内容放到字符串s中
        putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s); //接着把字符串s显示出来
    
        for (;;) {
            io_hlt();
        }
    }
    
    void init_palette(void)
    {
        static unsigned char table_rgb[16 * 3] = {
            0x00, 0x00, 0x00,    
            0xff, 0x00, 0x00,    
            0x00, 0xff, 0x00,    
            0xff, 0xff, 0x00,    
            0x00, 0x00, 0xff,    
            0xff, 0x00, 0xff,    
            0x00, 0xff, 0xff,    
            0xff, 0xff, 0xff,    
            0xc6, 0xc6, 0xc6,    
            0x84, 0x00, 0x00,    
            0x00, 0x84, 0x00,    
            0x84, 0x84, 0x00,    
            0x00, 0x00, 0x84,    
            0x84, 0x00, 0x84,    
            0x00, 0x84, 0x84,    
            0x84, 0x84, 0x84    
        };
        set_palette(0, 15, table_rgb);
        return;
    }
    
    void set_palette(int start, int end, unsigned char *rgb)
    {
        int i, eflags;
        eflags = io_load_eflags();
        io_cli();                     
        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 /* data */;
        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*16=512字符(字节)*/
    {
        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;
    }
    
    void init_gdtidt(void)   //GDT和IDT的初始化
    {
        struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) 0x00270000;
        struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) 0x0026f800;
        int i;
    
        /* GDT初始化 */
        for (i = 0; i < 8192; i++) {    //i每次加一;但是gdt指向8字节的结构体;结果地址增加了8
            set_segmdesc(gdt + i, 0, 0, 0);    //gdt*(地址)每次+8
        }
        set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, 0x4092);  //段号为1;大小4G 表示CPU管理的全部内存
        set_segmdesc(gdt + 2, 0x0007ffff, 0x00280000, 0x409a);  //段号位2; 大小512K  为bootpack.hrb准备
        load_gdtr(0xffff, 0x00270000);  //GDT    0x270000-0x27ffff  借助汇编语言的力量给寄存器GDTR赋值
    
        /* IDT初始化  */
        for (i = 0; i < 256; i++) {    //和上面一样
            set_gatedesc(idt + i, 0, 0, 0);
        }                               //IDT    0x26f800-0x26ffff
        load_idtr(0x7ff, 0x0026f800);    //向寄存器IDTR赋值
    
        return;
    }
    
    void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
    {
        if (limit > 0xfffff) {
            ar |= 0x8000; /* G_bit = 1 */
            limit /= 0x1000;
        }
        sd->limit_low    = limit & 0xffff;
        sd->base_low     = base & 0xffff;
        sd->base_mid     = (base >> 16) & 0xff;
        sd->access_right = ar & 0xff;
        sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
        sd->base_high    = (base >> 24) & 0xff;
        return;
    }
    
    void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
    {
        gd->offset_low   = offset & 0xffff;
        gd->selector     = selector;
        gd->dw_count     = (ar >> 8) & 0xff;
        gd->access_right = ar & 0xff;
        gd->offset_high  = (offset >> 16) & 0xffff;
        return;
    }
    bootpack.c 完整代码day_05

    harib02a:

      P89 这里做的就是数值写入asmhead.nas中,然后取值;
      而不是将这些数值直接写入程序bootpack.c中

    //bootpack.c节选
    void HariMain(void)
    {
        char *vram;
        int xsize, ysize;
        short *binfo_scrnx, *binfo_scrny;
        int *binfo_vram;
    init_palette(); binfo_scrnx
    = (short *) 0x0ff4; binfo_scrny = (short *) 0x0ff6; binfo_vram = (int *) 0x0ff8; xsize = *binfo_scrnx; ysize = *binfo_scrny; vram = (char *) *binfo_vram; init_screen(vram, xsize, ysize); for (;;) { io_hlt(); } }

    harib02b:
      这次使用的是结构体的方法重新写一遍,实现的内容是一样的
      只是实现方法在这里使用了结构体的写法。如下:

    //bootpack.c节选
    //接受启动信息写成结构体的形式 P89.接着从asmhead.nas中读取启动信息数据(启动地址和内容)
    //注意在第一天中,我们已经把asmhead.nas中的信息写到了镜像中。每次系统启动时,首先载入镜像,然后读到asmhead.nas中的内容启动
    struct BOOTINFO {
        char cyls, leds, vmode, reserve;
        short scrnx, scrny;
        char *vram;
    };
    void HariMain(void)
    {
        char *vram;
        int xsize, ysize;
        struct BOOTINFO *binfo;
    
        init_palette();
        binfo = (struct BOOTINFO *) 0x0ff0;
        xsize = (*binfo).scrnx;
        ysize = (*binfo).scrny;
        vram = (*binfo).vram;
    
        init_screen(vram, xsize, ysize);
    
        for (;;) {
            io_hlt();
        }
    }

    harib02c:
      这一步在结构体的基础上,引入了箭头记号的C变成的方式
      eg::xsize = (*binfo).scrnx  可以写成  xsize = binfo -> scrnx
      进一步改进了程序,但实现的内容任然不变

    void HariMain(void)
    {
        struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
    
        init_palette();
        init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
    
        for (;;) {
            io_hlt();
        }
    }

    harib02d:
      P92 显示字符;
      原理:字符使用8*16的像素点阵来表示,
      1个字符是16个字节
      建立了font结构体数组,用来表示像素点阵字符
      函数purfont8()用来将像素点阵字符输出

    //字符显示函数
    void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
    {
        int i;
        char *p, d /* data */;
        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;
    }

    harib02e:
      P94 增加了字体的显示; 这里使用了OSASK的字体数据;
      原理:相应了字体显示的像素点阵存储在hankaku.txt中。
      每一个字体字符都有一个编号。直接查找调用即可
      方法:用OSASK的专用编译器makefont.exe将hankaku.txt编译成hankaku.bin
      再由连接器bin2obj.exer将hankaku.bin加上必须的接口信息和bootpack.obj链接
      生成目标文件

    //显示ABC  123
    void HariMain(void)
    {
        struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
        extern char hankaku[4096];
    
        init_palette();
        init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
        putfont8(binfo->vram, binfo->scrnx, 10, 0, COL8_FFFFFF, hankaku + 'A' * 16);
        putfont8(binfo->vram, binfo->scrnx, 16, 8, COL8_FFFFFF, hankaku + 'B' * 16);
        putfont8(binfo->vram, binfo->scrnx, 24, 8, COL8_FFFFFF, hankaku + 'C' * 16);
        putfont8(binfo->vram, binfo->scrnx, 40, 8, COL8_FFFFFF, hankaku + '1' * 16);
        putfont8(binfo->vram, binfo->scrnx, 48, 8, COL8_FFFFFF, hankaku + '2' * 16);
        putfont8(binfo->vram, binfo->scrnx, 56, 8, COL8_FFFFFF, hankaku + '3' * 16);
        for (;;) {
            io_hlt();
        }
    }

    harib02f:
      接着笔者干脆写了一个函数用来专门显示字符串;putfonts8_asc();

    //字符串显示函数
    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;
    }

    harib02g:
      P98 显示变量的值;虽然我们不能用prinft()函数;但是我们可以使用sprintf()函数
      sprintf()将输出的内容写在内存中间。这个函数只对内存进行操作,可以应用于所有的操作系统
      笔者还附带的介绍了一下sprintf()的使用方法和格式;

        sprintf(s, "scrnx = %d", binfo->scrnx);
        putfonts8_asc(binfo->vram, binfo->scrnx, 16, 64, COL8_FFFFFF, s);

    harib02h:
      P100 鼠标指针的显示。大小设定为16*16的字符数组的大小
      内存空间:16*16=256字节;程序写在了init_mouse_cursor8中。
      显示的原理和上面字符显示的原理一样;将buf中的数据复制到VARM中去就可以了
      接下来笔者写了一个显示的函数putblock8_8();教材100面有函数详细的介绍。

    //bootpack.c 节选
    void init_mouse_cursor8(char *mouse, char bc)
    /* 准备,初始化鼠标指针 16*16=512字符(字节)*/
    {
        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;
    }

    harib02i:
      P101 怎么才能让鼠标动起来?我们先来看看什么事GDT和IDT
      这两个东西是CPU有关的设定(大家暂时不用深究什么是设定,先往下看)
      接下来要用汇编语言(有回到汇编语言了)来对CPU做一些鼠标的设定
      接下来笔者讲了操作系统分段的概念,关于分段、分页。学过操作系统的都应该知道,不再赘述
      GDT:全局段号记录表,存放在内存中的。把需要查找的地址和相应的段号对应起来,便于寻址和查找;
          寄存器GDTR用来存储该段内存的起始地址和有效的设定个数
      IDT:中断记录表;中断号为0-255;每一个中断号对应一个函数调用,
           这些函数就是用来处理操作系统中的中断的,中断发生后,调用通过IDT调用相应的中断函数即可

    //bootpack.c节选
    struct SEGMENT_DESCRIPTOR {  //GDT的内容;8字节
        short limit_low, base_low;
        char base_mid, access_right;
        char limit_high, base_high;
    };
    
    struct GATE_DESCRIPTOR {   //IDT的内容,8字节
        short offset_low, selector;
        char dw_count, access_right;
        short offset_high;
    };
    ...................
    void init_gdtidt(void)   //GDT和IDT的初始化
    {
        struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) 0x00270000;
        struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) 0x0026f800;
        int i;
    
        /* GDT初始化 */
        for (i = 0; i < 8192; i++) {    //i每次加一;但是gdt指向8字节的结构体;结果地址增加了8
            set_segmdesc(gdt + i, 0, 0, 0);    //gdt*(地址)每次+8
        }
        set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, 0x4092);  //段号为1;大小4G 表示CPU管理的全部内存
        set_segmdesc(gdt + 2, 0x0007ffff, 0x00280000, 0x409a);  //段号位2; 大小512K  为bootpack.hrb准备
        load_gdtr(0xffff, 0x00270000);  //GDT    0x270000-0x27ffff  借助汇编语言的力量给寄存器GDTR赋值
    
        /* IDT初始化  */
        for (i = 0; i < 256; i++) {    //和上面一样
            set_gatedesc(idt + i, 0, 0, 0);
        }                               //IDT    0x26f800-0x26ffff
        load_idtr(0x7ff, 0x0026f800);    //向寄存器IDTR赋值
    
        return;
    }
  • 相关阅读:
    PHP基本的语法以及和Java的差别
    Linux 性能測试工具
    【Oracle 集群】Linux下Oracle RAC集群搭建之Oracle DataBase安装(八)
    【Oracle 集群】Oracle 11G RAC教程之集群安装(七)
    【Oracle 集群】11G RAC 知识图文详细教程之RAC在LINUX上使用NFS安装前准备(六)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 特殊问题和实战经验(五)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之缓存融合技术和主要后台进程(四)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)
    Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之集群概念介绍(一)
  • 原文地址:https://www.cnblogs.com/pengfeiz/p/5781750.html
Copyright © 2011-2022 走看看