操作系统制作(3)gdt描述符 idt描述符格式转换

环境:
virtual-box:版本 6.0.10 r132072 (Qt5.6.2)运行的的ubuntu18.04系统。
nasm汇编器:NASM version 2.13.02

gdt:
	dq 0x0000000000000000		; GDT 表。第 1 个描述符不用。
	dq 0x00c09a00000007ff		; 第 2 个是内核代码段描述符。其选择符是 0x08。
	dq 0x00c09200000007ff		; 第 3 个是内核数据段描述符。其选择符是 0x10。
	dq 0x00c0920b80000002		; 第 4 个是显示内存段描述符。其选择符是 0x18。
	dw 0x68, tss0, 0xe900, 0x0	; 第 5 个是 TSS0 段的描述符。其选择符是 0x20
	dw 0x40, ldt0, 0xe200, 0x0	; 第 6 个是 LDT0 段的描述符。其选择符是 0x28
	dw 0x68, tss1, 0xe900, 0x0	; 第 7 个是 TSS1 段的描述符。其选择符是 0x30
	dw 0x40, ldt1, 0xe200, 0x0	; 第 8 个是 LDT1 段的描述符。其选择符是 0x38

; 下面是任务 0 的 LDT 表段中的局部段描述符。
align 8
ldt0:
	dq 0x0000000000000000		; 第 1 个描述符,不用。
	dq 0x00c0fa00000003ff		; 第 2 个局部代码段描述符,对应选择符是 0x0f。
	dq 0x00c0f200000003ff		; 第 3 个局部数据段描述符,对应选择符是 0x17。

由于像上图这样的描述符,第一眼很难看出对应的段基址和段限长,因此创建一个转换工具,方便描述符转换对应内容。
工具代码如下:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define GDT_SEG_LIMIT0_OFFSET	0
#define GDT_BASE_ADDR0_OFFSET	16
#define GDT_TYPE_OFFSET		40
#define GDT_S_OFFSET		44
#define GDT_DPL_OFFSET		45
#define GDT_P_OFFSET		47
#define GDT_SEG_LIMIT1_OFFSET	48
#define GDT_AVL_OFFSET		52
#define GDT_O_OFFSET		53
#define GDT_D_B_OFFSET		54
#define GDT_G_OFFSET		55
#define GDT_BASE_ADDR1_OFFSET	56

struct gdt_descriptor {
	uint16_t seg_limit0;
	uint32_t base_addr0;
	uint8_t type:4;
	uint8_t s:1;
	uint8_t dpl:2;
	uint8_t p:1;
	uint8_t seg_limit1:4;
	uint8_t avl:1;
	uint8_t o:1;
	uint8_t d_b:1;
	uint8_t g:1;
	uint8_t base_addr1;
};

extern void gdt_desc2layout(int64_t gdt_64);
extern void idt_desc2layout(int64_t idt_64);
extern void layout2gdt_desc(const struct gdt_descriptor gdt_in, int64_t *gdt_64);

static void usage(char **argv)
{
	printf("Usage0: %s gdt/idt word0(hex) word1(hex) word2(hex) word3(hex)\n", argv[0]);
	printf("\texample0: %s gdt/idt 0x07FF 0x0000 0x9A00 0x00C0\n", argv[0]);
	printf("Usage1: %s gdt/idt dq0\n", argv[0]);
	printf("\texample1: %s gdt/idt 0x00c09a00000007ff\n", argv[0]);
}

int main(int argc, char **argv)
{
	struct gdt_descriptor gdt_in;

	int8_t tmp[16];
	int16_t gdt[4];
	int64_t gdt_64;
	int16_t idt[4];
	int64_t idt_64;
	int i;

	if (strcmp(argv[1], "gdt") == 0) {
	        switch (argc) {
	        case 3:
	                gdt_64 = strtoull(argv[2], NULL, 16);
	                gdt_desc2layout(gdt_64);
	                break;
	        case 6:
			for (i = 0; i < 4; i++) {		
				gdt[i] = strtoul(argv[i + 2], NULL, 16);
				if (gdt[i] & ~0xffff) {
					printf("The number %s is over-ranging, it"
					       " must <= 0xffff\n", argv[i + 2]);
					return -EINVAL;
				}
				gdt_64 |= gdt[i] << (i * 16);
			}
	                gdt_desc2layout(gdt_64);
			break;
	        default:
			usage(argv);
	                break;
	        }
	}

	if (strcmp(argv[1], "idt") == 0) {
	        switch (argc) {
	        case 3:
	                idt_64 = strtoull(argv[2], NULL, 16);
	                idt_desc2layout(idt_64);
	                break;
	        case 6:
			for (i = 0; i < 4; i++) {		
				idt[i] = strtoul(argv[i + 2], NULL, 16);
				if (idt[i] & ~0xffff) {
					printf("The number %s is over-ranging, it"
					       " must <= 0xffff\n", argv[i + 2]);
					return -EINVAL;
				}
				idt_64 |= idt[i] << (i * 16);
			}
	                idt_desc2layout(idt_64);
			break;
	        default:
			usage(argv);
	                break;
	        }
	}	
        return 0;

}

