import
This commit is contained in:
		
						commit
						55e95b16db
					
				
					 18 changed files with 1505 additions and 0 deletions
				
			
		
							
								
								
									
										30
									
								
								Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o | ||||||
|  | 
 | ||||||
|  | CC = i386-jos-elf-gcc | ||||||
|  | LD = i386-jos-elf-ld | ||||||
|  | OBJCOPY = i386-jos-elf-objcopy | ||||||
|  | OBJDUMP = i386-jos-elf-objdump | ||||||
|  | 
 | ||||||
|  | xv6.img : bootblock kernel | ||||||
|  | 	dd if=/dev/zero of=xv6.img count=10000 | ||||||
|  | 	dd if=bootblock of=xv6.img conv=notrunc | ||||||
|  | 	dd if=kernel of=xv6.img seek=1 conv=notrunc | ||||||
|  | 
 | ||||||
|  | bootblock : bootasm.S bootmain.c | ||||||
|  | 	$(CC) -O -nostdinc -I. -c bootmain.c | ||||||
|  | 	$(CC) -nostdinc -I. -c bootasm.S | ||||||
|  | 	$(LD) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o | ||||||
|  | 	$(OBJDUMP) -S bootblock.o > bootblock.asm | ||||||
|  | 	$(OBJCOPY) -S -O binary bootblock.o bootblock | ||||||
|  | 	./sign.pl bootblock | ||||||
|  | 
 | ||||||
|  | kernel : $(OBJS) | ||||||
|  | 	$(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) | ||||||
|  | 	$(OBJDUMP) -S kernel > kernel.asm | ||||||
|  | 
 | ||||||
|  | %.o: %.c | ||||||
|  | 	$(CC) -nostdinc -I. -O -c -o $@ $< | ||||||
|  | 
 | ||||||
|  | clean :  | ||||||
|  | 	rm -f bootmain.o bootasm.o bootblock.o bootblock | ||||||
|  | 	rm -f kernel main.o kernel.asm xv6.img | ||||||
							
								
								
									
										67
									
								
								Notes
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								Notes
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,67 @@ | ||||||
|  | bootmain.c doesn't work right if the ELF sections aren't | ||||||
|  | sector-aligned. so you can't use ld -N. and the sections may also need | ||||||
|  | to be non-zero length, only really matters for tiny "kernels". | ||||||
|  | 
 | ||||||
|  | kernel loaded at 1 megabyte. stack same place that bootasm.S left it. | ||||||
|  | 
 | ||||||
|  | kinit() should find real mem size | ||||||
|  |   and rescue useable memory below 1 meg | ||||||
|  | 
 | ||||||
|  | no paging, no use of page table hardware, just segments | ||||||
|  | 
 | ||||||
|  | no user area: no magic kernel stack mapping | ||||||
|  |   so no copying of kernel stack during fork | ||||||
|  |   though there is a kernel stack page for each process | ||||||
|  | 
 | ||||||
|  | no kernel malloc(), just kalloc() for user core | ||||||
|  | 
 | ||||||
|  | user pointers aren't valid in the kernel | ||||||
|  | 
 | ||||||
|  | setting up first process | ||||||
|  |   we do want a process zero, as template | ||||||
|  |     but not runnable | ||||||
|  |   just set up return-from-trap frame on new kernel stack | ||||||
|  |   fake user program that calls exec | ||||||
|  | 
 | ||||||
|  | map text read-only? | ||||||
|  | shared text? | ||||||
|  | 
 | ||||||
|  | what's on the stack during a trap or sys call? | ||||||
|  |   PUSHA before scheduler switch? for callee-saved registers. | ||||||
|  |   segment contents? | ||||||
|  |   what does iret need to get out of the kernel? | ||||||
|  |   how does INT know what kernel stack to use? | ||||||
|  |   | ||||||
|  | are interrupts turned on in the kernel? probably. | ||||||
|  | 
 | ||||||
|  | per-cpu curproc | ||||||
|  | one tss per process, or one per cpu? | ||||||
|  | one segment array per cpu, or per process? | ||||||
|  | 
 | ||||||
|  | pass curproc explicitly, or implicit from cpu #? | ||||||
|  |   e.g. argument to newproc()? | ||||||
|  | 
 | ||||||
|  | test stack expansion | ||||||
|  | test running out of memory, process slots | ||||||
|  | 
 | ||||||
|  | we can't really use a separate stack segment, since stack addresses | ||||||
|  | need to work correctly as ordinary pointers. the same may be true of | ||||||
|  | data vs text. how can we have a gap between data and stack, so that | ||||||
|  | both can grow, without committing 4GB of physical memory? does this | ||||||
|  | mean we need paging? | ||||||
|  | 
 | ||||||
|  | what's the simplest way to add the paging we need? | ||||||
|  |   one page table, re-write it each time we leave the kernel? | ||||||
|  |   page table per process? | ||||||
|  |   probably need to use 0-0xffffffff segments, so that | ||||||
|  |     both data and stack pointers always work | ||||||
|  |   so is it now worth it to make a process's phys mem contiguous? | ||||||
|  |   or could use segment limits and 4 meg pages? | ||||||
|  |     but limits would prevent using stack pointers as data pointers | ||||||
|  |   how to write-protect text? not important? | ||||||
|  | 
 | ||||||
|  | perhaps have fixed-size stack, put it in the data segment? | ||||||
|  | 
 | ||||||
|  | oops, if kernel stack is in contiguous user phys mem, then moving | ||||||
|  | users' memory (e.g. to expand it) will wreck any pointers into the | ||||||
|  | kernel stack. | ||||||
							
								
								
									
										109
									
								
								bootasm.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								bootasm.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,109 @@ | ||||||
|  | #define SEG_NULL						\ | ||||||
|  | 	.word 0, 0;						\
 | ||||||
|  | 	.byte 0, 0, 0, 0 | ||||||
|  | #define SEG(type,base,lim)					\ | ||||||
|  | 	.word (((lim) >> 12) & 0xffff), ((base) & 0xffff);	\
 | ||||||
|  | 	.byte (((base) >> 16) & 0xff), (0x90 | (type)),		\ | ||||||
|  | 		(0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) | ||||||
|  | 
 | ||||||
|  | #define STA_X		0x8	    // Executable segment | ||||||
|  | #define STA_E		0x4	    // Expand down (non-executable segments) | ||||||
|  | #define STA_C		0x4	    // Conforming code segment (executable only) | ||||||
|  | #define STA_W		0x2	    // Writeable (non-executable segments) | ||||||
|  | #define STA_R		0x2	    // Readable (executable segments) | ||||||
|  | #define STA_A		0x1	    // Accessed | ||||||
|  | 	 | ||||||
|  | .set PROT_MODE_CSEG,0x8		# code segment selector | ||||||
|  | .set PROT_MODE_DSEG,0x10        # data segment selector | ||||||
|  | .set CR0_PE_ON,0x1		# protected mode enable flag | ||||||
|  | 	 | ||||||
|  | ################################################################################### | ||||||
|  | # ENTRY POINT	 | ||||||
|  | #   This code should be stored in the first sector of the hard disk. | ||||||
|  | #   After the BIOS initializes the hardware on startup or system reset, | ||||||
|  | #   it loads this code at physical address 0x7c00 - 0x7d00 (512 bytes). | ||||||
|  | #   Then the BIOS jumps to the beginning of it, address 0x7c00, | ||||||
|  | #   while running in 16-bit real-mode (8086 compatibility mode). | ||||||
|  | #   The Code Segment register (CS) is initially zero on entry. | ||||||
|  | #	 | ||||||
|  | # This code switches into 32-bit protected mode so that all of | ||||||
|  | # memory can accessed, then calls into C. | ||||||
|  | ################################################################################### | ||||||
|  | 	 | ||||||
|  | .globl start					# Entry point	 | ||||||
|  | start:		.code16				# This runs in real mode | ||||||
|  | 		cli				# Disable interrupts | ||||||
|  | 		cld				# String operations increment | ||||||
|  | 
 | ||||||
|  | 		# Set up the important data segment registers (DS, ES, SS). | ||||||
|  | 		xorw	%ax,%ax			# Segment number zero | ||||||
|  | 		movw	%ax,%ds			# -> Data Segment | ||||||
|  | 		movw	%ax,%es			# -> Extra Segment | ||||||
|  | 		movw	%ax,%ss			# -> Stack Segment | ||||||
|  | 
 | ||||||
|  | 		# Set up the stack pointer, growing downward from 0x7c00. | ||||||
|  | 		movw	$start,%sp         	# Stack Pointer | ||||||
|  | 	 | ||||||
|  | #### Enable A20: | ||||||
|  | ####   For fascinating historical reasons (related to the fact that | ||||||
|  | ####   the earliest 8086-based PCs could only address 1MB of physical memory | ||||||
|  | ####   and subsequent 80286-based PCs wanted to retain maximum compatibility), | ||||||
|  | ####   physical address line 20 is tied to low when the machine boots. | ||||||
|  | ####   Obviously this a bit of a drag for us, especially when trying to | ||||||
|  | ####   address memory above 1MB.  This code undoes this. | ||||||
|  | 	 | ||||||
|  | seta20.1:	inb	$0x64,%al		# Get status | ||||||
|  | 		testb	$0x2,%al		# Busy? | ||||||
|  | 		jnz	seta20.1		# Yes | ||||||
|  | 		movb	$0xd1,%al		# Command: Write | ||||||
|  | 		outb	%al,$0x64		#  output port | ||||||
|  | seta20.2:	inb	$0x64,%al		# Get status | ||||||
|  | 		testb	$0x2,%al		# Busy? | ||||||
|  | 		jnz	seta20.2		# Yes | ||||||
|  | 		movb	$0xdf,%al		# Enable | ||||||
|  | 		outb	%al,$0x60		#  A20 | ||||||
|  | 
 | ||||||
