haribote dsctbl.c 设置GDT和IDT程序阅读注释

Posted 资质平庸的程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了haribote dsctbl.c 设置GDT和IDT程序阅读注释相关的知识,希望对你有一定的参考价值。

[ 1] haribote ipl09.nas 引导程序阅读注释
[ 2] haribote asmhead.nas 从实模式进入保护模式程序阅读注释

篇幅较长,可通过浏览器的搜索功能(Ctrl + f)搜索函数名了解相应函数的实现机制,如 init_gdtidt。

[3] haribote设置GDT和IDT的程序阅读注释

dsctbl.c
/* dsctbl.c, 设置 GDT&&IDT 的程序接口 */

#include "bootpack.h"

/* 设置GDT和IDT后,内存空间分布大体如下。
 * 0x00000|-------------------------|
 *        |         ...             |
 * 100000h|=========================|
 *        |   floppy image(FAT12)   |
 * 267fffh|=========================|
 *        |          ...            |
 * 26f800h|=========================|
 *        |        IDT[256]         |
 * 270000h|=========================|
 *        |        GDT[8192]        |
 * 280000h|=========================|
 *        |   haribote os(C part)   |
 * 2fffffh|=========================|
 *        |  stack and global-data  |
 *        |  haribote os (C part)   |
 * 3fffffh|=========================|
 *        |          ....           | */

/* init_gdtidt,初始化GDT,IDT。
 *
 * 在asmhead.nas中为进入保护模式设置过GDT,
 * 此处重新设置后续程序会用到的GDT和IDT。*/
void init_gdtidt(void)

    /* haribote分别在
     * [ADR_GDT, ADR_GDT+LIMIT_GDT]和[ADR_IDT,ADR_IDT+LIMIT_IDT]内存段设置GDT和IDT。*/
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
    struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) ADR_IDT;
    int i;

    /* 先将GDT内存段初始化为0,保证了GDT[0]保留为0 */
    for (i = 0; i <= LIMIT_GDT / 8; i++) 
        set_segmdesc(gdt + i, 0, 0, 0);
    
    /* 设置haribote数据内存段和代码内存段GDT表项。
     *
     * GDT[1]描述内存地址空间[0x0, 0xffffffff]对应内存段,该内存段特权级为0即系统
     * 级,具 有效,可读写(即数据内存段)并使用ss:esp来维护栈内存等属性。
     * 
     * GDT[2]描述内存地址空间[ADR_BOTPAK,ADR_BOTPAK+LIMIT_BOTPAK](共64Kb)的内存段,
     * 该内存段的特权级为0(即系统级),具有效, 可读可执行(即代码内存段)并使用ss:esp
     * 维护栈内存等属性。GDT[2]所描述内存段刚好是haribote os C部分指令所在内存段。
     * 
     * 将GDT基址和限长信息加载给GDTR寄存器。*/
    set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);
    set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
    load_gdtr(LIMIT_GDT, ADR_GDT);

    /* 先将IDT初始化为0,将IDT基址和限长信息加载给IDTR寄存器 */
    for (i = 0; i <= LIMIT_IDT / 8; i++) 
        set_gatedesc(idt + i, 0, 0, 0);
    
    load_idtr(LIMIT_IDT, ADR_IDT);

   /* 在IDT中为以下中断设置中断处理入口程序,
     * IDT[0x00..0x10]是Intel规定保留用于设定特殊中断/异常入口处理程序的,
     * IDT[0x0c..0x0d]分别用于设定栈异常(如栈越界到数据段之外内存)和保护
     * 异常(如非法访问内存)的中断入口处理程序。
     * 
     * IDT[0x21..0x2f]在 int.c 中被设置为用来设定PIC各中断的中断入口处理
     * 程序;IDT[0x20]用于设定定时器中断入口处理程序; IDT[0x21]用于设定键
     * 盘中断入口处理程序;IDT[0x2c]用于设定鼠标中断处理程序。
     * 
     * IDT[0x40]用于设定haribote os api(系统调用)的入口处理程序,即通过指
     * 令int 0x40进入内核调用指定函数。
     *
     * 各中断处理入口程序定义在naskfunc.nas中。
     * 2*8为GDT段描述符GDT[2]的选择符,即各中断处理函数都在操作系统所在内
     * 存段。
     * 
     * AR_INTGATE32 用作设定IDT描述符有效且存在(P=1),特权级DPL=0(系统级),
     * IDT描述符类型为中断门描述符等属性。
     * AR_INTGATE32 +0x60:用作设定IDT描述符存在(P=1),特权级DPL=3(用户级),
     * IDT类型为中断门描述符等属性。
     * 
     * IDT[0x40]中的特权级(DPL)设置为3是因为用户程序会通过int 40h进行系统
     * 调用,通过int指令引用IDT描述符时CPU会检查CPL <= IDT.DPL的条件是否成
     * 立,只有该条件成立时CPU才会引用该IDT描述符。用户程序当前特权级CPL为
     * 3,所以用于设定系统调用的IDT[0x40]的特权级需为3。另外,通过IDT访问GDT
     * 所描述内存段时,CPL >= GDT.DPL时也可访问。*/
    set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x40, (int) asm_hrb_api,      2 * 8, AR_INTGATE32 + 0x60);

    return;


