十八、可以输出文字了

    那个点阵字库数组这么大,占地方,难看。而且要换字体也不方便,还得重新制作。还是直接把现有的字库文件作为一个资源文件比较好,loadre 到内存就行。

    字库暂时放到内存 0x10000处

; const.inc
; 常量
; 四彩
; 2015-12-12

%ifndef _CONSTANT_INC
%define _CONSTANT_INC

; ========================================================================================
; 内存中 0x0500 ~ 0x7BFF 段(29.75 KB)和 0x7E00 ~ 0x9FBFF 段(607.5 KB)可自由使用。
; 引导扇区段在加载完 Loader 后也可使用,即整个 0x500 ~ 0x9FBFF 段(637.25 KB)都可自由使用。
;
STACKSIZE           equ 0x1000          ; 堆栈大小

SEGMENTOFGPARAM     equ 0x50            ; 存放全局数据的段基址
SEGMENTOFTEMP       equ 0x7E            ; 临时数据被加载到内存的段基址
SEGMENTOFFONT       equ 0x1000          ; 点阵字库被加载到内存的段基址
SEGMENTOFLOADER     equ 0x9000          ; LOADER.SYS 被加载到内存的段基址
SEGMENTOFKERNEL     equ 0x8000          ; KERNEL.EXE 被加载到内存的段基址
KERNELENTRYPHYADDR  equ 0x30400         ; kernel 的程序入口的物理地址
                                        ; 必须与 Makefile 中 -Ttext 参数的值相等
; ****************************************************************************************

%endif
; loader.asm
; 加载程序
; 四彩
; 2015-12-12


; ========================================================================================
; ----------------------------------------------------------------------------------------
; 头文件
%include "./boot/inc/const.inc"
%include "./boot/inc/FAT12.inc"
%include "./boot/inc/PMode.inc"
%include "./boot/inc/ELF.inc"

; ----------------------------------------------------------------------------------------
    org STACKSIZE
    jmp RMode_main
; ****************************************************************************************


;=========================================================================================
[SECTION .data]
; ----------------------------------------------------------------------------------------
; 地址范围描述符结构(Address Range Descriptor Structure)
struc T_AddrRngDscStruc
;      字段名                       ;偏移 长度 说明
    .dwBaseAddrLow      resd 1      ; 0x00  4   基地址的低 32 位
    .dwBaseAddrHigh     resd 1      ; 0x04  4   基地址的高 32 位(未使用,为 0)
    .dwLengthLow        resd 1      ; 0x08  4   长度(字节)的低32位
    .dwLengthHigh       resd 1      ; 0x0C  4   长度(字节)的高32位(未使用,为 0)
    .dwType             resd 1      ; 0x10  4   地址类型:1 = 可用段, 2 = 正用或保留段,
endstruc

; 全局变量结构
struc T_Global_Param
;      字段名                       ;偏移 长度 说明
    .dwMemorySize       resd 1      ; 0x00  4   内存总容量
    .dwPhyAddrOfVideo   resd 1      ; 0x04  4   显存基址
    .wScreenX           resw 1      ; 0x08  2   分辨率 X
    .wScreenY           resw 1      ; 0x0A  2   分辨率 Y
    .bBitsPerPixel      resb 1      ; 0x0C  1   颜色数
endstruc

; ----------------------------------------------------------------------------------------
; 出错提示信息及 kernel 文件名
    strCheckMemoryFail  db "Failed to check memory", 0
    strNotSupportVESA   db "Not support VESA", 0
    strNotFoundFile     db "Not found ", 0
    FileNameOfKernel    db "KERNEL  SYS", 0     ; kernel 文件名(8 + 3 格式)
    FileNameOfFont      db "ASC16      ", 0     ; 点阵字库文件名

; ----------------------------------------------------------------------------------------
tArds istruc T_AddrRngDscStruc      ; 地址范围描述符结构实体
    times T_AddrRngDscStruc_size db 0
iend

; ----------------------------------------------------------------------------------------
; GDT
; Loader 把全部内存都作为一个段使用,分为两类:代码段、数据段
;                       基址        界限        属性
Desc_Begin : Descriptor 0,          0,          0                           ; 空描述符
Desc_Code  : Descriptor 0,          0xFFFFF,    DA_CS_ER + DA_32 + DA_4K    ; 代码段
Desc_Data  : Descriptor 0,          0xFFFFF,    DA_DS_RW + DA_32 + DA_4K    ; 数据段
Desc_End   :