|  | #### Switch from real to protected mode	 | ||||||
|  | ####     The descriptors in our GDT allow all physical memory to be accessed. | ||||||
|  | ####     Furthermore, the descriptors have base addresses of 0, so that the | ||||||
|  | ####     segment translation is a NOP, ie. virtual addresses are identical to | ||||||
|  | ####     their physical addresses.  With this setup, immediately after | ||||||
|  | ####	 enabling protected mode it will still appear to this code | ||||||
|  | ####	 that it is running directly on physical memory with no translation. | ||||||
|  | ####	 This initial NOP-translation setup is required by the processor | ||||||
|  | ####	 to ensure that the transition to protected mode occurs smoothly. | ||||||
|  | 	 | ||||||
|  | real_to_prot:	cli				# Mandatory since we dont set up an IDT | ||||||
|  | 		lgdt	gdtdesc			# load GDT -- mandatory in protected mode | ||||||
|  | 		movl	%cr0, %eax		# turn on protected mode | ||||||
|  | 		orl	$CR0_PE_ON, %eax	#  | ||||||
|  | 		movl	%eax, %cr0		#  | ||||||
|  | 	        ### CPU magic: jump to relocation, flush prefetch queue, and reload %cs | ||||||
|  | 		### Has the effect of just jmp to the next instruction, but simultaneous | ||||||
|  | 		### loads CS with $PROT_MODE_CSEG. | ||||||
|  | 		ljmp	$PROT_MODE_CSEG, $protcseg | ||||||
|  | 	 | ||||||
|  | #### we are in 32-bit protected mode (hence the .code32) | ||||||
|  | .code32 | ||||||
|  | protcseg:	 | ||||||
|  | 		# Set up the protected-mode data segment registers | ||||||
|  | 		movw	$PROT_MODE_DSEG, %ax	# Our data segment selector | ||||||
|  | 		movw	%ax, %ds		# -> DS: Data Segment | ||||||
|  | 		movw	%ax, %es		# -> ES: Extra Segment | ||||||
|  | 		movw	%ax, %fs		# -> FS | ||||||
|  | 		movw	%ax, %gs		# -> GS | ||||||
|  | 		movw	%ax, %ss		# -> SS: Stack Segment | ||||||
|  | 	 | ||||||
|  | 		call cmain			# finish the boot load from C. | ||||||
|  | 						# cmain() should not return | ||||||
|  | spin:		jmp spin			# ..but in case it does, spin | ||||||
|  | 	 | ||||||
|  | .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 | ||||||
							
								
								
									
										121
									
								
								bootmain.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								bootmain.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,121 @@ | ||||||
|  | #include <types.h> | ||||||
|  | #include <elf.h> | ||||||
|  | #include <x86.h> | ||||||
|  | 
 | ||||||
|  | /**********************************************************************
 | ||||||
|  |  * This a dirt simple boot loader, whose sole job is to boot | ||||||
|  |  * an elf kernel image from the first IDE hard disk. | ||||||
|  |  * | ||||||
|  |  * DISK LAYOUT | ||||||
|  |  *  * This program(boot.S and main.c) is the bootloader.  It should | ||||||
|  |  *    be stored in the first sector of the disk. | ||||||
|  |  *  | ||||||
|  |  *  * The 2nd sector onward holds the kernel image. | ||||||
|  |  *	 | ||||||
|  |  *  * The kernel image must be in ELF format. | ||||||
|  |  * | ||||||
|  |  * BOOT UP STEPS	 | ||||||
|  |  *  * when the CPU boots it loads the BIOS into memory and executes it | ||||||
|  |  * | ||||||
|  |  *  * the BIOS intializes devices, sets of the interrupt routines, and | ||||||
|  |  *    reads the first sector of the boot device(e.g., hard-drive)  | ||||||
|  |  *    into memory and jumps to it. | ||||||
|  |  * | ||||||
|  |  *  * Assuming this boot loader is stored in the first sector of the | ||||||
|  |  *    hard-drive, this code takes over... | ||||||
|  |  * | ||||||
|  |  *  * control starts in bootloader.S -- which sets up protected mode, | ||||||
|  |  *    and a stack so C code then run, then calls cmain() | ||||||
|  |  * | ||||||
|  |  *  * cmain() in this file takes over, reads in the kernel and jumps to it. | ||||||
|  |  **********************************************************************/ | ||||||
|  | 
 | ||||||
|  | #define SECTSIZE	512 | ||||||
|  | #define ELFHDR		((struct Elf *) 0x10000) // scratch space
 | ||||||
|  | 
 | ||||||
|  | void readsect(void*, uint32_t); | ||||||
|  | void readseg(uint32_t, uint32_t, uint32_t); | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | cmain(void) | ||||||
|  | { | ||||||
|  | 	struct Proghdr *ph, *eph; | ||||||
|  | 
 | ||||||
|  | 	// read 1st page off disk
 | ||||||
|  | 	readseg((uint32_t) ELFHDR, SECTSIZE*8, 0); | ||||||
|  | 
 | ||||||
|  | 	// is this a valid ELF?
 | ||||||
|  | 	if (ELFHDR->e_magic != ELF_MAGIC) | ||||||
|  | 		goto bad; | ||||||
|  | 
 | ||||||
|  | 	// load each program segment (ignores ph flags)
 | ||||||
|  | 	ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff); | ||||||
|  | 	eph = ph + ELFHDR->e_phnum; | ||||||
|  | 	for (; ph < eph; ph++) | ||||||
|  | 		readseg(ph->p_va, ph->p_memsz, ph->p_offset); | ||||||
|  | 
 | ||||||
|  | 	// call the entry point from the ELF header
 | ||||||
|  | 	// note: does not return!
 | ||||||
|  | 	((void (*)(void)) (ELFHDR->e_entry & 0xFFFFFF))(); | ||||||
|  | 
 | ||||||
|  | bad: | ||||||
|  | 	outw(0x8A00, 0x8A00); | ||||||
|  | 	outw(0x8A00, 0x8E00); | ||||||
|  | 	while (1) | ||||||
|  | 		/* do nothing */; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Read 'count' bytes at 'offset' from kernel into virtual address 'va'.
 | ||||||
|  | // Might copy more than asked
 | ||||||
