分段机制源码分析

Linux对段机制的应用效果是等价于几乎绕过了段基址。在Linux中仅有4个段,用户代码段、数据段和内核代码段、数据段。
这些段相应的选择器分别由以下宏定义:_USER_CS, __USER_DS, __KERNEL_CS, 和__KERNEL_DS。
举例来说,如果要定位内核代码段,内核只需要加载__KERNEK_CS宏的值到cs寄存器中。
我们先看进入保护模式的函数go_to_protected_mode:

    void go_to_protected_mode(void)
    {
        /* Hook before leaving real mode, also disables interrupts */
        realmode_switch_hook();

        /* Enable the A20 gate */
        if (enable_a20()) {
            puts("A20 gate not responding, unable to boot...\n");
            die();
        }

        /* Reset coprocessor (IGNNE#) */
        reset_coprocessor();

        /* Mask all interrupts in the PIC */
        mask_all_interrupts();

        /* Actual transition to protected mode... */
        setup_idt();
        setup_gdt();
        protected_mode_jump(boot_params.hdr.code32_start,
                 (u32)&boot_params + (ds() << 4));
    }

realmode_switch_hook()根据注释和函数命名可以知道这是在实模式切换前的钩子函数调用的地方;

static void realmode_switch_hook(void)
{
	if (boot_params.hdr.realmode_swtch) {
		asm volatile("lcallw *%0"
			     : : "m" (boot_params.hdr.realmode_swtch)
			     : "eax", "ebx", "ecx", "edx");
	} else {
		asm volatile("cli");
		outb(0x80, 0x70); /* Disable NMI */
		io_delay();
	}
}

enable_a20()就开启A20;
reset_coprocessor()是把协处理器重置一下

tatic void reset_coprocessor(void)
{
	outb(0, 0xf0);
	io_delay();
	outb(0, 0xf1);
	io_delay();
}

mask_all_interrupts()则是把中断关了,避免切换过程中出现状况。

static void mask_all_interrupts(void)
{
	outb(0xff, 0xa1);	/* Mask all interrupts on the secondary PIC */
	io_delay();
	outb(0xfb, 0x21);	/* Mask all but cascade on the primary PIC */
	io_delay();
}

其中setup_idt()setup_gdt()是重点,函数名字告诉我们这是设置idt和gdt的.

static void setup_idt(void)
{
	static const struct gdt_ptr null_idt = {0, 0};
	asm volatile("lidtl %0" : : "m" (null_idt));
}
static void setup_gdt(void)
{
	/* There are machines which are known to not boot with the GDT
	   being 8-byte unaligned.  Intel recommends 16 byte alignment. */
	static const u64 boot_gdt[] __attribute__((aligned(16))) = {
		/* CS: code, read/execute, 4 GB, base 0 */
		[GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff),
		/* DS: data, read/write, 4 GB, base 0 */
		[GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff),
		/* TSS: 32-bit tss, 104 bytes, base 4096 */
		/* We only have a TSS here to keep Intel VT happy;
		   we don't actually use it for anything. */
		[GDT_ENTRY_BOOT_TSS] = GDT_ENTRY(0x0089, 4096, 103),
	};
	/* Xen HVM incorrectly stores a pointer to the gdt_ptr, instead
	   of the gdt_ptr contents.  Thus, make it static so it will
	   stay in memory, at least long enough that we switch to the
	   proper kernel GDT. */
	static struct gdt_ptr gdt;

	gdt.len = sizeof(boot_gdt)-1;
	gdt.ptr = (u32)&boot_gdt + (ds() << 4);

	asm volatile("lgdtl %0" : : "m" (gdt));
}
SYM_FUNC_START_NOALIGN(protected_mode_jump)
	movl	%edx, %esi		# Pointer to boot_params table

	xorl	%ebx, %ebx
	movw	%cs, %bx
	shll	$4, %ebx
	addl	%ebx, 2f
	jmp	1f			# Short jump to serialize on 386/486
1:

	movw	$__BOOT_DS, %cx
	movw	$__BOOT_TSS, %di

	movl	%cr0, %edx
	orb	$X86_CR0_PE, %dl	# Protected mode
	movl	%edx, %cr0

	# Transition to 32-bit mode
	.byte	0x66, 0xea		# ljmpl opcode
2:	.long	.Lin_pm32		# offset
	.word	__BOOT_CS		# segment
SYM_FUNC_END(protected_mode_jump)

我们先看看GDT entry的结构图
在这里插入图片描述
GDT entry的结构如下

#define GDT_ENTRY(flags, base, limit)			\
	((((base)  & _AC(0xff000000,ULL)) << (56-24)) |	\
	 (((flags) & _AC(0x0000f0ff,ULL)) << 40) |	\
	 (((limit) & _AC(0x000f0000,ULL)) << (48-16)) |	\
	 (((base)  & _AC(0x00ffffff,ULL)) << 16) |	\
	 (((limit) & _AC(0x0000ffff,ULL))))

可以看出,base, limit和flag通过位移和或组成了GDT_ENTRY。其中flags代表了40-47位的access byte和52-55位的flags。

CS和DS的flags为0xc0,所以G=1,意味着4K为一个页面,B/D为1,1-32位段;
CS的Access Byte=0x9b,意味着P=1(合法的Entry Pr必须为1),DPL=0,S=1,这里该段只能在Ring 0下访问,该段是代码段
DS的Access Byte=0x93,意味着P=1(合法的Entry Pr必须为1),DPL=0,S=1,这里该段只能在Ring 0下访问,该段是数据段。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单片微型计算机(MCU)经过多年的发展,在性能上有很大的进步,在型号上发展到上千种类,已经广泛应用于人类社会生活的各个领域。单片机课程已经成为高校计算机、自动化、测控以及电子信息工程等专业的重要课程。该课程是一门理论性和实践性都很强的课程,在实际教学中,应将理论教学和实验教学紧密结合。学生在掌握理论知识之余,必须通过编写程序、设计硬件电路、仿真、调试这一系列的实验过程,才能更好地掌握单片机的结构原理和应用技能。随着单片机及其接口技术的飞速发展,目前市场上供应的编程仿真实验资源并不能完全满足高校单片机课程教与学的需求,构建低成本、技术先进、源码公开的单片机编程仿真实验系统,对我国单片机课程的教学和单片机领域人才的培养具有重要的现实意义。 本论文结合目前教学中对单片机编程仿真实验系统的实际需求,采用模块化结构设计思想,精心设计和开发了单片机编程仿真实验系统。该单片机编程仿真实验系统由PC机端单片机编程控制软件和单片机编程仿真实验板两部分组成。PC机端的单片机编程控制软件可以自动检测到连接到单片机编程仿真实验板上的单片机,控制单片机编程器擦除、写入、读出、校验目标单片机ROM中的程序,以十六进制文件(.HEX文件)格式显示在控制界面内;单片机仿真实验系统能够把写入单片机的程序实时地运行,并呈现实际运行效果。单片机编程控制软件和单片机仿真实验板组成一个完整的单片机编程仿真实验系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值