add exercise of lab5 spoc discussion
This commit is contained in:
		
							parent
							
								
									331b8dff5a
								
							
						
					
					
						commit
						f39299c9a2
					
				
							
								
								
									
										328
									
								
								related_info/lab5/lab5-spoc-discuss/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										328
									
								
								related_info/lab5/lab5-spoc-discuss/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,328 @@
 | 
				
			|||||||
 | 
					PROJ	:= 5
 | 
				
			||||||
 | 
					EMPTY	:=
 | 
				
			||||||
 | 
					SPACE	:= $(EMPTY) $(EMPTY)
 | 
				
			||||||
 | 
					SLASH	:= /
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					V       := @
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# try to infer the correct GCCPREFX
 | 
				
			||||||
 | 
					ifndef GCCPREFIX
 | 
				
			||||||
 | 
					GCCPREFIX := $(shell if i386-ucore-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
 | 
				
			||||||
 | 
						then echo 'i386-ucore-elf-'; \
 | 
				
			||||||
 | 
						elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \
 | 
				
			||||||
 | 
						then echo ''; \
 | 
				
			||||||
 | 
						else echo "***" 1>&2; \
 | 
				
			||||||
 | 
						echo "*** Error: Couldn't find an i386-ucore-elf version of GCC/binutils." 1>&2; \
 | 
				
			||||||
 | 
						echo "*** Is the directory with i386-ucore-elf-gcc in your PATH?" 1>&2; \
 | 
				
			||||||
 | 
						echo "*** If your i386-ucore-elf toolchain is installed with a command" 1>&2; \
 | 
				
			||||||
 | 
						echo "*** prefix other than 'i386-ucore-elf-', set your GCCPREFIX" 1>&2; \
 | 
				
			||||||
 | 
						echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
 | 
				
			||||||
 | 
						echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \
 | 
				
			||||||
 | 
						echo "***" 1>&2; exit 1; fi)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# try to infer the correct QEMU
 | 
				
			||||||
 | 
					ifndef QEMU
 | 
				
			||||||
 | 
					QEMU := $(shell if which qemu-system-i386 > /dev/null; \
 | 
				
			||||||
 | 
						then echo 'qemu-system-i386'; exit; \
 | 
				
			||||||
 | 
						elif which i386-ucore-elf-qemu > /dev/null; \
 | 
				
			||||||
 | 
						then echo 'i386-ucore-elf-qemu'; exit; \
 | 
				
			||||||
 | 
						else \
 | 
				
			||||||
 | 
						echo "***" 1>&2; \
 | 
				
			||||||
 | 
						echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \
 | 
				
			||||||
 | 
						echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \
 | 
				
			||||||
 | 
						echo "***" 1>&2; exit 1; fi)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# eliminate default suffix rules
 | 
				
			||||||
 | 
					.SUFFIXES: .c .S .h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# delete target files if there is an error (or make is interrupted)
 | 
				
			||||||
 | 
					.DELETE_ON_ERROR:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define compiler and flags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HOSTCC		:= gcc
 | 
				
			||||||
 | 
					HOSTCFLAGS	:= -g -Wall -O2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GDB		:= $(GCCPREFIX)gdb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CC		?= $(GCCPREFIX)gcc
 | 
				
			||||||
 | 
					CFLAGS	:= -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc $(DEFS)
 | 
				
			||||||
 | 
					CFLAGS	+= $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
 | 
				
			||||||
 | 
					CTYPE	:= c S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LD      := $(GCCPREFIX)ld
 | 
				
			||||||
 | 
					LDFLAGS	:= -m $(shell $(LD) -V | grep elf_i386 2>/dev/null)
 | 
				
			||||||
 | 
					LDFLAGS	+= -nostdlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OBJCOPY := $(GCCPREFIX)objcopy
 | 
				
			||||||
 | 
					OBJDUMP := $(GCCPREFIX)objdump
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY	:= cp
 | 
				
			||||||
 | 
					MKDIR   := mkdir -p
 | 
				
			||||||
 | 
					MV		:= mv
 | 
				
			||||||
 | 
					RM		:= rm -f
 | 
				
			||||||
 | 
					AWK		:= awk
 | 
				
			||||||
 | 
					SED		:= sed
 | 
				
			||||||
 | 
					SH		:= sh
 | 
				
			||||||
 | 
					TR		:= tr
 | 
				
			||||||
 | 
					TOUCH	:= touch -c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OBJDIR	:= obj
 | 
				
			||||||
 | 
					BINDIR	:= bin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALLOBJS	:=
 | 
				
			||||||
 | 
					ALLDEPS	:=
 | 
				
			||||||
 | 
					TARGETS	:=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include tools/function.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					listf_cc = $(call listf,$(1),$(CTYPE))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USER_PREFIX	:= __user_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# for cc
 | 
				
			||||||
 | 
					add_files_cc = $(call add_files,$(1),$(CC),$(CFLAGS) $(3),$(2),$(4))
 | 
				
			||||||
 | 
					create_target_cc = $(call create_target,$(1),$(2),$(3),$(CC),$(CFLAGS))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# for hostcc
 | 
				
			||||||
 | 
					add_files_host = $(call add_files,$(1),$(HOSTCC),$(HOSTCFLAGS),$(2),$(3))
 | 
				
			||||||
 | 
					create_target_host = $(call create_target,$(1),$(2),$(3),$(HOSTCC),$(HOSTCFLAGS))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cgtype = $(patsubst %.$(2),%.$(3),$(1))
 | 
				
			||||||
 | 
					objfile = $(call toobj,$(1))
 | 
				
			||||||
 | 
					asmfile = $(call cgtype,$(call toobj,$(1)),o,asm)
 | 
				
			||||||
 | 
					outfile = $(call cgtype,$(call toobj,$(1)),o,out)
 | 
				
			||||||
 | 
					symfile = $(call cgtype,$(call toobj,$(1)),o,sym)
 | 
				
			||||||
 | 
					filename = $(basename $(notdir $(1)))
 | 
				
			||||||
 | 
					ubinfile = $(call outfile,$(addprefix $(USER_PREFIX),$(call filename,$(1))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# for match pattern
 | 
				
			||||||
 | 
					match = $(shell echo $(2) | $(AWK) '{for(i=1;i<=NF;i++){if(match("$(1)","^"$$(i)"$$")){exit 1;}}}'; echo $$?)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
				
			||||||
 | 
					# include kernel/user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INCLUDE	+= libs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFLAGS	+= $(addprefix -I,$(INCLUDE))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBDIR	+= libs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call add_files_cc,$(call listf_cc,$(LIBDIR)),libs,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -------------------------------------------------------------------
 | 
				
			||||||
 | 
					# user programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UINCLUDE	+= user/include/ \
 | 
				
			||||||
 | 
								   user/libs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USRCDIR		+= user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ULIBDIR		+= user/libs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UCFLAGS		+= $(addprefix -I,$(UINCLUDE))
 | 
				
			||||||
 | 
					USER_BINS	:=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call add_files_cc,$(call listf_cc,$(ULIBDIR)),ulibs,$(UCFLAGS))
 | 
				
			||||||
 | 
					$(call add_files_cc,$(call listf_cc,$(USRCDIR)),uprog,$(UCFLAGS))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UOBJS	:= $(call read_packet,ulibs libs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					define uprog_ld
 | 
				
			||||||
 | 
					__user_bin__ := $$(call ubinfile,$(1))
 | 
				
			||||||
 | 
					USER_BINS += $$(__user_bin__)
 | 
				
			||||||
 | 
					$$(__user_bin__): tools/user.ld
 | 
				
			||||||
 | 
					$$(__user_bin__): $$(UOBJS)
 | 
				
			||||||
 | 
					$$(__user_bin__): $(1) | $$$$(dir $$$$@)
 | 
				
			||||||
 | 
						$(V)$(LD) $(LDFLAGS) -T tools/user.ld -o $$@ $$(UOBJS) $(1)
 | 
				
			||||||
 | 
						@$(OBJDUMP) -S $$@ > $$(call cgtype,$$<,o,asm)
 | 
				
			||||||
 | 
						@$(OBJDUMP) -t $$@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$$$/d' > $$(call cgtype,$$<,o,sym)
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(foreach p,$(call read_packet,uprog),$(eval $(call uprog_ld,$(p))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -------------------------------------------------------------------
 | 
				
			||||||
 | 
					# kernel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					KINCLUDE	+= kern/debug/ \
 | 
				
			||||||
 | 
								   kern/driver/ \
 | 
				
			||||||
 | 
								   kern/trap/ \
 | 
				
			||||||
 | 
								   kern/mm/ \
 | 
				
			||||||
 | 
								   kern/libs/ \
 | 
				
			||||||
 | 
								   kern/sync/ \
 | 
				
			||||||
 | 
								   kern/fs/    \
 | 
				
			||||||
 | 
								   kern/process \
 | 
				
			||||||
 | 
								   kern/schedule \
 | 
				
			||||||
 | 
								   kern/syscall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					KSRCDIR		+= kern/init \
 | 
				
			||||||
 | 
								   kern/libs \
 | 
				
			||||||
 | 
								   kern/debug \
 | 
				
			||||||
 | 
								   kern/driver \
 | 
				
			||||||
 | 
								   kern/trap \
 | 
				
			||||||
 | 
								   kern/mm \
 | 
				
			||||||
 | 
								   kern/sync \
 | 
				
			||||||
 | 
								   kern/fs    \
 | 
				
			||||||
 | 
								   kern/process \
 | 
				
			||||||
 | 
								   kern/schedule \
 | 
				
			||||||
 | 
								   kern/syscall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					KCFLAGS		+= $(addprefix -I,$(KINCLUDE))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					KOBJS	= $(call read_packet,kernel libs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# create kernel target
 | 
				
			||||||
 | 
					kernel = $(call totarget,kernel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(kernel): tools/kernel.ld
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(kernel): $(KOBJS) $(USER_BINS)
 | 
				
			||||||
 | 
						@echo + ld $@
 | 
				
			||||||
 | 
						$(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS) -b binary $(USER_BINS)
 | 
				
			||||||
 | 
						@$(OBJDUMP) -S $@ > $(call asmfile,kernel)
 | 
				
			||||||
 | 
						@$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call create_target,kernel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# create bootblock
 | 
				
			||||||
 | 
					bootfiles = $(call listf_cc,boot)
 | 
				
			||||||
 | 
					$(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bootblock = $(call totarget,bootblock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(bootblock): $(call toobj,boot/bootasm.S) $(call toobj,$(bootfiles)) | $(call totarget,sign)
 | 
				
			||||||
 | 
						@echo + ld $@
 | 
				
			||||||
 | 
						$(V)$(LD) $(LDFLAGS) -N -T tools/boot.ld $^ -o $(call toobj,bootblock)
 | 
				
			||||||
 | 
						@$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)
 | 
				
			||||||
 | 
						@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
 | 
				
			||||||
 | 
						@$(call totarget,sign) $(call outfile,bootblock) $(bootblock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call create_target,bootblock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# create 'sign' tools
 | 
				
			||||||
 | 
					$(call add_files_host,tools/sign.c,sign,sign)
 | 
				
			||||||
 | 
					$(call create_target_host,sign,sign)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# create ucore.img
 | 
				
			||||||
 | 
					UCOREIMG	:= $(call totarget,ucore.img)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(UCOREIMG): $(kernel) $(bootblock)
 | 
				
			||||||
 | 
						$(V)dd if=/dev/zero of=$@ count=10000
 | 
				
			||||||
 | 
						$(V)dd if=$(bootblock) of=$@ conv=notrunc
 | 
				
			||||||
 | 
						$(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call create_target,ucore.img)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# create swap.img
 | 
				
			||||||
 | 
					SWAPIMG		:= $(call totarget,swap.img)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(SWAPIMG):
 | 
				
			||||||
 | 
						$(V)dd if=/dev/zero of=$@ bs=1M count=128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call create_target,swap.img)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call finish_all)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IGNORE_ALLDEPS	= clean \
 | 
				
			||||||
 | 
									  dist-clean \
 | 
				
			||||||
 | 
									  grade \
 | 
				
			||||||
 | 
									  touch \
 | 
				
			||||||
 | 
									  print-.+ \
 | 
				
			||||||
 | 
									  run-.+ \
 | 
				
			||||||
 | 
									  build-.+ \
 | 
				
			||||||
 | 
									  handin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(call match,$(MAKECMDGOALS),$(IGNORE_ALLDEPS)),0)
 | 
				
			||||||
 | 
					-include $(ALLDEPS)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# files for grade script
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TARGETS: $(TARGETS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.DEFAULT_GOAL := TARGETS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QEMUOPTS = -hda $(UCOREIMG) -drive file=$(SWAPIMG),media=disk,cache=writeback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: qemu qemu-nox debug debug-nox
 | 
				
			||||||
 | 
					qemu-mon: $(UCOREIMG) $(SWAPIMG)
 | 
				
			||||||
 | 
						$(V)$(QEMU) -monitor stdio $(QEMUOPTS) -serial null
 | 
				
			||||||
 | 
					qemu: $(UCOREIMG) $(SWAPIMG)
 | 
				
			||||||
 | 
						$(V)$(QEMU) -parallel stdio $(QEMUOPTS) -serial null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qemu-nox: $(UCOREIMG) $(SWAPIMG)
 | 
				
			||||||
 | 
						$(V)$(QEMU) -serial mon:stdio $(QEMUOPTS) -nographic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TERMINAL := gnome-terminal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					debug: $(UCOREIMG) $(SWAPIMG)
 | 
				
			||||||
 | 
						$(V)$(QEMU) -S -s -parallel stdio $(QEMUOPTS) -serial null &
 | 
				
			||||||
 | 
						$(V)sleep 2
 | 
				
			||||||
 | 
						$(V)$(TERMINAL) -e "$(GDB) -q -x tools/gdbinit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					debug-nox: $(UCOREIMG) $(SWAPIMG)
 | 
				
			||||||
 | 
						$(V)$(QEMU) -S -s -serial mon:stdio $(QEMUOPTS) -nographic &
 | 
				
			||||||
 | 
						$(V)sleep 2
 | 
				
			||||||
 | 
						$(V)$(TERMINAL) -e "$(GDB) -q -x tools/gdbinit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN_PREFIX	:= _binary_$(OBJDIR)_$(USER_PREFIX)
 | 
				
			||||||
 | 
					MAKEOPTS	:= --quiet --no-print-directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run-%: build-%
 | 
				
			||||||
 | 
						$(V)$(QEMU) -parallel stdio $(QEMUOPTS) -serial null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run-nox-%: build-%
 | 
				
			||||||
 | 
						$(V)$(QEMU) -serial mon:stdio $(QEMUOPTS) -nographic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					build-%: touch
 | 
				
			||||||
 | 
						$(V)$(MAKE) $(MAKEOPTS) "DEFS+=-DTEST=$* -DTESTSTART=$(RUN_PREFIX)$*_out_start -DTESTSIZE=$(RUN_PREFIX)$*_out_size"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: grade touch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GRADE_GDB_IN	:= .gdb.in
 | 
				
			||||||
 | 
					GRADE_QEMU_OUT	:= .qemu.out
 | 
				
			||||||
 | 
					HANDIN			:= proj$(PROJ)-handin.tar.gz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TOUCH_FILES		:= kern/process/proc.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MAKEOPTS		:= --quiet --no-print-directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					grade:
 | 
				
			||||||
 | 
						$(V)$(MAKE) $(MAKEOPTS) clean
 | 
				
			||||||
 | 
						$(V)$(SH) tools/grade.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					touch:
 | 
				
			||||||
 | 
						$(V)$(foreach f,$(TOUCH_FILES),$(TOUCH) $(f))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print-%:
 | 
				
			||||||
 | 
						@echo $($(shell echo $(patsubst print-%,%,$@) | $(TR) [a-z] [A-Z]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: clean dist-clean handin packall
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						$(V)$(RM) $(GRADE_GDB_IN) $(GRADE_QEMU_OUT)
 | 
				
			||||||
 | 
						-$(RM) -r $(OBJDIR) $(BINDIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dist-clean: clean
 | 
				
			||||||
 | 
						-$(RM) $(HANDIN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handin: packall
 | 
				
			||||||
 | 
						@echo Please visit http://learn.tsinghua.edu.cn and upload $(HANDIN). Thanks!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					packall: clean
 | 
				
			||||||
 | 
						@$(RM) -f $(HANDIN)
 | 
				
			||||||
 | 
						@tar -czf $(HANDIN) `find . -type f -o -type d | grep -v '^\.*$$' | grep -vF '$(HANDIN)'`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								related_info/lab5/lab5-spoc-discuss/boot/asm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								related_info/lab5/lab5-spoc-discuss/boot/asm.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					#ifndef __BOOT_ASM_H__
 | 
				
			||||||
 | 
					#define __BOOT_ASM_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Assembler macros to create x86 segments */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Normal segment */
 | 
				
			||||||
 | 
					#define SEG_NULLASM                                             \
 | 
				
			||||||
 | 
					    .word 0, 0;                                                 \
 | 
				
			||||||
 | 
					    .byte 0, 0, 0, 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SEG_ASM(type,base,lim)                                  \
 | 
				
			||||||
 | 
					    .word (((lim) >> 12) & 0xffff), ((base) & 0xffff);          \
 | 
				
			||||||
 | 
					    .byte (((base) >> 16) & 0xff), (0x90 | (type)),             \
 | 
				
			||||||
 | 
					        (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__BOOT_ASM_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										107
									
								
								related_info/lab5/lab5-spoc-discuss/boot/bootasm.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								related_info/lab5/lab5-spoc-discuss/boot/bootasm.S
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					#include <asm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Start the CPU: switch to 32-bit protected mode, jump into C.
 | 
				
			||||||
 | 
					# The BIOS loads this code from the first sector of the hard disk into
 | 
				
			||||||
 | 
					# memory at physical address 0x7c00 and starts executing in real mode
 | 
				
			||||||
 | 
					# with %cs=0 %ip=7c00.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.set PROT_MODE_CSEG,        0x8                     # kernel code segment selector
 | 
				
			||||||
 | 
					.set PROT_MODE_DSEG,        0x10                    # kernel data segment selector
 | 
				
			||||||
 | 
					.set CR0_PE_ON,             0x1                     # protected mode enable flag
 | 
				
			||||||
 | 
					.set SMAP,                  0x534d4150
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# start address should be 0:7c00, in real mode, the beginning address of the running bootloader
 | 
				
			||||||
 | 
					.globl start
 | 
				
			||||||
 | 
					start:
 | 
				
			||||||
 | 
					.code16                                             # Assemble for 16-bit 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Enable A20:
 | 
				
			||||||
 | 
					    #  For backwards compatibility with the earliest PCs, physical
 | 
				
			||||||
 | 
					    #  address line 20 is tied low, so that addresses higher than
 | 
				
			||||||
 | 
					    #  1MB wrap around to zero by default. This code undoes this.
 | 
				
			||||||
 | 
					seta20.1:
 | 
				
			||||||
 | 
					    inb $0x64, %al                                  # Wait for not busy
 | 
				
			||||||
 | 
					    testb $0x2, %al
 | 
				
			||||||
 | 
					    jnz seta20.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    movb $0xd1, %al                                 # 0xd1 -> port 0x64
 | 
				
			||||||
 | 
					    outb %al, $0x64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					seta20.2:
 | 
				
			||||||
 | 
					    inb $0x64, %al                                  # Wait for not busy
 | 
				
			||||||
 | 
					    testb $0x2, %al
 | 
				
			||||||
 | 
					    jnz seta20.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    movb $0xdf, %al                                 # 0xdf -> port 0x60
 | 
				
			||||||
 | 
					    outb %al, $0x60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					probe_memory:
 | 
				
			||||||
 | 
					    movl $0, 0x8000
 | 
				
			||||||
 | 
					    xorl %ebx, %ebx
 | 
				
			||||||
 | 
					    movw $0x8004, %di
 | 
				
			||||||
 | 
					start_probe:
 | 
				
			||||||
 | 
					    movl $0xE820, %eax
 | 
				
			||||||
 | 
					    movl $20, %ecx
 | 
				
			||||||
 | 
					    movl $SMAP, %edx
 | 
				
			||||||
 | 
					    int $0x15
 | 
				
			||||||
 | 
					    jnc cont
 | 
				
			||||||
 | 
					    movw $12345, 0x8000
 | 
				
			||||||
 | 
					    jmp finish_probe
 | 
				
			||||||
 | 
					cont:
 | 
				
			||||||
 | 
					    addw $20, %di
 | 
				
			||||||
 | 
					    incl 0x8000
 | 
				
			||||||
 | 
					    cmpl $0, %ebx
 | 
				
			||||||
 | 
					    jnz start_probe
 | 
				
			||||||
 | 
					finish_probe:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Switch from real to protected mode, using a bootstrap GDT
 | 
				
			||||||
 | 
					    # and segment translation that makes virtual addresses
 | 
				
			||||||
 | 
					    # identical to physical addresses, so that the
 | 
				
			||||||
 | 
					    # effective memory map does not change during the switch.
 | 
				
			||||||
 | 
					    lgdt gdtdesc
 | 
				
			||||||
 | 
					    movl %cr0, %eax
 | 
				
			||||||
 | 
					    orl $CR0_PE_ON, %eax
 | 
				
			||||||
 | 
					    movl %eax, %cr0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Jump to next instruction, but in 32-bit code segment.
 | 
				
			||||||
 | 
					    # Switches processor into 32-bit mode.
 | 
				
			||||||
 | 
					    ljmp $PROT_MODE_CSEG, $protcseg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.code32                                             # Assemble for 32-bit mode
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Set up the stack pointer and call into C. The stack region is from 0--start(0x7c00)
 | 
				
			||||||
 | 
					    movl $0x0, %ebp
 | 
				
			||||||
 | 
					    movl $start, %esp
 | 
				
			||||||
 | 
					    call bootmain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If bootmain returns (it shouldn't), loop.
 | 
				
			||||||
 | 
					spin:
 | 
				
			||||||
 | 
					    jmp spin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.data
 | 
				
			||||||
 | 
					# Bootstrap GDT
 | 
				
			||||||
 | 
					.p2align 2                                          # force 4 byte alignment
 | 
				
			||||||
 | 
					gdt:
 | 
				
			||||||
 | 
					    SEG_NULLASM                                     # null seg
 | 
				
			||||||
 | 
					    SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)           # code seg for bootloader and kernel
 | 
				
			||||||
 | 
					    SEG_ASM(STA_W, 0x0, 0xffffffff)                 # data seg for bootloader and kernel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gdtdesc:
 | 
				
			||||||
 | 
					    .word 0x17                                      # sizeof(gdt) - 1
 | 
				
			||||||
 | 
					    .long gdt                                       # address gdt
 | 
				
			||||||
							
								
								
									
										116
									
								
								related_info/lab5/lab5-spoc-discuss/boot/bootmain.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								related_info/lab5/lab5-spoc-discuss/boot/bootmain.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <elf.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(bootasm.S and bootmain.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 bootasm.S -- which sets up protected mode,
 | 
				
			||||||
 | 
					 *    and a stack so C code then run, then calls bootmain()
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  * bootmain() in this file takes over, reads in the kernel and jumps to it.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SECTSIZE        512
 | 
				
			||||||
 | 
					#define ELFHDR          ((struct elfhdr *)0x10000)      // scratch space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* waitdisk - wait for disk ready */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					waitdisk(void) {
 | 
				
			||||||
 | 
					    while ((inb(0x1F7) & 0xC0) != 0x40)
 | 
				
			||||||
 | 
					        /* do nothing */;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* readsect - read a single sector at @secno into @dst */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					readsect(void *dst, uint32_t secno) {
 | 
				
			||||||
 | 
					    // wait for disk to be ready
 | 
				
			||||||
 | 
					    waitdisk();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    outb(0x1F2, 1);                         // count = 1
 | 
				
			||||||
 | 
					    outb(0x1F3, secno & 0xFF);
 | 
				
			||||||
 | 
					    outb(0x1F4, (secno >> 8) & 0xFF);
 | 
				
			||||||
 | 
					    outb(0x1F5, (secno >> 16) & 0xFF);
 | 
				
			||||||
 | 
					    outb(0x1F6, ((secno >> 24) & 0xF) | 0xE0);
 | 
				
			||||||
 | 
					    outb(0x1F7, 0x20);                      // cmd 0x20 - read sectors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // wait for disk to be ready
 | 
				
			||||||
 | 
					    waitdisk();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // read a sector
 | 
				
			||||||
 | 
					    insl(0x1F0, dst, SECTSIZE / 4);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * readseg - read @count bytes at @offset from kernel into virtual address @va,
 | 
				
			||||||
 | 
					 * might copy more than asked.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					readseg(uintptr_t va, uint32_t count, uint32_t offset) {
 | 
				
			||||||
 | 
					    uintptr_t end_va = va + count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // round down to sector boundary
 | 
				
			||||||
 | 
					    va -= offset % SECTSIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // translate from bytes to sectors; kernel starts at sector 1
 | 
				
			||||||
 | 
					    uint32_t secno = (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.
 | 
				
			||||||
 | 
					    for (; va < end_va; va += SECTSIZE, secno ++) {
 | 
				
			||||||
 | 
					        readsect((void *)va, secno);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* bootmain - the entry of bootloader */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					bootmain(void) {
 | 
				
			||||||
 | 
					    // read the 1st page off disk
 | 
				
			||||||
 | 
					    readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // is this a valid ELF?
 | 
				
			||||||
 | 
					    if (ELFHDR->e_magic != ELF_MAGIC) {
 | 
				
			||||||
 | 
					        goto bad;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct proghdr *ph, *eph;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // load each program segment (ignores ph flags)
 | 
				
			||||||
 | 
					    ph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);
 | 
				
			||||||
 | 
					    eph = ph + ELFHDR->e_phnum;
 | 
				
			||||||
 | 
					    for (; ph < eph; ph ++) {
 | 
				
			||||||
 | 
					        readseg(ph->p_va & 0xFFFFFF, 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* do nothing */
 | 
				
			||||||
 | 
					    while (1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/assert.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/assert.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DEBUG_ASSERT_H__
 | 
				
			||||||
 | 
					#define __KERN_DEBUG_ASSERT_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __warn(const char *file, int line, const char *fmt, ...);
 | 
				
			||||||
 | 
					void __noreturn __panic(const char *file, int line, const char *fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define warn(...)                                       \
 | 
				
			||||||
 | 
					    __warn(__FILE__, __LINE__, __VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define panic(...)                                      \
 | 
				
			||||||
 | 
					    __panic(__FILE__, __LINE__, __VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define assert(x)                                       \
 | 
				
			||||||
 | 
					    do {                                                \
 | 
				
			||||||
 | 
					        if (!(x)) {                                     \
 | 
				
			||||||
 | 
					            panic("assertion failed: %s", #x);          \
 | 
				
			||||||
 | 
					        }                                               \
 | 
				
			||||||
 | 
					    } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static_assert(x) will generate a compile-time error if 'x' is false.
 | 
				
			||||||
 | 
					#define static_assert(x)                                \
 | 
				
			||||||
 | 
					    switch (x) { case 0: case (x): ; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DEBUG_ASSERT_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										365
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/kdebug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/kdebug.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,365 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <stab.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					#include <vmm.h>
 | 
				
			||||||
 | 
					#include <proc.h>
 | 
				
			||||||
 | 
					#include <kdebug.h>
 | 
				
			||||||
 | 
					#include <kmonitor.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STACKFRAME_DEPTH 20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct stab __STAB_BEGIN__[];  // beginning of stabs table
 | 
				
			||||||
 | 
					extern const struct stab __STAB_END__[];    // end of stabs table
 | 
				
			||||||
 | 
					extern const char __STABSTR_BEGIN__[];      // beginning of string table
 | 
				
			||||||
 | 
					extern const char __STABSTR_END__[];        // end of string table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* debug information about a particular instruction pointer */
 | 
				
			||||||
 | 
					struct eipdebuginfo {
 | 
				
			||||||
 | 
					    const char *eip_file;                   // source code filename for eip
 | 
				
			||||||
 | 
					    int eip_line;                           // source code line number for eip
 | 
				
			||||||
 | 
					    const char *eip_fn_name;                // name of function containing eip
 | 
				
			||||||
 | 
					    int eip_fn_namelen;                     // length of function's name
 | 
				
			||||||
 | 
					    uintptr_t eip_fn_addr;                  // start address of function
 | 
				
			||||||
 | 
					    int eip_fn_narg;                        // number of function arguments
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* user STABS data structure  */
 | 
				
			||||||
 | 
					struct userstabdata {
 | 
				
			||||||
 | 
					    const struct stab *stabs;
 | 
				
			||||||
 | 
					    const struct stab *stab_end;
 | 
				
			||||||
 | 
					    const char *stabstr;
 | 
				
			||||||
 | 
					    const char *stabstr_end;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * stab_binsearch - according to the input, the initial value of
 | 
				
			||||||
 | 
					 * range [*@region_left, *@region_right], find a single stab entry
 | 
				
			||||||
 | 
					 * that includes the address @addr and matches the type @type,
 | 
				
			||||||
 | 
					 * and then save its boundary to the locations that pointed
 | 
				
			||||||
 | 
					 * by @region_left and @region_right.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Some stab types are arranged in increasing order by instruction address.
 | 
				
			||||||
 | 
					 * For example, N_FUN stabs (stab entries with n_type == N_FUN), which
 | 
				
			||||||
 | 
					 * mark functions, and N_SO stabs, which mark source files.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Given an instruction address, this function finds the single stab entry
 | 
				
			||||||
 | 
					 * of type @type that contains that address.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The search takes place within the range [*@region_left, *@region_right].
 | 
				
			||||||
 | 
					 * Thus, to search an entire set of N stabs, you might do:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      left = 0;
 | 
				
			||||||
 | 
					 *      right = N - 1;    (rightmost stab)
 | 
				
			||||||
 | 
					 *      stab_binsearch(stabs, &left, &right, type, addr);
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The search modifies *region_left and *region_right to bracket the @addr.
 | 
				
			||||||
 | 
					 * *@region_left points to the matching stab that contains @addr,
 | 
				
			||||||
 | 
					 * and *@region_right points just before the next stab.
 | 
				
			||||||
 | 
					 * If *@region_left > *region_right, then @addr is not contained in any
 | 
				
			||||||
 | 
					 * matching stab.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For example, given these N_SO stabs:
 | 
				
			||||||
 | 
					 *      Index  Type   Address
 | 
				
			||||||
 | 
					 *      0      SO     f0100000
 | 
				
			||||||
 | 
					 *      13     SO     f0100040
 | 
				
			||||||
 | 
					 *      117    SO     f0100176
 | 
				
			||||||
 | 
					 *      118    SO     f0100178
 | 
				
			||||||
 | 
					 *      555    SO     f0100652
 | 
				
			||||||
 | 
					 *      556    SO     f0100654
 | 
				
			||||||
 | 
					 *      657    SO     f0100849
 | 
				
			||||||
 | 
					 * this code:
 | 
				
			||||||
 | 
					 *      left = 0, right = 657;
 | 
				
			||||||
 | 
					 *      stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
 | 
				
			||||||
 | 
					 * will exit setting left = 118, right = 554.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					stab_binsearch(const struct stab *stabs, int *region_left, int *region_right,
 | 
				
			||||||
 | 
					           int type, uintptr_t addr) {
 | 
				
			||||||
 | 
					    int l = *region_left, r = *region_right, any_matches = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (l <= r) {
 | 
				
			||||||
 | 
					        int true_m = (l + r) / 2, m = true_m;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // search for earliest stab with right type
 | 
				
			||||||
 | 
					        while (m >= l && stabs[m].n_type != type) {
 | 
				
			||||||
 | 
					            m --;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (m < l) {    // no match in [l, m]
 | 
				
			||||||
 | 
					            l = true_m + 1;
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // actual binary search
 | 
				
			||||||
 | 
					        any_matches = 1;
 | 
				
			||||||
 | 
					        if (stabs[m].n_value < addr) {
 | 
				
			||||||
 | 
					            *region_left = m;
 | 
				
			||||||
 | 
					            l = true_m + 1;
 | 
				
			||||||
 | 
					        } else if (stabs[m].n_value > addr) {
 | 
				
			||||||
 | 
					            *region_right = m - 1;
 | 
				
			||||||
 | 
					            r = m - 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // exact match for 'addr', but continue loop to find
 | 
				
			||||||
 | 
					            // *region_right
 | 
				
			||||||
 | 
					            *region_left = m;
 | 
				
			||||||
 | 
					            l = m;
 | 
				
			||||||
 | 
					            addr ++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!any_matches) {
 | 
				
			||||||
 | 
					        *region_right = *region_left - 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        // find rightmost region containing 'addr'
 | 
				
			||||||
 | 
					        l = *region_right;
 | 
				
			||||||
 | 
					        for (; l > *region_left && stabs[l].n_type != type; l --)
 | 
				
			||||||
 | 
					            /* do nothing */;
 | 
				
			||||||
 | 
					        *region_left = l;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * debuginfo_eip - Fill in the @info structure with information about
 | 
				
			||||||
 | 
					 * the specified instruction address, @addr.  Returns 0 if information
 | 
				
			||||||
 | 
					 * was found, and negative if not.  But even if it returns negative it
 | 
				
			||||||
 | 
					 * has stored some information into '*info'.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					debuginfo_eip(uintptr_t addr, struct eipdebuginfo *info) {
 | 
				
			||||||
 | 
					    const struct stab *stabs, *stab_end;
 | 
				
			||||||
 | 
					    const char *stabstr, *stabstr_end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    info->eip_file = "<unknown>";
 | 
				
			||||||
 | 
					    info->eip_line = 0;
 | 
				
			||||||
 | 
					    info->eip_fn_name = "<unknown>";
 | 
				
			||||||
 | 
					    info->eip_fn_namelen = 9;
 | 
				
			||||||
 | 
					    info->eip_fn_addr = addr;
 | 
				
			||||||
 | 
					    info->eip_fn_narg = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // find the relevant set of stabs
 | 
				
			||||||
 | 
					    if (addr >= KERNBASE) {
 | 
				
			||||||
 | 
					        stabs = __STAB_BEGIN__;
 | 
				
			||||||
 | 
					        stab_end = __STAB_END__;
 | 
				
			||||||
 | 
					        stabstr = __STABSTR_BEGIN__;
 | 
				
			||||||
 | 
					        stabstr_end = __STABSTR_END__;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        // user-program linker script, tools/user.ld puts the information about the
 | 
				
			||||||
 | 
					        // program's stabs (included __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__,
 | 
				
			||||||
 | 
					        // and __STABSTR_END__) in a structure located at virtual address USTAB.
 | 
				
			||||||
 | 
					        const struct userstabdata *usd = (struct userstabdata *)USTAB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // make sure that debugger (current process) can access this memory
 | 
				
			||||||
 | 
					        struct mm_struct *mm;
 | 
				
			||||||
 | 
					        if (current == NULL || (mm = current->mm) == NULL) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!user_mem_check(mm, (uintptr_t)usd, sizeof(struct userstabdata), 0)) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stabs = usd->stabs;
 | 
				
			||||||
 | 
					        stab_end = usd->stab_end;
 | 
				
			||||||
 | 
					        stabstr = usd->stabstr;
 | 
				
			||||||
 | 
					        stabstr_end = usd->stabstr_end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // make sure the STABS and string table memory is valid
 | 
				
			||||||
 | 
					        if (!user_mem_check(mm, (uintptr_t)stabs, (uintptr_t)stab_end - (uintptr_t)stabs, 0)) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!user_mem_check(mm, (uintptr_t)stabstr, stabstr_end - stabstr, 0)) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // String table validity checks
 | 
				
			||||||
 | 
					    if (stabstr_end <= stabstr || stabstr_end[-1] != 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Now we find the right stabs that define the function containing
 | 
				
			||||||
 | 
					    // 'eip'.  First, we find the basic source file containing 'eip'.
 | 
				
			||||||
 | 
					    // Then, we look in that source file for the function.  Then we look
 | 
				
			||||||
 | 
					    // for the line number.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Search the entire set of stabs for the source file (type N_SO).
 | 
				
			||||||
 | 
					    int lfile = 0, rfile = (stab_end - stabs) - 1;
 | 
				
			||||||
 | 
					    stab_binsearch(stabs, &lfile, &rfile, N_SO, addr);
 | 
				
			||||||
 | 
					    if (lfile == 0)
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Search within that file's stabs for the function definition
 | 
				
			||||||
 | 
					    // (N_FUN).
 | 
				
			||||||
 | 
					    int lfun = lfile, rfun = rfile;
 | 
				
			||||||
 | 
					    int lline, rline;
 | 
				
			||||||
 | 
					    stab_binsearch(stabs, &lfun, &rfun, N_FUN, addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (lfun <= rfun) {
 | 
				
			||||||
 | 
					        // stabs[lfun] points to the function name
 | 
				
			||||||
 | 
					        // in the string table, but check bounds just in case.
 | 
				
			||||||
 | 
					        if (stabs[lfun].n_strx < stabstr_end - stabstr) {
 | 
				
			||||||
 | 
					            info->eip_fn_name = stabstr + stabs[lfun].n_strx;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        info->eip_fn_addr = stabs[lfun].n_value;
 | 
				
			||||||
 | 
					        addr -= info->eip_fn_addr;
 | 
				
			||||||
 | 
					        // Search within the function definition for the line number.
 | 
				
			||||||
 | 
					        lline = lfun;
 | 
				
			||||||
 | 
					        rline = rfun;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // Couldn't find function stab!  Maybe we're in an assembly
 | 
				
			||||||
 | 
					        // file.  Search the whole file for the line number.
 | 
				
			||||||
 | 
					        info->eip_fn_addr = addr;
 | 
				
			||||||
 | 
					        lline = lfile;
 | 
				
			||||||
 | 
					        rline = rfile;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Search within [lline, rline] for the line number stab.
 | 
				
			||||||
 | 
					    // If found, set info->eip_line to the right line number.
 | 
				
			||||||
 | 
					    // If not found, return -1.
 | 
				
			||||||
 | 
					    stab_binsearch(stabs, &lline, &rline, N_SLINE, addr);
 | 
				
			||||||
 | 
					    if (lline <= rline) {
 | 
				
			||||||
 | 
					        info->eip_line = stabs[rline].n_desc;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Search backwards from the line number for the relevant filename stab.
 | 
				
			||||||
 | 
					    // We can't just use the "lfile" stab because inlined functions
 | 
				
			||||||
 | 
					    // can interpolate code from a different file!
 | 
				
			||||||
 | 
					    // Such included source files use the N_SOL stab type.
 | 
				
			||||||
 | 
					    while (lline >= lfile
 | 
				
			||||||
 | 
					           && stabs[lline].n_type != N_SOL
 | 
				
			||||||
 | 
					           && (stabs[lline].n_type != N_SO || !stabs[lline].n_value)) {
 | 
				
			||||||
 | 
					        lline --;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr) {
 | 
				
			||||||
 | 
					        info->eip_file = stabstr + stabs[lline].n_strx;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Set eip_fn_narg to the number of arguments taken by the function,
 | 
				
			||||||
 | 
					    // or 0 if there was no containing function.
 | 
				
			||||||
 | 
					    if (lfun < rfun) {
 | 
				
			||||||
 | 
					        for (lline = lfun + 1;
 | 
				
			||||||
 | 
					             lline < rfun && stabs[lline].n_type == N_PSYM;
 | 
				
			||||||
 | 
					             lline ++) {
 | 
				
			||||||
 | 
					            info->eip_fn_narg ++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * print_kerninfo - print the information about kernel, including the location
 | 
				
			||||||
 | 
					 * of kernel entry, the start addresses of data and text segements, the start
 | 
				
			||||||
 | 
					 * address of free memory and how many memory that kernel has used.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					print_kerninfo(void) {
 | 
				
			||||||
 | 
					    extern char etext[], edata[], end[], kern_init[];
 | 
				
			||||||
 | 
					    cprintf("Special kernel symbols:\n");
 | 
				
			||||||
 | 
					    cprintf("  entry  0x%08x (phys)\n", kern_init);
 | 
				
			||||||
 | 
					    cprintf("  etext  0x%08x (phys)\n", etext);
 | 
				
			||||||
 | 
					    cprintf("  edata  0x%08x (phys)\n", edata);
 | 
				
			||||||
 | 
					    cprintf("  end    0x%08x (phys)\n", end);
 | 
				
			||||||
 | 
					    cprintf("Kernel executable memory footprint: %dKB\n", (end - kern_init + 1023)/1024);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * print_debuginfo - read and print the stat information for the address @eip,
 | 
				
			||||||
 | 
					 * and info.eip_fn_addr should be the first address of the related function.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					print_debuginfo(uintptr_t eip) {
 | 
				
			||||||
 | 
					    struct eipdebuginfo info;
 | 
				
			||||||
 | 
					    if (debuginfo_eip(eip, &info) != 0) {
 | 
				
			||||||
 | 
					        cprintf("    <unknow>: -- 0x%08x --\n", eip);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        char fnname[256];
 | 
				
			||||||
 | 
					        int j;
 | 
				
			||||||
 | 
					        for (j = 0; j < info.eip_fn_namelen; j ++) {
 | 
				
			||||||
 | 
					            fnname[j] = info.eip_fn_name[j];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fnname[j] = '\0';
 | 
				
			||||||
 | 
					        cprintf("    %s:%d: %s+%d\n", info.eip_file, info.eip_line,
 | 
				
			||||||
 | 
					                fnname, eip - info.eip_fn_addr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static __noinline uint32_t
 | 
				
			||||||
 | 
					read_eip(void) {
 | 
				
			||||||
 | 
					    uint32_t eip;
 | 
				
			||||||
 | 
					    asm volatile("movl 4(%%ebp), %0" : "=r" (eip));
 | 
				
			||||||
 | 
					    return eip;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * print_stackframe - print a list of the saved eip values from the nested 'call'
 | 
				
			||||||
 | 
					 * instructions that led to the current point of execution
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The x86 stack pointer, namely esp, points to the lowest location on the stack
 | 
				
			||||||
 | 
					 * that is currently in use. Everything below that location in stack is free. Pushing
 | 
				
			||||||
 | 
					 * a value onto the stack will invole decreasing the stack pointer and then writing
 | 
				
			||||||
 | 
					 * the value to the place that stack pointer pointes to. And popping a value do the
 | 
				
			||||||
 | 
					 * opposite.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The ebp (base pointer) register, in contrast, is associated with the stack
 | 
				
			||||||
 | 
					 * primarily by software convention. On entry to a C function, the function's
 | 
				
			||||||
 | 
					 * prologue code normally saves the previous function's base pointer by pushing
 | 
				
			||||||
 | 
					 * it onto the stack, and then copies the current esp value into ebp for the duration
 | 
				
			||||||
 | 
					 * of the function. If all the functions in a program obey this convention,
 | 
				
			||||||
 | 
					 * then at any given point during the program's execution, it is possible to trace
 | 
				
			||||||
 | 
					 * back through the stack by following the chain of saved ebp pointers and determining
 | 
				
			||||||
 | 
					 * exactly what nested sequence of function calls caused this particular point in the
 | 
				
			||||||
 | 
					 * program to be reached. This capability can be particularly useful, for example,
 | 
				
			||||||
 | 
					 * when a particular function causes an assert failure or panic because bad arguments
 | 
				
			||||||
 | 
					 * were passed to it, but you aren't sure who passed the bad arguments. A stack
 | 
				
			||||||
 | 
					 * backtrace lets you find the offending function.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The inline function read_ebp() can tell us the value of current ebp. And the
 | 
				
			||||||
 | 
					 * non-inline function read_eip() is useful, it can read the value of current eip,
 | 
				
			||||||
 | 
					 * since while calling this function, read_eip() can read the caller's eip from
 | 
				
			||||||
 | 
					 * stack easily.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In print_debuginfo(), the function debuginfo_eip() can get enough information about
 | 
				
			||||||
 | 
					 * calling-chain. Finally print_stackframe() will trace and print them for debugging.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that, the length of ebp-chain is limited. In boot/bootasm.S, before jumping
 | 
				
			||||||
 | 
					 * to the kernel entry, the value of ebp has been set to zero, that's the boundary.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					print_stackframe(void) {
 | 
				
			||||||
 | 
					     /* LAB1 YOUR CODE : STEP 1 */
 | 
				
			||||||
 | 
					     /* (1) call read_ebp() to get the value of ebp. the type is (uint32_t);
 | 
				
			||||||
 | 
					      * (2) call read_eip() to get the value of eip. the type is (uint32_t);
 | 
				
			||||||
 | 
					      * (3) from 0 .. STACKFRAME_DEPTH
 | 
				
			||||||
 | 
					      *    (3.1) printf value of ebp, eip
 | 
				
			||||||
 | 
					      *    (3.2) (uint32_t)calling arguments [0..4] = the contents in address (unit32_t)ebp +2 [0..4]
 | 
				
			||||||
 | 
					      *    (3.3) cprintf("\n");
 | 
				
			||||||
 | 
					      *    (3.4) call print_debuginfo(eip-1) to print the C calling function name and line number, etc.
 | 
				
			||||||
 | 
					      *    (3.5) popup a calling stackframe
 | 
				
			||||||
 | 
					      *           NOTICE: the calling funciton's return addr eip  = ss:[ebp+4]
 | 
				
			||||||
 | 
					      *                   the calling funciton's ebp = ss:[ebp]
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    uint32_t ebp = read_ebp(), eip = read_eip();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int i, j;
 | 
				
			||||||
 | 
					    for (i = 0; ebp != 0 && i < STACKFRAME_DEPTH; i ++) {
 | 
				
			||||||
 | 
					        cprintf("ebp:0x%08x eip:0x%08x args:", ebp, eip);
 | 
				
			||||||
 | 
					        uint32_t *args = (uint32_t *)ebp + 2;
 | 
				
			||||||
 | 
					        for (j = 0; j < 4; j ++) {
 | 
				
			||||||
 | 
					            cprintf("0x%08x ", args[j]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cprintf("\n");
 | 
				
			||||||
 | 
					        print_debuginfo(eip - 1);
 | 
				
			||||||
 | 
					        eip = ((uint32_t *)ebp)[1];
 | 
				
			||||||
 | 
					        ebp = ((uint32_t *)ebp)[0];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/kdebug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/kdebug.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DEBUG_KDEBUG_H__
 | 
				
			||||||
 | 
					#define __KERN_DEBUG_KDEBUG_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void print_kerninfo(void);
 | 
				
			||||||
 | 
					void print_stackframe(void);
 | 
				
			||||||
 | 
					void print_debuginfo(uintptr_t eip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DEBUG_KDEBUG_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										132
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/kmonitor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/kmonitor.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,132 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <kmonitor.h>
 | 
				
			||||||
 | 
					#include <kdebug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Simple command-line kernel monitor useful for controlling the
 | 
				
			||||||
 | 
					 * kernel and exploring the system interactively.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct command {
 | 
				
			||||||
 | 
					    const char *name;
 | 
				
			||||||
 | 
					    const char *desc;
 | 
				
			||||||
 | 
					    // return -1 to force monitor to exit
 | 
				
			||||||
 | 
					    int(*func)(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct command commands[] = {
 | 
				
			||||||
 | 
					    {"help", "Display this list of commands.", mon_help},
 | 
				
			||||||
 | 
					    {"kerninfo", "Display information about the kernel.", mon_kerninfo},
 | 
				
			||||||
 | 
					    {"backtrace", "Print backtrace of stack frame.", mon_backtrace},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* return if kernel is panic, in kern/debug/panic.c */
 | 
				
			||||||
 | 
					bool is_kernel_panic(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NCOMMANDS (sizeof(commands)/sizeof(struct command))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***** Kernel monitor command interpreter *****/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAXARGS         16
 | 
				
			||||||
 | 
					#define WHITESPACE      " \t\n\r"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* parse - parse the command buffer into whitespace-separated arguments */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					parse(char *buf, char **argv) {
 | 
				
			||||||
 | 
					    int argc = 0;
 | 
				
			||||||
 | 
					    while (1) {
 | 
				
			||||||
 | 
					        // find global whitespace
 | 
				
			||||||
 | 
					        while (*buf != '\0' && strchr(WHITESPACE, *buf) != NULL) {
 | 
				
			||||||
 | 
					            *buf ++ = '\0';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (*buf == '\0') {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // save and scan past next arg
 | 
				
			||||||
 | 
					        if (argc == MAXARGS - 1) {
 | 
				
			||||||
 | 
					            cprintf("Too many arguments (max %d).\n", MAXARGS);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        argv[argc ++] = buf;
 | 
				
			||||||
 | 
					        while (*buf != '\0' && strchr(WHITESPACE, *buf) == NULL) {
 | 
				
			||||||
 | 
					            buf ++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return argc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * runcmd - parse the input string, split it into separated arguments
 | 
				
			||||||
 | 
					 * and then lookup and invoke some related commands/
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					runcmd(char *buf, struct trapframe *tf) {
 | 
				
			||||||
 | 
					    char *argv[MAXARGS];
 | 
				
			||||||
 | 
					    int argc = parse(buf, argv);
 | 
				
			||||||
 | 
					    if (argc == 0) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; i < NCOMMANDS; i ++) {
 | 
				
			||||||
 | 
					        if (strcmp(commands[i].name, argv[0]) == 0) {
 | 
				
			||||||
 | 
					            return commands[i].func(argc - 1, argv + 1, tf);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cprintf("Unknown command '%s'\n", argv[0]);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***** Implementations of basic kernel monitor commands *****/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					kmonitor(struct trapframe *tf) {
 | 
				
			||||||
 | 
					    cprintf("Welcome to the kernel debug monitor!!\n");
 | 
				
			||||||
 | 
					    cprintf("Type 'help' for a list of commands.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (tf != NULL) {
 | 
				
			||||||
 | 
					        print_trapframe(tf);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *buf;
 | 
				
			||||||
 | 
					    while (1) {
 | 
				
			||||||
 | 
					        if ((buf = readline("K> ")) != NULL) {
 | 
				
			||||||
 | 
					            if (runcmd(buf, tf) < 0) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* mon_help - print the information about mon_* functions */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					mon_help(int argc, char **argv, struct trapframe *tf) {
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; i < NCOMMANDS; i ++) {
 | 
				
			||||||
 | 
					        cprintf("%s - %s\n", commands[i].name, commands[i].desc);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * mon_kerninfo - call print_kerninfo in kern/debug/kdebug.c to
 | 
				
			||||||
 | 
					 * print the memory occupancy in kernel.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					mon_kerninfo(int argc, char **argv, struct trapframe *tf) {
 | 
				
			||||||
 | 
					    print_kerninfo();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * mon_backtrace - call print_stackframe in kern/debug/kdebug.c to
 | 
				
			||||||
 | 
					 * print a backtrace of the stack.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					mon_backtrace(int argc, char **argv, struct trapframe *tf) {
 | 
				
			||||||
 | 
					    print_stackframe();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/kmonitor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/kmonitor.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DEBUG_MONITOR_H__
 | 
				
			||||||
 | 
					#define __KERN_DEBUG_MONITOR_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void kmonitor(struct trapframe *tf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mon_help(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					int mon_kerninfo(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					int mon_backtrace(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					int mon_continue(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					int mon_step(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					int mon_breakpoint(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					int mon_watchpoint(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					int mon_delete_dr(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					int mon_list_dr(int argc, char **argv, struct trapframe *tf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DEBUG_MONITOR_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										49
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/panic.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/panic.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <intr.h>
 | 
				
			||||||
 | 
					#include <kmonitor.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool is_panic = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * __panic - __panic is called on unresolvable fatal errors. it prints
 | 
				
			||||||
 | 
					 * "panic: 'message'", and then enters the kernel monitor.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					__panic(const char *file, int line, const char *fmt, ...) {
 | 
				
			||||||
 | 
					    if (is_panic) {
 | 
				
			||||||
 | 
					        goto panic_dead;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    is_panic = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // print the 'message'
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    va_start(ap, fmt);
 | 
				
			||||||
 | 
					    cprintf("kernel panic at %s:%d:\n    ", file, line);
 | 
				
			||||||
 | 
					    vcprintf(fmt, ap);
 | 
				
			||||||
 | 
					    cprintf("\n");
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					panic_dead:
 | 
				
			||||||
 | 
					    intr_disable();
 | 
				
			||||||
 | 
					    while (1) {
 | 
				
			||||||
 | 
					        kmonitor(NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* __warn - like panic, but don't */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					__warn(const char *file, int line, const char *fmt, ...) {
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    va_start(ap, fmt);
 | 
				
			||||||
 | 
					    cprintf("kernel warning at %s:%d:\n    ", file, line);
 | 
				
			||||||
 | 
					    vcprintf(fmt, ap);
 | 
				
			||||||
 | 
					    cprintf("\n");
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					is_kernel_panic(void) {
 | 
				
			||||||
 | 
					    return is_panic;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										54
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/stab.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								related_info/lab5/lab5-spoc-discuss/kern/debug/stab.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DEBUG_STAB_H__
 | 
				
			||||||
 | 
					#define __KERN_DEBUG_STAB_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * STABS debugging info
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The kernel debugger can understand some debugging information in
 | 
				
			||||||
 | 
					 * the STABS format.  For more information on this format, see
 | 
				
			||||||
 | 
					 * http://sources.redhat.com/gdb/onlinedocs/stabs_toc.html
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The constants below define some symbol types used by various debuggers
 | 
				
			||||||
 | 
					 * and compilers.  Kernel uses the N_SO, N_SOL, N_FUN, and N_SLINE types.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define N_GSYM      0x20    // global symbol
 | 
				
			||||||
 | 
					#define N_FNAME     0x22    // F77 function name
 | 
				
			||||||
 | 
					#define N_FUN       0x24    // procedure name
 | 
				
			||||||
 | 
					#define N_STSYM     0x26    // data segment variable
 | 
				
			||||||
 | 
					#define N_LCSYM     0x28    // bss segment variable
 | 
				
			||||||
 | 
					#define N_MAIN      0x2a    // main function name
 | 
				
			||||||
 | 
					#define N_PC        0x30    // global Pascal symbol
 | 
				
			||||||
 | 
					#define N_RSYM      0x40    // register variable
 | 
				
			||||||
 | 
					#define N_SLINE     0x44    // text segment line number
 | 
				
			||||||
 | 
					#define N_DSLINE    0x46    // data segment line number
 | 
				
			||||||
 | 
					#define N_BSLINE    0x48    // bss segment line number
 | 
				
			||||||
 | 
					#define N_SSYM      0x60    // structure/union element
 | 
				
			||||||
 | 
					#define N_SO        0x64    // main source file name
 | 
				
			||||||
 | 
					#define N_LSYM      0x80    // stack variable
 | 
				
			||||||
 | 
					#define N_BINCL     0x82    // include file beginning
 | 
				
			||||||
 | 
					#define N_SOL       0x84    // included source file name
 | 
				
			||||||
 | 
					#define N_PSYM      0xa0    // parameter variable
 | 
				
			||||||
 | 
					#define N_EINCL     0xa2    // include file end
 | 
				
			||||||
 | 
					#define N_ENTRY     0xa4    // alternate entry point
 | 
				
			||||||
 | 
					#define N_LBRAC     0xc0    // left bracket
 | 
				
			||||||
 | 
					#define N_EXCL      0xc2    // deleted include file
 | 
				
			||||||
 | 
					#define N_RBRAC     0xe0    // right bracket
 | 
				
			||||||
 | 
					#define N_BCOMM     0xe2    // begin common
 | 
				
			||||||
 | 
					#define N_ECOMM     0xe4    // end common
 | 
				
			||||||
 | 
					#define N_ECOML     0xe8    // end common (local name)
 | 
				
			||||||
 | 
					#define N_LENG      0xfe    // length of preceding entry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Entries in the STABS table are formatted as follows. */
 | 
				
			||||||
 | 
					struct stab {
 | 
				
			||||||
 | 
					    uint32_t n_strx;        // index into string table of name
 | 
				
			||||||
 | 
					    uint8_t n_type;         // type of symbol
 | 
				
			||||||
 | 
					    uint8_t n_other;        // misc info (usually empty)
 | 
				
			||||||
 | 
					    uint16_t n_desc;        // description field
 | 
				
			||||||
 | 
					    uintptr_t n_value;      // value of symbol
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DEBUG_STAB_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										45
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/clock.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/clock.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <picirq.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Support for time-related hardware gadgets - the 8253 timer,
 | 
				
			||||||
 | 
					 * which generates interruptes on IRQ-0.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IO_TIMER1           0x040               // 8253 Timer #1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Frequency of all three count-down timers; (TIMER_FREQ/freq)
 | 
				
			||||||
 | 
					 * is the appropriate count to generate a frequency of freq Hz.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TIMER_FREQ      1193182
 | 
				
			||||||
 | 
					#define TIMER_DIV(x)    ((TIMER_FREQ + (x) / 2) / (x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TIMER_MODE      (IO_TIMER1 + 3)         // timer mode port
 | 
				
			||||||
 | 
					#define TIMER_SEL0      0x00                    // select counter 0
 | 
				
			||||||
 | 
					#define TIMER_RATEGEN   0x04                    // mode 2, rate generator
 | 
				
			||||||
 | 
					#define TIMER_16BIT     0x30                    // r/w counter 16 bits, LSB first
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile size_t ticks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * clock_init - initialize 8253 clock to interrupt 100 times per second,
 | 
				
			||||||
 | 
					 * and then enable IRQ_TIMER.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					clock_init(void) {
 | 
				
			||||||
 | 
					    // set 8253 timer-chip
 | 
				
			||||||
 | 
					    outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
 | 
				
			||||||
 | 
					    outb(IO_TIMER1, TIMER_DIV(100) % 256);
 | 
				
			||||||
 | 
					    outb(IO_TIMER1, TIMER_DIV(100) / 256);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // initialize time counter 'ticks' to zero
 | 
				
			||||||
 | 
					    ticks = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("++ setup timer interrupts\n");
 | 
				
			||||||
 | 
					    pic_enable(IRQ_TIMER);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/clock.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/clock.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DRIVER_CLOCK_H__
 | 
				
			||||||
 | 
					#define __KERN_DRIVER_CLOCK_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern volatile size_t ticks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void clock_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DRIVER_CLOCK_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										465
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/console.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/console.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,465 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <kbdreg.h>
 | 
				
			||||||
 | 
					#include <picirq.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* stupid I/O delay routine necessitated by historical PC design flaws */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					delay(void) {
 | 
				
			||||||
 | 
					    inb(0x84);
 | 
				
			||||||
 | 
					    inb(0x84);
 | 
				
			||||||
 | 
					    inb(0x84);
 | 
				
			||||||
 | 
					    inb(0x84);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***** Serial I/O code *****/
 | 
				
			||||||
 | 
					#define COM1            0x3F8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define COM_RX          0       // In:  Receive buffer (DLAB=0)
 | 
				
			||||||
 | 
					#define COM_TX          0       // Out: Transmit buffer (DLAB=0)
 | 
				
			||||||
 | 
					#define COM_DLL         0       // Out: Divisor Latch Low (DLAB=1)
 | 
				
			||||||
 | 
					#define COM_DLM         1       // Out: Divisor Latch High (DLAB=1)
 | 
				
			||||||
 | 
					#define COM_IER         1       // Out: Interrupt Enable Register
 | 
				
			||||||
 | 
					#define COM_IER_RDI     0x01    // Enable receiver data interrupt
 | 
				
			||||||
 | 
					#define COM_IIR         2       // In:  Interrupt ID Register
 | 
				
			||||||
 | 
					#define COM_FCR         2       // Out: FIFO Control Register
 | 
				
			||||||
 | 
					#define COM_LCR         3       // Out: Line Control Register
 | 
				
			||||||
 | 
					#define COM_LCR_DLAB    0x80    // Divisor latch access bit
 | 
				
			||||||
 | 
					#define COM_LCR_WLEN8   0x03    // Wordlength: 8 bits
 | 
				
			||||||
 | 
					#define COM_MCR         4       // Out: Modem Control Register
 | 
				
			||||||
 | 
					#define COM_MCR_RTS     0x02    // RTS complement
 | 
				
			||||||
 | 
					#define COM_MCR_DTR     0x01    // DTR complement
 | 
				
			||||||
 | 
					#define COM_MCR_OUT2    0x08    // Out2 complement
 | 
				
			||||||
 | 
					#define COM_LSR         5       // In:  Line Status Register
 | 
				
			||||||
 | 
					#define COM_LSR_DATA    0x01    // Data available
 | 
				
			||||||
 | 
					#define COM_LSR_TXRDY   0x20    // Transmit buffer avail
 | 
				
			||||||
 | 
					#define COM_LSR_TSRE    0x40    // Transmitter off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MONO_BASE       0x3B4
 | 
				
			||||||
 | 
					#define MONO_BUF        0xB0000
 | 
				
			||||||
 | 
					#define CGA_BASE        0x3D4
 | 
				
			||||||
 | 
					#define CGA_BUF         0xB8000
 | 
				
			||||||
 | 
					#define CRT_ROWS        25
 | 
				
			||||||
 | 
					#define CRT_COLS        80
 | 
				
			||||||
 | 
					#define CRT_SIZE        (CRT_ROWS * CRT_COLS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LPTPORT         0x378
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint16_t *crt_buf;
 | 
				
			||||||
 | 
					static uint16_t crt_pos;
 | 
				
			||||||
 | 
					static uint16_t addr_6845;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TEXT-mode CGA/VGA display output */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					cga_init(void) {
 | 
				
			||||||
 | 
					    volatile uint16_t *cp = (uint16_t *)(CGA_BUF + KERNBASE);
 | 
				
			||||||
 | 
					    uint16_t was = *cp;
 | 
				
			||||||
 | 
					    *cp = (uint16_t) 0xA55A;
 | 
				
			||||||
 | 
					    if (*cp != 0xA55A) {
 | 
				
			||||||
 | 
					        cp = (uint16_t*)(MONO_BUF + KERNBASE);
 | 
				
			||||||
 | 
					        addr_6845 = MONO_BASE;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        *cp = was;
 | 
				
			||||||
 | 
					        addr_6845 = CGA_BASE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Extract cursor location
 | 
				
			||||||
 | 
					    uint32_t pos;
 | 
				
			||||||
 | 
					    outb(addr_6845, 14);
 | 
				
			||||||
 | 
					    pos = inb(addr_6845 + 1) << 8;
 | 
				
			||||||
 | 
					    outb(addr_6845, 15);
 | 
				
			||||||
 | 
					    pos |= inb(addr_6845 + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    crt_buf = (uint16_t*) cp;
 | 
				
			||||||
 | 
					    crt_pos = pos;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool serial_exists = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					serial_init(void) {
 | 
				
			||||||
 | 
					    // Turn off the FIFO
 | 
				
			||||||
 | 
					    outb(COM1 + COM_FCR, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Set speed; requires DLAB latch
 | 
				
			||||||
 | 
					    outb(COM1 + COM_LCR, COM_LCR_DLAB);
 | 
				
			||||||
 | 
					    outb(COM1 + COM_DLL, (uint8_t) (115200 / 9600));
 | 
				
			||||||
 | 
					    outb(COM1 + COM_DLM, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 8 data bits, 1 stop bit, parity off; turn off DLAB latch
 | 
				
			||||||
 | 
					    outb(COM1 + COM_LCR, COM_LCR_WLEN8 & ~COM_LCR_DLAB);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // No modem controls
 | 
				
			||||||
 | 
					    outb(COM1 + COM_MCR, 0);
 | 
				
			||||||
 | 
					    // Enable rcv interrupts
 | 
				
			||||||
 | 
					    outb(COM1 + COM_IER, COM_IER_RDI);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Clear any preexisting overrun indications and interrupts
 | 
				
			||||||
 | 
					    // Serial port doesn't exist if COM_LSR returns 0xFF
 | 
				
			||||||
 | 
					    serial_exists = (inb(COM1 + COM_LSR) != 0xFF);
 | 
				
			||||||
 | 
					    (void) inb(COM1+COM_IIR);
 | 
				
			||||||
 | 
					    (void) inb(COM1+COM_RX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (serial_exists) {
 | 
				
			||||||
 | 
					        pic_enable(IRQ_COM1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					lpt_putc_sub(int c) {
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; !(inb(LPTPORT + 1) & 0x80) && i < 12800; i ++) {
 | 
				
			||||||
 | 
					        delay();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    outb(LPTPORT + 0, c);
 | 
				
			||||||
 | 
					    outb(LPTPORT + 2, 0x08 | 0x04 | 0x01);
 | 
				
			||||||
 | 
					    outb(LPTPORT + 2, 0x08);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* lpt_putc - copy console output to parallel port */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					lpt_putc(int c) {
 | 
				
			||||||
 | 
					    if (c != '\b') {
 | 
				
			||||||
 | 
					        lpt_putc_sub(c);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        lpt_putc_sub('\b');
 | 
				
			||||||
 | 
					        lpt_putc_sub(' ');
 | 
				
			||||||
 | 
					        lpt_putc_sub('\b');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* cga_putc - print character to console */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					cga_putc(int c) {
 | 
				
			||||||
 | 
					    // set black on white
 | 
				
			||||||
 | 
					    if (!(c & ~0xFF)) {
 | 
				
			||||||
 | 
					        c |= 0x0700;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (c & 0xff) {
 | 
				
			||||||
 | 
					    case '\b':
 | 
				
			||||||
 | 
					        if (crt_pos > 0) {
 | 
				
			||||||
 | 
					            crt_pos --;
 | 
				
			||||||
 | 
					            crt_buf[crt_pos] = (c & ~0xff) | ' ';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case '\n':
 | 
				
			||||||
 | 
					        crt_pos += CRT_COLS;
 | 
				
			||||||
 | 
					    case '\r':
 | 
				
			||||||
 | 
					        crt_pos -= (crt_pos % CRT_COLS);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        crt_buf[crt_pos ++] = c;     // write the character
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // What is the purpose of this?
 | 
				
			||||||
 | 
					    if (crt_pos >= CRT_SIZE) {
 | 
				
			||||||
 | 
					        int i;
 | 
				
			||||||
 | 
					        memmove(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t));
 | 
				
			||||||
 | 
					        for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i ++) {
 | 
				
			||||||
 | 
					            crt_buf[i] = 0x0700 | ' ';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        crt_pos -= CRT_COLS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // move that little blinky thing
 | 
				
			||||||
 | 
					    outb(addr_6845, 14);
 | 
				
			||||||
 | 
					    outb(addr_6845 + 1, crt_pos >> 8);
 | 
				
			||||||
 | 
					    outb(addr_6845, 15);
 | 
				
			||||||
 | 
					    outb(addr_6845 + 1, crt_pos);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					serial_putc_sub(int c) {
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; !(inb(COM1 + COM_LSR) & COM_LSR_TXRDY) && i < 12800; i ++) {
 | 
				
			||||||
 | 
					        delay();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    outb(COM1 + COM_TX, c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* serial_putc - print character to serial port */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					serial_putc(int c) {
 | 
				
			||||||
 | 
					    if (c != '\b') {
 | 
				
			||||||
 | 
					        serial_putc_sub(c);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        serial_putc_sub('\b');
 | 
				
			||||||
 | 
					        serial_putc_sub(' ');
 | 
				
			||||||
 | 
					        serial_putc_sub('\b');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Here we manage the console input buffer, where we stash characters
 | 
				
			||||||
 | 
					 * received from the keyboard or serial port whenever the corresponding
 | 
				
			||||||
 | 
					 * interrupt occurs.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CONSBUFSIZE 512
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct {
 | 
				
			||||||
 | 
					    uint8_t buf[CONSBUFSIZE];
 | 
				
			||||||
 | 
					    uint32_t rpos;
 | 
				
			||||||
 | 
					    uint32_t wpos;
 | 
				
			||||||
 | 
					} cons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * cons_intr - called by device interrupt routines to feed input
 | 
				
			||||||
 | 
					 * characters into the circular console input buffer.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					cons_intr(int (*proc)(void)) {
 | 
				
			||||||
 | 
					    int c;
 | 
				
			||||||
 | 
					    while ((c = (*proc)()) != -1) {
 | 
				
			||||||
 | 
					        if (c != 0) {
 | 
				
			||||||
 | 
					            cons.buf[cons.wpos ++] = c;
 | 
				
			||||||
 | 
					            if (cons.wpos == CONSBUFSIZE) {
 | 
				
			||||||
 | 
					                cons.wpos = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* serial_proc_data - get data from serial port */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					serial_proc_data(void) {
 | 
				
			||||||
 | 
					    if (!(inb(COM1 + COM_LSR) & COM_LSR_DATA)) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int c = inb(COM1 + COM_RX);
 | 
				
			||||||
 | 
					    if (c == 127) {
 | 
				
			||||||
 | 
					        c = '\b';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* serial_intr - try to feed input characters from serial port */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					serial_intr(void) {
 | 
				
			||||||
 | 
					    if (serial_exists) {
 | 
				
			||||||
 | 
					        cons_intr(serial_proc_data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***** Keyboard input code *****/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NO              0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SHIFT           (1<<0)
 | 
				
			||||||
 | 
					#define CTL             (1<<1)
 | 
				
			||||||
 | 
					#define ALT             (1<<2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAPSLOCK        (1<<3)
 | 
				
			||||||
 | 
					#define NUMLOCK         (1<<4)
 | 
				
			||||||
 | 
					#define SCROLLLOCK      (1<<5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define E0ESC           (1<<6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t shiftcode[256] = {
 | 
				
			||||||
 | 
					    [0x1D] CTL,
 | 
				
			||||||
 | 
					    [0x2A] SHIFT,
 | 
				
			||||||
 | 
					    [0x36] SHIFT,
 | 
				
			||||||
 | 
					    [0x38] ALT,
 | 
				
			||||||
 | 
					    [0x9D] CTL,
 | 
				
			||||||
 | 
					    [0xB8] ALT
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t togglecode[256] = {
 | 
				
			||||||
 | 
					    [0x3A] CAPSLOCK,
 | 
				
			||||||
 | 
					    [0x45] NUMLOCK,
 | 
				
			||||||
 | 
					    [0x46] SCROLLLOCK
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t normalmap[256] = {
 | 
				
			||||||
 | 
					    NO,   0x1B, '1',  '2',  '3',  '4',  '5',  '6',  // 0x00
 | 
				
			||||||
 | 
					    '7',  '8',  '9',  '0',  '-',  '=',  '\b', '\t',
 | 
				
			||||||
 | 
					    'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',  // 0x10
 | 
				
			||||||
 | 
					    'o',  'p',  '[',  ']',  '\n', NO,   'a',  's',
 | 
				
			||||||
 | 
					    'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',  // 0x20
 | 
				
			||||||
 | 
					    '\'', '`',  NO,   '\\', 'z',  'x',  'c',  'v',
 | 
				
			||||||
 | 
					    'b',  'n',  'm',  ',',  '.',  '/',  NO,   '*',  // 0x30
 | 
				
			||||||
 | 
					    NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
 | 
				
			||||||
 | 
					    NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7',  // 0x40
 | 
				
			||||||
 | 
					    '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
 | 
				
			||||||
 | 
					    '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
 | 
				
			||||||
 | 
					    [0xC7] KEY_HOME,    [0x9C] '\n' /*KP_Enter*/,
 | 
				
			||||||
 | 
					    [0xB5] '/' /*KP_Div*/,  [0xC8] KEY_UP,
 | 
				
			||||||
 | 
					    [0xC9] KEY_PGUP,    [0xCB] KEY_LF,
 | 
				
			||||||
 | 
					    [0xCD] KEY_RT,      [0xCF] KEY_END,
 | 
				
			||||||
 | 
					    [0xD0] KEY_DN,      [0xD1] KEY_PGDN,
 | 
				
			||||||
 | 
					    [0xD2] KEY_INS,     [0xD3] KEY_DEL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t shiftmap[256] = {
 | 
				
			||||||
 | 
					    NO,   033,  '!',  '@',  '#',  '$',  '%',  '^',  // 0x00
 | 
				
			||||||
 | 
					    '&',  '*',  '(',  ')',  '_',  '+',  '\b', '\t',
 | 
				
			||||||
 | 
					    'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',  // 0x10
 | 
				
			||||||
 | 
					    'O',  'P',  '{',  '}',  '\n', NO,   'A',  'S',
 | 
				
			||||||
 | 
					    'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',  // 0x20
 | 
				
			||||||
 | 
					    '"',  '~',  NO,   '|',  'Z',  'X',  'C',  'V',
 | 
				
			||||||
 | 
					    'B',  'N',  'M',  '<',  '>',  '?',  NO,   '*',  // 0x30
 | 
				
			||||||
 | 
					    NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
 | 
				
			||||||
 | 
					    NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7',  // 0x40
 | 
				
			||||||
 | 
					    '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
 | 
				
			||||||
 | 
					    '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
 | 
				
			||||||
 | 
					    [0xC7] KEY_HOME,    [0x9C] '\n' /*KP_Enter*/,
 | 
				
			||||||
 | 
					    [0xB5] '/' /*KP_Div*/,  [0xC8] KEY_UP,
 | 
				
			||||||
 | 
					    [0xC9] KEY_PGUP,    [0xCB] KEY_LF,
 | 
				
			||||||
 | 
					    [0xCD] KEY_RT,      [0xCF] KEY_END,
 | 
				
			||||||
 | 
					    [0xD0] KEY_DN,      [0xD1] KEY_PGDN,
 | 
				
			||||||
 | 
					    [0xD2] KEY_INS,     [0xD3] KEY_DEL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define C(x) (x - '@')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t ctlmap[256] = {
 | 
				
			||||||
 | 
					    NO,      NO,      NO,      NO,      NO,      NO,      NO,      NO,
 | 
				
			||||||
 | 
					    NO,      NO,      NO,      NO,      NO,      NO,      NO,      NO,
 | 
				
			||||||
 | 
					    C('Q'),  C('W'),  C('E'),  C('R'),  C('T'),  C('Y'),  C('U'),  C('I'),
 | 
				
			||||||
 | 
					    C('O'),  C('P'),  NO,      NO,      '\r',    NO,      C('A'),  C('S'),
 | 
				
			||||||
 | 
					    C('D'),  C('F'),  C('G'),  C('H'),  C('J'),  C('K'),  C('L'),  NO,
 | 
				
			||||||
 | 
					    NO,      NO,      NO,      C('\\'), C('Z'),  C('X'),  C('C'),  C('V'),
 | 
				
			||||||
 | 
					    C('B'),  C('N'),  C('M'),  NO,      NO,      C('/'),  NO,      NO,
 | 
				
			||||||
 | 
					    [0x97] KEY_HOME,
 | 
				
			||||||
 | 
					    [0xB5] C('/'),      [0xC8] KEY_UP,
 | 
				
			||||||
 | 
					    [0xC9] KEY_PGUP,    [0xCB] KEY_LF,
 | 
				
			||||||
 | 
					    [0xCD] KEY_RT,      [0xCF] KEY_END,
 | 
				
			||||||
 | 
					    [0xD0] KEY_DN,      [0xD1] KEY_PGDN,
 | 
				
			||||||
 | 
					    [0xD2] KEY_INS,     [0xD3] KEY_DEL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t *charcode[4] = {
 | 
				
			||||||
 | 
					    normalmap,
 | 
				
			||||||
 | 
					    shiftmap,
 | 
				
			||||||
 | 
					    ctlmap,
 | 
				
			||||||
 | 
					    ctlmap
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * kbd_proc_data - get data from keyboard
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The kbd_proc_data() function gets data from the keyboard.
 | 
				
			||||||
 | 
					 * If we finish a character, return it, else 0. And return -1 if no data.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					kbd_proc_data(void) {
 | 
				
			||||||
 | 
					    int c;
 | 
				
			||||||
 | 
					    uint8_t data;
 | 
				
			||||||
 | 
					    static uint32_t shift;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((inb(KBSTATP) & KBS_DIB) == 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data = inb(KBDATAP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (data == 0xE0) {
 | 
				
			||||||
 | 
					        // E0 escape character
 | 
				
			||||||
 | 
					        shift |= E0ESC;
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    } else if (data & 0x80) {
 | 
				
			||||||
 | 
					        // Key released
 | 
				
			||||||
 | 
					        data = (shift & E0ESC ? data : data & 0x7F);
 | 
				
			||||||
 | 
					        shift &= ~(shiftcode[data] | E0ESC);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    } else if (shift & E0ESC) {
 | 
				
			||||||
 | 
					        // Last character was an E0 escape; or with 0x80
 | 
				
			||||||
 | 
					        data |= 0x80;
 | 
				
			||||||
 | 
					        shift &= ~E0ESC;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shift |= shiftcode[data];
 | 
				
			||||||
 | 
					    shift ^= togglecode[data];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c = charcode[shift & (CTL | SHIFT)][data];
 | 
				
			||||||
 | 
					    if (shift & CAPSLOCK) {
 | 
				
			||||||
 | 
					        if ('a' <= c && c <= 'z')
 | 
				
			||||||
 | 
					            c += 'A' - 'a';
 | 
				
			||||||
 | 
					        else if ('A' <= c && c <= 'Z')
 | 
				
			||||||
 | 
					            c += 'a' - 'A';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Process special keys
 | 
				
			||||||
 | 
					    // Ctrl-Alt-Del: reboot
 | 
				
			||||||
 | 
					    if (!(~shift & (CTL | ALT)) && c == KEY_DEL) {
 | 
				
			||||||
 | 
					        cprintf("Rebooting!\n");
 | 
				
			||||||
 | 
					        outb(0x92, 0x3); // courtesy of Chris Frost
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* kbd_intr - try to feed input characters from keyboard */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					kbd_intr(void) {
 | 
				
			||||||
 | 
					    cons_intr(kbd_proc_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					kbd_init(void) {
 | 
				
			||||||
 | 
					    // drain the kbd buffer
 | 
				
			||||||
 | 
					    kbd_intr();
 | 
				
			||||||
 | 
					    pic_enable(IRQ_KBD);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* cons_init - initializes the console devices */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					cons_init(void) {
 | 
				
			||||||
 | 
					    cga_init();
 | 
				
			||||||
 | 
					    serial_init();
 | 
				
			||||||
 | 
					    kbd_init();
 | 
				
			||||||
 | 
					    if (!serial_exists) {
 | 
				
			||||||
 | 
					        cprintf("serial port does not exist!!\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* cons_putc - print a single character @c to console devices */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					cons_putc(int c) {
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lpt_putc(c);
 | 
				
			||||||
 | 
					        cga_putc(c);
 | 
				
			||||||
 | 
					        serial_putc(c);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * cons_getc - return the next input character from console,
 | 
				
			||||||
 | 
					 * or 0 if none waiting.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cons_getc(void) {
 | 
				
			||||||
 | 
					    int c = 0;
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // poll for any pending input characters,
 | 
				
			||||||
 | 
					        // so that this function works even when interrupts are disabled
 | 
				
			||||||
 | 
					        // (e.g., when called from the kernel monitor).
 | 
				
			||||||
 | 
					        serial_intr();
 | 
				
			||||||
 | 
					        kbd_intr();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // grab the next character from the input buffer.
 | 
				
			||||||
 | 
					        if (cons.rpos != cons.wpos) {
 | 
				
			||||||
 | 
					            c = cons.buf[cons.rpos ++];
 | 
				
			||||||
 | 
					            if (cons.rpos == CONSBUFSIZE) {
 | 
				
			||||||
 | 
					                cons.rpos = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					    return c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/console.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/console.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DRIVER_CONSOLE_H__
 | 
				
			||||||
 | 
					#define __KERN_DRIVER_CONSOLE_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cons_init(void);
 | 
				
			||||||
 | 
					void cons_putc(int c);
 | 
				
			||||||
 | 
					int cons_getc(void);
 | 
				
			||||||
 | 
					void serial_intr(void);
 | 
				
			||||||
 | 
					void kbd_intr(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DRIVER_CONSOLE_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										214
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/ide.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/ide.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,214 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <picirq.h>
 | 
				
			||||||
 | 
					#include <fs.h>
 | 
				
			||||||
 | 
					#include <ide.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ISA_DATA                0x00
 | 
				
			||||||
 | 
					#define ISA_ERROR               0x01
 | 
				
			||||||
 | 
					#define ISA_PRECOMP             0x01
 | 
				
			||||||
 | 
					#define ISA_CTRL                0x02
 | 
				
			||||||
 | 
					#define ISA_SECCNT              0x02
 | 
				
			||||||
 | 
					#define ISA_SECTOR              0x03
 | 
				
			||||||
 | 
					#define ISA_CYL_LO              0x04
 | 
				
			||||||
 | 
					#define ISA_CYL_HI              0x05
 | 
				
			||||||
 | 
					#define ISA_SDH                 0x06
 | 
				
			||||||
 | 
					#define ISA_COMMAND             0x07
 | 
				
			||||||
 | 
					#define ISA_STATUS              0x07
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IDE_BSY                 0x80
 | 
				
			||||||
 | 
					#define IDE_DRDY                0x40
 | 
				
			||||||
 | 
					#define IDE_DF                  0x20
 | 
				
			||||||
 | 
					#define IDE_DRQ                 0x08
 | 
				
			||||||
 | 
					#define IDE_ERR                 0x01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IDE_CMD_READ            0x20
 | 
				
			||||||
 | 
					#define IDE_CMD_WRITE           0x30
 | 
				
			||||||
 | 
					#define IDE_CMD_IDENTIFY        0xEC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IDE_IDENT_SECTORS       20
 | 
				
			||||||
 | 
					#define IDE_IDENT_MODEL         54
 | 
				
			||||||
 | 
					#define IDE_IDENT_CAPABILITIES  98
 | 
				
			||||||
 | 
					#define IDE_IDENT_CMDSETS       164
 | 
				
			||||||
 | 
					#define IDE_IDENT_MAX_LBA       120
 | 
				
			||||||
 | 
					#define IDE_IDENT_MAX_LBA_EXT   200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IO_BASE0                0x1F0
 | 
				
			||||||
 | 
					#define IO_BASE1                0x170
 | 
				
			||||||
 | 
					#define IO_CTRL0                0x3F4
 | 
				
			||||||
 | 
					#define IO_CTRL1                0x374
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_IDE                 4
 | 
				
			||||||
 | 
					#define MAX_NSECS               128
 | 
				
			||||||
 | 
					#define MAX_DISK_NSECS          0x10000000U
 | 
				
			||||||
 | 
					#define VALID_IDE(ideno)        (((ideno) >= 0) && ((ideno) < MAX_IDE) && (ide_devices[ideno].valid))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct {
 | 
				
			||||||
 | 
					    unsigned short base;        // I/O Base
 | 
				
			||||||
 | 
					    unsigned short ctrl;        // Control Base
 | 
				
			||||||
 | 
					} channels[2] = {
 | 
				
			||||||
 | 
					    {IO_BASE0, IO_CTRL0},
 | 
				
			||||||
 | 
					    {IO_BASE1, IO_CTRL1},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IO_BASE(ideno)          (channels[(ideno) >> 1].base)
 | 
				
			||||||
 | 
					#define IO_CTRL(ideno)          (channels[(ideno) >> 1].ctrl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ide_device {
 | 
				
			||||||
 | 
					    unsigned char valid;        // 0 or 1 (If Device Really Exists)
 | 
				
			||||||
 | 
					    unsigned int sets;          // Commend Sets Supported
 | 
				
			||||||
 | 
					    unsigned int size;          // Size in Sectors
 | 
				
			||||||
 | 
					    unsigned char model[41];    // Model in String
 | 
				
			||||||
 | 
					} ide_devices[MAX_IDE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					ide_wait_ready(unsigned short iobase, bool check_error) {
 | 
				
			||||||
 | 
					    int r;
 | 
				
			||||||
 | 
					    while ((r = inb(iobase + ISA_STATUS)) & IDE_BSY)
 | 
				
			||||||
 | 
					        /* nothing */;
 | 
				
			||||||
 | 
					    if (check_error && (r & (IDE_DF | IDE_ERR)) != 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					ide_init(void) {
 | 
				
			||||||
 | 
					    static_assert((SECTSIZE % 4) == 0);
 | 
				
			||||||
 | 
					    unsigned short ideno, iobase;
 | 
				
			||||||
 | 
					    for (ideno = 0; ideno < MAX_IDE; ideno ++) {
 | 
				
			||||||
 | 
					        /* assume that no device here */
 | 
				
			||||||
 | 
					        ide_devices[ideno].valid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        iobase = IO_BASE(ideno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* wait device ready */
 | 
				
			||||||
 | 
					        ide_wait_ready(iobase, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* step1: select drive */
 | 
				
			||||||
 | 
					        outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4));
 | 
				
			||||||
 | 
					        ide_wait_ready(iobase, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* step2: send ATA identify command */
 | 
				
			||||||
 | 
					        outb(iobase + ISA_COMMAND, IDE_CMD_IDENTIFY);
 | 
				
			||||||
 | 
					        ide_wait_ready(iobase, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* step3: polling */
 | 
				
			||||||
 | 
					        if (inb(iobase + ISA_STATUS) == 0 || ide_wait_ready(iobase, 1) != 0) {
 | 
				
			||||||
 | 
					            continue ;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* device is ok */
 | 
				
			||||||
 | 
					        ide_devices[ideno].valid = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* read identification space of the device */
 | 
				
			||||||
 | 
					        unsigned int buffer[128];
 | 
				
			||||||
 | 
					        insl(iobase + ISA_DATA, buffer, sizeof(buffer) / sizeof(unsigned int));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsigned char *ident = (unsigned char *)buffer;
 | 
				
			||||||
 | 
					        unsigned int sectors;
 | 
				
			||||||
 | 
					        unsigned int cmdsets = *(unsigned int *)(ident + IDE_IDENT_CMDSETS);
 | 
				
			||||||
 | 
					        /* device use 48-bits or 28-bits addressing */
 | 
				
			||||||
 | 
					        if (cmdsets & (1 << 26)) {
 | 
				
			||||||
 | 
					            sectors = *(unsigned int *)(ident + IDE_IDENT_MAX_LBA_EXT);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            sectors = *(unsigned int *)(ident + IDE_IDENT_MAX_LBA);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ide_devices[ideno].sets = cmdsets;
 | 
				
			||||||
 | 
					        ide_devices[ideno].size = sectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* check if supports LBA */
 | 
				
			||||||
 | 
					        assert((*(unsigned short *)(ident + IDE_IDENT_CAPABILITIES) & 0x200) != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsigned char *model = ide_devices[ideno].model, *data = ident + IDE_IDENT_MODEL;
 | 
				
			||||||
 | 
					        unsigned int i, length = 40;
 | 
				
			||||||
 | 
					        for (i = 0; i < length; i += 2) {
 | 
				
			||||||
 | 
					            model[i] = data[i + 1], model[i + 1] = data[i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        do {
 | 
				
			||||||
 | 
					            model[i] = '\0';
 | 
				
			||||||
 | 
					        } while (i -- > 0 && model[i] == ' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cprintf("ide %d: %10u(sectors), '%s'.\n", ideno, ide_devices[ideno].size, ide_devices[ideno].model);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // enable ide interrupt
 | 
				
			||||||
 | 
					    pic_enable(IRQ_IDE1);
 | 
				
			||||||
 | 
					    pic_enable(IRQ_IDE2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					ide_device_valid(unsigned short ideno) {
 | 
				
			||||||
 | 
					    return VALID_IDE(ideno);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t
 | 
				
			||||||
 | 
					ide_device_size(unsigned short ideno) {
 | 
				
			||||||
 | 
					    if (ide_device_valid(ideno)) {
 | 
				
			||||||
 | 
					        return ide_devices[ideno].size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					ide_read_secs(unsigned short ideno, uint32_t secno, void *dst, size_t nsecs) {
 | 
				
			||||||
 | 
					    assert(nsecs <= MAX_NSECS && VALID_IDE(ideno));
 | 
				
			||||||
 | 
					    assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS);
 | 
				
			||||||
 | 
					    unsigned short iobase = IO_BASE(ideno), ioctrl = IO_CTRL(ideno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ide_wait_ready(iobase, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // generate interrupt
 | 
				
			||||||
 | 
					    outb(ioctrl + ISA_CTRL, 0);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_SECCNT, nsecs);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_SECTOR, secno & 0xFF);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_CYL_LO, (secno >> 8) & 0xFF);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_CYL_HI, (secno >> 16) & 0xFF);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4) | ((secno >> 24) & 0xF));
 | 
				
			||||||
 | 
					    outb(iobase + ISA_COMMAND, IDE_CMD_READ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = 0;
 | 
				
			||||||
 | 
					    for (; nsecs > 0; nsecs --, dst += SECTSIZE) {
 | 
				
			||||||
 | 
					        if ((ret = ide_wait_ready(iobase, 1)) != 0) {
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        insl(iobase, dst, SECTSIZE / sizeof(uint32_t));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					ide_write_secs(unsigned short ideno, uint32_t secno, const void *src, size_t nsecs) {
 | 
				
			||||||
 | 
					    assert(nsecs <= MAX_NSECS && VALID_IDE(ideno));
 | 
				
			||||||
 | 
					    assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS);
 | 
				
			||||||
 | 
					    unsigned short iobase = IO_BASE(ideno), ioctrl = IO_CTRL(ideno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ide_wait_ready(iobase, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // generate interrupt
 | 
				
			||||||
 | 
					    outb(ioctrl + ISA_CTRL, 0);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_SECCNT, nsecs);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_SECTOR, secno & 0xFF);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_CYL_LO, (secno >> 8) & 0xFF);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_CYL_HI, (secno >> 16) & 0xFF);
 | 
				
			||||||
 | 
					    outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4) | ((secno >> 24) & 0xF));
 | 
				
			||||||
 | 
					    outb(iobase + ISA_COMMAND, IDE_CMD_WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = 0;
 | 
				
			||||||
 | 
					    for (; nsecs > 0; nsecs --, src += SECTSIZE) {
 | 
				
			||||||
 | 
					        if ((ret = ide_wait_ready(iobase, 1)) != 0) {
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        outsl(iobase, src, SECTSIZE / sizeof(uint32_t));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/ide.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/ide.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DRIVER_IDE_H__
 | 
				
			||||||
 | 
					#define __KERN_DRIVER_IDE_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ide_init(void);
 | 
				
			||||||
 | 
					bool ide_device_valid(unsigned short ideno);
 | 
				
			||||||
 | 
					size_t ide_device_size(unsigned short ideno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ide_read_secs(unsigned short ideno, uint32_t secno, void *dst, size_t nsecs);
 | 
				
			||||||
 | 
					int ide_write_secs(unsigned short ideno, uint32_t secno, const void *src, size_t nsecs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DRIVER_IDE_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/intr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/intr.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <intr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* intr_enable - enable irq interrupt */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					intr_enable(void) {
 | 
				
			||||||
 | 
					    sti();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* intr_disable - disable irq interrupt */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					intr_disable(void) {
 | 
				
			||||||
 | 
					    cli();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/intr.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/intr.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DRIVER_INTR_H__
 | 
				
			||||||
 | 
					#define __KERN_DRIVER_INTR_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void intr_enable(void);
 | 
				
			||||||
 | 
					void intr_disable(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DRIVER_INTR_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										84
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/kbdreg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/kbdreg.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DRIVER_KBDREG_H__
 | 
				
			||||||
 | 
					#define __KERN_DRIVER_KBDREG_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Special keycodes
 | 
				
			||||||
 | 
					#define KEY_HOME            0xE0
 | 
				
			||||||
 | 
					#define KEY_END             0xE1
 | 
				
			||||||
 | 
					#define KEY_UP              0xE2
 | 
				
			||||||
 | 
					#define KEY_DN              0xE3
 | 
				
			||||||
 | 
					#define KEY_LF              0xE4
 | 
				
			||||||
 | 
					#define KEY_RT              0xE5
 | 
				
			||||||
 | 
					#define KEY_PGUP            0xE6
 | 
				
			||||||
 | 
					#define KEY_PGDN            0xE7
 | 
				
			||||||
 | 
					#define KEY_INS             0xE8
 | 
				
			||||||
 | 
					#define KEY_DEL             0xE9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This is i8042reg.h + kbdreg.h from NetBSD. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KBSTATP             0x64    // kbd controller status port(I)
 | 
				
			||||||
 | 
					#define KBS_DIB             0x01    // kbd data in buffer
 | 
				
			||||||
 | 
					#define KBS_IBF             0x02    // kbd input buffer low
 | 
				
			||||||
 | 
					#define KBS_WARM            0x04    // kbd input buffer low
 | 
				
			||||||
 | 
					#define BS_OCMD             0x08    // kbd output buffer has command
 | 
				
			||||||
 | 
					#define KBS_NOSEC           0x10    // kbd security lock not engaged
 | 
				
			||||||
 | 
					#define KBS_TERR            0x20    // kbd transmission error
 | 
				
			||||||
 | 
					#define KBS_RERR            0x40    // kbd receive error
 | 
				
			||||||
 | 
					#define KBS_PERR            0x80    // kbd parity error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KBCMDP              0x64    // kbd controller port(O)
 | 
				
			||||||
 | 
					#define KBC_RAMREAD         0x20    // read from RAM
 | 
				
			||||||
 | 
					#define KBC_RAMWRITE        0x60    // write to RAM
 | 
				
			||||||
 | 
					#define KBC_AUXDISABLE      0xa7    // disable auxiliary port
 | 
				
			||||||
 | 
					#define KBC_AUXENABLE       0xa8    // enable auxiliary port
 | 
				
			||||||
 | 
					#define KBC_AUXTEST         0xa9    // test auxiliary port
 | 
				
			||||||
 | 
					#define KBC_KBDECHO         0xd2    // echo to keyboard port
 | 
				
			||||||
 | 
					#define KBC_AUXECHO         0xd3    // echo to auxiliary port
 | 
				
			||||||
 | 
					#define KBC_AUXWRITE        0xd4    // write to auxiliary port
 | 
				
			||||||
 | 
					#define KBC_SELFTEST        0xaa    // start self-test
 | 
				
			||||||
 | 
					#define KBC_KBDTEST         0xab    // test keyboard port
 | 
				
			||||||
 | 
					#define KBC_KBDDISABLE      0xad    // disable keyboard port
 | 
				
			||||||
 | 
					#define KBC_KBDENABLE       0xae    // enable keyboard port
 | 
				
			||||||
 | 
					#define KBC_PULSE0          0xfe    // pulse output bit 0
 | 
				
			||||||
 | 
					#define KBC_PULSE1          0xfd    // pulse output bit 1
 | 
				
			||||||
 | 
					#define KBC_PULSE2          0xfb    // pulse output bit 2
 | 
				
			||||||
 | 
					#define KBC_PULSE3          0xf7    // pulse output bit 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KBDATAP             0x60    // kbd data port(I)
 | 
				
			||||||
 | 
					#define KBOUTP              0x60    // kbd data port(O)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define K_RDCMDBYTE         0x20
 | 
				
			||||||
 | 
					#define K_LDCMDBYTE         0x60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KC8_TRANS           0x40    // convert to old scan codes
 | 
				
			||||||
 | 
					#define KC8_MDISABLE        0x20    // disable mouse
 | 
				
			||||||
 | 
					#define KC8_KDISABLE        0x10    // disable keyboard
 | 
				
			||||||
 | 
					#define KC8_IGNSEC          0x08    // ignore security lock
 | 
				
			||||||
 | 
					#define KC8_CPU             0x04    // exit from protected mode reset
 | 
				
			||||||
 | 
					#define KC8_MENABLE         0x02    // enable mouse interrupt
 | 
				
			||||||
 | 
					#define KC8_KENABLE         0x01    // enable keyboard interrupt
 | 
				
			||||||
 | 
					#define CMDBYTE             (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* keyboard commands */
 | 
				
			||||||
 | 
					#define KBC_RESET           0xFF    // reset the keyboard
 | 
				
			||||||
 | 
					#define KBC_RESEND          0xFE    // request the keyboard resend the last byte
 | 
				
			||||||
 | 
					#define KBC_SETDEFAULT      0xF6    // resets keyboard to its power-on defaults
 | 
				
			||||||
 | 
					#define KBC_DISABLE         0xF5    // as per KBC_SETDEFAULT, but also disable key scanning
 | 
				
			||||||
 | 
					#define KBC_ENABLE          0xF4    // enable key scanning
 | 
				
			||||||
 | 
					#define KBC_TYPEMATIC       0xF3    // set typematic rate and delay
 | 
				
			||||||
 | 
					#define KBC_SETTABLE        0xF0    // set scancode translation table
 | 
				
			||||||
 | 
					#define KBC_MODEIND         0xED    // set mode indicators(i.e. LEDs)
 | 
				
			||||||
 | 
					#define KBC_ECHO            0xEE    // request an echo from the keyboard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* keyboard responses */
 | 
				
			||||||
 | 
					#define KBR_EXTENDED        0xE0    // extended key sequence
 | 
				
			||||||
 | 
					#define KBR_RESEND          0xFE    // needs resend of command
 | 
				
			||||||
 | 
					#define KBR_ACK             0xFA    // received a valid command
 | 
				
			||||||
 | 
					#define KBR_OVERRUN         0x00    // flooded
 | 
				
			||||||
 | 
					#define KBR_FAILURE         0xFD    // diagnosic failure
 | 
				
			||||||
 | 
					#define KBR_BREAK           0xF0    // break code prefix - sent on key release
 | 
				
			||||||
 | 
					#define KBR_RSTDONE         0xAA    // reset complete
 | 
				
			||||||
 | 
					#define KBR_ECHO            0xEE    // echo response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DRIVER_KBDREG_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										86
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/picirq.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/picirq.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <picirq.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// I/O Addresses of the two programmable interrupt controllers
 | 
				
			||||||
 | 
					#define IO_PIC1             0x20    // Master (IRQs 0-7)
 | 
				
			||||||
 | 
					#define IO_PIC2             0xA0    // Slave (IRQs 8-15)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IRQ_SLAVE           2       // IRQ at which slave connects to master
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Current IRQ mask.
 | 
				
			||||||
 | 
					// Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
 | 
				
			||||||
 | 
					static uint16_t irq_mask = 0xFFFF & ~(1 << IRQ_SLAVE);
 | 
				
			||||||
 | 
					static bool did_init = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					pic_setmask(uint16_t mask) {
 | 
				
			||||||
 | 
					    irq_mask = mask;
 | 
				
			||||||
 | 
					    if (did_init) {
 | 
				
			||||||
 | 
					        outb(IO_PIC1 + 1, mask);
 | 
				
			||||||
 | 
					        outb(IO_PIC2 + 1, mask >> 8);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					pic_enable(unsigned int irq) {
 | 
				
			||||||
 | 
					    pic_setmask(irq_mask & ~(1 << irq));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* pic_init - initialize the 8259A interrupt controllers */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					pic_init(void) {
 | 
				
			||||||
 | 
					    did_init = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // mask all interrupts
 | 
				
			||||||
 | 
					    outb(IO_PIC1 + 1, 0xFF);
 | 
				
			||||||
 | 
					    outb(IO_PIC2 + 1, 0xFF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Set up master (8259A-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ICW1:  0001g0hi
 | 
				
			||||||
 | 
					    //    g:  0 = edge triggering, 1 = level triggering
 | 
				
			||||||
 | 
					    //    h:  0 = cascaded PICs, 1 = master only
 | 
				
			||||||
 | 
					    //    i:  0 = no ICW4, 1 = ICW4 required
 | 
				
			||||||
 | 
					    outb(IO_PIC1, 0x11);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ICW2:  Vector offset
 | 
				
			||||||
 | 
					    outb(IO_PIC1 + 1, IRQ_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ICW3:  (master PIC) bit mask of IR lines connected to slaves
 | 
				
			||||||
 | 
					    //        (slave PIC) 3-bit # of slave's connection to master
 | 
				
			||||||
 | 
					    outb(IO_PIC1 + 1, 1 << IRQ_SLAVE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ICW4:  000nbmap
 | 
				
			||||||
 | 
					    //    n:  1 = special fully nested mode
 | 
				
			||||||
 | 
					    //    b:  1 = buffered mode
 | 
				
			||||||
 | 
					    //    m:  0 = slave PIC, 1 = master PIC
 | 
				
			||||||
 | 
					    //        (ignored when b is 0, as the master/slave role
 | 
				
			||||||
 | 
					    //         can be hardwired).
 | 
				
			||||||
 | 
					    //    a:  1 = Automatic EOI mode
 | 
				
			||||||
 | 
					    //    p:  0 = MCS-80/85 mode, 1 = intel x86 mode
 | 
				
			||||||
 | 
					    outb(IO_PIC1 + 1, 0x3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Set up slave (8259A-2)
 | 
				
			||||||
 | 
					    outb(IO_PIC2, 0x11);    // ICW1
 | 
				
			||||||
 | 
					    outb(IO_PIC2 + 1, IRQ_OFFSET + 8);  // ICW2
 | 
				
			||||||
 | 
					    outb(IO_PIC2 + 1, IRQ_SLAVE);       // ICW3
 | 
				
			||||||
 | 
					    // NB Automatic EOI mode doesn't tend to work on the slave.
 | 
				
			||||||
 | 
					    // Linux source code says it's "to be investigated".
 | 
				
			||||||
 | 
					    outb(IO_PIC2 + 1, 0x3);             // ICW4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // OCW3:  0ef01prs
 | 
				
			||||||
 | 
					    //   ef:  0x = NOP, 10 = clear specific mask, 11 = set specific mask
 | 
				
			||||||
 | 
					    //    p:  0 = no polling, 1 = polling mode
 | 
				
			||||||
 | 
					    //   rs:  0x = NOP, 10 = read IRR, 11 = read ISR
 | 
				
			||||||
 | 
					    outb(IO_PIC1, 0x68);    // clear specific mask
 | 
				
			||||||
 | 
					    outb(IO_PIC1, 0x0a);    // read IRR by default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    outb(IO_PIC2, 0x68);    // OCW3
 | 
				
			||||||
 | 
					    outb(IO_PIC2, 0x0a);    // OCW3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (irq_mask != 0xFFFF) {
 | 
				
			||||||
 | 
					        pic_setmask(irq_mask);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/picirq.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								related_info/lab5/lab5-spoc-discuss/kern/driver/picirq.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_DRIVER_PICIRQ_H__
 | 
				
			||||||
 | 
					#define __KERN_DRIVER_PICIRQ_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pic_init(void);
 | 
				
			||||||
 | 
					void pic_enable(unsigned int irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IRQ_OFFSET      32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_DRIVER_PICIRQ_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								related_info/lab5/lab5-spoc-discuss/kern/fs/fs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								related_info/lab5/lab5-spoc-discuss/kern/fs/fs.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_FS_FS_H__
 | 
				
			||||||
 | 
					#define __KERN_FS_FS_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SECTSIZE            512
 | 
				
			||||||
 | 
					#define PAGE_NSECT          (PGSIZE / SECTSIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SWAP_DEV_NO         1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_FS_FS_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								related_info/lab5/lab5-spoc-discuss/kern/fs/swapfs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								related_info/lab5/lab5-spoc-discuss/kern/fs/swapfs.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					#include <swapfs.h>
 | 
				
			||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					#include <fs.h>
 | 
				
			||||||
 | 
					#include <ide.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					swapfs_init(void) {
 | 
				
			||||||
 | 
					    static_assert((PGSIZE % SECTSIZE) == 0);
 | 
				
			||||||
 | 
					    if (!ide_device_valid(SWAP_DEV_NO)) {
 | 
				
			||||||
 | 
					        panic("swap fs isn't available.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    max_swap_offset = ide_device_size(SWAP_DEV_NO) / (PGSIZE / SECTSIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swapfs_read(swap_entry_t entry, struct Page *page) {
 | 
				
			||||||
 | 
					    return ide_read_secs(SWAP_DEV_NO, swap_offset(entry) * PAGE_NSECT, page2kva(page), PAGE_NSECT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swapfs_write(swap_entry_t entry, struct Page *page) {
 | 
				
			||||||
 | 
					    return ide_write_secs(SWAP_DEV_NO, swap_offset(entry) * PAGE_NSECT, page2kva(page), PAGE_NSECT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								related_info/lab5/lab5-spoc-discuss/kern/fs/swapfs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								related_info/lab5/lab5-spoc-discuss/kern/fs/swapfs.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_FS_SWAPFS_H__
 | 
				
			||||||
 | 
					#define __KERN_FS_SWAPFS_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void swapfs_init(void);
 | 
				
			||||||
 | 
					int swapfs_read(swap_entry_t entry, struct Page *page);
 | 
				
			||||||
 | 
					int swapfs_write(swap_entry_t entry, struct Page *page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_FS_SWAPFS_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										49
									
								
								related_info/lab5/lab5-spoc-discuss/kern/init/entry.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								related_info/lab5/lab5-spoc-discuss/kern/init/entry.S
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REALLOC(x) (x - KERNBASE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.text
 | 
				
			||||||
 | 
					.globl kern_entry
 | 
				
			||||||
 | 
					kern_entry:
 | 
				
			||||||
 | 
					    # reload temperate gdt (second time) to remap all physical memory
 | 
				
			||||||
 | 
					    # virtual_addr 0~4G=linear_addr&physical_addr -KERNBASE~4G-KERNBASE 
 | 
				
			||||||
 | 
					    lgdt REALLOC(__gdtdesc)
 | 
				
			||||||
 | 
					    movl $KERNEL_DS, %eax
 | 
				
			||||||
 | 
					    movw %ax, %ds
 | 
				
			||||||
 | 
					    movw %ax, %es
 | 
				
			||||||
 | 
					    movw %ax, %ss
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ljmp $KERNEL_CS, $relocated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					relocated:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # set ebp, esp
 | 
				
			||||||
 | 
					    movl $0x0, %ebp
 | 
				
			||||||
 | 
					    # the kernel stack region is from bootstack -- bootstacktop,
 | 
				
			||||||
 | 
					    # the kernel stack size is KSTACKSIZE (8KB)defined in memlayout.h
 | 
				
			||||||
 | 
					    movl $bootstacktop, %esp
 | 
				
			||||||
 | 
					    # now kernel stack is ready , call the first C function
 | 
				
			||||||
 | 
					    call kern_init
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# should never get here
 | 
				
			||||||
 | 
					spin:
 | 
				
			||||||
 | 
					    jmp spin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.data
 | 
				
			||||||
 | 
					.align PGSIZE
 | 
				
			||||||
 | 
					    .globl bootstack
 | 
				
			||||||
 | 
					bootstack:
 | 
				
			||||||
 | 
					    .space KSTACKSIZE
 | 
				
			||||||
 | 
					    .globl bootstacktop
 | 
				
			||||||
 | 
					bootstacktop:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.align 4
 | 
				
			||||||
 | 
					__gdt:
 | 
				
			||||||
 | 
					    SEG_NULL
 | 
				
			||||||
 | 
					    SEG_ASM(STA_X | STA_R, - KERNBASE, 0xFFFFFFFF)      # code segment
 | 
				
			||||||
 | 
					    SEG_ASM(STA_W, - KERNBASE, 0xFFFFFFFF)              # data segment
 | 
				
			||||||
 | 
					__gdtdesc:
 | 
				
			||||||
 | 
					    .word 0x17                                          # sizeof(__gdt) - 1
 | 
				
			||||||
 | 
					    .long REALLOC(__gdt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										113
									
								
								related_info/lab5/lab5-spoc-discuss/kern/init/init.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								related_info/lab5/lab5-spoc-discuss/kern/init/init.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <console.h>
 | 
				
			||||||
 | 
					#include <kdebug.h>
 | 
				
			||||||
 | 
					#include <picirq.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <clock.h>
 | 
				
			||||||
 | 
					#include <intr.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <vmm.h>
 | 
				
			||||||
 | 
					#include <ide.h>
 | 
				
			||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					#include <proc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int kern_init(void) __attribute__((noreturn));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void lab1_switch_test(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					kern_init(void) {
 | 
				
			||||||
 | 
					    extern char edata[], end[];
 | 
				
			||||||
 | 
					    memset(edata, 0, end - edata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cons_init();                // init the console
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *message = "(THU.CST) os is loading ...";
 | 
				
			||||||
 | 
					    cprintf("%s\n\n", message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print_kerninfo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    grade_backtrace();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pmm_init();                 // init physical memory management
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pic_init();                 // init interrupt controller
 | 
				
			||||||
 | 
					    idt_init();                 // init interrupt descriptor table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vmm_init();                 // init virtual memory management
 | 
				
			||||||
 | 
					    proc_init();                // init process table
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ide_init();                 // init ide devices
 | 
				
			||||||
 | 
					    swap_init();                // init swap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clock_init();               // init clock interrupt
 | 
				
			||||||
 | 
					    intr_enable();              // enable irq interrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //LAB1: CAHLLENGE 1 If you try to do it, uncomment lab1_switch_test()
 | 
				
			||||||
 | 
					    // user/kernel mode switch test
 | 
				
			||||||
 | 
					    //lab1_switch_test();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    cpu_idle();                 // run idle process
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __attribute__((noinline))
 | 
				
			||||||
 | 
					grade_backtrace2(int arg0, int arg1, int arg2, int arg3) {
 | 
				
			||||||
 | 
					    mon_backtrace(0, NULL, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __attribute__((noinline))
 | 
				
			||||||
 | 
					grade_backtrace1(int arg0, int arg1) {
 | 
				
			||||||
 | 
					    grade_backtrace2(arg0, (int)&arg0, arg1, (int)&arg1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __attribute__((noinline))
 | 
				
			||||||
 | 
					grade_backtrace0(int arg0, int arg1, int arg2) {
 | 
				
			||||||
 | 
					    grade_backtrace1(arg0, arg2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					grade_backtrace(void) {
 | 
				
			||||||
 | 
					    grade_backtrace0(0, (int)kern_init, 0xffff0000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					lab1_print_cur_status(void) {
 | 
				
			||||||
 | 
					    static int round = 0;
 | 
				
			||||||
 | 
					    uint16_t reg1, reg2, reg3, reg4;
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					            "mov %%cs, %0;"
 | 
				
			||||||
 | 
					            "mov %%ds, %1;"
 | 
				
			||||||
 | 
					            "mov %%es, %2;"
 | 
				
			||||||
 | 
					            "mov %%ss, %3;"
 | 
				
			||||||
 | 
					            : "=m"(reg1), "=m"(reg2), "=m"(reg3), "=m"(reg4));
 | 
				
			||||||
 | 
					    cprintf("%d: @ring %d\n", round, reg1 & 3);
 | 
				
			||||||
 | 
					    cprintf("%d:  cs = %x\n", round, reg1);
 | 
				
			||||||
 | 
					    cprintf("%d:  ds = %x\n", round, reg2);
 | 
				
			||||||
 | 
					    cprintf("%d:  es = %x\n", round, reg3);
 | 
				
			||||||
 | 
					    cprintf("%d:  ss = %x\n", round, reg4);
 | 
				
			||||||
 | 
					    round ++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					lab1_switch_to_user(void) {
 | 
				
			||||||
 | 
					    //LAB1 CHALLENGE 1 : TODO
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					lab1_switch_to_kernel(void) {
 | 
				
			||||||
 | 
					    //LAB1 CHALLENGE 1 :  TODO
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					lab1_switch_test(void) {
 | 
				
			||||||
 | 
					    lab1_print_cur_status();
 | 
				
			||||||
 | 
					    cprintf("+++ switch to  user  mode +++\n");
 | 
				
			||||||
 | 
					    lab1_switch_to_user();
 | 
				
			||||||
 | 
					    lab1_print_cur_status();
 | 
				
			||||||
 | 
					    cprintf("+++ switch to kernel mode +++\n");
 | 
				
			||||||
 | 
					    lab1_switch_to_kernel();
 | 
				
			||||||
 | 
					    lab1_print_cur_status();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										528
									
								
								related_info/lab5/lab5-spoc-discuss/kern/libs/rb_tree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										528
									
								
								related_info/lab5/lab5-spoc-discuss/kern/libs/rb_tree.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,528 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <kmalloc.h>
 | 
				
			||||||
 | 
					#include <rb_tree.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* rb_node_create - create a new rb_node */
 | 
				
			||||||
 | 
					static inline rb_node *
 | 
				
			||||||
 | 
					rb_node_create(void) {
 | 
				
			||||||
 | 
					    return kmalloc(sizeof(rb_node));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* rb_tree_empty - tests if tree is empty */
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					rb_tree_empty(rb_tree *tree) {
 | 
				
			||||||
 | 
					    rb_node *nil = tree->nil, *root = tree->root;
 | 
				
			||||||
 | 
					    return root->left == nil;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_tree_create - creates a new red-black tree, the 'compare' function
 | 
				
			||||||
 | 
					 * is required and returns 'NULL' if failed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that, root->left should always point to the node that is the root
 | 
				
			||||||
 | 
					 * of the tree. And nil points to a 'NULL' node which should always be
 | 
				
			||||||
 | 
					 * black and may have arbitrary children and parent node.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					rb_tree *
 | 
				
			||||||
 | 
					rb_tree_create(int (*compare)(rb_node *node1, rb_node *node2)) {
 | 
				
			||||||
 | 
					    assert(compare != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rb_tree *tree;
 | 
				
			||||||
 | 
					    rb_node *nil, *root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((tree = kmalloc(sizeof(rb_tree))) == NULL) {
 | 
				
			||||||
 | 
					        goto bad_tree;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tree->compare = compare;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((nil = rb_node_create()) == NULL) {
 | 
				
			||||||
 | 
					        goto bad_node_cleanup_tree;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nil->parent = nil->left = nil->right = nil;
 | 
				
			||||||
 | 
					    nil->red = 0;
 | 
				
			||||||
 | 
					    tree->nil = nil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((root = rb_node_create()) == NULL) {
 | 
				
			||||||
 | 
					        goto bad_node_cleanup_nil;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    root->parent = root->left = root->right = nil;
 | 
				
			||||||
 | 
					    root->red = 0;
 | 
				
			||||||
 | 
					    tree->root = root;
 | 
				
			||||||
 | 
					    return tree;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bad_node_cleanup_nil:
 | 
				
			||||||
 | 
					    kfree(nil);
 | 
				
			||||||
 | 
					bad_node_cleanup_tree:
 | 
				
			||||||
 | 
					    kfree(tree);
 | 
				
			||||||
 | 
					bad_tree:
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * FUNC_ROTATE - rotates as described in "Introduction to Algorithm".
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For example, FUNC_ROTATE(rb_left_rotate, left, right) can be expaned to a
 | 
				
			||||||
 | 
					 * left-rotate function, which requires an red-black 'tree' and a node 'x'
 | 
				
			||||||
 | 
					 * to be rotated on. Basically, this function, named rb_left_rotate, makes the
 | 
				
			||||||
 | 
					 * parent of 'x' be the left child of 'x', 'x' the parent of its parent before
 | 
				
			||||||
 | 
					 * rotation and finally fixes other nodes accordingly.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * FUNC_ROTATE(xx, left, right) means left-rotate,
 | 
				
			||||||
 | 
					 * and FUNC_ROTATE(xx, right, left) means right-rotate.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					#define FUNC_ROTATE(func_name, _left, _right)                   \
 | 
				
			||||||
 | 
					static void                                                     \
 | 
				
			||||||
 | 
					func_name(rb_tree *tree, rb_node *x) {                          \
 | 
				
			||||||
 | 
					    rb_node *nil = tree->nil, *y = x->_right;                   \
 | 
				
			||||||
 | 
					    assert(x != tree->root && x != nil && y != nil);            \
 | 
				
			||||||
 | 
					    x->_right = y->_left;                                       \
 | 
				
			||||||
 | 
					    if (y->_left != nil) {                                      \
 | 
				
			||||||
 | 
					        y->_left->parent = x;                                   \
 | 
				
			||||||
 | 
					    }                                                           \
 | 
				
			||||||
 | 
					    y->parent = x->parent;                                      \
 | 
				
			||||||
 | 
					    if (x == x->parent->_left) {                                \
 | 
				
			||||||
 | 
					        x->parent->_left = y;                                   \
 | 
				
			||||||
 | 
					    }                                                           \
 | 
				
			||||||
 | 
					    else {                                                      \
 | 
				
			||||||
 | 
					        x->parent->_right = y;                                  \
 | 
				
			||||||
 | 
					    }                                                           \
 | 
				
			||||||
 | 
					    y->_left = x;                                               \
 | 
				
			||||||
 | 
					    x->parent = y;                                              \
 | 
				
			||||||
 | 
					    assert(!(nil->red));                                        \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FUNC_ROTATE(rb_left_rotate, left, right);
 | 
				
			||||||
 | 
					FUNC_ROTATE(rb_right_rotate, right, left);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef FUNC_ROTATE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define COMPARE(tree, node1, node2)                             \
 | 
				
			||||||
 | 
					    ((tree))->compare((node1), (node2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_insert_binary - insert @node to red-black @tree as if it were
 | 
				
			||||||
 | 
					 * a regular binary tree. This function is only intended to be called
 | 
				
			||||||
 | 
					 * by function rb_insert.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					rb_insert_binary(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *x, *y, *z = node, *nil = tree->nil, *root = tree->root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    z->left = z->right = nil;
 | 
				
			||||||
 | 
					    y = root, x = y->left;
 | 
				
			||||||
 | 
					    while (x != nil) {
 | 
				
			||||||
 | 
					        y = x;
 | 
				
			||||||
 | 
					        x = (COMPARE(tree, x, node) > 0) ? x->left : x->right;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    z->parent = y;
 | 
				
			||||||
 | 
					    if (y == root || COMPARE(tree, y, z) > 0) {
 | 
				
			||||||
 | 
					        y->left = z;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        y->right = z;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* rb_insert - insert a node to red-black tree */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					rb_insert(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_insert_binary(tree, node);
 | 
				
			||||||
 | 
					    node->red = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rb_node *x = node, *y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RB_INSERT_SUB(_left, _right)                            \
 | 
				
			||||||
 | 
					    do {                                                        \
 | 
				
			||||||
 | 
					        y = x->parent->parent->_right;                          \
 | 
				
			||||||
 | 
					        if (y->red) {                                           \
 | 
				
			||||||
 | 
					            x->parent->red = 0;                                 \
 | 
				
			||||||
 | 
					            y->red = 0;                                         \
 | 
				
			||||||
 | 
					            x->parent->parent->red = 1;                         \
 | 
				
			||||||
 | 
					            x = x->parent->parent;                              \
 | 
				
			||||||
 | 
					        }                                                       \
 | 
				
			||||||
 | 
					        else {                                                  \
 | 
				
			||||||
 | 
					            if (x == x->parent->_right) {                       \
 | 
				
			||||||
 | 
					                x = x->parent;                                  \
 | 
				
			||||||
 | 
					                rb_##_left##_rotate(tree, x);                   \
 | 
				
			||||||
 | 
					            }                                                   \
 | 
				
			||||||
 | 
					            x->parent->red = 0;                                 \
 | 
				
			||||||
 | 
					            x->parent->parent->red = 1;                         \
 | 
				
			||||||
 | 
					            rb_##_right##_rotate(tree, x->parent->parent);      \
 | 
				
			||||||
 | 
					        }                                                       \
 | 
				
			||||||
 | 
					    } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (x->parent->red) {
 | 
				
			||||||
 | 
					        if (x->parent == x->parent->parent->left) {
 | 
				
			||||||
 | 
					            RB_INSERT_SUB(left, right);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            RB_INSERT_SUB(right, left);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    tree->root->left->red = 0;
 | 
				
			||||||
 | 
					    assert(!(tree->nil->red) && !(tree->root->red));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef RB_INSERT_SUB
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_tree_successor - returns the successor of @node, or nil
 | 
				
			||||||
 | 
					 * if no successor exists. Make sure that @node must belong to @tree,
 | 
				
			||||||
 | 
					 * and this function should only be called by rb_node_prev.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline rb_node *
 | 
				
			||||||
 | 
					rb_tree_successor(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *x = node, *y, *nil = tree->nil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((y = x->right) != nil) {
 | 
				
			||||||
 | 
					        while (y->left != nil) {
 | 
				
			||||||
 | 
					            y = y->left;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        y = x->parent;
 | 
				
			||||||
 | 
					        while (x == y->right) {
 | 
				
			||||||
 | 
					            x = y, y = y->parent;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (y == tree->root) {
 | 
				
			||||||
 | 
					            return nil;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_tree_predecessor - returns the predecessor of @node, or nil
 | 
				
			||||||
 | 
					 * if no predecessor exists, likes rb_tree_successor.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline rb_node *
 | 
				
			||||||
 | 
					rb_tree_predecessor(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *x = node, *y, *nil = tree->nil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((y = x->left) != nil) {
 | 
				
			||||||
 | 
					        while (y->right != nil) {
 | 
				
			||||||
 | 
					            y = y->right;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        y = x->parent;
 | 
				
			||||||
 | 
					        while (x == y->left) {
 | 
				
			||||||
 | 
					            if (y == tree->root) {
 | 
				
			||||||
 | 
					                return nil;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            x = y, y = y->parent;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_search - returns a node with value 'equal' to @key (according to
 | 
				
			||||||
 | 
					 * function @compare). If there're multiple nodes with value 'equal' to @key,
 | 
				
			||||||
 | 
					 * the functions returns the one highest in the tree.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					rb_node *
 | 
				
			||||||
 | 
					rb_search(rb_tree *tree, int (*compare)(rb_node *node, void *key), void *key) {
 | 
				
			||||||
 | 
					    rb_node *nil = tree->nil, *node = tree->root->left;
 | 
				
			||||||
 | 
					    int r;
 | 
				
			||||||
 | 
					    while (node != nil && (r = compare(node, key)) != 0) {
 | 
				
			||||||
 | 
					        node = (r > 0) ? node->left : node->right;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return (node != nil) ? node : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_delete_fixup - performs rotations and changes colors to restore
 | 
				
			||||||
 | 
					 * red-black properties after a node is deleted.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					rb_delete_fixup(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *x = node, *w, *root = tree->root->left;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RB_DELETE_FIXUP_SUB(_left, _right)                      \
 | 
				
			||||||
 | 
					    do {                                                        \
 | 
				
			||||||
 | 
					        w = x->parent->_right;                                  \
 | 
				
			||||||
 | 
					        if (w->red) {                                           \
 | 
				
			||||||
 | 
					            w->red = 0;                                         \
 | 
				
			||||||
 | 
					            x->parent->red = 1;                                 \
 | 
				
			||||||
 | 
					            rb_##_left##_rotate(tree, x->parent);               \
 | 
				
			||||||
 | 
					            w = x->parent->_right;                              \
 | 
				
			||||||
 | 
					        }                                                       \
 | 
				
			||||||
 | 
					        if (!w->_left->red && !w->_right->red) {                \
 | 
				
			||||||
 | 
					            w->red = 1;                                         \
 | 
				
			||||||
 | 
					            x = x->parent;                                      \
 | 
				
			||||||
 | 
					        }                                                       \
 | 
				
			||||||
 | 
					        else {                                                  \
 | 
				
			||||||
 | 
					            if (!w->_right->red) {                              \
 | 
				
			||||||
 | 
					                w->_left->red = 0;                              \
 | 
				
			||||||
 | 
					                w->red = 1;                                     \
 | 
				
			||||||
 | 
					                rb_##_right##_rotate(tree, w);                  \
 | 
				
			||||||
 | 
					                w = x->parent->_right;                          \
 | 
				
			||||||
 | 
					            }                                                   \
 | 
				
			||||||
 | 
					            w->red = x->parent->red;                            \
 | 
				
			||||||
 | 
					            x->parent->red = 0;                                 \
 | 
				
			||||||
 | 
					            w->_right->red = 0;                                 \
 | 
				
			||||||
 | 
					            rb_##_left##_rotate(tree, x->parent);               \
 | 
				
			||||||
 | 
					            x = root;                                           \
 | 
				
			||||||
 | 
					        }                                                       \
 | 
				
			||||||
 | 
					    } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (x != root && !x->red) {
 | 
				
			||||||
 | 
					        if (x == x->parent->left) {
 | 
				
			||||||
 | 
					            RB_DELETE_FIXUP_SUB(left, right);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            RB_DELETE_FIXUP_SUB(right, left);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    x->red = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef RB_DELETE_FIXUP_SUB
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_delete - deletes @node from @tree, and calls rb_delete_fixup to
 | 
				
			||||||
 | 
					 * restore red-black properties.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					rb_delete(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *x, *y, *z = node;
 | 
				
			||||||
 | 
					    rb_node *nil = tree->nil, *root = tree->root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    y = (z->left == nil || z->right == nil) ? z : rb_tree_successor(tree, z);
 | 
				
			||||||
 | 
					    x = (y->left != nil) ? y->left : y->right;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(y != root && y != nil);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    x->parent = y->parent;
 | 
				
			||||||
 | 
					    if (y == y->parent->left) {
 | 
				
			||||||
 | 
					        y->parent->left = x;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        y->parent->right = x;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool need_fixup = !(y->red);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (y != z) {
 | 
				
			||||||
 | 
					        if (z == z->parent->left) {
 | 
				
			||||||
 | 
					            z->parent->left = y;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            z->parent->right = y;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        z->left->parent = z->right->parent = y;
 | 
				
			||||||
 | 
					        *y = *z;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (need_fixup) {
 | 
				
			||||||
 | 
					        rb_delete_fixup(tree, x);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* rb_tree_destroy - destroy a tree and free memory */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					rb_tree_destroy(rb_tree *tree) {
 | 
				
			||||||
 | 
					    kfree(tree->root);
 | 
				
			||||||
 | 
					    kfree(tree->nil);
 | 
				
			||||||
 | 
					    kfree(tree);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_node_prev - returns the predecessor node of @node in @tree,
 | 
				
			||||||
 | 
					 * or 'NULL' if no predecessor exists.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					rb_node *
 | 
				
			||||||
 | 
					rb_node_prev(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *prev = rb_tree_predecessor(tree, node);
 | 
				
			||||||
 | 
					    return (prev != tree->nil) ? prev : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rb_node_next - returns the successor node of @node in @tree,
 | 
				
			||||||
 | 
					 * or 'NULL' if no successor exists.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					rb_node *
 | 
				
			||||||
 | 
					rb_node_next(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *next = rb_tree_successor(tree, node);
 | 
				
			||||||
 | 
					    return (next != tree->nil) ? next : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* rb_node_root - returns the root node of a @tree, or 'NULL' if tree is empty */
 | 
				
			||||||
 | 
					rb_node *
 | 
				
			||||||
 | 
					rb_node_root(rb_tree *tree) {
 | 
				
			||||||
 | 
					    rb_node *node = tree->root->left;
 | 
				
			||||||
 | 
					    return (node != tree->nil) ? node : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* rb_node_left - gets the left child of @node, or 'NULL' if no such node */
 | 
				
			||||||
 | 
					rb_node *
 | 
				
			||||||
 | 
					rb_node_left(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *left = node->left;
 | 
				
			||||||
 | 
					    return (left != tree->nil) ? left : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* rb_node_right - gets the right child of @node, or 'NULL' if no such node */
 | 
				
			||||||
 | 
					rb_node *
 | 
				
			||||||
 | 
					rb_node_right(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *right = node->right;
 | 
				
			||||||
 | 
					    return (right != tree->nil) ? right : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					check_tree(rb_tree *tree, rb_node *node) {
 | 
				
			||||||
 | 
					    rb_node *nil = tree->nil;
 | 
				
			||||||
 | 
					    if (node == nil) {
 | 
				
			||||||
 | 
					        assert(!node->red);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (node->left != nil) {
 | 
				
			||||||
 | 
					        assert(COMPARE(tree, node, node->left) >= 0);
 | 
				
			||||||
 | 
					        assert(node->left->parent == node);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (node->right != nil) {
 | 
				
			||||||
 | 
					        assert(COMPARE(tree, node, node->right) <= 0);
 | 
				
			||||||
 | 
					        assert(node->right->parent == node);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (node->red) {
 | 
				
			||||||
 | 
					        assert(!node->left->red && !node->right->red);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int hb_left = check_tree(tree, node->left);
 | 
				
			||||||
 | 
					    int hb_right = check_tree(tree, node->right);
 | 
				
			||||||
 | 
					    assert(hb_left == hb_right);
 | 
				
			||||||
 | 
					    int hb = hb_left;
 | 
				
			||||||
 | 
					    if (!node->red) {
 | 
				
			||||||
 | 
					        hb ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return hb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *
 | 
				
			||||||
 | 
					check_safe_kmalloc(size_t size) {
 | 
				
			||||||
 | 
					    void *ret = kmalloc(size);
 | 
				
			||||||
 | 
					    assert(ret != NULL);
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct check_data {
 | 
				
			||||||
 | 
					    long data;
 | 
				
			||||||
 | 
					    rb_node rb_link;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define rbn2data(node)              \
 | 
				
			||||||
 | 
					    (to_struct(node, struct check_data, rb_link))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					check_compare1(rb_node *node1, rb_node *node2) {
 | 
				
			||||||
 | 
					    return rbn2data(node1)->data - rbn2data(node2)->data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					check_compare2(rb_node *node, void *key) {
 | 
				
			||||||
 | 
					    return rbn2data(node)->data - (long)key;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					check_rb_tree(void) {
 | 
				
			||||||
 | 
					    rb_tree *tree = rb_tree_create(check_compare1);
 | 
				
			||||||
 | 
					    assert(tree != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rb_node *nil = tree->nil, *root = tree->root;
 | 
				
			||||||
 | 
					    assert(!nil->red && root->left == nil);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int total = 1000;
 | 
				
			||||||
 | 
					    struct check_data **all = check_safe_kmalloc(sizeof(struct check_data *) * total);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    long i;
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        all[i] = check_safe_kmalloc(sizeof(struct check_data));
 | 
				
			||||||
 | 
					        all[i]->data = i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int *mark = check_safe_kmalloc(sizeof(int) * total);
 | 
				
			||||||
 | 
					    memset(mark, 0, sizeof(int) * total);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        mark[all[i]->data] = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        assert(mark[i] == 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        int j = (rand() % (total - i)) + i;
 | 
				
			||||||
 | 
					        struct check_data *z = all[i];
 | 
				
			||||||
 | 
					        all[i] = all[j];
 | 
				
			||||||
 | 
					        all[j] = z;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(mark, 0, sizeof(int) * total);
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        mark[all[i]->data] = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        assert(mark[i] == 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        rb_insert(tree, &(all[i]->rb_link));
 | 
				
			||||||
 | 
					        check_tree(tree, root->left);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rb_node *node;
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        node = rb_search(tree, check_compare2, (void *)(all[i]->data));
 | 
				
			||||||
 | 
					        assert(node != NULL && node == &(all[i]->rb_link));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        node = rb_search(tree, check_compare2, (void *)i);
 | 
				
			||||||
 | 
					        assert(node != NULL && rbn2data(node)->data == i);
 | 
				
			||||||
 | 
					        rb_delete(tree, node);
 | 
				
			||||||
 | 
					        check_tree(tree, root->left);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(!nil->red && root->left == nil);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    long max = 32;
 | 
				
			||||||
 | 
					    if (max > total) {
 | 
				
			||||||
 | 
					        max = total;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < max; i ++) {
 | 
				
			||||||
 | 
					        all[i]->data = max;
 | 
				
			||||||
 | 
					        rb_insert(tree, &(all[i]->rb_link));
 | 
				
			||||||
 | 
					        check_tree(tree, root->left);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < max; i ++) {
 | 
				
			||||||
 | 
					        node = rb_search(tree, check_compare2, (void *)max);
 | 
				
			||||||
 | 
					        assert(node != NULL && rbn2data(node)->data == max);
 | 
				
			||||||
 | 
					        rb_delete(tree, node);
 | 
				
			||||||
 | 
					        check_tree(tree, root->left);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(rb_tree_empty(tree));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        rb_insert(tree, &(all[i]->rb_link));
 | 
				
			||||||
 | 
					        check_tree(tree, root->left);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rb_tree_destroy(tree);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < total; i ++) {
 | 
				
			||||||
 | 
					        kfree(all[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    kfree(mark);
 | 
				
			||||||
 | 
					    kfree(all);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										32
									
								
								related_info/lab5/lab5-spoc-discuss/kern/libs/rb_tree.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								related_info/lab5/lab5-spoc-discuss/kern/libs/rb_tree.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_LIBS_RB_TREE_H__
 | 
				
			||||||
 | 
					#define __KERN_LIBS_RB_TREE_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct rb_node {
 | 
				
			||||||
 | 
					    bool red;                           // if red = 0, it's a black node
 | 
				
			||||||
 | 
					    struct rb_node *parent;
 | 
				
			||||||
 | 
					    struct rb_node *left, *right;
 | 
				
			||||||
 | 
					} rb_node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct rb_tree {
 | 
				
			||||||
 | 
					    // compare function should return -1 if *node1 < *node2, 1 if *node1 > *node2, and 0 otherwise
 | 
				
			||||||
 | 
					    int (*compare)(rb_node *node1, rb_node *node2);
 | 
				
			||||||
 | 
					    struct rb_node *nil, *root;
 | 
				
			||||||
 | 
					} rb_tree;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rb_tree *rb_tree_create(int (*compare)(rb_node *node1, rb_node *node2));
 | 
				
			||||||
 | 
					void rb_tree_destroy(rb_tree *tree);
 | 
				
			||||||
 | 
					void rb_insert(rb_tree *tree, rb_node *node);
 | 
				
			||||||
 | 
					void rb_delete(rb_tree *tree, rb_node *node);
 | 
				
			||||||
 | 
					rb_node *rb_search(rb_tree *tree, int (*compare)(rb_node *node, void *key), void *key);
 | 
				
			||||||
 | 
					rb_node *rb_node_prev(rb_tree *tree, rb_node *node);
 | 
				
			||||||
 | 
					rb_node *rb_node_next(rb_tree *tree, rb_node *node);
 | 
				
			||||||
 | 
					rb_node *rb_node_root(rb_tree *tree);
 | 
				
			||||||
 | 
					rb_node *rb_node_left(rb_tree *tree, rb_node *node);
 | 
				
			||||||
 | 
					rb_node *rb_node_right(rb_tree *tree, rb_node *node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void check_rb_tree(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_LIBS_RBTREE_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										50
									
								
								related_info/lab5/lab5-spoc-discuss/kern/libs/readline.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								related_info/lab5/lab5-spoc-discuss/kern/libs/readline.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BUFSIZE 1024
 | 
				
			||||||
 | 
					static char buf[BUFSIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * readline - get a line from stdin
 | 
				
			||||||
 | 
					 * @prompt:     the string to be written to stdout
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The readline() function will write the input string @prompt to
 | 
				
			||||||
 | 
					 * stdout first. If the @prompt is NULL or the empty string,
 | 
				
			||||||
 | 
					 * no prompt is issued.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function will keep on reading characters and saving them to buffer
 | 
				
			||||||
 | 
					 * 'buf' until '\n' or '\r' is encountered.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that, if the length of string that will be read is longer than
 | 
				
			||||||
 | 
					 * buffer size, the end of string will be discarded.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The readline() function returns the text of the line read. If some errors
 | 
				
			||||||
 | 
					 * are happened, NULL is returned. The return value is a global variable,
 | 
				
			||||||
 | 
					 * thus it should be copied before it is used.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					readline(const char *prompt) {
 | 
				
			||||||
 | 
					    if (prompt != NULL) {
 | 
				
			||||||
 | 
					        cprintf("%s", prompt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int i = 0, c;
 | 
				
			||||||
 | 
					    while (1) {
 | 
				
			||||||
 | 
					        c = getchar();
 | 
				
			||||||
 | 
					        if (c < 0) {
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (c >= ' ' && i < BUFSIZE - 1) {
 | 
				
			||||||
 | 
					            cputchar(c);
 | 
				
			||||||
 | 
					            buf[i ++] = c;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (c == '\b' && i > 0) {
 | 
				
			||||||
 | 
					            cputchar(c);
 | 
				
			||||||
 | 
					            i --;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (c == '\n' || c == '\r') {
 | 
				
			||||||
 | 
					            cputchar(c);
 | 
				
			||||||
 | 
					            buf[i] = '\0';
 | 
				
			||||||
 | 
					            return buf;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										78
									
								
								related_info/lab5/lab5-spoc-discuss/kern/libs/stdio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								related_info/lab5/lab5-spoc-discuss/kern/libs/stdio.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <console.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* HIGH level console I/O */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * cputch - writes a single character @c to stdout, and it will
 | 
				
			||||||
 | 
					 * increace the value of counter pointed by @cnt.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					cputch(int c, int *cnt) {
 | 
				
			||||||
 | 
					    cons_putc(c);
 | 
				
			||||||
 | 
					    (*cnt) ++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * vcprintf - format a string and writes it to stdout
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The return value is the number of characters which would be
 | 
				
			||||||
 | 
					 * written to stdout.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Call this function if you are already dealing with a va_list.
 | 
				
			||||||
 | 
					 * Or you probably want cprintf() instead.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					vcprintf(const char *fmt, va_list ap) {
 | 
				
			||||||
 | 
					    int cnt = 0;
 | 
				
			||||||
 | 
					    vprintfmt((void*)cputch, &cnt, fmt, ap);
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * cprintf - formats a string and writes it to stdout
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The return value is the number of characters which would be
 | 
				
			||||||
 | 
					 * written to stdout.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cprintf(const char *fmt, ...) {
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    int cnt;
 | 
				
			||||||
 | 
					    va_start(ap, fmt);
 | 
				
			||||||
 | 
					    cnt = vcprintf(fmt, ap);
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* cputchar - writes a single character to stdout */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					cputchar(int c) {
 | 
				
			||||||
 | 
					    cons_putc(c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * cputs- writes the string pointed by @str to stdout and
 | 
				
			||||||
 | 
					 * appends a newline character.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cputs(const char *str) {
 | 
				
			||||||
 | 
					    int cnt = 0;
 | 
				
			||||||
 | 
					    char c;
 | 
				
			||||||
 | 
					    while ((c = *str ++) != '\0') {
 | 
				
			||||||
 | 
					        cputch(c, &cnt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cputch('\n', &cnt);
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* getchar - reads a single non-zero character from stdin */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					getchar(void) {
 | 
				
			||||||
 | 
					    int c;
 | 
				
			||||||
 | 
					    while ((c = cons_getc()) == 0)
 | 
				
			||||||
 | 
					        /* do nothing */;
 | 
				
			||||||
 | 
					    return c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										294
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/default_pmm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/default_pmm.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,294 @@
 | 
				
			|||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <list.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <default_pmm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* In the first fit algorithm, the allocator keeps a list of free blocks (known as the free list) and,
 | 
				
			||||||
 | 
					   on receiving a request for memory, scans along the list for the first block that is large enough to
 | 
				
			||||||
 | 
					   satisfy the request. If the chosen block is significantly larger than that requested, then it is 
 | 
				
			||||||
 | 
					   usually split, and the remainder added to the list as another free block.
 | 
				
			||||||
 | 
					   Please see Page 196~198, Section 8.2 of Yan Wei Ming's chinese book "Data Structure -- C programming language"
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					// LAB2 EXERCISE 1: YOUR CODE
 | 
				
			||||||
 | 
					// you should rewrite functions: default_init,default_init_memmap,default_alloc_pages, default_free_pages.
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Details of FFMA
 | 
				
			||||||
 | 
					 * (1) Prepare: In order to implement the First-Fit Mem Alloc (FFMA), we should manage the free mem block use some list.
 | 
				
			||||||
 | 
					 *              The struct free_area_t is used for the management of free mem blocks. At first you should
 | 
				
			||||||
 | 
					 *              be familiar to the struct list in list.h. struct list is a simple doubly linked list implementation.
 | 
				
			||||||
 | 
					 *              You should know howto USE: list_init, list_add(list_add_after), list_add_before, list_del, list_next, list_prev
 | 
				
			||||||
 | 
					 *              Another tricky method is to transform a general list struct to a special struct (such as struct page):
 | 
				
			||||||
 | 
					 *              you can find some MACRO: le2page (in memlayout.h), (in future labs: le2vma (in vmm.h), le2proc (in proc.h),etc.)
 | 
				
			||||||
 | 
					 * (2) default_init: you can reuse the  demo default_init fun to init the free_list and set nr_free to 0.
 | 
				
			||||||
 | 
					 *              free_list is used to record the free mem blocks. nr_free is the total number for free mem blocks.
 | 
				
			||||||
 | 
					 * (3) default_init_memmap:  CALL GRAPH: kern_init --> pmm_init-->page_init-->init_memmap--> pmm_manager->init_memmap
 | 
				
			||||||
 | 
					 *              This fun is used to init a free block (with parameter: addr_base, page_number).
 | 
				
			||||||
 | 
					 *              First you should init each page (in memlayout.h) in this free block, include:
 | 
				
			||||||
 | 
					 *                  p->flags should be set bit PG_property (means this page is valid. In pmm_init fun (in pmm.c),
 | 
				
			||||||
 | 
					 *                  the bit PG_reserved is setted in p->flags)
 | 
				
			||||||
 | 
					 *                  if this page  is free and is not the first page of free block, p->property should be set to 0.
 | 
				
			||||||
 | 
					 *                  if this page  is free and is the first page of free block, p->property should be set to total num of block.
 | 
				
			||||||
 | 
					 *                  p->ref should be 0, because now p is free and no reference.
 | 
				
			||||||
 | 
					 *                  We can use p->page_link to link this page to free_list, (such as: list_add_before(&free_list, &(p->page_link)); )
 | 
				
			||||||
 | 
					 *              Finally, we should sum the number of free mem block: nr_free+=n
 | 
				
			||||||
 | 
					 * (4) default_alloc_pages: search find a first free block (block size >=n) in free list and reszie the free block, return the addr
 | 
				
			||||||
 | 
					 *              of malloced block.
 | 
				
			||||||
 | 
					 *              (4.1) So you should search freelist like this:
 | 
				
			||||||
 | 
					 *                       list_entry_t le = &free_list;
 | 
				
			||||||
 | 
					 *                       while((le=list_next(le)) != &free_list) {
 | 
				
			||||||
 | 
					 *                       ....
 | 
				
			||||||
 | 
					 *                 (4.1.1) In while loop, get the struct page and check the p->property (record the num of free block) >=n?
 | 
				
			||||||
 | 
					 *                       struct Page *p = le2page(le, page_link);
 | 
				
			||||||
 | 
					 *                       if(p->property >= n){ ...
 | 
				
			||||||
 | 
					 *                 (4.1.2) If we find this p, then it' means we find a free block(block size >=n), and the first n pages can be malloced.
 | 
				
			||||||
 | 
					 *                     Some flag bits of this page should be setted: PG_reserved =1, PG_property =0
 | 
				
			||||||
 | 
					 *                     unlink the pages from free_list
 | 
				
			||||||
 | 
					 *                     (4.1.2.1) If (p->property >n), we should re-caluclate number of the the rest of this free block,
 | 
				
			||||||
 | 
					 *                           (such as: le2page(le,page_link))->property = p->property - n;)
 | 
				
			||||||
 | 
					 *                 (4.1.3)  re-caluclate nr_free (number of the the rest of all free block)
 | 
				
			||||||
 | 
					 *                 (4.1.4)  return p
 | 
				
			||||||
 | 
					 *               (4.2) If we can not find a free block (block size >=n), then return NULL
 | 
				
			||||||
 | 
					 * (5) default_free_pages: relink the pages into  free list, maybe merge small free blocks into big free blocks.
 | 
				
			||||||
 | 
					 *               (5.1) according the base addr of withdrawed blocks, search free list, find the correct position
 | 
				
			||||||
 | 
					 *                     (from low to high addr), and insert the pages. (may use list_next, le2page, list_add_before)
 | 
				
			||||||
 | 
					 *               (5.2) reset the fields of pages, such as p->ref, p->flags (PageProperty)
 | 
				
			||||||
 | 
					 *               (5.3) try to merge low addr or high addr blocks. Notice: should change some pages's p->property correctly.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					free_area_t free_area;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define free_list (free_area.free_list)
 | 
				
			||||||
 | 
					#define nr_free (free_area.nr_free)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					default_init(void) {
 | 
				
			||||||
 | 
					    list_init(&free_list);
 | 
				
			||||||
 | 
					    nr_free = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					default_init_memmap(struct Page *base, size_t n) {
 | 
				
			||||||
 | 
					    assert(n > 0);
 | 
				
			||||||
 | 
					    struct Page *p = base;
 | 
				
			||||||
 | 
					    for (; p != base + n; p ++) {
 | 
				
			||||||
 | 
					        assert(PageReserved(p));
 | 
				
			||||||
 | 
					        p->flags = 0;
 | 
				
			||||||
 | 
					        SetPageProperty(p);
 | 
				
			||||||
 | 
					        p->property = 0;
 | 
				
			||||||
 | 
					        set_page_ref(p, 0);
 | 
				
			||||||
 | 
					        list_add_before(&free_list, &(p->page_link));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nr_free += n;
 | 
				
			||||||
 | 
					    //first block
 | 
				
			||||||
 | 
					    base->property = n;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct Page *
 | 
				
			||||||
 | 
					default_alloc_pages(size_t n) {
 | 
				
			||||||
 | 
					    assert(n > 0);
 | 
				
			||||||
 | 
					    if (n > nr_free) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    list_entry_t *le, *len;
 | 
				
			||||||
 | 
					    le = &free_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while((le=list_next(le)) != &free_list) {
 | 
				
			||||||
 | 
					      struct Page *p = le2page(le, page_link);
 | 
				
			||||||
 | 
					      if(p->property >= n){
 | 
				
			||||||
 | 
					        int i;
 | 
				
			||||||
 | 
					        for(i=0;i<n;i++){
 | 
				
			||||||
 | 
					          len = list_next(le);
 | 
				
			||||||
 | 
					          struct Page *pp = le2page(le, page_link);
 | 
				
			||||||
 | 
					          SetPageReserved(pp);
 | 
				
			||||||
 | 
					          ClearPageProperty(pp);
 | 
				
			||||||
 | 
					          list_del(le);
 | 
				
			||||||
 | 
					          le = len;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(p->property>n){
 | 
				
			||||||
 | 
					          (le2page(le,page_link))->property = p->property - n;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ClearPageProperty(p);
 | 
				
			||||||
 | 
					        SetPageReserved(p);
 | 
				
			||||||
 | 
					        nr_free -= n;
 | 
				
			||||||
 | 
					        return p;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					default_free_pages(struct Page *base, size_t n) {
 | 
				
			||||||
 | 
					    assert(n > 0);
 | 
				
			||||||
 | 
					    assert(PageReserved(base));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    list_entry_t *le = &free_list;
 | 
				
			||||||
 | 
					    struct Page * p;
 | 
				
			||||||
 | 
					    while((le=list_next(le)) != &free_list) {
 | 
				
			||||||
 | 
					      p = le2page(le, page_link);
 | 
				
			||||||
 | 
					      if(p>base){
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //list_add_before(le, base->page_link);
 | 
				
			||||||
 | 
					    for(p=base;p<base+n;p++){
 | 
				
			||||||
 | 
					      list_add_before(le, &(p->page_link));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    base->flags = 0;
 | 
				
			||||||
 | 
					    set_page_ref(base, 0);
 | 
				
			||||||
 | 
					    ClearPageProperty(base);
 | 
				
			||||||
 | 
					    SetPageProperty(base);
 | 
				
			||||||
 | 
					    base->property = n;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    p = le2page(le,page_link) ;
 | 
				
			||||||
 | 
					    if( base+n == p ){
 | 
				
			||||||
 | 
					      base->property += p->property;
 | 
				
			||||||
 | 
					      p->property = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    le = list_prev(&(base->page_link));
 | 
				
			||||||
 | 
					    p = le2page(le, page_link);
 | 
				
			||||||
 | 
					    if(le!=&free_list && p==base-1){
 | 
				
			||||||
 | 
					      while(le!=&free_list){
 | 
				
			||||||
 | 
					        if(p->property){
 | 
				
			||||||
 | 
					          p->property += base->property;
 | 
				
			||||||
 | 
					          base->property = 0;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        le = list_prev(le);
 | 
				
			||||||
 | 
					        p = le2page(le,page_link);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nr_free += n;
 | 
				
			||||||
 | 
					    return ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t
 | 
				
			||||||
 | 
					default_nr_free_pages(void) {
 | 
				
			||||||
 | 
					    return nr_free;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					basic_check(void) {
 | 
				
			||||||
 | 
					    struct Page *p0, *p1, *p2;
 | 
				
			||||||
 | 
					    p0 = p1 = p2 = NULL;
 | 
				
			||||||
 | 
					    assert((p0 = alloc_page()) != NULL);
 | 
				
			||||||
 | 
					    assert((p1 = alloc_page()) != NULL);
 | 
				
			||||||
 | 
					    assert((p2 = alloc_page()) != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(p0 != p1 && p0 != p2 && p1 != p2);
 | 
				
			||||||
 | 
					    assert(page_ref(p0) == 0 && page_ref(p1) == 0 && page_ref(p2) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(page2pa(p0) < npage * PGSIZE);
 | 
				
			||||||
 | 
					    assert(page2pa(p1) < npage * PGSIZE);
 | 
				
			||||||
 | 
					    assert(page2pa(p2) < npage * PGSIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    list_entry_t free_list_store = free_list;
 | 
				
			||||||
 | 
					    list_init(&free_list);
 | 
				
			||||||
 | 
					    assert(list_empty(&free_list));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned int nr_free_store = nr_free;
 | 
				
			||||||
 | 
					    nr_free = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(alloc_page() == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_page(p0);
 | 
				
			||||||
 | 
					    free_page(p1);
 | 
				
			||||||
 | 
					    free_page(p2);
 | 
				
			||||||
 | 
					    assert(nr_free == 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert((p0 = alloc_page()) != NULL);
 | 
				
			||||||
 | 
					    assert((p1 = alloc_page()) != NULL);
 | 
				
			||||||
 | 
					    assert((p2 = alloc_page()) != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(alloc_page() == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_page(p0);
 | 
				
			||||||
 | 
					    assert(!list_empty(&free_list));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Page *p;
 | 
				
			||||||
 | 
					    assert((p = alloc_page()) == p0);
 | 
				
			||||||
 | 
					    assert(alloc_page() == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(nr_free == 0);
 | 
				
			||||||
 | 
					    free_list = free_list_store;
 | 
				
			||||||
 | 
					    nr_free = nr_free_store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_page(p);
 | 
				
			||||||
 | 
					    free_page(p1);
 | 
				
			||||||
 | 
					    free_page(p2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LAB2: below code is used to check the first fit allocation algorithm (your EXERCISE 1) 
 | 
				
			||||||
 | 
					// NOTICE: You SHOULD NOT CHANGE basic_check, default_check functions!
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					default_check(void) {
 | 
				
			||||||
 | 
					    int count = 0, total = 0;
 | 
				
			||||||
 | 
					    list_entry_t *le = &free_list;
 | 
				
			||||||
 | 
					    while ((le = list_next(le)) != &free_list) {
 | 
				
			||||||
 | 
					        struct Page *p = le2page(le, page_link);
 | 
				
			||||||
 | 
					        assert(PageProperty(p));
 | 
				
			||||||
 | 
					        count ++, total += p->property;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(total == nr_free_pages());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    basic_check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Page *p0 = alloc_pages(5), *p1, *p2;
 | 
				
			||||||
 | 
					    assert(p0 != NULL);
 | 
				
			||||||
 | 
					    assert(!PageProperty(p0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    list_entry_t free_list_store = free_list;
 | 
				
			||||||
 | 
					    list_init(&free_list);
 | 
				
			||||||
 | 
					    assert(list_empty(&free_list));
 | 
				
			||||||
 | 
					    assert(alloc_page() == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned int nr_free_store = nr_free;
 | 
				
			||||||
 | 
					    nr_free = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_pages(p0 + 2, 3);
 | 
				
			||||||
 | 
					    assert(alloc_pages(4) == NULL);
 | 
				
			||||||
 | 
					    assert(PageProperty(p0 + 2) && p0[2].property == 3);
 | 
				
			||||||
 | 
					    assert((p1 = alloc_pages(3)) != NULL);
 | 
				
			||||||
 | 
					    assert(alloc_page() == NULL);
 | 
				
			||||||
 | 
					    assert(p0 + 2 == p1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p2 = p0 + 1;
 | 
				
			||||||
 | 
					    free_page(p0);
 | 
				
			||||||
 | 
					    free_pages(p1, 3);
 | 
				
			||||||
 | 
					    assert(PageProperty(p0) && p0->property == 1);
 | 
				
			||||||
 | 
					    assert(PageProperty(p1) && p1->property == 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert((p0 = alloc_page()) == p2 - 1);
 | 
				
			||||||
 | 
					    free_page(p0);
 | 
				
			||||||
 | 
					    assert((p0 = alloc_pages(2)) == p2 + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_pages(p0, 2);
 | 
				
			||||||
 | 
					    free_page(p2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert((p0 = alloc_pages(5)) != NULL);
 | 
				
			||||||
 | 
					    assert(alloc_page() == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(nr_free == 0);
 | 
				
			||||||
 | 
					    nr_free = nr_free_store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_list = free_list_store;
 | 
				
			||||||
 | 
					    free_pages(p0, 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    le = &free_list;
 | 
				
			||||||
 | 
					    while ((le = list_next(le)) != &free_list) {
 | 
				
			||||||
 | 
					        struct Page *p = le2page(le, page_link);
 | 
				
			||||||
 | 
					        count --, total -= p->property;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(count == 0);
 | 
				
			||||||
 | 
					    assert(total == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct pmm_manager default_pmm_manager = {
 | 
				
			||||||
 | 
					    .name = "default_pmm_manager",
 | 
				
			||||||
 | 
					    .init = default_init,
 | 
				
			||||||
 | 
					    .init_memmap = default_init_memmap,
 | 
				
			||||||
 | 
					    .alloc_pages = default_alloc_pages,
 | 
				
			||||||
 | 
					    .free_pages = default_free_pages,
 | 
				
			||||||
 | 
					    .nr_free_pages = default_nr_free_pages,
 | 
				
			||||||
 | 
					    .check = default_check,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_MM_DEFAULT_PMM_H__
 | 
				
			||||||
 | 
					#define  __KERN_MM_DEFAULT_PMM_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct pmm_manager default_pmm_manager;
 | 
				
			||||||
 | 
					extern free_area_t free_area;
 | 
				
			||||||
 | 
					#endif /* ! __KERN_MM_DEFAULT_PMM_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										310
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/kmalloc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/kmalloc.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,310 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <list.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <kmalloc.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * SLOB Allocator: Simple List Of Blocks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Matt Mackall <mpm@selenic.com> 12/30/03
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * How SLOB works:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The core of SLOB is a traditional K&R style heap allocator, with
 | 
				
			||||||
 | 
					 * support for returning aligned objects. The granularity of this
 | 
				
			||||||
 | 
					 * allocator is 8 bytes on x86, though it's perhaps possible to reduce
 | 
				
			||||||
 | 
					 * this to 4 if it's deemed worth the effort. The slob heap is a
 | 
				
			||||||
 | 
					 * singly-linked list of pages from __get_free_page, grown on demand
 | 
				
			||||||
 | 
					 * and allocation from the heap is currently first-fit.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Above this is an implementation of kmalloc/kfree. Blocks returned
 | 
				
			||||||
 | 
					 * from kmalloc are 8-byte aligned and prepended with a 8-byte header.
 | 
				
			||||||
 | 
					 * If kmalloc is asked for objects of PAGE_SIZE or larger, it calls
 | 
				
			||||||
 | 
					 * __get_free_pages directly so that it can return page-aligned blocks
 | 
				
			||||||
 | 
					 * and keeps a linked list of such pages and their orders. These
 | 
				
			||||||
 | 
					 * objects are detected in kfree() by their page alignment.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SLAB is emulated on top of SLOB by simply calling constructors and
 | 
				
			||||||
 | 
					 * destructors for every SLAB allocation. Objects are returned with
 | 
				
			||||||
 | 
					 * the 8-byte alignment unless the SLAB_MUST_HWCACHE_ALIGN flag is
 | 
				
			||||||
 | 
					 * set, in which case the low-level allocator will fragment blocks to
 | 
				
			||||||
 | 
					 * create the proper alignment. Again, objects of page-size or greater
 | 
				
			||||||
 | 
					 * are allocated by calling __get_free_pages. As SLAB objects know
 | 
				
			||||||
 | 
					 * their size, no separate size bookkeeping is necessary and there is
 | 
				
			||||||
 | 
					 * essentially no allocation space overhead.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//some helper
 | 
				
			||||||
 | 
					#define spin_lock_irqsave(l, f) local_intr_save(f)
 | 
				
			||||||
 | 
					#define spin_unlock_irqrestore(l, f) local_intr_restore(f)
 | 
				
			||||||
 | 
					typedef unsigned int gfp_t;
 | 
				
			||||||
 | 
					#ifndef PAGE_SIZE
 | 
				
			||||||
 | 
					#define PAGE_SIZE PGSIZE
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef L1_CACHE_BYTES
 | 
				
			||||||
 | 
					#define L1_CACHE_BYTES 64
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef ALIGN
 | 
				
			||||||
 | 
					#define ALIGN(addr,size)   (((addr)+(size)-1)&(~((size)-1))) 
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct slob_block {
 | 
				
			||||||
 | 
						int units;
 | 
				
			||||||
 | 
						struct slob_block *next;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef struct slob_block slob_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SLOB_UNIT sizeof(slob_t)
 | 
				
			||||||
 | 
					#define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT)
 | 
				
			||||||
 | 
					#define SLOB_ALIGN L1_CACHE_BYTES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bigblock {
 | 
				
			||||||
 | 
						int order;
 | 
				
			||||||
 | 
						void *pages;
 | 
				
			||||||
 | 
						struct bigblock *next;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef struct bigblock bigblock_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static slob_t arena = { .next = &arena, .units = 1 };
 | 
				
			||||||
 | 
					static slob_t *slobfree = &arena;
 | 
				
			||||||
 | 
					static bigblock_t *bigblocks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void* __slob_get_free_pages(gfp_t gfp, int order)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  struct Page * page = alloc_pages(1 << order);
 | 
				
			||||||
 | 
					  if(!page)
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					  return page2kva(page);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __slob_get_free_page(gfp) __slob_get_free_pages(gfp, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void __slob_free_pages(unsigned long kva, int order)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  free_pages(kva2page(kva), 1 << order);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void slob_free(void *b, int size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *slob_alloc(size_t size, gfp_t gfp, int align)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  assert( (size + SLOB_UNIT) < PAGE_SIZE );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						slob_t *prev, *cur, *aligned = 0;
 | 
				
			||||||
 | 
						int delta = 0, units = SLOB_UNITS(size);
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&slob_lock, flags);
 | 
				
			||||||
 | 
						prev = slobfree;
 | 
				
			||||||
 | 
						for (cur = prev->next; ; prev = cur, cur = cur->next) {
 | 
				
			||||||
 | 
							if (align) {
 | 
				
			||||||
 | 
								aligned = (slob_t *)ALIGN((unsigned long)cur, align);
 | 
				
			||||||
 | 
								delta = aligned - cur;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (cur->units >= units + delta) { /* room enough? */
 | 
				
			||||||
 | 
								if (delta) { /* need to fragment head to align? */
 | 
				
			||||||
 | 
									aligned->units = cur->units - delta;
 | 
				
			||||||
 | 
									aligned->next = cur->next;
 | 
				
			||||||
 | 
									cur->next = aligned;
 | 
				
			||||||
 | 
									cur->units = delta;
 | 
				
			||||||
 | 
									prev = cur;
 | 
				
			||||||
 | 
									cur = aligned;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (cur->units == units) /* exact fit? */
 | 
				
			||||||
 | 
									prev->next = cur->next; /* unlink */
 | 
				
			||||||
 | 
								else { /* fragment */
 | 
				
			||||||
 | 
									prev->next = cur + units;
 | 
				
			||||||
 | 
									prev->next->units = cur->units - units;
 | 
				
			||||||
 | 
									prev->next->next = cur->next;
 | 
				
			||||||
 | 
									cur->units = units;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								slobfree = prev;
 | 
				
			||||||
 | 
								spin_unlock_irqrestore(&slob_lock, flags);
 | 
				
			||||||
 | 
								return cur;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (cur == slobfree) {
 | 
				
			||||||
 | 
								spin_unlock_irqrestore(&slob_lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (size == PAGE_SIZE) /* trying to shrink arena? */
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								cur = (slob_t *)__slob_get_free_page(gfp);
 | 
				
			||||||
 | 
								if (!cur)
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								slob_free(cur, PAGE_SIZE);
 | 
				
			||||||
 | 
								spin_lock_irqsave(&slob_lock, flags);
 | 
				
			||||||
 | 
								cur = slobfree;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void slob_free(void *block, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						slob_t *cur, *b = (slob_t *)block;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!block)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (size)
 | 
				
			||||||
 | 
							b->units = SLOB_UNITS(size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find reinsertion point */
 | 
				
			||||||
 | 
						spin_lock_irqsave(&slob_lock, flags);
 | 
				
			||||||
 | 
						for (cur = slobfree; !(b > cur && b < cur->next); cur = cur->next)
 | 
				
			||||||
 | 
							if (cur >= cur->next && (b > cur || b < cur->next))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (b + b->units == cur->next) {
 | 
				
			||||||
 | 
							b->units += cur->next->units;
 | 
				
			||||||
 | 
							b->next = cur->next->next;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							b->next = cur->next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cur + cur->units == b) {
 | 
				
			||||||
 | 
							cur->units += b->units;
 | 
				
			||||||
 | 
							cur->next = b->next;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							cur->next = b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						slobfree = cur;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&slob_lock, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void check_slab(void) {
 | 
				
			||||||
 | 
					  cprintf("check_slab() success\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					slab_init(void) {
 | 
				
			||||||
 | 
					  cprintf("use SLOB allocator\n");
 | 
				
			||||||
 | 
					  check_slab();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline void 
 | 
				
			||||||
 | 
					kmalloc_init(void) {
 | 
				
			||||||
 | 
					    slab_init();
 | 
				
			||||||
 | 
					    cprintf("kmalloc_init() succeeded!\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t
 | 
				
			||||||
 | 
					slab_allocated(void) {
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t
 | 
				
			||||||
 | 
					kallocated(void) {
 | 
				
			||||||
 | 
					   return slab_allocated();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int find_order(int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int order = 0;
 | 
				
			||||||
 | 
						for ( ; size > 4096 ; size >>=1)
 | 
				
			||||||
 | 
							order++;
 | 
				
			||||||
 | 
						return order;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *__kmalloc(size_t size, gfp_t gfp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						slob_t *m;
 | 
				
			||||||
 | 
						bigblock_t *bb;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (size < PAGE_SIZE - SLOB_UNIT) {
 | 
				
			||||||
 | 
							m = slob_alloc(size + SLOB_UNIT, gfp, 0);
 | 
				
			||||||
 | 
							return m ? (void *)(m + 1) : 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bb = slob_alloc(sizeof(bigblock_t), gfp, 0);
 | 
				
			||||||
 | 
						if (!bb)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bb->order = find_order(size);
 | 
				
			||||||
 | 
						bb->pages = (void *)__slob_get_free_pages(gfp, bb->order);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bb->pages) {
 | 
				
			||||||
 | 
							spin_lock_irqsave(&block_lock, flags);
 | 
				
			||||||
 | 
							bb->next = bigblocks;
 | 
				
			||||||
 | 
							bigblocks = bb;
 | 
				
			||||||
 | 
							spin_unlock_irqrestore(&block_lock, flags);
 | 
				
			||||||
 | 
							return bb->pages;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						slob_free(bb, sizeof(bigblock_t));
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *
 | 
				
			||||||
 | 
					kmalloc(size_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return __kmalloc(size, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void kfree(void *block)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bigblock_t *bb, **last = &bigblocks;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!block)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!((unsigned long)block & (PAGE_SIZE-1))) {
 | 
				
			||||||
 | 
							/* might be on the big block list */
 | 
				
			||||||
 | 
							spin_lock_irqsave(&block_lock, flags);
 | 
				
			||||||
 | 
							for (bb = bigblocks; bb; last = &bb->next, bb = bb->next) {
 | 
				
			||||||
 | 
								if (bb->pages == block) {
 | 
				
			||||||
 | 
									*last = bb->next;
 | 
				
			||||||
 | 
									spin_unlock_irqrestore(&block_lock, flags);
 | 
				
			||||||
 | 
									__slob_free_pages((unsigned long)block, bb->order);
 | 
				
			||||||
 | 
									slob_free(bb, sizeof(bigblock_t));
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							spin_unlock_irqrestore(&block_lock, flags);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						slob_free((slob_t *)block - 1, 0);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int ksize(const void *block)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bigblock_t *bb;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!block)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!((unsigned long)block & (PAGE_SIZE-1))) {
 | 
				
			||||||
 | 
							spin_lock_irqsave(&block_lock, flags);
 | 
				
			||||||
 | 
							for (bb = bigblocks; bb; bb = bb->next)
 | 
				
			||||||
 | 
								if (bb->pages == block) {
 | 
				
			||||||
 | 
									spin_unlock_irqrestore(&slob_lock, flags);
 | 
				
			||||||
 | 
									return PAGE_SIZE << bb->order;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							spin_unlock_irqrestore(&block_lock, flags);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ((slob_t *)block - 1)->units * SLOB_UNIT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										16
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/kmalloc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/kmalloc.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_MM_SLAB_H__
 | 
				
			||||||
 | 
					#define __KERN_MM_SLAB_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KMALLOC_MAX_ORDER       10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void kmalloc_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *kmalloc(size_t n);
 | 
				
			||||||
 | 
					void kfree(void *objp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t kallocated(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_MM_SLAB_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										169
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/memlayout.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/memlayout.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,169 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_MM_MEMLAYOUT_H__
 | 
				
			||||||
 | 
					#define __KERN_MM_MEMLAYOUT_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This file contains the definitions for memory management in our OS. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* global segment number */
 | 
				
			||||||
 | 
					#define SEG_KTEXT   1
 | 
				
			||||||
 | 
					#define SEG_KDATA   2
 | 
				
			||||||
 | 
					#define SEG_UTEXT   3
 | 
				
			||||||
 | 
					#define SEG_UDATA   4
 | 
				
			||||||
 | 
					#define SEG_TSS     5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* global descrptor numbers */
 | 
				
			||||||
 | 
					#define GD_KTEXT    ((SEG_KTEXT) << 3)      // kernel text
 | 
				
			||||||
 | 
					#define GD_KDATA    ((SEG_KDATA) << 3)      // kernel data
 | 
				
			||||||
 | 
					#define GD_UTEXT    ((SEG_UTEXT) << 3)      // user text
 | 
				
			||||||
 | 
					#define GD_UDATA    ((SEG_UDATA) << 3)      // user data
 | 
				
			||||||
 | 
					#define GD_TSS      ((SEG_TSS) << 3)        // task segment selector
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DPL_KERNEL  (0)
 | 
				
			||||||
 | 
					#define DPL_USER    (3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KERNEL_CS   ((GD_KTEXT) | DPL_KERNEL)
 | 
				
			||||||
 | 
					#define KERNEL_DS   ((GD_KDATA) | DPL_KERNEL)
 | 
				
			||||||
 | 
					#define USER_CS     ((GD_UTEXT) | DPL_USER)
 | 
				
			||||||
 | 
					#define USER_DS     ((GD_UDATA) | DPL_USER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Virtual memory map:                                          Permissions
 | 
				
			||||||
 | 
					 *                                                              kernel/user
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *     4G ------------------> +---------------------------------+
 | 
				
			||||||
 | 
					 *                            |                                 |
 | 
				
			||||||
 | 
					 *                            |         Empty Memory (*)        |
 | 
				
			||||||
 | 
					 *                            |                                 |
 | 
				
			||||||
 | 
					 *                            +---------------------------------+ 0xFB000000
 | 
				
			||||||
 | 
					 *                            |   Cur. Page Table (Kern, RW)    | RW/-- PTSIZE
 | 
				
			||||||
 | 
					 *     VPT -----------------> +---------------------------------+ 0xFAC00000
 | 
				
			||||||
 | 
					 *                            |        Invalid Memory (*)       | --/--
 | 
				
			||||||
 | 
					 *     KERNTOP -------------> +---------------------------------+ 0xF8000000
 | 
				
			||||||
 | 
					 *                            |                                 |
 | 
				
			||||||
 | 
					 *                            |    Remapped Physical Memory     | RW/-- KMEMSIZE
 | 
				
			||||||
 | 
					 *                            |                                 |
 | 
				
			||||||
 | 
					 *     KERNBASE ------------> +---------------------------------+ 0xC0000000
 | 
				
			||||||
 | 
					 *                            |        Invalid Memory (*)       | --/--
 | 
				
			||||||
 | 
					 *     USERTOP -------------> +---------------------------------+ 0xB0000000
 | 
				
			||||||
 | 
					 *                            |           User stack            |
 | 
				
			||||||
 | 
					 *                            +---------------------------------+
 | 
				
			||||||
 | 
					 *                            |                                 |
 | 
				
			||||||
 | 
					 *                            :                                 :
 | 
				
			||||||
 | 
					 *                            |         ~~~~~~~~~~~~~~~~        |
 | 
				
			||||||
 | 
					 *                            :                                 :
 | 
				
			||||||
 | 
					 *                            |                                 |
 | 
				
			||||||
 | 
					 *                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					 *                            |       User Program & Heap       |
 | 
				
			||||||
 | 
					 *     UTEXT ---------------> +---------------------------------+ 0x00800000
 | 
				
			||||||
 | 
					 *                            |        Invalid Memory (*)       | --/--
 | 
				
			||||||
 | 
					 *                            |  - - - - - - - - - - - - - - -  |
 | 
				
			||||||
 | 
					 *                            |    User STAB Data (optional)    |
 | 
				
			||||||
 | 
					 *     USERBASE, USTAB------> +---------------------------------+ 0x00200000
 | 
				
			||||||
 | 
					 *                            |        Invalid Memory (*)       | --/--
 | 
				
			||||||
 | 
					 *     0 -------------------> +---------------------------------+ 0x00000000
 | 
				
			||||||
 | 
					 * (*) Note: The kernel ensures that "Invalid Memory" is *never* mapped.
 | 
				
			||||||
 | 
					 *     "Empty Memory" is normally unmapped, but user programs may map pages
 | 
				
			||||||
 | 
					 *     there if desired.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* All physical memory mapped at this address */
 | 
				
			||||||
 | 
					#define KERNBASE            0xC0000000
 | 
				
			||||||
 | 
					#define KMEMSIZE            0x38000000                  // the maximum amount of physical memory
 | 
				
			||||||
 | 
					#define KERNTOP             (KERNBASE + KMEMSIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Virtual page table. Entry PDX[VPT] in the PD (Page Directory) contains
 | 
				
			||||||
 | 
					 * a pointer to the page directory itself, thereby turning the PD into a page
 | 
				
			||||||
 | 
					 * table, which maps all the PTEs (Page Table Entry) containing the page mappings
 | 
				
			||||||
 | 
					 * for the entire virtual address space into that 4 Meg region starting at VPT.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					#define VPT                 0xFAC00000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KSTACKPAGE          2                           // # of pages in kernel stack
 | 
				
			||||||
 | 
					#define KSTACKSIZE          (KSTACKPAGE * PGSIZE)       // sizeof kernel stack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USERTOP             0xB0000000
 | 
				
			||||||
 | 
					#define USTACKTOP           USERTOP
 | 
				
			||||||
 | 
					#define USTACKPAGE          256                         // # of pages in user stack
 | 
				
			||||||
 | 
					#define USTACKSIZE          (USTACKPAGE * PGSIZE)       // sizeof user stack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USERBASE            0x00200000
 | 
				
			||||||
 | 
					#define UTEXT               0x00800000                  // where user programs generally begin
 | 
				
			||||||
 | 
					#define USTAB               USERBASE                    // the location of the user STABS data structure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USER_ACCESS(start, end)                     \
 | 
				
			||||||
 | 
					(USERBASE <= (start) && (start) < (end) && (end) <= USERTOP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KERN_ACCESS(start, end)                     \
 | 
				
			||||||
 | 
					(KERNBASE <= (start) && (start) < (end) && (end) <= KERNTOP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __ASSEMBLER__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <atomic.h>
 | 
				
			||||||
 | 
					#include <list.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef uintptr_t pte_t;
 | 
				
			||||||
 | 
					typedef uintptr_t pde_t;
 | 
				
			||||||
 | 
					typedef pte_t swap_entry_t; //the pte can also be a swap entry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// some constants for bios interrupt 15h AX = 0xE820
 | 
				
			||||||
 | 
					#define E820MAX             20      // number of entries in E820MAP
 | 
				
			||||||
 | 
					#define E820_ARM            1       // address range memory
 | 
				
			||||||
 | 
					#define E820_ARR            2       // address range reserved
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct e820map {
 | 
				
			||||||
 | 
					    int nr_map;
 | 
				
			||||||
 | 
					    struct {
 | 
				
			||||||
 | 
					        uint64_t addr;
 | 
				
			||||||
 | 
					        uint64_t size;
 | 
				
			||||||
 | 
					        uint32_t type;
 | 
				
			||||||
 | 
					    } __attribute__((packed)) map[E820MAX];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * struct Page - Page descriptor structures. Each Page describes one
 | 
				
			||||||
 | 
					 * physical page. In kern/mm/pmm.h, you can find lots of useful functions
 | 
				
			||||||
 | 
					 * that convert Page to other data types, such as phyical address.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					struct Page {
 | 
				
			||||||
 | 
					    int ref;                        // page frame's reference counter
 | 
				
			||||||
 | 
					    uint32_t flags;                 // array of flags that describe the status of the page frame
 | 
				
			||||||
 | 
					    unsigned int property;          // used in buddy system, stores the order (the X in 2^X) of the continuous memory block
 | 
				
			||||||
 | 
					    int zone_num;                   // used in buddy system, the No. of zone which the page belongs to
 | 
				
			||||||
 | 
					    list_entry_t page_link;         // free list link
 | 
				
			||||||
 | 
					    list_entry_t pra_page_link;     // used for pra (page replace algorithm)
 | 
				
			||||||
 | 
					    uintptr_t pra_vaddr;            // used for pra (page replace algorithm)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Flags describing the status of a page frame */
 | 
				
			||||||
 | 
					#define PG_reserved                 0       // the page descriptor is reserved for kernel or unusable
 | 
				
			||||||
 | 
					#define PG_property                 1       // the member 'property' is valid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SetPageReserved(page)       set_bit(PG_reserved, &((page)->flags))
 | 
				
			||||||
 | 
					#define ClearPageReserved(page)     clear_bit(PG_reserved, &((page)->flags))
 | 
				
			||||||
 | 
					#define PageReserved(page)          test_bit(PG_reserved, &((page)->flags))
 | 
				
			||||||
 | 
					#define SetPageProperty(page)       set_bit(PG_property, &((page)->flags))
 | 
				
			||||||
 | 
					#define ClearPageProperty(page)     clear_bit(PG_property, &((page)->flags))
 | 
				
			||||||
 | 
					#define PageProperty(page)          test_bit(PG_property, &((page)->flags))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// convert list entry to page
 | 
				
			||||||
 | 
					#define le2page(le, member)                 \
 | 
				
			||||||
 | 
					    to_struct((le), struct Page, member)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* free_area_t - maintains a doubly linked list to record free (unused) pages */
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    list_entry_t free_list;         // the list header
 | 
				
			||||||
 | 
					    unsigned int nr_free;           // # of free pages in this free list
 | 
				
			||||||
 | 
					} free_area_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* for slab style kmalloc */
 | 
				
			||||||
 | 
					#define PG_slab                     2       // page frame is included in a slab
 | 
				
			||||||
 | 
					#define SetPageSlab(page)           set_bit(PG_slab, &((page)->flags))
 | 
				
			||||||
 | 
					#define ClearPageSlab(page)         clear_bit(PG_slab, &((page)->flags))
 | 
				
			||||||
 | 
					#define PageSlab(page)              test_bit(PG_slab, &((page)->flags))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__ASSEMBLER__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_MM_MEMLAYOUT_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										272
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/mmu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/mmu.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,272 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_MM_MMU_H__
 | 
				
			||||||
 | 
					#define __KERN_MM_MMU_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __ASSEMBLER__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SEG_NULL                                                \
 | 
				
			||||||
 | 
					    .word 0, 0;                                                 \
 | 
				
			||||||
 | 
					    .byte 0, 0, 0, 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SEG_ASM(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__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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;        \
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SEG_NULL                                            \
 | 
				
			||||||
 | 
					    (struct segdesc) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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 SEGTSS(type, base, lim, dpl)                        \
 | 
				
			||||||
 | 
					    (struct segdesc) {                                      \
 | 
				
			||||||
 | 
					        (lim) & 0xffff, (base) & 0xffff,                    \
 | 
				
			||||||
 | 
					        ((base) >> 16) & 0xff, type, 0, dpl, 1,             \
 | 
				
			||||||
 | 
					        (unsigned) (lim) >> 16, 0, 0, 1, 0,                 \
 | 
				
			||||||
 | 
					        (unsigned) (base) >> 24                             \
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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;
 | 
				
			||||||
 | 
					    uintptr_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
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__ASSEMBLER__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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 directory index
 | 
				
			||||||
 | 
					#define PDX(la) ((((uintptr_t)(la)) >> PDXSHIFT) & 0x3FF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// page table index
 | 
				
			||||||
 | 
					#define PTX(la) ((((uintptr_t)(la)) >> PTXSHIFT) & 0x3FF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// page number field of address
 | 
				
			||||||
 | 
					#define PPN(la) (((uintptr_t)(la)) >> PTXSHIFT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// offset in page
 | 
				
			||||||
 | 
					#define PGOFF(la) (((uintptr_t)(la)) & 0xFFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// construct linear address from indexes and offset
 | 
				
			||||||
 | 
					#define PGADDR(d, t, o) ((uintptr_t)((d) << PDXSHIFT | (t) << PTXSHIFT | (o)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// address in page table or page directory entry
 | 
				
			||||||
 | 
					#define PTE_ADDR(pte)   ((uintptr_t)(pte) & ~0xFFF)
 | 
				
			||||||
 | 
					#define PDE_ADDR(pde)   PTE_ADDR(pde)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* page directory and page table constants */
 | 
				
			||||||
 | 
					#define NPDEENTRY       1024                    // page directory entries per page directory
 | 
				
			||||||
 | 
					#define NPTEENTRY       1024                    // page table entries per page table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PGSIZE          4096                    // bytes mapped by a page
 | 
				
			||||||
 | 
					#define PGSHIFT         12                      // log2(PGSIZE)
 | 
				
			||||||
 | 
					#define PTSIZE          (PGSIZE * NPTEENTRY)    // 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
 | 
				
			||||||
 | 
					#define PTE_AVAIL       0xE00                   // Available for software use
 | 
				
			||||||
 | 
					                                                // 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_USER        (PTE_U | PTE_W | PTE_P)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_MM_MMU_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										785
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/pmm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										785
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/pmm.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,785 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <default_pmm.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					#include <error.h>
 | 
				
			||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					#include <vmm.h>
 | 
				
			||||||
 | 
					#include <kmalloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Task State Segment:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The TSS may reside anywhere in memory. A special segment register called
 | 
				
			||||||
 | 
					 * the Task Register (TR) holds a segment selector that points a valid TSS
 | 
				
			||||||
 | 
					 * segment descriptor which resides in the GDT. Therefore, to use a TSS
 | 
				
			||||||
 | 
					 * the following must be done in function gdt_init:
 | 
				
			||||||
 | 
					 *   - create a TSS descriptor entry in GDT
 | 
				
			||||||
 | 
					 *   - add enough information to the TSS in memory as needed
 | 
				
			||||||
 | 
					 *   - load the TR register with a segment selector for that segment
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * There are several fileds in TSS for specifying the new stack pointer when a
 | 
				
			||||||
 | 
					 * privilege level change happens. But only the fields SS0 and ESP0 are useful
 | 
				
			||||||
 | 
					 * in our os kernel.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The field SS0 contains the stack segment selector for CPL = 0, and the ESP0
 | 
				
			||||||
 | 
					 * contains the new ESP value for CPL = 0. When an interrupt happens in protected
 | 
				
			||||||
 | 
					 * mode, the x86 CPU will look in the TSS for SS0 and ESP0 and load their value
 | 
				
			||||||
 | 
					 * into SS and ESP respectively.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static struct taskstate ts = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// virtual address of physicall page array
 | 
				
			||||||
 | 
					struct Page *pages;
 | 
				
			||||||
 | 
					// amount of physical memory (in pages)
 | 
				
			||||||
 | 
					size_t npage = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// virtual address of boot-time page directory
 | 
				
			||||||
 | 
					pde_t *boot_pgdir = NULL;
 | 
				
			||||||
 | 
					// physical address of boot-time page directory
 | 
				
			||||||
 | 
					uintptr_t boot_cr3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// physical memory management
 | 
				
			||||||
 | 
					const struct pmm_manager *pmm_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * The page directory entry corresponding to the virtual address range
 | 
				
			||||||
 | 
					 * [VPT, VPT + PTSIZE) points to the page directory itself. Thus, the page
 | 
				
			||||||
 | 
					 * directory is treated as a page table as well as a page directory.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * One result of treating the page directory as a page table is that all PTEs
 | 
				
			||||||
 | 
					 * can be accessed though a "virtual page table" at virtual address VPT. And the
 | 
				
			||||||
 | 
					 * PTE for number n is stored in vpt[n].
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A second consequence is that the contents of the current page directory will
 | 
				
			||||||
 | 
					 * always available at virtual address PGADDR(PDX(VPT), PDX(VPT), 0), to which
 | 
				
			||||||
 | 
					 * vpd is set bellow.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					pte_t * const vpt = (pte_t *)VPT;
 | 
				
			||||||
 | 
					pde_t * const vpd = (pde_t *)PGADDR(PDX(VPT), PDX(VPT), 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Global Descriptor Table:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The kernel and user segments are identical (except for the DPL). To load
 | 
				
			||||||
 | 
					 * the %ss register, the CPL must equal the DPL. Thus, we must duplicate the
 | 
				
			||||||
 | 
					 * segments for the user and the kernel. Defined as follows:
 | 
				
			||||||
 | 
					 *   - 0x0 :  unused (always faults -- for trapping NULL far pointers)
 | 
				
			||||||
 | 
					 *   - 0x8 :  kernel code segment
 | 
				
			||||||
 | 
					 *   - 0x10:  kernel data segment
 | 
				
			||||||
 | 
					 *   - 0x18:  user code segment
 | 
				
			||||||
 | 
					 *   - 0x20:  user data segment
 | 
				
			||||||
 | 
					 *   - 0x28:  defined for tss, initialized in gdt_init
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static struct segdesc gdt[] = {
 | 
				
			||||||
 | 
					    SEG_NULL,
 | 
				
			||||||
 | 
					    [SEG_KTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_KERNEL),
 | 
				
			||||||
 | 
					    [SEG_KDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_KERNEL),
 | 
				
			||||||
 | 
					    [SEG_UTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_USER),
 | 
				
			||||||
 | 
					    [SEG_UDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_USER),
 | 
				
			||||||
 | 
					    [SEG_TSS]   = SEG_NULL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pseudodesc gdt_pd = {
 | 
				
			||||||
 | 
					    sizeof(gdt) - 1, (uintptr_t)gdt
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void check_alloc_page(void);
 | 
				
			||||||
 | 
					static void check_pgdir(void);
 | 
				
			||||||
 | 
					static void check_boot_pgdir(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * lgdt - load the global descriptor table register and reset the
 | 
				
			||||||
 | 
					 * data/code segement registers for kernel.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					lgdt(struct pseudodesc *pd) {
 | 
				
			||||||
 | 
					    asm volatile ("lgdt (%0)" :: "r" (pd));
 | 
				
			||||||
 | 
					    asm volatile ("movw %%ax, %%gs" :: "a" (USER_DS));
 | 
				
			||||||
 | 
					    asm volatile ("movw %%ax, %%fs" :: "a" (USER_DS));
 | 
				
			||||||
 | 
					    asm volatile ("movw %%ax, %%es" :: "a" (KERNEL_DS));
 | 
				
			||||||
 | 
					    asm volatile ("movw %%ax, %%ds" :: "a" (KERNEL_DS));
 | 
				
			||||||
 | 
					    asm volatile ("movw %%ax, %%ss" :: "a" (KERNEL_DS));
 | 
				
			||||||
 | 
					    // reload cs
 | 
				
			||||||
 | 
					    asm volatile ("ljmp %0, $1f\n 1:\n" :: "i" (KERNEL_CS));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * load_esp0 - change the ESP0 in default task state segment,
 | 
				
			||||||
 | 
					 * so that we can use different kernel stack when we trap frame
 | 
				
			||||||
 | 
					 * user to kernel.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					load_esp0(uintptr_t esp0) {
 | 
				
			||||||
 | 
					    ts.ts_esp0 = esp0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* gdt_init - initialize the default GDT and TSS */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					gdt_init(void) {
 | 
				
			||||||
 | 
					    // set boot kernel stack and default SS0
 | 
				
			||||||
 | 
					    load_esp0((uintptr_t)bootstacktop);
 | 
				
			||||||
 | 
					    ts.ts_ss0 = KERNEL_DS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // initialize the TSS filed of the gdt
 | 
				
			||||||
 | 
					    gdt[SEG_TSS] = SEGTSS(STS_T32A, (uintptr_t)&ts, sizeof(ts), DPL_KERNEL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // reload all segment registers
 | 
				
			||||||
 | 
					    lgdt(&gdt_pd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // load the TSS
 | 
				
			||||||
 | 
					    ltr(GD_TSS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//init_pmm_manager - initialize a pmm_manager instance
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					init_pmm_manager(void) {
 | 
				
			||||||
 | 
					    pmm_manager = &default_pmm_manager;
 | 
				
			||||||
 | 
					    cprintf("memory management: %s\n", pmm_manager->name);
 | 
				
			||||||
 | 
					    pmm_manager->init();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//init_memmap - call pmm->init_memmap to build Page struct for free memory  
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					init_memmap(struct Page *base, size_t n) {
 | 
				
			||||||
 | 
					    pmm_manager->init_memmap(base, n);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//alloc_pages - call pmm->alloc_pages to allocate a continuous n*PAGESIZE memory 
 | 
				
			||||||
 | 
					struct Page *
 | 
				
			||||||
 | 
					alloc_pages(size_t n) {
 | 
				
			||||||
 | 
					    struct Page *page=NULL;
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    while (1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					         local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					              page = pmm_manager->alloc_pages(n);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         if (page != NULL || n > 1 || swap_init_ok == 0) break;
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					         extern struct mm_struct *check_mm_struct;
 | 
				
			||||||
 | 
					         //cprintf("page %x, call swap_out in alloc_pages %d\n",page, n);
 | 
				
			||||||
 | 
					         swap_out(check_mm_struct, n, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //cprintf("n %d,get page %x, No %d in alloc_pages\n",n,page,(page-pages));
 | 
				
			||||||
 | 
					    return page;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//free_pages - call pmm->free_pages to free a continuous n*PAGESIZE memory 
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					free_pages(struct Page *base, size_t n) {
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        pmm_manager->free_pages(base, n);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//nr_free_pages - call pmm->nr_free_pages to get the size (nr*PAGESIZE) 
 | 
				
			||||||
 | 
					//of current free memory
 | 
				
			||||||
 | 
					size_t
 | 
				
			||||||
 | 
					nr_free_pages(void) {
 | 
				
			||||||
 | 
					    size_t ret;
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ret = pmm_manager->nr_free_pages();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* pmm_init - initialize the physical memory management */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					page_init(void) {
 | 
				
			||||||
 | 
					    struct e820map *memmap = (struct e820map *)(0x8000 + KERNBASE);
 | 
				
			||||||
 | 
					    uint64_t maxpa = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("e820map:\n");
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; i < memmap->nr_map; i ++) {
 | 
				
			||||||
 | 
					        uint64_t begin = memmap->map[i].addr, end = begin + memmap->map[i].size;
 | 
				
			||||||
 | 
					        cprintf("  memory: %08llx, [%08llx, %08llx], type = %d.\n",
 | 
				
			||||||
 | 
					                memmap->map[i].size, begin, end - 1, memmap->map[i].type);
 | 
				
			||||||
 | 
					        if (memmap->map[i].type == E820_ARM) {
 | 
				
			||||||
 | 
					            if (maxpa < end && begin < KMEMSIZE) {
 | 
				
			||||||
 | 
					                maxpa = end;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (maxpa > KMEMSIZE) {
 | 
				
			||||||
 | 
					        maxpa = KMEMSIZE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    extern char end[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    npage = maxpa / PGSIZE;
 | 
				
			||||||
 | 
					    pages = (struct Page *)ROUNDUP((void *)end, PGSIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < npage; i ++) {
 | 
				
			||||||
 | 
					        SetPageReserved(pages + i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uintptr_t freemem = PADDR((uintptr_t)pages + sizeof(struct Page) * npage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < memmap->nr_map; i ++) {
 | 
				
			||||||
 | 
					        uint64_t begin = memmap->map[i].addr, end = begin + memmap->map[i].size;
 | 
				
			||||||
 | 
					        if (memmap->map[i].type == E820_ARM) {
 | 
				
			||||||
 | 
					            if (begin < freemem) {
 | 
				
			||||||
 | 
					                begin = freemem;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (end > KMEMSIZE) {
 | 
				
			||||||
 | 
					                end = KMEMSIZE;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (begin < end) {
 | 
				
			||||||
 | 
					                begin = ROUNDUP(begin, PGSIZE);
 | 
				
			||||||
 | 
					                end = ROUNDDOWN(end, PGSIZE);
 | 
				
			||||||
 | 
					                if (begin < end) {
 | 
				
			||||||
 | 
					                    init_memmap(pa2page(begin), (end - begin) / PGSIZE);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					enable_paging(void) {
 | 
				
			||||||
 | 
					    lcr3(boot_cr3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // turn on paging
 | 
				
			||||||
 | 
					    uint32_t cr0 = rcr0();
 | 
				
			||||||
 | 
					    cr0 |= CR0_PE | CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_TS | CR0_EM | CR0_MP;
 | 
				
			||||||
 | 
					    cr0 &= ~(CR0_TS | CR0_EM);
 | 
				
			||||||
 | 
					    lcr0(cr0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//boot_map_segment - setup&enable the paging mechanism
 | 
				
			||||||
 | 
					// parameters
 | 
				
			||||||
 | 
					//  la:   linear address of this memory need to map (after x86 segment map)
 | 
				
			||||||
 | 
					//  size: memory size
 | 
				
			||||||
 | 
					//  pa:   physical address of this memory
 | 
				
			||||||
 | 
					//  perm: permission of this memory  
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					boot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, uintptr_t pa, uint32_t perm) {
 | 
				
			||||||
 | 
					    assert(PGOFF(la) == PGOFF(pa));
 | 
				
			||||||
 | 
					    size_t n = ROUNDUP(size + PGOFF(la), PGSIZE) / PGSIZE;
 | 
				
			||||||
 | 
					    la = ROUNDDOWN(la, PGSIZE);
 | 
				
			||||||
 | 
					    pa = ROUNDDOWN(pa, PGSIZE);
 | 
				
			||||||
 | 
					    for (; n > 0; n --, la += PGSIZE, pa += PGSIZE) {
 | 
				
			||||||
 | 
					        pte_t *ptep = get_pte(pgdir, la, 1);
 | 
				
			||||||
 | 
					        assert(ptep != NULL);
 | 
				
			||||||
 | 
					        *ptep = pa | PTE_P | perm;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//boot_alloc_page - allocate one page using pmm->alloc_pages(1) 
 | 
				
			||||||
 | 
					// return value: the kernel virtual address of this allocated page
 | 
				
			||||||
 | 
					//note: this function is used to get the memory for PDT(Page Directory Table)&PT(Page Table)
 | 
				
			||||||
 | 
					static void *
 | 
				
			||||||
 | 
					boot_alloc_page(void) {
 | 
				
			||||||
 | 
					    struct Page *p = alloc_page();
 | 
				
			||||||
 | 
					    if (p == NULL) {
 | 
				
			||||||
 | 
					        panic("boot_alloc_page failed.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return page2kva(p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//pmm_init - setup a pmm to manage physical memory, build PDT&PT to setup paging mechanism 
 | 
				
			||||||
 | 
					//         - check the correctness of pmm & paging mechanism, print PDT&PT
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					pmm_init(void) {
 | 
				
			||||||
 | 
					    //We need to alloc/free the physical memory (granularity is 4KB or other size). 
 | 
				
			||||||
 | 
					    //So a framework of physical memory manager (struct pmm_manager)is defined in pmm.h
 | 
				
			||||||
 | 
					    //First we should init a physical memory manager(pmm) based on the framework.
 | 
				
			||||||
 | 
					    //Then pmm can alloc/free the physical memory. 
 | 
				
			||||||
 | 
					    //Now the first_fit/best_fit/worst_fit/buddy_system pmm are available.
 | 
				
			||||||
 | 
					    init_pmm_manager();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // detect physical memory space, reserve already used memory,
 | 
				
			||||||
 | 
					    // then use pmm->init_memmap to create free page list
 | 
				
			||||||
 | 
					    page_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //use pmm->check to verify the correctness of the alloc/free function in a pmm
 | 
				
			||||||
 | 
					    check_alloc_page();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // create boot_pgdir, an initial page directory(Page Directory Table, PDT)
 | 
				
			||||||
 | 
					    boot_pgdir = boot_alloc_page();
 | 
				
			||||||
 | 
					    memset(boot_pgdir, 0, PGSIZE);
 | 
				
			||||||
 | 
					    boot_cr3 = PADDR(boot_pgdir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    check_pgdir();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static_assert(KERNBASE % PTSIZE == 0 && KERNTOP % PTSIZE == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // recursively insert boot_pgdir in itself
 | 
				
			||||||
 | 
					    // to form a virtual page table at virtual address VPT
 | 
				
			||||||
 | 
					    boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_P | PTE_W;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // map all physical memory to linear memory with base linear addr KERNBASE
 | 
				
			||||||
 | 
					    //linear_addr KERNBASE~KERNBASE+KMEMSIZE = phy_addr 0~KMEMSIZE
 | 
				
			||||||
 | 
					    //But shouldn't use this map until enable_paging() & gdt_init() finished.
 | 
				
			||||||
 | 
					    boot_map_segment(boot_pgdir, KERNBASE, KMEMSIZE, 0, PTE_W);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //temporary map: 
 | 
				
			||||||
 | 
					    //virtual_addr 3G~3G+4M = linear_addr 0~4M = linear_addr 3G~3G+4M = phy_addr 0~4M     
 | 
				
			||||||
 | 
					    boot_pgdir[0] = boot_pgdir[PDX(KERNBASE)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enable_paging();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //reload gdt(third time,the last time) to map all physical memory
 | 
				
			||||||
 | 
					    //virtual_addr 0~4G=liear_addr 0~4G
 | 
				
			||||||
 | 
					    //then set kernel stack(ss:esp) in TSS, setup TSS in gdt, load TSS
 | 
				
			||||||
 | 
					    gdt_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //disable the map of virtual_addr 0~4M
 | 
				
			||||||
 | 
					    boot_pgdir[0] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //now the basic virtual memory map(see memalyout.h) is established.
 | 
				
			||||||
 | 
					    //check the correctness of the basic virtual memory map.
 | 
				
			||||||
 | 
					    check_boot_pgdir();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print_pgdir();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    kmalloc_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//get_pte - get pte and return the kernel virtual address of this pte for la
 | 
				
			||||||
 | 
					//        - if the PT contians this pte didn't exist, alloc a page for PT
 | 
				
			||||||
 | 
					// parameter:
 | 
				
			||||||
 | 
					//  pgdir:  the kernel virtual base address of PDT
 | 
				
			||||||
 | 
					//  la:     the linear address need to map
 | 
				
			||||||
 | 
					//  create: a logical value to decide if alloc a page for PT
 | 
				
			||||||
 | 
					// return vaule: the kernel virtual address of this pte
 | 
				
			||||||
 | 
					pte_t *
 | 
				
			||||||
 | 
					get_pte(pde_t *pgdir, uintptr_t la, bool create) {
 | 
				
			||||||
 | 
					    /* LAB2 EXERCISE 2: YOUR CODE
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * If you need to visit a physical address, please use KADDR()
 | 
				
			||||||
 | 
					     * please read pmm.h for useful macros
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Maybe you want help comment, BELOW comments can help you finish the code
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Some Useful MACROs and DEFINEs, you can use them in below implementation.
 | 
				
			||||||
 | 
					     * MACROs or Functions:
 | 
				
			||||||
 | 
					     *   PDX(la) = the index of page directory entry of VIRTUAL ADDRESS la.
 | 
				
			||||||
 | 
					     *   KADDR(pa) : takes a physical address and returns the corresponding kernel virtual address.
 | 
				
			||||||
 | 
					     *   set_page_ref(page,1) : means the page be referenced by one time
 | 
				
			||||||
 | 
					     *   page2pa(page): get the physical address of memory which this (struct Page *) page  manages
 | 
				
			||||||
 | 
					     *   struct Page * alloc_page() : allocation a page
 | 
				
			||||||
 | 
					     *   memset(void *s, char c, size_t n) : sets the first n bytes of the memory area pointed by s
 | 
				
			||||||
 | 
					     *                                       to the specified value c.
 | 
				
			||||||
 | 
					     * DEFINEs:
 | 
				
			||||||
 | 
					     *   PTE_P           0x001                   // page table/directory entry flags bit : Present
 | 
				
			||||||
 | 
					     *   PTE_W           0x002                   // page table/directory entry flags bit : Writeable
 | 
				
			||||||
 | 
					     *   PTE_U           0x004                   // page table/directory entry flags bit : User can access
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    pde_t *pdep = NULL;   // (1) find page directory entry
 | 
				
			||||||
 | 
					    if (0) {              // (2) check if entry is not present
 | 
				
			||||||
 | 
					                          // (3) check if creating is needed, then alloc page for page table
 | 
				
			||||||
 | 
					                          // CAUTION: this page is used for page table, not for common data page
 | 
				
			||||||
 | 
					                          // (4) set page reference
 | 
				
			||||||
 | 
					        uintptr_t pa = 0; // (5) get linear address of page
 | 
				
			||||||
 | 
					                          // (6) clear page content using memset
 | 
				
			||||||
 | 
					                          // (7) set page directory entry's permission
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;          // (8) return page table entry
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    pde_t *pdep = &pgdir[PDX(la)];
 | 
				
			||||||
 | 
					    if (!(*pdep & PTE_P)) {
 | 
				
			||||||
 | 
					        struct Page *page;
 | 
				
			||||||
 | 
					        if (!create || (page = alloc_page()) == NULL) {
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        set_page_ref(page, 1);
 | 
				
			||||||
 | 
					        uintptr_t pa = page2pa(page);
 | 
				
			||||||
 | 
					        memset(KADDR(pa), 0, PGSIZE);
 | 
				
			||||||
 | 
					        *pdep = pa | PTE_U | PTE_W | PTE_P;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return &((pte_t *)KADDR(PDE_ADDR(*pdep)))[PTX(la)];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//get_page - get related Page struct for linear address la using PDT pgdir
 | 
				
			||||||
 | 
					struct Page *
 | 
				
			||||||
 | 
					get_page(pde_t *pgdir, uintptr_t la, pte_t **ptep_store) {
 | 
				
			||||||
 | 
					    pte_t *ptep = get_pte(pgdir, la, 0);
 | 
				
			||||||
 | 
					    if (ptep_store != NULL) {
 | 
				
			||||||
 | 
					        *ptep_store = ptep;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (ptep != NULL && *ptep & PTE_P) {
 | 
				
			||||||
 | 
					        return pa2page(*ptep);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//page_remove_pte - free an Page sturct which is related linear address la
 | 
				
			||||||
 | 
					//                - and clean(invalidate) pte which is related linear address la
 | 
				
			||||||
 | 
					//note: PT is changed, so the TLB need to be invalidate 
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					page_remove_pte(pde_t *pgdir, uintptr_t la, pte_t *ptep) {
 | 
				
			||||||
 | 
					    /* LAB2 EXERCISE 3: YOUR CODE
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Please check if ptep is valid, and tlb must be manually updated if mapping is updated
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Maybe you want help comment, BELOW comments can help you finish the code
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Some Useful MACROs and DEFINEs, you can use them in below implementation.
 | 
				
			||||||
 | 
					     * MACROs or Functions:
 | 
				
			||||||
 | 
					     *   struct Page *page pte2page(*ptep): get the according page from the value of a ptep
 | 
				
			||||||
 | 
					     *   free_page : free a page
 | 
				
			||||||
 | 
					     *   page_ref_dec(page) : decrease page->ref. NOTICE: ff page->ref == 0 , then this page should be free.
 | 
				
			||||||
 | 
					     *   tlb_invalidate(pde_t *pgdir, uintptr_t la) : Invalidate a TLB entry, but only if the page tables being
 | 
				
			||||||
 | 
					     *                        edited are the ones currently in use by the processor.
 | 
				
			||||||
 | 
					     * DEFINEs:
 | 
				
			||||||
 | 
					     *   PTE_P           0x001                   // page table/directory entry flags bit : Present
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    if (0) {                      //(1) check if page directory is present
 | 
				
			||||||
 | 
					        struct Page *page = NULL; //(2) find corresponding page to pte
 | 
				
			||||||
 | 
					                                  //(3) decrease page reference
 | 
				
			||||||
 | 
					                                  //(4) and free this page when page reference reachs 0
 | 
				
			||||||
 | 
					                                  //(5) clear second page table entry
 | 
				
			||||||
 | 
					                                  //(6) flush tlb
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    if (*ptep & PTE_P) {
 | 
				
			||||||
 | 
					        struct Page *page = pte2page(*ptep);
 | 
				
			||||||
 | 
					        if (page_ref_dec(page) == 0) {
 | 
				
			||||||
 | 
					            free_page(page);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        *ptep = 0;
 | 
				
			||||||
 | 
					        tlb_invalidate(pgdir, la);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					unmap_range(pde_t *pgdir, uintptr_t start, uintptr_t end) {
 | 
				
			||||||
 | 
					    assert(start % PGSIZE == 0 && end % PGSIZE == 0);
 | 
				
			||||||
 | 
					    assert(USER_ACCESS(start, end));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        pte_t *ptep = get_pte(pgdir, start, 0);
 | 
				
			||||||
 | 
					        if (ptep == NULL) {
 | 
				
			||||||
 | 
					            start = ROUNDDOWN(start + PTSIZE, PTSIZE);
 | 
				
			||||||
 | 
					            continue ;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (*ptep != 0) {
 | 
				
			||||||
 | 
					            page_remove_pte(pgdir, start, ptep);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        start += PGSIZE;
 | 
				
			||||||
 | 
					    } while (start != 0 && start < end);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					exit_range(pde_t *pgdir, uintptr_t start, uintptr_t end) {
 | 
				
			||||||
 | 
					    assert(start % PGSIZE == 0 && end % PGSIZE == 0);
 | 
				
			||||||
 | 
					    assert(USER_ACCESS(start, end));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    start = ROUNDDOWN(start, PTSIZE);
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        int pde_idx = PDX(start);
 | 
				
			||||||
 | 
					        if (pgdir[pde_idx] & PTE_P) {
 | 
				
			||||||
 | 
					            free_page(pde2page(pgdir[pde_idx]));
 | 
				
			||||||
 | 
					            pgdir[pde_idx] = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        start += PTSIZE;
 | 
				
			||||||
 | 
					    } while (start != 0 && start < end);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/* copy_range - copy content of memory (start, end) of one process A to another process B
 | 
				
			||||||
 | 
					 * @to:    the addr of process B's Page Directory
 | 
				
			||||||
 | 
					 * @from:  the addr of process A's Page Directory
 | 
				
			||||||
 | 
					 * @share: flags to indicate to dup OR share. We just use dup method, so it didn't be used.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * CALL GRAPH: copy_mm-->dup_mmap-->copy_range
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					copy_range(pde_t *to, pde_t *from, uintptr_t start, uintptr_t end, bool share) {
 | 
				
			||||||
 | 
					    assert(start % PGSIZE == 0 && end % PGSIZE == 0);
 | 
				
			||||||
 | 
					    assert(USER_ACCESS(start, end));
 | 
				
			||||||
 | 
					    // copy content by page unit.
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        //call get_pte to find process A's pte according to the addr start
 | 
				
			||||||
 | 
					        pte_t *ptep = get_pte(from, start, 0), *nptep;
 | 
				
			||||||
 | 
					        if (ptep == NULL) {
 | 
				
			||||||
 | 
					            start = ROUNDDOWN(start + PTSIZE, PTSIZE);
 | 
				
			||||||
 | 
					            continue ;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //call get_pte to find process B's pte according to the addr start. If pte is NULL, just alloc a PT
 | 
				
			||||||
 | 
					        if (*ptep & PTE_P) {
 | 
				
			||||||
 | 
					            if ((nptep = get_pte(to, start, 1)) == NULL) {
 | 
				
			||||||
 | 
					                return -E_NO_MEM;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        uint32_t perm = (*ptep & PTE_USER);
 | 
				
			||||||
 | 
					        //get page from ptep
 | 
				
			||||||
 | 
					        struct Page *page = pte2page(*ptep);
 | 
				
			||||||
 | 
					        // alloc a page for process B
 | 
				
			||||||
 | 
					        struct Page *npage=alloc_page();
 | 
				
			||||||
 | 
					        assert(page!=NULL);
 | 
				
			||||||
 | 
					        assert(npage!=NULL);
 | 
				
			||||||
 | 
					        int ret=0;
 | 
				
			||||||
 | 
					        /* LAB5:EXERCISE2 YOUR CODE
 | 
				
			||||||
 | 
					         * replicate content of page to npage, build the map of phy addr of nage with the linear addr start
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * Some Useful MACROs and DEFINEs, you can use them in below implementation.
 | 
				
			||||||
 | 
					         * MACROs or Functions:
 | 
				
			||||||
 | 
					         *    page2kva(struct Page *page): return the kernel vritual addr of memory which page managed (SEE pmm.h)
 | 
				
			||||||
 | 
					         *    page_insert: build the map of phy addr of an Page with the linear addr la
 | 
				
			||||||
 | 
					         *    memcpy: typical memory copy function
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * (1) find src_kvaddr: the kernel virtual address of page
 | 
				
			||||||
 | 
					         * (2) find dst_kvaddr: the kernel virtual address of npage
 | 
				
			||||||
 | 
					         * (3) memory copy from src_kvaddr to dst_kvaddr, size is PGSIZE
 | 
				
			||||||
 | 
					         * (4) build the map of phy addr of  nage with the linear addr start
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        void * kva_src = page2kva(page);
 | 
				
			||||||
 | 
					        void * kva_dst = page2kva(npage);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        memcpy(kva_dst, kva_src, PGSIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = page_insert(to, npage, start, perm);
 | 
				
			||||||
 | 
					        assert(ret == 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        start += PGSIZE;
 | 
				
			||||||
 | 
					    } while (start != 0 && start < end);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//page_remove - free an Page which is related linear address la and has an validated pte
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					page_remove(pde_t *pgdir, uintptr_t la) {
 | 
				
			||||||
 | 
					    pte_t *ptep = get_pte(pgdir, la, 0);
 | 
				
			||||||
 | 
					    if (ptep != NULL) {
 | 
				
			||||||
 | 
					        page_remove_pte(pgdir, la, ptep);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//page_insert - build the map of phy addr of an Page with the linear addr la
 | 
				
			||||||
 | 
					// paramemters:
 | 
				
			||||||
 | 
					//  pgdir: the kernel virtual base address of PDT
 | 
				
			||||||
 | 
					//  page:  the Page which need to map
 | 
				
			||||||
 | 
					//  la:    the linear address need to map
 | 
				
			||||||
 | 
					//  perm:  the permission of this Page which is setted in related pte
 | 
				
			||||||
 | 
					// return value: always 0
 | 
				
			||||||
 | 
					//note: PT is changed, so the TLB need to be invalidate 
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					page_insert(pde_t *pgdir, struct Page *page, uintptr_t la, uint32_t perm) {
 | 
				
			||||||
 | 
					    pte_t *ptep = get_pte(pgdir, la, 1);
 | 
				
			||||||
 | 
					    if (ptep == NULL) {
 | 
				
			||||||
 | 
					        return -E_NO_MEM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    page_ref_inc(page);
 | 
				
			||||||
 | 
					    if (*ptep & PTE_P) {
 | 
				
			||||||
 | 
					        struct Page *p = pte2page(*ptep);
 | 
				
			||||||
 | 
					        if (p == page) {
 | 
				
			||||||
 | 
					            page_ref_dec(page);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            page_remove_pte(pgdir, la, ptep);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    *ptep = page2pa(page) | PTE_P | perm;
 | 
				
			||||||
 | 
					    tlb_invalidate(pgdir, la);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// invalidate a TLB entry, but only if the page tables being
 | 
				
			||||||
 | 
					// edited are the ones currently in use by the processor.
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					tlb_invalidate(pde_t *pgdir, uintptr_t la) {
 | 
				
			||||||
 | 
					    if (rcr3() == PADDR(pgdir)) {
 | 
				
			||||||
 | 
					        invlpg((void *)la);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// pgdir_alloc_page - call alloc_page & page_insert functions to 
 | 
				
			||||||
 | 
					//                  - allocate a page size memory & setup an addr map
 | 
				
			||||||
 | 
					//                  - pa<->la with linear address la and the PDT pgdir
 | 
				
			||||||
 | 
					struct Page *
 | 
				
			||||||
 | 
					pgdir_alloc_page(pde_t *pgdir, uintptr_t la, uint32_t perm) {
 | 
				
			||||||
 | 
					    struct Page *page = alloc_page();
 | 
				
			||||||
 | 
					    if (page != NULL) {
 | 
				
			||||||
 | 
					        if (page_insert(pgdir, page, la, perm) != 0) {
 | 
				
			||||||
 | 
					            free_page(page);
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (swap_init_ok){
 | 
				
			||||||
 | 
					            if(check_mm_struct!=NULL) {
 | 
				
			||||||
 | 
					                swap_map_swappable(check_mm_struct, la, page, 0);
 | 
				
			||||||
 | 
					                page->pra_vaddr=la;
 | 
				
			||||||
 | 
					                assert(page_ref(page) == 1);
 | 
				
			||||||
 | 
					                //cprintf("get No. %d  page: pra_vaddr %x, pra_link.prev %x, pra_link_next %x in pgdir_alloc_page\n", (page-pages), page->pra_vaddr,page->pra_page_link.prev, page->pra_page_link.next);
 | 
				
			||||||
 | 
					            } 
 | 
				
			||||||
 | 
					            else  {  //now current is existed, should fix it in the future
 | 
				
			||||||
 | 
					                //swap_map_swappable(current->mm, la, page, 0);
 | 
				
			||||||
 | 
					                //page->pra_vaddr=la;
 | 
				
			||||||
 | 
					                //assert(page_ref(page) == 1);
 | 
				
			||||||
 | 
					                //panic("pgdir_alloc_page: no pages. now current is existed, should fix it in the future\n");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return page;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					check_alloc_page(void) {
 | 
				
			||||||
 | 
					    pmm_manager->check();
 | 
				
			||||||
 | 
					    cprintf("check_alloc_page() succeeded!\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					check_pgdir(void) {
 | 
				
			||||||
 | 
					    assert(npage <= KMEMSIZE / PGSIZE);
 | 
				
			||||||
 | 
					    assert(boot_pgdir != NULL && (uint32_t)PGOFF(boot_pgdir) == 0);
 | 
				
			||||||
 | 
					    assert(get_page(boot_pgdir, 0x0, NULL) == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Page *p1, *p2;
 | 
				
			||||||
 | 
					    p1 = alloc_page();
 | 
				
			||||||
 | 
					    assert(page_insert(boot_pgdir, p1, 0x0, 0) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pte_t *ptep;
 | 
				
			||||||
 | 
					    assert((ptep = get_pte(boot_pgdir, 0x0, 0)) != NULL);
 | 
				
			||||||
 | 
					    assert(pa2page(*ptep) == p1);
 | 
				
			||||||
 | 
					    assert(page_ref(p1) == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptep = &((pte_t *)KADDR(PDE_ADDR(boot_pgdir[0])))[1];
 | 
				
			||||||
 | 
					    assert(get_pte(boot_pgdir, PGSIZE, 0) == ptep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p2 = alloc_page();
 | 
				
			||||||
 | 
					    assert(page_insert(boot_pgdir, p2, PGSIZE, PTE_U | PTE_W) == 0);
 | 
				
			||||||
 | 
					    assert((ptep = get_pte(boot_pgdir, PGSIZE, 0)) != NULL);
 | 
				
			||||||
 | 
					    assert(*ptep & PTE_U);
 | 
				
			||||||
 | 
					    assert(*ptep & PTE_W);
 | 
				
			||||||
 | 
					    assert(boot_pgdir[0] & PTE_U);
 | 
				
			||||||
 | 
					    assert(page_ref(p2) == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(page_insert(boot_pgdir, p1, PGSIZE, 0) == 0);
 | 
				
			||||||
 | 
					    assert(page_ref(p1) == 2);
 | 
				
			||||||
 | 
					    assert(page_ref(p2) == 0);
 | 
				
			||||||
 | 
					    assert((ptep = get_pte(boot_pgdir, PGSIZE, 0)) != NULL);
 | 
				
			||||||
 | 
					    assert(pa2page(*ptep) == p1);
 | 
				
			||||||
 | 
					    assert((*ptep & PTE_U) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    page_remove(boot_pgdir, 0x0);
 | 
				
			||||||
 | 
					    assert(page_ref(p1) == 1);
 | 
				
			||||||
 | 
					    assert(page_ref(p2) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    page_remove(boot_pgdir, PGSIZE);
 | 
				
			||||||
 | 
					    assert(page_ref(p1) == 0);
 | 
				
			||||||
 | 
					    assert(page_ref(p2) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(page_ref(pa2page(boot_pgdir[0])) == 1);
 | 
				
			||||||
 | 
					    free_page(pa2page(boot_pgdir[0]));
 | 
				
			||||||
 | 
					    boot_pgdir[0] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("check_pgdir() succeeded!\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					check_boot_pgdir(void) {
 | 
				
			||||||
 | 
					    pte_t *ptep;
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; i < npage; i += PGSIZE) {
 | 
				
			||||||
 | 
					        assert((ptep = get_pte(boot_pgdir, (uintptr_t)KADDR(i), 0)) != NULL);
 | 
				
			||||||
 | 
					        assert(PTE_ADDR(*ptep) == i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(PDE_ADDR(boot_pgdir[PDX(VPT)]) == PADDR(boot_pgdir));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(boot_pgdir[0] == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Page *p;
 | 
				
			||||||
 | 
					    p = alloc_page();
 | 
				
			||||||
 | 
					    assert(page_insert(boot_pgdir, p, 0x100, PTE_W) == 0);
 | 
				
			||||||
 | 
					    assert(page_ref(p) == 1);
 | 
				
			||||||
 | 
					    assert(page_insert(boot_pgdir, p, 0x100 + PGSIZE, PTE_W) == 0);
 | 
				
			||||||
 | 
					    assert(page_ref(p) == 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *str = "ucore: Hello world!!";
 | 
				
			||||||
 | 
					    strcpy((void *)0x100, str);
 | 
				
			||||||
 | 
					    assert(strcmp((void *)0x100, (void *)(0x100 + PGSIZE)) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *(char *)(page2kva(p) + 0x100) = '\0';
 | 
				
			||||||
 | 
					    assert(strlen((const char *)0x100) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_page(p);
 | 
				
			||||||
 | 
					    free_page(pa2page(PDE_ADDR(boot_pgdir[0])));
 | 
				
			||||||
 | 
					    boot_pgdir[0] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("check_boot_pgdir() succeeded!\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//perm2str - use string 'u,r,w,-' to present the permission
 | 
				
			||||||
 | 
					static const char *
 | 
				
			||||||
 | 
					perm2str(int perm) {
 | 
				
			||||||
 | 
					    static char str[4];
 | 
				
			||||||
 | 
					    str[0] = (perm & PTE_U) ? 'u' : '-';
 | 
				
			||||||
 | 
					    str[1] = 'r';
 | 
				
			||||||
 | 
					    str[2] = (perm & PTE_W) ? 'w' : '-';
 | 
				
			||||||
 | 
					    str[3] = '\0';
 | 
				
			||||||
 | 
					    return str;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//get_pgtable_items - In [left, right] range of PDT or PT, find a continuous linear addr space
 | 
				
			||||||
 | 
					//                  - (left_store*X_SIZE~right_store*X_SIZE) for PDT or PT
 | 
				
			||||||
 | 
					//                  - X_SIZE=PTSIZE=4M, if PDT; X_SIZE=PGSIZE=4K, if PT
 | 
				
			||||||
 | 
					// paramemters:
 | 
				
			||||||
 | 
					//  left:        no use ???
 | 
				
			||||||
 | 
					//  right:       the high side of table's range
 | 
				
			||||||
 | 
					//  start:       the low side of table's range
 | 
				
			||||||
 | 
					//  table:       the beginning addr of table
 | 
				
			||||||
 | 
					//  left_store:  the pointer of the high side of table's next range
 | 
				
			||||||
 | 
					//  right_store: the pointer of the low side of table's next range
 | 
				
			||||||
 | 
					// return value: 0 - not a invalid item range, perm - a valid item range with perm permission 
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					get_pgtable_items(size_t left, size_t right, size_t start, uintptr_t *table, size_t *left_store, size_t *right_store) {
 | 
				
			||||||
 | 
					    if (start >= right) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    while (start < right && !(table[start] & PTE_P)) {
 | 
				
			||||||
 | 
					        start ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (start < right) {
 | 
				
			||||||
 | 
					        if (left_store != NULL) {
 | 
				
			||||||
 | 
					            *left_store = start;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int perm = (table[start ++] & PTE_USER);
 | 
				
			||||||
 | 
					        while (start < right && (table[start] & PTE_USER) == perm) {
 | 
				
			||||||
 | 
					            start ++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (right_store != NULL) {
 | 
				
			||||||
 | 
					            *right_store = start;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return perm;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//print_pgdir - print the PDT&PT
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					print_pgdir(void) {
 | 
				
			||||||
 | 
					    cprintf("-------------------- BEGIN --------------------\n");
 | 
				
			||||||
 | 
					    size_t left, right = 0, perm;
 | 
				
			||||||
 | 
					    while ((perm = get_pgtable_items(0, NPDEENTRY, right, vpd, &left, &right)) != 0) {
 | 
				
			||||||
 | 
					        cprintf("PDE(%03x) %08x-%08x %08x %s\n", right - left,
 | 
				
			||||||
 | 
					                left * PTSIZE, right * PTSIZE, (right - left) * PTSIZE, perm2str(perm));
 | 
				
			||||||
 | 
					        size_t l, r = left * NPTEENTRY;
 | 
				
			||||||
 | 
					        while ((perm = get_pgtable_items(left * NPTEENTRY, right * NPTEENTRY, r, vpt, &l, &r)) != 0) {
 | 
				
			||||||
 | 
					            cprintf("  |-- PTE(%05x) %08x-%08x %08x %s\n", r - l,
 | 
				
			||||||
 | 
					                    l * PGSIZE, r * PGSIZE, (r - l) * PGSIZE, perm2str(perm));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cprintf("--------------------- END ---------------------\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										147
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/pmm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/pmm.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,147 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_MM_PMM_H__
 | 
				
			||||||
 | 
					#define __KERN_MM_PMM_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <atomic.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// pmm_manager is a physical memory management class. A special pmm manager - XXX_pmm_manager
 | 
				
			||||||
 | 
					// only needs to implement the methods in pmm_manager class, then XXX_pmm_manager can be used
 | 
				
			||||||
 | 
					// by ucore to manage the total physical memory space.
 | 
				
			||||||
 | 
					struct pmm_manager {
 | 
				
			||||||
 | 
					    const char *name;                                 // XXX_pmm_manager's name
 | 
				
			||||||
 | 
					    void (*init)(void);                               // initialize internal description&management data structure
 | 
				
			||||||
 | 
					                                                      // (free block list, number of free block) of XXX_pmm_manager 
 | 
				
			||||||
 | 
					    void (*init_memmap)(struct Page *base, size_t n); // setup description&management data structcure according to
 | 
				
			||||||
 | 
					                                                      // the initial free physical memory space 
 | 
				
			||||||
 | 
					    struct Page *(*alloc_pages)(size_t n);            // allocate >=n pages, depend on the allocation algorithm 
 | 
				
			||||||
 | 
					    void (*free_pages)(struct Page *base, size_t n);  // free >=n pages with "base" addr of Page descriptor structures(memlayout.h)
 | 
				
			||||||
 | 
					    size_t (*nr_free_pages)(void);                    // return the number of free pages 
 | 
				
			||||||
 | 
					    void (*check)(void);                              // check the correctness of XXX_pmm_manager 
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct pmm_manager *pmm_manager;
 | 
				
			||||||
 | 
					extern pde_t *boot_pgdir;
 | 
				
			||||||
 | 
					extern uintptr_t boot_cr3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pmm_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Page *alloc_pages(size_t n);
 | 
				
			||||||
 | 
					void free_pages(struct Page *base, size_t n);
 | 
				
			||||||
 | 
					size_t nr_free_pages(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define alloc_page() alloc_pages(1)
 | 
				
			||||||
 | 
					#define free_page(page) free_pages(page, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pte_t *get_pte(pde_t *pgdir, uintptr_t la, bool create);
 | 
				
			||||||
 | 
					struct Page *get_page(pde_t *pgdir, uintptr_t la, pte_t **ptep_store);
 | 
				
			||||||
 | 
					void page_remove(pde_t *pgdir, uintptr_t la);
 | 
				
			||||||
 | 
					int page_insert(pde_t *pgdir, struct Page *page, uintptr_t la, uint32_t perm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void load_esp0(uintptr_t esp0);
 | 
				
			||||||
 | 
					void tlb_invalidate(pde_t *pgdir, uintptr_t la);
 | 
				
			||||||
 | 
					struct Page *pgdir_alloc_page(pde_t *pgdir, uintptr_t la, uint32_t perm);
 | 
				
			||||||
 | 
					void unmap_range(pde_t *pgdir, uintptr_t start, uintptr_t end);
 | 
				
			||||||
 | 
					void exit_range(pde_t *pgdir, uintptr_t start, uintptr_t end);
 | 
				
			||||||
 | 
					int copy_range(pde_t *to, pde_t *from, uintptr_t start, uintptr_t end, bool share);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void print_pgdir(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * PADDR - takes a kernel virtual address (an address that points above KERNBASE),
 | 
				
			||||||
 | 
					 * where the machine's maximum 256MB of physical memory is mapped and returns the
 | 
				
			||||||
 | 
					 * corresponding physical address.  It panics if you pass it a non-kernel virtual address.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					#define PADDR(kva) ({                                                   \
 | 
				
			||||||
 | 
					            uintptr_t __m_kva = (uintptr_t)(kva);                       \
 | 
				
			||||||
 | 
					            if (__m_kva < KERNBASE) {                                   \
 | 
				
			||||||
 | 
					                panic("PADDR called with invalid kva %08lx", __m_kva);  \
 | 
				
			||||||
 | 
					            }                                                           \
 | 
				
			||||||
 | 
					            __m_kva - KERNBASE;                                         \
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * KADDR - takes a physical address and returns the corresponding kernel virtual
 | 
				
			||||||
 | 
					 * address. It panics if you pass an invalid physical address.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					#define KADDR(pa) ({                                                    \
 | 
				
			||||||
 | 
					            uintptr_t __m_pa = (pa);                                    \
 | 
				
			||||||
 | 
					            size_t __m_ppn = PPN(__m_pa);                               \
 | 
				
			||||||
 | 
					            if (__m_ppn >= npage) {                                     \
 | 
				
			||||||
 | 
					                panic("KADDR called with invalid pa %08lx", __m_pa);    \
 | 
				
			||||||
 | 
					            }                                                           \
 | 
				
			||||||
 | 
					            (void *) (__m_pa + KERNBASE);                               \
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct Page *pages;
 | 
				
			||||||
 | 
					extern size_t npage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline ppn_t
 | 
				
			||||||
 | 
					page2ppn(struct Page *page) {
 | 
				
			||||||
 | 
					    return page - pages;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uintptr_t
 | 
				
			||||||
 | 
					page2pa(struct Page *page) {
 | 
				
			||||||
 | 
					    return page2ppn(page) << PGSHIFT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct Page *
 | 
				
			||||||
 | 
					pa2page(uintptr_t pa) {
 | 
				
			||||||
 | 
					    if (PPN(pa) >= npage) {
 | 
				
			||||||
 | 
					        panic("pa2page called with invalid pa");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return &pages[PPN(pa)];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void *
 | 
				
			||||||
 | 
					page2kva(struct Page *page) {
 | 
				
			||||||
 | 
					    return KADDR(page2pa(page));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct Page *
 | 
				
			||||||
 | 
					kva2page(void *kva) {
 | 
				
			||||||
 | 
					    return pa2page(PADDR(kva));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct Page *
 | 
				
			||||||
 | 
					pte2page(pte_t pte) {
 | 
				
			||||||
 | 
					    if (!(pte & PTE_P)) {
 | 
				
			||||||
 | 
					        panic("pte2page called with invalid pte");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return pa2page(PTE_ADDR(pte));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct Page *
 | 
				
			||||||
 | 
					pde2page(pde_t pde) {
 | 
				
			||||||
 | 
					    return pa2page(PDE_ADDR(pde));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					page_ref(struct Page *page) {
 | 
				
			||||||
 | 
					    return page->ref;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					set_page_ref(struct Page *page, int val) {
 | 
				
			||||||
 | 
					    page->ref = val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					page_ref_inc(struct Page *page) {
 | 
				
			||||||
 | 
					    page->ref += 1;
 | 
				
			||||||
 | 
					    return page->ref;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					page_ref_dec(struct Page *page) {
 | 
				
			||||||
 | 
					    page->ref -= 1;
 | 
				
			||||||
 | 
					    return page->ref;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern char bootstack[], bootstacktop[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_MM_PMM_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										284
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/swap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/swap.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,284 @@
 | 
				
			|||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					#include <swapfs.h>
 | 
				
			||||||
 | 
					#include <swap_fifo.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					#include <default_pmm.h>
 | 
				
			||||||
 | 
					#include <kdebug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// the valid vaddr for check is between 0~CHECK_VALID_VADDR-1
 | 
				
			||||||
 | 
					#define CHECK_VALID_VIR_PAGE_NUM 5
 | 
				
			||||||
 | 
					#define BEING_CHECK_VALID_VADDR 0X1000
 | 
				
			||||||
 | 
					#define CHECK_VALID_VADDR (CHECK_VALID_VIR_PAGE_NUM+1)*0x1000
 | 
				
			||||||
 | 
					// the max number of valid physical page for check
 | 
				
			||||||
 | 
					#define CHECK_VALID_PHY_PAGE_NUM 4
 | 
				
			||||||
 | 
					// the max access seq number
 | 
				
			||||||
 | 
					#define MAX_SEQ_NO 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct swap_manager *sm;
 | 
				
			||||||
 | 
					size_t max_swap_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile int swap_init_ok = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int swap_page[CHECK_VALID_VIR_PAGE_NUM];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int swap_in_seq_no[MAX_SEQ_NO],swap_out_seq_no[MAX_SEQ_NO];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void check_swap(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swap_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     swapfs_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     if (!(1024 <= max_swap_offset && max_swap_offset < MAX_SWAP_OFFSET_LIMIT))
 | 
				
			||||||
 | 
					     {
 | 
				
			||||||
 | 
					          panic("bad max_swap_offset %08x.\n", max_swap_offset);
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     sm = &swap_manager_fifo;
 | 
				
			||||||
 | 
					     int r = sm->init();
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     if (r == 0)
 | 
				
			||||||
 | 
					     {
 | 
				
			||||||
 | 
					          swap_init_ok = 1;
 | 
				
			||||||
 | 
					          cprintf("SWAP: manager = %s\n", sm->name);
 | 
				
			||||||
 | 
					          check_swap();
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swap_init_mm(struct mm_struct *mm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     return sm->init_mm(mm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swap_tick_event(struct mm_struct *mm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     return sm->tick_event(mm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swap_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     return sm->map_swappable(mm, addr, page, swap_in);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swap_set_unswappable(struct mm_struct *mm, uintptr_t addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     return sm->set_unswappable(mm, addr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile unsigned int swap_out_num=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swap_out(struct mm_struct *mm, int n, int in_tick)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     int i;
 | 
				
			||||||
 | 
					     for (i = 0; i != n; ++ i)
 | 
				
			||||||
 | 
					     {
 | 
				
			||||||
 | 
					          uintptr_t v;
 | 
				
			||||||
 | 
					          //struct Page **ptr_page=NULL;
 | 
				
			||||||
 | 
					          struct Page *page;
 | 
				
			||||||
 | 
					          // cprintf("i %d, SWAP: call swap_out_victim\n",i);
 | 
				
			||||||
 | 
					          int r = sm->swap_out_victim(mm, &page, in_tick);
 | 
				
			||||||
 | 
					          if (r != 0) {
 | 
				
			||||||
 | 
					                    cprintf("i %d, swap_out: call swap_out_victim failed\n",i);
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					          }          
 | 
				
			||||||
 | 
					          //assert(!PageReserved(page));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          //cprintf("SWAP: choose victim page 0x%08x\n", page);
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          v=page->pra_vaddr; 
 | 
				
			||||||
 | 
					          pte_t *ptep = get_pte(mm->pgdir, v, 0);
 | 
				
			||||||
 | 
					          assert((*ptep & PTE_P) != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (swapfs_write( (page->pra_vaddr/PGSIZE+1)<<8, page) != 0) {
 | 
				
			||||||
 | 
					                    cprintf("SWAP: failed to save\n");
 | 
				
			||||||
 | 
					                    sm->map_swappable(mm, v, page, 0);
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          else {
 | 
				
			||||||
 | 
					                    cprintf("swap_out: i %d, store page in vaddr 0x%x to disk swap entry %d\n", i, v, page->pra_vaddr/PGSIZE+1);
 | 
				
			||||||
 | 
					                    *ptep = (page->pra_vaddr/PGSIZE+1)<<8;
 | 
				
			||||||
 | 
					                    free_page(page);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          tlb_invalidate(mm->pgdir, v);
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     return i;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					swap_in(struct mm_struct *mm, uintptr_t addr, struct Page **ptr_result)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     struct Page *result = alloc_page();
 | 
				
			||||||
 | 
					     assert(result!=NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     pte_t *ptep = get_pte(mm->pgdir, addr, 0);
 | 
				
			||||||
 | 
					     // cprintf("SWAP: load ptep %x swap entry %d to vaddr 0x%08x, page %x, No %d\n", ptep, (*ptep)>>8, addr, result, (result-pages));
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					     int r;
 | 
				
			||||||
 | 
					     if ((r = swapfs_read((*ptep), result)) != 0)
 | 
				
			||||||
 | 
					     {
 | 
				
			||||||
 | 
					        assert(r!=0);
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     cprintf("swap_in: load disk swap entry %d with swap_page in vadr 0x%x\n", (*ptep)>>8, addr);
 | 
				
			||||||
 | 
					     *ptr_result=result;
 | 
				
			||||||
 | 
					     return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					check_content_set(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     *(unsigned char *)0x1000 = 0x0a;
 | 
				
			||||||
 | 
					     assert(pgfault_num==1);
 | 
				
			||||||
 | 
					     *(unsigned char *)0x1010 = 0x0a;
 | 
				
			||||||
 | 
					     assert(pgfault_num==1);
 | 
				
			||||||
 | 
					     *(unsigned char *)0x2000 = 0x0b;
 | 
				
			||||||
 | 
					     assert(pgfault_num==2);
 | 
				
			||||||
 | 
					     *(unsigned char *)0x2010 = 0x0b;
 | 
				
			||||||
 | 
					     assert(pgfault_num==2);
 | 
				
			||||||
 | 
					     *(unsigned char *)0x3000 = 0x0c;
 | 
				
			||||||
 | 
					     assert(pgfault_num==3);
 | 
				
			||||||
 | 
					     *(unsigned char *)0x3010 = 0x0c;
 | 
				
			||||||
 | 
					     assert(pgfault_num==3);
 | 
				
			||||||
 | 
					     *(unsigned char *)0x4000 = 0x0d;
 | 
				
			||||||
 | 
					     assert(pgfault_num==4);
 | 
				
			||||||
 | 
					     *(unsigned char *)0x4010 = 0x0d;
 | 
				
			||||||
 | 
					     assert(pgfault_num==4);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					check_content_access(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = sm->check_swap();
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Page * check_rp[CHECK_VALID_PHY_PAGE_NUM];
 | 
				
			||||||
 | 
					pte_t * check_ptep[CHECK_VALID_PHY_PAGE_NUM];
 | 
				
			||||||
 | 
					unsigned int check_swap_addr[CHECK_VALID_VIR_PAGE_NUM];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern free_area_t free_area;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define free_list (free_area.free_list)
 | 
				
			||||||
 | 
					#define nr_free (free_area.nr_free)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					check_swap(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //backup mem env
 | 
				
			||||||
 | 
					     int ret, count = 0, total = 0, i;
 | 
				
			||||||
 | 
					     list_entry_t *le = &free_list;
 | 
				
			||||||
 | 
					     while ((le = list_next(le)) != &free_list) {
 | 
				
			||||||
 | 
					        struct Page *p = le2page(le, page_link);
 | 
				
			||||||
 | 
					        assert(PageProperty(p));
 | 
				
			||||||
 | 
					        count ++, total += p->property;
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     assert(total == nr_free_pages());
 | 
				
			||||||
 | 
					     cprintf("BEGIN check_swap: count %d, total %d\n",count,total);
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     //now we set the phy pages env     
 | 
				
			||||||
 | 
					     struct mm_struct *mm = mm_create();
 | 
				
			||||||
 | 
					     assert(mm != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     extern struct mm_struct *check_mm_struct;
 | 
				
			||||||
 | 
					     assert(check_mm_struct == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     check_mm_struct = mm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     pde_t *pgdir = mm->pgdir = boot_pgdir;
 | 
				
			||||||
 | 
					     assert(pgdir[0] == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     struct vma_struct *vma = vma_create(BEING_CHECK_VALID_VADDR, CHECK_VALID_VADDR, VM_WRITE | VM_READ);
 | 
				
			||||||
 | 
					     assert(vma != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     insert_vma_struct(mm, vma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     //setup the temp Page Table vaddr 0~4MB
 | 
				
			||||||
 | 
					     cprintf("setup Page Table for vaddr 0X1000, so alloc a page\n");
 | 
				
			||||||
 | 
					     pte_t *temp_ptep=NULL;
 | 
				
			||||||
 | 
					     temp_ptep = get_pte(mm->pgdir, BEING_CHECK_VALID_VADDR, 1);
 | 
				
			||||||
 | 
					     assert(temp_ptep!= NULL);
 | 
				
			||||||
 | 
					     cprintf("setup Page Table vaddr 0~4MB OVER!\n");
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     for (i=0;i<CHECK_VALID_PHY_PAGE_NUM;i++) {
 | 
				
			||||||
 | 
					          check_rp[i] = alloc_page();
 | 
				
			||||||
 | 
					          assert(check_rp[i] != NULL );
 | 
				
			||||||
 | 
					          assert(!PageProperty(check_rp[i]));
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     list_entry_t free_list_store = free_list;
 | 
				
			||||||
 | 
					     list_init(&free_list);
 | 
				
			||||||
 | 
					     assert(list_empty(&free_list));
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     //assert(alloc_page() == NULL);
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     unsigned int nr_free_store = nr_free;
 | 
				
			||||||
 | 
					     nr_free = 0;
 | 
				
			||||||
 | 
					     for (i=0;i<CHECK_VALID_PHY_PAGE_NUM;i++) {
 | 
				
			||||||
 | 
					        free_pages(check_rp[i],1);
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     assert(nr_free==CHECK_VALID_PHY_PAGE_NUM);
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     cprintf("set up init env for check_swap begin!\n");
 | 
				
			||||||
 | 
					     //setup initial vir_page<->phy_page environment for page relpacement algorithm 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     pgfault_num=0;
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     check_content_set();
 | 
				
			||||||
 | 
					     assert( nr_free == 0);         
 | 
				
			||||||
 | 
					     for(i = 0; i<MAX_SEQ_NO ; i++) 
 | 
				
			||||||
 | 
					         swap_out_seq_no[i]=swap_in_seq_no[i]=-1;
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     for (i= 0;i<CHECK_VALID_PHY_PAGE_NUM;i++) {
 | 
				
			||||||
 | 
					         check_ptep[i]=0;
 | 
				
			||||||
 | 
					         check_ptep[i] = get_pte(pgdir, (i+1)*0x1000, 0);
 | 
				
			||||||
 | 
					         //cprintf("i %d, check_ptep addr %x, value %x\n", i, check_ptep[i], *check_ptep[i]);
 | 
				
			||||||
 | 
					         assert(check_ptep[i] != NULL);
 | 
				
			||||||
 | 
					         assert(pte2page(*check_ptep[i]) == check_rp[i]);
 | 
				
			||||||
 | 
					         assert((*check_ptep[i] & PTE_P));          
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     cprintf("set up init env for check_swap over!\n");
 | 
				
			||||||
 | 
					     // now access the virt pages to test  page relpacement algorithm 
 | 
				
			||||||
 | 
					     ret=check_content_access();
 | 
				
			||||||
 | 
					     assert(ret==0);
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     //restore kernel mem env
 | 
				
			||||||
 | 
					     for (i=0;i<CHECK_VALID_PHY_PAGE_NUM;i++) {
 | 
				
			||||||
 | 
					         free_pages(check_rp[i],1);
 | 
				
			||||||
 | 
					     } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     //free_page(pte2page(*temp_ptep));
 | 
				
			||||||
 | 
					    free_page(pa2page(pgdir[0]));
 | 
				
			||||||
 | 
					     pgdir[0] = 0;
 | 
				
			||||||
 | 
					     mm->pgdir = NULL;
 | 
				
			||||||
 | 
					     mm_destroy(mm);
 | 
				
			||||||
 | 
					     check_mm_struct = NULL;
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     nr_free = nr_free_store;
 | 
				
			||||||
 | 
					     free_list = free_list_store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     le = &free_list;
 | 
				
			||||||
 | 
					     while ((le = list_next(le)) != &free_list) {
 | 
				
			||||||
 | 
					         struct Page *p = le2page(le, page_link);
 | 
				
			||||||
 | 
					         count --, total -= p->property;
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     cprintf("count is %d, total is %d\n",count,total);
 | 
				
			||||||
 | 
					     //assert(count == 0);
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					     cprintf("check_swap() succeeded!\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										65
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/swap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/swap.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_MM_SWAP_H__
 | 
				
			||||||
 | 
					#define __KERN_MM_SWAP_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <vmm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * swap_entry_t
 | 
				
			||||||
 | 
					 * --------------------------------------------
 | 
				
			||||||
 | 
					 * |         offset        |   reserved   | 0 |
 | 
				
			||||||
 | 
					 * --------------------------------------------
 | 
				
			||||||
 | 
					 *           24 bits            7 bits    1 bit
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_SWAP_OFFSET_LIMIT                   (1 << 24)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern size_t max_swap_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * swap_offset - takes a swap_entry (saved in pte), and returns
 | 
				
			||||||
 | 
					 * the corresponding offset in swap mem_map.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					#define swap_offset(entry) ({                                       \
 | 
				
			||||||
 | 
					               size_t __offset = (entry >> 8);                        \
 | 
				
			||||||
 | 
					               if (!(__offset > 0 && __offset < max_swap_offset)) {    \
 | 
				
			||||||
 | 
					                    panic("invalid swap_entry_t = %08x.\n", entry);    \
 | 
				
			||||||
 | 
					               }                                                    \
 | 
				
			||||||
 | 
					               __offset;                                            \
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swap_manager
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     const char *name;
 | 
				
			||||||
 | 
					     /* Global initialization for the swap manager */
 | 
				
			||||||
 | 
					     int (*init)            (void);
 | 
				
			||||||
 | 
					     /* Initialize the priv data inside mm_struct */
 | 
				
			||||||
 | 
					     int (*init_mm)         (struct mm_struct *mm);
 | 
				
			||||||
 | 
					     /* Called when tick interrupt occured */
 | 
				
			||||||
 | 
					     int (*tick_event)      (struct mm_struct *mm);
 | 
				
			||||||
 | 
					     /* Called when map a swappable page into the mm_struct */
 | 
				
			||||||
 | 
					     int (*map_swappable)   (struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in);
 | 
				
			||||||
 | 
					     /* When a page is marked as shared, this routine is called to
 | 
				
			||||||
 | 
					      * delete the addr entry from the swap manager */
 | 
				
			||||||
 | 
					     int (*set_unswappable) (struct mm_struct *mm, uintptr_t addr);
 | 
				
			||||||
 | 
					     /* Try to swap out a page, return then victim */
 | 
				
			||||||
 | 
					     int (*swap_out_victim) (struct mm_struct *mm, struct Page **ptr_page, int in_tick);
 | 
				
			||||||
 | 
					     /* check the page relpacement algorithm */
 | 
				
			||||||
 | 
					     int (*check_swap)(void);     
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern volatile int swap_init_ok;
 | 
				
			||||||
 | 
					int swap_init(void);
 | 
				
			||||||
 | 
					int swap_init_mm(struct mm_struct *mm);
 | 
				
			||||||
 | 
					int swap_tick_event(struct mm_struct *mm);
 | 
				
			||||||
 | 
					int swap_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in);
 | 
				
			||||||
 | 
					int swap_set_unswappable(struct mm_struct *mm, uintptr_t addr);
 | 
				
			||||||
 | 
					int swap_out(struct mm_struct *mm, int n, int in_tick);
 | 
				
			||||||
 | 
					int swap_in(struct mm_struct *mm, uintptr_t addr, struct Page **ptr_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//#define MEMBER_OFFSET(m,t) ((int)(&((t *)0)->m))
 | 
				
			||||||
 | 
					//#define FROM_MEMBER(m,t,a) ((t *)((char *)(a) - MEMBER_OFFSET(m,t)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										144
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/swap_fifo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/swap_fifo.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,144 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					#include <swap_fifo.h>
 | 
				
			||||||
 | 
					#include <list.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* [wikipedia]The simplest Page Replacement Algorithm(PRA) is a FIFO algorithm. The first-in, first-out
 | 
				
			||||||
 | 
					 * page replacement algorithm is a low-overhead algorithm that requires little book-keeping on
 | 
				
			||||||
 | 
					 * the part of the operating system. The idea is obvious from the name - the operating system
 | 
				
			||||||
 | 
					 * keeps track of all the pages in memory in a queue, with the most recent arrival at the back,
 | 
				
			||||||
 | 
					 * and the earliest arrival in front. When a page needs to be replaced, the page at the front
 | 
				
			||||||
 | 
					 * of the queue (the oldest page) is selected. While FIFO is cheap and intuitive, it performs
 | 
				
			||||||
 | 
					 * poorly in practical application. Thus, it is rarely used in its unmodified form. This
 | 
				
			||||||
 | 
					 * algorithm experiences Belady's anomaly.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Details of FIFO PRA
 | 
				
			||||||
 | 
					 * (1) Prepare: In order to implement FIFO PRA, we should manage all swappable pages, so we can
 | 
				
			||||||
 | 
					 *              link these pages into pra_list_head according the time order. At first you should
 | 
				
			||||||
 | 
					 *              be familiar to the struct list in list.h. struct list is a simple doubly linked list
 | 
				
			||||||
 | 
					 *              implementation. You should know howto USE: list_init, list_add(list_add_after),
 | 
				
			||||||
 | 
					 *              list_add_before, list_del, list_next, list_prev. Another tricky method is to transform
 | 
				
			||||||
 | 
					 *              a general list struct to a special struct (such as struct page). You can find some MACRO:
 | 
				
			||||||
 | 
					 *              le2page (in memlayout.h), (in future labs: le2vma (in vmm.h), le2proc (in proc.h),etc.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					list_entry_t pra_list_head;
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (2) _fifo_init_mm: init pra_list_head and let  mm->sm_priv point to the addr of pra_list_head.
 | 
				
			||||||
 | 
					 *              Now, From the memory control struct mm_struct, we can access FIFO PRA
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					_fifo_init_mm(struct mm_struct *mm)
 | 
				
			||||||
 | 
					{     
 | 
				
			||||||
 | 
					     list_init(&pra_list_head);
 | 
				
			||||||
 | 
					     mm->sm_priv = &pra_list_head;
 | 
				
			||||||
 | 
					     //cprintf(" mm->sm_priv %x in fifo_init_mm\n",mm->sm_priv);
 | 
				
			||||||
 | 
					     return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (3)_fifo_map_swappable: According FIFO PRA, we should link the most recent arrival page at the back of pra_list_head qeueue
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					_fifo_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    list_entry_t *head=(list_entry_t*) mm->sm_priv;
 | 
				
			||||||
 | 
					    list_entry_t *entry=&(page->pra_page_link);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    assert(entry != NULL && head != NULL);
 | 
				
			||||||
 | 
					    //record the page access situlation
 | 
				
			||||||
 | 
					    /*LAB3 EXERCISE 2: YOUR CODE*/ 
 | 
				
			||||||
 | 
					    //(1)link the most recent arrival page at the back of the pra_list_head qeueue.
 | 
				
			||||||
 | 
					    list_add(head, entry);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  (4)_fifo_swap_out_victim: According FIFO PRA, we should unlink the  earliest arrival page in front of pra_list_head qeueue,
 | 
				
			||||||
 | 
					 *                            then set the addr of addr of this page to ptr_page.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					_fifo_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page, int in_tick)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     list_entry_t *head=(list_entry_t*) mm->sm_priv;
 | 
				
			||||||
 | 
					         assert(head != NULL);
 | 
				
			||||||
 | 
					     assert(in_tick==0);
 | 
				
			||||||
 | 
					     /* Select the victim */
 | 
				
			||||||
 | 
					     /*LAB3 EXERCISE 2: YOUR CODE*/ 
 | 
				
			||||||
 | 
					     //(1)  unlink the  earliest arrival page in front of pra_list_head qeueue
 | 
				
			||||||
 | 
					     //(2)  set the addr of addr of this page to ptr_page
 | 
				
			||||||
 | 
					     /* Select the tail */
 | 
				
			||||||
 | 
					     list_entry_t *le = head->prev;
 | 
				
			||||||
 | 
					     assert(head!=le);
 | 
				
			||||||
 | 
					     struct Page *p = le2page(le, pra_page_link);
 | 
				
			||||||
 | 
					     list_del(le);
 | 
				
			||||||
 | 
					     assert(p !=NULL);
 | 
				
			||||||
 | 
					     *ptr_page = p;
 | 
				
			||||||
 | 
					     return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					_fifo_check_swap(void) {
 | 
				
			||||||
 | 
					    cprintf("write Virt Page c in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x3000 = 0x0c;
 | 
				
			||||||
 | 
					    assert(pgfault_num==4);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page a in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x1000 = 0x0a;
 | 
				
			||||||
 | 
					    assert(pgfault_num==4);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page d in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x4000 = 0x0d;
 | 
				
			||||||
 | 
					    assert(pgfault_num==4);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page b in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x2000 = 0x0b;
 | 
				
			||||||
 | 
					    assert(pgfault_num==4);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page e in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x5000 = 0x0e;
 | 
				
			||||||
 | 
					    assert(pgfault_num==5);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page b in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x2000 = 0x0b;
 | 
				
			||||||
 | 
					    assert(pgfault_num==5);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page a in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x1000 = 0x0a;
 | 
				
			||||||
 | 
					    assert(pgfault_num==6);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page b in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x2000 = 0x0b;
 | 
				
			||||||
 | 
					    assert(pgfault_num==7);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page c in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x3000 = 0x0c;
 | 
				
			||||||
 | 
					    assert(pgfault_num==8);
 | 
				
			||||||
 | 
					    cprintf("write Virt Page d in fifo_check_swap\n");
 | 
				
			||||||
 | 
					    *(unsigned char *)0x4000 = 0x0d;
 | 
				
			||||||
 | 
					    assert(pgfault_num==9);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					_fifo_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					_fifo_set_unswappable(struct mm_struct *mm, uintptr_t addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					_fifo_tick_event(struct mm_struct *mm)
 | 
				
			||||||
 | 
					{ return 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct swap_manager swap_manager_fifo =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					     .name            = "fifo swap manager",
 | 
				
			||||||
 | 
					     .init            = &_fifo_init,
 | 
				
			||||||
 | 
					     .init_mm         = &_fifo_init_mm,
 | 
				
			||||||
 | 
					     .tick_event      = &_fifo_tick_event,
 | 
				
			||||||
 | 
					     .map_swappable   = &_fifo_map_swappable,
 | 
				
			||||||
 | 
					     .set_unswappable = &_fifo_set_unswappable,
 | 
				
			||||||
 | 
					     .swap_out_victim = &_fifo_swap_out_victim,
 | 
				
			||||||
 | 
					     .check_swap      = &_fifo_check_swap,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										7
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/swap_fifo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/swap_fifo.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_MM_SWAP_FIFO_H__
 | 
				
			||||||
 | 
					#define __KERN_MM_SWAP_FIFO_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					extern struct swap_manager swap_manager_fifo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										562
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/vmm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										562
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/vmm.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,562 @@
 | 
				
			|||||||
 | 
					#include <vmm.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <error.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					#include <kmalloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 
 | 
				
			||||||
 | 
					  vmm design include two parts: mm_struct (mm) & vma_struct (vma)
 | 
				
			||||||
 | 
					  mm is the memory manager for the set of continuous virtual memory  
 | 
				
			||||||
 | 
					  area which have the same PDT. vma is a continuous virtual memory area.
 | 
				
			||||||
 | 
					  There a linear link list for vma & a redblack link list for vma in mm.
 | 
				
			||||||
 | 
					---------------
 | 
				
			||||||
 | 
					  mm related functions:
 | 
				
			||||||
 | 
					   golbal functions
 | 
				
			||||||
 | 
					     struct mm_struct * mm_create(void)
 | 
				
			||||||
 | 
					     void mm_destroy(struct mm_struct *mm)
 | 
				
			||||||
 | 
					     int do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr)
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					  vma related functions:
 | 
				
			||||||
 | 
					   global functions
 | 
				
			||||||
 | 
					     struct vma_struct * vma_create (uintptr_t vm_start, uintptr_t vm_end,...)
 | 
				
			||||||
 | 
					     void insert_vma_struct(struct mm_struct *mm, struct vma_struct *vma)
 | 
				
			||||||
 | 
					     struct vma_struct * find_vma(struct mm_struct *mm, uintptr_t addr)
 | 
				
			||||||
 | 
					   local functions
 | 
				
			||||||
 | 
					     inline void check_vma_overlap(struct vma_struct *prev, struct vma_struct *next)
 | 
				
			||||||
 | 
					---------------
 | 
				
			||||||
 | 
					   check correctness functions
 | 
				
			||||||
 | 
					     void check_vmm(void);
 | 
				
			||||||
 | 
					     void check_vma_struct(void);
 | 
				
			||||||
 | 
					     void check_pgfault(void);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void check_vmm(void);
 | 
				
			||||||
 | 
					static void check_vma_struct(void);
 | 
				
			||||||
 | 
					static void check_pgfault(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mm_create -  alloc a mm_struct & initialize it.
 | 
				
			||||||
 | 
					struct mm_struct *
 | 
				
			||||||
 | 
					mm_create(void) {
 | 
				
			||||||
 | 
					    struct mm_struct *mm = kmalloc(sizeof(struct mm_struct));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mm != NULL) {
 | 
				
			||||||
 | 
					        list_init(&(mm->mmap_list));
 | 
				
			||||||
 | 
					        mm->mmap_cache = NULL;
 | 
				
			||||||
 | 
					        mm->pgdir = NULL;
 | 
				
			||||||
 | 
					        mm->map_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (swap_init_ok) swap_init_mm(mm);
 | 
				
			||||||
 | 
					        else mm->sm_priv = NULL;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        set_mm_count(mm, 0);
 | 
				
			||||||
 | 
					        lock_init(&(mm->mm_lock));
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					    return mm;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// vma_create - alloc a vma_struct & initialize it. (addr range: vm_start~vm_end)
 | 
				
			||||||
 | 
					struct vma_struct *
 | 
				
			||||||
 | 
					vma_create(uintptr_t vm_start, uintptr_t vm_end, uint32_t vm_flags) {
 | 
				
			||||||
 | 
					    struct vma_struct *vma = kmalloc(sizeof(struct vma_struct));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (vma != NULL) {
 | 
				
			||||||
 | 
					        vma->vm_start = vm_start;
 | 
				
			||||||
 | 
					        vma->vm_end = vm_end;
 | 
				
			||||||
 | 
					        vma->vm_flags = vm_flags;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return vma;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// find_vma - find a vma  (vma->vm_start <= addr <= vma_vm_end)
 | 
				
			||||||
 | 
					struct vma_struct *
 | 
				
			||||||
 | 
					find_vma(struct mm_struct *mm, uintptr_t addr) {
 | 
				
			||||||
 | 
					    struct vma_struct *vma = NULL;
 | 
				
			||||||
 | 
					    if (mm != NULL) {
 | 
				
			||||||
 | 
					        vma = mm->mmap_cache;
 | 
				
			||||||
 | 
					        if (!(vma != NULL && vma->vm_start <= addr && vma->vm_end > addr)) {
 | 
				
			||||||
 | 
					                bool found = 0;
 | 
				
			||||||
 | 
					                list_entry_t *list = &(mm->mmap_list), *le = list;
 | 
				
			||||||
 | 
					                while ((le = list_next(le)) != list) {
 | 
				
			||||||
 | 
					                    vma = le2vma(le, list_link);
 | 
				
			||||||
 | 
					                    if (vma->vm_start<=addr && addr < vma->vm_end) {
 | 
				
			||||||
 | 
					                        found = 1;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (!found) {
 | 
				
			||||||
 | 
					                    vma = NULL;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (vma != NULL) {
 | 
				
			||||||
 | 
					            mm->mmap_cache = vma;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return vma;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// check_vma_overlap - check if vma1 overlaps vma2 ?
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					check_vma_overlap(struct vma_struct *prev, struct vma_struct *next) {
 | 
				
			||||||
 | 
					    assert(prev->vm_start < prev->vm_end);
 | 
				
			||||||
 | 
					    assert(prev->vm_end <= next->vm_start);
 | 
				
			||||||
 | 
					    assert(next->vm_start < next->vm_end);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// insert_vma_struct -insert vma in mm's list link
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					insert_vma_struct(struct mm_struct *mm, struct vma_struct *vma) {
 | 
				
			||||||
 | 
					    assert(vma->vm_start < vma->vm_end);
 | 
				
			||||||
 | 
					    list_entry_t *list = &(mm->mmap_list);
 | 
				
			||||||
 | 
					    list_entry_t *le_prev = list, *le_next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        list_entry_t *le = list;
 | 
				
			||||||
 | 
					        while ((le = list_next(le)) != list) {
 | 
				
			||||||
 | 
					            struct vma_struct *mmap_prev = le2vma(le, list_link);
 | 
				
			||||||
 | 
					            if (mmap_prev->vm_start > vma->vm_start) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            le_prev = le;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    le_next = list_next(le_prev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* check overlap */
 | 
				
			||||||
 | 
					    if (le_prev != list) {
 | 
				
			||||||
 | 
					        check_vma_overlap(le2vma(le_prev, list_link), vma);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (le_next != list) {
 | 
				
			||||||
 | 
					        check_vma_overlap(vma, le2vma(le_next, list_link));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vma->vm_mm = mm;
 | 
				
			||||||
 | 
					    list_add_after(le_prev, &(vma->list_link));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mm->map_count ++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mm_destroy - free mm and mm internal fields
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					mm_destroy(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    assert(mm_count(mm) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    list_entry_t *list = &(mm->mmap_list), *le;
 | 
				
			||||||
 | 
					    while ((le = list_next(list)) != list) {
 | 
				
			||||||
 | 
					        list_del(le);
 | 
				
			||||||
 | 
					        kfree(le2vma(le, list_link));  //kfree vma        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    kfree(mm); //kfree mm
 | 
				
			||||||
 | 
					    mm=NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					mm_map(struct mm_struct *mm, uintptr_t addr, size_t len, uint32_t vm_flags,
 | 
				
			||||||
 | 
					       struct vma_struct **vma_store) {
 | 
				
			||||||
 | 
					    uintptr_t start = ROUNDDOWN(addr, PGSIZE), end = ROUNDUP(addr + len, PGSIZE);
 | 
				
			||||||
 | 
					    if (!USER_ACCESS(start, end)) {
 | 
				
			||||||
 | 
					        return -E_INVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(mm != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = -E_INVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct vma_struct *vma;
 | 
				
			||||||
 | 
					    if ((vma = find_vma(mm, start)) != NULL && end > vma->vm_start) {
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret = -E_NO_MEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((vma = vma_create(start, end, vm_flags)) == NULL) {
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    insert_vma_struct(mm, vma);
 | 
				
			||||||
 | 
					    if (vma_store != NULL) {
 | 
				
			||||||
 | 
					        *vma_store = vma;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					dup_mmap(struct mm_struct *to, struct mm_struct *from) {
 | 
				
			||||||
 | 
					    assert(to != NULL && from != NULL);
 | 
				
			||||||
 | 
					    list_entry_t *list = &(from->mmap_list), *le = list;
 | 
				
			||||||
 | 
					    while ((le = list_prev(le)) != list) {
 | 
				
			||||||
 | 
					        struct vma_struct *vma, *nvma;
 | 
				
			||||||
 | 
					        vma = le2vma(le, list_link);
 | 
				
			||||||
 | 
					        nvma = vma_create(vma->vm_start, vma->vm_end, vma->vm_flags);
 | 
				
			||||||
 | 
					        if (nvma == NULL) {
 | 
				
			||||||
 | 
					            return -E_NO_MEM;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        insert_vma_struct(to, nvma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool share = 0;
 | 
				
			||||||
 | 
					        if (copy_range(to->pgdir, from->pgdir, vma->vm_start, vma->vm_end, share) != 0) {
 | 
				
			||||||
 | 
					            return -E_NO_MEM;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					exit_mmap(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    assert(mm != NULL && mm_count(mm) == 0);
 | 
				
			||||||
 | 
					    pde_t *pgdir = mm->pgdir;
 | 
				
			||||||
 | 
					    list_entry_t *list = &(mm->mmap_list), *le = list;
 | 
				
			||||||
 | 
					    while ((le = list_next(le)) != list) {
 | 
				
			||||||
 | 
					        struct vma_struct *vma = le2vma(le, list_link);
 | 
				
			||||||
 | 
					        unmap_range(pgdir, vma->vm_start, vma->vm_end);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    while ((le = list_next(le)) != list) {
 | 
				
			||||||
 | 
					        struct vma_struct *vma = le2vma(le, list_link);
 | 
				
			||||||
 | 
					        exit_range(pgdir, vma->vm_start, vma->vm_end);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					copy_from_user(struct mm_struct *mm, void *dst, const void *src, size_t len, bool writable) {
 | 
				
			||||||
 | 
					    if (!user_mem_check(mm, (uintptr_t)src, len, writable)) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    memcpy(dst, src, len);
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					copy_to_user(struct mm_struct *mm, void *dst, const void *src, size_t len) {
 | 
				
			||||||
 | 
					    if (!user_mem_check(mm, (uintptr_t)dst, len, 1)) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    memcpy(dst, src, len);
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// vmm_init - initialize virtual memory management
 | 
				
			||||||
 | 
					//          - now just call check_vmm to check correctness of vmm
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vmm_init(void) {
 | 
				
			||||||
 | 
					    check_vmm();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// check_vmm - check correctness of vmm
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					check_vmm(void) {
 | 
				
			||||||
 | 
					    size_t nr_free_pages_store = nr_free_pages();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    check_vma_struct();
 | 
				
			||||||
 | 
					    check_pgfault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    assert(nr_free_pages_store == nr_free_pages());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("check_vmm() succeeded.\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					check_vma_struct(void) {
 | 
				
			||||||
 | 
					    size_t nr_free_pages_store = nr_free_pages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct mm_struct *mm = mm_create();
 | 
				
			||||||
 | 
					    assert(mm != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int step1 = 10, step2 = step1 * 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = step1; i >= 1; i --) {
 | 
				
			||||||
 | 
					        struct vma_struct *vma = vma_create(i * 5, i * 5 + 2, 0);
 | 
				
			||||||
 | 
					        assert(vma != NULL);
 | 
				
			||||||
 | 
					        insert_vma_struct(mm, vma);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = step1 + 1; i <= step2; i ++) {
 | 
				
			||||||
 | 
					        struct vma_struct *vma = vma_create(i * 5, i * 5 + 2, 0);
 | 
				
			||||||
 | 
					        assert(vma != NULL);
 | 
				
			||||||
 | 
					        insert_vma_struct(mm, vma);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    list_entry_t *le = list_next(&(mm->mmap_list));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 1; i <= step2; i ++) {
 | 
				
			||||||
 | 
					        assert(le != &(mm->mmap_list));
 | 
				
			||||||
 | 
					        struct vma_struct *mmap = le2vma(le, list_link);
 | 
				
			||||||
 | 
					        assert(mmap->vm_start == i * 5 && mmap->vm_end == i * 5 + 2);
 | 
				
			||||||
 | 
					        le = list_next(le);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 5; i <= 5 * step2; i +=5) {
 | 
				
			||||||
 | 
					        struct vma_struct *vma1 = find_vma(mm, i);
 | 
				
			||||||
 | 
					        assert(vma1 != NULL);
 | 
				
			||||||
 | 
					        struct vma_struct *vma2 = find_vma(mm, i+1);
 | 
				
			||||||
 | 
					        assert(vma2 != NULL);
 | 
				
			||||||
 | 
					        struct vma_struct *vma3 = find_vma(mm, i+2);
 | 
				
			||||||
 | 
					        assert(vma3 == NULL);
 | 
				
			||||||
 | 
					        struct vma_struct *vma4 = find_vma(mm, i+3);
 | 
				
			||||||
 | 
					        assert(vma4 == NULL);
 | 
				
			||||||
 | 
					        struct vma_struct *vma5 = find_vma(mm, i+4);
 | 
				
			||||||
 | 
					        assert(vma5 == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(vma1->vm_start == i  && vma1->vm_end == i  + 2);
 | 
				
			||||||
 | 
					        assert(vma2->vm_start == i  && vma2->vm_end == i  + 2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i =4; i>=0; i--) {
 | 
				
			||||||
 | 
					        struct vma_struct *vma_below_5= find_vma(mm,i);
 | 
				
			||||||
 | 
					        if (vma_below_5 != NULL ) {
 | 
				
			||||||
 | 
					           cprintf("vma_below_5: i %x, start %x, end %x\n",i, vma_below_5->vm_start, vma_below_5->vm_end); 
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        assert(vma_below_5 == NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mm_destroy(mm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    assert(nr_free_pages_store == nr_free_pages());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("check_vma_struct() succeeded!\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mm_struct *check_mm_struct;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// check_pgfault - check correctness of pgfault handler
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					check_pgfault(void) {
 | 
				
			||||||
 | 
					    size_t nr_free_pages_store = nr_free_pages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    check_mm_struct = mm_create();
 | 
				
			||||||
 | 
					    assert(check_mm_struct != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct mm_struct *mm = check_mm_struct;
 | 
				
			||||||
 | 
					    pde_t *pgdir = mm->pgdir = boot_pgdir;
 | 
				
			||||||
 | 
					    assert(pgdir[0] == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct vma_struct *vma = vma_create(0, PTSIZE, VM_WRITE);
 | 
				
			||||||
 | 
					    assert(vma != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    insert_vma_struct(mm, vma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uintptr_t addr = 0x100;
 | 
				
			||||||
 | 
					    assert(find_vma(mm, addr) == vma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int i, sum = 0;
 | 
				
			||||||
 | 
					    for (i = 0; i < 100; i ++) {
 | 
				
			||||||
 | 
					        *(char *)(addr + i) = i;
 | 
				
			||||||
 | 
					        sum += i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (i = 0; i < 100; i ++) {
 | 
				
			||||||
 | 
					        sum -= *(char *)(addr + i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(sum == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    page_remove(pgdir, ROUNDDOWN(addr, PGSIZE));
 | 
				
			||||||
 | 
					    free_page(pa2page(pgdir[0]));
 | 
				
			||||||
 | 
					    pgdir[0] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mm->pgdir = NULL;
 | 
				
			||||||
 | 
					    mm_destroy(mm);
 | 
				
			||||||
 | 
					    check_mm_struct = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(nr_free_pages_store == nr_free_pages());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("check_pgfault() succeeded!\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//page fault number
 | 
				
			||||||
 | 
					volatile unsigned int pgfault_num=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* do_pgfault - interrupt handler to process the page fault execption
 | 
				
			||||||
 | 
					 * @mm         : the control struct for a set of vma using the same PDT
 | 
				
			||||||
 | 
					 * @error_code : the error code recorded in trapframe->tf_err which is setted by x86 hardware
 | 
				
			||||||
 | 
					 * @addr       : the addr which causes a memory access exception, (the contents of the CR2 register)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * CALL GRAPH: trap--> trap_dispatch-->pgfault_handler-->do_pgfault
 | 
				
			||||||
 | 
					 * The processor provides ucore's do_pgfault function with two items of information to aid in diagnosing
 | 
				
			||||||
 | 
					 * the exception and recovering from it.
 | 
				
			||||||
 | 
					 *   (1) The contents of the CR2 register. The processor loads the CR2 register with the
 | 
				
			||||||
 | 
					 *       32-bit linear address that generated the exception. The do_pgfault fun can
 | 
				
			||||||
 | 
					 *       use this address to locate the corresponding page directory and page-table
 | 
				
			||||||
 | 
					 *       entries.
 | 
				
			||||||
 | 
					 *   (2) An error code on the kernel stack. The error code for a page fault has a format different from
 | 
				
			||||||
 | 
					 *       that for other exceptions. The error code tells the exception handler three things:
 | 
				
			||||||
 | 
					 *         -- The P flag   (bit 0) indicates whether the exception was due to a not-present page (0)
 | 
				
			||||||
 | 
					 *            or to either an access rights violation or the use of a reserved bit (1).
 | 
				
			||||||
 | 
					 *         -- The W/R flag (bit 1) indicates whether the memory access that caused the exception
 | 
				
			||||||
 | 
					 *            was a read (0) or write (1).
 | 
				
			||||||
 | 
					 *         -- The U/S flag (bit 2) indicates whether the processor was executing at user mode (1)
 | 
				
			||||||
 | 
					 *            or supervisor mode (0) at the time of the exception.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr) {
 | 
				
			||||||
 | 
					    int ret = -E_INVAL;
 | 
				
			||||||
 | 
					    //try to find a vma which include addr
 | 
				
			||||||
 | 
					    struct vma_struct *vma = find_vma(mm, addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pgfault_num++;
 | 
				
			||||||
 | 
					    //If the addr is in the range of a mm's vma?
 | 
				
			||||||
 | 
					    if (vma == NULL || vma->vm_start > addr) {
 | 
				
			||||||
 | 
					        cprintf("not valid addr %x, and  can not find it in vma\n", addr);
 | 
				
			||||||
 | 
					        goto failed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //check the error_code
 | 
				
			||||||
 | 
					    switch (error_code & 3) {
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					            /* error code flag : default is 3 ( W/R=1, P=1): write, present */
 | 
				
			||||||
 | 
					    case 2: /* error code flag : (W/R=1, P=0): write, not present */
 | 
				
			||||||
 | 
					        if (!(vma->vm_flags & VM_WRITE)) {
 | 
				
			||||||
 | 
					            cprintf("do_pgfault failed: error code flag = write AND not present, but the addr's vma cannot write\n");
 | 
				
			||||||
 | 
					            goto failed;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 1: /* error code flag : (W/R=0, P=1): read, present */
 | 
				
			||||||
 | 
					        cprintf("do_pgfault failed: error code flag = read AND present\n");
 | 
				
			||||||
 | 
					        goto failed;
 | 
				
			||||||
 | 
					    case 0: /* error code flag : (W/R=0, P=0): read, not present */
 | 
				
			||||||
 | 
					        if (!(vma->vm_flags & (VM_READ | VM_EXEC))) {
 | 
				
			||||||
 | 
					            cprintf("do_pgfault failed: error code flag = read AND not present, but the addr's vma cannot read or exec\n");
 | 
				
			||||||
 | 
					            goto failed;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* IF (write an existed addr ) OR
 | 
				
			||||||
 | 
					     *    (write an non_existed addr && addr is writable) OR
 | 
				
			||||||
 | 
					     *    (read  an non_existed addr && addr is readable)
 | 
				
			||||||
 | 
					     * THEN
 | 
				
			||||||
 | 
					     *    continue process
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    uint32_t perm = PTE_U;
 | 
				
			||||||
 | 
					    if (vma->vm_flags & VM_WRITE) {
 | 
				
			||||||
 | 
					        perm |= PTE_W;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    addr = ROUNDDOWN(addr, PGSIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = -E_NO_MEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pte_t *ptep=NULL;
 | 
				
			||||||
 | 
					    /*LAB3 EXERCISE 1: YOUR CODE
 | 
				
			||||||
 | 
					    * Maybe you want help comment, BELOW comments can help you finish the code
 | 
				
			||||||
 | 
					    *
 | 
				
			||||||
 | 
					    * Some Useful MACROs and DEFINEs, you can use them in below implementation.
 | 
				
			||||||
 | 
					    * MACROs or Functions:
 | 
				
			||||||
 | 
					    *   get_pte : get an pte and return the kernel virtual address of this pte for la
 | 
				
			||||||
 | 
					    *             if the PT contians this pte didn't exist, alloc a page for PT (notice the 3th parameter '1')
 | 
				
			||||||
 | 
					    *   pgdir_alloc_page : call alloc_page & page_insert functions to allocate a page size memory & setup
 | 
				
			||||||
 | 
					    *             an addr map pa<--->la with linear address la and the PDT pgdir
 | 
				
			||||||
 | 
					    * DEFINES:
 | 
				
			||||||
 | 
					    *   VM_WRITE  : If vma->vm_flags & VM_WRITE == 1/0, then the vma is writable/non writable
 | 
				
			||||||
 | 
					    *   PTE_W           0x002                   // page table/directory entry flags bit : Writeable
 | 
				
			||||||
 | 
					    *   PTE_U           0x004                   // page table/directory entry flags bit : User can access
 | 
				
			||||||
 | 
					    * VARIABLES:
 | 
				
			||||||
 | 
					    *   mm->pgdir : the PDT of these vma
 | 
				
			||||||
 | 
					    *
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    /*LAB3 EXERCISE 1: YOUR CODE*/
 | 
				
			||||||
 | 
					    ptep = ???              //(1) try to find a pte, if pte's PT(Page Table) isn't existed, then create a PT.
 | 
				
			||||||
 | 
					    if (*ptep == 0) {
 | 
				
			||||||
 | 
					                            //(2) if the phy addr isn't exist, then alloc a page & map the phy addr with logical addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					    /*LAB3 EXERCISE 2: YOUR CODE
 | 
				
			||||||
 | 
					    * Now we think this pte is a  swap entry, we should load data from disk to a page with phy addr,
 | 
				
			||||||
 | 
					    * and map the phy addr with logical addr, trigger swap manager to record the access situation of this page.
 | 
				
			||||||
 | 
					    *
 | 
				
			||||||
 | 
					    *  Some Useful MACROs and DEFINEs, you can use them in below implementation.
 | 
				
			||||||
 | 
					    *  MACROs or Functions:
 | 
				
			||||||
 | 
					    *    swap_in(mm, addr, &page) : alloc a memory page, then according to the swap entry in PTE for addr,
 | 
				
			||||||
 | 
					    *                               find the addr of disk page, read the content of disk page into this memroy page
 | 
				
			||||||
 | 
					    *    page_insert : build the map of phy addr of an Page with the linear addr la
 | 
				
			||||||
 | 
					    *    swap_map_swappable : set the page swappable
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					        if(swap_init_ok) {
 | 
				
			||||||
 | 
					            struct Page *page=NULL;
 | 
				
			||||||
 | 
					                                    //(1)According to the mm AND addr, try to load the content of right disk page
 | 
				
			||||||
 | 
					                                    //    into the memory which page managed.
 | 
				
			||||||
 | 
					                                    //(2) According to the mm, addr AND page, setup the map of phy addr <---> logical addr
 | 
				
			||||||
 | 
					                                    //(3) make the page swappable.
 | 
				
			||||||
 | 
					                                    //(4) [NOTICE]: you myabe need to update your lab3's implementation for LAB5's normal execution.
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
 | 
				
			||||||
 | 
					            goto failed;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    // try to find a pte, if pte's PT(Page Table) isn't existed, then create a PT.
 | 
				
			||||||
 | 
					    // (notice the 3th parameter '1')
 | 
				
			||||||
 | 
					    if ((ptep = get_pte(mm->pgdir, addr, 1)) == NULL) {
 | 
				
			||||||
 | 
					        cprintf("get_pte in do_pgfault failed\n");
 | 
				
			||||||
 | 
					        goto failed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (*ptep == 0) { // if the phy addr isn't exist, then alloc a page & map the phy addr with logical addr
 | 
				
			||||||
 | 
					        if (pgdir_alloc_page(mm->pgdir, addr, perm) == NULL) {
 | 
				
			||||||
 | 
					            cprintf("pgdir_alloc_page in do_pgfault failed\n");
 | 
				
			||||||
 | 
					            goto failed;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        struct Page *page=NULL;
 | 
				
			||||||
 | 
					        cprintf("do pgfault: ptep %x, pte %x\n",ptep, *ptep);
 | 
				
			||||||
 | 
					        if (*ptep & PTE_P) {
 | 
				
			||||||
 | 
					            //if process write to this existed readonly page (PTE_P means existed), then should be here now.
 | 
				
			||||||
 | 
					            //we can implement the delayed memory space copy for fork child process (AKA copy on write, COW).
 | 
				
			||||||
 | 
					            //we didn't implement now, we will do it in future.
 | 
				
			||||||
 | 
					            panic("error write a non-writable pte");
 | 
				
			||||||
 | 
					            //page = pte2page(*ptep);
 | 
				
			||||||
 | 
					        } else{
 | 
				
			||||||
 | 
					           // if this pte is a swap entry, then load data from disk to a page with phy addr
 | 
				
			||||||
 | 
					           // and call page_insert to map the phy addr with logical addr
 | 
				
			||||||
 | 
					           if(swap_init_ok) {               
 | 
				
			||||||
 | 
					               if ((ret = swap_in(mm, addr, &page)) != 0) {
 | 
				
			||||||
 | 
					                   cprintf("swap_in in do_pgfault failed\n");
 | 
				
			||||||
 | 
					                   goto failed;
 | 
				
			||||||
 | 
					               }    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					           }  
 | 
				
			||||||
 | 
					           else {
 | 
				
			||||||
 | 
					            cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
 | 
				
			||||||
 | 
					            goto failed;
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					       } 
 | 
				
			||||||
 | 
					       page_insert(mm->pgdir, page, addr, perm);
 | 
				
			||||||
 | 
					       swap_map_swappable(mm, addr, page, 1);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   ret = 0;
 | 
				
			||||||
 | 
					failed:
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					user_mem_check(struct mm_struct *mm, uintptr_t addr, size_t len, bool write) {
 | 
				
			||||||
 | 
					    if (mm != NULL) {
 | 
				
			||||||
 | 
					        if (!USER_ACCESS(addr, addr + len)) {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        struct vma_struct *vma;
 | 
				
			||||||
 | 
					        uintptr_t start = addr, end = addr + len;
 | 
				
			||||||
 | 
					        while (start < end) {
 | 
				
			||||||
 | 
					            if ((vma = find_vma(mm, start)) == NULL || start < vma->vm_start) {
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!(vma->vm_flags & ((write) ? VM_WRITE : VM_READ))) {
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (write && (vma->vm_flags & VM_STACK)) {
 | 
				
			||||||
 | 
					                if (start < vma->vm_start + PGSIZE) { //check stack start & size
 | 
				
			||||||
 | 
					                    return 0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            start = vma->vm_end;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return KERN_ACCESS(addr, addr + len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										102
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/vmm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								related_info/lab5/lab5-spoc-discuss/kern/mm/vmm.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_MM_VMM_H__
 | 
				
			||||||
 | 
					#define __KERN_MM_VMM_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <list.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//pre define
 | 
				
			||||||
 | 
					struct mm_struct;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// the virtual continuous memory area(vma)
 | 
				
			||||||
 | 
					struct vma_struct {
 | 
				
			||||||
 | 
					    struct mm_struct *vm_mm; // the set of vma using the same PDT 
 | 
				
			||||||
 | 
					    uintptr_t vm_start;      //    start addr of vma    
 | 
				
			||||||
 | 
					    uintptr_t vm_end;        // end addr of vma
 | 
				
			||||||
 | 
					    uint32_t vm_flags;       // flags of vma
 | 
				
			||||||
 | 
					    list_entry_t list_link;  // linear list link which sorted by start addr of vma
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define le2vma(le, member)                  \
 | 
				
			||||||
 | 
					    to_struct((le), struct vma_struct, member)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VM_READ                 0x00000001
 | 
				
			||||||
 | 
					#define VM_WRITE                0x00000002
 | 
				
			||||||
 | 
					#define VM_EXEC                 0x00000004
 | 
				
			||||||
 | 
					#define VM_STACK                0x00000008
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// the control struct for a set of vma using the same PDT
 | 
				
			||||||
 | 
					struct mm_struct {
 | 
				
			||||||
 | 
					    list_entry_t mmap_list;        // linear list link which sorted by start addr of vma
 | 
				
			||||||
 | 
					    struct vma_struct *mmap_cache; // current accessed vma, used for speed purpose
 | 
				
			||||||
 | 
					    pde_t *pgdir;                  // the PDT of these vma
 | 
				
			||||||
 | 
					    int map_count;                 // the count of these vma
 | 
				
			||||||
 | 
					    void *sm_priv;                 // the private data for swap manager
 | 
				
			||||||
 | 
					    int mm_count;                  // the number ofprocess which shared the mm
 | 
				
			||||||
 | 
					    lock_t mm_lock;                // mutex for using dup_mmap fun to duplicat the mm
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct vma_struct *find_vma(struct mm_struct *mm, uintptr_t addr);
 | 
				
			||||||
 | 
					struct vma_struct *vma_create(uintptr_t vm_start, uintptr_t vm_end, uint32_t vm_flags);
 | 
				
			||||||
 | 
					void insert_vma_struct(struct mm_struct *mm, struct vma_struct *vma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mm_struct *mm_create(void);
 | 
				
			||||||
 | 
					void mm_destroy(struct mm_struct *mm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vmm_init(void);
 | 
				
			||||||
 | 
					int mm_map(struct mm_struct *mm, uintptr_t addr, size_t len, uint32_t vm_flags,
 | 
				
			||||||
 | 
					           struct vma_struct **vma_store);
 | 
				
			||||||
 | 
					int do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mm_unmap(struct mm_struct *mm, uintptr_t addr, size_t len);
 | 
				
			||||||
 | 
					int dup_mmap(struct mm_struct *to, struct mm_struct *from);
 | 
				
			||||||
 | 
					void exit_mmap(struct mm_struct *mm);
 | 
				
			||||||
 | 
					uintptr_t get_unmapped_area(struct mm_struct *mm, size_t len);
 | 
				
			||||||
 | 
					int mm_brk(struct mm_struct *mm, uintptr_t addr, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern volatile unsigned int pgfault_num;
 | 
				
			||||||
 | 
					extern struct mm_struct *check_mm_struct;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool user_mem_check(struct mm_struct *mm, uintptr_t start, size_t len, bool write);
 | 
				
			||||||
 | 
					bool copy_from_user(struct mm_struct *mm, void *dst, const void *src, size_t len, bool writable);
 | 
				
			||||||
 | 
					bool copy_to_user(struct mm_struct *mm, void *dst, const void *src, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					mm_count(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    return mm->mm_count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					set_mm_count(struct mm_struct *mm, int val) {
 | 
				
			||||||
 | 
					    mm->mm_count = val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					mm_count_inc(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    mm->mm_count += 1;
 | 
				
			||||||
 | 
					    return mm->mm_count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					mm_count_dec(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    mm->mm_count -= 1;
 | 
				
			||||||
 | 
					    return mm->mm_count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					lock_mm(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    if (mm != NULL) {
 | 
				
			||||||
 | 
					        lock(&(mm->mm_lock));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					unlock_mm(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    if (mm != NULL) {
 | 
				
			||||||
 | 
					        unlock(&(mm->mm_lock));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_MM_VMM_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								related_info/lab5/lab5-spoc-discuss/kern/process/entry.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								related_info/lab5/lab5-spoc-discuss/kern/process/entry.S
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					.text
 | 
				
			||||||
 | 
					.globl kernel_thread_entry
 | 
				
			||||||
 | 
					kernel_thread_entry:        # void kernel_thread(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pushl %edx              # push arg
 | 
				
			||||||
 | 
					    call *%ebx              # call fn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pushl %eax              # save the return value of fn(arg)
 | 
				
			||||||
 | 
					    call do_exit            # call do_exit to terminate current thread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										888
									
								
								related_info/lab5/lab5-spoc-discuss/kern/process/proc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										888
									
								
								related_info/lab5/lab5-spoc-discuss/kern/process/proc.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,888 @@
 | 
				
			|||||||
 | 
					#include <proc.h>
 | 
				
			||||||
 | 
					#include <kmalloc.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <error.h>
 | 
				
			||||||
 | 
					#include <sched.h>
 | 
				
			||||||
 | 
					#include <elf.h>
 | 
				
			||||||
 | 
					#include <vmm.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------- process/thread mechanism design&implementation -------------
 | 
				
			||||||
 | 
					(an simplified Linux process/thread mechanism )
 | 
				
			||||||
 | 
					introduction:
 | 
				
			||||||
 | 
					  ucore implements a simple process/thread mechanism. process contains the independent memory sapce, at least one threads
 | 
				
			||||||
 | 
					for execution, the kernel data(for management), processor state (for context switch), files(in lab6), etc. ucore needs to
 | 
				
			||||||
 | 
					manage all these details efficiently. In ucore, a thread is just a special kind of process(share process's memory).
 | 
				
			||||||
 | 
					------------------------------
 | 
				
			||||||
 | 
					process state       :     meaning               -- reason
 | 
				
			||||||
 | 
					    PROC_UNINIT     :   uninitialized           -- alloc_proc
 | 
				
			||||||
 | 
					    PROC_SLEEPING   :   sleeping                -- try_free_pages, do_wait, do_sleep
 | 
				
			||||||
 | 
					    PROC_RUNNABLE   :   runnable(maybe running) -- proc_init, wakeup_proc, 
 | 
				
			||||||
 | 
					    PROC_ZOMBIE     :   almost dead             -- do_exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-----------------------------
 | 
				
			||||||
 | 
					process state changing:
 | 
				
			||||||
 | 
					                                            
 | 
				
			||||||
 | 
					  alloc_proc                                 RUNNING
 | 
				
			||||||
 | 
					      +                                   +--<----<--+
 | 
				
			||||||
 | 
					      +                                   + proc_run +
 | 
				
			||||||
 | 
					      V                                   +-->---->--+ 
 | 
				
			||||||
 | 
					PROC_UNINIT -- proc_init/wakeup_proc --> PROC_RUNNABLE -- try_free_pages/do_wait/do_sleep --> PROC_SLEEPING --
 | 
				
			||||||
 | 
					                                           A      +                                                           +
 | 
				
			||||||
 | 
					                                           |      +--- do_exit --> PROC_ZOMBIE                                +
 | 
				
			||||||
 | 
					                                           +                                                                  + 
 | 
				
			||||||
 | 
					                                           -----------------------wakeup_proc----------------------------------
 | 
				
			||||||
 | 
					-----------------------------
 | 
				
			||||||
 | 
					process relations
 | 
				
			||||||
 | 
					parent:           proc->parent  (proc is children)
 | 
				
			||||||
 | 
					children:         proc->cptr    (proc is parent)
 | 
				
			||||||
 | 
					older sibling:    proc->optr    (proc is younger sibling)
 | 
				
			||||||
 | 
					younger sibling:  proc->yptr    (proc is older sibling)
 | 
				
			||||||
 | 
					-----------------------------
 | 
				
			||||||
 | 
					related syscall for process:
 | 
				
			||||||
 | 
					SYS_exit        : process exit,                           -->do_exit
 | 
				
			||||||
 | 
					SYS_fork        : create child process, dup mm            -->do_fork-->wakeup_proc
 | 
				
			||||||
 | 
					SYS_wait        : wait process                            -->do_wait
 | 
				
			||||||
 | 
					SYS_exec        : after fork, process execute a program   -->load a program and refresh the mm
 | 
				
			||||||
 | 
					SYS_clone       : create child thread                     -->do_fork-->wakeup_proc
 | 
				
			||||||
 | 
					SYS_yield       : process flag itself need resecheduling, -- proc->need_sched=1, then scheduler will rescheule this process
 | 
				
			||||||
 | 
					SYS_sleep       : process sleep                           -->do_sleep 
 | 
				
			||||||
 | 
					SYS_kill        : kill process                            -->do_kill-->proc->flags |= PF_EXITING
 | 
				
			||||||
 | 
					                                                                 -->wakeup_proc-->do_wait-->do_exit   
 | 
				
			||||||
 | 
					SYS_getpid      : get the process's pid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// the process set's list
 | 
				
			||||||
 | 
					list_entry_t proc_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define HASH_SHIFT          10
 | 
				
			||||||
 | 
					#define HASH_LIST_SIZE      (1 << HASH_SHIFT)
 | 
				
			||||||
 | 
					#define pid_hashfn(x)       (hash32(x, HASH_SHIFT))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// has list for process set based on pid
 | 
				
			||||||
 | 
					static list_entry_t hash_list[HASH_LIST_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// idle proc
 | 
				
			||||||
 | 
					struct proc_struct *idleproc = NULL;
 | 
				
			||||||
 | 
					// init proc
 | 
				
			||||||
 | 
					struct proc_struct *initproc = NULL;
 | 
				
			||||||
 | 
					// current proc
 | 
				
			||||||
 | 
					struct proc_struct *current = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nr_process = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void kernel_thread_entry(void);
 | 
				
			||||||
 | 
					void forkrets(struct trapframe *tf);
 | 
				
			||||||
 | 
					void switch_to(struct context *from, struct context *to);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// alloc_proc - alloc a proc_struct and init all fields of proc_struct
 | 
				
			||||||
 | 
					static struct proc_struct *
 | 
				
			||||||
 | 
					alloc_proc(void) {
 | 
				
			||||||
 | 
					    struct proc_struct *proc = kmalloc(sizeof(struct proc_struct));
 | 
				
			||||||
 | 
					    if (proc != NULL) {
 | 
				
			||||||
 | 
					    //LAB4:EXERCISE1 YOUR CODE
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * below fields in proc_struct need to be initialized
 | 
				
			||||||
 | 
					     *       enum proc_state state;                      // Process state
 | 
				
			||||||
 | 
					     *       int pid;                                    // Process ID
 | 
				
			||||||
 | 
					     *       int runs;                                   // the running times of Proces
 | 
				
			||||||
 | 
					     *       uintptr_t kstack;                           // Process kernel stack
 | 
				
			||||||
 | 
					     *       volatile bool need_resched;                 // bool value: need to be rescheduled to release CPU?
 | 
				
			||||||
 | 
					     *       struct proc_struct *parent;                 // the parent process
 | 
				
			||||||
 | 
					     *       struct mm_struct *mm;                       // Process's memory management field
 | 
				
			||||||
 | 
					     *       struct context context;                     // Switch here to run process
 | 
				
			||||||
 | 
					     *       struct trapframe *tf;                       // Trap frame for current interrupt
 | 
				
			||||||
 | 
					     *       uintptr_t cr3;                              // CR3 register: the base addr of Page Directroy Table(PDT)
 | 
				
			||||||
 | 
					     *       uint32_t flags;                             // Process flag
 | 
				
			||||||
 | 
					     *       char name[PROC_NAME_LEN + 1];               // Process name
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					        proc->state = PROC_UNINIT;
 | 
				
			||||||
 | 
					        proc->pid = -1;
 | 
				
			||||||
 | 
					        proc->runs = 0;
 | 
				
			||||||
 | 
					        proc->kstack = 0;
 | 
				
			||||||
 | 
					        proc->need_resched = 0;
 | 
				
			||||||
 | 
					        proc->parent = NULL;
 | 
				
			||||||
 | 
					        proc->mm = NULL;
 | 
				
			||||||
 | 
					        memset(&(proc->context), 0, sizeof(struct context));
 | 
				
			||||||
 | 
					        proc->tf = NULL;
 | 
				
			||||||
 | 
					        proc->cr3 = boot_cr3;
 | 
				
			||||||
 | 
					        proc->flags = 0;
 | 
				
			||||||
 | 
					        memset(proc->name, 0, PROC_NAME_LEN);
 | 
				
			||||||
 | 
					        proc->wait_state = 0;
 | 
				
			||||||
 | 
					        proc->cptr = proc->optr = proc->yptr = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return proc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// set_proc_name - set the name of proc
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					set_proc_name(struct proc_struct *proc, const char *name) {
 | 
				
			||||||
 | 
					    memset(proc->name, 0, sizeof(proc->name));
 | 
				
			||||||
 | 
					    return memcpy(proc->name, name, PROC_NAME_LEN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// get_proc_name - get the name of proc
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					get_proc_name(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    static char name[PROC_NAME_LEN + 1];
 | 
				
			||||||
 | 
					    memset(name, 0, sizeof(name));
 | 
				
			||||||
 | 
					    return memcpy(name, proc->name, PROC_NAME_LEN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// set_links - set the relation links of process
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					set_links(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    list_add(&proc_list, &(proc->list_link));
 | 
				
			||||||
 | 
					    proc->yptr = NULL;
 | 
				
			||||||
 | 
					    if ((proc->optr = proc->parent->cptr) != NULL) {
 | 
				
			||||||
 | 
					        proc->optr->yptr = proc;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    proc->parent->cptr = proc;
 | 
				
			||||||
 | 
					    nr_process ++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// remove_links - clean the relation links of process
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					remove_links(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    list_del(&(proc->list_link));
 | 
				
			||||||
 | 
					    if (proc->optr != NULL) {
 | 
				
			||||||
 | 
					        proc->optr->yptr = proc->yptr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (proc->yptr != NULL) {
 | 
				
			||||||
 | 
					        proc->yptr->optr = proc->optr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					       proc->parent->cptr = proc->optr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nr_process --;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// get_pid - alloc a unique pid for process
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					get_pid(void) {
 | 
				
			||||||
 | 
					    static_assert(MAX_PID > MAX_PROCESS);
 | 
				
			||||||
 | 
					    struct proc_struct *proc;
 | 
				
			||||||
 | 
					    list_entry_t *list = &proc_list, *le;
 | 
				
			||||||
 | 
					    static int next_safe = MAX_PID, last_pid = MAX_PID;
 | 
				
			||||||
 | 
					    if (++ last_pid >= MAX_PID) {
 | 
				
			||||||
 | 
					        last_pid = 1;
 | 
				
			||||||
 | 
					        goto inside;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (last_pid >= next_safe) {
 | 
				
			||||||
 | 
					    inside:
 | 
				
			||||||
 | 
					        next_safe = MAX_PID;
 | 
				
			||||||
 | 
					    repeat:
 | 
				
			||||||
 | 
					        le = list;
 | 
				
			||||||
 | 
					        while ((le = list_next(le)) != list) {
 | 
				
			||||||
 | 
					            proc = le2proc(le, list_link);
 | 
				
			||||||
 | 
					            if (proc->pid == last_pid) {
 | 
				
			||||||
 | 
					                if (++ last_pid >= next_safe) {
 | 
				
			||||||
 | 
					                    if (last_pid >= MAX_PID) {
 | 
				
			||||||
 | 
					                        last_pid = 1;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    next_safe = MAX_PID;
 | 
				
			||||||
 | 
					                    goto repeat;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (proc->pid > last_pid && next_safe > proc->pid) {
 | 
				
			||||||
 | 
					                next_safe = proc->pid;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return last_pid;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// proc_run - make process "proc" running on cpu
 | 
				
			||||||
 | 
					// NOTE: before call switch_to, should load  base addr of "proc"'s new PDT
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					proc_run(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    if (proc != current) {
 | 
				
			||||||
 | 
					        bool intr_flag;
 | 
				
			||||||
 | 
					        struct proc_struct *prev = current, *next = proc;
 | 
				
			||||||
 | 
					        local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            current = proc;
 | 
				
			||||||
 | 
					            load_esp0(next->kstack + KSTACKSIZE);
 | 
				
			||||||
 | 
					            lcr3(next->cr3);
 | 
				
			||||||
 | 
					            switch_to(&(prev->context), &(next->context));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// forkret -- the first kernel entry point of a new thread/process
 | 
				
			||||||
 | 
					// NOTE: the addr of forkret is setted in copy_thread function
 | 
				
			||||||
 | 
					//       after switch_to, the current proc will execute here.
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					forkret(void) {
 | 
				
			||||||
 | 
					    forkrets(current->tf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// hash_proc - add proc into proc hash_list
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					hash_proc(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    list_add(hash_list + pid_hashfn(proc->pid), &(proc->hash_link));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// unhash_proc - delete proc from proc hash_list
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					unhash_proc(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    list_del(&(proc->hash_link));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// find_proc - find proc frome proc hash_list according to pid
 | 
				
			||||||
 | 
					struct proc_struct *
 | 
				
			||||||
 | 
					find_proc(int pid) {
 | 
				
			||||||
 | 
					    if (0 < pid && pid < MAX_PID) {
 | 
				
			||||||
 | 
					        list_entry_t *list = hash_list + pid_hashfn(pid), *le = list;
 | 
				
			||||||
 | 
					        while ((le = list_next(le)) != list) {
 | 
				
			||||||
 | 
					            struct proc_struct *proc = le2proc(le, hash_link);
 | 
				
			||||||
 | 
					            if (proc->pid == pid) {
 | 
				
			||||||
 | 
					                return proc;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// kernel_thread - create a kernel thread using "fn" function
 | 
				
			||||||
 | 
					// NOTE: the contents of temp trapframe tf will be copied to 
 | 
				
			||||||
 | 
					//       proc->tf in do_fork-->copy_thread function
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					kernel_thread(int (*fn)(void *), void *arg, uint32_t clone_flags) {
 | 
				
			||||||
 | 
					    struct trapframe tf;
 | 
				
			||||||
 | 
					    memset(&tf, 0, sizeof(struct trapframe));
 | 
				
			||||||
 | 
					    tf.tf_cs = KERNEL_CS;
 | 
				
			||||||
 | 
					    tf.tf_ds = tf.tf_es = tf.tf_ss = KERNEL_DS;
 | 
				
			||||||
 | 
					    tf.tf_regs.reg_ebx = (uint32_t)fn;
 | 
				
			||||||
 | 
					    tf.tf_regs.reg_edx = (uint32_t)arg;
 | 
				
			||||||
 | 
					    tf.tf_eip = (uint32_t)kernel_thread_entry;
 | 
				
			||||||
 | 
					    return do_fork(clone_flags | CLONE_VM, 0, &tf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// setup_kstack - alloc pages with size KSTACKPAGE as process kernel stack
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					setup_kstack(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    struct Page *page = alloc_pages(KSTACKPAGE);
 | 
				
			||||||
 | 
					    if (page != NULL) {
 | 
				
			||||||
 | 
					        proc->kstack = (uintptr_t)page2kva(page);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return -E_NO_MEM;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// put_kstack - free the memory space of process kernel stack
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					put_kstack(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    free_pages(kva2page((void *)(proc->kstack)), KSTACKPAGE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// setup_pgdir - alloc one page as PDT
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					setup_pgdir(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    struct Page *page;
 | 
				
			||||||
 | 
					    if ((page = alloc_page()) == NULL) {
 | 
				
			||||||
 | 
					        return -E_NO_MEM;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pde_t *pgdir = page2kva(page);
 | 
				
			||||||
 | 
					    memcpy(pgdir, boot_pgdir, PGSIZE);
 | 
				
			||||||
 | 
					    pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_P | PTE_W;
 | 
				
			||||||
 | 
					    mm->pgdir = pgdir;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// put_pgdir - free the memory space of PDT
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					put_pgdir(struct mm_struct *mm) {
 | 
				
			||||||
 | 
					    free_page(kva2page(mm->pgdir));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// copy_mm - process "proc" duplicate OR share process "current"'s mm according clone_flags
 | 
				
			||||||
 | 
					//         - if clone_flags & CLONE_VM, then "share" ; else "duplicate"
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					copy_mm(uint32_t clone_flags, struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    struct mm_struct *mm, *oldmm = current->mm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* current is a kernel thread */
 | 
				
			||||||
 | 
					    if (oldmm == NULL) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (clone_flags & CLONE_VM) {
 | 
				
			||||||
 | 
					        mm = oldmm;
 | 
				
			||||||
 | 
					        goto good_mm;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = -E_NO_MEM;
 | 
				
			||||||
 | 
					    if ((mm = mm_create()) == NULL) {
 | 
				
			||||||
 | 
					        goto bad_mm;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (setup_pgdir(mm) != 0) {
 | 
				
			||||||
 | 
					        goto bad_pgdir_cleanup_mm;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lock_mm(oldmm);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ret = dup_mmap(mm, oldmm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    unlock_mm(oldmm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret != 0) {
 | 
				
			||||||
 | 
					        goto bad_dup_cleanup_mmap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					good_mm:
 | 
				
			||||||
 | 
					    mm_count_inc(mm);
 | 
				
			||||||
 | 
					    proc->mm = mm;
 | 
				
			||||||
 | 
					    proc->cr3 = PADDR(mm->pgdir);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					bad_dup_cleanup_mmap:
 | 
				
			||||||
 | 
					    exit_mmap(mm);
 | 
				
			||||||
 | 
					    put_pgdir(mm);
 | 
				
			||||||
 | 
					bad_pgdir_cleanup_mm:
 | 
				
			||||||
 | 
					    mm_destroy(mm);
 | 
				
			||||||
 | 
					bad_mm:
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// copy_thread - setup the trapframe on the  process's kernel stack top and
 | 
				
			||||||
 | 
					//             - setup the kernel entry point and stack of process
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					copy_thread(struct proc_struct *proc, uintptr_t esp, struct trapframe *tf) {
 | 
				
			||||||
 | 
					    proc->tf = (struct trapframe *)(proc->kstack + KSTACKSIZE) - 1;
 | 
				
			||||||
 | 
					    *(proc->tf) = *tf;
 | 
				
			||||||
 | 
					    proc->tf->tf_regs.reg_eax = 0;
 | 
				
			||||||
 | 
					    proc->tf->tf_esp = esp;
 | 
				
			||||||
 | 
					    proc->tf->tf_eflags |= FL_IF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    proc->context.eip = (uintptr_t)forkret;
 | 
				
			||||||
 | 
					    proc->context.esp = (uintptr_t)(proc->tf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* do_fork -     parent process for a new child process
 | 
				
			||||||
 | 
					 * @clone_flags: used to guide how to clone the child process
 | 
				
			||||||
 | 
					 * @stack:       the parent's user stack pointer. if stack==0, It means to fork a kernel thread.
 | 
				
			||||||
 | 
					 * @tf:          the trapframe info, which will be copied to child process's proc->tf
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) {
 | 
				
			||||||
 | 
					    int ret = -E_NO_FREE_PROC;
 | 
				
			||||||
 | 
					    struct proc_struct *proc;
 | 
				
			||||||
 | 
					    if (nr_process >= MAX_PROCESS) {
 | 
				
			||||||
 | 
					        goto fork_out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret = -E_NO_MEM;
 | 
				
			||||||
 | 
					    //LAB4:EXERCISE2 YOUR CODE
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Some Useful MACROs, Functions and DEFINEs, you can use them in below implementation.
 | 
				
			||||||
 | 
					     * MACROs or Functions:
 | 
				
			||||||
 | 
					     *   alloc_proc:   create a proc struct and init fields (lab4:exercise1)
 | 
				
			||||||
 | 
					     *   setup_kstack: alloc pages with size KSTACKPAGE as process kernel stack
 | 
				
			||||||
 | 
					     *   copy_mm:      process "proc" duplicate OR share process "current"'s mm according clone_flags
 | 
				
			||||||
 | 
					     *                 if clone_flags & CLONE_VM, then "share" ; else "duplicate"
 | 
				
			||||||
 | 
					     *   copy_thread:  setup the trapframe on the  process's kernel stack top and
 | 
				
			||||||
 | 
					     *                 setup the kernel entry point and stack of process
 | 
				
			||||||
 | 
					     *   hash_proc:    add proc into proc hash_list
 | 
				
			||||||
 | 
					     *   get_pid:      alloc a unique pid for process
 | 
				
			||||||
 | 
					     *   wakup_proc:   set proc->state = PROC_RUNNABLE
 | 
				
			||||||
 | 
					     * VARIABLES:
 | 
				
			||||||
 | 
					     *   proc_list:    the process set's list
 | 
				
			||||||
 | 
					     *   nr_process:   the number of process set
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //    1. call alloc_proc to allocate a proc_struct
 | 
				
			||||||
 | 
					    //    2. call setup_kstack to allocate a kernel stack for child process
 | 
				
			||||||
 | 
					    //    3. call copy_mm to dup OR share mm according clone_flag
 | 
				
			||||||
 | 
					    //    4. call copy_thread to setup tf & context in proc_struct
 | 
				
			||||||
 | 
					    //    5. insert proc_struct into hash_list && proc_list
 | 
				
			||||||
 | 
					    //    6. call wakup_proc to make the new child process RUNNABLE
 | 
				
			||||||
 | 
					    //    7. set ret vaule using child proc's pid
 | 
				
			||||||
 | 
					    if ((proc = alloc_proc()) == NULL) {
 | 
				
			||||||
 | 
					        goto fork_out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    proc->parent = current;
 | 
				
			||||||
 | 
					    assert(current->wait_state == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (setup_kstack(proc) != 0) {
 | 
				
			||||||
 | 
					        goto bad_fork_cleanup_proc;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (copy_mm(clone_flags, proc) != 0) {
 | 
				
			||||||
 | 
					        goto bad_fork_cleanup_kstack;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    copy_thread(proc, stack, tf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        proc->pid = get_pid();
 | 
				
			||||||
 | 
					        hash_proc(proc);
 | 
				
			||||||
 | 
					        set_links(proc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wakeup_proc(proc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = proc->pid;
 | 
				
			||||||
 | 
					fork_out:
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bad_fork_cleanup_kstack:
 | 
				
			||||||
 | 
					    put_kstack(proc);
 | 
				
			||||||
 | 
					bad_fork_cleanup_proc:
 | 
				
			||||||
 | 
					    kfree(proc);
 | 
				
			||||||
 | 
					    goto fork_out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// do_exit - called by sys_exit
 | 
				
			||||||
 | 
					//   1. call exit_mmap & put_pgdir & mm_destroy to free the almost all memory space of process
 | 
				
			||||||
 | 
					//   2. set process' state as PROC_ZOMBIE, then call wakeup_proc(parent) to ask parent reclaim itself.
 | 
				
			||||||
 | 
					//   3. call scheduler to switch to other process
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					do_exit(int error_code) {
 | 
				
			||||||
 | 
					    if (current == idleproc) {
 | 
				
			||||||
 | 
					        panic("idleproc exit.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (current == initproc) {
 | 
				
			||||||
 | 
					        panic("initproc exit.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    struct mm_struct *mm = current->mm;
 | 
				
			||||||
 | 
					    if (mm != NULL) {
 | 
				
			||||||
 | 
					        lcr3(boot_cr3);
 | 
				
			||||||
 | 
					        if (mm_count_dec(mm) == 0) {
 | 
				
			||||||
 | 
					            exit_mmap(mm);
 | 
				
			||||||
 | 
					            put_pgdir(mm);
 | 
				
			||||||
 | 
					            mm_destroy(mm);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        current->mm = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    current->state = PROC_ZOMBIE;
 | 
				
			||||||
 | 
					    current->exit_code = error_code;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    struct proc_struct *proc;
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        proc = current->parent;
 | 
				
			||||||
 | 
					        if (proc->wait_state == WT_CHILD) {
 | 
				
			||||||
 | 
					            wakeup_proc(proc);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        while (current->cptr != NULL) {
 | 
				
			||||||
 | 
					            proc = current->cptr;
 | 
				
			||||||
 | 
					            current->cptr = proc->optr;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					            proc->yptr = NULL;
 | 
				
			||||||
 | 
					            if ((proc->optr = initproc->cptr) != NULL) {
 | 
				
			||||||
 | 
					                initproc->cptr->yptr = proc;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            proc->parent = initproc;
 | 
				
			||||||
 | 
					            initproc->cptr = proc;
 | 
				
			||||||
 | 
					            if (proc->state == PROC_ZOMBIE) {
 | 
				
			||||||
 | 
					                if (initproc->wait_state == WT_CHILD) {
 | 
				
			||||||
 | 
					                    wakeup_proc(initproc);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    schedule();
 | 
				
			||||||
 | 
					    panic("do_exit will not return!! %d.\n", current->pid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* load_icode - load the content of binary program(ELF format) as the new content of current process
 | 
				
			||||||
 | 
					 * @binary:  the memory addr of the content of binary program
 | 
				
			||||||
 | 
					 * @size:  the size of the content of binary program
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					load_icode(unsigned char *binary, size_t size) {
 | 
				
			||||||
 | 
					    if (current->mm != NULL) {
 | 
				
			||||||
 | 
					        panic("load_icode: current->mm must be empty.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = -E_NO_MEM;
 | 
				
			||||||
 | 
					    struct mm_struct *mm;
 | 
				
			||||||
 | 
					    //(1) create a new mm for current process
 | 
				
			||||||
 | 
					    if ((mm = mm_create()) == NULL) {
 | 
				
			||||||
 | 
					        goto bad_mm;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //(2) create a new PDT, and mm->pgdir= kernel virtual addr of PDT
 | 
				
			||||||
 | 
					    if (setup_pgdir(mm) != 0) {
 | 
				
			||||||
 | 
					        goto bad_pgdir_cleanup_mm;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //(3) copy TEXT/DATA section, build BSS parts in binary to memory space of process
 | 
				
			||||||
 | 
					    struct Page *page;
 | 
				
			||||||
 | 
					    //(3.1) get the file header of the bianry program (ELF format)
 | 
				
			||||||
 | 
					    struct elfhdr *elf = (struct elfhdr *)binary;
 | 
				
			||||||
 | 
					    //(3.2) get the entry of the program section headers of the bianry program (ELF format)
 | 
				
			||||||
 | 
					    struct proghdr *ph = (struct proghdr *)(binary + elf->e_phoff);
 | 
				
			||||||
 | 
					    //(3.3) This program is valid?
 | 
				
			||||||
 | 
					    if (elf->e_magic != ELF_MAGIC) {
 | 
				
			||||||
 | 
					        ret = -E_INVAL_ELF;
 | 
				
			||||||
 | 
					        goto bad_elf_cleanup_pgdir;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t vm_flags, perm;
 | 
				
			||||||
 | 
					    struct proghdr *ph_end = ph + elf->e_phnum;
 | 
				
			||||||
 | 
					    for (; ph < ph_end; ph ++) {
 | 
				
			||||||
 | 
					    //(3.4) find every program section headers
 | 
				
			||||||
 | 
					        if (ph->p_type != ELF_PT_LOAD) {
 | 
				
			||||||
 | 
					            continue ;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (ph->p_filesz > ph->p_memsz) {
 | 
				
			||||||
 | 
					            ret = -E_INVAL_ELF;
 | 
				
			||||||
 | 
					            goto bad_cleanup_mmap;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (ph->p_filesz == 0) {
 | 
				
			||||||
 | 
					            continue ;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    //(3.5) call mm_map fun to setup the new vma ( ph->p_va, ph->p_memsz)
 | 
				
			||||||
 | 
					        vm_flags = 0, perm = PTE_U;
 | 
				
			||||||
 | 
					        if (ph->p_flags & ELF_PF_X) vm_flags |= VM_EXEC;
 | 
				
			||||||
 | 
					        if (ph->p_flags & ELF_PF_W) vm_flags |= VM_WRITE;
 | 
				
			||||||
 | 
					        if (ph->p_flags & ELF_PF_R) vm_flags |= VM_READ;
 | 
				
			||||||
 | 
					        if (vm_flags & VM_WRITE) perm |= PTE_W;
 | 
				
			||||||
 | 
					        if ((ret = mm_map(mm, ph->p_va, ph->p_memsz, vm_flags, NULL)) != 0) {
 | 
				
			||||||
 | 
					            goto bad_cleanup_mmap;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        unsigned char *from = binary + ph->p_offset;
 | 
				
			||||||
 | 
					        size_t off, size;
 | 
				
			||||||
 | 
					        uintptr_t start = ph->p_va, end, la = ROUNDDOWN(start, PGSIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = -E_NO_MEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     //(3.6) alloc memory, and  copy the contents of every program section (from, from+end) to process's memory (la, la+end)
 | 
				
			||||||
 | 
					        end = ph->p_va + ph->p_filesz;
 | 
				
			||||||
 | 
					     //(3.6.1) copy TEXT/DATA section of bianry program
 | 
				
			||||||
 | 
					        while (start < end) {
 | 
				
			||||||
 | 
					            if ((page = pgdir_alloc_page(mm->pgdir, la, perm)) == NULL) {
 | 
				
			||||||
 | 
					                goto bad_cleanup_mmap;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            off = start - la, size = PGSIZE - off, la += PGSIZE;
 | 
				
			||||||
 | 
					            if (end < la) {
 | 
				
			||||||
 | 
					                size -= la - end;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            memcpy(page2kva(page) + off, from, size);
 | 
				
			||||||
 | 
					            start += size, from += size;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      //(3.6.2) build BSS section of binary program
 | 
				
			||||||
 | 
					        end = ph->p_va + ph->p_memsz;
 | 
				
			||||||
 | 
					        if (start < la) {
 | 
				
			||||||
 | 
					            /* ph->p_memsz == ph->p_filesz */
 | 
				
			||||||
 | 
					            if (start == end) {
 | 
				
			||||||
 | 
					                continue ;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            off = start + PGSIZE - la, size = PGSIZE - off;
 | 
				
			||||||
 | 
					            if (end < la) {
 | 
				
			||||||
 | 
					                size -= la - end;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            memset(page2kva(page) + off, 0, size);
 | 
				
			||||||
 | 
					            start += size;
 | 
				
			||||||
 | 
					            assert((end < la && start == end) || (end >= la && start == la));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        while (start < end) {
 | 
				
			||||||
 | 
					            if ((page = pgdir_alloc_page(mm->pgdir, la, perm)) == NULL) {
 | 
				
			||||||
 | 
					                goto bad_cleanup_mmap;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            off = start - la, size = PGSIZE - off, la += PGSIZE;
 | 
				
			||||||
 | 
					            if (end < la) {
 | 
				
			||||||
 | 
					                size -= la - end;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            memset(page2kva(page) + off, 0, size);
 | 
				
			||||||
 | 
					            start += size;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //(4) build user stack memory
 | 
				
			||||||
 | 
					    vm_flags = VM_READ | VM_WRITE | VM_STACK;
 | 
				
			||||||
 | 
					    if ((ret = mm_map(mm, USTACKTOP - USTACKSIZE, USTACKSIZE, vm_flags, NULL)) != 0) {
 | 
				
			||||||
 | 
					        goto bad_cleanup_mmap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-PGSIZE , PTE_USER) != NULL);
 | 
				
			||||||
 | 
					    assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-2*PGSIZE , PTE_USER) != NULL);
 | 
				
			||||||
 | 
					    assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-3*PGSIZE , PTE_USER) != NULL);
 | 
				
			||||||
 | 
					    assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-4*PGSIZE , PTE_USER) != NULL);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    //(5) set current process's mm, sr3, and set CR3 reg = physical addr of Page Directory
 | 
				
			||||||
 | 
					    mm_count_inc(mm);
 | 
				
			||||||
 | 
					    current->mm = mm;
 | 
				
			||||||
 | 
					    current->cr3 = PADDR(mm->pgdir);
 | 
				
			||||||
 | 
					    lcr3(PADDR(mm->pgdir));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //(6) setup trapframe for user environment
 | 
				
			||||||
 | 
					    struct trapframe *tf = current->tf;
 | 
				
			||||||
 | 
					    memset(tf, 0, sizeof(struct trapframe));
 | 
				
			||||||
 | 
					    /* LAB5:EXERCISE1 YOUR CODE
 | 
				
			||||||
 | 
					     * should set tf_cs,tf_ds,tf_es,tf_ss,tf_esp,tf_eip,tf_eflags
 | 
				
			||||||
 | 
					     * NOTICE: If we set trapframe correctly, then the user level process can return to USER MODE from kernel. So
 | 
				
			||||||
 | 
					     *          tf_cs should be USER_CS segment (see memlayout.h)
 | 
				
			||||||
 | 
					     *          tf_ds=tf_es=tf_ss should be USER_DS segment
 | 
				
			||||||
 | 
					     *          tf_esp should be the top addr of user stack (USTACKTOP)
 | 
				
			||||||
 | 
					     *          tf_eip should be the entry point of this binary program (elf->e_entry)
 | 
				
			||||||
 | 
					     *          tf_eflags should be set to enable computer to produce Interrupt
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    tf->tf_cs = USER_CS;
 | 
				
			||||||
 | 
					    tf->tf_ds = tf->tf_es = tf->tf_ss = USER_DS;
 | 
				
			||||||
 | 
					    tf->tf_esp = USTACKTOP;
 | 
				
			||||||
 | 
					    tf->tf_eip = elf->e_entry;
 | 
				
			||||||
 | 
					    tf->tf_eflags = FL_IF;
 | 
				
			||||||
 | 
					    ret = 0;
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					bad_cleanup_mmap:
 | 
				
			||||||
 | 
					    exit_mmap(mm);
 | 
				
			||||||
 | 
					bad_elf_cleanup_pgdir:
 | 
				
			||||||
 | 
					    put_pgdir(mm);
 | 
				
			||||||
 | 
					bad_pgdir_cleanup_mm:
 | 
				
			||||||
 | 
					    mm_destroy(mm);
 | 
				
			||||||
 | 
					bad_mm:
 | 
				
			||||||
 | 
					    goto out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// do_execve - call exit_mmap(mm)&pug_pgdir(mm) to reclaim memory space of current process
 | 
				
			||||||
 | 
					//           - call load_icode to setup new memory space accroding binary prog.
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					do_execve(const char *name, size_t len, unsigned char *binary, size_t size) {
 | 
				
			||||||
 | 
					    struct mm_struct *mm = current->mm;
 | 
				
			||||||
 | 
					    if (!user_mem_check(mm, (uintptr_t)name, len, 0)) {
 | 
				
			||||||
 | 
					        return -E_INVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (len > PROC_NAME_LEN) {
 | 
				
			||||||
 | 
					        len = PROC_NAME_LEN;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char local_name[PROC_NAME_LEN + 1];
 | 
				
			||||||
 | 
					    memset(local_name, 0, sizeof(local_name));
 | 
				
			||||||
 | 
					    memcpy(local_name, name, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mm != NULL) {
 | 
				
			||||||
 | 
					        lcr3(boot_cr3);
 | 
				
			||||||
 | 
					        if (mm_count_dec(mm) == 0) {
 | 
				
			||||||
 | 
					            exit_mmap(mm);
 | 
				
			||||||
 | 
					            put_pgdir(mm);
 | 
				
			||||||
 | 
					            mm_destroy(mm);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        current->mm = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    if ((ret = load_icode(binary, size)) != 0) {
 | 
				
			||||||
 | 
					        goto execve_exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    set_proc_name(current, local_name);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					execve_exit:
 | 
				
			||||||
 | 
					    do_exit(ret);
 | 
				
			||||||
 | 
					    panic("already exit: %e.\n", ret);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// do_yield - ask the scheduler to reschedule
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					do_yield(void) {
 | 
				
			||||||
 | 
					    current->need_resched = 1;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// do_wait - wait one OR any children with PROC_ZOMBIE state, and free memory space of kernel stack
 | 
				
			||||||
 | 
					//         - proc struct of this child.
 | 
				
			||||||
 | 
					// NOTE: only after do_wait function, all resources of the child proces are free.
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					do_wait(int pid, int *code_store) {
 | 
				
			||||||
 | 
					    struct mm_struct *mm = current->mm;
 | 
				
			||||||
 | 
					    if (code_store != NULL) {
 | 
				
			||||||
 | 
					        if (!user_mem_check(mm, (uintptr_t)code_store, sizeof(int), 1)) {
 | 
				
			||||||
 | 
					            return -E_INVAL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct proc_struct *proc;
 | 
				
			||||||
 | 
					    bool intr_flag, haskid;
 | 
				
			||||||
 | 
					repeat:
 | 
				
			||||||
 | 
					    haskid = 0;
 | 
				
			||||||
 | 
					    if (pid != 0) {
 | 
				
			||||||
 | 
					        proc = find_proc(pid);
 | 
				
			||||||
 | 
					        if (proc != NULL && proc->parent == current) {
 | 
				
			||||||
 | 
					            haskid = 1;
 | 
				
			||||||
 | 
					            if (proc->state == PROC_ZOMBIE) {
 | 
				
			||||||
 | 
					                goto found;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        proc = current->cptr;
 | 
				
			||||||
 | 
					        for (; proc != NULL; proc = proc->optr) {
 | 
				
			||||||
 | 
					            haskid = 1;
 | 
				
			||||||
 | 
					            if (proc->state == PROC_ZOMBIE) {
 | 
				
			||||||
 | 
					                goto found;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (haskid) {
 | 
				
			||||||
 | 
					        current->state = PROC_SLEEPING;
 | 
				
			||||||
 | 
					        current->wait_state = WT_CHILD;
 | 
				
			||||||
 | 
					        schedule();
 | 
				
			||||||
 | 
					        if (current->flags & PF_EXITING) {
 | 
				
			||||||
 | 
					            do_exit(-E_KILLED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        goto repeat;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return -E_BAD_PROC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					found:
 | 
				
			||||||
 | 
					    if (proc == idleproc || proc == initproc) {
 | 
				
			||||||
 | 
					        panic("wait idleproc or initproc.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (code_store != NULL) {
 | 
				
			||||||
 | 
					        *code_store = proc->exit_code;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        unhash_proc(proc);
 | 
				
			||||||
 | 
					        remove_links(proc);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					    put_kstack(proc);
 | 
				
			||||||
 | 
					    kfree(proc);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// do_kill - kill process with pid by set this process's flags with PF_EXITING
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					do_kill(int pid) {
 | 
				
			||||||
 | 
					    struct proc_struct *proc;
 | 
				
			||||||
 | 
					    if ((proc = find_proc(pid)) != NULL) {
 | 
				
			||||||
 | 
					        if (!(proc->flags & PF_EXITING)) {
 | 
				
			||||||
 | 
					            proc->flags |= PF_EXITING;
 | 
				
			||||||
 | 
					            if (proc->wait_state & WT_INTERRUPTED) {
 | 
				
			||||||
 | 
					                wakeup_proc(proc);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return -E_KILLED;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return -E_INVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// kernel_execve - do SYS_exec syscall to exec a user program called by user_main kernel_thread
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					kernel_execve(const char *name, unsigned char *binary, size_t size) {
 | 
				
			||||||
 | 
					    int ret, len = strlen(name);
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "int %1;"
 | 
				
			||||||
 | 
					        : "=a" (ret)
 | 
				
			||||||
 | 
					        : "i" (T_SYSCALL), "0" (SYS_exec), "d" (name), "c" (len), "b" (binary), "D" (size)
 | 
				
			||||||
 | 
					        : "memory");
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __KERNEL_EXECVE(name, binary, size) ({                          \
 | 
				
			||||||
 | 
					            cprintf("kernel_execve: pid = %d, name = \"%s\".\n",        \
 | 
				
			||||||
 | 
					                    current->pid, name);                                \
 | 
				
			||||||
 | 
					            kernel_execve(name, binary, (size_t)(size));                \
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KERNEL_EXECVE(x) ({                                             \
 | 
				
			||||||
 | 
					            extern unsigned char _binary_obj___user_##x##_out_start[],  \
 | 
				
			||||||
 | 
					                _binary_obj___user_##x##_out_size[];                    \
 | 
				
			||||||
 | 
					            __KERNEL_EXECVE(#x, _binary_obj___user_##x##_out_start,     \
 | 
				
			||||||
 | 
					                            _binary_obj___user_##x##_out_size);         \
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __KERNEL_EXECVE2(x, xstart, xsize) ({                           \
 | 
				
			||||||
 | 
					            extern unsigned char xstart[], xsize[];                     \
 | 
				
			||||||
 | 
					            __KERNEL_EXECVE(#x, xstart, (size_t)xsize);                 \
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KERNEL_EXECVE2(x, xstart, xsize)        __KERNEL_EXECVE2(x, xstart, xsize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// user_main - kernel thread used to exec a user program
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					user_main(void *arg) {
 | 
				
			||||||
 | 
					#ifdef TEST
 | 
				
			||||||
 | 
					    KERNEL_EXECVE2(TEST, TESTSTART, TESTSIZE);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    KERNEL_EXECVE(exit);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    panic("user_main execve failed.\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// init_main - the second kernel thread used to create user_main kernel threads
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					init_main(void *arg) {
 | 
				
			||||||
 | 
					    size_t nr_free_pages_store = nr_free_pages();
 | 
				
			||||||
 | 
					    size_t kernel_allocated_store = kallocated();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int pid = kernel_thread(user_main, NULL, 0);
 | 
				
			||||||
 | 
					    if (pid <= 0) {
 | 
				
			||||||
 | 
					        panic("create user_main failed.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (do_wait(0, NULL) == 0) {
 | 
				
			||||||
 | 
					        schedule();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("all user-mode processes have quit.\n");
 | 
				
			||||||
 | 
					    assert(initproc->cptr == NULL && initproc->yptr == NULL && initproc->optr == NULL);
 | 
				
			||||||
 | 
					    assert(nr_process == 2);
 | 
				
			||||||
 | 
					    assert(list_next(&proc_list) == &(initproc->list_link));
 | 
				
			||||||
 | 
					    assert(list_prev(&proc_list) == &(initproc->list_link));
 | 
				
			||||||
 | 
					    assert(nr_free_pages_store == nr_free_pages());
 | 
				
			||||||
 | 
					    assert(kernel_allocated_store == kallocated());
 | 
				
			||||||
 | 
					    cprintf("init check memory pass.\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// proc_init - set up the first kernel thread idleproc "idle" by itself and 
 | 
				
			||||||
 | 
					//           - create the second kernel thread init_main
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					proc_init(void) {
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    list_init(&proc_list);
 | 
				
			||||||
 | 
					    for (i = 0; i < HASH_LIST_SIZE; i ++) {
 | 
				
			||||||
 | 
					        list_init(hash_list + i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((idleproc = alloc_proc()) == NULL) {
 | 
				
			||||||
 | 
					        panic("cannot alloc idleproc.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    idleproc->pid = 0;
 | 
				
			||||||
 | 
					    idleproc->state = PROC_RUNNABLE;
 | 
				
			||||||
 | 
					    idleproc->kstack = (uintptr_t)bootstack;
 | 
				
			||||||
 | 
					    idleproc->need_resched = 1;
 | 
				
			||||||
 | 
					    set_proc_name(idleproc, "idle");
 | 
				
			||||||
 | 
					    nr_process ++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    current = idleproc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int pid = kernel_thread(init_main, NULL, 0);
 | 
				
			||||||
 | 
					    if (pid <= 0) {
 | 
				
			||||||
 | 
					        panic("create init_main failed.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    initproc = find_proc(pid);
 | 
				
			||||||
 | 
					    set_proc_name(initproc, "init");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(idleproc != NULL && idleproc->pid == 0);
 | 
				
			||||||
 | 
					    assert(initproc != NULL && initproc->pid == 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// cpu_idle - at the end of kern_init, the first kernel thread idleproc will do below works
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					cpu_idle(void) {
 | 
				
			||||||
 | 
					    while (1) {
 | 
				
			||||||
 | 
					        if (current->need_resched) {
 | 
				
			||||||
 | 
					            schedule();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										89
									
								
								related_info/lab5/lab5-spoc-discuss/kern/process/proc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								related_info/lab5/lab5-spoc-discuss/kern/process/proc.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_PROCESS_PROC_H__
 | 
				
			||||||
 | 
					#define __KERN_PROCESS_PROC_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <list.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// process's state in his life cycle
 | 
				
			||||||
 | 
					enum proc_state {
 | 
				
			||||||
 | 
					    PROC_UNINIT = 0,  // uninitialized
 | 
				
			||||||
 | 
					    PROC_SLEEPING,    // sleeping
 | 
				
			||||||
 | 
					    PROC_RUNNABLE,    // runnable(maybe running)
 | 
				
			||||||
 | 
					    PROC_ZOMBIE,      // almost dead, and wait parent proc to reclaim his resource
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Saved registers for kernel context switches.
 | 
				
			||||||
 | 
					// Don't need to save all the %fs etc. segment registers,
 | 
				
			||||||
 | 
					// because they are constant across kernel contexts.
 | 
				
			||||||
 | 
					// Save all the regular registers so we don't need to care
 | 
				
			||||||
 | 
					// which are caller save, but not the return register %eax.
 | 
				
			||||||
 | 
					// (Not saving %eax just simplifies the switching code.)
 | 
				
			||||||
 | 
					// The layout of context must match code in switch.S.
 | 
				
			||||||
 | 
					struct context {
 | 
				
			||||||
 | 
					    uint32_t eip;
 | 
				
			||||||
 | 
					    uint32_t esp;
 | 
				
			||||||
 | 
					    uint32_t ebx;
 | 
				
			||||||
 | 
					    uint32_t ecx;
 | 
				
			||||||
 | 
					    uint32_t edx;
 | 
				
			||||||
 | 
					    uint32_t esi;
 | 
				
			||||||
 | 
					    uint32_t edi;
 | 
				
			||||||
 | 
					    uint32_t ebp;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PROC_NAME_LEN               15
 | 
				
			||||||
 | 
					#define MAX_PROCESS                 4096
 | 
				
			||||||
 | 
					#define MAX_PID                     (MAX_PROCESS * 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern list_entry_t proc_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct proc_struct {
 | 
				
			||||||
 | 
					    enum proc_state state;                      // Process state
 | 
				
			||||||
 | 
					    int pid;                                    // Process ID
 | 
				
			||||||
 | 
					    int runs;                                   // the running times of Proces
 | 
				
			||||||
 | 
					    uintptr_t kstack;                           // Process kernel stack
 | 
				
			||||||
 | 
					    volatile bool need_resched;                 // bool value: need to be rescheduled to release CPU?
 | 
				
			||||||
 | 
					    struct proc_struct *parent;                 // the parent process
 | 
				
			||||||
 | 
					    struct mm_struct *mm;                       // Process's memory management field
 | 
				
			||||||
 | 
					    struct context context;                     // Switch here to run process
 | 
				
			||||||
 | 
					    struct trapframe *tf;                       // Trap frame for current interrupt
 | 
				
			||||||
 | 
					    uintptr_t cr3;                              // CR3 register: the base addr of Page Directroy Table(PDT)
 | 
				
			||||||
 | 
					    uint32_t flags;                             // Process flag
 | 
				
			||||||
 | 
					    char name[PROC_NAME_LEN + 1];               // Process name
 | 
				
			||||||
 | 
					    list_entry_t list_link;                     // Process link list 
 | 
				
			||||||
 | 
					    list_entry_t hash_link;                     // Process hash list
 | 
				
			||||||
 | 
					    int exit_code;                              // exit code (be sent to parent proc)
 | 
				
			||||||
 | 
					    uint32_t wait_state;                        // waiting state
 | 
				
			||||||
 | 
					    struct proc_struct *cptr, *yptr, *optr;     // relations between processes
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PF_EXITING                  0x00000001      // getting shutdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define WT_CHILD                    (0x00000001 | WT_INTERRUPTED)
 | 
				
			||||||
 | 
					#define WT_INTERRUPTED               0x80000000                    // the wait state could be interrupted
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define le2proc(le, member)         \
 | 
				
			||||||
 | 
					    to_struct((le), struct proc_struct, member)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct proc_struct *idleproc, *initproc, *current;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void proc_init(void);
 | 
				
			||||||
 | 
					void proc_run(struct proc_struct *proc);
 | 
				
			||||||
 | 
					int kernel_thread(int (*fn)(void *), void *arg, uint32_t clone_flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *set_proc_name(struct proc_struct *proc, const char *name);
 | 
				
			||||||
 | 
					char *get_proc_name(struct proc_struct *proc);
 | 
				
			||||||
 | 
					void cpu_idle(void) __attribute__((noreturn));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct proc_struct *find_proc(int pid);
 | 
				
			||||||
 | 
					int do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf);
 | 
				
			||||||
 | 
					int do_exit(int error_code);
 | 
				
			||||||
 | 
					int do_yield(void);
 | 
				
			||||||
 | 
					int do_execve(const char *name, size_t len, unsigned char *binary, size_t size);
 | 
				
			||||||
 | 
					int do_wait(int pid, int *code_store);
 | 
				
			||||||
 | 
					int do_kill(int pid);
 | 
				
			||||||
 | 
					#endif /* !__KERN_PROCESS_PROC_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										30
									
								
								related_info/lab5/lab5-spoc-discuss/kern/process/switch.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								related_info/lab5/lab5-spoc-discuss/kern/process/switch.S
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					.text
 | 
				
			||||||
 | 
					.globl switch_to
 | 
				
			||||||
 | 
					switch_to:                      # switch_to(from, to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # save from's registers
 | 
				
			||||||
 | 
					    movl 4(%esp), %eax          # eax points to from
 | 
				
			||||||
 | 
					    popl 0(%eax)                # save eip !popl
 | 
				
			||||||
 | 
					    movl %esp, 4(%eax)
 | 
				
			||||||
 | 
					    movl %ebx, 8(%eax)
 | 
				
			||||||
 | 
					    movl %ecx, 12(%eax)
 | 
				
			||||||
 | 
					    movl %edx, 16(%eax)
 | 
				
			||||||
 | 
					    movl %esi, 20(%eax)
 | 
				
			||||||
 | 
					    movl %edi, 24(%eax)
 | 
				
			||||||
 | 
					    movl %ebp, 28(%eax)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # restore to's registers
 | 
				
			||||||
 | 
					    movl 4(%esp), %eax          # not 8(%esp): popped return address already
 | 
				
			||||||
 | 
					                                # eax now points to to
 | 
				
			||||||
 | 
					    movl 28(%eax), %ebp
 | 
				
			||||||
 | 
					    movl 24(%eax), %edi
 | 
				
			||||||
 | 
					    movl 20(%eax), %esi
 | 
				
			||||||
 | 
					    movl 16(%eax), %edx
 | 
				
			||||||
 | 
					    movl 12(%eax), %ecx
 | 
				
			||||||
 | 
					    movl 8(%eax), %ebx
 | 
				
			||||||
 | 
					    movl 4(%eax), %esp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pushl 0(%eax)               # push eip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										52
									
								
								related_info/lab5/lab5-spoc-discuss/kern/schedule/sched.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								related_info/lab5/lab5-spoc-discuss/kern/schedule/sched.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					#include <list.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					#include <proc.h>
 | 
				
			||||||
 | 
					#include <sched.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					wakeup_proc(struct proc_struct *proc) {
 | 
				
			||||||
 | 
					    assert(proc->state != PROC_ZOMBIE);
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (proc->state != PROC_RUNNABLE) {
 | 
				
			||||||
 | 
					            proc->state = PROC_RUNNABLE;
 | 
				
			||||||
 | 
					            proc->wait_state = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            warn("wakeup runnable process.\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					schedule(void) {
 | 
				
			||||||
 | 
					    bool intr_flag;
 | 
				
			||||||
 | 
					    list_entry_t *le, *last;
 | 
				
			||||||
 | 
					    struct proc_struct *next = NULL;
 | 
				
			||||||
 | 
					    local_intr_save(intr_flag);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        current->need_resched = 0;
 | 
				
			||||||
 | 
					        last = (current == idleproc) ? &proc_list : &(current->list_link);
 | 
				
			||||||
 | 
					        le = last;
 | 
				
			||||||
 | 
					        do {
 | 
				
			||||||
 | 
					            if ((le = list_next(le)) != &proc_list) {
 | 
				
			||||||
 | 
					                next = le2proc(le, list_link);
 | 
				
			||||||
 | 
					                if (next->state == PROC_RUNNABLE) {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } while (le != last);
 | 
				
			||||||
 | 
					        if (next == NULL || next->state != PROC_RUNNABLE) {
 | 
				
			||||||
 | 
					            next = idleproc;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        next->runs ++;
 | 
				
			||||||
 | 
					        if (next != current) {
 | 
				
			||||||
 | 
					            proc_run(next);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    local_intr_restore(intr_flag);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								related_info/lab5/lab5-spoc-discuss/kern/schedule/sched.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								related_info/lab5/lab5-spoc-discuss/kern/schedule/sched.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_SCHEDULE_SCHED_H__
 | 
				
			||||||
 | 
					#define __KERN_SCHEDULE_SCHED_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <proc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void schedule(void);
 | 
				
			||||||
 | 
					void wakeup_proc(struct proc_struct *proc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_SCHEDULE_SCHED_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										57
									
								
								related_info/lab5/lab5-spoc-discuss/kern/sync/sync.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								related_info/lab5/lab5-spoc-discuss/kern/sync/sync.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_SYNC_SYNC_H__
 | 
				
			||||||
 | 
					#define __KERN_SYNC_SYNC_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <intr.h>
 | 
				
			||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <atomic.h>
 | 
				
			||||||
 | 
					#include <sched.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					__intr_save(void) {
 | 
				
			||||||
 | 
					    if (read_eflags() & FL_IF) {
 | 
				
			||||||
 | 
					        intr_disable();
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					__intr_restore(bool flag) {
 | 
				
			||||||
 | 
					    if (flag) {
 | 
				
			||||||
 | 
					        intr_enable();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define local_intr_save(x)      do { x = __intr_save(); } while (0)
 | 
				
			||||||
 | 
					#define local_intr_restore(x)   __intr_restore(x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef volatile bool lock_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					lock_init(lock_t *lock) {
 | 
				
			||||||
 | 
					    *lock = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					try_lock(lock_t *lock) {
 | 
				
			||||||
 | 
					    return !test_and_set_bit(0, lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					lock(lock_t *lock) {
 | 
				
			||||||
 | 
					    while (!try_lock(lock)) {
 | 
				
			||||||
 | 
					        schedule();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					unlock(lock_t *lock) {
 | 
				
			||||||
 | 
					    if (!test_and_clear_bit(0, lock)) {
 | 
				
			||||||
 | 
					        panic("Unlock failed.\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_SYNC_SYNC_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										101
									
								
								related_info/lab5/lab5-spoc-discuss/kern/syscall/syscall.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								related_info/lab5/lab5-spoc-discuss/kern/syscall/syscall.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <proc.h>
 | 
				
			||||||
 | 
					#include <syscall.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <pmm.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_exit(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    int error_code = (int)arg[0];
 | 
				
			||||||
 | 
					    return do_exit(error_code);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_fork(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    struct trapframe *tf = current->tf;
 | 
				
			||||||
 | 
					    uintptr_t stack = tf->tf_esp;
 | 
				
			||||||
 | 
					    return do_fork(0, stack, tf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_wait(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    int pid = (int)arg[0];
 | 
				
			||||||
 | 
					    int *store = (int *)arg[1];
 | 
				
			||||||
 | 
					    return do_wait(pid, store);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_exec(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    const char *name = (const char *)arg[0];
 | 
				
			||||||
 | 
					    size_t len = (size_t)arg[1];
 | 
				
			||||||
 | 
					    unsigned char *binary = (unsigned char *)arg[2];
 | 
				
			||||||
 | 
					    size_t size = (size_t)arg[3];
 | 
				
			||||||
 | 
					    return do_execve(name, len, binary, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_yield(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    return do_yield();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_kill(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    int pid = (int)arg[0];
 | 
				
			||||||
 | 
					    return do_kill(pid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_getpid(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    return current->pid;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_putc(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    int c = (int)arg[0];
 | 
				
			||||||
 | 
					    cputchar(c);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					sys_pgdir(uint32_t arg[]) {
 | 
				
			||||||
 | 
					    print_pgdir();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int (*syscalls[])(uint32_t arg[]) = {
 | 
				
			||||||
 | 
					    [SYS_exit]              sys_exit,
 | 
				
			||||||
 | 
					    [SYS_fork]              sys_fork,
 | 
				
			||||||
 | 
					    [SYS_wait]              sys_wait,
 | 
				
			||||||
 | 
					    [SYS_exec]              sys_exec,
 | 
				
			||||||
 | 
					    [SYS_yield]             sys_yield,
 | 
				
			||||||
 | 
					    [SYS_kill]              sys_kill,
 | 
				
			||||||
 | 
					    [SYS_getpid]            sys_getpid,
 | 
				
			||||||
 | 
					    [SYS_putc]              sys_putc,
 | 
				
			||||||
 | 
					    [SYS_pgdir]             sys_pgdir,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NUM_SYSCALLS        ((sizeof(syscalls)) / (sizeof(syscalls[0])))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					syscall(void) {
 | 
				
			||||||
 | 
					    struct trapframe *tf = current->tf;
 | 
				
			||||||
 | 
					    uint32_t arg[5];
 | 
				
			||||||
 | 
					    int num = tf->tf_regs.reg_eax;
 | 
				
			||||||
 | 
					    if (num >= 0 && num < NUM_SYSCALLS) {
 | 
				
			||||||
 | 
					        if (syscalls[num] != NULL) {
 | 
				
			||||||
 | 
					            arg[0] = tf->tf_regs.reg_edx;
 | 
				
			||||||
 | 
					            arg[1] = tf->tf_regs.reg_ecx;
 | 
				
			||||||
 | 
					            arg[2] = tf->tf_regs.reg_ebx;
 | 
				
			||||||
 | 
					            arg[3] = tf->tf_regs.reg_edi;
 | 
				
			||||||
 | 
					            arg[4] = tf->tf_regs.reg_esi;
 | 
				
			||||||
 | 
					            tf->tf_regs.reg_eax = syscalls[num](arg);
 | 
				
			||||||
 | 
					            return ;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    print_trapframe(tf);
 | 
				
			||||||
 | 
					    panic("undefined syscall %d, pid = %d, name = %s.\n",
 | 
				
			||||||
 | 
					            num, current->pid, current->name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_SYSCALL_SYSCALL_H__
 | 
				
			||||||
 | 
					#define __KERN_SYSCALL_SYSCALL_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void syscall(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_SYSCALL_SYSCALL_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										300
									
								
								related_info/lab5/lab5-spoc-discuss/kern/trap/trap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								related_info/lab5/lab5-spoc-discuss/kern/trap/trap.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,300 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <mmu.h>
 | 
				
			||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					#include <clock.h>
 | 
				
			||||||
 | 
					#include <trap.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <console.h>
 | 
				
			||||||
 | 
					#include <vmm.h>
 | 
				
			||||||
 | 
					#include <swap.h>
 | 
				
			||||||
 | 
					#include <kdebug.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <syscall.h>
 | 
				
			||||||
 | 
					#include <error.h>
 | 
				
			||||||
 | 
					#include <sched.h>
 | 
				
			||||||
 | 
					#include <sync.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TICK_NUM 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_ticks() {
 | 
				
			||||||
 | 
					    cprintf("%d ticks\n",TICK_NUM);
 | 
				
			||||||
 | 
					#ifdef DEBUG_GRADE
 | 
				
			||||||
 | 
					    cprintf("End of Test.\n");
 | 
				
			||||||
 | 
					    panic("EOT: kernel seems ok.");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Interrupt descriptor table:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Must be built at run time because shifted function addresses can't
 | 
				
			||||||
 | 
					 * be represented in relocation records.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static struct gatedesc idt[256] = {{0}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pseudodesc idt_pd = {
 | 
				
			||||||
 | 
					    sizeof(idt) - 1, (uintptr_t)idt
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* idt_init - initialize IDT to each of the entry points in kern/trap/vectors.S */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					idt_init(void) {
 | 
				
			||||||
 | 
					     /* LAB1 YOUR CODE : STEP 2 */
 | 
				
			||||||
 | 
					     /* (1) Where are the entry addrs of each Interrupt Service Routine (ISR)?
 | 
				
			||||||
 | 
					      *     All ISR's entry addrs are stored in __vectors. where is uintptr_t __vectors[] ?
 | 
				
			||||||
 | 
					      *     __vectors[] is in kern/trap/vector.S which is produced by tools/vector.c
 | 
				
			||||||
 | 
					      *     (try "make" command in lab1, then you will find vector.S in kern/trap DIR)
 | 
				
			||||||
 | 
					      *     You can use  "extern uintptr_t __vectors[];" to define this extern variable which will be used later.
 | 
				
			||||||
 | 
					      * (2) Now you should setup the entries of ISR in Interrupt Description Table (IDT).
 | 
				
			||||||
 | 
					      *     Can you see idt[256] in this file? Yes, it's IDT! you can use SETGATE macro to setup each item of IDT
 | 
				
			||||||
 | 
					      * (3) After setup the contents of IDT, you will let CPU know where is the IDT by using 'lidt' instruction.
 | 
				
			||||||
 | 
					      *     You don't know the meaning of this instruction? just google it! and check the libs/x86.h to know more.
 | 
				
			||||||
 | 
					      *     Notice: the argument of lidt is idt_pd. try to find it!
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					     /* LAB5 YOUR CODE */ 
 | 
				
			||||||
 | 
					     //you should update your lab1 code (just add ONE or TWO lines of code), let user app to use syscall to get the service of ucore
 | 
				
			||||||
 | 
					     //so you should setup the syscall interrupt gate in here
 | 
				
			||||||
 | 
					    extern uintptr_t __vectors[];
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) {
 | 
				
			||||||
 | 
					        SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER);
 | 
				
			||||||
 | 
					    lidt(&idt_pd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *
 | 
				
			||||||
 | 
					trapname(int trapno) {
 | 
				
			||||||
 | 
					    static const char * const excnames[] = {
 | 
				
			||||||
 | 
					        "Divide error",
 | 
				
			||||||
 | 
					        "Debug",
 | 
				
			||||||
 | 
					        "Non-Maskable Interrupt",
 | 
				
			||||||
 | 
					        "Breakpoint",
 | 
				
			||||||
 | 
					        "Overflow",
 | 
				
			||||||
 | 
					        "BOUND Range Exceeded",
 | 
				
			||||||
 | 
					        "Invalid Opcode",
 | 
				
			||||||
 | 
					        "Device Not Available",
 | 
				
			||||||
 | 
					        "Double Fault",
 | 
				
			||||||
 | 
					        "Coprocessor Segment Overrun",
 | 
				
			||||||
 | 
					        "Invalid TSS",
 | 
				
			||||||
 | 
					        "Segment Not Present",
 | 
				
			||||||
 | 
					        "Stack Fault",
 | 
				
			||||||
 | 
					        "General Protection",
 | 
				
			||||||
 | 
					        "Page Fault",
 | 
				
			||||||
 | 
					        "(unknown trap)",
 | 
				
			||||||
 | 
					        "x87 FPU Floating-Point Error",
 | 
				
			||||||
 | 
					        "Alignment Check",
 | 
				
			||||||
 | 
					        "Machine-Check",
 | 
				
			||||||
 | 
					        "SIMD Floating-Point Exception"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (trapno < sizeof(excnames)/sizeof(const char * const)) {
 | 
				
			||||||
 | 
					        return excnames[trapno];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (trapno >= IRQ_OFFSET && trapno < IRQ_OFFSET + 16) {
 | 
				
			||||||
 | 
					        return "Hardware Interrupt";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return "(unknown trap)";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* trap_in_kernel - test if trap happened in kernel */
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					trap_in_kernel(struct trapframe *tf) {
 | 
				
			||||||
 | 
					    return (tf->tf_cs == (uint16_t)KERNEL_CS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *IA32flags[] = {
 | 
				
			||||||
 | 
					    "CF", NULL, "PF", NULL, "AF", NULL, "ZF", "SF",
 | 
				
			||||||
 | 
					    "TF", "IF", "DF", "OF", NULL, NULL, "NT", NULL,
 | 
				
			||||||
 | 
					    "RF", "VM", "AC", "VIF", "VIP", "ID", NULL, NULL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					print_trapframe(struct trapframe *tf) {
 | 
				
			||||||
 | 
					    cprintf("trapframe at %p\n", tf);
 | 
				
			||||||
 | 
					    print_regs(&tf->tf_regs);
 | 
				
			||||||
 | 
					    cprintf("  ds   0x----%04x\n", tf->tf_ds);
 | 
				
			||||||
 | 
					    cprintf("  es   0x----%04x\n", tf->tf_es);
 | 
				
			||||||
 | 
					    cprintf("  fs   0x----%04x\n", tf->tf_fs);
 | 
				
			||||||
 | 
					    cprintf("  gs   0x----%04x\n", tf->tf_gs);
 | 
				
			||||||
 | 
					    cprintf("  trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
 | 
				
			||||||
 | 
					    cprintf("  err  0x%08x\n", tf->tf_err);
 | 
				
			||||||
 | 
					    cprintf("  eip  0x%08x\n", tf->tf_eip);
 | 
				
			||||||
 | 
					    cprintf("  cs   0x----%04x\n", tf->tf_cs);
 | 
				
			||||||
 | 
					    cprintf("  flag 0x%08x ", tf->tf_eflags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int i, j;
 | 
				
			||||||
 | 
					    for (i = 0, j = 1; i < sizeof(IA32flags) / sizeof(IA32flags[0]); i ++, j <<= 1) {
 | 
				
			||||||
 | 
					        if ((tf->tf_eflags & j) && IA32flags[i] != NULL) {
 | 
				
			||||||
 | 
					            cprintf("%s,", IA32flags[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cprintf("IOPL=%d\n", (tf->tf_eflags & FL_IOPL_MASK) >> 12);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!trap_in_kernel(tf)) {
 | 
				
			||||||
 | 
					        cprintf("  esp  0x%08x\n", tf->tf_esp);
 | 
				
			||||||
 | 
					        cprintf("  ss   0x----%04x\n", tf->tf_ss);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					print_regs(struct pushregs *regs) {
 | 
				
			||||||
 | 
					    cprintf("  edi  0x%08x\n", regs->reg_edi);
 | 
				
			||||||
 | 
					    cprintf("  esi  0x%08x\n", regs->reg_esi);
 | 
				
			||||||
 | 
					    cprintf("  ebp  0x%08x\n", regs->reg_ebp);
 | 
				
			||||||
 | 
					    cprintf("  oesp 0x%08x\n", regs->reg_oesp);
 | 
				
			||||||
 | 
					    cprintf("  ebx  0x%08x\n", regs->reg_ebx);
 | 
				
			||||||
 | 
					    cprintf("  edx  0x%08x\n", regs->reg_edx);
 | 
				
			||||||
 | 
					    cprintf("  ecx  0x%08x\n", regs->reg_ecx);
 | 
				
			||||||
 | 
					    cprintf("  eax  0x%08x\n", regs->reg_eax);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					print_pgfault(struct trapframe *tf) {
 | 
				
			||||||
 | 
					    /* error_code:
 | 
				
			||||||
 | 
					     * bit 0 == 0 means no page found, 1 means protection fault
 | 
				
			||||||
 | 
					     * bit 1 == 0 means read, 1 means write
 | 
				
			||||||
 | 
					     * bit 2 == 0 means kernel, 1 means user
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    cprintf("page fault at 0x%08x: %c/%c [%s].\n", rcr2(),
 | 
				
			||||||
 | 
					            (tf->tf_err & 4) ? 'U' : 'K',
 | 
				
			||||||
 | 
					            (tf->tf_err & 2) ? 'W' : 'R',
 | 
				
			||||||
 | 
					            (tf->tf_err & 1) ? "protection fault" : "no page found");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					pgfault_handler(struct trapframe *tf) {
 | 
				
			||||||
 | 
					    extern struct mm_struct *check_mm_struct;
 | 
				
			||||||
 | 
					    if(check_mm_struct !=NULL) { //used for test check_swap
 | 
				
			||||||
 | 
					            print_pgfault(tf);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    struct mm_struct *mm;
 | 
				
			||||||
 | 
					    if (check_mm_struct != NULL) {
 | 
				
			||||||
 | 
					        assert(current == idleproc);
 | 
				
			||||||
 | 
					        mm = check_mm_struct;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        if (current == NULL) {
 | 
				
			||||||
 | 
					            print_trapframe(tf);
 | 
				
			||||||
 | 
					            print_pgfault(tf);
 | 
				
			||||||
 | 
					            panic("unhandled page fault.\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        mm = current->mm;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return do_pgfault(mm, tf->tf_err, rcr2());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static volatile int in_swap_tick_event = 0;
 | 
				
			||||||
 | 
					extern struct mm_struct *check_mm_struct;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					trap_dispatch(struct trapframe *tf) {
 | 
				
			||||||
 | 
					    char c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (tf->tf_trapno) {
 | 
				
			||||||
 | 
					    case T_PGFLT:  //page fault
 | 
				
			||||||
 | 
					        if ((ret = pgfault_handler(tf)) != 0) {
 | 
				
			||||||
 | 
					            print_trapframe(tf);
 | 
				
			||||||
 | 
					            if (current == NULL) {
 | 
				
			||||||
 | 
					                panic("handle pgfault failed. ret=%d\n", ret);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                if (trap_in_kernel(tf)) {
 | 
				
			||||||
 | 
					                    panic("handle pgfault failed in kernel mode. ret=%d\n", ret);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                cprintf("killed by kernel.\n");
 | 
				
			||||||
 | 
					                panic("handle user mode pgfault failed. ret=%d\n", ret); 
 | 
				
			||||||
 | 
					                do_exit(-E_KILLED);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case T_SYSCALL:
 | 
				
			||||||
 | 
					        syscall();
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case IRQ_OFFSET + IRQ_TIMER:
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    LAB3 : If some page replacement algorithm(such as CLOCK PRA) need tick to change the priority of pages, 
 | 
				
			||||||
 | 
					    then you can add code here. 
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        /* LAB1 YOUR CODE : STEP 3 */
 | 
				
			||||||
 | 
					        /* handle the timer interrupt */
 | 
				
			||||||
 | 
					        /* (1) After a timer interrupt, you should record this event using a global variable (increase it), such as ticks in kern/driver/clock.c
 | 
				
			||||||
 | 
					         * (2) Every TICK_NUM cycle, you can print some info using a funciton, such as print_ticks().
 | 
				
			||||||
 | 
					         * (3) Too Simple? Yes, I think so!
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        /* LAB5 YOUR CODE */
 | 
				
			||||||
 | 
					        /* you should upate you lab1 code (just add ONE or TWO lines of code):
 | 
				
			||||||
 | 
					         *    Every TICK_NUM cycle, you should set current process's current->need_resched = 1
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        ticks ++;
 | 
				
			||||||
 | 
					        if (ticks % TICK_NUM == 0) {
 | 
				
			||||||
 | 
					            assert(current != NULL);
 | 
				
			||||||
 | 
					            current->need_resched = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case IRQ_OFFSET + IRQ_COM1:
 | 
				
			||||||
 | 
					        c = cons_getc();
 | 
				
			||||||
 | 
					        cprintf("serial [%03d] %c\n", c, c);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case IRQ_OFFSET + IRQ_KBD:
 | 
				
			||||||
 | 
					        c = cons_getc();
 | 
				
			||||||
 | 
					        cprintf("kbd [%03d] %c\n", c, c);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    //LAB1 CHALLENGE 1 : YOUR CODE you should modify below codes.
 | 
				
			||||||
 | 
					    case T_SWITCH_TOU:
 | 
				
			||||||
 | 
					    case T_SWITCH_TOK:
 | 
				
			||||||
 | 
					        panic("T_SWITCH_** ??\n");
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case IRQ_OFFSET + IRQ_IDE1:
 | 
				
			||||||
 | 
					    case IRQ_OFFSET + IRQ_IDE2:
 | 
				
			||||||
 | 
					        /* do nothing */
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        print_trapframe(tf);
 | 
				
			||||||
 | 
					        if (current != NULL) {
 | 
				
			||||||
 | 
					            cprintf("unhandled trap.\n");
 | 
				
			||||||
 | 
					            do_exit(-E_KILLED);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // in kernel, it must be a mistake
 | 
				
			||||||
 | 
					        panic("unexpected trap in kernel.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * trap - handles or dispatches an exception/interrupt. if and when trap() returns,
 | 
				
			||||||
 | 
					 * the code in kern/trap/trapentry.S restores the old CPU state saved in the
 | 
				
			||||||
 | 
					 * trapframe and then uses the iret instruction to return from the exception.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					trap(struct trapframe *tf) {
 | 
				
			||||||
 | 
					    // dispatch based on what type of trap occurred
 | 
				
			||||||
 | 
					    // used for previous projects
 | 
				
			||||||
 | 
					    if (current == NULL) {
 | 
				
			||||||
 | 
					        trap_dispatch(tf);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        // keep a trapframe chain in stack
 | 
				
			||||||
 | 
					        struct trapframe *otf = current->tf;
 | 
				
			||||||
 | 
					        current->tf = tf;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        bool in_kernel = trap_in_kernel(tf);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        trap_dispatch(tf);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        current->tf = otf;
 | 
				
			||||||
 | 
					        if (!in_kernel) {
 | 
				
			||||||
 | 
					            if (current->flags & PF_EXITING) {
 | 
				
			||||||
 | 
					                do_exit(-E_KILLED);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (current->need_resched) {
 | 
				
			||||||
 | 
					                schedule();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										89
									
								
								related_info/lab5/lab5-spoc-discuss/kern/trap/trap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								related_info/lab5/lab5-spoc-discuss/kern/trap/trap.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					#ifndef __KERN_TRAP_TRAP_H__
 | 
				
			||||||
 | 
					#define __KERN_TRAP_TRAP_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Trap Numbers */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Processor-defined: */
 | 
				
			||||||
 | 
					#define T_DIVIDE                0   // divide error
 | 
				
			||||||
 | 
					#define T_DEBUG                 1   // debug exception
 | 
				
			||||||
 | 
					#define T_NMI                   2   // non-maskable interrupt
 | 
				
			||||||
 | 
					#define T_BRKPT                 3   // breakpoint
 | 
				
			||||||
 | 
					#define T_OFLOW                 4   // overflow
 | 
				
			||||||
 | 
					#define T_BOUND                 5   // bounds check
 | 
				
			||||||
 | 
					#define T_ILLOP                 6   // illegal opcode
 | 
				
			||||||
 | 
					#define T_DEVICE                7   // device not available
 | 
				
			||||||
 | 
					#define T_DBLFLT                8   // double fault
 | 
				
			||||||
 | 
					// #define T_COPROC             9   // reserved (not used since 486)
 | 
				
			||||||
 | 
					#define T_TSS                   10  // invalid task switch segment
 | 
				
			||||||
 | 
					#define T_SEGNP                 11  // segment not present
 | 
				
			||||||
 | 
					#define T_STACK                 12  // stack exception
 | 
				
			||||||
 | 
					#define T_GPFLT                 13  // general protection fault
 | 
				
			||||||
 | 
					#define T_PGFLT                 14  // page fault
 | 
				
			||||||
 | 
					// #define T_RES                15  // reserved
 | 
				
			||||||
 | 
					#define T_FPERR                 16  // floating point error
 | 
				
			||||||
 | 
					#define T_ALIGN                 17  // aligment check
 | 
				
			||||||
 | 
					#define T_MCHK                  18  // machine check
 | 
				
			||||||
 | 
					#define T_SIMDERR               19  // SIMD floating point error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Hardware IRQ numbers. We receive these as (IRQ_OFFSET + IRQ_xx) */
 | 
				
			||||||
 | 
					#define IRQ_OFFSET              32  // IRQ 0 corresponds to int IRQ_OFFSET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IRQ_TIMER               0
 | 
				
			||||||
 | 
					#define IRQ_KBD                 1
 | 
				
			||||||
 | 
					#define IRQ_COM1                4
 | 
				
			||||||
 | 
					#define IRQ_IDE1                14
 | 
				
			||||||
 | 
					#define IRQ_IDE2                15
 | 
				
			||||||
 | 
					#define IRQ_ERROR               19
 | 
				
			||||||
 | 
					#define IRQ_SPURIOUS            31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * These are arbitrarily chosen, but with care not to overlap
 | 
				
			||||||
 | 
					 * processor defined exceptions or interrupt vectors.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					#define T_SWITCH_TOU                120    // user/kernel switch
 | 
				
			||||||
 | 
					#define T_SWITCH_TOK                121    // user/kernel switch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* registers as pushed by pushal */
 | 
				
			||||||
 | 
					struct pushregs {
 | 
				
			||||||
 | 
					    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_gs;
 | 
				
			||||||
 | 
					    uint16_t tf_padding0;
 | 
				
			||||||
 | 
					    uint16_t tf_fs;
 | 
				
			||||||
 | 
					    uint16_t tf_padding1;
 | 
				
			||||||
 | 
					    uint16_t tf_es;
 | 
				
			||||||
 | 
					    uint16_t tf_padding2;
 | 
				
			||||||
 | 
					    uint16_t tf_ds;
 | 
				
			||||||
 | 
					    uint16_t tf_padding3;
 | 
				
			||||||
 | 
					    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_padding4;
 | 
				
			||||||
 | 
					    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_padding5;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void idt_init(void);
 | 
				
			||||||
 | 
					void print_trapframe(struct trapframe *tf);
 | 
				
			||||||
 | 
					void print_regs(struct pushregs *regs);
 | 
				
			||||||
 | 
					bool trap_in_kernel(struct trapframe *tf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__KERN_TRAP_TRAP_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										49
									
								
								related_info/lab5/lab5-spoc-discuss/kern/trap/trapentry.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								related_info/lab5/lab5-spoc-discuss/kern/trap/trapentry.S
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					#include <memlayout.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# vectors.S sends all traps here.
 | 
				
			||||||
 | 
					.text
 | 
				
			||||||
 | 
					.globl __alltraps
 | 
				
			||||||
 | 
					__alltraps:
 | 
				
			||||||
 | 
					    # push registers to build a trap frame
 | 
				
			||||||
 | 
					    # therefore make the stack look like a struct trapframe
 | 
				
			||||||
 | 
					    pushl %ds
 | 
				
			||||||
 | 
					    pushl %es
 | 
				
			||||||
 | 
					    pushl %fs
 | 
				
			||||||
 | 
					    pushl %gs
 | 
				
			||||||
 | 
					    pushal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # load GD_KDATA into %ds and %es to set up data segments for kernel
 | 
				
			||||||
 | 
					    movl $GD_KDATA, %eax
 | 
				
			||||||
 | 
					    movw %ax, %ds
 | 
				
			||||||
 | 
					    movw %ax, %es
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # push %esp to pass a pointer to the trapframe as an argument to trap()
 | 
				
			||||||
 | 
					    pushl %esp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # call trap(tf), where tf=%esp
 | 
				
			||||||
 | 
					    call trap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # pop the pushed stack pointer
 | 
				
			||||||
 | 
					    popl %esp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # return falls through to trapret...
 | 
				
			||||||
 | 
					.globl __trapret
 | 
				
			||||||
 | 
					__trapret:
 | 
				
			||||||
 | 
					    # restore registers from stack
 | 
				
			||||||
 | 
					    popal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # restore %ds, %es, %fs and %gs
 | 
				
			||||||
 | 
					    popl %gs
 | 
				
			||||||
 | 
					    popl %fs
 | 
				
			||||||
 | 
					    popl %es
 | 
				
			||||||
 | 
					    popl %ds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # get rid of the trap number and error code
 | 
				
			||||||
 | 
					    addl $0x8, %esp
 | 
				
			||||||
 | 
					    iret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.globl forkrets
 | 
				
			||||||
 | 
					forkrets:
 | 
				
			||||||
 | 
					    # set stack to this new process's trapframe
 | 
				
			||||||
 | 
					    movl 4(%esp), %esp
 | 
				
			||||||
 | 
					    jmp __trapret
 | 
				
			||||||
							
								
								
									
										1536
									
								
								related_info/lab5/lab5-spoc-discuss/kern/trap/vectors.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1536
									
								
								related_info/lab5/lab5-spoc-discuss/kern/trap/vectors.S
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										81
									
								
								related_info/lab5/lab5-spoc-discuss/libs/atomic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								related_info/lab5/lab5-spoc-discuss/libs/atomic.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_ATOMIC_H__
 | 
				
			||||||
 | 
					#define __LIBS_ATOMIC_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Atomic operations that C can't guarantee us. Useful for resource counting etc.. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void set_bit(int nr, volatile void *addr) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void clear_bit(int nr, volatile void *addr) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void change_bit(int nr, volatile void *addr) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline bool test_bit(int nr, volatile void *addr) __attribute__((always_inline));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * set_bit - Atomically set a bit in memory
 | 
				
			||||||
 | 
					 * @nr:     the bit to set
 | 
				
			||||||
 | 
					 * @addr:   the address to start counting from
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that @nr may be almost arbitrarily large; this function is not
 | 
				
			||||||
 | 
					 * restricted to acting on a single-word quantity.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					set_bit(int nr, volatile void *addr) {
 | 
				
			||||||
 | 
					    asm volatile ("btsl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * clear_bit - Atomically clears a bit in memory
 | 
				
			||||||
 | 
					 * @nr:     the bit to clear
 | 
				
			||||||
 | 
					 * @addr:   the address to start counting from
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					clear_bit(int nr, volatile void *addr) {
 | 
				
			||||||
 | 
					    asm volatile ("btrl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * change_bit - Atomically toggle a bit in memory
 | 
				
			||||||
 | 
					 * @nr:     the bit to change
 | 
				
			||||||
 | 
					 * @addr:   the address to start counting from
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					change_bit(int nr, volatile void *addr) {
 | 
				
			||||||
 | 
					    asm volatile ("btcl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * test_bit - Determine whether a bit is set
 | 
				
			||||||
 | 
					 * @nr:     the bit to test
 | 
				
			||||||
 | 
					 * @addr:   the address to count from
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					test_bit(int nr, volatile void *addr) {
 | 
				
			||||||
 | 
					    int oldbit;
 | 
				
			||||||
 | 
					    asm volatile ("btl %2, %1; sbbl %0,%0" : "=r" (oldbit) : "m" (*(volatile long *)addr), "Ir" (nr));
 | 
				
			||||||
 | 
					    return oldbit != 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * test_and_set_bit - Atomically set a bit and return its old value
 | 
				
			||||||
 | 
					 * @nr:     the bit to set
 | 
				
			||||||
 | 
					 * @addr:   the address to count from
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					test_and_set_bit(int nr, volatile void *addr) {
 | 
				
			||||||
 | 
					    int oldbit;
 | 
				
			||||||
 | 
					    asm volatile ("btsl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory");
 | 
				
			||||||
 | 
					    return oldbit != 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * test_and_clear_bit - Atomically clear a bit and return its old value
 | 
				
			||||||
 | 
					 * @nr:     the bit to clear
 | 
				
			||||||
 | 
					 * @addr:   the address to count from
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					test_and_clear_bit(int nr, volatile void *addr) {
 | 
				
			||||||
 | 
					    int oldbit;
 | 
				
			||||||
 | 
					    asm volatile ("btrl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory");
 | 
				
			||||||
 | 
					    return oldbit != 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_ATOMIC_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										68
									
								
								related_info/lab5/lab5-spoc-discuss/libs/defs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								related_info/lab5/lab5-spoc-discuss/libs/defs.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_DEFS_H__
 | 
				
			||||||
 | 
					#define __LIBS_DEFS_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef NULL
 | 
				
			||||||
 | 
					#define NULL ((void *)0)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __always_inline inline __attribute__((always_inline))
 | 
				
			||||||
 | 
					#define __noinline __attribute__((noinline))
 | 
				
			||||||
 | 
					#define __noreturn __attribute__((noreturn))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Represents true-or-false values */
 | 
				
			||||||
 | 
					typedef int bool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Explicitly-sized versions of integer types */
 | 
				
			||||||
 | 
					typedef char int8_t;
 | 
				
			||||||
 | 
					typedef unsigned char uint8_t;
 | 
				
			||||||
 | 
					typedef short int16_t;
 | 
				
			||||||
 | 
					typedef unsigned short uint16_t;
 | 
				
			||||||
 | 
					typedef int int32_t;
 | 
				
			||||||
 | 
					typedef unsigned int uint32_t;
 | 
				
			||||||
 | 
					typedef long long int64_t;
 | 
				
			||||||
 | 
					typedef unsigned long long uint64_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Pointers and addresses are 32 bits long.
 | 
				
			||||||
 | 
					 * We use pointer types to represent addresses,
 | 
				
			||||||
 | 
					 * uintptr_t to represent the numerical values of addresses.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					typedef int32_t intptr_t;
 | 
				
			||||||
 | 
					typedef uint32_t uintptr_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* size_t is used for memory object sizes */
 | 
				
			||||||
 | 
					typedef uintptr_t size_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* used for page numbers */
 | 
				
			||||||
 | 
					typedef size_t ppn_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Rounding operations (efficient when n is a power of 2)
 | 
				
			||||||
 | 
					 * Round down to the nearest multiple of n
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					#define ROUNDDOWN(a, n) ({                                          \
 | 
				
			||||||
 | 
					            size_t __a = (size_t)(a);                               \
 | 
				
			||||||
 | 
					            (typeof(a))(__a - __a % (n));                           \
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Round up to the nearest multiple of n */
 | 
				
			||||||
 | 
					#define ROUNDUP(a, n) ({                                            \
 | 
				
			||||||
 | 
					            size_t __n = (size_t)(n);                               \
 | 
				
			||||||
 | 
					            (typeof(a))(ROUNDDOWN((size_t)(a) + __n - 1, __n));     \
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return the offset of 'member' relative to the beginning of a struct type */
 | 
				
			||||||
 | 
					#define offsetof(type, member)                                      \
 | 
				
			||||||
 | 
					    ((size_t)(&((type *)0)->member))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * to_struct - get the struct from a ptr
 | 
				
			||||||
 | 
					 * @ptr:    a struct pointer of member
 | 
				
			||||||
 | 
					 * @type:   the type of the struct this is embedded in
 | 
				
			||||||
 | 
					 * @member: the name of the member within the struct
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					#define to_struct(ptr, type, member)                               \
 | 
				
			||||||
 | 
					    ((type *)((char *)(ptr) - offsetof(type, member)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_DEFS_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										48
									
								
								related_info/lab5/lab5-spoc-discuss/libs/elf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								related_info/lab5/lab5-spoc-discuss/libs/elf.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_ELF_H__
 | 
				
			||||||
 | 
					#define __LIBS_ELF_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ELF_MAGIC   0x464C457FU         // "\x7FELF" in little endian
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* file header */
 | 
				
			||||||
 | 
					struct elfhdr {
 | 
				
			||||||
 | 
					    uint32_t e_magic;     // must equal ELF_MAGIC
 | 
				
			||||||
 | 
					    uint8_t e_elf[12];
 | 
				
			||||||
 | 
					    uint16_t e_type;      // 1=relocatable, 2=executable, 3=shared object, 4=core image
 | 
				
			||||||
 | 
					    uint16_t e_machine;   // 3=x86, 4=68K, etc.
 | 
				
			||||||
 | 
					    uint32_t e_version;   // file version, always 1
 | 
				
			||||||
 | 
					    uint32_t e_entry;     // entry point if executable
 | 
				
			||||||
 | 
					    uint32_t e_phoff;     // file position of program header or 0
 | 
				
			||||||
 | 
					    uint32_t e_shoff;     // file position of section header or 0
 | 
				
			||||||
 | 
					    uint32_t e_flags;     // architecture-specific flags, usually 0
 | 
				
			||||||
 | 
					    uint16_t e_ehsize;    // size of this elf header
 | 
				
			||||||
 | 
					    uint16_t e_phentsize; // size of an entry in program header
 | 
				
			||||||
 | 
					    uint16_t e_phnum;     // number of entries in program header or 0
 | 
				
			||||||
 | 
					    uint16_t e_shentsize; // size of an entry in section header
 | 
				
			||||||
 | 
					    uint16_t e_shnum;     // number of entries in section header or 0
 | 
				
			||||||
 | 
					    uint16_t e_shstrndx;  // section number that contains section name strings
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* program section header */
 | 
				
			||||||
 | 
					struct proghdr {
 | 
				
			||||||
 | 
					    uint32_t p_type;   // loadable code or data, dynamic linking info,etc.
 | 
				
			||||||
 | 
					    uint32_t p_offset; // file offset of segment
 | 
				
			||||||
 | 
					    uint32_t p_va;     // virtual address to map segment
 | 
				
			||||||
 | 
					    uint32_t p_pa;     // physical address, not used
 | 
				
			||||||
 | 
					    uint32_t p_filesz; // size of segment in file
 | 
				
			||||||
 | 
					    uint32_t p_memsz;  // size of segment in memory (bigger if contains bss)
 | 
				
			||||||
 | 
					    uint32_t p_flags;  // read/write/execute bits
 | 
				
			||||||
 | 
					    uint32_t p_align;  // required alignment, invariably hardware page size
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* values for Proghdr::p_type */
 | 
				
			||||||
 | 
					#define ELF_PT_LOAD                     1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* flag bits for Proghdr::p_flags */
 | 
				
			||||||
 | 
					#define ELF_PF_X                        1
 | 
				
			||||||
 | 
					#define ELF_PF_W                        2
 | 
				
			||||||
 | 
					#define ELF_PF_R                        4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_ELF_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										33
									
								
								related_info/lab5/lab5-spoc-discuss/libs/error.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								related_info/lab5/lab5-spoc-discuss/libs/error.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_ERROR_H__
 | 
				
			||||||
 | 
					#define __LIBS_ERROR_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* kernel error codes -- keep in sync with list in lib/printfmt.c */
 | 
				
			||||||
 | 
					#define E_UNSPECIFIED       1   // Unspecified or unknown problem
 | 
				
			||||||
 | 
					#define E_BAD_PROC          2   // Process doesn't exist or otherwise
 | 
				
			||||||
 | 
					#define E_INVAL             3   // Invalid parameter
 | 
				
			||||||
 | 
					#define E_NO_MEM            4   // Request failed due to memory shortage
 | 
				
			||||||
 | 
					#define E_NO_FREE_PROC      5   // Attempt to create a new process beyond
 | 
				
			||||||
 | 
					#define E_FAULT             6   // Memory fault
 | 
				
			||||||
 | 
					#define E_SWAP_FAULT        7   // SWAP READ/WRITE fault
 | 
				
			||||||
 | 
					#define E_INVAL_ELF         8   // Invalid elf file
 | 
				
			||||||
 | 
					#define E_KILLED            9   // Process is killed
 | 
				
			||||||
 | 
					#define E_PANIC             10  // Panic Failure
 | 
				
			||||||
 | 
					#define E_TIMEOUT           11  // Timeout
 | 
				
			||||||
 | 
					#define E_TOO_BIG           12  // Argument is Too Big
 | 
				
			||||||
 | 
					#define E_NO_DEV            13  // No such Device
 | 
				
			||||||
 | 
					#define E_NA_DEV            14  // Device Not Available
 | 
				
			||||||
 | 
					#define E_BUSY              15  // Device/File is Busy
 | 
				
			||||||
 | 
					#define E_NOENT             16  // No Such File or Directory
 | 
				
			||||||
 | 
					#define E_ISDIR             17  // Is a Directory
 | 
				
			||||||
 | 
					#define E_NOTDIR            18  // Not a Directory
 | 
				
			||||||
 | 
					#define E_XDEV              19  // Cross Device-Link
 | 
				
			||||||
 | 
					#define E_UNIMP             20  // Unimplemented Feature
 | 
				
			||||||
 | 
					#define E_SEEK              21  // Illegal Seek
 | 
				
			||||||
 | 
					#define E_MAX_OPEN          22  // Too Many Files are Open
 | 
				
			||||||
 | 
					#define E_EXISTS            23  // File/Directory Already Exists
 | 
				
			||||||
 | 
					#define E_NOTEMPTY          24  // Directory is Not Empty
 | 
				
			||||||
 | 
					/* the maximum allowed */
 | 
				
			||||||
 | 
					#define MAXERROR            24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_ERROR_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								related_info/lab5/lab5-spoc-discuss/libs/hash.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								related_info/lab5/lab5-spoc-discuss/libs/hash.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
 | 
				
			||||||
 | 
					#define GOLDEN_RATIO_PRIME_32       0x9e370001UL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * hash32 - generate a hash value in the range [0, 2^@bits - 1]
 | 
				
			||||||
 | 
					 * @val:    the input value
 | 
				
			||||||
 | 
					 * @bits:   the number of bits in a return value
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * High bits are more random, so we use them.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					uint32_t
 | 
				
			||||||
 | 
					hash32(uint32_t val, unsigned int bits) {
 | 
				
			||||||
 | 
					    uint32_t hash = val * GOLDEN_RATIO_PRIME_32;
 | 
				
			||||||
 | 
					    return (hash >> (32 - bits));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										163
									
								
								related_info/lab5/lab5-spoc-discuss/libs/list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								related_info/lab5/lab5-spoc-discuss/libs/list.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_LIST_H__
 | 
				
			||||||
 | 
					#define __LIBS_LIST_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __ASSEMBLER__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Simple doubly linked list implementation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Some of the internal functions ("__xxx") are useful when manipulating
 | 
				
			||||||
 | 
					 * whole lists rather than single entries, as sometimes we already know
 | 
				
			||||||
 | 
					 * the next/prev entries and we can generate better code by using them
 | 
				
			||||||
 | 
					 * directly rather than using the generic single-entry routines.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct list_entry {
 | 
				
			||||||
 | 
					    struct list_entry *prev, *next;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct list_entry list_entry_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void list_init(list_entry_t *elm) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void list_add(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void list_add_before(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void list_add_after(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void list_del(list_entry_t *listelm) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void list_del_init(list_entry_t *listelm) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline bool list_empty(list_entry_t *list) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline list_entry_t *list_next(list_entry_t *listelm) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline list_entry_t *list_prev(list_entry_t *listelm) __attribute__((always_inline));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void __list_add(list_entry_t *elm, list_entry_t *prev, list_entry_t *next) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void __list_del(list_entry_t *prev, list_entry_t *next) __attribute__((always_inline));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_init - initialize a new entry
 | 
				
			||||||
 | 
					 * @elm:        new entry to be initialized
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					list_init(list_entry_t *elm) {
 | 
				
			||||||
 | 
					    elm->prev = elm->next = elm;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_add - add a new entry
 | 
				
			||||||
 | 
					 * @listelm:    list head to add after
 | 
				
			||||||
 | 
					 * @elm:        new entry to be added
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Insert the new element @elm *after* the element @listelm which
 | 
				
			||||||
 | 
					 * is already in the list.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					list_add(list_entry_t *listelm, list_entry_t *elm) {
 | 
				
			||||||
 | 
					    list_add_after(listelm, elm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_add_before - add a new entry
 | 
				
			||||||
 | 
					 * @listelm:    list head to add before
 | 
				
			||||||
 | 
					 * @elm:        new entry to be added
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Insert the new element @elm *before* the element @listelm which
 | 
				
			||||||
 | 
					 * is already in the list.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					list_add_before(list_entry_t *listelm, list_entry_t *elm) {
 | 
				
			||||||
 | 
					    __list_add(elm, listelm->prev, listelm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_add_after - add a new entry
 | 
				
			||||||
 | 
					 * @listelm:    list head to add after
 | 
				
			||||||
 | 
					 * @elm:        new entry to be added
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Insert the new element @elm *after* the element @listelm which
 | 
				
			||||||
 | 
					 * is already in the list.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					list_add_after(list_entry_t *listelm, list_entry_t *elm) {
 | 
				
			||||||
 | 
					    __list_add(elm, listelm, listelm->next);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_del - deletes entry from list
 | 
				
			||||||
 | 
					 * @listelm:    the element to delete from the list
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: list_empty() on @listelm does not return true after this, the entry is
 | 
				
			||||||
 | 
					 * in an undefined state.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					list_del(list_entry_t *listelm) {
 | 
				
			||||||
 | 
					    __list_del(listelm->prev, listelm->next);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_del_init - deletes entry from list and reinitialize it.
 | 
				
			||||||
 | 
					 * @listelm:    the element to delete from the list.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: list_empty() on @listelm returns true after this.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					list_del_init(list_entry_t *listelm) {
 | 
				
			||||||
 | 
					    list_del(listelm);
 | 
				
			||||||
 | 
					    list_init(listelm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_empty - tests whether a list is empty
 | 
				
			||||||
 | 
					 * @list:       the list to test.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					list_empty(list_entry_t *list) {
 | 
				
			||||||
 | 
					    return list->next == list;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_next - get the next entry
 | 
				
			||||||
 | 
					 * @listelm:    the list head
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					static inline list_entry_t *
 | 
				
			||||||
 | 
					list_next(list_entry_t *listelm) {
 | 
				
			||||||
 | 
					    return listelm->next;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * list_prev - get the previous entry
 | 
				
			||||||
 | 
					 * @listelm:    the list head
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					static inline list_entry_t *
 | 
				
			||||||
 | 
					list_prev(list_entry_t *listelm) {
 | 
				
			||||||
 | 
					    return listelm->prev;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Insert a new entry between two known consecutive entries.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is only for internal list manipulation where we know
 | 
				
			||||||
 | 
					 * the prev/next entries already!
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					__list_add(list_entry_t *elm, list_entry_t *prev, list_entry_t *next) {
 | 
				
			||||||
 | 
					    prev->next = next->prev = elm;
 | 
				
			||||||
 | 
					    elm->next = next;
 | 
				
			||||||
 | 
					    elm->prev = prev;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Delete a list entry by making the prev/next entries point to each other.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is only for internal list manipulation where we know
 | 
				
			||||||
 | 
					 * the prev/next entries already!
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					__list_del(list_entry_t *prev, list_entry_t *next) {
 | 
				
			||||||
 | 
					    prev->next = next;
 | 
				
			||||||
 | 
					    next->prev = prev;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__ASSEMBLER__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_LIST_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										343
									
								
								related_info/lab5/lab5-spoc-discuss/libs/printfmt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								related_info/lab5/lab5-spoc-discuss/libs/printfmt.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,343 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <error.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * Space or zero padding and a field width are supported for the numeric
 | 
				
			||||||
 | 
					 * formats only.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The special format %e takes an integer error code
 | 
				
			||||||
 | 
					 * and prints a string describing the error.
 | 
				
			||||||
 | 
					 * The integer may be positive or negative,
 | 
				
			||||||
 | 
					 * so that -E_NO_MEM and E_NO_MEM are equivalent.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char * const error_string[MAXERROR + 1] = {
 | 
				
			||||||
 | 
					    [0]                     NULL,
 | 
				
			||||||
 | 
					    [E_UNSPECIFIED]         "unspecified error",
 | 
				
			||||||
 | 
					    [E_BAD_PROC]            "bad process",
 | 
				
			||||||
 | 
					    [E_INVAL]               "invalid parameter",
 | 
				
			||||||
 | 
					    [E_NO_MEM]              "out of memory",
 | 
				
			||||||
 | 
					    [E_NO_FREE_PROC]        "out of processes",
 | 
				
			||||||
 | 
					    [E_FAULT]               "segmentation fault",
 | 
				
			||||||
 | 
					    [E_INVAL_ELF]           "invalid elf file",
 | 
				
			||||||
 | 
					    [E_KILLED]              "process is killed",
 | 
				
			||||||
 | 
					    [E_PANIC]               "panic failure",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * printnum - print a number (base <= 16) in reverse order
 | 
				
			||||||
 | 
					 * @putch:      specified putch function, print a single character
 | 
				
			||||||
 | 
					 * @putdat:     used by @putch function
 | 
				
			||||||
 | 
					 * @num:        the number will be printed
 | 
				
			||||||
 | 
					 * @base:       base for print, must be in [1, 16]
 | 
				
			||||||
 | 
					 * @width:      maximum number of digits, if the actual width is less than @width, use @padc instead
 | 
				
			||||||
 | 
					 * @padc:       character that padded on the left if the actual width is less than @width
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					printnum(void (*putch)(int, void*), void *putdat,
 | 
				
			||||||
 | 
					        unsigned long long num, unsigned base, int width, int padc) {
 | 
				
			||||||
 | 
					    unsigned long long result = num;
 | 
				
			||||||
 | 
					    unsigned mod = do_div(result, base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // first recursively print all preceding (more significant) digits
 | 
				
			||||||
 | 
					    if (num >= base) {
 | 
				
			||||||
 | 
					        printnum(putch, putdat, result, base, width - 1, padc);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // print any needed pad characters before first digit
 | 
				
			||||||
 | 
					        while (-- width > 0)
 | 
				
			||||||
 | 
					            putch(padc, putdat);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // then print this (the least significant) digit
 | 
				
			||||||
 | 
					    putch("0123456789abcdef"[mod], putdat);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * getuint - get an unsigned int of various possible sizes from a varargs list
 | 
				
			||||||
 | 
					 * @ap:         a varargs list pointer
 | 
				
			||||||
 | 
					 * @lflag:      determines the size of the vararg that @ap points to
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static unsigned long long
 | 
				
			||||||
 | 
					getuint(va_list *ap, int lflag) {
 | 
				
			||||||
 | 
					    if (lflag >= 2) {
 | 
				
			||||||
 | 
					        return va_arg(*ap, unsigned long long);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (lflag) {
 | 
				
			||||||
 | 
					        return va_arg(*ap, unsigned long);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        return va_arg(*ap, unsigned int);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * getint - same as getuint but signed, we can't use getuint because of sign extension
 | 
				
			||||||
 | 
					 * @ap:         a varargs list pointer
 | 
				
			||||||
 | 
					 * @lflag:      determines the size of the vararg that @ap points to
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static long long
 | 
				
			||||||
 | 
					getint(va_list *ap, int lflag) {
 | 
				
			||||||
 | 
					    if (lflag >= 2) {
 | 
				
			||||||
 | 
					        return va_arg(*ap, long long);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (lflag) {
 | 
				
			||||||
 | 
					        return va_arg(*ap, long);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        return va_arg(*ap, int);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * printfmt - format a string and print it by using putch
 | 
				
			||||||
 | 
					 * @putch:      specified putch function, print a single character
 | 
				
			||||||
 | 
					 * @putdat:     used by @putch function
 | 
				
			||||||
 | 
					 * @fmt:        the format string to use
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...) {
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    va_start(ap, fmt);
 | 
				
			||||||
 | 
					    vprintfmt(putch, putdat, fmt, ap);
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * vprintfmt - format a string and print it by using putch, it's called with a va_list
 | 
				
			||||||
 | 
					 * instead of a variable number of arguments
 | 
				
			||||||
 | 
					 * @putch:      specified putch function, print a single character
 | 
				
			||||||
 | 
					 * @putdat:     used by @putch function
 | 
				
			||||||
 | 
					 * @fmt:        the format string to use
 | 
				
			||||||
 | 
					 * @ap:         arguments for the format string
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Call this function if you are already dealing with a va_list.
 | 
				
			||||||
 | 
					 * Or you probably want printfmt() instead.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap) {
 | 
				
			||||||
 | 
					    register const char *p;
 | 
				
			||||||
 | 
					    register int ch, err;
 | 
				
			||||||
 | 
					    unsigned long long num;
 | 
				
			||||||
 | 
					    int base, width, precision, lflag, altflag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (1) {
 | 
				
			||||||
 | 
					        while ((ch = *(unsigned char *)fmt ++) != '%') {
 | 
				
			||||||
 | 
					            if (ch == '\0') {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            putch(ch, putdat);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Process a %-escape sequence
 | 
				
			||||||
 | 
					        char padc = ' ';
 | 
				
			||||||
 | 
					        width = precision = -1;
 | 
				
			||||||
 | 
					        lflag = altflag = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reswitch:
 | 
				
			||||||
 | 
					        switch (ch = *(unsigned char *)fmt ++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // flag to pad on the right
 | 
				
			||||||
 | 
					        case '-':
 | 
				
			||||||
 | 
					            padc = '-';
 | 
				
			||||||
 | 
					            goto reswitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // flag to pad with 0's instead of spaces
 | 
				
			||||||
 | 
					        case '0':
 | 
				
			||||||
 | 
					            padc = '0';
 | 
				
			||||||
 | 
					            goto reswitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // width field
 | 
				
			||||||
 | 
					        case '1' ... '9':
 | 
				
			||||||
 | 
					            for (precision = 0; ; ++ fmt) {
 | 
				
			||||||
 | 
					                precision = precision * 10 + ch - '0';
 | 
				
			||||||
 | 
					                ch = *fmt;
 | 
				
			||||||
 | 
					                if (ch < '0' || ch > '9') {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            goto process_precision;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case '*':
 | 
				
			||||||
 | 
					            precision = va_arg(ap, int);
 | 
				
			||||||
 | 
					            goto process_precision;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case '.':
 | 
				
			||||||
 | 
					            if (width < 0)
 | 
				
			||||||
 | 
					                width = 0;
 | 
				
			||||||
 | 
					            goto reswitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case '#':
 | 
				
			||||||
 | 
					            altflag = 1;
 | 
				
			||||||
 | 
					            goto reswitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        process_precision:
 | 
				
			||||||
 | 
					            if (width < 0)
 | 
				
			||||||
 | 
					                width = precision, precision = -1;
 | 
				
			||||||
 | 
					            goto reswitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // long flag (doubled for long long)
 | 
				
			||||||
 | 
					        case 'l':
 | 
				
			||||||
 | 
					            lflag ++;
 | 
				
			||||||
 | 
					            goto reswitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // character
 | 
				
			||||||
 | 
					        case 'c':
 | 
				
			||||||
 | 
					            putch(va_arg(ap, int), putdat);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // error message
 | 
				
			||||||
 | 
					        case 'e':
 | 
				
			||||||
 | 
					            err = va_arg(ap, int);
 | 
				
			||||||
 | 
					            if (err < 0) {
 | 
				
			||||||
 | 
					                err = -err;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (err > MAXERROR || (p = error_string[err]) == NULL) {
 | 
				
			||||||
 | 
					                printfmt(putch, putdat, "error %d", err);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                printfmt(putch, putdat, "%s", p);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // string
 | 
				
			||||||
 | 
					        case 's':
 | 
				
			||||||
 | 
					            if ((p = va_arg(ap, char *)) == NULL) {
 | 
				
			||||||
 | 
					                p = "(null)";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (width > 0 && padc != '-') {
 | 
				
			||||||
 | 
					                for (width -= strnlen(p, precision); width > 0; width --) {
 | 
				
			||||||
 | 
					                    putch(padc, putdat);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            for (; (ch = *p ++) != '\0' && (precision < 0 || -- precision >= 0); width --) {
 | 
				
			||||||
 | 
					                if (altflag && (ch < ' ' || ch > '~')) {
 | 
				
			||||||
 | 
					                    putch('?', putdat);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    putch(ch, putdat);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            for (; width > 0; width --) {
 | 
				
			||||||
 | 
					                putch(' ', putdat);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // (signed) decimal
 | 
				
			||||||
 | 
					        case 'd':
 | 
				
			||||||
 | 
					            num = getint(&ap, lflag);
 | 
				
			||||||
 | 
					            if ((long long)num < 0) {
 | 
				
			||||||
 | 
					                putch('-', putdat);
 | 
				
			||||||
 | 
					                num = -(long long)num;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            base = 10;
 | 
				
			||||||
 | 
					            goto number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // unsigned decimal
 | 
				
			||||||
 | 
					        case 'u':
 | 
				
			||||||
 | 
					            num = getuint(&ap, lflag);
 | 
				
			||||||
 | 
					            base = 10;
 | 
				
			||||||
 | 
					            goto number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // (unsigned) octal
 | 
				
			||||||
 | 
					        case 'o':
 | 
				
			||||||
 | 
					            num = getuint(&ap, lflag);
 | 
				
			||||||
 | 
					            base = 8;
 | 
				
			||||||
 | 
					            goto number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // pointer
 | 
				
			||||||
 | 
					        case 'p':
 | 
				
			||||||
 | 
					            putch('0', putdat);
 | 
				
			||||||
 | 
					            putch('x', putdat);
 | 
				
			||||||
 | 
					            num = (unsigned long long)(uintptr_t)va_arg(ap, void *);
 | 
				
			||||||
 | 
					            base = 16;
 | 
				
			||||||
 | 
					            goto number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // (unsigned) hexadecimal
 | 
				
			||||||
 | 
					        case 'x':
 | 
				
			||||||
 | 
					            num = getuint(&ap, lflag);
 | 
				
			||||||
 | 
					            base = 16;
 | 
				
			||||||
 | 
					        number:
 | 
				
			||||||
 | 
					            printnum(putch, putdat, num, base, width, padc);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // escaped '%' character
 | 
				
			||||||
 | 
					        case '%':
 | 
				
			||||||
 | 
					            putch(ch, putdat);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // unrecognized escape sequence - just print it literally
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            putch('%', putdat);
 | 
				
			||||||
 | 
					            for (fmt --; fmt[-1] != '%'; fmt --)
 | 
				
			||||||
 | 
					                /* do nothing */;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* sprintbuf is used to save enough information of a buffer */
 | 
				
			||||||
 | 
					struct sprintbuf {
 | 
				
			||||||
 | 
					    char *buf;          // address pointer points to the first unused memory
 | 
				
			||||||
 | 
					    char *ebuf;         // points the end of the buffer
 | 
				
			||||||
 | 
					    int cnt;            // the number of characters that have been placed in this buffer
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * sprintputch - 'print' a single character in a buffer
 | 
				
			||||||
 | 
					 * @ch:         the character will be printed
 | 
				
			||||||
 | 
					 * @b:          the buffer to place the character @ch
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					sprintputch(int ch, struct sprintbuf *b) {
 | 
				
			||||||
 | 
					    b->cnt ++;
 | 
				
			||||||
 | 
					    if (b->buf < b->ebuf) {
 | 
				
			||||||
 | 
					        *b->buf ++ = ch;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * snprintf - format a string and place it in a buffer
 | 
				
			||||||
 | 
					 * @str:        the buffer to place the result into
 | 
				
			||||||
 | 
					 * @size:       the size of buffer, including the trailing null space
 | 
				
			||||||
 | 
					 * @fmt:        the format string to use
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					snprintf(char *str, size_t size, const char *fmt, ...) {
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    int cnt;
 | 
				
			||||||
 | 
					    va_start(ap, fmt);
 | 
				
			||||||
 | 
					    cnt = vsnprintf(str, size, fmt, ap);
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * vsnprintf - format a string and place it in a buffer, it's called with a va_list
 | 
				
			||||||
 | 
					 * instead of a variable number of arguments
 | 
				
			||||||
 | 
					 * @str:        the buffer to place the result into
 | 
				
			||||||
 | 
					 * @size:       the size of buffer, including the trailing null space
 | 
				
			||||||
 | 
					 * @fmt:        the format string to use
 | 
				
			||||||
 | 
					 * @ap:         arguments for the format string
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The return value is the number of characters which would be generated for the
 | 
				
			||||||
 | 
					 * given input, excluding the trailing '\0'.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Call this function if you are already dealing with a va_list.
 | 
				
			||||||
 | 
					 * Or you probably want snprintf() instead.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					vsnprintf(char *str, size_t size, const char *fmt, va_list ap) {
 | 
				
			||||||
 | 
					    struct sprintbuf b = {str, str + size - 1, 0};
 | 
				
			||||||
 | 
					    if (str == NULL || b.buf > b.ebuf) {
 | 
				
			||||||
 | 
					        return -E_INVAL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // print the string to the buffer
 | 
				
			||||||
 | 
					    vprintfmt((void*)sprintputch, &b, fmt, ap);
 | 
				
			||||||
 | 
					    // null terminate the buffer
 | 
				
			||||||
 | 
					    *b.buf = '\0';
 | 
				
			||||||
 | 
					    return b.cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								related_info/lab5/lab5-spoc-discuss/libs/rand.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								related_info/lab5/lab5-spoc-discuss/libs/rand.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned long long next = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * rand - returns a pseudo-random integer
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The rand() function return a value in the range [0, RAND_MAX].
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					rand(void) {
 | 
				
			||||||
 | 
					    next = (next * 0x5DEECE66DLL + 0xBLL) & ((1LL << 48) - 1);
 | 
				
			||||||
 | 
					    unsigned long long result = (next >> 12);
 | 
				
			||||||
 | 
					    return (int)do_div(result, RAND_MAX + 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * srand - seed the random number generator with the given number
 | 
				
			||||||
 | 
					 * @seed:   the required seed number
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					srand(unsigned int seed) {
 | 
				
			||||||
 | 
					    next = seed;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								related_info/lab5/lab5-spoc-discuss/libs/stdarg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								related_info/lab5/lab5-spoc-discuss/libs/stdarg.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_STDARG_H__
 | 
				
			||||||
 | 
					#define __LIBS_STDARG_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* compiler provides size of save area */
 | 
				
			||||||
 | 
					typedef __builtin_va_list va_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define va_start(ap, last)              (__builtin_va_start(ap, last))
 | 
				
			||||||
 | 
					#define va_arg(ap, type)                (__builtin_va_arg(ap, type))
 | 
				
			||||||
 | 
					#define va_end(ap)                      /*nothing*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_STDARG_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										24
									
								
								related_info/lab5/lab5-spoc-discuss/libs/stdio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								related_info/lab5/lab5-spoc-discuss/libs/stdio.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_STDIO_H__
 | 
				
			||||||
 | 
					#define __LIBS_STDIO_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* kern/libs/stdio.c */
 | 
				
			||||||
 | 
					int cprintf(const char *fmt, ...);
 | 
				
			||||||
 | 
					int vcprintf(const char *fmt, va_list ap);
 | 
				
			||||||
 | 
					void cputchar(int c);
 | 
				
			||||||
 | 
					int cputs(const char *str);
 | 
				
			||||||
 | 
					int getchar(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* kern/libs/readline.c */
 | 
				
			||||||
 | 
					char *readline(const char *prompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* libs/printfmt.c */
 | 
				
			||||||
 | 
					void printfmt(void (*putch)(int, void *), void *putdat, const char *fmt, ...);
 | 
				
			||||||
 | 
					void vprintfmt(void (*putch)(int, void *), void *putdat, const char *fmt, va_list ap);
 | 
				
			||||||
 | 
					int snprintf(char *str, size_t size, const char *fmt, ...);
 | 
				
			||||||
 | 
					int vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_STDIO_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								related_info/lab5/lab5-spoc-discuss/libs/stdlib.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								related_info/lab5/lab5-spoc-discuss/libs/stdlib.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_STDLIB_H__
 | 
				
			||||||
 | 
					#define __LIBS_STDLIB_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* the largest number rand will return */
 | 
				
			||||||
 | 
					#define RAND_MAX    2147483647UL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* libs/rand.c */
 | 
				
			||||||
 | 
					int rand(void);
 | 
				
			||||||
 | 
					void srand(unsigned int seed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* libs/hash.c */
 | 
				
			||||||
 | 
					uint32_t hash32(uint32_t val, unsigned int bits);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_RAND_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										367
									
								
								related_info/lab5/lab5-spoc-discuss/libs/string.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								related_info/lab5/lab5-spoc-discuss/libs/string.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,367 @@
 | 
				
			|||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <x86.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strlen - calculate the length of the string @s, not including
 | 
				
			||||||
 | 
					 * the terminating '\0' character.
 | 
				
			||||||
 | 
					 * @s:      the input string
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The strlen() function returns the length of string @s.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					size_t
 | 
				
			||||||
 | 
					strlen(const char *s) {
 | 
				
			||||||
 | 
					    size_t cnt = 0;
 | 
				
			||||||
 | 
					    while (*s ++ != '\0') {
 | 
				
			||||||
 | 
					        cnt ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strnlen - calculate the length of the string @s, not including
 | 
				
			||||||
 | 
					 * the terminating '\0' char acter, but at most @len.
 | 
				
			||||||
 | 
					 * @s:      the input string
 | 
				
			||||||
 | 
					 * @len:    the max-length that function will scan
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that, this function looks only at the first @len characters
 | 
				
			||||||
 | 
					 * at @s, and never beyond @s + @len.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The return value is strlen(s), if that is less than @len, or
 | 
				
			||||||
 | 
					 * @len if there is no '\0' character among the first @len characters
 | 
				
			||||||
 | 
					 * pointed by @s.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					size_t
 | 
				
			||||||
 | 
					strnlen(const char *s, size_t len) {
 | 
				
			||||||
 | 
					    size_t cnt = 0;
 | 
				
			||||||
 | 
					    while (cnt < len && *s ++ != '\0') {
 | 
				
			||||||
 | 
					        cnt ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strcpy - copies the string pointed by @src into the array pointed by @dst,
 | 
				
			||||||
 | 
					 * including the terminating null character.
 | 
				
			||||||
 | 
					 * @dst:    pointer to the destination array where the content is to be copied
 | 
				
			||||||
 | 
					 * @src:    string to be copied
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The return value is @dst.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * To avoid overflows, the size of array pointed by @dst should be long enough to
 | 
				
			||||||
 | 
					 * contain the same string as @src (including the terminating null character), and
 | 
				
			||||||
 | 
					 * should not overlap in memory with @src.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					strcpy(char *dst, const char *src) {
 | 
				
			||||||
 | 
					#ifdef __HAVE_ARCH_STRCPY
 | 
				
			||||||
 | 
					    return __strcpy(dst, src);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    char *p = dst;
 | 
				
			||||||
 | 
					    while ((*p ++ = *src ++) != '\0')
 | 
				
			||||||
 | 
					        /* nothing */;
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_STRCPY */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strncpy - copies the first @len characters of @src to @dst. If the end of string @src
 | 
				
			||||||
 | 
					 * if found before @len characters have been copied, @dst is padded with '\0' until a
 | 
				
			||||||
 | 
					 * total of @len characters have been written to it.
 | 
				
			||||||
 | 
					 * @dst:    pointer to the destination array where the content is to be copied
 | 
				
			||||||
 | 
					 * @src:    string to be copied
 | 
				
			||||||
 | 
					 * @len:    maximum number of characters to be copied from @src
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The return value is @dst
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					strncpy(char *dst, const char *src, size_t len) {
 | 
				
			||||||
 | 
					    char *p = dst;
 | 
				
			||||||
 | 
					    while (len > 0) {
 | 
				
			||||||
 | 
					        if ((*p = *src) != '\0') {
 | 
				
			||||||
 | 
					            src ++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        p ++, len --;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strcmp - compares the string @s1 and @s2
 | 
				
			||||||
 | 
					 * @s1:     string to be compared
 | 
				
			||||||
 | 
					 * @s2:     string to be compared
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function starts comparing the first character of each string. If
 | 
				
			||||||
 | 
					 * they are equal to each other, it continues with the following pairs until
 | 
				
			||||||
 | 
					 * the characters differ or until a terminanting null-character is reached.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns an integral value indicating the relationship between the strings:
 | 
				
			||||||
 | 
					 * - A zero value indicates that both strings are equal;
 | 
				
			||||||
 | 
					 * - A value greater than zero indicates that the first character that does
 | 
				
			||||||
 | 
					 *   not match has a greater value in @s1 than in @s2;
 | 
				
			||||||
 | 
					 * - And a value less than zero indicates the opposite.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					strcmp(const char *s1, const char *s2) {
 | 
				
			||||||
 | 
					#ifdef __HAVE_ARCH_STRCMP
 | 
				
			||||||
 | 
					    return __strcmp(s1, s2);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    while (*s1 != '\0' && *s1 == *s2) {
 | 
				
			||||||
 | 
					        s1 ++, s2 ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return (int)((unsigned char)*s1 - (unsigned char)*s2);
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_STRCMP */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strncmp - compares up to @n characters of the string @s1 to those of the string @s2
 | 
				
			||||||
 | 
					 * @s1:     string to be compared
 | 
				
			||||||
 | 
					 * @s2:     string to be compared
 | 
				
			||||||
 | 
					 * @n:      maximum number of characters to compare
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function starts comparing the first character of each string. If
 | 
				
			||||||
 | 
					 * they are equal to each other, it continues with the following pairs until
 | 
				
			||||||
 | 
					 * the characters differ, until a terminating null-character is reached, or
 | 
				
			||||||
 | 
					 * until @n characters match in both strings, whichever happens first.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					strncmp(const char *s1, const char *s2, size_t n) {
 | 
				
			||||||
 | 
					    while (n > 0 && *s1 != '\0' && *s1 == *s2) {
 | 
				
			||||||
 | 
					        n --, s1 ++, s2 ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return (n == 0) ? 0 : (int)((unsigned char)*s1 - (unsigned char)*s2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strchr - locates first occurrence of character in string
 | 
				
			||||||
 | 
					 * @s:      the input string
 | 
				
			||||||
 | 
					 * @c:      character to be located
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The strchr() function returns a pointer to the first occurrence of
 | 
				
			||||||
 | 
					 * character in @s. If the value is not found, the function returns 'NULL'.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					strchr(const char *s, char c) {
 | 
				
			||||||
 | 
					    while (*s != '\0') {
 | 
				
			||||||
 | 
					        if (*s == c) {
 | 
				
			||||||
 | 
					            return (char *)s;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        s ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strfind - locates first occurrence of character in string
 | 
				
			||||||
 | 
					 * @s:      the input string
 | 
				
			||||||
 | 
					 * @c:      character to be located
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The strfind() function is like strchr() except that if @c is
 | 
				
			||||||
 | 
					 * not found in @s, then it returns a pointer to the null byte at the
 | 
				
			||||||
 | 
					 * end of @s, rather than 'NULL'.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					strfind(const char *s, char c) {
 | 
				
			||||||
 | 
					    while (*s != '\0') {
 | 
				
			||||||
 | 
					        if (*s == c) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        s ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return (char *)s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * strtol - converts string to long integer
 | 
				
			||||||
 | 
					 * @s:      the input string that contains the representation of an integer number
 | 
				
			||||||
 | 
					 * @endptr: reference to an object of type char *, whose value is set by the
 | 
				
			||||||
 | 
					 *          function to the next character in @s after the numerical value. This
 | 
				
			||||||
 | 
					 *          parameter can also be a null pointer, in which case it is not used.
 | 
				
			||||||
 | 
					 * @base:   x
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The function first discards as many whitespace characters as necessary until
 | 
				
			||||||
 | 
					 * the first non-whitespace character is found. Then, starting from this character,
 | 
				
			||||||
 | 
					 * takes as many characters as possible that are valid following a syntax that
 | 
				
			||||||
 | 
					 * depends on the base parameter, and interprets them as a numerical value. Finally,
 | 
				
			||||||
 | 
					 * a pointer to the first character following the integer representation in @s
 | 
				
			||||||
 | 
					 * is stored in the object pointed by @endptr.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the value of base is zero, the syntax expected is similar to that of
 | 
				
			||||||
 | 
					 * integer constants, which is formed by a succession of:
 | 
				
			||||||
 | 
					 * - An optional plus or minus sign;
 | 
				
			||||||
 | 
					 * - An optional prefix indicating octal or hexadecimal base ("0" or "0x" respectively)
 | 
				
			||||||
 | 
					 * - A sequence of decimal digits (if no base prefix was specified) or either octal
 | 
				
			||||||
 | 
					 *   or hexadecimal digits if a specific prefix is present
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the base value is between 2 and 36, the format expected for the integral number
 | 
				
			||||||
 | 
					 * is a succession of the valid digits and/or letters needed to represent integers of
 | 
				
			||||||
 | 
					 * the specified radix (starting from '0' and up to 'z'/'Z' for radix 36). The
 | 
				
			||||||
 | 
					 * sequence may optionally be preceded by a plus or minus sign and, if base is 16,
 | 
				
			||||||
 | 
					 * an optional "0x" or "0X" prefix.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The strtol() function returns the converted integral number as a long int value.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					long
 | 
				
			||||||
 | 
					strtol(const char *s, char **endptr, int base) {
 | 
				
			||||||
 | 
					    int neg = 0;
 | 
				
			||||||
 | 
					    long val = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // gobble initial whitespace
 | 
				
			||||||
 | 
					    while (*s == ' ' || *s == '\t') {
 | 
				
			||||||
 | 
					        s ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // plus/minus sign
 | 
				
			||||||
 | 
					    if (*s == '+') {
 | 
				
			||||||
 | 
					        s ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (*s == '-') {
 | 
				
			||||||
 | 
					        s ++, neg = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // hex or octal base prefix
 | 
				
			||||||
 | 
					    if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x')) {
 | 
				
			||||||
 | 
					        s += 2, base = 16;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (base == 0 && s[0] == '0') {
 | 
				
			||||||
 | 
					        s ++, base = 8;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (base == 0) {
 | 
				
			||||||
 | 
					        base = 10;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // digits
 | 
				
			||||||
 | 
					    while (1) {
 | 
				
			||||||
 | 
					        int dig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (*s >= '0' && *s <= '9') {
 | 
				
			||||||
 | 
					            dig = *s - '0';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (*s >= 'a' && *s <= 'z') {
 | 
				
			||||||
 | 
					            dig = *s - 'a' + 10;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (*s >= 'A' && *s <= 'Z') {
 | 
				
			||||||
 | 
					            dig = *s - 'A' + 10;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (dig >= base) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        s ++, val = (val * base) + dig;
 | 
				
			||||||
 | 
					        // we don't properly detect overflow!
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (endptr) {
 | 
				
			||||||
 | 
					        *endptr = (char *) s;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return (neg ? -val : val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * memset - sets the first @n bytes of the memory area pointed by @s
 | 
				
			||||||
 | 
					 * to the specified value @c.
 | 
				
			||||||
 | 
					 * @s:      pointer the the memory area to fill
 | 
				
			||||||
 | 
					 * @c:      value to set
 | 
				
			||||||
 | 
					 * @n:      number of bytes to be set to the value
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The memset() function returns @s.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void *
 | 
				
			||||||
 | 
					memset(void *s, char c, size_t n) {
 | 
				
			||||||
 | 
					#ifdef __HAVE_ARCH_MEMSET
 | 
				
			||||||
 | 
					    return __memset(s, c, n);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    char *p = s;
 | 
				
			||||||
 | 
					    while (n -- > 0) {
 | 
				
			||||||
 | 
					        *p ++ = c;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return s;
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_MEMSET */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * memmove - copies the values of @n bytes from the location pointed by @src to
 | 
				
			||||||
 | 
					 * the memory area pointed by @dst. @src and @dst are allowed to overlap.
 | 
				
			||||||
 | 
					 * @dst     pointer to the destination array where the content is to be copied
 | 
				
			||||||
 | 
					 * @src     pointer to the source of data to by copied
 | 
				
			||||||
 | 
					 * @n:      number of bytes to copy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The memmove() function returns @dst.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void *
 | 
				
			||||||
 | 
					memmove(void *dst, const void *src, size_t n) {
 | 
				
			||||||
 | 
					#ifdef __HAVE_ARCH_MEMMOVE
 | 
				
			||||||
 | 
					    return __memmove(dst, src, n);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    const char *s = src;
 | 
				
			||||||
 | 
					    char *d = dst;
 | 
				
			||||||
 | 
					    if (s < d && s + n > d) {
 | 
				
			||||||
 | 
					        s += n, d += n;
 | 
				
			||||||
 | 
					        while (n -- > 0) {
 | 
				
			||||||
 | 
					            *-- d = *-- s;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        while (n -- > 0) {
 | 
				
			||||||
 | 
					            *d ++ = *s ++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_MEMMOVE */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * memcpy - copies the value of @n bytes from the location pointed by @src to
 | 
				
			||||||
 | 
					 * the memory area pointed by @dst.
 | 
				
			||||||
 | 
					 * @dst     pointer to the destination array where the content is to be copied
 | 
				
			||||||
 | 
					 * @src     pointer to the source of data to by copied
 | 
				
			||||||
 | 
					 * @n:      number of bytes to copy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The memcpy() returns @dst.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that, the function does not check any terminating null character in @src,
 | 
				
			||||||
 | 
					 * it always copies exactly @n bytes. To avoid overflows, the size of arrays pointed
 | 
				
			||||||
 | 
					 * by both @src and @dst, should be at least @n bytes, and should not overlap
 | 
				
			||||||
 | 
					 * (for overlapping memory area, memmove is a safer approach).
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void *
 | 
				
			||||||
 | 
					memcpy(void *dst, const void *src, size_t n) {
 | 
				
			||||||
 | 
					#ifdef __HAVE_ARCH_MEMCPY
 | 
				
			||||||
 | 
					    return __memcpy(dst, src, n);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    const char *s = src;
 | 
				
			||||||
 | 
					    char *d = dst;
 | 
				
			||||||
 | 
					    while (n -- > 0) {
 | 
				
			||||||
 | 
					        *d ++ = *s ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_MEMCPY */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * memcmp - compares two blocks of memory
 | 
				
			||||||
 | 
					 * @v1:     pointer to block of memory
 | 
				
			||||||
 | 
					 * @v2:     pointer to block of memory
 | 
				
			||||||
 | 
					 * @n:      number of bytes to compare
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The memcmp() functions returns an integral value indicating the
 | 
				
			||||||
 | 
					 * relationship between the content of the memory blocks:
 | 
				
			||||||
 | 
					 * - A zero value indicates that the contents of both memory blocks are equal;
 | 
				
			||||||
 | 
					 * - A value greater than zero indicates that the first byte that does not
 | 
				
			||||||
 | 
					 *   match in both memory blocks has a greater value in @v1 than in @v2
 | 
				
			||||||
 | 
					 *   as if evaluated as unsigned char values;
 | 
				
			||||||
 | 
					 * - And a value less than zero indicates the opposite.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					memcmp(const void *v1, const void *v2, size_t n) {
 | 
				
			||||||
 | 
					    const char *s1 = (const char *)v1;
 | 
				
			||||||
 | 
					    const char *s2 = (const char *)v2;
 | 
				
			||||||
 | 
					    while (n -- > 0) {
 | 
				
			||||||
 | 
					        if (*s1 != *s2) {
 | 
				
			||||||
 | 
					            return (int)((unsigned char)*s1 - (unsigned char)*s2);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        s1 ++, s2 ++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								related_info/lab5/lab5-spoc-discuss/libs/string.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								related_info/lab5/lab5-spoc-discuss/libs/string.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_STRING_H__
 | 
				
			||||||
 | 
					#define __LIBS_STRING_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t strlen(const char *s);
 | 
				
			||||||
 | 
					size_t strnlen(const char *s, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *strcpy(char *dst, const char *src);
 | 
				
			||||||
 | 
					char *strncpy(char *dst, const char *src, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int strcmp(const char *s1, const char *s2);
 | 
				
			||||||
 | 
					int strncmp(const char *s1, const char *s2, size_t n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *strchr(const char *s, char c);
 | 
				
			||||||
 | 
					char *strfind(const char *s, char c);
 | 
				
			||||||
 | 
					long strtol(const char *s, char **endptr, int base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *memset(void *s, char c, size_t n);
 | 
				
			||||||
 | 
					void *memmove(void *dst, const void *src, size_t n);
 | 
				
			||||||
 | 
					void *memcpy(void *dst, const void *src, size_t n);
 | 
				
			||||||
 | 
					int memcmp(const void *v1, const void *v2, size_t n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_STRING_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										29
									
								
								related_info/lab5/lab5-spoc-discuss/libs/unistd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								related_info/lab5/lab5-spoc-discuss/libs/unistd.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_UNISTD_H__
 | 
				
			||||||
 | 
					#define __LIBS_UNISTD_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define T_SYSCALL           0x80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* syscall number */
 | 
				
			||||||
 | 
					#define SYS_exit            1
 | 
				
			||||||
 | 
					#define SYS_fork            2
 | 
				
			||||||
 | 
					#define SYS_wait            3
 | 
				
			||||||
 | 
					#define SYS_exec            4
 | 
				
			||||||
 | 
					#define SYS_clone           5
 | 
				
			||||||
 | 
					#define SYS_yield           10
 | 
				
			||||||
 | 
					#define SYS_sleep           11
 | 
				
			||||||
 | 
					#define SYS_kill            12
 | 
				
			||||||
 | 
					#define SYS_gettime         17
 | 
				
			||||||
 | 
					#define SYS_getpid          18
 | 
				
			||||||
 | 
					#define SYS_brk             19
 | 
				
			||||||
 | 
					#define SYS_mmap            20
 | 
				
			||||||
 | 
					#define SYS_munmap          21
 | 
				
			||||||
 | 
					#define SYS_shmem           22
 | 
				
			||||||
 | 
					#define SYS_putc            30
 | 
				
			||||||
 | 
					#define SYS_pgdir           31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* SYS_fork flags */
 | 
				
			||||||
 | 
					#define CLONE_VM            0x00000100  // set if VM shared between processes
 | 
				
			||||||
 | 
					#define CLONE_THREAD        0x00000200  // thread group
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_UNISTD_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										302
									
								
								related_info/lab5/lab5-spoc-discuss/libs/x86.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								related_info/lab5/lab5-spoc-discuss/libs/x86.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,302 @@
 | 
				
			|||||||
 | 
					#ifndef __LIBS_X86_H__
 | 
				
			||||||
 | 
					#define __LIBS_X86_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define do_div(n, base) ({                                          \
 | 
				
			||||||
 | 
					            unsigned long __upper, __low, __high, __mod, __base;    \
 | 
				
			||||||
 | 
					            __base = (base);                                        \
 | 
				
			||||||
 | 
					            asm ("" : "=a" (__low), "=d" (__high) : "A" (n));       \
 | 
				
			||||||
 | 
					            __upper = __high;                                       \
 | 
				
			||||||
 | 
					            if (__high != 0) {                                      \
 | 
				
			||||||
 | 
					                __upper = __high % __base;                          \
 | 
				
			||||||
 | 
					                __high = __high / __base;                           \
 | 
				
			||||||
 | 
					            }                                                       \
 | 
				
			||||||
 | 
					            asm ("divl %2" : "=a" (__low), "=d" (__mod)             \
 | 
				
			||||||
 | 
					                : "rm" (__base), "0" (__low), "1" (__upper));       \
 | 
				
			||||||
 | 
					            asm ("" : "=A" (n) : "a" (__low), "d" (__high));        \
 | 
				
			||||||
 | 
					            __mod;                                                  \
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define barrier() __asm__ __volatile__ ("" ::: "memory")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uint8_t inb(uint16_t port) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void insl(uint32_t port, void *addr, int cnt) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void outb(uint16_t port, uint8_t data) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void outw(uint16_t port, uint16_t data) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void outsl(uint32_t port, const void *addr, int cnt) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline uint32_t read_ebp(void) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void breakpoint(void) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline uint32_t read_dr(unsigned regnum) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void write_dr(unsigned regnum, uint32_t value) __attribute__((always_inline));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Pseudo-descriptors used for LGDT, LLDT(not used) and LIDT instructions. */
 | 
				
			||||||
 | 
					struct pseudodesc {
 | 
				
			||||||
 | 
					    uint16_t pd_lim;        // Limit
 | 
				
			||||||
 | 
					    uintptr_t pd_base;      // Base address
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void lidt(struct pseudodesc *pd) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void sti(void) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void cli(void) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void ltr(uint16_t sel) __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 void lcr0(uintptr_t cr0) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void lcr3(uintptr_t cr3) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline uintptr_t rcr0(void) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline uintptr_t rcr1(void) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline uintptr_t rcr2(void) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline uintptr_t rcr3(void) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void invlpg(void *addr) __attribute__((always_inline));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uint8_t
 | 
				
			||||||
 | 
					inb(uint16_t port) {
 | 
				
			||||||
 | 
					    uint8_t data;
 | 
				
			||||||
 | 
					    asm volatile ("inb %1, %0" : "=a" (data) : "d" (port) : "memory");
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					insl(uint32_t port, void *addr, int cnt) {
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "cld;"
 | 
				
			||||||
 | 
					        "repne; insl;"
 | 
				
			||||||
 | 
					        : "=D" (addr), "=c" (cnt)
 | 
				
			||||||
 | 
					        : "d" (port), "0" (addr), "1" (cnt)
 | 
				
			||||||
 | 
					        : "memory", "cc");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					outb(uint16_t port, uint8_t data) {
 | 
				
			||||||
 | 
					    asm volatile ("outb %0, %1" :: "a" (data), "d" (port) : "memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					outw(uint16_t port, uint16_t data) {
 | 
				
			||||||
 | 
					    asm volatile ("outw %0, %1" :: "a" (data), "d" (port) : "memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					outsl(uint32_t port, const void *addr, int cnt) {
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "cld;"
 | 
				
			||||||
 | 
					        "repne; outsl;"
 | 
				
			||||||
 | 
					        : "=S" (addr), "=c" (cnt)
 | 
				
			||||||
 | 
					        : "d" (port), "0" (addr), "1" (cnt)
 | 
				
			||||||
 | 
					        : "memory", "cc");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uint32_t
 | 
				
			||||||
 | 
					read_ebp(void) {
 | 
				
			||||||
 | 
					    uint32_t ebp;
 | 
				
			||||||
 | 
					    asm volatile ("movl %%ebp, %0" : "=r" (ebp));
 | 
				
			||||||
 | 
					    return ebp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					breakpoint(void) {
 | 
				
			||||||
 | 
					    asm volatile ("int $3");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uint32_t
 | 
				
			||||||
 | 
					read_dr(unsigned regnum) {
 | 
				
			||||||
 | 
					    uint32_t value = 0;
 | 
				
			||||||
 | 
					    switch (regnum) {
 | 
				
			||||||
 | 
					    case 0: asm volatile ("movl %%db0, %0" : "=r" (value)); break;
 | 
				
			||||||
 | 
					    case 1: asm volatile ("movl %%db1, %0" : "=r" (value)); break;
 | 
				
			||||||
 | 
					    case 2: asm volatile ("movl %%db2, %0" : "=r" (value)); break;
 | 
				
			||||||
 | 
					    case 3: asm volatile ("movl %%db3, %0" : "=r" (value)); break;
 | 
				
			||||||
 | 
					    case 6: asm volatile ("movl %%db6, %0" : "=r" (value)); break;
 | 
				
			||||||
 | 
					    case 7: asm volatile ("movl %%db7, %0" : "=r" (value)); break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					write_dr(unsigned regnum, uint32_t value) {
 | 
				
			||||||
 | 
					    switch (regnum) {
 | 
				
			||||||
 | 
					    case 0: asm volatile ("movl %0, %%db0" :: "r" (value)); break;
 | 
				
			||||||
 | 
					    case 1: asm volatile ("movl %0, %%db1" :: "r" (value)); break;
 | 
				
			||||||
 | 
					    case 2: asm volatile ("movl %0, %%db2" :: "r" (value)); break;
 | 
				
			||||||
 | 
					    case 3: asm volatile ("movl %0, %%db3" :: "r" (value)); break;
 | 
				
			||||||
 | 
					    case 6: asm volatile ("movl %0, %%db6" :: "r" (value)); break;
 | 
				
			||||||
 | 
					    case 7: asm volatile ("movl %0, %%db7" :: "r" (value)); break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					lidt(struct pseudodesc *pd) {
 | 
				
			||||||
 | 
					    asm volatile ("lidt (%0)" :: "r" (pd) : "memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					sti(void) {
 | 
				
			||||||
 | 
					    asm volatile ("sti");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					cli(void) {
 | 
				
			||||||
 | 
					    asm volatile ("cli" ::: "memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					ltr(uint16_t sel) {
 | 
				
			||||||
 | 
					    asm volatile ("ltr %0" :: "r" (sel) : "memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 void
 | 
				
			||||||
 | 
					lcr0(uintptr_t cr0) {
 | 
				
			||||||
 | 
					    asm volatile ("mov %0, %%cr0" :: "r" (cr0) : "memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					lcr3(uintptr_t cr3) {
 | 
				
			||||||
 | 
					    asm volatile ("mov %0, %%cr3" :: "r" (cr3) : "memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uintptr_t
 | 
				
			||||||
 | 
					rcr0(void) {
 | 
				
			||||||
 | 
					    uintptr_t cr0;
 | 
				
			||||||
 | 
					    asm volatile ("mov %%cr0, %0" : "=r" (cr0) :: "memory");
 | 
				
			||||||
 | 
					    return cr0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uintptr_t
 | 
				
			||||||
 | 
					rcr1(void) {
 | 
				
			||||||
 | 
					    uintptr_t cr1;
 | 
				
			||||||
 | 
					    asm volatile ("mov %%cr1, %0" : "=r" (cr1) :: "memory");
 | 
				
			||||||
 | 
					    return cr1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uintptr_t
 | 
				
			||||||
 | 
					rcr2(void) {
 | 
				
			||||||
 | 
					    uintptr_t cr2;
 | 
				
			||||||
 | 
					    asm volatile ("mov %%cr2, %0" : "=r" (cr2) :: "memory");
 | 
				
			||||||
 | 
					    return cr2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uintptr_t
 | 
				
			||||||
 | 
					rcr3(void) {
 | 
				
			||||||
 | 
					    uintptr_t cr3;
 | 
				
			||||||
 | 
					    asm volatile ("mov %%cr3, %0" : "=r" (cr3) :: "memory");
 | 
				
			||||||
 | 
					    return cr3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					invlpg(void *addr) {
 | 
				
			||||||
 | 
					    asm volatile ("invlpg (%0)" :: "r" (addr) : "memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int __strcmp(const char *s1, const char *s2) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline char *__strcpy(char *dst, const char *src) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void *__memset(void *s, char c, size_t n) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void *__memmove(void *dst, const void *src, size_t n) __attribute__((always_inline));
 | 
				
			||||||
 | 
					static inline void *__memcpy(void *dst, const void *src, size_t n) __attribute__((always_inline));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __HAVE_ARCH_STRCMP
 | 
				
			||||||
 | 
					#define __HAVE_ARCH_STRCMP
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					__strcmp(const char *s1, const char *s2) {
 | 
				
			||||||
 | 
					    int d0, d1, ret;
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "1: lodsb;"
 | 
				
			||||||
 | 
					        "scasb;"
 | 
				
			||||||
 | 
					        "jne 2f;"
 | 
				
			||||||
 | 
					        "testb %%al, %%al;"
 | 
				
			||||||
 | 
					        "jne 1b;"
 | 
				
			||||||
 | 
					        "xorl %%eax, %%eax;"
 | 
				
			||||||
 | 
					        "jmp 3f;"
 | 
				
			||||||
 | 
					        "2: sbbl %%eax, %%eax;"
 | 
				
			||||||
 | 
					        "orb $1, %%al;"
 | 
				
			||||||
 | 
					        "3:"
 | 
				
			||||||
 | 
					        : "=a" (ret), "=&S" (d0), "=&D" (d1)
 | 
				
			||||||
 | 
					        : "1" (s1), "2" (s2)
 | 
				
			||||||
 | 
					        : "memory");
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_STRCMP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __HAVE_ARCH_STRCPY
 | 
				
			||||||
 | 
					#define __HAVE_ARCH_STRCPY
 | 
				
			||||||
 | 
					static inline char *
 | 
				
			||||||
 | 
					__strcpy(char *dst, const char *src) {
 | 
				
			||||||
 | 
					    int d0, d1, d2;
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "1: lodsb;"
 | 
				
			||||||
 | 
					        "stosb;"
 | 
				
			||||||
 | 
					        "testb %%al, %%al;"
 | 
				
			||||||
 | 
					        "jne 1b;"
 | 
				
			||||||
 | 
					        : "=&S" (d0), "=&D" (d1), "=&a" (d2)
 | 
				
			||||||
 | 
					        : "0" (src), "1" (dst) : "memory");
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_STRCPY */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __HAVE_ARCH_MEMSET
 | 
				
			||||||
 | 
					#define __HAVE_ARCH_MEMSET
 | 
				
			||||||
 | 
					static inline void *
 | 
				
			||||||
 | 
					__memset(void *s, char c, size_t n) {
 | 
				
			||||||
 | 
					    int d0, d1;
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "rep; stosb;"
 | 
				
			||||||
 | 
					        : "=&c" (d0), "=&D" (d1)
 | 
				
			||||||
 | 
					        : "0" (n), "a" (c), "1" (s)
 | 
				
			||||||
 | 
					        : "memory");
 | 
				
			||||||
 | 
					    return s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_MEMSET */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __HAVE_ARCH_MEMMOVE
 | 
				
			||||||
 | 
					#define __HAVE_ARCH_MEMMOVE
 | 
				
			||||||
 | 
					static inline void *
 | 
				
			||||||
 | 
					__memmove(void *dst, const void *src, size_t n) {
 | 
				
			||||||
 | 
					    if (dst < src) {
 | 
				
			||||||
 | 
					        return __memcpy(dst, src, n);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int d0, d1, d2;
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "std;"
 | 
				
			||||||
 | 
					        "rep; movsb;"
 | 
				
			||||||
 | 
					        "cld;"
 | 
				
			||||||
 | 
					        : "=&c" (d0), "=&S" (d1), "=&D" (d2)
 | 
				
			||||||
 | 
					        : "0" (n), "1" (n - 1 + src), "2" (n - 1 + dst)
 | 
				
			||||||
 | 
					        : "memory");
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_MEMMOVE */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __HAVE_ARCH_MEMCPY
 | 
				
			||||||
 | 
					#define __HAVE_ARCH_MEMCPY
 | 
				
			||||||
 | 
					static inline void *
 | 
				
			||||||
 | 
					__memcpy(void *dst, const void *src, size_t n) {
 | 
				
			||||||
 | 
					    int d0, d1, d2;
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "rep; movsl;"
 | 
				
			||||||
 | 
					        "movl %4, %%ecx;"
 | 
				
			||||||
 | 
					        "andl $3, %%ecx;"
 | 
				
			||||||
 | 
					        "jz 1f;"
 | 
				
			||||||
 | 
					        "rep; movsb;"
 | 
				
			||||||
 | 
					        "1:"
 | 
				
			||||||
 | 
					        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
 | 
				
			||||||
 | 
					        : "0" (n / 4), "g" (n), "1" (dst), "2" (src)
 | 
				
			||||||
 | 
					        : "memory");
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* __HAVE_ARCH_MEMCPY */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__LIBS_X86_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								related_info/lab5/lab5-spoc-discuss/tools/boot.ld
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								related_info/lab5/lab5-spoc-discuss/tools/boot.ld
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					OUTPUT_FORMAT("elf32-i386")
 | 
				
			||||||
 | 
					OUTPUT_ARCH(i386)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SECTIONS {
 | 
				
			||||||
 | 
					    . = 0x7C00;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .startup : {
 | 
				
			||||||
 | 
					        *bootasm.o(.text)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .text : { *(.text) }
 | 
				
			||||||
 | 
					    .data : { *(.data .rodata) }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /DISCARD/ : { *(.eh_*) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										95
									
								
								related_info/lab5/lab5-spoc-discuss/tools/function.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								related_info/lab5/lab5-spoc-discuss/tools/function.mk
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					OBJPREFIX	:= __objs_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.SECONDEXPANSION:
 | 
				
			||||||
 | 
					# -------------------- function begin --------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# list all files in some directories: (#directories, #types)
 | 
				
			||||||
 | 
					listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\
 | 
				
			||||||
 | 
							  $(wildcard $(addsuffix $(SLASH)*,$(1))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# get .o obj files: (#files[, packet])
 | 
				
			||||||
 | 
					toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\
 | 
				
			||||||
 | 
							$(addsuffix .o,$(basename $(1))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# get .d dependency files: (#files[, packet])
 | 
				
			||||||
 | 
					todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					totarget = $(addprefix $(BINDIR)$(SLASH),$(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# change $(name) to $(OBJPREFIX)$(name): (#names)
 | 
				
			||||||
 | 
					packetname = $(if $(1),$(addprefix $(OBJPREFIX),$(1)),$(OBJPREFIX))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
 | 
				
			||||||
 | 
					define cc_template
 | 
				
			||||||
 | 
					$$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$@)
 | 
				
			||||||
 | 
						@$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$@) $$@"> $$@
 | 
				
			||||||
 | 
					$$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$@)
 | 
				
			||||||
 | 
						@echo + cc $$<
 | 
				
			||||||
 | 
						$(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$@
 | 
				
			||||||
 | 
					ALLOBJS += $$(call toobj,$(1),$(4))
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# compile file: (#files, cc[, flags, dir])
 | 
				
			||||||
 | 
					define do_cc_compile
 | 
				
			||||||
 | 
					$$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(4))))
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# add files to packet: (#files, cc[, flags, packet, dir])
 | 
				
			||||||
 | 
					define do_add_files_to_packet
 | 
				
			||||||
 | 
					__temp_packet__ := $(call packetname,$(4))
 | 
				
			||||||
 | 
					ifeq ($$(origin $$(__temp_packet__)),undefined)
 | 
				
			||||||
 | 
					$$(__temp_packet__) :=
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					__temp_objs__ := $(call toobj,$(1),$(5))
 | 
				
			||||||
 | 
					$$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(5))))
 | 
				
			||||||
 | 
					$$(__temp_packet__) += $$(__temp_objs__)
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# add objs to packet: (#objs, packet)
 | 
				
			||||||
 | 
					define do_add_objs_to_packet
 | 
				
			||||||
 | 
					__temp_packet__ := $(call packetname,$(2))
 | 
				
			||||||
 | 
					ifeq ($$(origin $$(__temp_packet__)),undefined)
 | 
				
			||||||
 | 
					$$(__temp_packet__) :=
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					$$(__temp_packet__) += $(1)
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# add packets and objs to target (target, #packes, #objs[, cc, flags])
 | 
				
			||||||
 | 
					define do_create_target
 | 
				
			||||||
 | 
					__temp_target__ = $(call totarget,$(1))
 | 
				
			||||||
 | 
					__temp_objs__ = $$(foreach p,$(call packetname,$(2)),$$($$(p))) $(3)
 | 
				
			||||||
 | 
					TARGETS += $$(__temp_target__)
 | 
				
			||||||
 | 
					ifneq ($(4),)
 | 
				
			||||||
 | 
					$$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@)
 | 
				
			||||||
 | 
						$(V)$(4) $(5) $$^ -o $$@
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					$$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# finish all
 | 
				
			||||||
 | 
					define do_finish_all
 | 
				
			||||||
 | 
					ALLDEPS = $$(ALLOBJS:.o=.d)
 | 
				
			||||||
 | 
					$$(sort $$(dir $$(ALLOBJS)) $(BINDIR)$(SLASH) $(OBJDIR)$(SLASH)):
 | 
				
			||||||
 | 
						@$(MKDIR) $$@
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# --------------------  function end  --------------------
 | 
				
			||||||
 | 
					# compile file: (#files, cc[, flags, dir])
 | 
				
			||||||
 | 
					cc_compile = $(eval $(call do_cc_compile,$(1),$(2),$(3),$(4)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# add files to packet: (#files, cc[, flags, packet, dir])
 | 
				
			||||||
 | 
					add_files = $(eval $(call do_add_files_to_packet,$(1),$(2),$(3),$(4),$(5)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# add objs to packet: (#objs, packet)
 | 
				
			||||||
 | 
					add_objs = $(eval $(call do_add_objs_to_packet,$(1),$(2)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# add packets and objs to target (target, #packes, #objs, cc, [, flags])
 | 
				
			||||||
 | 
					create_target = $(eval $(call do_create_target,$(1),$(2),$(3),$(4),$(5)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					read_packet = $(foreach p,$(call packetname,$(1)),$($(p)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_dependency = $(eval $(1): $(2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					finish_all = $(eval $(call do_finish_all))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								related_info/lab5/lab5-spoc-discuss/tools/gdbinit
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								related_info/lab5/lab5-spoc-discuss/tools/gdbinit
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					file bin/kernel
 | 
				
			||||||
 | 
					target remote :1234
 | 
				
			||||||
 | 
					break kern_init
 | 
				
			||||||
							
								
								
									
										556
									
								
								related_info/lab5/lab5-spoc-discuss/tools/grade.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										556
									
								
								related_info/lab5/lab5-spoc-discuss/tools/grade.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,556 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					verbose=false
 | 
				
			||||||
 | 
					if [ "x$1" = "x-v" ]; then
 | 
				
			||||||
 | 
					    verbose=true
 | 
				
			||||||
 | 
					    out=/dev/stdout
 | 
				
			||||||
 | 
					    err=/dev/stderr
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    out=/dev/null
 | 
				
			||||||
 | 
					    err=/dev/null
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## make & makeopts
 | 
				
			||||||
 | 
					if gmake --version > /dev/null 2>&1; then
 | 
				
			||||||
 | 
					    make=gmake;
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    make=make;
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					makeopts="--quiet --no-print-directory -j"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					make_print() {
 | 
				
			||||||
 | 
					    echo `$make $makeopts print-$1`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## command tools
 | 
				
			||||||
 | 
					awk='awk'
 | 
				
			||||||
 | 
					bc='bc'
 | 
				
			||||||
 | 
					date='date'
 | 
				
			||||||
 | 
					grep='grep'
 | 
				
			||||||
 | 
					rm='rm -f'
 | 
				
			||||||
 | 
					sed='sed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## symbol table
 | 
				
			||||||
 | 
					sym_table='obj/kernel.sym'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## gdb & gdbopts
 | 
				
			||||||
 | 
					gdb="$(make_print GDB)"
 | 
				
			||||||
 | 
					gdbport='1234'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gdb_in="$(make_print GRADE_GDB_IN)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## qemu & qemuopts
 | 
				
			||||||
 | 
					qemu="$(make_print qemu)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qemu_out="$(make_print GRADE_QEMU_OUT)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if $qemu -nographic -help | grep -q '^-gdb'; then
 | 
				
			||||||
 | 
					    qemugdb="-gdb tcp::$gdbport"
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    qemugdb="-s -p $gdbport"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## default variables
 | 
				
			||||||
 | 
					default_timeout=30
 | 
				
			||||||
 | 
					default_pts=5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pts=5
 | 
				
			||||||
 | 
					part=0
 | 
				
			||||||
 | 
					part_pos=0
 | 
				
			||||||
 | 
					total=0
 | 
				
			||||||
 | 
					total_pos=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## default functions
 | 
				
			||||||
 | 
					update_score() {
 | 
				
			||||||
 | 
					    total=`expr $total + $part`
 | 
				
			||||||
 | 
					    total_pos=`expr $total_pos + $part_pos`
 | 
				
			||||||
 | 
					    part=0
 | 
				
			||||||
 | 
					    part_pos=0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					get_time() {
 | 
				
			||||||
 | 
					    echo `$date +%s.%N 2> /dev/null`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					show_part() {
 | 
				
			||||||
 | 
					    echo "Part $1 Score: $part/$part_pos"
 | 
				
			||||||
 | 
					    echo
 | 
				
			||||||
 | 
					    update_score
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					show_final() {
 | 
				
			||||||
 | 
					    update_score
 | 
				
			||||||
 | 
					    echo "Total Score: $total/$total_pos"
 | 
				
			||||||
 | 
					    if [ $total -lt $total_pos ]; then
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					show_time() {
 | 
				
			||||||
 | 
					    t1=$(get_time)
 | 
				
			||||||
 | 
					    time=`echo "scale=1; ($t1-$t0)/1" | $sed 's/.N/.0/g' | $bc 2> /dev/null`
 | 
				
			||||||
 | 
					    echo "(${time}s)"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					show_build_tag() {
 | 
				
			||||||
 | 
					    echo "$1:" | $awk '{printf "%-24s ", $0}'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					show_check_tag() {
 | 
				
			||||||
 | 
					    echo "$1:" | $awk '{printf "  -%-40s  ", $0}'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					show_msg() {
 | 
				
			||||||
 | 
					    echo $1
 | 
				
			||||||
 | 
					    shift
 | 
				
			||||||
 | 
					    if [ $# -gt 0 ]; then
 | 
				
			||||||
 | 
					        echo "$@" | awk '{printf "   %s\n", $0}'
 | 
				
			||||||
 | 
					        echo
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pass() {
 | 
				
			||||||
 | 
					    show_msg OK "$@"
 | 
				
			||||||
 | 
					    part=`expr $part + $pts`
 | 
				
			||||||
 | 
					    part_pos=`expr $part_pos + $pts`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fail() {
 | 
				
			||||||
 | 
					    show_msg WRONG "$@"
 | 
				
			||||||
 | 
					    part_pos=`expr $part_pos + $pts`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_qemu() {
 | 
				
			||||||
 | 
					    # Run qemu with serial output redirected to $qemu_out. If $brkfun is non-empty,
 | 
				
			||||||
 | 
					    # wait until $brkfun is reached or $timeout expires, then kill QEMU
 | 
				
			||||||
 | 
					    qemuextra=
 | 
				
			||||||
 | 
					    if [ "$brkfun" ]; then
 | 
				
			||||||
 | 
					        qemuextra="-S $qemugdb"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ -z "$timeout" ] || [ $timeout -le 0 ]; then
 | 
				
			||||||
 | 
					        timeout=$default_timeout;
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    t0=$(get_time)
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					        ulimit -t $timeout
 | 
				
			||||||
 | 
					        exec $qemu -nographic $qemuopts -serial file:$qemu_out -monitor null -no-reboot $qemuextra
 | 
				
			||||||
 | 
					    ) > $out 2> $err &
 | 
				
			||||||
 | 
					    pid=$!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # wait for QEMU to start
 | 
				
			||||||
 | 
					    sleep 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ -n "$brkfun" ]; then
 | 
				
			||||||
 | 
					        # find the address of the kernel $brkfun function
 | 
				
			||||||
 | 
					        brkaddr=`$grep " $brkfun\$" $sym_table | $sed -e's/ .*$//g'`
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            echo "target remote localhost:$gdbport"
 | 
				
			||||||
 | 
					            echo "break *0x$brkaddr"
 | 
				
			||||||
 | 
					            echo "continue"
 | 
				
			||||||
 | 
					        ) > $gdb_in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $gdb -batch -nx -x $gdb_in > /dev/null 2>&1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # make sure that QEMU is dead
 | 
				
			||||||
 | 
					        # on OS X, exiting gdb doesn't always exit qemu
 | 
				
			||||||
 | 
					        kill $pid > /dev/null 2>&1
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					build_run() {
 | 
				
			||||||
 | 
					    # usage: build_run <tag> <args>
 | 
				
			||||||
 | 
					    show_build_tag "$1"
 | 
				
			||||||
 | 
					    shift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if $verbose; then
 | 
				
			||||||
 | 
					        echo "$make $@ ..."
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    $make $makeopts $@ 'DEFS+=-DDEBUG_GRADE' > $out 2> $err
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ $? -ne 0 ]; then
 | 
				
			||||||
 | 
					        echo $make $@ failed
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # now run qemu and save the output
 | 
				
			||||||
 | 
					    run_qemu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    show_time
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check_result() {
 | 
				
			||||||
 | 
					    # usage: check_result <tag> <check> <check args...>
 | 
				
			||||||
 | 
					    show_check_tag "$1"
 | 
				
			||||||
 | 
					    shift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # give qemu some time to run (for asynchronous mode)
 | 
				
			||||||
 | 
					    if [ ! -s $qemu_out ]; then
 | 
				
			||||||
 | 
					        sleep 4
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ ! -s $qemu_out ]; then
 | 
				
			||||||
 | 
					        fail > /dev/null
 | 
				
			||||||
 | 
					        echo 'no $qemu_out'
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        check=$1
 | 
				
			||||||
 | 
					        shift
 | 
				
			||||||
 | 
					        $check "$@"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check_regexps() {
 | 
				
			||||||
 | 
					    okay=yes
 | 
				
			||||||
 | 
					    not=0
 | 
				
			||||||
 | 
					    reg=0
 | 
				
			||||||
 | 
					    error=
 | 
				
			||||||
 | 
					    for i do
 | 
				
			||||||
 | 
					        if [ "x$i" = "x!" ]; then
 | 
				
			||||||
 | 
					            not=1
 | 
				
			||||||
 | 
					        elif [ "x$i" = "x-" ]; then
 | 
				
			||||||
 | 
					            reg=1
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            if [ $reg -ne 0 ]; then
 | 
				
			||||||
 | 
					                $grep '-E' "^$i\$" $qemu_out > /dev/null
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                $grep '-F' "$i" $qemu_out > /dev/null
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
 | 
					            found=$(($? == 0))
 | 
				
			||||||
 | 
					            if [ $found -eq $not ]; then
 | 
				
			||||||
 | 
					                if [ $found -eq 0 ]; then
 | 
				
			||||||
 | 
					                    msg="!! error: missing '$i'"
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    msg="!! error: got unexpected line '$i'"
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                okay=no
 | 
				
			||||||
 | 
					                if [ -z "$error" ]; then
 | 
				
			||||||
 | 
					                    error="$msg"
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    error="$error\n$msg"
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
 | 
					            not=0
 | 
				
			||||||
 | 
					            reg=0
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					    done
 | 
				
			||||||
 | 
					    if [ "$okay" = "yes" ]; then
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        fail "$error"
 | 
				
			||||||
 | 
					        if $verbose; then
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test() {
 | 
				
			||||||
 | 
					    # usage: run_test [-tag <tag>] [-prog <prog>] [-Ddef...] [-check <check>] checkargs ...
 | 
				
			||||||
 | 
					    tag=
 | 
				
			||||||
 | 
					    prog=
 | 
				
			||||||
 | 
					    check=check_regexps
 | 
				
			||||||
 | 
					    while true; do
 | 
				
			||||||
 | 
					        select=
 | 
				
			||||||
 | 
					        case $1 in
 | 
				
			||||||
 | 
					            -tag|-prog)
 | 
				
			||||||
 | 
					                select=`expr substr $1 2 ${#1}`
 | 
				
			||||||
 | 
					                eval $select='$2'
 | 
				
			||||||
 | 
					                ;;
 | 
				
			||||||
 | 
					        esac
 | 
				
			||||||
 | 
					        if [ -z "$select" ]; then
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					        shift
 | 
				
			||||||
 | 
					        shift
 | 
				
			||||||
 | 
					    done
 | 
				
			||||||
 | 
					    defs=
 | 
				
			||||||
 | 
					    while expr "x$1" : "x-D.*" > /dev/null; do
 | 
				
			||||||
 | 
					        defs="DEFS+='$1' $defs"
 | 
				
			||||||
 | 
					        shift
 | 
				
			||||||
 | 
					    done
 | 
				
			||||||
 | 
					    if [ "x$1" = "x-check" ]; then
 | 
				
			||||||
 | 
					        check=$2
 | 
				
			||||||
 | 
					        shift
 | 
				
			||||||
 | 
					        shift
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ -z "$prog" ]; then
 | 
				
			||||||
 | 
					        $make $makeopts touch > /dev/null 2>&1
 | 
				
			||||||
 | 
					        args="$defs"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        if [ -z "$tag" ]; then
 | 
				
			||||||
 | 
					            tag="$prog"
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					        args="build-$prog $defs"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    build_run "$tag" "$args"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    check_result 'check result' "$check" "$@"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					quick_run() {
 | 
				
			||||||
 | 
					    # usage: quick_run <tag> [-Ddef...]
 | 
				
			||||||
 | 
					    tag="$1"
 | 
				
			||||||
 | 
					    shift
 | 
				
			||||||
 | 
					    defs=
 | 
				
			||||||
 | 
					    while expr "x$1" : "x-D.*" > /dev/null; do
 | 
				
			||||||
 | 
					        defs="DEFS+='$1' $defs"
 | 
				
			||||||
 | 
					        shift
 | 
				
			||||||
 | 
					    done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $make $makeopts touch > /dev/null 2>&1
 | 
				
			||||||
 | 
					    build_run "$tag" "$defs"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					quick_check() {
 | 
				
			||||||
 | 
					    # usage: quick_check <tag> checkargs ...
 | 
				
			||||||
 | 
					    tag="$1"
 | 
				
			||||||
 | 
					    shift
 | 
				
			||||||
 | 
					    check_result "$tag" check_regexps "$@"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## kernel image
 | 
				
			||||||
 | 
					osimg=$(make_print ucoreimg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## swap image
 | 
				
			||||||
 | 
					swapimg=$(make_print swapimg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## set default qemu-options
 | 
				
			||||||
 | 
					qemuopts="-hda $osimg -drive file=$swapimg,media=disk,cache=writeback"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## set break-function, default is readline
 | 
				
			||||||
 | 
					brkfun=readline
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					default_check() {
 | 
				
			||||||
 | 
					    pts=7
 | 
				
			||||||
 | 
					    check_regexps "$@"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pts=3
 | 
				
			||||||
 | 
					    quick_check 'check output'                                  \
 | 
				
			||||||
 | 
					    'memory management: default_pmm_manager'                      \
 | 
				
			||||||
 | 
					    'check_alloc_page() succeeded!'                             \
 | 
				
			||||||
 | 
					    'check_pgdir() succeeded!'                                  \
 | 
				
			||||||
 | 
					    'check_boot_pgdir() succeeded!'				\
 | 
				
			||||||
 | 
					    'PDE(0e0) c0000000-f8000000 38000000 urw'                   \
 | 
				
			||||||
 | 
					    '  |-- PTE(38000) c0000000-f8000000 38000000 -rw'           \
 | 
				
			||||||
 | 
					    'PDE(001) fac00000-fb000000 00400000 -rw'                   \
 | 
				
			||||||
 | 
					    '  |-- PTE(000e0) faf00000-fafe0000 000e0000 urw'           \
 | 
				
			||||||
 | 
					    '  |-- PTE(00001) fafeb000-fafec000 00001000 -rw'		\
 | 
				
			||||||
 | 
					    'check_slab() succeeded!'					\
 | 
				
			||||||
 | 
					    'check_vma_struct() succeeded!'                             \
 | 
				
			||||||
 | 
					    'page fault at 0x00000100: K/W [no page found].'            \
 | 
				
			||||||
 | 
					    'check_pgfault() succeeded!'                                \
 | 
				
			||||||
 | 
					    'check_vmm() succeeded.'					\
 | 
				
			||||||
 | 
					    'page fault at 0x00001000: K/W [no page found].'            \
 | 
				
			||||||
 | 
					    'page fault at 0x00002000: K/W [no page found].'            \
 | 
				
			||||||
 | 
					    'page fault at 0x00003000: K/W [no page found].'            \
 | 
				
			||||||
 | 
					    'page fault at 0x00004000: K/W [no page found].'            \
 | 
				
			||||||
 | 
					    'write Virt Page e in fifo_check_swap'			\
 | 
				
			||||||
 | 
					    'page fault at 0x00005000: K/W [no page found].'		\
 | 
				
			||||||
 | 
					    'page fault at 0x00001000: K/W [no page found]'		\
 | 
				
			||||||
 | 
					    'page fault at 0x00002000: K/W [no page found].'		\
 | 
				
			||||||
 | 
					    'page fault at 0x00003000: K/W [no page found].'		\
 | 
				
			||||||
 | 
					    'page fault at 0x00004000: K/W [no page found].'		\
 | 
				
			||||||
 | 
					    'check_swap() succeeded!'					\
 | 
				
			||||||
 | 
					    '++ setup timer interrupts'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## check now!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'badsegment' -check default_check                \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "badsegment".'          \
 | 
				
			||||||
 | 
					      - 'trapframe at 0xc.......'                               \
 | 
				
			||||||
 | 
					        'trap 0x0000000d General Protection'                    \
 | 
				
			||||||
 | 
					        '  err  0x00000028'                                     \
 | 
				
			||||||
 | 
					      - '  eip  0x008.....'                                     \
 | 
				
			||||||
 | 
					      - '  esp  0xaff.....'                                     \
 | 
				
			||||||
 | 
					        '  cs   0x----001b'                                     \
 | 
				
			||||||
 | 
					        '  ss   0x----0023'                                     \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'divzero' -check default_check                   \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "divzero".'             \
 | 
				
			||||||
 | 
					      - 'trapframe at 0xc.......'                               \
 | 
				
			||||||
 | 
					        'trap 0x00000000 Divide error'                          \
 | 
				
			||||||
 | 
					      - '  eip  0x008.....'                                     \
 | 
				
			||||||
 | 
					      - '  esp  0xaff.....'                                     \
 | 
				
			||||||
 | 
					        '  cs   0x----001b'                                     \
 | 
				
			||||||
 | 
					        '  ss   0x----0023'                                     \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'softint' -check default_check                   \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "softint".'             \
 | 
				
			||||||
 | 
					      - 'trapframe at 0xc.......'                               \
 | 
				
			||||||
 | 
					        'trap 0x0000000d General Protection'                    \
 | 
				
			||||||
 | 
					        '  err  0x00000072'                                     \
 | 
				
			||||||
 | 
					      - '  eip  0x008.....'                                     \
 | 
				
			||||||
 | 
					      - '  esp  0xaff.....'                                     \
 | 
				
			||||||
 | 
					        '  cs   0x----001b'                                     \
 | 
				
			||||||
 | 
					        '  ss   0x----0023'                                     \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pts=10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'faultread'  -check default_check                                     \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "faultread".'           \
 | 
				
			||||||
 | 
					      - 'trapframe at 0xc.......'                               \
 | 
				
			||||||
 | 
					        'trap 0x0000000e Page Fault'                            \
 | 
				
			||||||
 | 
					        '  err  0x00000004'                                     \
 | 
				
			||||||
 | 
					      - '  eip  0x008.....'                                     \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'faultreadkernel' -check default_check                                \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "faultreadkernel".'     \
 | 
				
			||||||
 | 
					      - 'trapframe at 0xc.......'                               \
 | 
				
			||||||
 | 
					        'trap 0x0000000e Page Fault'                            \
 | 
				
			||||||
 | 
					        '  err  0x00000005'                                     \
 | 
				
			||||||
 | 
					      - '  eip  0x008.....'                                     \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'hello' -check default_check                                          \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "hello".'               \
 | 
				
			||||||
 | 
					        'Hello world!!.'                                        \
 | 
				
			||||||
 | 
					        'I am process 2.'                                       \
 | 
				
			||||||
 | 
					        'hello pass.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'testbss' -check default_check                                        \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "testbss".'             \
 | 
				
			||||||
 | 
					        'Making sure bss works right...'                        \
 | 
				
			||||||
 | 
					        'Yes, good.  Now doing a wild write off the end...'     \
 | 
				
			||||||
 | 
					        'testbss may pass.'                                     \
 | 
				
			||||||
 | 
					      - 'trapframe at 0xc.......'                               \
 | 
				
			||||||
 | 
					        'trap 0x0000000e Page Fault'                            \
 | 
				
			||||||
 | 
					        '  err  0x00000006'                                     \
 | 
				
			||||||
 | 
					      - '  eip  0x008.....'                                     \
 | 
				
			||||||
 | 
					        'killed by kernel.'                                     \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'pgdir' -check default_check                                          \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "pgdir".'               \
 | 
				
			||||||
 | 
					        'I am 2, print pgdir.'                                  \
 | 
				
			||||||
 | 
					        'PDE(001) 00800000-00c00000 00400000 urw'               \
 | 
				
			||||||
 | 
					        '  |-- PTE(00002) 00800000-00802000 00002000 ur-'       \
 | 
				
			||||||
 | 
					        '  |-- PTE(00001) 00802000-00803000 00001000 urw'       \
 | 
				
			||||||
 | 
					        'PDE(001) afc00000-b0000000 00400000 urw'               \
 | 
				
			||||||
 | 
					        '  |-- PTE(00004) afffc000-b0000000 00004000 urw'       \
 | 
				
			||||||
 | 
					        'PDE(0e0) c0000000-f8000000 38000000 urw'               \
 | 
				
			||||||
 | 
					        '  |-- PTE(38000) c0000000-f8000000 38000000 -rw'       \
 | 
				
			||||||
 | 
					        'pgdir pass.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'yield' -check default_check                                          \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "yield".'               \
 | 
				
			||||||
 | 
					        'Hello, I am process 2.'                                \
 | 
				
			||||||
 | 
					        'Back in process 2, iteration 0.'                       \
 | 
				
			||||||
 | 
					        'Back in process 2, iteration 1.'                       \
 | 
				
			||||||
 | 
					        'Back in process 2, iteration 2.'                       \
 | 
				
			||||||
 | 
					        'Back in process 2, iteration 3.'                       \
 | 
				
			||||||
 | 
					        'Back in process 2, iteration 4.'                       \
 | 
				
			||||||
 | 
					        'All done in process 2.'                                \
 | 
				
			||||||
 | 
					        'yield pass.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'badarg' -check default_check                    \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "badarg".'              \
 | 
				
			||||||
 | 
					        'fork ok.'                                              \
 | 
				
			||||||
 | 
					        'badarg pass.'                                          \
 | 
				
			||||||
 | 
					        'all user-mode processes have quit.'                    \
 | 
				
			||||||
 | 
					        'init check memory pass.'                               \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pts=10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'exit'  -check default_check                                          \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "exit".'                \
 | 
				
			||||||
 | 
					        'I am the parent. Forking the child...'                 \
 | 
				
			||||||
 | 
					        'I am the parent, waiting now..'                        \
 | 
				
			||||||
 | 
					        'I am the child.'                                       \
 | 
				
			||||||
 | 
					      - 'waitpid [0-9]+ ok\.'                                   \
 | 
				
			||||||
 | 
					        'exit pass.'                                            \
 | 
				
			||||||
 | 
					        'all user-mode processes have quit.'                    \
 | 
				
			||||||
 | 
					        'init check memory pass.'                               \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'spin'  -check default_check                                          \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "spin".'                \
 | 
				
			||||||
 | 
					        'I am the parent. Forking the child...'                 \
 | 
				
			||||||
 | 
					        'I am the parent. Running the child...'                 \
 | 
				
			||||||
 | 
					        'I am the child. spinning ...'                          \
 | 
				
			||||||
 | 
					        'I am the parent.  Killing the child...'                \
 | 
				
			||||||
 | 
					        'kill returns 0'                                        \
 | 
				
			||||||
 | 
					        'wait returns 0'                                        \
 | 
				
			||||||
 | 
					        'spin may pass.'                                        \
 | 
				
			||||||
 | 
					        'all user-mode processes have quit.'                    \
 | 
				
			||||||
 | 
					        'init check memory pass.'                               \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'waitkill'  -check default_check                                      \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "waitkill".'            \
 | 
				
			||||||
 | 
					        'wait child 1.'                                         \
 | 
				
			||||||
 | 
					        'child 2.'                                              \
 | 
				
			||||||
 | 
					        'child 1.'                                              \
 | 
				
			||||||
 | 
					        'kill parent ok.'                                       \
 | 
				
			||||||
 | 
					        'kill child1 ok.'                                       \
 | 
				
			||||||
 | 
					        'all user-mode processes have quit.'                    \
 | 
				
			||||||
 | 
					        'init check memory pass.'                               \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pts=15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_test -prog 'forktest'   -check default_check                                     \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "forktest".'            \
 | 
				
			||||||
 | 
					        'I am child 31'                                         \
 | 
				
			||||||
 | 
					        'I am child 19'                                         \
 | 
				
			||||||
 | 
					        'I am child 13'                                         \
 | 
				
			||||||
 | 
					        'I am child 0'                                          \
 | 
				
			||||||
 | 
					        'forktest pass.'                                        \
 | 
				
			||||||
 | 
					        'all user-mode processes have quit.'                    \
 | 
				
			||||||
 | 
					        'init check memory pass.'                               \
 | 
				
			||||||
 | 
					    ! - 'fork claimed to work [0-9]+ times!'                    \
 | 
				
			||||||
 | 
					    !   'wait stopped early'                                    \
 | 
				
			||||||
 | 
					    !   'wait got too many'                                     \
 | 
				
			||||||
 | 
					    ! - 'user panic at .*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pts=10
 | 
				
			||||||
 | 
					run_test -prog 'forktree'    -check default_check               \
 | 
				
			||||||
 | 
					        'kernel_execve: pid = 2, name = "forktree".'            \
 | 
				
			||||||
 | 
					      - '....: I am '\'''\'                                     \
 | 
				
			||||||
 | 
					      - '....: I am '\''0'\'                                    \
 | 
				
			||||||
 | 
					      - '....: I am '\'''\'                                     \
 | 
				
			||||||
 | 
					      - '....: I am '\''1'\'                                    \
 | 
				
			||||||
 | 
					      - '....: I am '\''0'\'                                    \
 | 
				
			||||||
 | 
					      - '....: I am '\''01'\'                                   \
 | 
				
			||||||
 | 
					      - '....: I am '\''00'\'                                   \
 | 
				
			||||||
 | 
					      - '....: I am '\''11'\'                                   \
 | 
				
			||||||
 | 
					      - '....: I am '\''10'\'                                   \
 | 
				
			||||||
 | 
					      - '....: I am '\''101'\'                                  \
 | 
				
			||||||
 | 
					      - '....: I am '\''100'\'                                  \
 | 
				
			||||||
 | 
					      - '....: I am '\''111'\'                                  \
 | 
				
			||||||
 | 
					      - '....: I am '\''110'\'                                  \
 | 
				
			||||||
 | 
					      - '....: I am '\''001'\'                                  \
 | 
				
			||||||
 | 
					      - '....: I am '\''000'\'                                  \
 | 
				
			||||||
 | 
					      - '....: I am '\''011'\'                                  \
 | 
				
			||||||
 | 
					      - '....: I am '\''010'\'                                  \
 | 
				
			||||||
 | 
					      - '....: I am '\''0101'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''0100'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''0111'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''0110'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''0001'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''0000'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''0011'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''0010'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''1101'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''1100'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''1111'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''1110'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''1001'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''1000'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''1011'\'                                 \
 | 
				
			||||||
 | 
					      - '....: I am '\''1010'\'                                 \
 | 
				
			||||||
 | 
					        'all user-mode processes have quit.'                    \
 | 
				
			||||||
 | 
					        'init check memory pass.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## print final-score
 | 
				
			||||||
 | 
					show_final
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										58
									
								
								related_info/lab5/lab5-spoc-discuss/tools/kernel.ld
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								related_info/lab5/lab5-spoc-discuss/tools/kernel.ld
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					/* Simple linker script for the ucore kernel.
 | 
				
			||||||
 | 
					   See the GNU ld 'info' manual ("info ld") to learn the syntax. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 | 
				
			||||||
 | 
					OUTPUT_ARCH(i386)
 | 
				
			||||||
 | 
					ENTRY(kern_entry)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SECTIONS {
 | 
				
			||||||
 | 
					    /* Load the kernel at this address: "." means the current address */
 | 
				
			||||||
 | 
					    . = 0xC0100000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .text : {
 | 
				
			||||||
 | 
					        *(.text .stub .text.* .gnu.linkonce.t.*)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PROVIDE(etext = .); /* Define the 'etext' symbol to this value */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .rodata : {
 | 
				
			||||||
 | 
					        *(.rodata .rodata.* .gnu.linkonce.r.*)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Include debugging information in kernel memory */
 | 
				
			||||||
 | 
					    .stab : {
 | 
				
			||||||
 | 
					        PROVIDE(__STAB_BEGIN__ = .);
 | 
				
			||||||
 | 
					        *(.stab);
 | 
				
			||||||
 | 
					        PROVIDE(__STAB_END__ = .);
 | 
				
			||||||
 | 
					        BYTE(0)     /* Force the linker to allocate space
 | 
				
			||||||
 | 
					                   for this section */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .stabstr : {
 | 
				
			||||||
 | 
					        PROVIDE(__STABSTR_BEGIN__ = .);
 | 
				
			||||||
 | 
					        *(.stabstr);
 | 
				
			||||||
 | 
					        PROVIDE(__STABSTR_END__ = .);
 | 
				
			||||||
 | 
					        BYTE(0)     /* Force the linker to allocate space
 | 
				
			||||||
 | 
					                   for this section */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Adjust the address for the data segment to the next page */
 | 
				
			||||||
 | 
					    . = ALIGN(0x1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* The data segment */
 | 
				
			||||||
 | 
					    .data : {
 | 
				
			||||||
 | 
					        *(.data)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PROVIDE(edata = .);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .bss : {
 | 
				
			||||||
 | 
					        *(.bss)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PROVIDE(end = .);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /DISCARD/ : {
 | 
				
			||||||
 | 
					        *(.eh_frame .note.GNU-stack)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								related_info/lab5/lab5-spoc-discuss/tools/sign.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								related_info/lab5/lab5-spoc-discuss/tools/sign.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(int argc, char *argv[]) {
 | 
				
			||||||
 | 
					    struct stat st;
 | 
				
			||||||
 | 
					    if (argc != 3) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Usage: <input filename> <output filename>\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (stat(argv[1], &st) != 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Error opening file '%s': %s\n", argv[1], strerror(errno));
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("'%s' size: %lld bytes\n", argv[1], (long long)st.st_size);
 | 
				
			||||||
 | 
					    if (st.st_size > 510) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "%lld >> 510!!\n", (long long)st.st_size);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    char buf[512];
 | 
				
			||||||
 | 
					    memset(buf, 0, sizeof(buf));
 | 
				
			||||||
 | 
					    FILE *ifp = fopen(argv[1], "rb");
 | 
				
			||||||
 | 
					    int size = fread(buf, 1, st.st_size, ifp);
 | 
				
			||||||
 | 
					    if (size != st.st_size) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "read '%s' error, size is %d.\n", argv[1], size);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fclose(ifp);
 | 
				
			||||||
 | 
					    buf[510] = 0x55;
 | 
				
			||||||
 | 
					    buf[511] = 0xAA;
 | 
				
			||||||
 | 
					    FILE *ofp = fopen(argv[2], "wb+");
 | 
				
			||||||
 | 
					    size = fwrite(buf, 1, 512, ofp);
 | 
				
			||||||
 | 
					    if (size != 512) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "write '%s' error, size is %d.\n", argv[2], size);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fclose(ofp);
 | 
				
			||||||
 | 
					    printf("build 512 bytes boot sector: '%s' success!\n", argv[2]);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										71
									
								
								related_info/lab5/lab5-spoc-discuss/tools/user.ld
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								related_info/lab5/lab5-spoc-discuss/tools/user.ld
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					/* Simple linker script for ucore user-level programs.
 | 
				
			||||||
 | 
					   See the GNU ld 'info' manual ("info ld") to learn the syntax. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 | 
				
			||||||
 | 
					OUTPUT_ARCH(i386)
 | 
				
			||||||
 | 
					ENTRY(_start)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SECTIONS {
 | 
				
			||||||
 | 
					    /* Load programs at this address: "." means the current address */
 | 
				
			||||||
 | 
					    . = 0x800020;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .text : {
 | 
				
			||||||
 | 
					        *(.text .stub .text.* .gnu.linkonce.t.*)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PROVIDE(etext = .); /* Define the 'etext' symbol to this value */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .rodata : {
 | 
				
			||||||
 | 
					        *(.rodata .rodata.* .gnu.linkonce.r.*)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Adjust the address for the data segment to the next page */
 | 
				
			||||||
 | 
					    . = ALIGN(0x1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .data : {
 | 
				
			||||||
 | 
					        *(.data)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PROVIDE(edata = .);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .bss : {
 | 
				
			||||||
 | 
					        *(.bss)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PROVIDE(end = .);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Place debugging symbols so that they can be found by
 | 
				
			||||||
 | 
					     * the kernel debugger.
 | 
				
			||||||
 | 
					     * Specifically, the four words at 0x200000 mark the beginning of
 | 
				
			||||||
 | 
					     * the stabs, the end of the stabs, the beginning of the stabs
 | 
				
			||||||
 | 
					     * string table, and the end of the stabs string table, respectively.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .stab_info 0x200000 : {
 | 
				
			||||||
 | 
					        LONG(__STAB_BEGIN__);
 | 
				
			||||||
 | 
					        LONG(__STAB_END__);
 | 
				
			||||||
 | 
					        LONG(__STABSTR_BEGIN__);
 | 
				
			||||||
 | 
					        LONG(__STABSTR_END__);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .stab : {
 | 
				
			||||||
 | 
					        __STAB_BEGIN__ = DEFINED(__STAB_BEGIN__) ? __STAB_BEGIN__ : .;
 | 
				
			||||||
 | 
					        *(.stab);
 | 
				
			||||||
 | 
					        __STAB_END__ = DEFINED(__STAB_END__) ? __STAB_END__ : .;
 | 
				
			||||||
 | 
					        BYTE(0)     /* Force the linker to allocate space
 | 
				
			||||||
 | 
					                   for this section */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .stabstr : {
 | 
				
			||||||
 | 
					        __STABSTR_BEGIN__ = DEFINED(__STABSTR_BEGIN__) ? __STABSTR_BEGIN__ : .;
 | 
				
			||||||
 | 
					        *(.stabstr);
 | 
				
			||||||
 | 
					        __STABSTR_END__ = DEFINED(__STABSTR_END__) ? __STABSTR_END__ : .;
 | 
				
			||||||
 | 
					        BYTE(0)     /* Force the linker to allocate space
 | 
				
			||||||
 | 
					                   for this section */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /DISCARD/ : {
 | 
				
			||||||
 | 
					        *(.eh_frame .note.GNU-stack .comment)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								related_info/lab5/lab5-spoc-discuss/tools/vector.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								related_info/lab5/lab5-spoc-discuss/tools/vector.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    printf("# handler\n");
 | 
				
			||||||
 | 
					    printf(".text\n");
 | 
				
			||||||
 | 
					    printf(".globl __alltraps\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; i < 256; i ++) {
 | 
				
			||||||
 | 
					        printf(".globl vector%d\n", i);
 | 
				
			||||||
 | 
					        printf("vector%d:\n", i);
 | 
				
			||||||
 | 
					        if ((i < 8 || i > 14) && i != 17) {
 | 
				
			||||||
 | 
					            printf("  pushl $0\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        printf("  pushl $%d\n", i);
 | 
				
			||||||
 | 
					        printf("  jmp __alltraps\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("\n");
 | 
				
			||||||
 | 
					    printf("# vector table\n");
 | 
				
			||||||
 | 
					    printf(".data\n");
 | 
				
			||||||
 | 
					    printf(".globl __vectors\n");
 | 
				
			||||||
 | 
					    printf("__vectors:\n");
 | 
				
			||||||
 | 
					    for (i = 0; i < 256; i ++) {
 | 
				
			||||||
 | 
					        printf("  .long vector%d\n", i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								related_info/lab5/lab5-spoc-discuss/user/badarg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								related_info/lab5/lab5-spoc-discuss/user/badarg.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    int pid, exit_code;
 | 
				
			||||||
 | 
					    if ((pid = fork()) == 0) {
 | 
				
			||||||
 | 
					        cprintf("fork ok.\n");
 | 
				
			||||||
 | 
					        int i;
 | 
				
			||||||
 | 
					        for (i = 0; i < 10; i ++) {
 | 
				
			||||||
 | 
					            yield();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        exit(0xbeaf);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(pid > 0);
 | 
				
			||||||
 | 
					    assert(waitpid(-1, NULL) != 0);
 | 
				
			||||||
 | 
					    assert(waitpid(pid, (void *)0xC0000000) != 0);
 | 
				
			||||||
 | 
					    assert(waitpid(pid, &exit_code) == 0 && exit_code == 0xbeaf);
 | 
				
			||||||
 | 
					    cprintf("badarg pass.\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/user/badsegment.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/user/badsegment.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* try to load the kernel's TSS selector into the DS register */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    asm volatile("movw $0x28,%ax; movw %ax,%ds");
 | 
				
			||||||
 | 
					    panic("FAIL: T.T\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/user/divzero.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/user/divzero.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    cprintf("value is %d.\n", 1 / zero);
 | 
				
			||||||
 | 
					    panic("FAIL: T.T\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								related_info/lab5/lab5-spoc-discuss/user/exit.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								related_info/lab5/lab5-spoc-discuss/user/exit.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int magic = -0x10384;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    int pid, code;
 | 
				
			||||||
 | 
					    cprintf("I am the parent. Forking the child...\n");
 | 
				
			||||||
 | 
					    if ((pid = fork()) == 0) {
 | 
				
			||||||
 | 
					        cprintf("I am the child.\n");
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
 | 
					        exit(magic);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        cprintf("I am parent, fork a child pid %d\n",pid);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(pid > 0);
 | 
				
			||||||
 | 
					    cprintf("I am the parent, waiting now..\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(waitpid(pid, &code) == 0 && code == magic);
 | 
				
			||||||
 | 
					    assert(waitpid(pid, &code) != 0 && wait() != 0);
 | 
				
			||||||
 | 
					    cprintf("waitpid %d ok.\n", pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("exit pass.\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								related_info/lab5/lab5-spoc-discuss/user/faultread.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								related_info/lab5/lab5-spoc-discuss/user/faultread.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    cprintf("I read %8x from 0.\n", *(unsigned int *)0);
 | 
				
			||||||
 | 
					    panic("FAIL: T.T\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    cprintf("I read %08x from 0xfac00000!\n", *(unsigned *)0xfac00000);
 | 
				
			||||||
 | 
					    panic("FAIL: T.T\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								related_info/lab5/lab5-spoc-discuss/user/forktest.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								related_info/lab5/lab5-spoc-discuss/user/forktest.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const int max_child = 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    int n, pid;
 | 
				
			||||||
 | 
					    for (n = 0; n < max_child; n ++) {
 | 
				
			||||||
 | 
					        if ((pid = fork()) == 0) {
 | 
				
			||||||
 | 
					            cprintf("I am child %d\n", n);
 | 
				
			||||||
 | 
					            exit(0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        assert(pid > 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (n > max_child) {
 | 
				
			||||||
 | 
					        panic("fork claimed to work %d times!\n", n);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (; n > 0; n --) {
 | 
				
			||||||
 | 
					        if (wait() != 0) {
 | 
				
			||||||
 | 
					            panic("wait stopped early\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (wait() == 0) {
 | 
				
			||||||
 | 
					        panic("wait got too many\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cprintf("forktest pass.\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										37
									
								
								related_info/lab5/lab5-spoc-discuss/user/forktree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								related_info/lab5/lab5-spoc-discuss/user/forktree.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEPTH 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void forktree(const char *cur);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					forkchild(const char *cur, char branch) {
 | 
				
			||||||
 | 
					    char nxt[DEPTH + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (strlen(cur) >= DEPTH)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snprintf(nxt, DEPTH + 1, "%s%c", cur, branch);
 | 
				
			||||||
 | 
					    if (fork() == 0) {
 | 
				
			||||||
 | 
					        forktree(nxt);
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
 | 
					        exit(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					forktree(const char *cur) {
 | 
				
			||||||
 | 
					    cprintf("%04x: I am '%s'\n", getpid(), cur);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    forkchild(cur, '0');
 | 
				
			||||||
 | 
					    forkchild(cur, '1');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    forktree("");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/user/hello.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/user/hello.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    cprintf("Hello world!!.\n");
 | 
				
			||||||
 | 
					    cprintf("I am process %d.\n", getpid());
 | 
				
			||||||
 | 
					    cprintf("hello pass.\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/initcode.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/initcode.S
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					.text
 | 
				
			||||||
 | 
					.globl _start
 | 
				
			||||||
 | 
					_start:
 | 
				
			||||||
 | 
					    # set ebp for backtrace
 | 
				
			||||||
 | 
					    movl $0x0, %ebp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # move down the esp register
 | 
				
			||||||
 | 
					    # since it may cause page fault in backtrace
 | 
				
			||||||
 | 
					    subl $0x20, %esp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # call user-program function
 | 
				
			||||||
 | 
					    call umain
 | 
				
			||||||
 | 
					1:  jmp 1b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										28
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/panic.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/panic.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					#include <error.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					__panic(const char *file, int line, const char *fmt, ...) {
 | 
				
			||||||
 | 
					    // print the 'message'
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    va_start(ap, fmt);
 | 
				
			||||||
 | 
					    cprintf("user panic at %s:%d:\n    ", file, line);
 | 
				
			||||||
 | 
					    vcprintf(fmt, ap);
 | 
				
			||||||
 | 
					    cprintf("\n");
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					    exit(-E_PANIC);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					__warn(const char *file, int line, const char *fmt, ...) {
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    va_start(ap, fmt);
 | 
				
			||||||
 | 
					    cprintf("user warning at %s:%d:\n    ", file, line);
 | 
				
			||||||
 | 
					    vcprintf(fmt, ap);
 | 
				
			||||||
 | 
					    cprintf("\n");
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										62
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/stdio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/stdio.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <syscall.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * cputch - writes a single character @c to stdout, and it will
 | 
				
			||||||
 | 
					 * increace the value of counter pointed by @cnt.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					cputch(int c, int *cnt) {
 | 
				
			||||||
 | 
					    sys_putc(c);
 | 
				
			||||||
 | 
					    (*cnt) ++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * vcprintf - format a string and writes it to stdout
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The return value is the number of characters which would be
 | 
				
			||||||
 | 
					 * written to stdout.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Call this function if you are already dealing with a va_list.
 | 
				
			||||||
 | 
					 * Or you probably want cprintf() instead.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					vcprintf(const char *fmt, va_list ap) {
 | 
				
			||||||
 | 
					    int cnt = 0;
 | 
				
			||||||
 | 
					    vprintfmt((void*)cputch, &cnt, fmt, ap);
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * cprintf - formats a string and writes it to stdout
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The return value is the number of characters which would be
 | 
				
			||||||
 | 
					 * written to stdout.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cprintf(const char *fmt, ...) {
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    va_start(ap, fmt);
 | 
				
			||||||
 | 
					    int cnt = vcprintf(fmt, ap);
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *
 | 
				
			||||||
 | 
					 * cputs- writes the string pointed by @str to stdout and
 | 
				
			||||||
 | 
					 * appends a newline character.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					cputs(const char *str) {
 | 
				
			||||||
 | 
					    int cnt = 0;
 | 
				
			||||||
 | 
					    char c;
 | 
				
			||||||
 | 
					    while ((c = *str ++) != '\0') {
 | 
				
			||||||
 | 
					        cputch(c, &cnt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cputch('\n', &cnt);
 | 
				
			||||||
 | 
					    return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										72
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/syscall.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/syscall.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <syscall.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_ARGS            5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					syscall(int num, ...) {
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    va_start(ap, num);
 | 
				
			||||||
 | 
					    uint32_t a[MAX_ARGS];
 | 
				
			||||||
 | 
					    int i, ret;
 | 
				
			||||||
 | 
					    for (i = 0; i < MAX_ARGS; i ++) {
 | 
				
			||||||
 | 
					        a[i] = va_arg(ap, uint32_t);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    asm volatile (
 | 
				
			||||||
 | 
					        "int %1;"
 | 
				
			||||||
 | 
					        : "=a" (ret)
 | 
				
			||||||
 | 
					        : "i" (T_SYSCALL),
 | 
				
			||||||
 | 
					          "a" (num),
 | 
				
			||||||
 | 
					          "d" (a[0]),
 | 
				
			||||||
 | 
					          "c" (a[1]),
 | 
				
			||||||
 | 
					          "b" (a[2]),
 | 
				
			||||||
 | 
					          "D" (a[3]),
 | 
				
			||||||
 | 
					          "S" (a[4])
 | 
				
			||||||
 | 
					        : "cc", "memory");
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sys_exit(int error_code) {
 | 
				
			||||||
 | 
					    return syscall(SYS_exit, error_code);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sys_fork(void) {
 | 
				
			||||||
 | 
					    return syscall(SYS_fork);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sys_wait(int pid, int *store) {
 | 
				
			||||||
 | 
					    return syscall(SYS_wait, pid, store);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sys_yield(void) {
 | 
				
			||||||
 | 
					    return syscall(SYS_yield);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sys_kill(int pid) {
 | 
				
			||||||
 | 
					    return syscall(SYS_kill, pid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sys_getpid(void) {
 | 
				
			||||||
 | 
					    return syscall(SYS_getpid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sys_putc(int c) {
 | 
				
			||||||
 | 
					    return syscall(SYS_putc, c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					sys_pgdir(void) {
 | 
				
			||||||
 | 
					    return syscall(SYS_pgdir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/syscall.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/syscall.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					#ifndef __USER_LIBS_SYSCALL_H__
 | 
				
			||||||
 | 
					#define __USER_LIBS_SYSCALL_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sys_exit(int error_code);
 | 
				
			||||||
 | 
					int sys_fork(void);
 | 
				
			||||||
 | 
					int sys_wait(int pid, int *store);
 | 
				
			||||||
 | 
					int sys_yield(void);
 | 
				
			||||||
 | 
					int sys_kill(int pid);
 | 
				
			||||||
 | 
					int sys_getpid(void);
 | 
				
			||||||
 | 
					int sys_putc(int c);
 | 
				
			||||||
 | 
					int sys_pgdir(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__USER_LIBS_SYSCALL_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										48
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/ulib.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/ulib.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					#include <syscall.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					exit(int error_code) {
 | 
				
			||||||
 | 
					    sys_exit(error_code);
 | 
				
			||||||
 | 
					    cprintf("BUG: exit failed.\n");
 | 
				
			||||||
 | 
					    while (1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					fork(void) {
 | 
				
			||||||
 | 
					    return sys_fork();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					wait(void) {
 | 
				
			||||||
 | 
					    return sys_wait(0, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					waitpid(int pid, int *store) {
 | 
				
			||||||
 | 
					    return sys_wait(pid, store);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					yield(void) {
 | 
				
			||||||
 | 
					    sys_yield();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					kill(int pid) {
 | 
				
			||||||
 | 
					    return sys_kill(pid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					getpid(void) {
 | 
				
			||||||
 | 
					    return sys_getpid();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//print_pgdir - print the PDT&PT
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					print_pgdir(void) {
 | 
				
			||||||
 | 
					    sys_pgdir();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										36
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/ulib.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/ulib.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					#ifndef __USER_LIBS_ULIB_H__
 | 
				
			||||||
 | 
					#define __USER_LIBS_ULIB_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __warn(const char *file, int line, const char *fmt, ...);
 | 
				
			||||||
 | 
					void __noreturn __panic(const char *file, int line, const char *fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define warn(...)                                       \
 | 
				
			||||||
 | 
					    __warn(__FILE__, __LINE__, __VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define panic(...)                                      \
 | 
				
			||||||
 | 
					    __panic(__FILE__, __LINE__, __VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define assert(x)                                       \
 | 
				
			||||||
 | 
					    do {                                                \
 | 
				
			||||||
 | 
					        if (!(x)) {                                     \
 | 
				
			||||||
 | 
					            panic("assertion failed: %s", #x);          \
 | 
				
			||||||
 | 
					        }                                               \
 | 
				
			||||||
 | 
					    } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static_assert(x) will generate a compile-time error if 'x' is false.
 | 
				
			||||||
 | 
					#define static_assert(x)                                \
 | 
				
			||||||
 | 
					    switch (x) { case 0: case (x): ; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __noreturn exit(int error_code);
 | 
				
			||||||
 | 
					int fork(void);
 | 
				
			||||||
 | 
					int wait(void);
 | 
				
			||||||
 | 
					int waitpid(int pid, int *store);
 | 
				
			||||||
 | 
					void yield(void);
 | 
				
			||||||
 | 
					int kill(int pid);
 | 
				
			||||||
 | 
					int getpid(void);
 | 
				
			||||||
 | 
					void print_pgdir(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__USER_LIBS_ULIB_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/umain.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								related_info/lab5/lab5-spoc-discuss/user/libs/umain.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					umain(void) {
 | 
				
			||||||
 | 
					    int ret = main();
 | 
				
			||||||
 | 
					    exit(ret);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/user/pgdir.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								related_info/lab5/lab5-spoc-discuss/user/pgdir.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    cprintf("I am %d, print pgdir.\n", getpid());
 | 
				
			||||||
 | 
					    print_pgdir();
 | 
				
			||||||
 | 
					    cprintf("pgdir pass.\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								related_info/lab5/lab5-spoc-discuss/user/softint.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								related_info/lab5/lab5-spoc-discuss/user/softint.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <ulib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(void) {
 | 
				
			||||||
 | 
					    asm volatile("int $14");
 | 
				
			||||||
 | 
					    panic("FAIL: T.T\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user