; ----------------------------------------------------------------------------------------
; GDTPtr
GDTPtr  dw Desc_End - Desc_Begin - 1            ; 界限
        dd SEGMENTOFLOADER * 0x10 + Desc_Begin  ; 基址

; ----------------------------------------------------------------------------------------
; 选择子
SelectorCode    equ Desc_Code  - Desc_Begin
SelectorData    equ Desc_Data  - Desc_Begin
; ****************************************************************************************


; ========================================================================================
[SECTION .code16]
[BITS 16]
; 实模式代码段:取得内存容量、复制 kernel 到内存、设定画面模式、开启保护模式
; ----------------------------------------------------------------------------------------
RMode_main:
    ; 初始化寄存器
    mov ax, cs
    mov ds, ax
    mov ss, ax
    mov ax, STACKSIZE
    mov bp, ax
    mov sp, ax

    ; 获取内存信息
    ; BIOS 中断 int 0x15
    ; 入口参数:eax = 0xE820 功能号
    ;           ebx = ARDS 所需的后续值,第一个为 0
    ;           es : di = 内存缓冲区基址,指向一个地址范围描述符结构(ARDS)
    ;           ecx = ARDS 的大小,通常 BIOS 总是填充 20 字节的信息到 ARDS 中
    ;           edx = “SMAP” 的 ASCII 码(0x0534D4150)
    ; 出口参数:CF 置 1 表明调用出错,否则无错
    ;           eax = "SMAP" 的 ASCII 码
    ;           ebx = 下一 ARDS 所需的后续值,如果为 0 则说明已到最后一个 ARDS。
    push SEGMENTOFGPARAM
    pop fs
    xor ebx, ebx
    mov di, tArds
.MemChkLoop:
    mov eax, 0xE820
    mov ecx, T_AddrRngDscStruc_size
    mov edx, 0x534D4150
    int 15h
    jnc .MemChkOK
    mov si, strCheckMemoryFail
    call PrintStr
    jmp $
.MemChkOK:
    mov eax, [tArds + T_AddrRngDscStruc.dwLengthLow]    ; 累加内存总容量
    add [fs : T_Global_Param.dwMemorySize], eax
    cmp ebx, 0
    jne .MemChkLoop


    ; 复制 Kernel 到内存
    mov si, FileNameOfKernel                ; 寻找
    call SearchFile
    cmp ax, 0
    jnz .LoadKernel
    mov si, strNotFoundFile
    call PrintStr
    mov si, FileNameOfKernel
    call PrintStr
    jmp $
.LoadKernel:
    push SEGMENTOFKERNEL                    ; 复制
    pop es
    xor bx, bx
    call LoadFile


    ; 复制字库到内存
    mov si, FileNameOfFont
    call SearchFile
    cmp ax, 0
    jnz .LoadFont
    mov si, strNotFoundFile
    call PrintStr
    mov si, FileNameOfFont
    call PrintStr
    jmp $
.LoadFont:
    push SEGMENTOFFONT
    pop es
    xor bx, bx
    call LoadFile


   ; 设置图形模式
    push SEGMENTOFTEMP                    ; 取得 VBE 信息
    pop es
    xor di, di
    mov ax, 0x4F00
    int 0x10
    mov di, 0x200
    mov ax, 0x4F01                          ; 取得 800*600*16 模式信息
    mov cx, 0x114
    int 0x10
    cmp ax, 0x004F
    jz .Support
    mov si, strNotSupportVESA
    call PrintStr
    jmp $
.Support:
    mov ax, 0x4F02                          ; 设置画面模式
    mov bx, 0x4114                          ; 800 * 600,16 位色,线性帧缓冲区
    int 0x10

    ; 保存显存相关信息到全局变量
    mov eax, [es : 0x200 + 0x28]
    mov [fs : T_Global_Param.dwPhyAddrOfVideo], eax
    mov ax, [es : 0x200 + 0x12]
    mov [fs : T_Global_Param.wScreenX], ax
    mov ax, [es : 0x200 + 0x14]
    mov [fs : T_Global_Param.wScreenY], ax
    mov al, [es : 0x200 + 0x19]
    mov [fs : T_Global_Param.bBitsPerPixel], al


    ; 开启保护模式
    lgdt [GDTPtr]                           ; 加载 GDT
    in al, 0x92                             ; 打开地址线 A20
    or al, 0b10
    out 0x92, al
    mov eax, cr0                            ; 置保护模式标志位
    or eax, 1
    mov cr0, eax
    jmp dword SelectorCode : (SEGMENTOFLOADER * 0x10 + PMode_main)  ; 跳转至保护模式代码段