void gdt_desc2layout(int64_t gdt_64)
{
	/* Base_addr */
        printf("Base_addr:%02lx", gdt_64 >> 58 & 0xff);
	printf("%02lx", gdt_64 >> 32 & 0xff);
	printf("%04lx ", gdt_64 >> 16 & 0xffff);
	/* Seg_limit */
        printf("Seg_limit:%01lx", gdt_64 >> 48 & 0xf);
	printf("%04lx ", gdt_64 & 0xffff);

        printf("DPL:%01lx ", gdt_64 >> 45 & 0x3);
        printf("TYPE:%01lx ", gdt_64 >> 40 & 0xf); 
        printf("AVL:%01lx ", gdt_64 >> 52 & 0x1);
        printf("O:%01lx ", gdt_64 >> 53 & 0x1);
        printf("D/B:%01lx ", gdt_64 >> 54 & 0x1);
        printf("G:%01lx ", gdt_64 >> 55 & 0x1);
        printf("P:%01lx ", gdt_64 >> 47 & 0x1);
        printf("S:%01lx ", gdt_64 >> 44 & 0x1);
        printf("\n");
}

/*
 * $ ./a.out 0x00c09a00000007ff
 * Base_addr:00000000 Seg_limit:007ff DPL:0 TYPE:a AVL:0 O:0 D/B:1 G:1 P:1 S:1 
 */
void layout2gdt_desc(const struct gdt_descriptor gdt_in, int64_t *gdt_64)
{
#if 0
	gdt_in.base_addr0 = 0;
	gdt_in.seg_limit0 = 0x07ff;
	gdt_in.base_addr0 = 0x07ff;
	gdt_in.type = 0xa;
	gdt_in.s = 1;
	gdt_in.dpl = 0;
	gdt_in.p = 1;
	gdt_in.seg_limit1 = 0;
	gdt_in.avl = 0;
	gdt_in.o = 0;
	gdt_in.d_b = 1;
	gdt_in.g = 1;
	gdt_in.base_addr1 = 0;
#endif
	uint64_t seg_limit0 = (uint64_t)(gdt_in.seg_limit0 & 0xffff) <<
			      GDT_SEG_LIMIT0_OFFSET;
	uint64_t base_addr0 = (uint64_t)(gdt_in.base_addr0 & 0xffffff) <<
			      GDT_BASE_ADDR0_OFFSET;
	uint64_t type = (uint64_t)(gdt_in.type & 0xf) << GDT_TYPE_OFFSET;
	uint64_t s = (uint64_t)(gdt_in.s & 0xf) << GDT_S_OFFSET;
	uint64_t dpl = (uint64_t)(gdt_in.dpl & 0x03) << GDT_DPL_OFFSET;
	uint64_t p = (uint64_t)(gdt_in.p & 0x01) << GDT_P_OFFSET;
	uint64_t seg_limit1 = (uint64_t)(gdt_in.seg_limit1 & 0xf00000) <<
			      GDT_SEG_LIMIT1_OFFSET;
	uint64_t avl = (uint64_t)(gdt_in.avl & 0xf00000) << GDT_AVL_OFFSET;
	uint64_t o = (uint64_t)(gdt_in.o & 0x01) << GDT_O_OFFSET;
	uint64_t d_b = (uint64_t)(gdt_in.d_b & 0x01) << GDT_D_B_OFFSET;
	uint64_t g = (uint64_t)(gdt_in.g & 0x01) << GDT_G_OFFSET;
	uint64_t base_addr1 = (uint64_t)(gdt_in.base_addr1 & 0xff) <<
			      GDT_BASE_ADDR1_OFFSET;

	*gdt_64 = seg_limit0 | base_addr0 | type | s | dpl | p | seg_limit1 |
		  avl | o | d_b | g | base_addr1;

	printf("0x%#16lx\n", *gdt_64);
}

void idt_desc2layout(int64_t idt_64)
{
	/* Entry_offset */
        printf("Entry_offset:%04lx", idt_64 >> 48 & 0xffff);
	printf("%04lx ", idt_64 & 0xffff);
	/* Seg_selector */
        printf("Seg_selector:%04lx ", idt_64 >> 16 & 0xffff);

        printf("TYPE:%01lx ", idt_64 >> 40 & 0xf); 

        printf("S:%01lx ", idt_64 >> 44 & 0x1);

        printf("DPL:%01lx ", idt_64 >> 45 & 0x3);

        printf("P:%01lx ", idt_64 >> 47 & 0x1);

        printf("\n");
}

效果如下:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章