MIT操作系统实验1-3

Part 3: The Kernel

Exercise 8.Use Bochs to trace into the JOS kernel, and identify the exact point at which the new virtual-to-physical mapping takes effect. Then examine the Global Descriptor Table (GDT) that the code uses to achieve this effect, and make sure you understand what's going on is the first instruction after this point that would fail to work properly if this virtual-to-physical mapping wasn't in place? Comment out or otherwise intentionally "break" the segmentation setup code in kern/entry.S, trace into it in Bochs, and see if you were right.

What

What is the first instruction after this point that would fail to work properly if this virtual-to-physical mapping wasn't in place? Comment out or otherwise intentionally "break" the segmentation setup code in kern/entry.S, trace into it in Bochs, and see if you were right.   

bootloader在加载自己初始化数据的时候定义了一个GDT表,这个表的结构如下:
# Bootstrap GDT
.p2align 2                                # force 4 byte alignment
gdt:
  SEG_NULL				# null seg
  SEG(STA_X|STA_R, 0x0, 0xffffffff)	# code seg
  SEG(STA_W, 0x0, 0xffffffff)	        # data seg

gdtdesc:
  .word   0x17                            # sizeof(gdt) - 1
  .long   gdt                             # address gdt
在这里,gdt表项中的每一项的基址都是0,也就是说现在的物理地址和线性地址的值实际上是一样的。
在加载内核后,entry.S中重新定义了GDT表。其主要部分如下:
###################################################################
# setup the GDT	
###################################################################
	.p2align	2		# force 4 byte alignment
mygdt:
	SEG_NULL				# null seg
	SEG(STA_X|STA_R, -KERNBASE, 0xffffffff)	# code seg
	SEG(STA_W, -KERNBASE, 0xffffffff)	# data seg
mygdtdesc:
	.word	0x17			# sizeof(mygdt) - 1
	.long	RELOC(mygdt)		# address mygdt


在这里,我们的基址不再是0,而是-KERNBASE, 而-KERNBASE的值为-0xf0000000。
所以当我们使用objdump查看程序的入口地址时:

oslab@oslab:~/lab1/obj/kern$ objdump -f kernel
 
kernel:     file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0xf010000c    .word   0x17            # sizeof(mygdt) - 1
    .long   RELOC(mygdt)        # address mygdt
 
 
 
 
 
 
 
 
得到的物理地址是0xf010000c,而实际对应的物理地址应该是0x0010000c。

 

2.1  Formatted Printing to the Console

Exercise 9.We have omitted a small fragment of code - the code necessary to print octal numbers using patterns of the form "%o". Find and fill in this code fragment.

 

 

 

使用八进制打印,这个比较简单。修改printfmt.c中的vprintfmt函数:

		case 'o':
			// Replace this with your code.
			//putch('X', putdat);
			//putch('X', putdat);
			//putch('X', putdat);
			num = getuint(&ap, lflag);
			base = 8;
			//break;
			goto number;

Challenge! Enhance the console to allow text to be printed in different colors. The traditional way to do this would be to make it interpret ANSI escape sequences embedded in the text strings printed to the console, but you may use any mechanism you like. There is plenty of information on the 6.828 reference page and elsewhere on the web on programming the VGA display hardware. If you're feeling really adventurous, you could try switching the VGA hardware into a graphics mode and making the console draw text onto the graphical frame buffer.

//printfmt.c, hky added
#define FORE_BLACK 		(0)
#define FORE_RED    	    (4 << 8)
#define FORE_GREEN 		(2 << 8)
#define FORE_BLUE  		(1 << 8)
#define FORE_WHITE 		((4+2+1) << 8)
#define BACK_BLACK 		(0)
#define BACK_RED   		(4 << 12)
#define BACK_GREEN 		(2 << 12)
#define BACK_BLUE 		(1 << 12)
#define BACK_WHITE 		((4+2+1) << 12)

int get_color(int fore_back, char type)
{
	int color = 0;

	if (fore_back == 1) //foreground
	{
		switch (type)
		{
			case 'R':
				color = FORE_RED;
				break;
			case 'G':
				color = FORE_GREEN;
				break;
			case 'B':
				color = FORE_BLUE;
				break;
			case 'W':
				color = FORE_WHITE;
			case 'K':
				color = FORE_BLACK;
			default:
				break;
		}
	}
	else //background
	{
		switch (type)
		{
			case 'R':
				color = BACK_RED;
				break;
			case 'G':
				color = BACK_GREEN;
				break;
			case 'B':
				color = BACK_BLUE;
				break;
			case 'W':
				color = BACK_WHITE;
			case 'K':
				color = BACK_BLACK;
			default:
				break;
		}
	}
	return color;
}

修改vprintfmt:
while (1) {
…
		while ((ch = *(unsigned char *) fmt++) != '%') {
			if (ch == '\0')
				return;
			c_flag = 1;
			if (ch == '$') //foreground color
			{
				ch = *(unsigned char *)fmt++;
				color |= get_color(1, ch);
				c_flag = 0;
			}
			if (ch == '#') //background color
			{
				ch = *(unsigned char *)fmt++;
				color |= get_color(0, ch);
				c_flag = 0;
			}
			if (c_flag)
				putch(ch, putdat);
		}
…
}

Exercise 10.Determine where the kernel initializes its stack, and exactly where in memory its stack is located. How does the kernel reserve space for its stack? And at which "end" of this reserved area is the stack pointer initialized to point to?

 

 

 

 

在entry.S中有如下定义:
###################################################################
# boot stack
###################################################################
	.p2align	PGSHIFT		# force page alignment
	.globl		bootstack
bootstack:
	.space		KSTKSIZE
	.globl		bootstacktop   
bootstacktop:

Exercise 11.To become familiar with the C calling conventions on the x86, find the address of thetest_backtracefunction in obj/kern/kernel.asm, set a breakpoint there in Bochs, and examine what happens each time it gets called after the kernel starts. There are two ways you can set this breakpoint: with thebcommand and a physical address, or with thevbcommand, a segment selector (use 8 for the code segment), and a virtual address. How many 32-bit words does each recursive nesting level oftest_backtracepush on the stack, and what are those word


 

 

 

 

 

 

 

该练习主要是要了解函数调用的原理以及参数是如何压栈的。
stack top: +-------------------------------(low memory)
           +-----------last EBP------------(current SP)
           +------------EIP----------------(RET addr)
           +------------arg0---------------
           +------------arg1---------------
           +……----------------------------(high memory)


int
mon_backtrace(int argc, char **argv, struct Trapframe *tf)
{
	// Your code here.
	uint32_t m_ebp;
	uint32_t m_eip;
	uint32_t arg0, arg1, arg2, arg3, arg4;
	
	uint32_t *p_bp;
		
	m_ebp = read_ebp();
	
	while (m_ebp != 0)
	{
		p_bp = (uint32_t *)m_ebp;
		m_eip = *(p_bp + 1);
		arg0 = *(p_bp + 2);
		arg1 = *(p_bp + 3);
		arg2 = *(p_bp + 4);
		arg3 = *(p_bp + 5);
		arg4 = *(p_bp + 6);
		cprintf("ebp %08x eip %08x args %08x %08x %08x %08x %08x\n", 	  	       m_ebp, m_eip, arg0, arg1, arg2, arg3, arg4);
		m_ebp = *p_bp;
	}
		return 0;
}

你可能感兴趣的:(操作系统)