; ----------------------------------------------------------------------------------------
; 包含 FAT12 子函数
    IncludeFAT12Function SEGMENTOFTEMP
; ****************************************************************************************


; ========================================================================================
[SECTION .code32]
[BITS 32]
; 保护模式代码段,由实模式跳入:重定位 kernel,跳转到 kernel
; ----------------------------------------------------------------------------------------
PMode_main:
    ; 初始化寄存器
    mov ax, SelectorData
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, SEGMENTOFLOADER * 0x10 + STACKSIZE
    mov ebp, eax
    mov esp, eax


    ; 装载 kernel 各段(重定位)
    xor ecx, ecx
    mov cx, [SEGMENTOFKERNEL * 0x10 + Tag_ELF_Header.e_phnum]   ; 段数
    mov esi, [SEGMENTOFKERNEL * 0x10 + Tag_ELF_Header.e_phoff]  ; 指向程序头表
    add esi, SEGMENTOFKERNEL * 0x10
.Load:
    mov eax, [esi + Tag_Program_Header.p_type]                  ; 只装载可装载段
    cmp eax, PT_LOAD
    jnz .NotNeedLoad
    push dword[esi + Tag_Program_Header.p_filesz]
    mov eax, [esi + Tag_Program_Header.p_offset]
    add eax, SEGMENTOFKERNEL * 0x10
    push eax
    push dword[esi + Tag_Program_Header.p_vaddr]
    call memcpy
    add esp, 3 * 4
.NotNeedLoad:
    add esi, Tag_ELF_Header.e_phentsize
    loop .Load


    ; 跳转至 kernel(修改 cs 和 eip)
    jmp SelectorCode : KERNELENTRYPHYADDR


; ----------------------------------------------------------------------------------------
; 函数功能:内存复制
; void memcpy(void *pDest, void *pSrc, DWORD dwSize);
; 入口参数:es : pDest = 目标内存地址
;           ds : pSrc  = 源内存地址
;           dwSize     = 数据长度(字节)
; 出口参数:无
memcpy:
    push ebp
    mov ebp, esp

    push esi
    push edi
    push ecx

    mov edi, [ebp + 2 * 4]                  ; pDest
    mov esi, [ebp + 3 * 4]                  ; pSrc
    mov ecx, [ebp + 4 * 4]                  ; dwSize
    jecxz .Return

.Copy:
    lodsb
    stosb
    loop .Copy

.Return:
    pop ecx
    pop edi
    pop esi

    mov esp, ebp
    pop ebp
    ret
; ****************************************************************************************

    显示文字其实也是画图,把显示文字的函数也放到 graphics.c 里,只是头文件单列出来

/*  graphics.c
    图形相关全局变量及函数
	函数被分配到两个头文件:graphics.h(绘图)、io.h(文字)
    四彩
    2015-12-12
*/

#include "../lib/include/stddef.h"
#include "../lib/include/string.h"
#include "../kernel/include/graphics.h"
#include "../kernel/include/io.h"


// =======================================================================================
// 全局参数
// ---------------------------------------------------------------------------------------
// 图形函数相关全局参数
static unsigned short *pVideo, Color = 0;           // 显存地址和当前颜色
static unsigned short Screen_X, Screen_Y;           // 屏幕分辨率
static unsigned char BytePerPix;                    // 每个像素占用的位数

// ---------------------------------------------------------------------------------------
// 文字函数相关全局参数
static unsigned char *pFont;                        // 点阵字库的物理内存地址
static unsigned char WidthPerChar, HeightPerChar;   // 每个字符的宽度和高度
// ***************************************************************************************


