Exercise 1

i386_init identifies the file system environment by passing the type ENV_TYPE_FS to your environment creation function, env_create. Modify env_create in env.c, so that it gives the file system environment I/O privilege, but never gives that privilege to any other environment.

Make sure you can start the file environment without causing a General Protection fault. You should pass the “fs i/o” test in make grade.

This can be set using following changes in env_create function in kern/env.c.

	e->env_type = type;
	if(e->env_type == ENV_TYPE_FS){
		e->env_tf.tf_eflags |= FL_IOPL_MASK;
	}

we are enabling the FL_IOPL_MASK only for FS user environment. This will prevent other environments to have I/O privileges.

Error Faced

When I tried to run fs i/o test, I kept facing this error.

qemu-system-i386 -nographic -drive file=obj/kern/kernel.img,index=0,media=disk,format=raw -serial mon:stdio -gdb tcp::26000 -D qemu.log -smp 1 -drive file=obj/fs/fs.img,index=1,media=disk,format=raw
6828 decimal is 15254 octal!
395 decimal is 613 octal!
Physical memory: 131072K available, base = 640K, extended = 130432K
EAX=00000000 EBX=00000000 ECX=0000f800 EDX=00000000
ESI=00000000 EDI=f0400000 EBP=f0124f68 ESP=f0124f5c
EIP=f0105e61 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007c4c 00000017
IDT=     00000000 000003ff
CR0=80010011 CR2=f0400000 CR3=00125000 CR4=00000010
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
EFER=0000000000000000
Triple fault.  Halting for inspection via QEMU monitor.

In the beginning, I thought that it might be due to my errors. So I started checking if I missed something. Once I was sure that the error had nothing to do with my fix, I started debugging.

Using gdb, I tracked the code which was causing the Triple Fault.