/* set_segmdesc,
 * 设置sd指向的GDT段描述符,
 * sd,GDT段描述符内存首地址;limit,段描述符所描述内存段基于段基址最大偏移;
 * base,段描述符所描述内存段基址;ar,段描述符特权级,类型等属性。*/
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)

    /* 如果内存段超过1Mb,则置位GDT段描述符
     * 内存颗粒度位G(bit[55])。GDT段描述符
     * G位置位后,CPU将以4Kb为单位计算该GDT
     * 段描述符所描述内存段长度。*/
    if (limit > 0xfffff) 
        ar |= 0x8000; /* G_bit = 1 */
        limit /= 0x1000; /* 单位换算为4Kb */
    
    /* 根据GDT段描述符位格式,通过GDT段描述符结构体设置GDT描述符。
     *
     * bit[15..0],内存段长度低16位;
     * bit[31..16],内存段基址低16位;
     * bit[39..32],内存段基址23..16位;
     * bit[47..40],有效位P,特权级DPL,类型TYPE等;
     * bit[55..48],内存颗粒度,内存段长度19..16位;
     * bit[63..56],内存段基址高8位。*/
    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;


/* set_gatedesc,
 * 设置gd指向的IDT描述符,
 * gd,IDT描述符内存首地址;offset,处理程序在其所在段的偏移地址;
 * selector,处理程序所在内存段的段选择符;ar,IDT描述符有效位,特权级,类型等属性。*/
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)

    /* 根据IDT段描述符位格式,通过IDT描述符结构体设置IDT描述符。
     * 
     * bit[15..0],处理程序偏移地址低16位;
     * bit[31..16],处理程序所在内存段的段选择符;
     * bit[39..32],保留未用;
     * bit[47..40],有效位P,特权级DPL,类型TYPE等;
     * bit[63..48],处理程序偏移地址高16位。*/
    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.h
/* ... */

/* dsctbl.c */
/* struct SEGMENT_DESCRIPTOR,
 * 描述GDT段描述符的结构体类型。
 * GDT段描述符位格式参见x86CPU手册。*/
struct SEGMENT_DESCRIPTOR 
/* limit_high&&limit_low,
 * 所描述内存段基于其基址的最大偏移(内存段长度);
 * base_high&&base_mid&&base_low,所描述内存段的基址;
 * access_right,段描述符有效位,特权级(DPL),类型(TYPE)等属性。*/
    short limit_low, base_low;
    char base_mid, access_right;
    char limit_high, base_high;
;
/* struct GATE_DESCRIPTOR,
 * 描述IDT描述符的结构体类型。
 * IDT描述符位格式参见x86CPU手册。*/
struct GATE_DESCRIPTOR 
/* offset_high&&offset_low,
 * 中断或异常处理程序在其所在内存段中的偏移;
 * selector,处理程序所在内存段的段选择符;
 * dw_count,保留未用;
 * access_right,IDT描述符有效位,特权级(DPL),类型(TYPE)等属性。*/
    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  /* IDT内存段基址 */
#define LIMIT_IDT       0x000007ff  /* IDT限长 */
#define ADR_GDT         0x00270000  /* GDT内存段基址 */
#define LIMIT_GDT       0x0000ffff  /* GDT限长 */
#define ADR_BOTPAK      0x00280000  /* haribote os C部分内存地址起始地址, 见asmhead.nas */
#define LIMIT_BOTPAK    0x0007ffff  /* haribote os C部分大小, 64Kb */
#define AR_DATA32_RW    0x4092  /* 用于设定GDT段描述符所描述内存段为可读写数据内存段,DPL=0 */
#define AR_CODE32_ER    0x409a  /* 用于设定GDT段描述符所描述内存段为可读可执行内存段,DPL=0 */
#define AR_LDT          0x0082  /* 用于表征GDT段描述符所描述内存段为LDT */
#define AR_TSS32        0x0089  /* 用于表征GDT段描述符所描述内存段为TSS */
#define AR_INTGATE32    0x008e  /* 用于设定IDT描述符为中断门描述符,DPL=0 */

/* ... */

以上是关于haribote dsctbl.c 设置GDT和IDT程序阅读注释的主要内容,如果未能解决你的问题,请参考以下文章

haribote file.c 文件读取程序阅读注释

haribote系统调用 工程管理及应用程序阅读注释

haribote bootpack.c 主任务程序代码阅读注释

haribote naskfunc.nas 汇编函数接口程序阅读注释

haribote window.c 自制窗口画面信息程序阅读注释

haribote sheet.c 窗口画面及显示管理程序阅读注释