// =======================================================================================
// 函数
// ---------------------------------------------------------------------------------------
// 图形部分
/*  画一条线
*/
void line(unsigned x0, unsigned y0, unsigned x1, unsigned y1)
{
    int x, y;

    if(x0 == x1)
        for(y = y0; y <= y1; y++)
            pVideo[Screen_X * y + x] = Color;
    else if(x0 < x1)
        for(x = x0; x <= x1; x++)
        {
            y = ((x - x0) * y1 + (x1 - x) * y0) / (x1 - x0);
            pVideo[Screen_X * y + x] = Color;
        }
    else // if(x0 > x1)
        for(x = x1; x <= x0; x++)
        {
            y = ((x0 - x) * y1 + (x - x1) * y0) / (x0 - x1);
            pVideo[Screen_X * y + x] = Color;
        }
}

/*  画一个方框并填色
*/
void rectangle(unsigned x0, unsigned y0, unsigned x1, unsigned y1)
{
    unsigned x, y;
    for(y = y0; y <= y1; y++)
        for(x = x0; x <= x1; x++)
            pVideo[Screen_X * y + x] = Color;
}


// ---------------------------------------------------------------------------------------
// 文字部分
/*  函数功能:显示一个字符
    参数表:x, y = 屏幕起始坐标
            ch  = 字符
    返回值:无
*/
void putc(unsigned x, unsigned y, char ch)
{
    int i, j, k;

    k = HeightPerChar * ch;
    for(i = 0; i < HeightPerChar; i++)
        for(j = 0; j < WidthPerChar; j++)
            if(pFont[k + i] & (1 << (7 - j)))
                pVideo[Screen_X * (y + i) + x + j] = Color;
}

/*  函数功能:显示字符串
    参数表:x, y = 屏幕起始坐标
            str = 字符串
    返回值:无
*/
void puts(unsigned x, unsigned y, char *str)
{
    int i, j, k;

    while(*str != NUL)
    {
        k = HeightPerChar * (*str);
        for(i = 0; i < HeightPerChar; i++)
            for(j = 0; j < WidthPerChar; j++)
                if(pFont[k + i] & (1 << (7 - j)))
                    pVideo[Screen_X * (y + i) + x + j] = Color;
        str++;
        x += WidthPerChar;
    }
}

// ---------------------------------------------------------------------------------------
// 设置参数部分
/*	初始化图形参数
*/
void InitGraphics(GRAPHICS_PARAM *ptGraphics)
{
    pVideo     = (unsigned short *)ptGraphics->dwPhyAddrOfVideo;
    Screen_X   = ptGraphics->wScreenX;
    Screen_Y   = ptGraphics->wScreenY;
    BytePerPix = ptGraphics->bBitsPerPixel;
}

/*	设置颜色
*/
void SetColor(unsigned color)
{
    Color = color;
}

/*  函数功能:设置字体
    参数表:addr   = 点阵字库的物理内存地址
           width  = 点阵字的宽度(像素)
           height = 点阵字的高度(像素)
    返回值:无
*/
void SetFont(unsigned addr, unsigned char width, unsigned char height)
{
    pFont         = (unsigned char *)addr;
    WidthPerChar  = width;
    HeightPerChar = height;
}

// ---------------------------------------------------------------------------------------
// 输出当前参数部分
unsigned GetScreenX()
{
    return Screen_X;
}

unsigned GetScreenY()
{
    return Screen_Y;
}

// ***************************************************************************************
/*	io.h
	输入输出函数,输出部分的实现在 graphics.c 内
	四彩
	2015-12-12
*/

#ifndef _IO_H
#define _IO_H


/*  函数功能:显示一个字符
    参数表:x, y = 屏幕起始坐标
            ch   = 字符
    返回值:无
*/
void putc(unsigned x, unsigned y, char ch);


/*	函数功能:显示字符串
	参数表:x, y = 屏幕起始坐标
			str  = 字符串
	返回值:无
*/
void puts(unsigned x, unsigned y, char *str);


/*  函数功能:设置字体
    参数表:addr   = 点阵字库的物理内存地址
           width  = 点阵字的宽度(像素)
           height = 点阵字的高度(像素)
    返回值:无
*/
void SetFont(unsigned addr, unsigned char width, unsigned char height);


#endif

   用到几个处理字符串的函数,自己实现就行 —— C语言干这个手到擒来。顺手把可能会用到的都实现了

/*  string.h
    字符串处理函数
    四彩
    2015-12-12
*/