Program received signal SIGTRAP, Trace/breakpoint trap.
The target architecture is set to "i386".
=> 0xf0105e61 <memset+53>:      rep stos %eax,%es:(%edi)
0xf0105e61 in memset (v=0xf03fe000, c=0, n=262144) at lib/string.c:131
131                     asm volatile("cld; rep stosl\n"
(gdb)

The complete disassembly is as follows:

f0105e5b:	09 d0                	or     %edx,%eax
		asm volatile("cld; rep stosl\n"
			:: "D" (v), "a" (c), "c" (n/4)
f0105e5d:	c1 e9 02             	shr    $0x2,%ecx
		asm volatile("cld; rep stosl\n"
f0105e60:	fc                   	cld
f0105e61:	f3 ab                	rep stos %eax,%es:(%edi)
f0105e63:	eb 06                	jmp    f0105e6b <memset+0x3f>
			: "cc", "memory");
	} else
		asm volatile("cld; rep stosb\n"

The panic was happening while running the following instruction:

f0105e61:	f3 ab                	rep stos %eax,%es:(%edi)

In this instruction, we are in a loop. We take the value from eax and write it into the register address given in edi and decrease ecx. Next we’ll increment/decrement edi depending upon the direction flag. Since we have cleared the flag (using cld instruction), we are incrementing edi. This loop goes on until ecx is zero.

This seemed like a normal instruction to me. I went back to check the register set after panic.

EAX=00000000 EBX=00000000 ECX=0000f800 EDX=00000000
ESI=00000000 EDI=f0400000 EBP=f0124f68 ESP=f0124f5c
EIP=f0105e61 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0

It can be seen that ecx is non zero. This means that panic happened while the loop was running. Using qemu monitor, I collected the values of page directory. Here are the page directory values:

(qemu) info pg
VPN range     Entry         Flags        Physical page
[00000-003ff]  PDE[000]     ----A----P
  [00000-00000]  PTE[000]     ----A---WP 00000
  [00001-000b7]  PTE[001-0b7] --------WP 00001-000b7
  [000b8-000b8]  PTE[0b8]     ---DA---WP 000b8
  [000b9-000ff]  PTE[0b9-0ff] --------WP 000b9-000ff
  [00100-00101]  PTE[100-101] ----A---WP 00100-00101
  [00102-00102]  PTE[102]     --------WP 00102
  [00103-00103]  PTE[103]     ----A---WP 00103
  [00104-00104]  PTE[104]     --------WP 00104
  [00105-00108]  PTE[105-108] ----A---WP 00105-00108
  [00109-00123]  PTE[109-123] --------WP 00109-00123
  [00124-00124]  PTE[124]     ---DA---WP 00124
  [00125-00126]  PTE[125-126] --------WP 00125-00126
  [00127-00127]  PTE[127]     ---DA---WP 00127
  [00128-003ba]  PTE[128-3ba] --------WP 00128-003ba
  [003bb-003bb]  PTE[3bb]     ---DA---WP 003bb
  [003bc-003fc]  PTE[3bc-3fc] --------WP 003bc-003fc
  [003fd-003ff]  PTE[3fd-3ff] ---DA---WP 003fd-003ff
[f0000-f03ff]  PDE[3c0]     ----A---WP
  [f0000-f0000]  PTE[000]     ----A---WP 00000
  [f0001-f00b7]  PTE[001-0b7] --------WP 00001-000b7
  [f00b8-f00b8]  PTE[0b8]     ---DA---WP 000b8
  [f00b9-f00ff]  PTE[0b9-0ff] --------WP 000b9-000ff
  [f0100-f0101]  PTE[100-101] ----A---WP 00100-00101
  [f0102-f0102]  PTE[102]     --------WP 00102
  [f0103-f0103]  PTE[103]     ----A---WP 00103
  [f0104-f0104]  PTE[104]     --------WP 00104
  [f0105-f0108]  PTE[105-108] ----A---WP 00105-00108
  [f0109-f0123]  PTE[109-123] --------WP 00109-00123
  [f0124-f0124]  PTE[124]     ---DA---WP 00124
  [f0125-f0126]  PTE[125-126] --------WP 00125-00126
  [f0127-f0127]  PTE[127]     ---DA---WP 00127
  [f0128-f03ba]  PTE[128-3ba] --------WP 00128-003ba
  [f03bb-f03bb]  PTE[3bb]     ---DA---WP 003bb
  [f03bc-f03fc]  PTE[3bc-3fc] --------WP 003bc-003fc
  [f03fd-f03ff]  PTE[3fd-3ff] ---DA---WP 003fd-003ff

It cam be seen that VPA range which has been mapped to physical memory is [f0000-f03ff] and [00000-003ff]. Each index represent as virtual page. This made me think. See the loop which caused the panic increases the value of edi every iteration. At the time of fault, value of edi is f0400000. This is the first entry which is not mapped to any Physical page. This was my eureka moment. I had found the error.

I still wasn’t sure why it has failed now. It never failed before. So there had been some changes which are now leading to increase in address which in turn, is causing a panic.

I tracked which variable address was sent to memset which in turn is fed into edi. It was kern_pgdir. And kern_pgdir is set using boot_alloc as follows:

kern_pgdir = (pde_t *) boot_alloc(PGSIZE);

......
// here is the boot_alloc code:

// Initialize nextfree if this is the first time.
// 'end' is a magic symbol automatically generated by the linker,
// which points to the end of the kernel's bss segment:
// the first virtual address that the linker did *not* assign
// to any kernel code or global variables.
if (!nextfree) {
	extern char end[];
	nextfree = ROUNDUP((char *) end, PGSIZE);
}

Since kern_pgdir is the first address to be allocated, it is equal to end. Now who sets this end? I found this in the kernel.ld file as follows:

.bss : {
		PROVIDE(edata = .);
		*(.dynbss)
		*(.bss .bss.*)
		*(COMMON)
		PROVIDE(end = .);
	}

So end is the address which is available after mapping all the code/text/data related to kernel. But I was surprised. See this error has never happened before. So there must be some new data being added to kernel which is causing this overshoot in address.

I started checking all the segments and I found that we are packing the test binaries along with kernel image in this section:

/* The data segment */
	.data : {
		*(.data .data.*)
	}

So now we knew the culprit. I came across kernel/Makefrag, where we are packing all the test binaries.

# Binary program images to embed within the kernel.
# Binary files for LAB3
KERN_BINFILES :=	user/hello \
			user/buggyhello \
			user/buggyhello2 \

similar files are added for Lab 4 and Lab 5. each new lab was increasing the size of data segment and which in turn was increasing the value of end and thus kern_pgdir. This was leading to the dangerous error pasted above. Once I commented out the test files from earlier labs, everything worked fine and I was a pretty happy man.