|  | void | ||||||
|  | readseg(uint32_t va, uint32_t count, uint32_t offset) | ||||||
|  | { | ||||||
|  | 	uint32_t end_va; | ||||||
|  | 
 | ||||||
|  | 	va &= 0xFFFFFF; | ||||||
|  | 	end_va = va + count; | ||||||
|  | 	 | ||||||
|  | 	// round down to sector boundary
 | ||||||
|  | 	va &= ~(SECTSIZE - 1); | ||||||
|  | 
 | ||||||
|  | 	// translate from bytes to sectors, and kernel starts at sector 1
 | ||||||
|  | 	offset = (offset / SECTSIZE) + 1; | ||||||
|  | 
 | ||||||
|  | 	// If this is too slow, we could read lots of sectors at a time.
 | ||||||
|  | 	// We'd write more to memory than asked, but it doesn't matter --
 | ||||||
|  | 	// we load in increasing order.
 | ||||||
|  | 	while (va < end_va) { | ||||||
|  | 		readsect((uint8_t*) va, offset); | ||||||
|  | 		va += SECTSIZE; | ||||||
|  | 		offset++; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | waitdisk(void) | ||||||
|  | { | ||||||
|  | 	// wait for disk reaady
 | ||||||
|  | 	while ((inb(0x1F7) & 0xC0) != 0x40) | ||||||
|  | 		/* do nothing */; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | readsect(void *dst, uint32_t offset) | ||||||
|  | { | ||||||
|  | 	// wait for disk to be ready
 | ||||||
|  | 	waitdisk(); | ||||||
|  | 
 | ||||||
|  | 	outb(0x1F2, 1);		// count = 1
 | ||||||
|  | 	outb(0x1F3, offset); | ||||||
|  | 	outb(0x1F4, offset >> 8); | ||||||
|  | 	outb(0x1F5, offset >> 16); | ||||||
|  | 	outb(0x1F6, (offset >> 24) | 0xE0); | ||||||
|  | 	outb(0x1F7, 0x20);	// cmd 0x20 - read sectors
 | ||||||
|  | 
 | ||||||
|  | 	// wait for disk to be ready
 | ||||||
|  | 	waitdisk(); | ||||||
|  | 
 | ||||||
|  | 	// read a sector
 | ||||||
|  | 	insl(0x1F0, dst, SECTSIZE/4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										108
									
								
								console.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								console.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,108 @@ | ||||||
|  | #include <types.h> | ||||||
|  | #include <x86.h> | ||||||
|  | #include "defs.h" | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | cons_putc(int c) | ||||||
|  | { | ||||||
|  |   int crtport = 0x3d4; // io port of CGA
 | ||||||
|  |   unsigned short *crt = (unsigned short *) 0xB8000; // base of CGA memory
 | ||||||
|  |   int ind; | ||||||
|  | 
 | ||||||
|  |   // cursor position, 16 bits, col + 80*row
 | ||||||
|  |   outb(crtport, 14); | ||||||
|  |   ind = inb(crtport + 1) << 8; | ||||||
|  |   outb(crtport, 15); | ||||||
|  |   ind |= inb(crtport + 1); | ||||||
|  | 
 | ||||||
|  |   c &= 0xff; | ||||||
|  | 
 | ||||||
|  |   if(c == '\n'){ | ||||||
|  |     ind -= (ind % 80); | ||||||
|  |     ind += 80; | ||||||
|  |   } else { | ||||||
|  |     c |= 0x0700; // black on white
 | ||||||
|  |     crt[ind] = c; | ||||||
|  |     ind += 1; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if((ind / 80) >= 24){ | ||||||
|  |     // scroll up
 | ||||||
|  |     memcpy(crt, crt + 80, sizeof(crt[0]) * (23 * 80)); | ||||||
|  |     ind -= 80; | ||||||
|  |     memset(crt + ind, 0, sizeof(crt[0]) * ((24 * 80) - ind)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   outb(crtport, 14); | ||||||
|  |   outb(crtport + 1, ind >> 8); | ||||||
|  |   outb(crtport, 15); | ||||||
|  |   outb(crtport + 1, ind); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | printint(int xx, int base, int sgn) | ||||||
|  | { | ||||||
|  |   char buf[16]; | ||||||
|  |   char digits[] = "0123456789ABCDEF"; | ||||||
|  |   int i = 0, neg = 0; | ||||||
|  |   unsigned int x; | ||||||
|  |    | ||||||
|  |   if(sgn && xx < 0){ | ||||||
|  |     neg = 1; | ||||||
|  |     x = 0 - xx; | ||||||
|  |   } else { | ||||||
|  |     x = xx; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   do { | ||||||
|  |     buf[i++] = digits[x % base]; | ||||||
|  |   } while((x /= base) != 0); | ||||||
|  |   if(neg) | ||||||
|  |     buf[i++] = '-'; | ||||||
|  | 
 | ||||||
|  |   while(i > 0){ | ||||||
|  |     i -= 1; | ||||||
|  |     cons_putc(buf[i]); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * print to the console. only understands %d and %x. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | cprintf(char *fmt, ...) | ||||||
|  | { | ||||||
|  |   int i, state = 0, c; | ||||||
|  |   unsigned int *ap = (unsigned int *) &fmt + 1; | ||||||
|  | 
 | ||||||
|  |   for(i = 0; fmt[i]; i++){ | ||||||
|  |     c = fmt[i] & 0xff; | ||||||
|  |     if(state == 0){ | ||||||
|  |       if(c == '%'){ | ||||||
|  |         state = '%'; | ||||||
|  |       } else { | ||||||
|  |         cons_putc(c); | ||||||
|  |       } | ||||||
|  |     } else if(state == '%'){ | ||||||
|  |       if(c == 'd'){ | ||||||
|  |         printint(*ap, 10, 1); | ||||||
|  |         ap++; | ||||||
|  |       } else if(c == 'x'){ | ||||||
|  |         printint(*ap, 16, 0); | ||||||
|  |         ap++; | ||||||
|  |       } else if(c == '%'){ | ||||||
|  |         cons_putc(c); | ||||||
|  |       } | ||||||
|  |       state = 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | panic(char *s) | ||||||
|  | { | ||||||
|  |   cprintf(s, 0); | ||||||
|  |   cprintf("\n", 0); | ||||||
|  |   while(1) | ||||||
|  |     ; | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								defs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								defs.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | // kalloc.c
 | ||||||
|  | char *kalloc(int n); | ||||||
|  | void kfree(char *cp, int len); | ||||||
|  | 
 | ||||||
|  | // console.c
 | ||||||
|  | void cprintf(char *fmt, ...); | ||||||
|  | void panic(char *s); | ||||||
|  | 
 | ||||||
|  | // proc.c
 | ||||||
|  | struct proc; | ||||||
|  | void setupsegs(struct proc *p); | ||||||
|  | struct proc * newproc(struct proc *op); | ||||||
							
								
								
									
										43
									
								
								elf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								elf.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | ||||||
|  | #ifndef JOS_INC_ELF_H | ||||||
|  | #define JOS_INC_ELF_H | ||||||
|  | 
 | ||||||
|  | #define ELF_MAGIC 0x464C457FU	/* "\x7FELF" in little endian */ | ||||||
|  | 
 | ||||||
|  | struct Elf { | ||||||
|  | 	uint32_t e_magic;	// must equal ELF_MAGIC
 | ||||||
|  | 	uint8_t e_elf[12]; | ||||||
|  | 	uint16_t e_type; | ||||||
|  | 	uint16_t e_machine; | ||||||
|  | 	uint32_t e_version; | ||||||
|  | 	uint32_t e_entry; | ||||||
|  | 	uint32_t e_phoff; | ||||||
|  | 	uint32_t e_shoff; | ||||||
|  | 	uint32_t e_flags; | ||||||
|  | 	uint16_t e_ehsize; | ||||||
|  | 	uint16_t e_phentsize; | ||||||
|  | 	uint16_t e_phnum; | ||||||
|  | 	uint16_t e_shentsize; | ||||||
|  | 	uint16_t e_shnum; | ||||||
|  | 	uint16_t e_shstrndx; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Proghdr { | ||||||
|  | 	uint32_t p_type; | ||||||
|  | 	uint32_t p_offset; | ||||||
|  | 	uint32_t p_va; | ||||||
|  | 	uint32_t p_pa; | ||||||
|  | 	uint32_t p_filesz; | ||||||
|  | 	uint32_t p_memsz; | ||||||
|  | 	uint32_t p_flags; | ||||||
|  | 	uint32_t p_align; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Values for Proghdr::p_type
 | ||||||
|  | #define ELF_PROG_LOAD		1 | ||||||
|  | 
 | ||||||
|  | // Flag bits for Proghdr::p_flags
 | ||||||
|  | #define ELF_PROG_FLAG_EXEC	1 | ||||||
|  | #define ELF_PROG_FLAG_WRITE	2 | ||||||
|  | #define ELF_PROG_FLAG_READ	4 | ||||||
|  | 
 | ||||||
|  | #endif /* !JOS_INC_ELF_H */ | ||||||
							
								
								
									
										158
									
								
								kalloc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								kalloc.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,158 @@ | ||||||
|  | /*
 | ||||||
|  |  * physical memory allocator, intended to be used to allocate | ||||||
|  |  * memory for user processes. allocates in 4096-byte "pages". | ||||||
|  |  * free list is sorted and combines adjacent pages into | ||||||
|  |  * long runs, to make it easier to allocate big segments. | ||||||
|  |  * one reason the page size is 4k is that the x86 segment size | ||||||
|  |  * granularity is 4k. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "param.h" | ||||||
|  | #include "types.h" | ||||||
|  | #include "defs.h" | ||||||
|  | 
 | ||||||
|  | struct run { | ||||||
|  |   struct run *next; | ||||||
|  |   int len; // bytes
 | ||||||
|  | }; | ||||||
|  | struct run *freelist; | ||||||
|  | 
 | ||||||
|  | void ktest(); | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * initialize free list of physical pages. this code | ||||||
|  |  * cheats by just considering the one megabyte of pages | ||||||
|  |  * after _end. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | kinit() | ||||||
|  | { | ||||||
|  |   extern int end; | ||||||
|  |   unsigned mem; | ||||||
|  |   char *start; | ||||||
|  |    | ||||||
|  |   start = (char *) &end; | ||||||
|  |   start = (char *) (((unsigned)start + PAGE) & ~(PAGE-1)); | ||||||
|  |   mem = 256; // XXX
 | ||||||
|  |   cprintf("mem = %d\n", mem * PAGE); | ||||||
|  |   kfree(start, mem * PAGE); | ||||||
|  |   ktest(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | kfree(char *cp, int len) | ||||||
|  | { | ||||||
|  |   struct run **rr; | ||||||
|  |   struct run *p = (struct run *) cp; | ||||||
|  |   struct run *pend = (struct run *) (cp + len); | ||||||
|  | 
 | ||||||
|  |   if(len % PAGE) | ||||||
|  |     panic("kfree"); | ||||||
|  | 
 | ||||||
|  |   rr = &freelist; | ||||||
|  |   while(*rr){ | ||||||
|  |     struct run *rend = (struct run *) ((char *)(*rr) + (*rr)->len); | ||||||
|  |     if(p >= *rr && p < rend) | ||||||
|  |       panic("freeing free page"); | ||||||
|  |     if(pend == *rr){ | ||||||
|  |       p->len = len + (*rr)->len; | ||||||
|  |       p->next = (*rr)->next; | ||||||
|  |       *rr = p; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if(pend < *rr){ | ||||||
|  |       p->len = len; | ||||||
|  |       p->next = *rr; | ||||||
|  |       *rr = p; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if(p == rend){ | ||||||
|  |       (*rr)->len += len; | ||||||
|  |       if((*rr)->next && (*rr)->next == pend){ | ||||||
|  |         (*rr)->len += (*rr)->next->len; | ||||||
|  |         (*rr)->next = (*rr)->next->next; | ||||||
|  |       } | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     rr = &((*rr)->next); | ||||||
|  |   } | ||||||
|  |   p->len = len; | ||||||
|  |   p->next = 0; | ||||||
|  |   *rr = p; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * allocate n bytes of physical memory. | ||||||
|  |  * returns a kernel-segment pointer. | ||||||
|  |  * returns 0 if there's no run that's big enough. | ||||||
|  |  */ | ||||||
|  | char * | ||||||
|  | kalloc(int n) | ||||||
|  | { | ||||||
|  |   struct run **rr; | ||||||
|  | 
 | ||||||
|  |   if(n % PAGE) | ||||||
|  |     panic("kalloc"); | ||||||
|  | 
 | ||||||
|  |   rr = &freelist; | ||||||
|  |   while(*rr){ | ||||||
|  |     struct run *r = *rr; | ||||||
|  |     if(r->len == n){ | ||||||
|  |       *rr = r->next; | ||||||
|  |       return (char *) r; | ||||||
|  |     } | ||||||
|  |     if(r->len > n){ | ||||||
|  |       char *p = (char *)r + (r->len - n); | ||||||
|  |       r->len -= n; | ||||||
|  |       return p; | ||||||
|  |     } | ||||||
|  |     rr = &(*rr)->next; | ||||||
|  |   } | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | ktest() | ||||||
|  | { | ||||||
|  |   char *p1, *p2, *p3; | ||||||
|  | 
 | ||||||
|  |   // test coalescing
 | ||||||
|  |   p1 = kalloc(4 * PAGE); | ||||||
|  |   kfree(p1 + 3*PAGE, PAGE); | ||||||
|  |   kfree(p1 + 2*PAGE, PAGE); | ||||||
|  |   kfree(p1, PAGE); | ||||||
|  |   kfree(p1 + PAGE, PAGE); | ||||||
|  |   p2 = kalloc(4 * PAGE); | ||||||
|  |   if(p2 != p1) | ||||||
|  |     panic("ktest"); | ||||||
|  |   kfree(p2, 4 * PAGE); | ||||||
|  | 
 | ||||||
|  |   // test finding first run that fits
 | ||||||
|  |   p1 = kalloc(1 * PAGE); | ||||||
|  |   p2 = kalloc(1 * PAGE); | ||||||
|  |   kfree(p1, PAGE); | ||||||
|  |   p3 = kalloc(2 * PAGE); | ||||||
|  |   kfree(p2, PAGE); | ||||||
|  |   kfree(p3, 2 * PAGE); | ||||||
|  | 
 | ||||||
|  |   // test running out of memory
 | ||||||
|  |   p1 = 0; | ||||||
|  |   while(1){ | ||||||
|  |     p2 = kalloc(PAGE); | ||||||
|  |     if(p2 == 0) | ||||||
|  |       break; | ||||||
|  |     *(char **)p2 = p1; | ||||||
|  |     p1 = p2; | ||||||
|  |   } | ||||||
|  |   while(p1){ | ||||||
|  |     p2 = *(char **)p1; | ||||||
|  |     kfree(p1, PAGE); | ||||||
|  |     p1 = p2; | ||||||
|  |   } | ||||||
|  |   p1 = kalloc(PAGE * 20); | ||||||
|  |   if(p1 == 0) | ||||||
|  |     panic("ktest2"); | ||||||
|  |   kfree(p1, PAGE * 20); | ||||||
|  | 
 | ||||||
|  |   cprintf("ktest ok\n"); | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								main.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								main.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | #include "types.h" | ||||||
|  | #include "param.h" | ||||||
|  | #include "mmu.h" | ||||||
|  | #include "proc.h" | ||||||
|  | #include "defs.h" | ||||||
|  | #include "x86.h" | ||||||
|  | 
 | ||||||
|  | char junk1[20000]; | ||||||
|  | char junk2[20000] = { 1 }; | ||||||
|  | 
 | ||||||
|  | main() | ||||||
|  | { | ||||||
|  |   struct proc *p; | ||||||
|  | 
 | ||||||
|  |   cprintf("\nxV6\n\n"); | ||||||
|  | 
 | ||||||
|  |   // initialize physical memory allocator
 | ||||||
|  |   kinit(); | ||||||
|  | 
 | ||||||
|  |   // create fake process zero
 | ||||||
|  |   p = &proc[0]; | ||||||
|  |   p->state = WAITING; | ||||||
|  |   p->sz = PAGE; | ||||||
|  |   p->mem = kalloc(p->sz); | ||||||
|  |   memset(p->mem, 0, p->sz); | ||||||
|  |   p->kstack = kalloc(KSTACKSIZE); | ||||||
|  |   p->tf = (struct Trapframe *) (p->kstack + KSTACKSIZE - sizeof(struct Trapframe)); | ||||||
|  |   memset(p->tf, 0, sizeof(struct Trapframe)); | ||||||
|  |   p->tf->tf_es = p->tf->tf_ds = p->tf->tf_ss = (SEG_UDATA << 3) | 3; | ||||||
|  |   p->tf->tf_cs = (SEG_UCODE << 3) | 3; | ||||||
|  |   p->tf->tf_eflags = FL_IF; | ||||||
|  |   setupsegs(p); | ||||||
|  | 
 | ||||||
|  |   p = newproc(&proc[0]); | ||||||
|  |   // xxx copy instructions to p->mem
 | ||||||
|  |   p->tf->tf_eip = 0; | ||||||
|  |   p->tf->tf_esp = p->sz; | ||||||
|  | 
 | ||||||
|  |   swtch(&proc[0]); | ||||||
|  | } | ||||||
							
								
								
									
										308
									
								
								mmu.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								mmu.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,308 @@ | ||||||
|  | /*
 | ||||||
|  |  * This file contains definitions for the x86 memory management unit (MMU), | ||||||
|  |  * including paging- and segmentation-related data structures and constants, | ||||||
|  |  * the %cr0, %cr4, and %eflags registers, and traps. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * | ||||||
|  |  *	Part 1.  Paging data structures and constants. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | // A linear address 'la' has a three-part structure as follows:
 | ||||||
|  | //
 | ||||||
|  | // +--------10------+-------10-------+---------12----------+
 | ||||||
|  | // | Page Directory |   Page Table   | Offset within Page  |
 | ||||||
|  | // |      Index     |      Index     |                     |
 | ||||||
|  | // +----------------+----------------+---------------------+
 | ||||||
|  | //  \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/
 | ||||||
|  | //  \----------- PPN(la) -----------/
 | ||||||
|  | //
 | ||||||
|  | // The PDX, PTX, PGOFF, and PPN macros decompose linear addresses as shown.
 | ||||||
|  | // To construct a linear address la from PDX(la), PTX(la), and PGOFF(la),
 | ||||||
|  | // use PGADDR(PDX(la), PTX(la), PGOFF(la)).
 | ||||||
|  | 
 | ||||||
|  | // page number field of address
 | ||||||
|  | #define PPN(la)		(((uintptr_t) (la)) >> PTXSHIFT) | ||||||
|  | #define VPN(la)		PPN(la)		// used to index into vpt[]
 | ||||||
|  | 
 | ||||||
|  | // page directory index
 | ||||||
|  | #define PDX(la)		((((uintptr_t) (la)) >> PDXSHIFT) & 0x3FF) | ||||||
|  | #define VPD(la)		PDX(la)		// used to index into vpd[]
 | ||||||
|  | 
 | ||||||
|  | // page table index
 | ||||||
|  | #define PTX(la)		((((uintptr_t) (la)) >> PTXSHIFT) & 0x3FF) | ||||||
|  | 
 | ||||||
|  | // offset in page
 | ||||||
|  | #define PGOFF(la)	(((uintptr_t) (la)) & 0xFFF) | ||||||
|  | 
 | ||||||
|  | // construct linear address from indexes and offset
 | ||||||
|  | #define PGADDR(d, t, o)	((void*) ((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) | ||||||
|  | 
 | ||||||
|  | // Page directory and page table constants.
 | ||||||
|  | #define NPDENTRIES	1024		// page directory entries per page directory
 | ||||||
|  | #define NPTENTRIES	1024		// page table entries per page table
 | ||||||
|  | 
 | ||||||
|  | #define PGSIZE		4096		// bytes mapped by a page
 | ||||||
|  | #define PGSHIFT		12		// log2(PGSIZE)
 | ||||||
|  | 
 | ||||||
|  | #define PTSIZE		(PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry
 | ||||||
|  | #define PTSHIFT		22		// log2(PTSIZE)
 | ||||||
|  | 
 | ||||||
|  | #define PTXSHIFT	12		// offset of PTX in a linear address
 | ||||||
|  | #define PDXSHIFT	22		// offset of PDX in a linear address
 | ||||||
|  | 
 | ||||||
|  | // Page table/directory entry flags.
 | ||||||
|  | #define PTE_P		0x001	// Present
 | ||||||
|  | #define PTE_W		0x002	// Writeable
 | ||||||
|  | #define PTE_U		0x004	// User
 | ||||||
|  | #define PTE_PWT		0x008	// Write-Through
 | ||||||
|  | #define PTE_PCD		0x010	// Cache-Disable
 | ||||||
|  | #define PTE_A		0x020	// Accessed
 | ||||||
|  | #define PTE_D		0x040	// Dirty
 | ||||||
|  | #define PTE_PS		0x080	// Page Size
 | ||||||
|  | #define PTE_MBZ		0x180	// Bits must be zero
 | ||||||
|  | 
 | ||||||
|  | // The PTE_AVAIL bits aren't used by the kernel or interpreted by the
 | ||||||
|  | // hardware, so user processes are allowed to set them arbitrarily.
 | ||||||
|  | #define PTE_AVAIL	0xE00	// Available for software use
 | ||||||
|  | 
 | ||||||
|  | // Only flags in PTE_USER may be used in system calls.
 | ||||||
|  | #define PTE_USER	(PTE_AVAIL | PTE_P | PTE_W | PTE_U) | ||||||
|  | 
 | ||||||
|  | // address in page table entry
 | ||||||
|  | #define PTE_ADDR(pte)	((physaddr_t) (pte) & ~0xFFF) | ||||||
|  | 
 | ||||||
|  | // Control Register flags
 | ||||||
|  | #define CR0_PE		0x00000001	// Protection Enable
 | ||||||
|  | #define CR0_MP		0x00000002	// Monitor coProcessor
 | ||||||
|  | #define CR0_EM		0x00000004	// Emulation
 | ||||||
|  | #define CR0_TS		0x00000008	// Task Switched
 | ||||||
|  | #define CR0_ET		0x00000010	// Extension Type
 | ||||||
|  | #define CR0_NE		0x00000020	// Numeric Errror
 | ||||||
|  | #define CR0_WP		0x00010000	// Write Protect
 | ||||||
|  | #define CR0_AM		0x00040000	// Alignment Mask
 | ||||||
|  | #define CR0_NW		0x20000000	// Not Writethrough
 | ||||||
|  | #define CR0_CD		0x40000000	// Cache Disable
 | ||||||
|  | #define CR0_PG		0x80000000	// Paging
 | ||||||
|  | 
 | ||||||
|  | #define CR4_PCE		0x00000100	// Performance counter enable
 | ||||||
|  | #define CR4_MCE		0x00000040	// Machine Check Enable
 | ||||||
|  | #define CR4_PSE		0x00000010	// Page Size Extensions
 | ||||||
|  | #define CR4_DE		0x00000008	// Debugging Extensions
 | ||||||
|  | #define CR4_TSD		0x00000004	// Time Stamp Disable
 | ||||||
|  | #define CR4_PVI		0x00000002	// Protected-Mode Virtual Interrupts
 | ||||||
|  | #define CR4_VME		0x00000001	// V86 Mode Extensions
 | ||||||
|  | 
 | ||||||
|  | // Eflags register
 | ||||||
|  | #define FL_CF		0x00000001	// Carry Flag
 | ||||||
|  | #define FL_PF		0x00000004	// Parity Flag
 | ||||||
|  | #define FL_AF		0x00000010	// Auxiliary carry Flag
 | ||||||
|  | #define FL_ZF		0x00000040	// Zero Flag
 | ||||||
|  | #define FL_SF		0x00000080	// Sign Flag
 | ||||||
|  | #define FL_TF		0x00000100	// Trap Flag
 | ||||||
|  | #define FL_IF		0x00000200	// Interrupt Flag
 | ||||||
|  | #define FL_DF		0x00000400	// Direction Flag
 | ||||||
|  | #define FL_OF		0x00000800	// Overflow Flag
 | ||||||
|  | #define FL_IOPL_MASK	0x00003000	// I/O Privilege Level bitmask
 | ||||||
|  | #define FL_IOPL_0	0x00000000	//   IOPL == 0
 | ||||||
|  | #define FL_IOPL_1	0x00001000	//   IOPL == 1
 | ||||||
|  | #define FL_IOPL_2	0x00002000	//   IOPL == 2
 | ||||||
|  | #define FL_IOPL_3	0x00003000	//   IOPL == 3
 | ||||||
|  | #define FL_NT		0x00004000	// Nested Task
 | ||||||
|  | #define FL_RF		0x00010000	// Resume Flag
 | ||||||
|  | #define FL_VM		0x00020000	// Virtual 8086 mode
 | ||||||
|  | #define FL_AC		0x00040000	// Alignment Check
 | ||||||
|  | #define FL_VIF		0x00080000	// Virtual Interrupt Flag
 | ||||||
|  | #define FL_VIP		0x00100000	// Virtual Interrupt Pending
 | ||||||
|  | #define FL_ID		0x00200000	// ID flag
 | ||||||
|  | 
 | ||||||
|  | // Page fault error codes
 | ||||||
|  | #define FEC_PR		0x1	// Page fault caused by protection violation
 | ||||||
|  | #define FEC_WR		0x2	// Page fault caused by a write
 | ||||||
|  | #define FEC_U		0x4	// Page fault occured while in user mode
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * | ||||||
|  |  *	Part 2.  Segmentation data structures and constants. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifdef __ASSEMBLER__ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Macros to build GDT entries in assembly. | ||||||
|  |  */ | ||||||
|  | #define SEG_NULL						\ | ||||||
|  | 	.word 0, 0;						\ | ||||||
|  | 	.byte 0, 0, 0, 0 | ||||||
|  | #define SEG(type,base,lim)					\ | ||||||
|  | 	.word (((lim) >> 12) & 0xffff), ((base) & 0xffff);	\ | ||||||
|  | 	.byte (((base) >> 16) & 0xff), (0x90 | (type)),		\ | ||||||
|  | 		(0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) | ||||||
|  | 
 | ||||||
|  | #else	// not __ASSEMBLER__
 | ||||||
|  | 
 | ||||||
|  | // Segment Descriptors
 | ||||||
|  | struct Segdesc { | ||||||
|  | 	unsigned sd_lim_15_0 : 16;  // Low bits of segment limit
 | ||||||
|  | 	unsigned sd_base_15_0 : 16; // Low bits of segment base address
 | ||||||
|  | 	unsigned sd_base_23_16 : 8; // Middle bits of segment base address
 | ||||||
|  | 	unsigned sd_type : 4;       // Segment type (see STS_ constants)
 | ||||||
|  | 	unsigned sd_s : 1;          // 0 = system, 1 = application
 | ||||||
|  | 	unsigned sd_dpl : 2;        // Descriptor Privilege Level
 | ||||||
|  | 	unsigned sd_p : 1;          // Present
 | ||||||
|  | 	unsigned sd_lim_19_16 : 4;  // High bits of segment limit
 | ||||||
|  | 	unsigned sd_avl : 1;        // Unused (available for software use)
 | ||||||
|  | 	unsigned sd_rsv1 : 1;       // Reserved
 | ||||||
|  | 	unsigned sd_db : 1;         // 0 = 16-bit segment, 1 = 32-bit segment
 | ||||||
|  | 	unsigned sd_g : 1;          // Granularity: limit scaled by 4K when set
 | ||||||
|  | 	unsigned sd_base_31_24 : 8; // High bits of segment base address
 | ||||||
|  | }; | ||||||
|  | // Null segment
 | ||||||
|  | #define SEG_NULL	(struct Segdesc){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } | ||||||
|  | // Segment that is loadable but faults when used
 | ||||||
|  | #define SEG_FAULT	(struct Segdesc){ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 } | ||||||
|  | // Normal segment
 | ||||||
|  | #define SEG(type, base, lim, dpl) (struct Segdesc)			\ | ||||||
|  | { ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,	\ | ||||||
|  |     type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,		\ | ||||||
|  |     (unsigned) (base) >> 24 } | ||||||
|  | #define SEG16(type, base, lim, dpl) (struct Segdesc)			\ | ||||||
|  | { (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,		\ | ||||||
|  |     type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0,		\ | ||||||
|  |     (unsigned) (base) >> 24 } | ||||||
|  | 
 | ||||||
|  | #endif /* !__ASSEMBLER__ */ | ||||||
|  | 
 | ||||||
|  | // Application segment type bits
 | ||||||
|  | #define STA_X		0x8	    // Executable segment
 | ||||||
|  | #define STA_E		0x4	    // Expand down (non-executable segments)
 | ||||||
|  | #define STA_C		0x4	    // Conforming code segment (executable only)
 | ||||||
|  | #define STA_W		0x2	    // Writeable (non-executable segments)
 | ||||||
|  | #define STA_R		0x2	    // Readable (executable segments)
 | ||||||
|  | #define STA_A		0x1	    // Accessed
 | ||||||
|  | 
 | ||||||
|  | // System segment type bits
 | ||||||
|  | #define STS_T16A	0x1	    // Available 16-bit TSS
 | ||||||
|  | #define STS_LDT		0x2	    // Local Descriptor Table
 | ||||||
|  | #define STS_T16B	0x3	    // Busy 16-bit TSS
 | ||||||
|  | #define STS_CG16	0x4	    // 16-bit Call Gate
 | ||||||
|  | #define STS_TG		0x5	    // Task Gate / Coum Transmitions
 | ||||||
|  | #define STS_IG16	0x6	    // 16-bit Interrupt Gate
 | ||||||
|  | #define STS_TG16	0x7	    // 16-bit Trap Gate
 | ||||||
|  | #define STS_T32A	0x9	    // Available 32-bit TSS
 | ||||||
|  | #define STS_T32B	0xB	    // Busy 32-bit TSS
 | ||||||
|  | #define STS_CG32	0xC	    // 32-bit Call Gate
 | ||||||
|  | #define STS_IG32	0xE	    // 32-bit Interrupt Gate
 | ||||||
|  | #define STS_TG32	0xF	    // 32-bit Trap Gate
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * | ||||||
|  |  *	Part 3.  Traps. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __ASSEMBLER__ | ||||||
|  | 
 | ||||||
|  | // Task state segment format (as described by the Pentium architecture book)
 | ||||||
|  | struct Taskstate { | ||||||
|  | 	uint32_t ts_link;	// Old ts selector
 | ||||||
|  | 	uintptr_t ts_esp0;	// Stack pointers and segment selectors
 | ||||||
|  | 	uint16_t ts_ss0;	//   after an increase in privilege level
 | ||||||
|  | 	uint16_t ts_padding1; | ||||||
|  | 	uintptr_t ts_esp1; | ||||||
|  | 	uint16_t ts_ss1; | ||||||
|  | 	uint16_t ts_padding2; | ||||||
|  | 	uintptr_t ts_esp2; | ||||||
|  | 	uint16_t ts_ss2; | ||||||
|  | 	uint16_t ts_padding3; | ||||||
|  | 	physaddr_t ts_cr3;	// Page directory base
 | ||||||
|  | 	uintptr_t ts_eip;	// Saved state from last task switch
 | ||||||
|  | 	uint32_t ts_eflags; | ||||||
|  | 	uint32_t ts_eax;	// More saved state (registers)
 | ||||||
|  | 	uint32_t ts_ecx; | ||||||
|  | 	uint32_t ts_edx; | ||||||
|  | 	uint32_t ts_ebx; | ||||||
|  | 	uintptr_t ts_esp; | ||||||
|  | 	uintptr_t ts_ebp; | ||||||
|  | 	uint32_t ts_esi; | ||||||
|  | 	uint32_t ts_edi; | ||||||
|  | 	uint16_t ts_es;		// Even more saved state (segment selectors)
 | ||||||
|  | 	uint16_t ts_padding4; | ||||||
|  | 	uint16_t ts_cs; | ||||||
|  | 	uint16_t ts_padding5; | ||||||
|  | 	uint16_t ts_ss; | ||||||
|  | 	uint16_t ts_padding6; | ||||||
|  | 	uint16_t ts_ds; | ||||||
|  | 	uint16_t ts_padding7; | ||||||
|  | 	uint16_t ts_fs; | ||||||
|  | 	uint16_t ts_padding8; | ||||||
|  | 	uint16_t ts_gs; | ||||||
|  | 	uint16_t ts_padding9; | ||||||
|  | 	uint16_t ts_ldt; | ||||||
|  | 	uint16_t ts_padding10; | ||||||
|  | 	uint16_t ts_t;		// Trap on task switch
 | ||||||
|  | 	uint16_t ts_iomb;	// I/O map base address
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Gate descriptors for interrupts and traps
 | ||||||
|  | struct Gatedesc { | ||||||
|  | 	unsigned gd_off_15_0 : 16;   // low 16 bits of offset in segment
 | ||||||
|  | 	unsigned gd_ss : 16;         // segment selector
 | ||||||
|  | 	unsigned gd_args : 5;        // # args, 0 for interrupt/trap gates
 | ||||||
|  | 	unsigned gd_rsv1 : 3;        // reserved(should be zero I guess)
 | ||||||
|  | 	unsigned gd_type : 4;        // type(STS_{TG,IG32,TG32})
 | ||||||
|  | 	unsigned gd_s : 1;           // must be 0 (system)
 | ||||||
|  | 	unsigned gd_dpl : 2;         // descriptor(meaning new) privilege level
 | ||||||
|  | 	unsigned gd_p : 1;           // Present
 | ||||||
|  | 	unsigned gd_off_31_16 : 16;  // high bits of offset in segment
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Set up a normal interrupt/trap gate descriptor.
 | ||||||
|  | // - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
 | ||||||
|  | // - sel: Code segment selector for interrupt/trap handler
 | ||||||
|  | // - off: Offset in code segment for interrupt/trap handler
 | ||||||
|  | // - dpl: Descriptor Privilege Level -
 | ||||||
|  | //	  the privilege level required for software to invoke
 | ||||||
|  | //	  this interrupt/trap gate explicitly using an int instruction.
 | ||||||
|  | #define SETGATE(gate, istrap, sel, off, dpl)			\ | ||||||
|  | {								\ | ||||||
|  | 	(gate).gd_off_15_0 = (uint32_t) (off) & 0xffff;		\ | ||||||
|  | 	(gate).gd_ss = (sel);					\ | ||||||
|  | 	(gate).gd_args = 0;					\ | ||||||
|  | 	(gate).gd_rsv1 = 0;					\ | ||||||
|  | 	(gate).gd_type = (istrap) ? STS_TG32 : STS_IG32;	\ | ||||||
|  | 	(gate).gd_s = 0;					\ | ||||||
|  | 	(gate).gd_dpl = (dpl);					\ | ||||||
|  | 	(gate).gd_p = 1;					\ | ||||||
|  | 	(gate).gd_off_31_16 = (uint32_t) (off) >> 16;		\ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Set up a call gate descriptor.
 | ||||||
|  | #define SETCALLGATE(gate, ss, off, dpl)           	        \ | ||||||
|  | {								\ | ||||||
|  | 	(gate).gd_off_15_0 = (uint32_t) (off) & 0xffff;		\ | ||||||
|  | 	(gate).gd_ss = (ss);					\ | ||||||
|  | 	(gate).gd_args = 0;					\ | ||||||
|  | 	(gate).gd_rsv1 = 0;					\ | ||||||
|  | 	(gate).gd_type = STS_CG32;				\ | ||||||
|  | 	(gate).gd_s = 0;					\ | ||||||
|  | 	(gate).gd_dpl = (dpl);					\ | ||||||
|  | 	(gate).gd_p = 1;					\ | ||||||
|  | 	(gate).gd_off_31_16 = (uint32_t) (off) >> 16;		\ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Pseudo-descriptors used for LGDT, LLDT and LIDT instructions.
 | ||||||
|  | struct Pseudodesc { | ||||||
|  | 	uint16_t pd__garbage;         // LGDT supposed to be from address 4N+2
 | ||||||
|  | 	uint16_t pd_lim;              // Limit
 | ||||||
|  | 	uint32_t pd_base __attribute__ ((packed));       // Base address
 | ||||||
|  | }; | ||||||
|  | #define PD_ADDR(desc)	(&(desc).pd_lim) | ||||||
|  | 
 | ||||||
|  | #endif /* !__ASSEMBLER__ */ | ||||||
|  | 
 | ||||||
							
								
								
									
										3
									
								
								param.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								param.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | #define NPROC 64 | ||||||
|  | #define PAGE 4096 | ||||||
|  | #define KSTACKSIZE PAGE | ||||||
							
								
								
									
										112
									
								
								proc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								proc.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | ||||||
|  | #include "types.h" | ||||||
|  | #include "mmu.h" | ||||||
|  | #include "x86.h" | ||||||
|  | #include "proc.h" | ||||||
|  | #include "param.h" | ||||||
|  | #include "defs.h" | ||||||
|  | 
 | ||||||
|  | struct proc proc[NPROC]; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * set up a process's task state and segment descriptors | ||||||
|  |  * correctly, given its current size and address in memory. | ||||||
|  |  * this should be called whenever the latter change. | ||||||
|  |  * doesn't change the cpu's current segmentation setup. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | setupsegs(struct proc *p) | ||||||
|  | { | ||||||
|  |   memset(&p->ts, 0, sizeof(struct Taskstate)); | ||||||
|  |   p->ts.ts_ss0 = SEG_KDATA << 3; | ||||||
|  |   p->ts.ts_esp0 = (unsigned)(p->kstack + KSTACKSIZE); | ||||||
|  | 
 | ||||||
|  |   memset(&p->gdt, 0, sizeof(p->gdt)); | ||||||
|  |   p->gdt[0] = SEG_NULL; | ||||||
|  |   p->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0); | ||||||
|  |   p->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); | ||||||
|  |   p->gdt[SEG_TSS] = SEG16(STS_T32A, (unsigned) &p->ts, sizeof(p->ts), 0); | ||||||
|  |   p->gdt[SEG_TSS].sd_s = 0; | ||||||
|  |   p->gdt[SEG_UCODE] = SEG(STA_X|STA_R, (unsigned)p->mem, p->sz, 3); | ||||||
|  |   p->gdt[SEG_UDATA] = SEG(STA_W, (unsigned)p->mem, p->sz, 3); | ||||||
|  |   p->gdt_pd.pd__garbage = 0; | ||||||
|  |   p->gdt_pd.pd_lim = sizeof(p->gdt) - 1; | ||||||
|  |   p->gdt_pd.pd_base = (unsigned) p->gdt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extern void trapret(); | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * internal fork(). does not copy kernel stack; instead, | ||||||
|  |  * sets up the stack to return as if from system call. | ||||||
|  |  */ | ||||||
|  | struct proc * | ||||||
|  | newproc(struct proc *op) | ||||||
|  | { | ||||||
|  |   struct proc *np; | ||||||
|  |   unsigned *sp; | ||||||
|  | 
 | ||||||
|  |   for(np = &proc[1]; np < &proc[NPROC]; np++) | ||||||
|  |     if(np->state == UNUSED) | ||||||
|  |       break; | ||||||
|  |   if(np >= &proc[NPROC]) | ||||||
|  |     return 0; | ||||||
|  | 
 | ||||||
|  |   np->sz = op->sz; | ||||||
|  |   np->mem = kalloc(op->sz); | ||||||
|  |   if(np->mem == 0) | ||||||
|  |     return 0; | ||||||
|  |   memcpy(np->mem, op->mem, np->sz); | ||||||
|  |   np->kstack = kalloc(KSTACKSIZE); | ||||||
|  |   if(np->kstack == 0){ | ||||||
|  |     kfree(np->mem, op->sz); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   np->tf = (struct Trapframe *) (np->kstack + KSTACKSIZE - sizeof(struct Trapframe)); | ||||||
|  |   setupsegs(np); | ||||||
|  |   np->state = RUNNABLE; | ||||||
|  |    | ||||||
|  |   // set up kernel stack to return to user space
 | ||||||
|  |   *(np->tf) = *(op->tf); | ||||||
|  |   sp = (unsigned *) np->tf; | ||||||
|  |   *(--sp) = (unsigned) &trapret;  // for return from swtch()
 | ||||||
|  |   *(--sp) = 0;  // previous bp for leave in swtch()
 | ||||||
|  |   np->esp = (unsigned) sp; | ||||||
|  |   np->ebp = (unsigned) sp; | ||||||
|  | 
 | ||||||
|  |   cprintf("esp %x ebp %x mem %x\n", np->esp, np->ebp, np->mem); | ||||||
|  | 
 | ||||||
|  |   return np; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * find a runnable process and switch to it. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | swtch(struct proc *op) | ||||||
|  | { | ||||||
|  |   struct proc *np; | ||||||
|  |    | ||||||
|  |   while(1){ | ||||||
|  |     for(np = op + 1; np != op; np++){ | ||||||
|  |       if(np == &proc[NPROC]) | ||||||
|  |         np = &proc[0]; | ||||||
|  |       if(np->state == RUNNABLE) | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     if(np->state == RUNNABLE) | ||||||
|  |       break; | ||||||
|  |     // idle...
 | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   op->ebp = read_ebp(); | ||||||
|  |   op->esp = read_esp(); | ||||||
|  | 
 | ||||||
|  |   // XXX callee-saved registers?
 | ||||||
|  | 
 | ||||||
|  |   // this happens to work, but probably isn't safe:
 | ||||||
|  |   // it's not clear that np->ebp will evaluate
 | ||||||
|  |   // correctly after changing the stack pointer.
 | ||||||
|  |   asm volatile("lgdt %0" : : "g" (np->gdt_pd.pd_lim)); | ||||||
|  |   asm volatile("movl %0, %%esp" : : "g" (np->esp)); | ||||||
|  |   asm volatile("movl %0, %%ebp" : : "g" (np->ebp)); | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								proc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								proc.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | /*
 | ||||||
|  |  * p->mem: | ||||||
|  |  *   text | ||||||
|  |  *   original data and bss | ||||||
|  |  *   fixed-size stack | ||||||
|  |  *   expandable heap | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * segments in proc->gdt | ||||||
|  |  */ | ||||||
|  | #define SEG_KCODE 1 // kernel code
 | ||||||
|  | #define SEG_KDATA 2 // kernel data+stack
 | ||||||
|  | #define SEG_UCODE 3 | ||||||
|  | #define SEG_UDATA 4 | ||||||
|  | #define SEG_TSS 5   // this process's task state
 | ||||||
|  | #define NSEGS 6 | ||||||
|  | 
 | ||||||
|  | struct proc{ | ||||||
|  |   char *mem; // start of process's physical memory
 | ||||||
|  |   unsigned sz; // total size of mem, including kernel stack
 | ||||||
|  |   char *kstack; // kernel stack, separate from mem so it doesn't move
 | ||||||
|  |   enum { UNUSED, RUNNABLE, WAITING } state; | ||||||
|  | 
 | ||||||
|  |   struct Taskstate ts;  // only to give cpu address of kernel stack
 | ||||||
|  |   struct Segdesc gdt[NSEGS]; | ||||||
|  |   struct Pseudodesc gdt_pd; | ||||||
|  |   unsigned esp; // kernel stack pointer
 | ||||||
|  |   unsigned ebp; // kernel frame pointer
 | ||||||
|  | 
 | ||||||
|  |   struct Trapframe *tf; // points into kstack, used to find user regs
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | extern struct proc proc[]; | ||||||
							
								
								
									
										19
									
								
								sign.pl
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										19
									
								
								sign.pl
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | #!/usr/bin/perl | ||||||
|  | 
 | ||||||
|  | open(SIG, $ARGV[0]) || die "open $ARGV[0]: $!"; | ||||||
|  | 
 | ||||||
|  | $n = sysread(SIG, $buf, 1000); | ||||||
|  | 
 | ||||||
|  | if($n > 510){ | ||||||
|  | 	print STDERR "boot block too large: $n bytes (max 510)\n"; | ||||||
|  | 	exit 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | print STDERR "boot block is $n bytes (max 510)\n"; | ||||||
|  | 
 | ||||||
|  | $buf .= "\0" x (510-$n); | ||||||
|  | $buf .= "\x55\xAA"; | ||||||
|  | 
 | ||||||
|  | open(SIG, ">$ARGV[0]") || die "open >$ARGV[0]: $!"; | ||||||
|  | print SIG $buf; | ||||||
|  | close SIG; | ||||||
							
								
								
									
										22
									
								
								string.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								string.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | void * | ||||||
|  | memcpy(void *dst, void *src, unsigned n) | ||||||
|  | { | ||||||
|  |   char *d = (char *) dst; | ||||||
|  |   char *s = (char *) src; | ||||||
|  | 
 | ||||||
|  |   while(n-- > 0) | ||||||
|  |     *d++ = *s++; | ||||||
|  | 
 | ||||||
|  |   return dst; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void * | ||||||
|  | memset(void *dst, int c, unsigned n) | ||||||
|  | { | ||||||
|  |   char *d = (char *) dst; | ||||||
|  | 
 | ||||||
|  |   while(n-- > 0) | ||||||
|  |     *d++ = c; | ||||||
|  | 
 | ||||||
|  |   return dst; | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								trapasm.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								trapasm.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | 	.text | ||||||
|  |         .globl trapret
 | ||||||
|  | 	/* | ||||||
|  |          * a forked process RETs here | ||||||
|  |          * expects ESP to point to a Trapframe | ||||||
|  |          */ | ||||||
|  | trapret: | ||||||
|  |         popal | ||||||
|  |         popl %es | ||||||
|  |         popl %ds | ||||||
|  |         addl $0x8, %esp /* trapno and errcode */ | ||||||
|  |         iret | ||||||
							
								
								
									
										6
									
								
								types.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								types.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | typedef unsigned long long uint64_t; | ||||||
|  | typedef unsigned int uint32_t; | ||||||
|  | typedef unsigned short uint16_t; | ||||||
|  | typedef unsigned char uint8_t; | ||||||
|  | typedef uint32_t uintptr_t; | ||||||
|  | typedef uint32_t physaddr_t; | ||||||
							
								
								
									
										301
									
								
								x86.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								x86.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,301 @@ | ||||||
|  | static __inline void breakpoint(void) __attribute__((always_inline)); | ||||||
|  | static __inline uint8_t inb(int port) __attribute__((always_inline)); | ||||||
|  | static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline)); | ||||||
|  | static __inline uint16_t inw(int port) __attribute__((always_inline)); | ||||||
|  | static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline)); | ||||||
|  | static __inline uint32_t inl(int port) __attribute__((always_inline)); | ||||||
|  | static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline)); | ||||||
|  | static __inline void outb(int port, uint8_t data) __attribute__((always_inline)); | ||||||
|  | static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline)); | ||||||
|  | static __inline void outw(int port, uint16_t data) __attribute__((always_inline)); | ||||||
|  | static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline)); | ||||||
|  | static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline)); | ||||||
|  | static __inline void outl(int port, uint32_t data) __attribute__((always_inline)); | ||||||
|  | static __inline void invlpg(void *addr) __attribute__((always_inline)); | ||||||
|  | static __inline void lidt(void *p) __attribute__((always_inline)); | ||||||
|  | static __inline void lldt(uint16_t sel) __attribute__((always_inline)); | ||||||
|  | static __inline void ltr(uint16_t sel) __attribute__((always_inline)); | ||||||
|  | static __inline void lcr0(uint32_t val) __attribute__((always_inline)); | ||||||
|  | static __inline uint32_t rcr0(void) __attribute__((always_inline)); | ||||||
|  | static __inline uint32_t rcr2(void) __attribute__((always_inline)); | ||||||
|  | static __inline void lcr3(uint32_t val) __attribute__((always_inline)); | ||||||
|  | static __inline uint32_t rcr3(void) __attribute__((always_inline)); | ||||||
|  | static __inline void lcr4(uint32_t val) __attribute__((always_inline)); | ||||||
|  | static __inline uint32_t rcr4(void) __attribute__((always_inline)); | ||||||
|  | static __inline void tlbflush(void) __attribute__((always_inline)); | ||||||
|  | static __inline uint32_t read_eflags(void) __attribute__((always_inline)); | ||||||
|  | static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline)); | ||||||
|  | static __inline uint32_t read_ebp(void) __attribute__((always_inline)); | ||||||
|  | static __inline uint32_t read_esp(void) __attribute__((always_inline)); | ||||||
|  | static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp); | ||||||
|  | static __inline uint64_t read_tsc(void) __attribute__((always_inline)); | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | breakpoint(void) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("int3"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint8_t | ||||||
|  | inb(int port) | ||||||
|  | { | ||||||
|  | 	uint8_t data; | ||||||
|  | 	__asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port)); | ||||||
|  | 	return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | insb(int port, void *addr, int cnt) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("cld\n\trepne\n\tinsb"			: | ||||||
|  | 			 "=D" (addr), "=c" (cnt)		: | ||||||
|  | 			 "d" (port), "0" (addr), "1" (cnt)	: | ||||||
|  | 			 "memory", "cc"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint16_t | ||||||
|  | inw(int port) | ||||||
|  | { | ||||||
|  | 	uint16_t data; | ||||||
|  | 	__asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port)); | ||||||
|  | 	return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | insw(int port, void *addr, int cnt) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("cld\n\trepne\n\tinsw"			: | ||||||
|  | 			 "=D" (addr), "=c" (cnt)		: | ||||||
|  | 			 "d" (port), "0" (addr), "1" (cnt)	: | ||||||
|  | 			 "memory", "cc"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint32_t | ||||||
|  | inl(int port) | ||||||
|  | { | ||||||
|  | 	uint32_t data; | ||||||
|  | 	__asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port)); | ||||||
|  | 	return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | insl(int port, void *addr, int cnt) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("cld\n\trepne\n\tinsl"			: | ||||||
|  | 			 "=D" (addr), "=c" (cnt)		: | ||||||
|  | 			 "d" (port), "0" (addr), "1" (cnt)	: | ||||||
|  | 			 "memory", "cc"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | outb(int port, uint8_t data) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("outb %0,%w1" : : "a" (data), "d" (port)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | outsb(int port, const void *addr, int cnt) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("cld\n\trepne\n\toutsb"		: | ||||||
|  | 			 "=S" (addr), "=c" (cnt)		: | ||||||
|  | 			 "d" (port), "0" (addr), "1" (cnt)	: | ||||||
|  | 			 "cc"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | outw(int port, uint16_t data) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("outw %0,%w1" : : "a" (data), "d" (port)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | outsw(int port, const void *addr, int cnt) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("cld\n\trepne\n\toutsw"		: | ||||||
|  | 			 "=S" (addr), "=c" (cnt)		: | ||||||
|  | 			 "d" (port), "0" (addr), "1" (cnt)	: | ||||||
|  | 			 "cc"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | outsl(int port, const void *addr, int cnt) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("cld\n\trepne\n\toutsl"		: | ||||||
|  | 			 "=S" (addr), "=c" (cnt)		: | ||||||
|  | 			 "d" (port), "0" (addr), "1" (cnt)	: | ||||||
|  | 			 "cc"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | outl(int port, uint32_t data) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("outl %0,%w1" : : "a" (data), "d" (port)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void  | ||||||
|  | invlpg(void *addr) | ||||||
|  | {  | ||||||
|  | 	__asm __volatile("invlpg (%0)" : : "r" (addr) : "memory"); | ||||||
|  | }   | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | lidt(void *p) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("lidt (%0)" : : "r" (p)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | lldt(uint16_t sel) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("lldt %0" : : "r" (sel)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | ltr(uint16_t sel) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("ltr %0" : : "r" (sel)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | lcr0(uint32_t val) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("movl %0,%%cr0" : : "r" (val)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint32_t | ||||||
|  | rcr0(void) | ||||||
|  | { | ||||||
|  | 	uint32_t val; | ||||||
|  | 	__asm __volatile("movl %%cr0,%0" : "=r" (val)); | ||||||
|  | 	return val; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint32_t | ||||||
|  | rcr2(void) | ||||||
|  | { | ||||||
|  | 	uint32_t val; | ||||||
|  | 	__asm __volatile("movl %%cr2,%0" : "=r" (val)); | ||||||
|  | 	return val; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | lcr3(uint32_t val) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("movl %0,%%cr3" : : "r" (val)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint32_t | ||||||
|  | rcr3(void) | ||||||
|  | { | ||||||
|  | 	uint32_t val; | ||||||
|  | 	__asm __volatile("movl %%cr3,%0" : "=r" (val)); | ||||||
|  | 	return val; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | lcr4(uint32_t val) | ||||||
|  | { | ||||||
|  | 	__asm __volatile("movl %0,%%cr4" : : "r" (val)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint32_t | ||||||
|  | rcr4(void) | ||||||
|  | { | ||||||
|  | 	uint32_t cr4; | ||||||
|  | 	__asm __volatile("movl %%cr4,%0" : "=r" (cr4)); | ||||||
|  | 	return cr4; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | tlbflush(void) | ||||||
|  | { | ||||||
|  | 	uint32_t cr3; | ||||||
|  | 	__asm __volatile("movl %%cr3,%0" : "=r" (cr3)); | ||||||
|  | 	__asm __volatile("movl %0,%%cr3" : : "r" (cr3)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint32_t | ||||||
|  | read_eflags(void) | ||||||
|  | { | ||||||
|  |         uint32_t eflags; | ||||||
|  |         __asm __volatile("pushfl; popl %0" : "=r" (eflags)); | ||||||
|  |         return eflags; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | write_eflags(uint32_t eflags) | ||||||
|  | { | ||||||
|  |         __asm __volatile("pushl %0; popfl" : : "r" (eflags)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint32_t | ||||||
|  | read_ebp(void) | ||||||
|  | { | ||||||
|  |         uint32_t ebp; | ||||||
|  |         __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); | ||||||
|  |         return ebp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint32_t | ||||||
|  | read_esp(void) | ||||||
|  | { | ||||||
|  |         uint32_t esp; | ||||||
|  |         __asm __volatile("movl %%esp,%0" : "=r" (esp)); | ||||||
|  |         return esp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline void | ||||||
|  | cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp) | ||||||
|  | { | ||||||
|  | 	uint32_t eax, ebx, ecx, edx; | ||||||
|  | 	asm volatile("cpuid"  | ||||||
|  | 		: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) | ||||||
|  | 		: "a" (info)); | ||||||
|  | 	if (eaxp) | ||||||
|  | 		*eaxp = eax; | ||||||
|  | 	if (ebxp) | ||||||
|  | 		*ebxp = ebx; | ||||||
|  | 	if (ecxp) | ||||||
|  | 		*ecxp = ecx; | ||||||
|  | 	if (edxp) | ||||||
|  | 		*edxp = edx; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline uint64_t | ||||||
|  | read_tsc(void) | ||||||
|  | { | ||||||
|  |         uint64_t tsc; | ||||||
|  |         __asm __volatile("rdtsc" : "=A" (tsc)); | ||||||
|  |         return tsc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct PushRegs { | ||||||
|  |     /* registers as pushed by pusha */ | ||||||
|  |     uint32_t reg_edi; | ||||||
|  |     uint32_t reg_esi; | ||||||
|  |     uint32_t reg_ebp; | ||||||
|  |     uint32_t reg_oesp;      /* Useless */ | ||||||
|  |     uint32_t reg_ebx; | ||||||
|  |     uint32_t reg_edx; | ||||||
|  |     uint32_t reg_ecx; | ||||||
|  |     uint32_t reg_eax; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Trapframe { | ||||||
|  |     struct PushRegs tf_regs; | ||||||
|  |     uint16_t tf_es; | ||||||
|  |     uint16_t tf_padding1; | ||||||
|  |     uint16_t tf_ds; | ||||||
|  |     uint16_t tf_padding2; | ||||||
|  |     uint32_t tf_trapno; | ||||||
|  |     /* below here defined by x86 hardware */ | ||||||
|  |     uint32_t tf_err; | ||||||
|  |     uintptr_t tf_eip; | ||||||
|  |     uint16_t tf_cs; | ||||||
|  |     uint16_t tf_padding3; | ||||||
|  |     uint32_t tf_eflags; | ||||||
|  |     /* below here only when crossing rings, such as from user to kernel */ | ||||||
|  |     uintptr_t tf_esp; | ||||||
|  |     uint16_t tf_ss; | ||||||
|  |     uint16_t tf_padding4; | ||||||
|  | }; | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 rtm
						rtm