#ifndef _STRING_H
#define _STRING_H


/*  函数功能:内存复制
    参数表:pDst  = 目标内存地址
           pSrc  = 源内存地址
           nSzie = 要复制的长度(字节单位)
    返回值:指向目标内存地址的指针
*/
void *memcpy(void *pDst, const void *pSrc, unsigned int nSzie);

/*  函数功能:取字符串长度
    参数表:pStr = 字符串地址
    返回值:字符串长度
*/
unsigned strlen(const char *pStr);

/*  函数功能:字符串比较
    参数表:pStr1 = 字符串 1 地址
           pStr2 = 字符串 2 地址
    返回值:当 pStr1 < pStr2 时,返回为负数
           当 pStr1 = pStr2 时,返回值 0
           当 pStr1 > pStr2 时,返回正数
*/
int strcmp(const char *pStr1, const char *pStr2);

/*  函数功能:复制字符串
    参数表:pDst  = 目标字符串地址
           pSrc  = 源字符串地址
    返回值:指向目标字符串的指针
*/
char *strcpy(char *pDst, const char *pSrc);

/*  函数功能:合并字符串
    参数表:pDst  = 目标字符串地址
           pSrc  = 源字符串地址
    返回值:指向目标字符串的指针
*/
char *strcat(char *pDst, const char *pSrc);

/*  函数功能:反转字符串
    参数表:string = 字符串的地址
    返回值:指向字符串的指针
*/
char *strrev(char *string);

/*  函数功能:将整数转换为字符串
    参数表:value  = 欲转换的数据
           string = 目标字符串的地址
           radix  = 转换后的进制数
    返回值:指向字符串的指针
*/
char *itoa(int value, char *string, int radix);

/*  函数功能:将无符号整数转换为字符串
    参数表:value  = 欲转换的数据
           string = 目标字符串的地址
           radix  = 转换后的进制数
    返回值:指向字符串的指针
*/
char *utoa(unsigned value, char *string, int radix);


#endif
/*  string.c
    字符串处理函数
    四彩
    2015-12-12
*/


#include "../lib/include/string.h"
#include "../lib/include/stddef.h"


/*  函数功能:内存复制
    参数表:pDst  = 目标内存地址
            pSrc  = 源内存地址
            nSzie = 要复制的长度(字节单位)
    返回值:指向目标内存地址的指针
*/
void *memcpy(void *pDst, const void *pSrc, unsigned nSzie)
{
    // 不清楚来源结构,只能逐字节复制
    unsigned char *p1 = (unsigned char *)pDst;
    unsigned char *p2 = (unsigned char *)pSrc;

    // 若目标内存与源内存完全一致,则无需复制
    if(p1 == p2 || NULL == p1 || NULL == p2)
        return(pDst);
    // 若目标内存与源内存无重叠,或目标内存尾部与源内存头部重叠,则顺序复制
    else if(p1 >= (p2 + nSzie) || p1 < p2)
        while(nSzie--)
            *p1++ = *p2++;
    // 若目标内存头部与源内存尾部重叠,则逆序复制
    else // if(p1 > p2 && p1 < (p2 + nSzie))
    {

        p1 += nSzie - 1;
        p2 += nSzie - 1;

        while(nSzie--)
            *p1-- = *p2--;
    }

    return pDst;
}

/*  函数功能:取字符串长度
    参数表:pStr = 字符串地址
    返回值:字符串长度
*/
unsigned strlen(const char *pStr)
{
    unsigned len = 0;

    if(NULL == pStr)
        return 0;

    while(NUL != *pStr)
    {
        pStr++;
        len++;
    }

    return len;
}

/*  函数功能:字符串比较
    参数表:pStr1 = 字符串 1 地址
            pStr2 = 字符串 2 地址
    返回值:当 pStr1 < pStr2 时,返回为负数
            当 pStr1 = pStr2 时,返回值 0
            当 pStr1 > pStr2 时,返回正数
*/
int strcmp(const char *pStr1, const char *pStr2)
{
    // 转无符号,进行 ASCII 编码比较
    unsigned char *s1 = (unsigned char *)pStr1, *s2 = (unsigned char *)pStr2;

    if(pStr1 == pStr2)              // 包含了两个都是空指针的情况
        return 0;
    else if(NULL == pStr1 && NULL != pStr2)
        return -1;
    else if(NULL != pStr1 && NULL == pStr2)
        return 1;

    for(; *s1 == *s2; ++s1, ++s2)
        if(NUL == *s1)
            return 0;

    return(*s1 < *s2 ? -1 : 1);
}

