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 EF Fect. Then examine the Global descriptor Table (GDT) The code uses to achieve this effect, and make sure your understand WHA T ' s going on is the ' the ' the ' instruction ', ' would fail to work properly if this virtual-to-physical Mappin G wasn ' t in place? Comment out or otherwise intentionally ' break ' segmentation setup code in Kern/entry. S, trace into the IT in Bochs, and the If you are were right. |
What |
What is the ' the ' ' instruction ', ' would fail to work, if this properly virtual-to-physical mapping ' t In place? Comment out or otherwise intentionally ' break ' segmentation setup code in Kern/entry. S, trace into the IT in Bochs, and the If you are were right.
Bootloader defines a GDT table when it loads its own initialization data, and the table is structured as follows:
# 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
Here, each item in the GDT table entry has a base address of 0, which means that the current physical address and the value of the linear address are actually the same.
After loading the kernel, entry. The GDT table is redefined in S. The main parts are as follows:
###################################################################
# 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
Here, our base address is no longer 0, but-kernbase, and the-kernbase value is -0xf0000000.
So when we use Objdump to view the entry address of the program:
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 |
The resulting physical address is 0xf010000c, and the actual corresponding physical address should be 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. |
Using octal to print, this is easier. To modify the VPRINTFMT function in printfmt.c:
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 is printed in different colors. The traditional way to does this would is to make it interpret ANSI escape sequences embedded in the text strings printed to The console, but you could use any mechanism. There is plenty of information on the 6.828 reference page and elsewhere on the web on programming the VGA display Hardwar E. If you ' re feeling really adventurous, your could try switching the VGA hardware into a graphics mode and making the Cons OLE 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 <<) #define BACK_GREEN (2 <<) #define BACK_BLUE (1 <<) #define Back_white (4+2+1
<<) 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;
Modify Vprintfmt:while (1) {... while (ch = * (unsigned char *) fmt++)!= '% ') {if (ch = = ' ") 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. Determine where the kernel initializes its stack, and exactly where in memory it stack is located. How does the kernel reserve spaces for its stack? and at which ' end ' of this reserved area is the stack pointer initialized to point to? |
In entry. The definition in S is as follows:
###################################################################
# boot Stack
####################### ############################################
. P2align pgshift # force page Alignment
. Globl Bootstack
bootstack:
. Space kstksize
. Globl bootstacktop
bootstacktop:
Exercise. To become familiar with the "C calling conventions on the x86", find the address of thetest_backtracefunction in Obj/kern/ke Rnel.asm, set a breakpoint there in Bochs, and examine what happens all time it gets called after the kernel. There are two ways can set this breakpoint:with Thebcommand and a physical address, or with Thevbcommand, a segment s Elector (use 8 for the code segment), and a virtual address. How many 32-bit words does all recursive nesting level oftest_backtracepush on the stack, and what are those word |
This exercise is mainly to understand the principle of function calls and how the parameters are pressed stack.
Stack top: +-------------------------------(Low memory)
+-----------Last EBP------------(the 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;
}