/*  函数功能:复制字符串
    参数表:pDst  = 目标字符串地址
            pSrc  = 源字符串地址
    返回值:指向目标字符串的指针
*/
char *strcpy(char *pDst, const char *pSrc)
{
    char *p1 = pDst;

    if(NULL == pDst || NULL == pSrc)
        return pDst;

    while(NUL != (*p1++ = *pSrc++));

    return pDst;
}


/*  函数功能:合并字符串
    参数表:pDst  = 目标字符串地址
            pSrc  = 源字符串地址
    返回值:指向目标字符串的指针
*/
char *strcat(char *pDst, const char *pSrc)
{
    char *p1 = pDst;

    if(NULL == pDst || NULL == pSrc)
        return pDst;

    while(NUL != *p1)
        p1++;
    while(NUL != (*p1++ = *pSrc++));

    return pDst;
}

/*  函数功能:反转字符串
    参数表:string = 字符串地址
    返回值:指向字符串的指针
*/
char *strrev(char *string)
{
    char ch, *p1, *p2;

    // p1 指向 string 的头部
    if(NULL == (p1 = p2 = string))
        return NULL;

    // p2 指向 string 的尾部
    while(*p2)
        ++p2;
    p2--;

    // 头尾交换反转
    while(p2 > p1)
    {
        ch = *p1;
        *p1++ = *p2;
        *p2-- = ch;
    }

    return string;
}

/*  函数功能:将整数转换为字符串
    参数表:value  = 欲转换的数据
            string = 目标字符串的地址
            radix  = 转换后的进制数
    返回值:指向字符串的指针
*/
char *itoa(int value, char *string, int radix)
{
    int i = 0, neg;
    char ch;

    if(NULL == string)
        return NULL;

    // 记录正负符号,并转为正数处理
    if((neg = value) < 0)
        value = -value;

    // 从数字变为 ASCII 码
    do
    {
        ch = value % radix;
        if(ch < 10)
            string[i++] = ch + '0';
        else
            string[i++] = ch - 10 + 'A';
    } while((value /= radix) > 0);

    // 正负符号
    if(neg < 0)
        string[i++] = '-';

    // 字符串以 0 结尾。
    string[i] = NUL;

    // 反转(生成的时候是从个位开始的,是逆序的)
    return(strrev(string));
}

/*  函数功能:将无符号整数转换为字符串
    参数表:value  = 欲转换的数据
            string = 目标字符串的地址
            radix  = 转换后的进制数
    返回值:指向字符串的指针
*/
char *utoa(unsigned value, char *string, int radix)
{
    int i = 0, neg;
    char ch;

    if(NULL == string)
        return NULL;

    // 从数字变为 ASCII 码
    do
    {
        ch = value % radix;
        if(ch < 10)
            string[i++] = ch + '0';
        else
            string[i++] = ch - 10 + 'A';
    } while((value /= radix) > 0);

    // 进制符
    if(16 == radix)
    {
        string[i++] = 'x';
        string[i++] = '0';
    }
    else if(8 == radix)
    {
        string[i++] = '0';
    }
    else if(2 == radix)
    {
        string[i++] = 'b';
        string[i++] = '0';
    }
    // 字符串以 0 结尾。
    string[i] = NUL;

    // 反转(生成的时候是从个位开始的,是逆序的)
    return(strrev(string));
}

    stddef.h 这个文件就是定义了 NUL 和 NULL:

// 常量
// —— 空指针 NULL
#ifndef NULL
    #define NULL    ((void *)0)
#endif
// —— 字符串结尾符 NUL
#ifndef NUL
    #define NUL     '\0'
#endif

    kernel 里可以显示字符了,把几个参数显示出来先:

/*  kernel.c
    内核
    whoozit
    2012-12-12
*/

#include "../lib/include/stddef.h"
#include "../lib/include/string.h"
#include "../kernel/include/PMode.h"
#include "../kernel/include/graphics.h"
#include "../kernel/include/io.h"


// 全局变量结构
typedef struct tag_Global_param
{
    unsigned int    dwMemorySize;
    GRAPHICS_PARAM  tGraphics;
} GLOBAL_PARAM;


// 存放全局变量的物理地址(const.inc 中的 SEGMENTOFGPARAM * 0x10)
#define PHYADDROFGPARAM     0x500
// 存放点阵字库的物理地址(const.inc 中的 SEGMENTOFFONT * 0x10)
#define PHYADDROFFONT       0x10000
// GDT 表存放的物理内存地址(就接在全局变量后面吧)
#define PHYADDROFGDT        (PHYADDROFGPARAM + sizeof(GLOBAL_PARAM))


// 引用汇编指令函数
extern void asm_hlt();


void c_main()
{
    unsigned i, j;
    unsigned short Screen_X, Screen_Y;
    char string[80], number[33];
    GLOBAL_PARAM g_Param;

    // 初始化 GDT 表
    InitGdt(PHYADDROFGDT);

    // 取全局变量
    memcpy((void *)&g_Param, (void *)(PHYADDROFGPARAM), sizeof(GLOBAL_PARAM));

    // 初始化图形参数
    InitGraphics(&(g_Param.tGraphics));
    Screen_X = GetScreenX();
    Screen_Y = GetScreenY();

    // 画界面
    SetColor(COLOR16_DEEPSKYBLUE);
    rectangle(0,             0,             Screen_X - 1,  Screen_Y - 1);

    SetColor(COLOR16_LIGHTGRAY);
    rectangle(0,             Screen_Y - 28, Screen_X - 1,  Screen_Y - 28);
    rectangle(0,             Screen_Y - 26, Screen_X - 1,  Screen_Y - 1);

    SetColor(COLOR16_WHITE);
    rectangle(0,             Screen_Y - 27, Screen_X - 1,  Screen_Y - 27);
    rectangle(3,             Screen_Y - 24, 59,            Screen_Y - 24);
    rectangle(2,             Screen_Y - 24, 2,             Screen_Y - 4);
    rectangle(2,             Screen_Y - 3,  59,            Screen_Y - 3);
    rectangle(60,            Screen_Y - 24, 60,            Screen_Y - 3);
    rectangle(Screen_X - 47, Screen_Y - 3,  Screen_X - 4,  Screen_Y - 3);
    rectangle(Screen_X - 3,  Screen_Y - 24, Screen_X - 3,  Screen_Y - 3);

    SetColor(COLOR16_DARKGRAY);
    rectangle(3,             Screen_Y - 4,  59,            Screen_Y - 4);
    rectangle(59,            Screen_Y - 23, 59,            Screen_Y - 5);
    rectangle(Screen_X - 47, Screen_Y - 24, Screen_X - 4,  Screen_Y - 24);
    rectangle(Screen_X - 47, Screen_Y - 23, Screen_X - 47, Screen_Y - 4);

    // 设置点阵字库
    SetFont(PHYADDROFFONT, 8, 16);

    SetColor(COLOR16_LIGHTVIOLET);
    puts(10, Screen_Y - 20, "BEGIN");

    SetColor(COLOR16_YELLOW);
    putc(Screen_X - 40, Screen_Y - 20, 'O');
    putc(Screen_X - 30, Screen_Y - 20, 'K');

    // 显示变量
    SetColor(COLOR16_BLACK);

    strcpy(string, "Memory = ");
    strcat(string, utoa(g_Param.dwMemorySize, number, 10));
    puts(10, 10, string);

    strcpy(string, "PhyAddrOfVideo = ");
    strcat(string, utoa(g_Param.tGraphics.dwPhyAddrOfVideo, number, 16));
    puts(10, 30, string);

    strcpy(string, "Screen_X = ");
    strcat(string, utoa(Screen_X, number, 10));
    puts(10, 50, string);

    strcpy(string, "Screen_Y = ");
    strcat(string, utoa(Screen_Y, number, 10));
    puts(10, 70, string);

    strcpy(string, "BitsPerPixel = ");
    strcat(string, utoa(g_Param.tGraphics.bBitsPerPixel, number, 10));
    puts(10, 90, string);

    while(1)
        asm_hlt();
}

    忙活了这么多天,总算看到字了,曙光啊,激动啊。。。。

十八、可以输出文字了_第1张图片





你可能感兴趣的:(十八、可以输出文字了)