Initial Upload
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
|||||||
|
*.asm
|
||||||
|
*.d
|
||||||
|
*.sym
|
||||||
|
_*
|
||||||
|
kernel
|
||||||
|
user1
|
||||||
|
userfs
|
||||||
|
usertests
|
||||||
|
xv6.img
|
||||||
|
vectors.S
|
||||||
|
bochsout.txt
|
||||||
|
bootblock
|
||||||
|
bootother
|
||||||
|
bootother.out
|
||||||
|
parport.out
|
||||||
|
fmt
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
((c-mode
|
||||||
|
(indent-tabs-mode . nil)
|
||||||
|
(c-file-style . "bsd")
|
||||||
|
(c-basic-offset . 2)))
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
set $lastcs = -1
|
||||||
|
|
||||||
|
define hook-stop
|
||||||
|
# There doesn't seem to be a good way to detect if we're in 16- or
|
||||||
|
# 32-bit mode, but in 32-bit mode we always run with CS == 8 in the
|
||||||
|
# kernel and CS == 35 in user space
|
||||||
|
if $cs == 8 || $cs == 35
|
||||||
|
if $lastcs != 8 && $lastcs != 35
|
||||||
|
set architecture i386
|
||||||
|
end
|
||||||
|
x/i $pc
|
||||||
|
else
|
||||||
|
if $lastcs == -1 || $lastcs == 8 || $lastcs == 35
|
||||||
|
set architecture i8086
|
||||||
|
end
|
||||||
|
# Translate the segment:offset into a physical address
|
||||||
|
printf "[%4x:%4x] ", $cs, $eip
|
||||||
|
x/i $cs*16+$eip
|
||||||
|
end
|
||||||
|
set $lastcs = $cs
|
||||||
|
end
|
||||||
|
|
||||||
|
echo + target remote localhost:1234\n
|
||||||
|
target remote localhost:1234
|
||||||
|
|
||||||
|
echo + symbol-file kernel\n
|
||||||
|
symbol-file kernel
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*.img filter=lfs diff=lfs merge=lfs -text
|
||||||
Vendored
+28
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "(gdb) Launch",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/kernel",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": true,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+35
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Build Xv6 operating system",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make",
|
||||||
|
"problemMatcher": [],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run Xv6 under QEMU",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make qemu",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run Xv6 under QEMU for debugging",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make qemu-gdb",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Clean non-source files",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make clean",
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
The xv6 software is:
|
||||||
|
|
||||||
|
Copyright (c) 2006-2018 Frans Kaashoek, Robert Morris, Russ Cox,
|
||||||
|
Massachusetts Institute of Technology
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
OBJS = \
|
||||||
|
bio.o\
|
||||||
|
console.o\
|
||||||
|
exec.o\
|
||||||
|
file.o\
|
||||||
|
fs.o\
|
||||||
|
ide.o\
|
||||||
|
ioapic.o\
|
||||||
|
kalloc.o\
|
||||||
|
kbd.o\
|
||||||
|
lapic.o\
|
||||||
|
log.o\
|
||||||
|
main.o\
|
||||||
|
mp.o\
|
||||||
|
picirq.o\
|
||||||
|
pipe.o\
|
||||||
|
proc.o\
|
||||||
|
sleeplock.o\
|
||||||
|
spinlock.o\
|
||||||
|
string.o\
|
||||||
|
swtch.o\
|
||||||
|
syscall.o\
|
||||||
|
sysfile.o\
|
||||||
|
sysproc.o\
|
||||||
|
trapasm.o\
|
||||||
|
trap.o\
|
||||||
|
uart.o\
|
||||||
|
vectors.o\
|
||||||
|
vm.o\
|
||||||
|
|
||||||
|
# Cross-compiling (e.g., on Mac OS X)
|
||||||
|
# TOOLPREFIX = i386-jos-elf
|
||||||
|
|
||||||
|
# Using native tools (e.g., on X86 Linux)
|
||||||
|
#TOOLPREFIX =
|
||||||
|
|
||||||
|
# Try to infer the correct TOOLPREFIX if not set
|
||||||
|
ifndef TOOLPREFIX
|
||||||
|
TOOLPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
|
||||||
|
then echo 'i386-jos-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-*-elf version of GCC/binutils." 1>&2; \
|
||||||
|
echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \
|
||||||
|
echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \
|
||||||
|
echo "*** prefix other than 'i386-jos-elf-', set your TOOLPREFIX" 1>&2; \
|
||||||
|
echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
|
||||||
|
echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; \
|
||||||
|
echo "***" 1>&2; exit 1; fi)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# If the makefile can't find QEMU, specify its path here
|
||||||
|
# QEMU = qemu-system-i386
|
||||||
|
|
||||||
|
# Try to infer the correct QEMU
|
||||||
|
ifndef QEMU
|
||||||
|
QEMU = $(shell if which qemu > /dev/null; \
|
||||||
|
then echo qemu; exit; \
|
||||||
|
elif which qemu-system-i386 > /dev/null; \
|
||||||
|
then echo qemu-system-i386; exit; \
|
||||||
|
elif which qemu-system-x86_64 > /dev/null; \
|
||||||
|
then echo qemu-system-x86_64; exit; \
|
||||||
|
else \
|
||||||
|
qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; \
|
||||||
|
if test -x $$qemu; then echo $$qemu; exit; fi; fi; \
|
||||||
|
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 "*** or have you tried setting the QEMU variable in Makefile?" 1>&2; \
|
||||||
|
echo "***" 1>&2; exit 1)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CC = $(TOOLPREFIX)gcc
|
||||||
|
AS = $(TOOLPREFIX)gas
|
||||||
|
LD = $(TOOLPREFIX)ld
|
||||||
|
OBJCOPY = $(TOOLPREFIX)objcopy
|
||||||
|
OBJDUMP = $(TOOLPREFIX)objdump
|
||||||
|
CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer
|
||||||
|
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
|
||||||
|
ASFLAGS = -m32 -gdwarf-2 -Wa,-divide
|
||||||
|
# FreeBSD ld wants ``elf_i386_fbsd''
|
||||||
|
LDFLAGS += -m $(shell $(LD) -V | grep elf_i386 2>/dev/null | head -n 1)
|
||||||
|
|
||||||
|
# Disable PIE when possible (for Ubuntu 16.10 toolchain)
|
||||||
|
ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
||||||
|
CFLAGS += -fno-pie -no-pie
|
||||||
|
endif
|
||||||
|
ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]nopie'),)
|
||||||
|
CFLAGS += -fno-pie -nopie
|
||||||
|
endif
|
||||||
|
|
||||||
|
xv6.img: bootblock kernel
|
||||||
|
dd if=/dev/zero of=xv6.img count=10000
|
||||||
|
dd if=bootblock of=xv6.img conv=notrunc
|
||||||
|
dd if=kernel of=xv6.img seek=1 conv=notrunc
|
||||||
|
|
||||||
|
xv6memfs.img: bootblock kernelmemfs
|
||||||
|
dd if=/dev/zero of=xv6memfs.img count=10000
|
||||||
|
dd if=bootblock of=xv6memfs.img conv=notrunc
|
||||||
|
dd if=kernelmemfs of=xv6memfs.img seek=1 conv=notrunc
|
||||||
|
|
||||||
|
bootblock: bootasm.S bootmain.c
|
||||||
|
$(CC) $(CFLAGS) -fno-pic -O -nostdinc -I. -c bootmain.c
|
||||||
|
$(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm.S
|
||||||
|
$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o
|
||||||
|
$(OBJDUMP) -S bootblock.o > bootblock.asm
|
||||||
|
$(OBJCOPY) -S -O binary -j .text bootblock.o bootblock
|
||||||
|
# The following line is here since it has been noticed that if you use Explorer to
|
||||||
|
# copy folders on wsl, sometimees the execute permissions can be removed from perl scripts.
|
||||||
|
# Uncomment if needed, but it will flag as a change for git.
|
||||||
|
# chmod +x sign.pl
|
||||||
|
./sign.pl bootblock
|
||||||
|
|
||||||
|
syscall.h: gensyscalls.pl
|
||||||
|
./gensyscalls.pl -h > syscall.h
|
||||||
|
|
||||||
|
syscalltable.h: gensyscalls.pl
|
||||||
|
./gensyscalls.pl -c > syscalltable.h
|
||||||
|
|
||||||
|
usys.S: gensyscalls.pl
|
||||||
|
./gensyscalls.pl -a > usys.S
|
||||||
|
|
||||||
|
entryother: entryother.S
|
||||||
|
$(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c entryother.S
|
||||||
|
$(LD) $(LDFLAGS) -N -e start -Ttext 0x7000 -o bootblockother.o entryother.o
|
||||||
|
$(OBJCOPY) -S -O binary -j .text bootblockother.o entryother
|
||||||
|
$(OBJDUMP) -S bootblockother.o > entryother.asm
|
||||||
|
|
||||||
|
initcode: initcode.S
|
||||||
|
$(CC) $(CFLAGS) -nostdinc -I. -c initcode.S
|
||||||
|
$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o
|
||||||
|
$(OBJCOPY) -S -O binary initcode.out initcode
|
||||||
|
$(OBJDUMP) -S initcode.o > initcode.asm
|
||||||
|
|
||||||
|
kernel: syscall.h syscalltable.h $(OBJS) entry.o entryother initcode kernel.ld
|
||||||
|
$(LD) $(LDFLAGS) -T kernel.ld -o kernel entry.o $(OBJS) -b binary initcode entryother
|
||||||
|
$(OBJDUMP) -S kernel > kernel.asm
|
||||||
|
$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym
|
||||||
|
|
||||||
|
# kernelmemfs is a copy of kernel that maintains the
|
||||||
|
# disk image in memory instead of writing to a disk.
|
||||||
|
# This is not so useful for testing persistent storage or
|
||||||
|
# exploring disk buffering implementations, but it is
|
||||||
|
# great for testing the kernel on real hardware without
|
||||||
|
# needing a scratch disk.
|
||||||
|
MEMFSOBJS = $(filter-out ide.o,$(OBJS)) memide.o
|
||||||
|
kernelmemfs: $(MEMFSOBJS) entry.o entryother initcode kernel.ld fs.img
|
||||||
|
$(LD) $(LDFLAGS) -T kernel.ld -o kernelmemfs entry.o $(MEMFSOBJS) -b binary initcode entryother fs.img
|
||||||
|
$(OBJDUMP) -S kernelmemfs > kernelmemfs.asm
|
||||||
|
$(OBJDUMP) -t kernelmemfs | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernelmemfs.sym
|
||||||
|
|
||||||
|
tags: $(OBJS) entryother.S _init
|
||||||
|
etags *.S *.c
|
||||||
|
|
||||||
|
vectors.S: vectors.pl
|
||||||
|
# chmod +x vectors.pl
|
||||||
|
./vectors.pl > vectors.S
|
||||||
|
|
||||||
|
ULIB = ulib.o usys.o printf.o umalloc.o
|
||||||
|
|
||||||
|
_%: %.o $(ULIB)
|
||||||
|
$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^
|
||||||
|
$(OBJDUMP) -S $@ > $*.asm
|
||||||
|
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
|
||||||
|
|
||||||
|
_forktest: forktest.o $(ULIB)
|
||||||
|
# forktest has less library code linked in - needs to be small
|
||||||
|
# in order to be able to max out the proc table.
|
||||||
|
$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o _forktest forktest.o ulib.o usys.o
|
||||||
|
$(OBJDUMP) -S _forktest > forktest.asm
|
||||||
|
|
||||||
|
mkfs: mkfs.c fs.h
|
||||||
|
gcc -Werror -Wall -o mkfs mkfs.c
|
||||||
|
|
||||||
|
# Prevent deletion of intermediate files, e.g. cat.o, after first build, so
|
||||||
|
# that disk image changes after first build are persistent until clean. More
|
||||||
|
# details:
|
||||||
|
# http://www.gnu.org/software/make/manual/html_node/Chained-Rules.html
|
||||||
|
.PRECIOUS: %.o
|
||||||
|
|
||||||
|
UPROGS=\
|
||||||
|
_cat\
|
||||||
|
_echo\
|
||||||
|
_forktest\
|
||||||
|
_grep\
|
||||||
|
_init\
|
||||||
|
_kill\
|
||||||
|
_ln\
|
||||||
|
_ls\
|
||||||
|
_mkdir\
|
||||||
|
_rm\
|
||||||
|
_sh\
|
||||||
|
_stressfs\
|
||||||
|
_usertests\
|
||||||
|
_wc\
|
||||||
|
_zombie\
|
||||||
|
_hello\
|
||||||
|
_shutdown\
|
||||||
|
_argtest\
|
||||||
|
_screen\
|
||||||
|
|
||||||
|
fs.img: mkfs $(UPROGS)
|
||||||
|
./mkfs fs.img $(UPROGS)
|
||||||
|
|
||||||
|
-include *.d
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
|
||||||
|
*.o *.d *.asm *.sym vectors.S bootblock entryother \
|
||||||
|
initcode initcode.out kernel xv6.img fs.img kernelmemfs \
|
||||||
|
xv6memfs.img mkfs .gdbinit \
|
||||||
|
syscall.h syscalltable.h usys.S \
|
||||||
|
$(UPROGS)
|
||||||
|
|
||||||
|
# run in emulators
|
||||||
|
|
||||||
|
# try to generate a unique GDB port
|
||||||
|
GDBPORT = $(shell expr `id -u` % 5000 + 25000)
|
||||||
|
# QEMU's gdb stub command line changed in 0.11
|
||||||
|
QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \
|
||||||
|
then echo "-gdb tcp::$(GDBPORT)"; \
|
||||||
|
else echo "-s -p $(GDBPORT)"; fi)
|
||||||
|
ifndef CPUS
|
||||||
|
CPUS := 2
|
||||||
|
endif
|
||||||
|
QEMUOPTS = -drive file=fs.img,index=1,media=disk,format=raw -drive file=xv6.img,index=0,media=disk,format=raw -smp $(CPUS) -m 512 $(QEMUEXTRA)
|
||||||
|
|
||||||
|
qemu: fs.img xv6.img
|
||||||
|
$(QEMU) -vga std -serial mon:stdio $(QEMUOPTS)
|
||||||
|
|
||||||
|
qemu-memfs: xv6memfs.img
|
||||||
|
$(QEMU) -vga std -drive file=xv6memfs.img,index=0,media=disk,format=raw -smp $(CPUS) -m 256
|
||||||
|
|
||||||
|
qemu-nox: fs.img xv6.img
|
||||||
|
$(QEMU) -nographic $(QEMUOPTS)
|
||||||
|
|
||||||
|
qemu-curses: fs.img xv6.img
|
||||||
|
$(QEMU) -curses $(QEMUOPTS)
|
||||||
|
|
||||||
|
.gdbinit: .gdbinit.tmpl
|
||||||
|
sed "s/localhost:1234/localhost:$(GDBPORT)/" < $^ > $@
|
||||||
|
|
||||||
|
qemu-gdb: fs.img xv6.img .gdbinit
|
||||||
|
@echo "*** Now run 'gdb'." 1>&2
|
||||||
|
$(QEMU) -vga std -serial mon:stdio $(QEMUOPTS) -S $(QEMUGDB)
|
||||||
|
|
||||||
|
qemu-nox-gdb: fs.img xv6.img .gdbinit
|
||||||
|
@echo "*** Now run 'gdb'." 1>&2
|
||||||
|
$(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB)
|
||||||
BIN
Binary file not shown.
+1162
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
printf(1, "Arg %d: %s\n", i, argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit();
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
00000000 argtest.c
|
||||||
|
00000000 ulib.c
|
||||||
|
00000000 printf.c
|
||||||
|
00000360 printint
|
||||||
|
000007a4 digits.0
|
||||||
|
00000000 umalloc.c
|
||||||
|
00000a58 freep
|
||||||
|
00000a5c base
|
||||||
|
00000050 strcpy
|
||||||
|
00000410 printf
|
||||||
|
0000034b greeting
|
||||||
|
00000270 memmove
|
||||||
|
0000031b mknod
|
||||||
|
00000170 gets
|
||||||
|
000002eb getpid
|
||||||
|
00000640 malloc
|
||||||
|
000002fb sleep
|
||||||
|
000002b3 pipe
|
||||||
|
00000343 getch
|
||||||
|
00000313 write
|
||||||
|
000002d3 fstat
|
||||||
|
000002c3 kill
|
||||||
|
000002db chdir
|
||||||
|
000002cb exec
|
||||||
|
000002ab wait
|
||||||
|
000002bb read
|
||||||
|
00000323 unlink
|
||||||
|
0000029b fork
|
||||||
|
000002f3 sbrk
|
||||||
|
00000303 uptime
|
||||||
|
00000a58 __bss_start
|
||||||
|
00000110 memset
|
||||||
|
00000000 main
|
||||||
|
00000080 strcmp
|
||||||
|
00000353 shutdown
|
||||||
|
000002e3 dup
|
||||||
|
000001e0 stat
|
||||||
|
00000a58 _edata
|
||||||
|
00000a64 _end
|
||||||
|
0000032b link
|
||||||
|
000002a3 exit
|
||||||
|
00000230 atoi
|
||||||
|
000000e0 strlen
|
||||||
|
0000030b open
|
||||||
|
00000130 strchr
|
||||||
|
00000333 mkdir
|
||||||
|
0000033b close
|
||||||
|
000005b0 free
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// assembler macros to create x86 segments
|
||||||
|
//
|
||||||
|
|
||||||
|
#define SEG_NULLASM \
|
||||||
|
.word 0, 0; \
|
||||||
|
.byte 0, 0, 0, 0
|
||||||
|
|
||||||
|
// The 0xC0 means the limit is in 4096-byte units
|
||||||
|
// and (for executable segments) 32-bit mode.
|
||||||
|
#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)
|
||||||
|
|
||||||
|
#define STA_X 0x8 // Executable segment
|
||||||
|
#define STA_W 0x2 // Writeable (non-executable segments)
|
||||||
|
#define STA_R 0x2 // Readable (executable segments)
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
// Buffer cache.
|
||||||
|
//
|
||||||
|
// The buffer cache is a linked list of buf structures holding
|
||||||
|
// cached copies of disk block contents. Caching disk blocks
|
||||||
|
// in memory reduces the number of disk reads and also provides
|
||||||
|
// a synchronization point for disk blocks used by multiple processes.
|
||||||
|
//
|
||||||
|
// Interface:
|
||||||
|
// * To get a buffer for a particular disk block, call bread.
|
||||||
|
// * After changing buffer data, call bwrite to write it to disk.
|
||||||
|
// * When done with the buffer, call brelse.
|
||||||
|
// * Do not use the buffer after calling brelse.
|
||||||
|
// * Only one process at a time can use a buffer,
|
||||||
|
// so do not keep them longer than necessary.
|
||||||
|
//
|
||||||
|
// The implementation uses two state flags internally:
|
||||||
|
// * B_VALID: the buffer data has been read from the disk.
|
||||||
|
// * B_DIRTY: the buffer data has been modified
|
||||||
|
// and needs to be written to disk.
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "defs.h"
|
||||||
|
#include "param.h"
|
||||||
|
#include "spinlock.h"
|
||||||
|
#include "sleeplock.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "buf.h"
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct spinlock lock;
|
||||||
|
struct buf buf[NBUF];
|
||||||
|
|
||||||
|
// Linked list of all buffers, through prev/next.
|
||||||
|
// head.next is most recently used.
|
||||||
|
struct buf head;
|
||||||
|
} bcache;
|
||||||
|
|
||||||
|
void binit(void) {
|
||||||
|
struct buf *b;
|
||||||
|
|
||||||
|
initlock(&bcache.lock, "bcache");
|
||||||
|
|
||||||
|
// Create linked list of buffers
|
||||||
|
bcache.head.prev = &bcache.head;
|
||||||
|
bcache.head.next = &bcache.head;
|
||||||
|
for (b = bcache.buf; b < bcache.buf + NBUF; b++) {
|
||||||
|
b->next = bcache.head.next;
|
||||||
|
b->prev = &bcache.head;
|
||||||
|
initsleeplock(&b->lock, "buffer");
|
||||||
|
bcache.head.next->prev = b;
|
||||||
|
bcache.head.next = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look through buffer cache for block on device dev.
|
||||||
|
// If not found, allocate a buffer.
|
||||||
|
// In either case, return locked buffer.
|
||||||
|
|
||||||
|
static struct buf* bget(uint dev, uint blockno) {
|
||||||
|
struct buf *b;
|
||||||
|
|
||||||
|
acquire(&bcache.lock);
|
||||||
|
|
||||||
|
// Is the block already cached?
|
||||||
|
for (b = bcache.head.next; b != &bcache.head; b = b->next) {
|
||||||
|
if (b->dev == dev && b->blockno == blockno) {
|
||||||
|
b->refcnt++;
|
||||||
|
release(&bcache.lock);
|
||||||
|
acquiresleep(&b->lock);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not cached; recycle an unused buffer.
|
||||||
|
// Even if refcnt==0, B_DIRTY indicates a buffer is in use
|
||||||
|
// because log.c has modified it but not yet committed it.
|
||||||
|
|
||||||
|
for (b = bcache.head.prev; b != &bcache.head; b = b->prev) {
|
||||||
|
if (b->refcnt == 0 && (b->flags & B_DIRTY) == 0) {
|
||||||
|
b->dev = dev;
|
||||||
|
b->blockno = blockno;
|
||||||
|
b->flags = 0;
|
||||||
|
b->refcnt = 1;
|
||||||
|
release(&bcache.lock);
|
||||||
|
acquiresleep(&b->lock);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("bget: no buffers");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a locked buf with the contents of the indicated block.
|
||||||
|
|
||||||
|
struct buf*bread(uint dev, uint blockno) {
|
||||||
|
struct buf *b;
|
||||||
|
|
||||||
|
b = bget(dev, blockno);
|
||||||
|
if ((b->flags & B_VALID) == 0) {
|
||||||
|
iderw(b);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write b's contents to disk. Must be locked.
|
||||||
|
|
||||||
|
void bwrite(struct buf *b) {
|
||||||
|
if (!holdingsleep(&b->lock)) {
|
||||||
|
panic("bwrite");
|
||||||
|
}
|
||||||
|
b->flags |= B_DIRTY;
|
||||||
|
iderw(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release a locked buffer.
|
||||||
|
// Move to the head of the MRU list.
|
||||||
|
|
||||||
|
void brelse(struct buf *b) {
|
||||||
|
if (!holdingsleep(&b->lock)) {
|
||||||
|
panic("brelse");
|
||||||
|
}
|
||||||
|
|
||||||
|
releasesleep(&b->lock);
|
||||||
|
|
||||||
|
acquire(&bcache.lock);
|
||||||
|
b->refcnt--;
|
||||||
|
if (b->refcnt == 0) {
|
||||||
|
// no one is waiting for it.
|
||||||
|
b->next->prev = b->prev;
|
||||||
|
b->prev->next = b->next;
|
||||||
|
b->next = bcache.head.next;
|
||||||
|
b->prev = &bcache.head;
|
||||||
|
bcache.head.next->prev = b;
|
||||||
|
bcache.head.next = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
release(&bcache.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bio.o: bio.c /usr/include/stdc-predef.h types.h defs.h param.h spinlock.h \
|
||||||
|
sleeplock.h fs.h buf.h
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#include "asm.h"
|
||||||
|
#include "memlayout.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
|
||||||
|
# Start the first 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.
|
||||||
|
|
||||||
|
.code16 # Assemble for 16-bit mode
|
||||||
|
.globl start
|
||||||
|
start:
|
||||||
|
cli # BIOS enabled interrupts; disable
|
||||||
|
|
||||||
|
# Zero data segment registers DS, ES, and SS.
|
||||||
|
xorw %ax,%ax # Set %ax to zero
|
||||||
|
movw %ax,%ds # -> Data Segment
|
||||||
|
movw %ax,%es # -> Extra Segment
|
||||||
|
movw %ax,%ss # -> Stack Segment
|
||||||
|
|
||||||
|
# Physical address line A20 is tied to zero so that the first PCs
|
||||||
|
# with 2 MB would run software that assumed 1 MB. Undo that.
|
||||||
|
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
|
||||||
|
|
||||||
|
# Switch from real to protected mode. Use a bootstrap GDT that makes
|
||||||
|
# virtual addresses map directly to physical addresses so that the
|
||||||
|
# effective memory map doesn't change during the transition.
|
||||||
|
lgdt gdtdesc
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $CR0_PE, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
# Complete the transition to 32-bit protected mode by using a long jmp
|
||||||
|
# to reload %cs and %eip. The segment descriptors are set up with no
|
||||||
|
# translation, so that the mapping is still the identity mapping.
|
||||||
|
ljmp $(SEG_KCODE<<3), $start32
|
||||||
|
|
||||||
|
.code32 # Tell assembler to generate 32-bit code now.
|
||||||
|
start32:
|
||||||
|
# Set up the protected-mode data segment registers
|
||||||
|
movw $(SEG_KDATA<<3), %ax # Our data segment selector
|
||||||
|
movw %ax, %ds # -> DS: Data Segment
|
||||||
|
movw %ax, %es # -> ES: Extra Segment
|
||||||
|
movw %ax, %ss # -> SS: Stack Segment
|
||||||
|
movw $0, %ax # Zero segments not ready for use
|
||||||
|
movw %ax, %fs # -> FS
|
||||||
|
movw %ax, %gs # -> GS
|
||||||
|
|
||||||
|
# Set up the stack pointer and call into C.
|
||||||
|
movl $start, %esp
|
||||||
|
call bootmain
|
||||||
|
|
||||||
|
# If bootmain returns (it shouldn't), loop.
|
||||||
|
spin:
|
||||||
|
jmp spin
|
||||||
|
|
||||||
|
# Bootstrap GDT
|
||||||
|
.p2align 2 # force 4 byte alignment
|
||||||
|
gdt:
|
||||||
|
SEG_NULLASM # null seg
|
||||||
|
SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg
|
||||||
|
SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg
|
||||||
|
|
||||||
|
gdtdesc:
|
||||||
|
.word (gdtdesc - gdt - 1) # sizeof(gdt) - 1
|
||||||
|
.long gdt # address gdt
|
||||||
|
|
||||||
+341
@@ -0,0 +1,341 @@
|
|||||||
|
|
||||||
|
bootblock.o: file format elf32-i386
|
||||||
|
|
||||||
|
|
||||||
|
Disassembly of section .text:
|
||||||
|
|
||||||
|
00007c00 <start>:
|
||||||
|
# with %cs=0 %ip=7c00.
|
||||||
|
|
||||||
|
.code16 # Assemble for 16-bit mode
|
||||||
|
.globl start
|
||||||
|
start:
|
||||||
|
cli # BIOS enabled interrupts; disable
|
||||||
|
7c00: fa cli
|
||||||
|
|
||||||
|
# Zero data segment registers DS, ES, and SS.
|
||||||
|
xorw %ax,%ax # Set %ax to zero
|
||||||
|
7c01: 31 c0 xor %eax,%eax
|
||||||
|
movw %ax,%ds # -> Data Segment
|
||||||
|
7c03: 8e d8 mov %eax,%ds
|
||||||
|
movw %ax,%es # -> Extra Segment
|
||||||
|
7c05: 8e c0 mov %eax,%es
|
||||||
|
movw %ax,%ss # -> Stack Segment
|
||||||
|
7c07: 8e d0 mov %eax,%ss
|
||||||
|
|
||||||
|
00007c09 <seta20.1>:
|
||||||
|
|
||||||
|
# Physical address line A20 is tied to zero so that the first PCs
|
||||||
|
# with 2 MB would run software that assumed 1 MB. Undo that.
|
||||||
|
seta20.1:
|
||||||
|
inb $0x64,%al # Wait for not busy
|
||||||
|
7c09: e4 64 in $0x64,%al
|
||||||
|
testb $0x2,%al
|
||||||
|
7c0b: a8 02 test $0x2,%al
|
||||||
|
jnz seta20.1
|
||||||
|
7c0d: 75 fa jne 7c09 <seta20.1>
|
||||||
|
|
||||||
|
movb $0xd1,%al # 0xd1 -> port 0x64
|
||||||
|
7c0f: b0 d1 mov $0xd1,%al
|
||||||
|
outb %al,$0x64
|
||||||
|
7c11: e6 64 out %al,$0x64
|
||||||
|
|
||||||
|
00007c13 <seta20.2>:
|
||||||
|
|
||||||
|
seta20.2:
|
||||||
|
inb $0x64,%al # Wait for not busy
|
||||||
|
7c13: e4 64 in $0x64,%al
|
||||||
|
testb $0x2,%al
|
||||||
|
7c15: a8 02 test $0x2,%al
|
||||||
|
jnz seta20.2
|
||||||
|
7c17: 75 fa jne 7c13 <seta20.2>
|
||||||
|
|
||||||
|
movb $0xdf,%al # 0xdf -> port 0x60
|
||||||
|
7c19: b0 df mov $0xdf,%al
|
||||||
|
outb %al,$0x60
|
||||||
|
7c1b: e6 60 out %al,$0x60
|
||||||
|
|
||||||
|
# Switch from real to protected mode. Use a bootstrap GDT that makes
|
||||||
|
# virtual addresses map directly to physical addresses so that the
|
||||||
|
# effective memory map doesn't change during the transition.
|
||||||
|
lgdt gdtdesc
|
||||||
|
7c1d: 0f 01 16 lgdtl (%esi)
|
||||||
|
7c20: 68 7c 0f 20 c0 push $0xc0200f7c
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $CR0_PE, %eax
|
||||||
|
7c25: 66 83 c8 01 or $0x1,%ax
|
||||||
|
movl %eax, %cr0
|
||||||
|
7c29: 0f 22 c0 mov %eax,%cr0
|
||||||
|
|
||||||
|
# Complete the transition to 32-bit protected mode by using a long jmp
|
||||||
|
# to reload %cs and %eip. The segment descriptors are set up with no
|
||||||
|
# translation, so that the mapping is still the identity mapping.
|
||||||
|
ljmp $(SEG_KCODE<<3), $start32
|
||||||
|
7c2c: ea .byte 0xea
|
||||||
|
7c2d: 31 7c 08 00 xor %edi,0x0(%eax,%ecx,1)
|
||||||
|
|
||||||
|
00007c31 <start32>:
|
||||||
|
|
||||||
|
.code32 # Tell assembler to generate 32-bit code now.
|
||||||
|
start32:
|
||||||
|
# Set up the protected-mode data segment registers
|
||||||
|
movw $(SEG_KDATA<<3), %ax # Our data segment selector
|
||||||
|
7c31: 66 b8 10 00 mov $0x10,%ax
|
||||||
|
movw %ax, %ds # -> DS: Data Segment
|
||||||
|
7c35: 8e d8 mov %eax,%ds
|
||||||
|
movw %ax, %es # -> ES: Extra Segment
|
||||||
|
7c37: 8e c0 mov %eax,%es
|
||||||
|
movw %ax, %ss # -> SS: Stack Segment
|
||||||
|
7c39: 8e d0 mov %eax,%ss
|
||||||
|
movw $0, %ax # Zero segments not ready for use
|
||||||
|
7c3b: 66 b8 00 00 mov $0x0,%ax
|
||||||
|
movw %ax, %fs # -> FS
|
||||||
|
7c3f: 8e e0 mov %eax,%fs
|
||||||
|
movw %ax, %gs # -> GS
|
||||||
|
7c41: 8e e8 mov %eax,%gs
|
||||||
|
|
||||||
|
# Set up the stack pointer and call into C.
|
||||||
|
movl $start, %esp
|
||||||
|
7c43: bc 00 7c 00 00 mov $0x7c00,%esp
|
||||||
|
call bootmain
|
||||||
|
7c48: e8 e0 00 00 00 call 7d2d <bootmain>
|
||||||
|
|
||||||
|
00007c4d <spin>:
|
||||||
|
|
||||||
|
# If bootmain returns (it shouldn't), loop.
|
||||||
|
spin:
|
||||||
|
jmp spin
|
||||||
|
7c4d: eb fe jmp 7c4d <spin>
|
||||||
|
7c4f: 90 nop
|
||||||
|
|
||||||
|
00007c50 <gdt>:
|
||||||
|
...
|
||||||
|
7c58: ff (bad)
|
||||||
|
7c59: ff 00 incl (%eax)
|
||||||
|
7c5b: 00 00 add %al,(%eax)
|
||||||
|
7c5d: 9a cf 00 ff ff 00 00 lcall $0x0,$0xffff00cf
|
||||||
|
7c64: 00 .byte 0x0
|
||||||
|
7c65: 92 xchg %eax,%edx
|
||||||
|
7c66: cf iret
|
||||||
|
...
|
||||||
|
|
||||||
|
00007c68 <gdtdesc>:
|
||||||
|
7c68: 17 pop %ss
|
||||||
|
7c69: 00 50 7c add %dl,0x7c(%eax)
|
||||||
|
...
|
||||||
|
|
||||||
|
00007c6e <waitdisk>:
|
||||||
|
// Routines to let C code use special x86 instructions.
|
||||||
|
|
||||||
|
static inline uchar inb(ushort port) {
|
||||||
|
uchar data;
|
||||||
|
|
||||||
|
asm volatile ("in %1,%0" : "=a" (data) : "d" (port));
|
||||||
|
7c6e: ba f7 01 00 00 mov $0x1f7,%edx
|
||||||
|
7c73: ec in (%dx),%al
|
||||||
|
entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitdisk(void) {
|
||||||
|
// Wait for disk ready.
|
||||||
|
while ((inb(0x1F7) & 0xC0) != 0x40) {
|
||||||
|
7c74: 83 e0 c0 and $0xffffffc0,%eax
|
||||||
|
7c77: 3c 40 cmp $0x40,%al
|
||||||
|
7c79: 75 f8 jne 7c73 <waitdisk+0x5>
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
7c7b: c3 ret
|
||||||
|
|
||||||
|
00007c7c <readsect>:
|
||||||
|
|
||||||
|
// Read a single sector at offset into dst.
|
||||||
|
void readsect(void *dst, uint offset) {
|
||||||
|
7c7c: 55 push %ebp
|
||||||
|
7c7d: 89 e5 mov %esp,%ebp
|
||||||
|
7c7f: 57 push %edi
|
||||||
|
7c80: 53 push %ebx
|
||||||
|
7c81: 8b 5d 0c mov 0xc(%ebp),%ebx
|
||||||
|
// Issue command.
|
||||||
|
waitdisk();
|
||||||
|
7c84: e8 e5 ff ff ff call 7c6e <waitdisk>
|
||||||
|
"d" (port), "0" (addr), "1" (cnt) :
|
||||||
|
"memory", "cc");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void outb(ushort port, uchar data) {
|
||||||
|
asm volatile ("out %0,%1" : : "a" (data), "d" (port));
|
||||||
|
7c89: b8 01 00 00 00 mov $0x1,%eax
|
||||||
|
7c8e: ba f2 01 00 00 mov $0x1f2,%edx
|
||||||
|
7c93: ee out %al,(%dx)
|
||||||
|
7c94: ba f3 01 00 00 mov $0x1f3,%edx
|
||||||
|
7c99: 89 d8 mov %ebx,%eax
|
||||||
|
7c9b: ee out %al,(%dx)
|
||||||
|
outb(0x1F2, 1); // count = 1
|
||||||
|
outb(0x1F3, offset);
|
||||||
|
outb(0x1F4, offset >> 8);
|
||||||
|
7c9c: 89 d8 mov %ebx,%eax
|
||||||
|
7c9e: c1 e8 08 shr $0x8,%eax
|
||||||
|
7ca1: ba f4 01 00 00 mov $0x1f4,%edx
|
||||||
|
7ca6: ee out %al,(%dx)
|
||||||
|
outb(0x1F5, offset >> 16);
|
||||||
|
7ca7: 89 d8 mov %ebx,%eax
|
||||||
|
7ca9: c1 e8 10 shr $0x10,%eax
|
||||||
|
7cac: ba f5 01 00 00 mov $0x1f5,%edx
|
||||||
|
7cb1: ee out %al,(%dx)
|
||||||
|
outb(0x1F6, (offset >> 24) | 0xE0);
|
||||||
|
7cb2: 89 d8 mov %ebx,%eax
|
||||||
|
7cb4: c1 e8 18 shr $0x18,%eax
|
||||||
|
7cb7: 83 c8 e0 or $0xffffffe0,%eax
|
||||||
|
7cba: ba f6 01 00 00 mov $0x1f6,%edx
|
||||||
|
7cbf: ee out %al,(%dx)
|
||||||
|
7cc0: b8 20 00 00 00 mov $0x20,%eax
|
||||||
|
7cc5: ba f7 01 00 00 mov $0x1f7,%edx
|
||||||
|
7cca: ee out %al,(%dx)
|
||||||
|
outb(0x1F7, 0x20); // cmd 0x20 - read sectors
|
||||||
|
|
||||||
|
// Read data.
|
||||||
|
waitdisk();
|
||||||
|
7ccb: e8 9e ff ff ff call 7c6e <waitdisk>
|
||||||
|
asm volatile ("cld; rep insl" :
|
||||||
|
7cd0: 8b 7d 08 mov 0x8(%ebp),%edi
|
||||||
|
7cd3: b9 80 00 00 00 mov $0x80,%ecx
|
||||||
|
7cd8: ba f0 01 00 00 mov $0x1f0,%edx
|
||||||
|
7cdd: fc cld
|
||||||
|
7cde: f3 6d rep insl (%dx),%es:(%edi)
|
||||||
|
insl(0x1F0, dst, SECTSIZE / 4);
|
||||||
|
}
|
||||||
|
7ce0: 5b pop %ebx
|
||||||
|
7ce1: 5f pop %edi
|
||||||
|
7ce2: 5d pop %ebp
|
||||||
|
7ce3: c3 ret
|
||||||
|
|
||||||
|
00007ce4 <readseg>:
|
||||||
|
|
||||||
|
// Read 'count' bytes at 'offset' from kernel into physical address 'pa'.
|
||||||
|
// Might copy more than asked.
|
||||||
|
|
||||||
|
void readseg(uchar* pa, uint count, uint offset) {
|
||||||
|
7ce4: 55 push %ebp
|
||||||
|
7ce5: 89 e5 mov %esp,%ebp
|
||||||
|
7ce7: 57 push %edi
|
||||||
|
7ce8: 56 push %esi
|
||||||
|
7ce9: 53 push %ebx
|
||||||
|
7cea: 83 ec 0c sub $0xc,%esp
|
||||||
|
7ced: 8b 5d 08 mov 0x8(%ebp),%ebx
|
||||||
|
7cf0: 8b 75 10 mov 0x10(%ebp),%esi
|
||||||
|
uchar* epa;
|
||||||
|
|
||||||
|
epa = pa + count;
|
||||||
|
7cf3: 89 df mov %ebx,%edi
|
||||||
|
7cf5: 03 7d 0c add 0xc(%ebp),%edi
|
||||||
|
|
||||||
|
// Round down to sector boundary.
|
||||||
|
pa -= offset % SECTSIZE;
|
||||||
|
7cf8: 89 f0 mov %esi,%eax
|
||||||
|
7cfa: 25 ff 01 00 00 and $0x1ff,%eax
|
||||||
|
7cff: 29 c3 sub %eax,%ebx
|
||||||
|
|
||||||
|
// Translate from bytes to sectors; kernel starts at sector 1.
|
||||||
|
offset = (offset / SECTSIZE) + 1;
|
||||||
|
7d01: c1 ee 09 shr $0x9,%esi
|
||||||
|
7d04: 83 c6 01 add $0x1,%esi
|
||||||
|
|
||||||
|
// 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 (; pa < epa; pa += SECTSIZE, offset++) {
|
||||||
|
7d07: 39 df cmp %ebx,%edi
|
||||||
|
7d09: 76 1a jbe 7d25 <readseg+0x41>
|
||||||
|
readsect(pa, offset);
|
||||||
|
7d0b: 83 ec 08 sub $0x8,%esp
|
||||||
|
7d0e: 56 push %esi
|
||||||
|
7d0f: 53 push %ebx
|
||||||
|
7d10: e8 67 ff ff ff call 7c7c <readsect>
|
||||||
|
for (; pa < epa; pa += SECTSIZE, offset++) {
|
||||||
|
7d15: 81 c3 00 02 00 00 add $0x200,%ebx
|
||||||
|
7d1b: 83 c6 01 add $0x1,%esi
|
||||||
|
7d1e: 83 c4 10 add $0x10,%esp
|
||||||
|
7d21: 39 df cmp %ebx,%edi
|
||||||
|
7d23: 77 e6 ja 7d0b <readseg+0x27>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
7d25: 8d 65 f4 lea -0xc(%ebp),%esp
|
||||||
|
7d28: 5b pop %ebx
|
||||||
|
7d29: 5e pop %esi
|
||||||
|
7d2a: 5f pop %edi
|
||||||
|
7d2b: 5d pop %ebp
|
||||||
|
7d2c: c3 ret
|
||||||
|
|
||||||
|
00007d2d <bootmain>:
|
||||||
|
void bootmain(void) {
|
||||||
|
7d2d: 55 push %ebp
|
||||||
|
7d2e: 89 e5 mov %esp,%ebp
|
||||||
|
7d30: 57 push %edi
|
||||||
|
7d31: 56 push %esi
|
||||||
|
7d32: 53 push %ebx
|
||||||
|
7d33: 83 ec 10 sub $0x10,%esp
|
||||||
|
readseg((uchar*)elf, 4096, 0);
|
||||||
|
7d36: 6a 00 push $0x0
|
||||||
|
7d38: 68 00 10 00 00 push $0x1000
|
||||||
|
7d3d: 68 00 00 01 00 push $0x10000
|
||||||
|
7d42: e8 9d ff ff ff call 7ce4 <readseg>
|
||||||
|
if (elf->magic != ELF_MAGIC) {
|
||||||
|
7d47: 83 c4 10 add $0x10,%esp
|
||||||
|
7d4a: 81 3d 00 00 01 00 7f cmpl $0x464c457f,0x10000
|
||||||
|
7d51: 45 4c 46
|
||||||
|
7d54: 75 21 jne 7d77 <bootmain+0x4a>
|
||||||
|
ph = (struct proghdr*)((uchar*)elf + elf->phoff);
|
||||||
|
7d56: a1 1c 00 01 00 mov 0x1001c,%eax
|
||||||
|
7d5b: 8d 98 00 00 01 00 lea 0x10000(%eax),%ebx
|
||||||
|
eph = ph + elf->phnum;
|
||||||
|
7d61: 0f b7 35 2c 00 01 00 movzwl 0x1002c,%esi
|
||||||
|
7d68: c1 e6 05 shl $0x5,%esi
|
||||||
|
7d6b: 01 de add %ebx,%esi
|
||||||
|
for (; ph < eph; ph++) {
|
||||||
|
7d6d: 39 f3 cmp %esi,%ebx
|
||||||
|
7d6f: 72 15 jb 7d86 <bootmain+0x59>
|
||||||
|
entry();
|
||||||
|
7d71: ff 15 18 00 01 00 call *0x10018
|
||||||
|
}
|
||||||
|
7d77: 8d 65 f4 lea -0xc(%ebp),%esp
|
||||||
|
7d7a: 5b pop %ebx
|
||||||
|
7d7b: 5e pop %esi
|
||||||
|
7d7c: 5f pop %edi
|
||||||
|
7d7d: 5d pop %ebp
|
||||||
|
7d7e: c3 ret
|
||||||
|
for (; ph < eph; ph++) {
|
||||||
|
7d7f: 83 c3 20 add $0x20,%ebx
|
||||||
|
7d82: 39 de cmp %ebx,%esi
|
||||||
|
7d84: 76 eb jbe 7d71 <bootmain+0x44>
|
||||||
|
pa = (uchar*)ph->paddr;
|
||||||
|
7d86: 8b 7b 0c mov 0xc(%ebx),%edi
|
||||||
|
readseg(pa, ph->filesz, ph->off);
|
||||||
|
7d89: 83 ec 04 sub $0x4,%esp
|
||||||
|
7d8c: ff 73 04 push 0x4(%ebx)
|
||||||
|
7d8f: ff 73 10 push 0x10(%ebx)
|
||||||
|
7d92: 57 push %edi
|
||||||
|
7d93: e8 4c ff ff ff call 7ce4 <readseg>
|
||||||
|
if (ph->memsz > ph->filesz) {
|
||||||
|
7d98: 8b 4b 14 mov 0x14(%ebx),%ecx
|
||||||
|
7d9b: 8b 43 10 mov 0x10(%ebx),%eax
|
||||||
|
7d9e: 83 c4 10 add $0x10,%esp
|
||||||
|
7da1: 39 c1 cmp %eax,%ecx
|
||||||
|
7da3: 76 da jbe 7d7f <bootmain+0x52>
|
||||||
|
stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz);
|
||||||
|
7da5: 01 c7 add %eax,%edi
|
||||||
|
7da7: 29 c1 sub %eax,%ecx
|
||||||
|
"d" (port), "0" (addr), "1" (cnt) :
|
||||||
|
"cc");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void stosb(void *addr, int data, int cnt) {
|
||||||
|
asm volatile ("cld; rep stosb" :
|
||||||
|
7da9: b8 00 00 00 00 mov $0x0,%eax
|
||||||
|
7dae: fc cld
|
||||||
|
7daf: f3 aa rep stos %al,%es:(%edi)
|
||||||
|
"=D" (addr), "=c" (cnt) :
|
||||||
|
"0" (addr), "1" (cnt), "a" (data) :
|
||||||
|
"memory", "cc");
|
||||||
|
}
|
||||||
|
7db1: eb cc jmp 7d7f <bootmain+0x52>
|
||||||
BIN
Binary file not shown.
Binary file not shown.
+93
@@ -0,0 +1,93 @@
|
|||||||
|
// Boot loader.
|
||||||
|
//
|
||||||
|
// Part of the boot block, along with bootasm.S, which calls bootmain().
|
||||||
|
// bootasm.S has put the processor into protected 32-bit mode.
|
||||||
|
// bootmain() loads an ELF kernel image from the disk starting at
|
||||||
|
// sector 1 and then jumps to the kernel entry routine.
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "elf.h"
|
||||||
|
#include "x86.h"
|
||||||
|
#include "memlayout.h"
|
||||||
|
|
||||||
|
#define SECTSIZE 512
|
||||||
|
|
||||||
|
void readseg(uchar*, uint, uint);
|
||||||
|
|
||||||
|
void bootmain(void) {
|
||||||
|
struct elfhdr *elf;
|
||||||
|
struct proghdr *ph, *eph;
|
||||||
|
void (*entry)(void);
|
||||||
|
uchar* pa;
|
||||||
|
|
||||||
|
elf = (struct elfhdr*)0x10000; // scratch space
|
||||||
|
|
||||||
|
// Read 1st page off disk
|
||||||
|
readseg((uchar*)elf, 4096, 0);
|
||||||
|
|
||||||
|
// Is this an ELF executable?
|
||||||
|
if (elf->magic != ELF_MAGIC) {
|
||||||
|
return; // let bootasm.S handle error
|
||||||
|
|
||||||
|
}
|
||||||
|
// Load each program segment (ignores ph flags).
|
||||||
|
ph = (struct proghdr*)((uchar*)elf + elf->phoff);
|
||||||
|
eph = ph + elf->phnum;
|
||||||
|
for (; ph < eph; ph++) {
|
||||||
|
pa = (uchar*)ph->paddr;
|
||||||
|
readseg(pa, ph->filesz, ph->off);
|
||||||
|
if (ph->memsz > ph->filesz) {
|
||||||
|
stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the entry point from the ELF header.
|
||||||
|
// Does not return!
|
||||||
|
entry = (void (*)(void))(elf->entry);
|
||||||
|
entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitdisk(void) {
|
||||||
|
// Wait for disk ready.
|
||||||
|
while ((inb(0x1F7) & 0xC0) != 0x40) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a single sector at offset into dst.
|
||||||
|
void readsect(void *dst, uint offset) {
|
||||||
|
// Issue command.
|
||||||
|
waitdisk();
|
||||||
|
outb(0x1F2, 1); // count = 1
|
||||||
|
outb(0x1F3, offset);
|
||||||
|
outb(0x1F4, offset >> 8);
|
||||||
|
outb(0x1F5, offset >> 16);
|
||||||
|
outb(0x1F6, (offset >> 24) | 0xE0);
|
||||||
|
outb(0x1F7, 0x20); // cmd 0x20 - read sectors
|
||||||
|
|
||||||
|
// Read data.
|
||||||
|
waitdisk();
|
||||||
|
insl(0x1F0, dst, SECTSIZE / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read 'count' bytes at 'offset' from kernel into physical address 'pa'.
|
||||||
|
// Might copy more than asked.
|
||||||
|
|
||||||
|
void readseg(uchar* pa, uint count, uint offset) {
|
||||||
|
uchar* epa;
|
||||||
|
|
||||||
|
epa = pa + count;
|
||||||
|
|
||||||
|
// Round down to sector boundary.
|
||||||
|
pa -= offset % SECTSIZE;
|
||||||
|
|
||||||
|
// Translate from bytes to sectors; kernel starts at sector 1.
|
||||||
|
offset = (offset / SECTSIZE) + 1;
|
||||||
|
|
||||||
|
// If this is too slow, we could read lots of sectors at a time.
|
||||||
|
// We'd write more to memory than asked, but it doesn't matter --
|
||||||
|
// we load in increasing order.
|
||||||
|
for (; pa < epa; pa += SECTSIZE, offset++) {
|
||||||
|
readsect(pa, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
bootmain.o: bootmain.c types.h elf.h x86.h memlayout.h
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,14 @@
|
|||||||
|
struct buf {
|
||||||
|
int flags;
|
||||||
|
uint dev;
|
||||||
|
uint blockno;
|
||||||
|
struct sleeplock lock;
|
||||||
|
uint refcnt;
|
||||||
|
struct buf *prev; // LRU cache list
|
||||||
|
struct buf *next;
|
||||||
|
struct buf *qnext; // disk queue
|
||||||
|
uchar data[BSIZE];
|
||||||
|
};
|
||||||
|
#define B_VALID 0x2 // buffer has been read from disk
|
||||||
|
#define B_DIRTY 0x4 // buffer needs to be written to disk
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "stat.h"
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
void cat(int fd) {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
|
if (write(1, buf, n) != n) {
|
||||||
|
printf(1, "cat: write error\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n < 0) {
|
||||||
|
printf(1, "cat: read error\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int fd, i;
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
cat(0);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if ((fd = open(argv[i], 0)) < 0) {
|
||||||
|
printf(1, "cat: cannot open %s\n", argv[i]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
cat(fd);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
00000000 cat.c
|
||||||
|
00000000 ulib.c
|
||||||
|
00000000 printf.c
|
||||||
|
00000420 printint
|
||||||
|
00000890 digits.0
|
||||||
|
00000000 umalloc.c
|
||||||
|
00000d80 freep
|
||||||
|
00000d84 base
|
||||||
|
00000110 strcpy
|
||||||
|
000004d0 printf
|
||||||
|
0000040b greeting
|
||||||
|
00000330 memmove
|
||||||
|
000003db mknod
|
||||||
|
00000230 gets
|
||||||
|
000003ab getpid
|
||||||
|
00000090 cat
|
||||||
|
00000700 malloc
|
||||||
|
000003bb sleep
|
||||||
|
00000373 pipe
|
||||||
|
00000403 getch
|
||||||
|
000003d3 write
|
||||||
|
00000393 fstat
|
||||||
|
00000383 kill
|
||||||
|
0000039b chdir
|
||||||
|
0000038b exec
|
||||||
|
0000036b wait
|
||||||
|
0000037b read
|
||||||
|
000003e3 unlink
|
||||||
|
0000035b fork
|
||||||
|
000003b3 sbrk
|
||||||
|
000003c3 uptime
|
||||||
|
00000b74 __bss_start
|
||||||
|
000001d0 memset
|
||||||
|
00000000 main
|
||||||
|
00000140 strcmp
|
||||||
|
00000413 shutdown
|
||||||
|
000003a3 dup
|
||||||
|
00000b80 buf
|
||||||
|
000002a0 stat
|
||||||
|
00000b74 _edata
|
||||||
|
00000d8c _end
|
||||||
|
000003eb link
|
||||||
|
00000363 exit
|
||||||
|
000002f0 atoi
|
||||||
|
000001a0 strlen
|
||||||
|
000003cb open
|
||||||
|
000001f0 strchr
|
||||||
|
000003f3 mkdir
|
||||||
|
000003fb close
|
||||||
|
00000670 free
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<XLaunch WindowMode="MultiWindow" ClientMode="NoClient" LocalClient="False" Display="-1" LocalProgram="xcalc" RemoteProgram="xterm" RemotePassword="" PrivateKey="" RemoteHost="" RemoteUser="" XDMCPHost="" XDMCPBroadcast="False" XDMCPIndirect="False" Clipboard="True" ClipboardPrimary="True" ExtraParams="" Wgl="True" DisableAC="True" XDMCPTerminate="False"/>
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
// Console input and output.
|
||||||
|
// Input is from the keyboard or serial port.
|
||||||
|
// Output is written to the screen and serial port.
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "defs.h"
|
||||||
|
#include "param.h"
|
||||||
|
#include "traps.h"
|
||||||
|
#include "spinlock.h"
|
||||||
|
#include "sleeplock.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "memlayout.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "proc.h"
|
||||||
|
#include "x86.h"
|
||||||
|
|
||||||
|
#define INPUT_BUF 128
|
||||||
|
|
||||||
|
struct kbdbuffer {
|
||||||
|
char buf[INPUT_BUF];
|
||||||
|
uint r; // Read index
|
||||||
|
uint w; // Write index
|
||||||
|
uint e; // Edit index
|
||||||
|
};
|
||||||
|
|
||||||
|
struct kbdbuffer inputBuffer;
|
||||||
|
|
||||||
|
struct kbdbuffer * input = 0;
|
||||||
|
|
||||||
|
#define C(x) ((x) - '@') // Control-x
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void consputc(int);
|
||||||
|
|
||||||
|
static int panicked = 0;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct spinlock lock;
|
||||||
|
int locking;
|
||||||
|
} cons;
|
||||||
|
|
||||||
|
static void printint(int xx, int base, int sign) {
|
||||||
|
static char digits[] = "0123456789abcdef";
|
||||||
|
char buf[16];
|
||||||
|
int i;
|
||||||
|
uint x;
|
||||||
|
|
||||||
|
if (sign && (sign = xx < 0)) {
|
||||||
|
x = -xx;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = xx;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
buf[i++] = digits[x % base];
|
||||||
|
}
|
||||||
|
while ((x /= base) != 0);
|
||||||
|
|
||||||
|
if (sign) {
|
||||||
|
buf[i++] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
while (--i >= 0) {
|
||||||
|
consputc(buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print to the console. only understands %d, %x, %p, %s.
|
||||||
|
void cprintf(char *fmt, ...) {
|
||||||
|
int i, c, locking;
|
||||||
|
uint *argp;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
locking = cons.locking;
|
||||||
|
if (locking) {
|
||||||
|
acquire(&cons.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fmt == 0) {
|
||||||
|
panic("null fmt");
|
||||||
|
}
|
||||||
|
|
||||||
|
argp = (uint*)(void*)(&fmt + 1);
|
||||||
|
for (i = 0; (c = fmt[i] & 0xff) != 0; i++) {
|
||||||
|
if (c != '%') {
|
||||||
|
consputc(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
c = fmt[++i] & 0xff;
|
||||||
|
if (c == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case 'd':
|
||||||
|
printint(*argp++, 10, 1);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
case 'p':
|
||||||
|
printint(*argp++, 16, 0);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if ((s = (char*)*argp++) == 0) {
|
||||||
|
s = "(null)";
|
||||||
|
}
|
||||||
|
for (; *s; s++) {
|
||||||
|
consputc(*s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
consputc('%');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Print unknown % sequence to draw attention.
|
||||||
|
consputc('%');
|
||||||
|
consputc(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locking) {
|
||||||
|
release(&cons.lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void panic(char *s) {
|
||||||
|
int i;
|
||||||
|
uint pcs[10];
|
||||||
|
|
||||||
|
cli();
|
||||||
|
cons.locking = 0;
|
||||||
|
// use lapiccpunum so that we can call panic from mycpu()
|
||||||
|
cprintf("lapicid %d: panic: ", lapicid());
|
||||||
|
cprintf(s);
|
||||||
|
cprintf("\n");
|
||||||
|
getcallerpcs(&s, pcs);
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
cprintf(" %p", pcs[i]);
|
||||||
|
}
|
||||||
|
panicked = 1; // freeze other CPU
|
||||||
|
for (;;) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BACKSPACE 0x100
|
||||||
|
#define CRTPORT 0x3d4
|
||||||
|
static ushort *crt = (ushort*)P2V(0xb8000); // CGA memory
|
||||||
|
|
||||||
|
static void cgaputc(int c) {
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
// Cursor position: col + 80*row.
|
||||||
|
outb(CRTPORT, 14);
|
||||||
|
pos = inb(CRTPORT + 1) << 8;
|
||||||
|
outb(CRTPORT, 15);
|
||||||
|
pos |= inb(CRTPORT + 1);
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
pos += 80 - pos % 80;
|
||||||
|
}
|
||||||
|
else if (c == BACKSPACE) {
|
||||||
|
if (pos > 0) {
|
||||||
|
--pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
crt[pos++] = (c & 0xff) | 0x0700; // black on white
|
||||||
|
|
||||||
|
}
|
||||||
|
if (pos < 0 || pos > 25 * 80) {
|
||||||
|
panic("pos under/overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pos / 80) >= 24) { // Scroll up.
|
||||||
|
memmove(crt, crt + 80, sizeof(crt[0]) * 23 * 80);
|
||||||
|
pos -= 80;
|
||||||
|
memset(crt + pos, 0, sizeof(crt[0]) * (24 * 80 - pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
outb(CRTPORT, 14);
|
||||||
|
outb(CRTPORT + 1, pos >> 8);
|
||||||
|
outb(CRTPORT, 15);
|
||||||
|
outb(CRTPORT + 1, pos);
|
||||||
|
crt[pos] = ' ' | 0x0700;
|
||||||
|
}
|
||||||
|
|
||||||
|
void consputc(int c) {
|
||||||
|
if (panicked) {
|
||||||
|
cli();
|
||||||
|
for (;;) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == BACKSPACE) {
|
||||||
|
uartputc('\b');
|
||||||
|
uartputc(' ');
|
||||||
|
uartputc('\b');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uartputc(c);
|
||||||
|
}
|
||||||
|
cgaputc(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int consoleget(void) {
|
||||||
|
int c;
|
||||||
|
|
||||||
|
acquire(&cons.lock);
|
||||||
|
|
||||||
|
while ((c = kbdgetc()) <= 0) {
|
||||||
|
if (c == 0) {
|
||||||
|
c = kbdgetc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
release(&cons.lock);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleintr(int (*getc)(void)) {
|
||||||
|
int c, doprocdump = 0;
|
||||||
|
|
||||||
|
acquire(&cons.lock);
|
||||||
|
while ((c = getc()) >= 0) {
|
||||||
|
switch (c) {
|
||||||
|
case C('P'): // Process listing.
|
||||||
|
// procdump() locks cons.lock indirectly; invoke later
|
||||||
|
doprocdump = 1;
|
||||||
|
break;
|
||||||
|
case C('U'): // Kill line.
|
||||||
|
while (input->e != input->w &&
|
||||||
|
input->buf[(input->e - 1) % INPUT_BUF] != '\n') {
|
||||||
|
input->e--;
|
||||||
|
consputc(BACKSPACE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case C('H'):
|
||||||
|
case '\x7f': // Backspace
|
||||||
|
if (input->e != input->w) {
|
||||||
|
input->e--;
|
||||||
|
consputc(BACKSPACE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (c != 0 && input->e - input->r < INPUT_BUF) {
|
||||||
|
c = (c == '\r') ? '\n' : c;
|
||||||
|
input->buf[input->e++ % INPUT_BUF] = c;
|
||||||
|
consputc(c);
|
||||||
|
if (c == '\n' || c == C('D') || input->e == input->r + INPUT_BUF) {
|
||||||
|
input->w = input->e;
|
||||||
|
wakeup(&(input->r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release(&cons.lock);
|
||||||
|
if (doprocdump) {
|
||||||
|
procdump(); // now call procdump() wo. cons.lock held
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int consoleread(struct inode *ip, char *dst, int n) {
|
||||||
|
uint target;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
iunlock(ip);
|
||||||
|
target = n;
|
||||||
|
acquire(&cons.lock);
|
||||||
|
while (n > 0) {
|
||||||
|
while (input->r == input->w) {
|
||||||
|
if (myproc()->killed) {
|
||||||
|
release(&cons.lock);
|
||||||
|
ilock(ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sleep(&(input->r), &cons.lock);
|
||||||
|
}
|
||||||
|
c = input->buf[input->r++ % INPUT_BUF];
|
||||||
|
if (c == C('D')) { // EOF
|
||||||
|
if (n < target) {
|
||||||
|
// Save ^D for next time, to make sure
|
||||||
|
// caller gets a 0-byte result.
|
||||||
|
input->r--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*dst++ = c;
|
||||||
|
--n;
|
||||||
|
if (c == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release(&cons.lock);
|
||||||
|
ilock(ip);
|
||||||
|
|
||||||
|
return target - n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int consolewrite(struct inode *ip, char *buf, int n) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
iunlock(ip);
|
||||||
|
acquire(&cons.lock);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
consputc(buf[i] & 0xff);
|
||||||
|
}
|
||||||
|
release(&cons.lock);
|
||||||
|
ilock(ip);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleinit(void) {
|
||||||
|
initlock(&cons.lock, "console");
|
||||||
|
|
||||||
|
// Initialise pointer to point to our console input buffer
|
||||||
|
input = &inputBuffer;
|
||||||
|
|
||||||
|
devsw[CONSOLE].write = consolewrite;
|
||||||
|
devsw[CONSOLE].read = consoleread;
|
||||||
|
cons.locking = 1;
|
||||||
|
|
||||||
|
ioapicenable(IRQ_KBD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
console.o: console.c /usr/include/stdc-predef.h types.h defs.h param.h \
|
||||||
|
traps.h spinlock.h sleeplock.h fs.h file.h memlayout.h mmu.h proc.h \
|
||||||
|
x86.h
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
$| = 1;
|
||||||
|
|
||||||
|
sub writefile($@){
|
||||||
|
my ($file, @lines) = @_;
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
open(F, ">$file") || die "open >$file: $!";
|
||||||
|
print F @lines;
|
||||||
|
close(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cut out #include lines that don't contribute anything.
|
||||||
|
for($i=0; $i<@ARGV; $i++){
|
||||||
|
$file = $ARGV[$i];
|
||||||
|
if(!open(F, $file)){
|
||||||
|
print STDERR "open $file: $!\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
@lines = <F>;
|
||||||
|
close(F);
|
||||||
|
|
||||||
|
$obj = "$file.o";
|
||||||
|
$obj =~ s/\.c\.o$/.o/;
|
||||||
|
system("touch $file");
|
||||||
|
|
||||||
|
if(system("make CC='gcc -Werror' $obj >/dev/null 2>\&1") != 0){
|
||||||
|
print STDERR "make $obj failed: $rv\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
system("cp $file =$file");
|
||||||
|
for($j=@lines-1; $j>=0; $j--){
|
||||||
|
if($lines[$j] =~ /^#include/){
|
||||||
|
$old = $lines[$j];
|
||||||
|
$lines[$j] = "/* CUT-H */\n";
|
||||||
|
writefile($file, @lines);
|
||||||
|
if(system("make CC='gcc -Werror' $obj >/dev/null 2>\&1") != 0){
|
||||||
|
$lines[$j] = $old;
|
||||||
|
}else{
|
||||||
|
print STDERR "$file $old";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writefile($file, grep {!/CUT-H/} @lines);
|
||||||
|
system("rm =$file");
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
struct rtcdate {
|
||||||
|
uint second;
|
||||||
|
uint minute;
|
||||||
|
uint hour;
|
||||||
|
uint day;
|
||||||
|
uint month;
|
||||||
|
uint year;
|
||||||
|
};
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
struct buf;
|
||||||
|
struct context;
|
||||||
|
struct file;
|
||||||
|
struct inode;
|
||||||
|
struct pipe;
|
||||||
|
struct proc;
|
||||||
|
struct rtcdate;
|
||||||
|
struct spinlock;
|
||||||
|
struct sleeplock;
|
||||||
|
struct stat;
|
||||||
|
struct superblock;
|
||||||
|
|
||||||
|
// bio.c
|
||||||
|
void binit(void);
|
||||||
|
struct buf* bread(uint, uint);
|
||||||
|
void brelse(struct buf*);
|
||||||
|
void bwrite(struct buf*);
|
||||||
|
|
||||||
|
// console.c
|
||||||
|
void consoleinit(void);
|
||||||
|
void cprintf(char*, ...);
|
||||||
|
void consoleintr(int (*)(void));
|
||||||
|
int consoleget(void);
|
||||||
|
void panic(char*) __attribute__((noreturn));
|
||||||
|
|
||||||
|
// exec.c
|
||||||
|
int exec(char*, char**);
|
||||||
|
|
||||||
|
// file.c
|
||||||
|
struct file* filealloc(void);
|
||||||
|
void fileclose(struct file*);
|
||||||
|
struct file* filedup(struct file*);
|
||||||
|
void fileinit(void);
|
||||||
|
int fileread(struct file*, char*, int n);
|
||||||
|
int filestat(struct file*, struct stat*);
|
||||||
|
int filewrite(struct file*, char*, int n);
|
||||||
|
|
||||||
|
// fs.c
|
||||||
|
void readsb(int dev, struct superblock *sb);
|
||||||
|
int dirlink(struct inode*, char*, uint);
|
||||||
|
struct inode* dirlookup(struct inode*, char*, uint*);
|
||||||
|
struct inode* ialloc(uint, short);
|
||||||
|
struct inode* idup(struct inode*);
|
||||||
|
void iinit(int dev);
|
||||||
|
void ilock(struct inode*);
|
||||||
|
void iput(struct inode*);
|
||||||
|
void iunlock(struct inode*);
|
||||||
|
void iunlockput(struct inode*);
|
||||||
|
void iupdate(struct inode*);
|
||||||
|
int namecmp(const char*, const char*);
|
||||||
|
struct inode* namei(char*);
|
||||||
|
struct inode* nameiparent(char*, char*);
|
||||||
|
int readi(struct inode*, char*, uint, uint);
|
||||||
|
void stati(struct inode*, struct stat*);
|
||||||
|
int writei(struct inode*, char*, uint, uint);
|
||||||
|
|
||||||
|
// ide.c
|
||||||
|
void ideinit(void);
|
||||||
|
void ideintr(void);
|
||||||
|
void iderw(struct buf*);
|
||||||
|
|
||||||
|
// ioapic.c
|
||||||
|
void ioapicenable(int irq, int cpu);
|
||||||
|
extern uchar ioapicid;
|
||||||
|
void ioapicinit(void);
|
||||||
|
|
||||||
|
// kalloc.c
|
||||||
|
char* kalloc(void);
|
||||||
|
void kfree(char*);
|
||||||
|
void kinit1(void*, void*);
|
||||||
|
void kinit2(void*, void*);
|
||||||
|
|
||||||
|
// kbd.c
|
||||||
|
void kbdintr(void);
|
||||||
|
int kbdgetc(void);
|
||||||
|
|
||||||
|
// lapic.c
|
||||||
|
void cmostime(struct rtcdate *r);
|
||||||
|
int lapicid(void);
|
||||||
|
extern volatile uint* lapic;
|
||||||
|
void lapiceoi(void);
|
||||||
|
void lapicinit(void);
|
||||||
|
void lapicstartap(uchar, uint);
|
||||||
|
void microdelay(int);
|
||||||
|
|
||||||
|
// log.c
|
||||||
|
void initlog(int dev);
|
||||||
|
void log_write(struct buf*);
|
||||||
|
void begin_op();
|
||||||
|
void end_op();
|
||||||
|
|
||||||
|
// mp.c
|
||||||
|
extern int ismp;
|
||||||
|
void mpinit(void);
|
||||||
|
|
||||||
|
// picirq.c
|
||||||
|
void picenable(int);
|
||||||
|
void picinit(void);
|
||||||
|
|
||||||
|
// pipe.c
|
||||||
|
int pipealloc(struct file**, struct file**);
|
||||||
|
void pipeclose(struct pipe*, int);
|
||||||
|
int piperead(struct pipe*, char*, int);
|
||||||
|
int pipewrite(struct pipe*, char*, int);
|
||||||
|
|
||||||
|
// proc.c
|
||||||
|
int cpuid(void);
|
||||||
|
void exit(void);
|
||||||
|
int fork(void);
|
||||||
|
int growproc(int);
|
||||||
|
int kill(int);
|
||||||
|
struct cpu* mycpu(void);
|
||||||
|
struct proc* myproc();
|
||||||
|
void pinit(void);
|
||||||
|
void procdump(void);
|
||||||
|
void scheduler(void) __attribute__((noreturn));
|
||||||
|
void sched(void);
|
||||||
|
void setproc(struct proc*);
|
||||||
|
void sleep(void*, struct spinlock*);
|
||||||
|
void userinit(void);
|
||||||
|
int wait(void);
|
||||||
|
void wakeup(void*);
|
||||||
|
void yield(void);
|
||||||
|
|
||||||
|
// swtch.S
|
||||||
|
void swtch(struct context**, struct context*);
|
||||||
|
|
||||||
|
// spinlock.c
|
||||||
|
void acquire(struct spinlock*);
|
||||||
|
void getcallerpcs(void*, uint*);
|
||||||
|
int holding(struct spinlock*);
|
||||||
|
void initlock(struct spinlock*, char*);
|
||||||
|
void release(struct spinlock*);
|
||||||
|
void pushcli(void);
|
||||||
|
void popcli(void);
|
||||||
|
|
||||||
|
// sleeplock.c
|
||||||
|
void acquiresleep(struct sleeplock*);
|
||||||
|
void releasesleep(struct sleeplock*);
|
||||||
|
int holdingsleep(struct sleeplock*);
|
||||||
|
void initsleeplock(struct sleeplock*, char*);
|
||||||
|
|
||||||
|
// string.c
|
||||||
|
int memcmp(const void*, const void*, uint);
|
||||||
|
void* memmove(void*, const void*, uint);
|
||||||
|
void* memset(void*, int, uint);
|
||||||
|
char* safestrcpy(char*, const char*, int);
|
||||||
|
int strlen(const char*);
|
||||||
|
int strncmp(const char*, const char*, uint);
|
||||||
|
char* strncpy(char*, const char*, int);
|
||||||
|
|
||||||
|
// syscall.c
|
||||||
|
int argint(int, int*);
|
||||||
|
int argptr(int, char**, int);
|
||||||
|
int argstr(int, char**);
|
||||||
|
int fetchint(uint, int*);
|
||||||
|
int fetchstr(uint, char**);
|
||||||
|
void syscall(void);
|
||||||
|
|
||||||
|
// timer.c
|
||||||
|
void timerinit(void);
|
||||||
|
|
||||||
|
// trap.c
|
||||||
|
void idtinit(void);
|
||||||
|
extern uint ticks;
|
||||||
|
void tvinit(void);
|
||||||
|
extern struct spinlock tickslock;
|
||||||
|
|
||||||
|
// uart.c
|
||||||
|
void uartinit(void);
|
||||||
|
void uartintr(void);
|
||||||
|
void uartputc(int);
|
||||||
|
|
||||||
|
// vm.c
|
||||||
|
void seginit(void);
|
||||||
|
void kvmalloc(void);
|
||||||
|
pde_t* setupkvm(void);
|
||||||
|
char* uva2ka(pde_t*, char*);
|
||||||
|
int allocuvm(pde_t*, uint, uint);
|
||||||
|
int deallocuvm(pde_t*, uint, uint);
|
||||||
|
void freevm(pde_t*);
|
||||||
|
void inituvm(pde_t*, char*, uint);
|
||||||
|
int loaduvm(pde_t*, char*, struct inode*, uint, uint);
|
||||||
|
pde_t* copyuvm(pde_t*, uint);
|
||||||
|
void switchuvm(struct proc*);
|
||||||
|
void switchkvm(void);
|
||||||
|
int copyout(pde_t*, uint, void*, uint);
|
||||||
|
void clearpteu(pde_t *pgdir, char *uva);
|
||||||
|
|
||||||
|
// number of elements in fixed-size array
|
||||||
|
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "stat.h"
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
printf(1, "%s%s", argv[i], i + 1 < argc ? " " : "\n");
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
00000000 echo.c
|
||||||
|
00000000 ulib.c
|
||||||
|
00000000 printf.c
|
||||||
|
00000380 printint
|
||||||
|
000007c0 digits.0
|
||||||
|
00000000 umalloc.c
|
||||||
|
00000a74 freep
|
||||||
|
00000a78 base
|
||||||
|
00000070 strcpy
|
||||||
|
00000430 printf
|
||||||
|
0000036b greeting
|
||||||
|
00000290 memmove
|
||||||
|
0000033b mknod
|
||||||
|
00000190 gets
|
||||||
|
0000030b getpid
|
||||||
|
00000660 malloc
|
||||||
|
0000031b sleep
|
||||||
|
000002d3 pipe
|
||||||
|
00000363 getch
|
||||||
|
00000333 write
|
||||||
|
000002f3 fstat
|
||||||
|
000002e3 kill
|
||||||
|
000002fb chdir
|
||||||
|
000002eb exec
|
||||||
|
000002cb wait
|
||||||
|
000002db read
|
||||||
|
00000343 unlink
|
||||||
|
000002bb fork
|
||||||
|
00000313 sbrk
|
||||||
|
00000323 uptime
|
||||||
|
00000a74 __bss_start
|
||||||
|
00000130 memset
|
||||||
|
00000000 main
|
||||||
|
000000a0 strcmp
|
||||||
|
00000373 shutdown
|
||||||
|
00000303 dup
|
||||||
|
00000200 stat
|
||||||
|
00000a74 _edata
|
||||||
|
00000a80 _end
|
||||||
|
0000034b link
|
||||||
|
000002c3 exit
|
||||||
|
00000250 atoi
|
||||||
|
00000100 strlen
|
||||||
|
0000032b open
|
||||||
|
00000150 strchr
|
||||||
|
00000353 mkdir
|
||||||
|
0000035b close
|
||||||
|
000005d0 free
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Format of an ELF executable file
|
||||||
|
|
||||||
|
#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian
|
||||||
|
|
||||||
|
// File header
|
||||||
|
struct elfhdr {
|
||||||
|
uint magic; // must equal ELF_MAGIC
|
||||||
|
uchar elf[12];
|
||||||
|
ushort type;
|
||||||
|
ushort machine;
|
||||||
|
uint version;
|
||||||
|
uint entry;
|
||||||
|
uint phoff;
|
||||||
|
uint shoff;
|
||||||
|
uint flags;
|
||||||
|
ushort ehsize;
|
||||||
|
ushort phentsize;
|
||||||
|
ushort phnum;
|
||||||
|
ushort shentsize;
|
||||||
|
ushort shnum;
|
||||||
|
ushort shstrndx;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Program section header
|
||||||
|
struct proghdr {
|
||||||
|
uint type;
|
||||||
|
uint off;
|
||||||
|
uint vaddr;
|
||||||
|
uint paddr;
|
||||||
|
uint filesz;
|
||||||
|
uint memsz;
|
||||||
|
uint flags;
|
||||||
|
uint align;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Values for Proghdr type
|
||||||
|
#define ELF_PROG_LOAD 1
|
||||||
|
|
||||||
|
// Flag bits for Proghdr flags
|
||||||
|
#define ELF_PROG_FLAG_EXEC 1
|
||||||
|
#define ELF_PROG_FLAG_WRITE 2
|
||||||
|
#define ELF_PROG_FLAG_READ 4
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# The xv6 kernel starts executing in this file. This file is linked with
|
||||||
|
# the kernel C code, so it can refer to kernel symbols such as main().
|
||||||
|
# The boot block (bootasm.S and bootmain.c) jumps to entry below.
|
||||||
|
|
||||||
|
# Multiboot header, for multiboot boot loaders like GNU Grub.
|
||||||
|
# http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
|
||||||
|
#
|
||||||
|
# Using GRUB 2, you can boot xv6 from a file stored in a
|
||||||
|
# Linux file system by copying kernel or kernelmemfs to /boot
|
||||||
|
# and then adding this menu entry:
|
||||||
|
#
|
||||||
|
# menuentry "xv6" {
|
||||||
|
# insmod ext2
|
||||||
|
# set root='(hd0,msdos1)'
|
||||||
|
# set kernel='/boot/kernel'
|
||||||
|
# echo "Loading ${kernel}..."
|
||||||
|
# multiboot ${kernel} ${kernel}
|
||||||
|
# boot
|
||||||
|
# }
|
||||||
|
|
||||||
|
#include "asm.h"
|
||||||
|
#include "memlayout.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "param.h"
|
||||||
|
|
||||||
|
# Multiboot header. Data to direct multiboot loader.
|
||||||
|
.p2align 2
|
||||||
|
.text
|
||||||
|
.globl multiboot_header
|
||||||
|
multiboot_header:
|
||||||
|
#define magic 0x1badb002
|
||||||
|
#define flags 0
|
||||||
|
.long magic
|
||||||
|
.long flags
|
||||||
|
.long (-magic-flags)
|
||||||
|
|
||||||
|
# By convention, the _start symbol specifies the ELF entry point.
|
||||||
|
# Since we haven't set up virtual memory yet, our entry point is
|
||||||
|
# the physical address of 'entry'.
|
||||||
|
.globl _start
|
||||||
|
_start = V2P_WO(entry)
|
||||||
|
|
||||||
|
# Entering xv6 on boot processor, with paging off.
|
||||||
|
.globl entry
|
||||||
|
entry:
|
||||||
|
# Turn on page size extension for 4Mbyte pages
|
||||||
|
movl %cr4, %eax
|
||||||
|
orl $(CR4_PSE), %eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
# Set page directory
|
||||||
|
movl $(V2P_WO(entrypgdir)), %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
# Turn on paging.
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $(CR0_PG|CR0_WP), %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
# Set up the stack pointer.
|
||||||
|
movl $(stack + KSTACKSIZE), %esp
|
||||||
|
|
||||||
|
# Jump to main(), and switch to executing at
|
||||||
|
# high addresses. The indirect call is needed because
|
||||||
|
# the assembler produces a PC-relative instruction
|
||||||
|
# for a direct jump.
|
||||||
|
mov $main, %eax
|
||||||
|
jmp *%eax
|
||||||
|
|
||||||
|
.comm stack, KSTACKSIZE
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,89 @@
|
|||||||
|
#include "asm.h"
|
||||||
|
#include "memlayout.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
|
||||||
|
# Each non-boot CPU ("AP") is started up in response to a STARTUP
|
||||||
|
# IPI from the boot CPU. Section B.4.2 of the Multi-Processor
|
||||||
|
# Specification says that the AP will start in real mode with CS:IP
|
||||||
|
# set to XY00:0000, where XY is an 8-bit value sent with the
|
||||||
|
# STARTUP. Thus this code must start at a 4096-byte boundary.
|
||||||
|
#
|
||||||
|
# Because this code sets DS to zero, it must sit
|
||||||
|
# at an address in the low 2^16 bytes.
|
||||||
|
#
|
||||||
|
# Startothers (in main.c) sends the STARTUPs one at a time.
|
||||||
|
# It copies this code (start) at 0x7000. It puts the address of
|
||||||
|
# a newly allocated per-core stack in start-4,the address of the
|
||||||
|
# place to jump to (mpenter) in start-8, and the physical address
|
||||||
|
# of entrypgdir in start-12.
|
||||||
|
#
|
||||||
|
# This code combines elements of bootasm.S and entry.S.
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.globl start
|
||||||
|
start:
|
||||||
|
cli
|
||||||
|
|
||||||
|
# Zero data segment registers DS, ES, and SS.
|
||||||
|
xorw %ax,%ax
|
||||||
|
movw %ax,%ds
|
||||||
|
movw %ax,%es
|
||||||
|
movw %ax,%ss
|
||||||
|
|
||||||
|
# Switch from real to protected mode. Use a bootstrap GDT that makes
|
||||||
|
# virtual addresses map directly to physical addresses so that the
|
||||||
|
# effective memory map doesn't change during the transition.
|
||||||
|
lgdt gdtdesc
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $CR0_PE, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
# Complete the transition to 32-bit protected mode by using a long jmp
|
||||||
|
# to reload %cs and %eip. The segment descriptors are set up with no
|
||||||
|
# translation, so that the mapping is still the identity mapping.
|
||||||
|
ljmpl $(SEG_KCODE<<3), $(start32)
|
||||||
|
|
||||||
|
|
||||||
|
.code32 # Tell assembler to generate 32-bit code now.
|
||||||
|
start32:
|
||||||
|
# Set up the protected-mode data segment registers
|
||||||
|
movw $(SEG_KDATA<<3), %ax # Our data segment selector
|
||||||
|
movw %ax, %ds # -> DS: Data Segment
|
||||||
|
movw %ax, %es # -> ES: Extra Segment
|
||||||
|
movw %ax, %ss # -> SS: Stack Segment
|
||||||
|
movw $0, %ax # Zero segments not ready for use
|
||||||
|
movw %ax, %fs # -> FS
|
||||||
|
movw %ax, %gs # -> GS
|
||||||
|
|
||||||
|
# Turn on page size extension for 4Mbyte pages
|
||||||
|
movl %cr4, %eax
|
||||||
|
orl $(CR4_PSE), %eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
# Use entrypgdir as our initial page table
|
||||||
|
movl (start-12), %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
# Turn on paging.
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $(CR0_PE|CR0_PG|CR0_WP), %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
# Switch to the stack allocated by startothers()
|
||||||
|
movl (start-4), %esp
|
||||||
|
# Call mpenter()
|
||||||
|
call *(start-8)
|
||||||
|
|
||||||
|
# We should never return.
|
||||||
|
spin:
|
||||||
|
jmp spin
|
||||||
|
|
||||||
|
.p2align 2
|
||||||
|
gdt:
|
||||||
|
SEG_NULLASM
|
||||||
|
SEG_ASM(STA_X|STA_R, 0, 0xffffffff)
|
||||||
|
SEG_ASM(STA_W, 0, 0xffffffff)
|
||||||
|
|
||||||
|
|
||||||
|
gdtdesc:
|
||||||
|
.word (gdtdesc - gdt - 1)
|
||||||
|
.long gdt
|
||||||
|
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
|
||||||
|
bootblockother.o: file format elf32-i386
|
||||||
|
|
||||||
|
|
||||||
|
Disassembly of section .text:
|
||||||
|
|
||||||
|
00007000 <start>:
|
||||||
|
# This code combines elements of bootasm.S and entry.S.
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.globl start
|
||||||
|
start:
|
||||||
|
cli
|
||||||
|
7000: fa cli
|
||||||
|
|
||||||
|
# Zero data segment registers DS, ES, and SS.
|
||||||
|
xorw %ax,%ax
|
||||||
|
7001: 31 c0 xor %eax,%eax
|
||||||
|
movw %ax,%ds
|
||||||
|
7003: 8e d8 mov %eax,%ds
|
||||||
|
movw %ax,%es
|
||||||
|
7005: 8e c0 mov %eax,%es
|
||||||
|
movw %ax,%ss
|
||||||
|
7007: 8e d0 mov %eax,%ss
|
||||||
|
|
||||||
|
# Switch from real to protected mode. Use a bootstrap GDT that makes
|
||||||
|
# virtual addresses map directly to physical addresses so that the
|
||||||
|
# effective memory map doesn't change during the transition.
|
||||||
|
lgdt gdtdesc
|
||||||
|
7009: 0f 01 16 lgdtl (%esi)
|
||||||
|
700c: 74 70 je 707e <_end+0x2>
|
||||||
|
movl %cr0, %eax
|
||||||
|
700e: 0f 20 c0 mov %cr0,%eax
|
||||||
|
orl $CR0_PE, %eax
|
||||||
|
7011: 66 83 c8 01 or $0x1,%ax
|
||||||
|
movl %eax, %cr0
|
||||||
|
7015: 0f 22 c0 mov %eax,%cr0
|
||||||
|
|
||||||
|
# Complete the transition to 32-bit protected mode by using a long jmp
|
||||||
|
# to reload %cs and %eip. The segment descriptors are set up with no
|
||||||
|
# translation, so that the mapping is still the identity mapping.
|
||||||
|
ljmpl $(SEG_KCODE<<3), $(start32)
|
||||||
|
7018: 66 ea 20 70 00 00 ljmpw $0x0,$0x7020
|
||||||
|
701e: 08 00 or %al,(%eax)
|
||||||
|
|
||||||
|
00007020 <start32>:
|
||||||
|
|
||||||
|
|
||||||
|
.code32 # Tell assembler to generate 32-bit code now.
|
||||||
|
start32:
|
||||||
|
# Set up the protected-mode data segment registers
|
||||||
|
movw $(SEG_KDATA<<3), %ax # Our data segment selector
|
||||||
|
7020: 66 b8 10 00 mov $0x10,%ax
|
||||||
|
movw %ax, %ds # -> DS: Data Segment
|
||||||
|
7024: 8e d8 mov %eax,%ds
|
||||||
|
movw %ax, %es # -> ES: Extra Segment
|
||||||
|
7026: 8e c0 mov %eax,%es
|
||||||
|
movw %ax, %ss # -> SS: Stack Segment
|
||||||
|
7028: 8e d0 mov %eax,%ss
|
||||||
|
movw $0, %ax # Zero segments not ready for use
|
||||||
|
702a: 66 b8 00 00 mov $0x0,%ax
|
||||||
|
movw %ax, %fs # -> FS
|
||||||
|
702e: 8e e0 mov %eax,%fs
|
||||||
|
movw %ax, %gs # -> GS
|
||||||
|
7030: 8e e8 mov %eax,%gs
|
||||||
|
|
||||||
|
# Turn on page size extension for 4Mbyte pages
|
||||||
|
movl %cr4, %eax
|
||||||
|
7032: 0f 20 e0 mov %cr4,%eax
|
||||||
|
orl $(CR4_PSE), %eax
|
||||||
|
7035: 83 c8 10 or $0x10,%eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
7038: 0f 22 e0 mov %eax,%cr4
|
||||||
|
# Use entrypgdir as our initial page table
|
||||||
|
movl (start-12), %eax
|
||||||
|
703b: a1 f4 6f 00 00 mov 0x6ff4,%eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
7040: 0f 22 d8 mov %eax,%cr3
|
||||||
|
# Turn on paging.
|
||||||
|
movl %cr0, %eax
|
||||||
|
7043: 0f 20 c0 mov %cr0,%eax
|
||||||
|
orl $(CR0_PE|CR0_PG|CR0_WP), %eax
|
||||||
|
7046: 0d 01 00 01 80 or $0x80010001,%eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
704b: 0f 22 c0 mov %eax,%cr0
|
||||||
|
|
||||||
|
# Switch to the stack allocated by startothers()
|
||||||
|
movl (start-4), %esp
|
||||||
|
704e: 8b 25 fc 6f 00 00 mov 0x6ffc,%esp
|
||||||
|
# Call mpenter()
|
||||||
|
call *(start-8)
|
||||||
|
7054: ff 15 f8 6f 00 00 call *0x6ff8
|
||||||
|
|
||||||
|
0000705a <spin>:
|
||||||
|
|
||||||
|
# We should never return.
|
||||||
|
spin:
|
||||||
|
jmp spin
|
||||||
|
705a: eb fe jmp 705a <spin>
|
||||||
|
|
||||||
|
0000705c <gdt>:
|
||||||
|
...
|
||||||
|
7064: ff (bad)
|
||||||
|
7065: ff 00 incl (%eax)
|
||||||
|
7067: 00 00 add %al,(%eax)
|
||||||
|
7069: 9a cf 00 ff ff 00 00 lcall $0x0,$0xffff00cf
|
||||||
|
7070: 00 .byte 0x0
|
||||||
|
7071: 92 xchg %eax,%edx
|
||||||
|
7072: cf iret
|
||||||
|
...
|
||||||
|
|
||||||
|
00007074 <gdtdesc>:
|
||||||
|
7074: 17 pop %ss
|
||||||
|
7075: 00 5c 70 00 add %bl,0x0(%eax,%esi,2)
|
||||||
|
...
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
entryother.o: entryother.S asm.h memlayout.h mmu.h
|
||||||
Binary file not shown.
@@ -0,0 +1,142 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "param.h"
|
||||||
|
#include "memlayout.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "proc.h"
|
||||||
|
#include "defs.h"
|
||||||
|
#include "x86.h"
|
||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
void cleanupexec(pde_t * pgdir, struct inode *ip) {
|
||||||
|
if (pgdir) {
|
||||||
|
freevm(pgdir);
|
||||||
|
}
|
||||||
|
if (ip) {
|
||||||
|
iunlockput(ip);
|
||||||
|
end_op();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec(char *path, char **argv) {
|
||||||
|
char *s, *last;
|
||||||
|
int i, off;
|
||||||
|
uint argc, sz, sp, ustack[3 + MAXARG + 1];
|
||||||
|
struct elfhdr elf;
|
||||||
|
struct inode *ip;
|
||||||
|
struct proghdr ph;
|
||||||
|
pde_t *pgdir, *oldpgdir;
|
||||||
|
struct proc *curproc = myproc();
|
||||||
|
|
||||||
|
begin_op();
|
||||||
|
|
||||||
|
if ((ip = namei(path)) == 0) {
|
||||||
|
end_op();
|
||||||
|
cprintf("exec: fail\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ilock(ip);
|
||||||
|
pgdir = 0;
|
||||||
|
|
||||||
|
// Check ELF header
|
||||||
|
if (readi(ip, (char*)&elf, 0, sizeof(elf)) != sizeof(elf)) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (elf.magic != ELF_MAGIC) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pgdir = setupkvm()) == 0) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load program into memory.
|
||||||
|
sz = 0;
|
||||||
|
for (i = 0, off = elf.phoff; i < elf.phnum; i++, off += sizeof(ph)) {
|
||||||
|
if (readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ph.type != ELF_PROG_LOAD) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ph.memsz < ph.filesz) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ph.vaddr + ph.memsz < ph.vaddr) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ph.vaddr % PGSIZE != 0) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (loaduvm(pgdir, (char*)ph.vaddr, ip, ph.off, ph.filesz) < 0) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iunlockput(ip);
|
||||||
|
end_op();
|
||||||
|
ip = 0;
|
||||||
|
|
||||||
|
// Allocate two pages at the next page boundary.
|
||||||
|
// Make the first inaccessible. Use the second as the user stack.
|
||||||
|
sz = PGROUNDUP(sz);
|
||||||
|
if ((sz = allocuvm(pgdir, sz, sz + 2 * PGSIZE)) == 0) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
clearpteu(pgdir, (char*)(sz - 2 * PGSIZE));
|
||||||
|
sp = sz;
|
||||||
|
|
||||||
|
// Push argument strings, prepare rest of stack in ustack.
|
||||||
|
for (argc = 0; argv[argc]; argc++) {
|
||||||
|
if (argc >= MAXARG) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sp = (sp - (strlen(argv[argc]) + 1)) & ~3;
|
||||||
|
if (copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ustack[3 + argc] = sp;
|
||||||
|
}
|
||||||
|
ustack[3 + argc] = 0;
|
||||||
|
|
||||||
|
ustack[0] = 0xffffffff; // fake return PC
|
||||||
|
ustack[1] = argc;
|
||||||
|
ustack[2] = sp - (argc + 1) * 4; // argv pointer
|
||||||
|
|
||||||
|
sp -= (3 + argc + 1) * 4;
|
||||||
|
if (copyout(pgdir, sp, ustack, (3 + argc + 1) * 4) < 0) {
|
||||||
|
cleanupexec(pgdir, ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save program name for debugging.
|
||||||
|
for (last = s = path; *s; s++) {
|
||||||
|
if (*s == '/') {
|
||||||
|
last = s + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
safestrcpy(curproc->name, last, sizeof(curproc->name));
|
||||||
|
|
||||||
|
// Commit to the user image.
|
||||||
|
oldpgdir = curproc->pgdir;
|
||||||
|
curproc->pgdir = pgdir;
|
||||||
|
curproc->sz = sz;
|
||||||
|
curproc->tf->eip = elf.entry; // main
|
||||||
|
curproc->tf->esp = sp;
|
||||||
|
switchuvm(curproc);
|
||||||
|
freevm(oldpgdir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
exec.o: exec.c /usr/include/stdc-predef.h types.h param.h memlayout.h \
|
||||||
|
mmu.h proc.h defs.h x86.h elf.h
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#define O_RDONLY 0x000
|
||||||
|
#define O_WRONLY 0x001
|
||||||
|
#define O_RDWR 0x002
|
||||||
|
#define O_CREATE 0x200
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
//
|
||||||
|
// File descriptors
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "defs.h"
|
||||||
|
#include "param.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "spinlock.h"
|
||||||
|
#include "sleeplock.h"
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
struct devsw devsw[NDEV];
|
||||||
|
struct {
|
||||||
|
struct spinlock lock;
|
||||||
|
struct file file[NFILE];
|
||||||
|
} ftable;
|
||||||
|
|
||||||
|
void fileinit(void) {
|
||||||
|
initlock(&ftable.lock, "ftable");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a file structure.
|
||||||
|
struct file* filealloc(void) {
|
||||||
|
struct file *f;
|
||||||
|
|
||||||
|
acquire(&ftable.lock);
|
||||||
|
for (f = ftable.file; f < ftable.file + NFILE; f++) {
|
||||||
|
if (f->ref == 0) {
|
||||||
|
f->ref = 1;
|
||||||
|
release(&ftable.lock);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release(&ftable.lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment ref count for file f.
|
||||||
|
struct file* filedup(struct file *f) {
|
||||||
|
acquire(&ftable.lock);
|
||||||
|
if (f->ref < 1) {
|
||||||
|
panic("filedup");
|
||||||
|
}
|
||||||
|
f->ref++;
|
||||||
|
release(&ftable.lock);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close file f. (Decrement ref count, close when reaches 0.)
|
||||||
|
void fileclose(struct file *f) {
|
||||||
|
struct file ff;
|
||||||
|
|
||||||
|
acquire(&ftable.lock);
|
||||||
|
if (f->ref < 1) {
|
||||||
|
panic("fileclose");
|
||||||
|
}
|
||||||
|
if (--f->ref > 0) {
|
||||||
|
release(&ftable.lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ff = *f;
|
||||||
|
f->ref = 0;
|
||||||
|
f->type = FD_NONE;
|
||||||
|
release(&ftable.lock);
|
||||||
|
|
||||||
|
if (ff.type == FD_PIPE) {
|
||||||
|
pipeclose(ff.pipe, ff.writable);
|
||||||
|
}
|
||||||
|
else if (ff.type == FD_INODE) {
|
||||||
|
begin_op();
|
||||||
|
iput(ff.ip);
|
||||||
|
end_op();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get metadata about file f.
|
||||||
|
int filestat(struct file *f, struct stat *st) {
|
||||||
|
if (f->type == FD_INODE) {
|
||||||
|
ilock(f->ip);
|
||||||
|
stati(f->ip, st);
|
||||||
|
iunlock(f->ip);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from file f.
|
||||||
|
int fileread(struct file *f, char *addr, int n) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (f->readable == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (f->type == FD_PIPE) {
|
||||||
|
return piperead(f->pipe, addr, n);
|
||||||
|
}
|
||||||
|
if (f->type == FD_INODE) {
|
||||||
|
ilock(f->ip);
|
||||||
|
if ((r = readi(f->ip, addr, f->off, n)) > 0) {
|
||||||
|
f->off += r;
|
||||||
|
}
|
||||||
|
iunlock(f->ip);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
panic("fileread");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write to file f.
|
||||||
|
int filewrite(struct file *f, char *addr, int n) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (f->writable == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (f->type == FD_PIPE) {
|
||||||
|
return pipewrite(f->pipe, addr, n);
|
||||||
|
}
|
||||||
|
if (f->type == FD_INODE) {
|
||||||
|
// write a few blocks at a time to avoid exceeding
|
||||||
|
// the maximum log transaction size, including
|
||||||
|
// i-node, indirect block, allocation blocks,
|
||||||
|
// and 2 blocks of slop for non-aligned writes.
|
||||||
|
// this really belongs lower down, since writei()
|
||||||
|
// might be writing a device like the console.
|
||||||
|
int max = ((MAXOPBLOCKS - 1 - 1 - 2) / 2) * 512;
|
||||||
|
int i = 0;
|
||||||
|
while (i < n) {
|
||||||
|
int n1 = n - i;
|
||||||
|
if (n1 > max) {
|
||||||
|
n1 = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
begin_op();
|
||||||
|
ilock(f->ip);
|
||||||
|
if ((r = writei(f->ip, addr + i, f->off, n1)) > 0) {
|
||||||
|
f->off += r;
|
||||||
|
}
|
||||||
|
iunlock(f->ip);
|
||||||
|
end_op();
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r != n1) {
|
||||||
|
panic("short filewrite");
|
||||||
|
}
|
||||||
|
i += r;
|
||||||
|
}
|
||||||
|
return i == n ? n : -1;
|
||||||
|
}
|
||||||
|
panic("filewrite");
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
file.o: file.c /usr/include/stdc-predef.h types.h defs.h param.h fs.h \
|
||||||
|
spinlock.h sleeplock.h file.h
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
struct file {
|
||||||
|
enum { FD_NONE, FD_PIPE, FD_INODE } type;
|
||||||
|
int ref; // reference count
|
||||||
|
char readable;
|
||||||
|
char writable;
|
||||||
|
struct pipe *pipe;
|
||||||
|
struct inode *ip;
|
||||||
|
uint off;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// in-memory copy of an inode
|
||||||
|
struct inode {
|
||||||
|
uint dev; // Device number
|
||||||
|
uint inum; // Inode number
|
||||||
|
int ref; // Reference count
|
||||||
|
struct sleeplock lock; // protects everything below here
|
||||||
|
int valid; // inode has been read from disk?
|
||||||
|
|
||||||
|
short type; // copy of disk inode
|
||||||
|
short major;
|
||||||
|
short minor;
|
||||||
|
short nlink;
|
||||||
|
uint size;
|
||||||
|
uint addrs[NDIRECT + 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
// table mapping major device number to
|
||||||
|
// device functions
|
||||||
|
struct devsw {
|
||||||
|
int (*read)(struct inode*, char*, int);
|
||||||
|
int (*write)(struct inode*, char*, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct devsw devsw[];
|
||||||
|
|
||||||
|
#define CONSOLE 1
|
||||||
+673
@@ -0,0 +1,673 @@
|
|||||||
|
|
||||||
|
_forktest: file format elf32-i386
|
||||||
|
|
||||||
|
|
||||||
|
Disassembly of section .text:
|
||||||
|
|
||||||
|
00000000 <main>:
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(1, "fork test OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
0: 55 push %ebp
|
||||||
|
1: 89 e5 mov %esp,%ebp
|
||||||
|
3: 83 e4 f0 and $0xfffffff0,%esp
|
||||||
|
forktest();
|
||||||
|
6: e8 35 00 00 00 call 40 <forktest>
|
||||||
|
exit();
|
||||||
|
b: e8 63 03 00 00 call 373 <exit>
|
||||||
|
|
||||||
|
00000010 <printf>:
|
||||||
|
void printf(int fd, const char *s, ...) {
|
||||||
|
10: 55 push %ebp
|
||||||
|
11: 89 e5 mov %esp,%ebp
|
||||||
|
13: 53 push %ebx
|
||||||
|
14: 83 ec 10 sub $0x10,%esp
|
||||||
|
17: 8b 5d 0c mov 0xc(%ebp),%ebx
|
||||||
|
write(fd, s, strlen(s));
|
||||||
|
1a: 53 push %ebx
|
||||||
|
1b: e8 90 01 00 00 call 1b0 <strlen>
|
||||||
|
20: 83 c4 0c add $0xc,%esp
|
||||||
|
23: 50 push %eax
|
||||||
|
24: 53 push %ebx
|
||||||
|
25: ff 75 08 push 0x8(%ebp)
|
||||||
|
28: e8 b6 03 00 00 call 3e3 <write>
|
||||||
|
}
|
||||||
|
2d: 8b 5d fc mov -0x4(%ebp),%ebx
|
||||||
|
30: 83 c4 10 add $0x10,%esp
|
||||||
|
33: c9 leave
|
||||||
|
34: c3 ret
|
||||||
|
35: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
3c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
|
||||||
|
00000040 <forktest>:
|
||||||
|
void forktest(void) {
|
||||||
|
40: 55 push %ebp
|
||||||
|
41: 89 e5 mov %esp,%ebp
|
||||||
|
43: 53 push %ebx
|
||||||
|
for (n = 0; n < N; n++) {
|
||||||
|
44: 31 db xor %ebx,%ebx
|
||||||
|
void forktest(void) {
|
||||||
|
46: 83 ec 10 sub $0x10,%esp
|
||||||
|
write(fd, s, strlen(s));
|
||||||
|
49: 68 2c 04 00 00 push $0x42c
|
||||||
|
4e: e8 5d 01 00 00 call 1b0 <strlen>
|
||||||
|
53: 83 c4 0c add $0xc,%esp
|
||||||
|
56: 50 push %eax
|
||||||
|
57: 68 2c 04 00 00 push $0x42c
|
||||||
|
5c: 6a 01 push $0x1
|
||||||
|
5e: e8 80 03 00 00 call 3e3 <write>
|
||||||
|
63: 83 c4 10 add $0x10,%esp
|
||||||
|
66: eb 19 jmp 81 <forktest+0x41>
|
||||||
|
68: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
6f: 90 nop
|
||||||
|
if (pid == 0) {
|
||||||
|
70: 74 58 je ca <forktest+0x8a>
|
||||||
|
for (n = 0; n < N; n++) {
|
||||||
|
72: 83 c3 01 add $0x1,%ebx
|
||||||
|
75: 81 fb e8 03 00 00 cmp $0x3e8,%ebx
|
||||||
|
7b: 0f 84 83 00 00 00 je 104 <forktest+0xc4>
|
||||||
|
pid = fork();
|
||||||
|
81: e8 e5 02 00 00 call 36b <fork>
|
||||||
|
if (pid < 0) {
|
||||||
|
86: 85 c0 test %eax,%eax
|
||||||
|
88: 79 e6 jns 70 <forktest+0x30>
|
||||||
|
for (; n > 0; n--) {
|
||||||
|
8a: 85 db test %ebx,%ebx
|
||||||
|
8c: 74 10 je 9e <forktest+0x5e>
|
||||||
|
8e: 66 90 xchg %ax,%ax
|
||||||
|
if (wait() < 0) {
|
||||||
|
90: e8 e6 02 00 00 call 37b <wait>
|
||||||
|
95: 85 c0 test %eax,%eax
|
||||||
|
97: 78 36 js cf <forktest+0x8f>
|
||||||
|
for (; n > 0; n--) {
|
||||||
|
99: 83 eb 01 sub $0x1,%ebx
|
||||||
|
9c: 75 f2 jne 90 <forktest+0x50>
|
||||||
|
if (wait() != -1) {
|
||||||
|
9e: e8 d8 02 00 00 call 37b <wait>
|
||||||
|
a3: 83 f8 ff cmp $0xffffffff,%eax
|
||||||
|
a6: 75 49 jne f1 <forktest+0xb1>
|
||||||
|
write(fd, s, strlen(s));
|
||||||
|
a8: 83 ec 0c sub $0xc,%esp
|
||||||
|
ab: 68 5e 04 00 00 push $0x45e
|
||||||
|
b0: e8 fb 00 00 00 call 1b0 <strlen>
|
||||||
|
b5: 83 c4 0c add $0xc,%esp
|
||||||
|
b8: 50 push %eax
|
||||||
|
b9: 68 5e 04 00 00 push $0x45e
|
||||||
|
be: 6a 01 push $0x1
|
||||||
|
c0: e8 1e 03 00 00 call 3e3 <write>
|
||||||
|
}
|
||||||
|
c5: 8b 5d fc mov -0x4(%ebp),%ebx
|
||||||
|
c8: c9 leave
|
||||||
|
c9: c3 ret
|
||||||
|
exit();
|
||||||
|
ca: e8 a4 02 00 00 call 373 <exit>
|
||||||
|
write(fd, s, strlen(s));
|
||||||
|
cf: 83 ec 0c sub $0xc,%esp
|
||||||
|
d2: 68 37 04 00 00 push $0x437
|
||||||
|
d7: e8 d4 00 00 00 call 1b0 <strlen>
|
||||||
|
dc: 83 c4 0c add $0xc,%esp
|
||||||
|
df: 50 push %eax
|
||||||
|
e0: 68 37 04 00 00 push $0x437
|
||||||
|
e5: 6a 01 push $0x1
|
||||||
|
e7: e8 f7 02 00 00 call 3e3 <write>
|
||||||
|
exit();
|
||||||
|
ec: e8 82 02 00 00 call 373 <exit>
|
||||||
|
printf(1, "wait got too many\n");
|
||||||
|
f1: 52 push %edx
|
||||||
|
f2: 52 push %edx
|
||||||
|
f3: 68 4b 04 00 00 push $0x44b
|
||||||
|
f8: 6a 01 push $0x1
|
||||||
|
fa: e8 11 ff ff ff call 10 <printf>
|
||||||
|
exit();
|
||||||
|
ff: e8 6f 02 00 00 call 373 <exit>
|
||||||
|
printf(1, "fork claimed to work N times!\n", N);
|
||||||
|
104: 50 push %eax
|
||||||
|
105: 68 e8 03 00 00 push $0x3e8
|
||||||
|
10a: 68 6c 04 00 00 push $0x46c
|
||||||
|
10f: 6a 01 push $0x1
|
||||||
|
111: e8 fa fe ff ff call 10 <printf>
|
||||||
|
exit();
|
||||||
|
116: e8 58 02 00 00 call 373 <exit>
|
||||||
|
11b: 66 90 xchg %ax,%ax
|
||||||
|
11d: 66 90 xchg %ax,%ax
|
||||||
|
11f: 90 nop
|
||||||
|
|
||||||
|
00000120 <strcpy>:
|
||||||
|
#include "stat.h"
|
||||||
|
#include "fcntl.h"
|
||||||
|
#include "user.h"
|
||||||
|
#include "x86.h"
|
||||||
|
|
||||||
|
char*strcpy(char *s, const char *t) {
|
||||||
|
120: 55 push %ebp
|
||||||
|
char *os;
|
||||||
|
|
||||||
|
os = s;
|
||||||
|
while ((*s++ = *t++) != 0) {
|
||||||
|
121: 31 c0 xor %eax,%eax
|
||||||
|
char*strcpy(char *s, const char *t) {
|
||||||
|
123: 89 e5 mov %esp,%ebp
|
||||||
|
125: 53 push %ebx
|
||||||
|
126: 8b 4d 08 mov 0x8(%ebp),%ecx
|
||||||
|
129: 8b 5d 0c mov 0xc(%ebp),%ebx
|
||||||
|
12c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
while ((*s++ = *t++) != 0) {
|
||||||
|
130: 0f b6 14 03 movzbl (%ebx,%eax,1),%edx
|
||||||
|
134: 88 14 01 mov %dl,(%ecx,%eax,1)
|
||||||
|
137: 83 c0 01 add $0x1,%eax
|
||||||
|
13a: 84 d2 test %dl,%dl
|
||||||
|
13c: 75 f2 jne 130 <strcpy+0x10>
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
13e: 8b 5d fc mov -0x4(%ebp),%ebx
|
||||||
|
141: 89 c8 mov %ecx,%eax
|
||||||
|
143: c9 leave
|
||||||
|
144: c3 ret
|
||||||
|
145: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
14c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
|
||||||
|
00000150 <strcmp>:
|
||||||
|
|
||||||
|
int strcmp(const char *p, const char *q) {
|
||||||
|
150: 55 push %ebp
|
||||||
|
151: 89 e5 mov %esp,%ebp
|
||||||
|
153: 53 push %ebx
|
||||||
|
154: 8b 55 08 mov 0x8(%ebp),%edx
|
||||||
|
157: 8b 4d 0c mov 0xc(%ebp),%ecx
|
||||||
|
while (*p && *p == *q) {
|
||||||
|
15a: 0f b6 02 movzbl (%edx),%eax
|
||||||
|
15d: 84 c0 test %al,%al
|
||||||
|
15f: 75 17 jne 178 <strcmp+0x28>
|
||||||
|
161: eb 3a jmp 19d <strcmp+0x4d>
|
||||||
|
163: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
167: 90 nop
|
||||||
|
168: 0f b6 42 01 movzbl 0x1(%edx),%eax
|
||||||
|
p++, q++;
|
||||||
|
16c: 83 c2 01 add $0x1,%edx
|
||||||
|
16f: 8d 59 01 lea 0x1(%ecx),%ebx
|
||||||
|
while (*p && *p == *q) {
|
||||||
|
172: 84 c0 test %al,%al
|
||||||
|
174: 74 1a je 190 <strcmp+0x40>
|
||||||
|
p++, q++;
|
||||||
|
176: 89 d9 mov %ebx,%ecx
|
||||||
|
while (*p && *p == *q) {
|
||||||
|
178: 0f b6 19 movzbl (%ecx),%ebx
|
||||||
|
17b: 38 c3 cmp %al,%bl
|
||||||
|
17d: 74 e9 je 168 <strcmp+0x18>
|
||||||
|
}
|
||||||
|
return (uchar) * p - (uchar) * q;
|
||||||
|
17f: 29 d8 sub %ebx,%eax
|
||||||
|
}
|
||||||
|
181: 8b 5d fc mov -0x4(%ebp),%ebx
|
||||||
|
184: c9 leave
|
||||||
|
185: c3 ret
|
||||||
|
186: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
18d: 8d 76 00 lea 0x0(%esi),%esi
|
||||||
|
return (uchar) * p - (uchar) * q;
|
||||||
|
190: 0f b6 59 01 movzbl 0x1(%ecx),%ebx
|
||||||
|
194: 31 c0 xor %eax,%eax
|
||||||
|
196: 29 d8 sub %ebx,%eax
|
||||||
|
}
|
||||||
|
198: 8b 5d fc mov -0x4(%ebp),%ebx
|
||||||
|
19b: c9 leave
|
||||||
|
19c: c3 ret
|
||||||
|
return (uchar) * p - (uchar) * q;
|
||||||
|
19d: 0f b6 19 movzbl (%ecx),%ebx
|
||||||
|
1a0: 31 c0 xor %eax,%eax
|
||||||
|
1a2: eb db jmp 17f <strcmp+0x2f>
|
||||||
|
1a4: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
1ab: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
1af: 90 nop
|
||||||
|
|
||||||
|
000001b0 <strlen>:
|
||||||
|
|
||||||
|
uint strlen(const char *s) {
|
||||||
|
1b0: 55 push %ebp
|
||||||
|
1b1: 89 e5 mov %esp,%ebp
|
||||||
|
1b3: 8b 55 08 mov 0x8(%ebp),%edx
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n = 0; s[n]; n++) {
|
||||||
|
1b6: 80 3a 00 cmpb $0x0,(%edx)
|
||||||
|
1b9: 74 15 je 1d0 <strlen+0x20>
|
||||||
|
1bb: 31 c0 xor %eax,%eax
|
||||||
|
1bd: 8d 76 00 lea 0x0(%esi),%esi
|
||||||
|
1c0: 83 c0 01 add $0x1,%eax
|
||||||
|
1c3: 80 3c 02 00 cmpb $0x0,(%edx,%eax,1)
|
||||||
|
1c7: 89 c1 mov %eax,%ecx
|
||||||
|
1c9: 75 f5 jne 1c0 <strlen+0x10>
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
1cb: 89 c8 mov %ecx,%eax
|
||||||
|
1cd: 5d pop %ebp
|
||||||
|
1ce: c3 ret
|
||||||
|
1cf: 90 nop
|
||||||
|
for (n = 0; s[n]; n++) {
|
||||||
|
1d0: 31 c9 xor %ecx,%ecx
|
||||||
|
}
|
||||||
|
1d2: 5d pop %ebp
|
||||||
|
1d3: 89 c8 mov %ecx,%eax
|
||||||
|
1d5: c3 ret
|
||||||
|
1d6: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
1dd: 8d 76 00 lea 0x0(%esi),%esi
|
||||||
|
|
||||||
|
000001e0 <memset>:
|
||||||
|
|
||||||
|
void* memset(void *dst, int c, uint n) {
|
||||||
|
1e0: 55 push %ebp
|
||||||
|
1e1: 89 e5 mov %esp,%ebp
|
||||||
|
1e3: 57 push %edi
|
||||||
|
1e4: 8b 55 08 mov 0x8(%ebp),%edx
|
||||||
|
"d" (port), "0" (addr), "1" (cnt) :
|
||||||
|
"cc");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void stosb(void *addr, int data, int cnt) {
|
||||||
|
asm volatile ("cld; rep stosb" :
|
||||||
|
1e7: 8b 4d 10 mov 0x10(%ebp),%ecx
|
||||||
|
1ea: 8b 45 0c mov 0xc(%ebp),%eax
|
||||||
|
1ed: 89 d7 mov %edx,%edi
|
||||||
|
1ef: fc cld
|
||||||
|
1f0: f3 aa rep stos %al,%es:(%edi)
|
||||||
|
stosb(dst, c, n);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
1f2: 8b 7d fc mov -0x4(%ebp),%edi
|
||||||
|
1f5: 89 d0 mov %edx,%eax
|
||||||
|
1f7: c9 leave
|
||||||
|
1f8: c3 ret
|
||||||
|
1f9: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
|
||||||
|
00000200 <strchr>:
|
||||||
|
|
||||||
|
char* strchr(const char *s, char c) {
|
||||||
|
200: 55 push %ebp
|
||||||
|
201: 89 e5 mov %esp,%ebp
|
||||||
|
203: 8b 45 08 mov 0x8(%ebp),%eax
|
||||||
|
206: 0f b6 4d 0c movzbl 0xc(%ebp),%ecx
|
||||||
|
for (; *s; s++) {
|
||||||
|
20a: 0f b6 10 movzbl (%eax),%edx
|
||||||
|
20d: 84 d2 test %dl,%dl
|
||||||
|
20f: 75 12 jne 223 <strchr+0x23>
|
||||||
|
211: eb 1d jmp 230 <strchr+0x30>
|
||||||
|
213: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
217: 90 nop
|
||||||
|
218: 0f b6 50 01 movzbl 0x1(%eax),%edx
|
||||||
|
21c: 83 c0 01 add $0x1,%eax
|
||||||
|
21f: 84 d2 test %dl,%dl
|
||||||
|
221: 74 0d je 230 <strchr+0x30>
|
||||||
|
if (*s == c) {
|
||||||
|
223: 38 d1 cmp %dl,%cl
|
||||||
|
225: 75 f1 jne 218 <strchr+0x18>
|
||||||
|
return (char*)s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
227: 5d pop %ebp
|
||||||
|
228: c3 ret
|
||||||
|
229: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
return 0;
|
||||||
|
230: 31 c0 xor %eax,%eax
|
||||||
|
}
|
||||||
|
232: 5d pop %ebp
|
||||||
|
233: c3 ret
|
||||||
|
234: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
23b: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
23f: 90 nop
|
||||||
|
|
||||||
|
00000240 <gets>:
|
||||||
|
|
||||||
|
char* gets(char *buf, int max) {
|
||||||
|
240: 55 push %ebp
|
||||||
|
241: 89 e5 mov %esp,%ebp
|
||||||
|
243: 57 push %edi
|
||||||
|
244: 56 push %esi
|
||||||
|
int i, cc;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
for (i = 0; i + 1 < max;) {
|
||||||
|
cc = read(0, &c, 1);
|
||||||
|
245: 8d 7d e7 lea -0x19(%ebp),%edi
|
||||||
|
char* gets(char *buf, int max) {
|
||||||
|
248: 53 push %ebx
|
||||||
|
for (i = 0; i + 1 < max;) {
|
||||||
|
249: 31 db xor %ebx,%ebx
|
||||||
|
char* gets(char *buf, int max) {
|
||||||
|
24b: 83 ec 1c sub $0x1c,%esp
|
||||||
|
for (i = 0; i + 1 < max;) {
|
||||||
|
24e: eb 27 jmp 277 <gets+0x37>
|
||||||
|
cc = read(0, &c, 1);
|
||||||
|
250: 83 ec 04 sub $0x4,%esp
|
||||||
|
253: 6a 01 push $0x1
|
||||||
|
255: 57 push %edi
|
||||||
|
256: 6a 00 push $0x0
|
||||||
|
258: e8 2e 01 00 00 call 38b <read>
|
||||||
|
if (cc < 1) {
|
||||||
|
25d: 83 c4 10 add $0x10,%esp
|
||||||
|
260: 85 c0 test %eax,%eax
|
||||||
|
262: 7e 1d jle 281 <gets+0x41>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[i++] = c;
|
||||||
|
264: 0f b6 45 e7 movzbl -0x19(%ebp),%eax
|
||||||
|
268: 8b 55 08 mov 0x8(%ebp),%edx
|
||||||
|
26b: 88 44 1a ff mov %al,-0x1(%edx,%ebx,1)
|
||||||
|
if (c == '\n' || c == '\r') {
|
||||||
|
26f: 3c 0a cmp $0xa,%al
|
||||||
|
271: 74 1d je 290 <gets+0x50>
|
||||||
|
273: 3c 0d cmp $0xd,%al
|
||||||
|
275: 74 19 je 290 <gets+0x50>
|
||||||
|
for (i = 0; i + 1 < max;) {
|
||||||
|
277: 89 de mov %ebx,%esi
|
||||||
|
279: 83 c3 01 add $0x1,%ebx
|
||||||
|
27c: 3b 5d 0c cmp 0xc(%ebp),%ebx
|
||||||
|
27f: 7c cf jl 250 <gets+0x10>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
281: 8b 45 08 mov 0x8(%ebp),%eax
|
||||||
|
284: c6 04 30 00 movb $0x0,(%eax,%esi,1)
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
288: 8d 65 f4 lea -0xc(%ebp),%esp
|
||||||
|
28b: 5b pop %ebx
|
||||||
|
28c: 5e pop %esi
|
||||||
|
28d: 5f pop %edi
|
||||||
|
28e: 5d pop %ebp
|
||||||
|
28f: c3 ret
|
||||||
|
buf[i] = '\0';
|
||||||
|
290: 8b 45 08 mov 0x8(%ebp),%eax
|
||||||
|
293: 89 de mov %ebx,%esi
|
||||||
|
295: c6 04 30 00 movb $0x0,(%eax,%esi,1)
|
||||||
|
}
|
||||||
|
299: 8d 65 f4 lea -0xc(%ebp),%esp
|
||||||
|
29c: 5b pop %ebx
|
||||||
|
29d: 5e pop %esi
|
||||||
|
29e: 5f pop %edi
|
||||||
|
29f: 5d pop %ebp
|
||||||
|
2a0: c3 ret
|
||||||
|
2a1: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
2a8: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
2af: 90 nop
|
||||||
|
|
||||||
|
000002b0 <stat>:
|
||||||
|
|
||||||
|
int stat(const char *n, struct stat *st) {
|
||||||
|
2b0: 55 push %ebp
|
||||||
|
2b1: 89 e5 mov %esp,%ebp
|
||||||
|
2b3: 56 push %esi
|
||||||
|
2b4: 53 push %ebx
|
||||||
|
int fd;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fd = open(n, O_RDONLY);
|
||||||
|
2b5: 83 ec 08 sub $0x8,%esp
|
||||||
|
2b8: 6a 00 push $0x0
|
||||||
|
2ba: ff 75 08 push 0x8(%ebp)
|
||||||
|
2bd: e8 19 01 00 00 call 3db <open>
|
||||||
|
if (fd < 0) {
|
||||||
|
2c2: 83 c4 10 add $0x10,%esp
|
||||||
|
2c5: 85 c0 test %eax,%eax
|
||||||
|
2c7: 78 27 js 2f0 <stat+0x40>
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
r = fstat(fd, st);
|
||||||
|
2c9: 83 ec 08 sub $0x8,%esp
|
||||||
|
2cc: ff 75 0c push 0xc(%ebp)
|
||||||
|
2cf: 89 c3 mov %eax,%ebx
|
||||||
|
2d1: 50 push %eax
|
||||||
|
2d2: e8 cc 00 00 00 call 3a3 <fstat>
|
||||||
|
close(fd);
|
||||||
|
2d7: 89 1c 24 mov %ebx,(%esp)
|
||||||
|
r = fstat(fd, st);
|
||||||
|
2da: 89 c6 mov %eax,%esi
|
||||||
|
close(fd);
|
||||||
|
2dc: e8 2a 01 00 00 call 40b <close>
|
||||||
|
return r;
|
||||||
|
2e1: 83 c4 10 add $0x10,%esp
|
||||||
|
}
|
||||||
|
2e4: 8d 65 f8 lea -0x8(%ebp),%esp
|
||||||
|
2e7: 89 f0 mov %esi,%eax
|
||||||
|
2e9: 5b pop %ebx
|
||||||
|
2ea: 5e pop %esi
|
||||||
|
2eb: 5d pop %ebp
|
||||||
|
2ec: c3 ret
|
||||||
|
2ed: 8d 76 00 lea 0x0(%esi),%esi
|
||||||
|
return -1;
|
||||||
|
2f0: be ff ff ff ff mov $0xffffffff,%esi
|
||||||
|
2f5: eb ed jmp 2e4 <stat+0x34>
|
||||||
|
2f7: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
2fe: 66 90 xchg %ax,%ax
|
||||||
|
|
||||||
|
00000300 <atoi>:
|
||||||
|
|
||||||
|
int atoi(const char *s) {
|
||||||
|
300: 55 push %ebp
|
||||||
|
301: 89 e5 mov %esp,%ebp
|
||||||
|
303: 53 push %ebx
|
||||||
|
304: 8b 55 08 mov 0x8(%ebp),%edx
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
while ('0' <= *s && *s <= '9') {
|
||||||
|
307: 0f be 02 movsbl (%edx),%eax
|
||||||
|
30a: 8d 48 d0 lea -0x30(%eax),%ecx
|
||||||
|
30d: 80 f9 09 cmp $0x9,%cl
|
||||||
|
n = 0;
|
||||||
|
310: b9 00 00 00 00 mov $0x0,%ecx
|
||||||
|
while ('0' <= *s && *s <= '9') {
|
||||||
|
315: 77 1e ja 335 <atoi+0x35>
|
||||||
|
317: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
31e: 66 90 xchg %ax,%ax
|
||||||
|
n = n * 10 + *s++ - '0';
|
||||||
|
320: 83 c2 01 add $0x1,%edx
|
||||||
|
323: 8d 0c 89 lea (%ecx,%ecx,4),%ecx
|
||||||
|
326: 8d 4c 48 d0 lea -0x30(%eax,%ecx,2),%ecx
|
||||||
|
while ('0' <= *s && *s <= '9') {
|
||||||
|
32a: 0f be 02 movsbl (%edx),%eax
|
||||||
|
32d: 8d 58 d0 lea -0x30(%eax),%ebx
|
||||||
|
330: 80 fb 09 cmp $0x9,%bl
|
||||||
|
333: 76 eb jbe 320 <atoi+0x20>
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
335: 8b 5d fc mov -0x4(%ebp),%ebx
|
||||||
|
338: 89 c8 mov %ecx,%eax
|
||||||
|
33a: c9 leave
|
||||||
|
33b: c3 ret
|
||||||
|
33c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
|
||||||
|
00000340 <memmove>:
|
||||||
|
|
||||||
|
void* memmove(void *vdst, const void *vsrc, int n) {
|
||||||
|
340: 55 push %ebp
|
||||||
|
341: 89 e5 mov %esp,%ebp
|
||||||
|
343: 57 push %edi
|
||||||
|
344: 8b 45 10 mov 0x10(%ebp),%eax
|
||||||
|
347: 8b 55 08 mov 0x8(%ebp),%edx
|
||||||
|
34a: 56 push %esi
|
||||||
|
34b: 8b 75 0c mov 0xc(%ebp),%esi
|
||||||
|
char *dst;
|
||||||
|
const char *src;
|
||||||
|
|
||||||
|
dst = vdst;
|
||||||
|
src = vsrc;
|
||||||
|
while (n-- > 0) {
|
||||||
|
34e: 85 c0 test %eax,%eax
|
||||||
|
350: 7e 13 jle 365 <memmove+0x25>
|
||||||
|
352: 01 d0 add %edx,%eax
|
||||||
|
dst = vdst;
|
||||||
|
354: 89 d7 mov %edx,%edi
|
||||||
|
356: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
|
||||||
|
35d: 8d 76 00 lea 0x0(%esi),%esi
|
||||||
|
*dst++ = *src++;
|
||||||
|
360: a4 movsb %ds:(%esi),%es:(%edi)
|
||||||
|
while (n-- > 0) {
|
||||||
|
361: 39 f8 cmp %edi,%eax
|
||||||
|
363: 75 fb jne 360 <memmove+0x20>
|
||||||
|
}
|
||||||
|
return vdst;
|
||||||
|
}
|
||||||
|
365: 5e pop %esi
|
||||||
|
366: 89 d0 mov %edx,%eax
|
||||||
|
368: 5f pop %edi
|
||||||
|
369: 5d pop %ebp
|
||||||
|
36a: c3 ret
|
||||||
|
|
||||||
|
0000036b <fork>:
|
||||||
|
name: \
|
||||||
|
movl $SYS_ ## name, %eax; \
|
||||||
|
int $T_SYSCALL; \
|
||||||
|
ret
|
||||||
|
|
||||||
|
SYSCALL(fork)
|
||||||
|
36b: b8 01 00 00 00 mov $0x1,%eax
|
||||||
|
370: cd 40 int $0x40
|
||||||
|
372: c3 ret
|
||||||
|
|
||||||
|
00000373 <exit>:
|
||||||
|
SYSCALL(exit)
|
||||||
|
373: b8 02 00 00 00 mov $0x2,%eax
|
||||||
|
378: cd 40 int $0x40
|
||||||
|
37a: c3 ret
|
||||||
|
|
||||||
|
0000037b <wait>:
|
||||||
|
SYSCALL(wait)
|
||||||
|
37b: b8 03 00 00 00 mov $0x3,%eax
|
||||||
|
380: cd 40 int $0x40
|
||||||
|
382: c3 ret
|
||||||
|
|
||||||
|
00000383 <pipe>:
|
||||||
|
SYSCALL(pipe)
|
||||||
|
383: b8 04 00 00 00 mov $0x4,%eax
|
||||||
|
388: cd 40 int $0x40
|
||||||
|
38a: c3 ret
|
||||||
|
|
||||||
|
0000038b <read>:
|
||||||
|
SYSCALL(read)
|
||||||
|
38b: b8 05 00 00 00 mov $0x5,%eax
|
||||||
|
390: cd 40 int $0x40
|
||||||
|
392: c3 ret
|
||||||
|
|
||||||
|
00000393 <kill>:
|
||||||
|
SYSCALL(kill)
|
||||||
|
393: b8 06 00 00 00 mov $0x6,%eax
|
||||||
|
398: cd 40 int $0x40
|
||||||
|
39a: c3 ret
|
||||||
|
|
||||||
|
0000039b <exec>:
|
||||||
|
SYSCALL(exec)
|
||||||
|
39b: b8 07 00 00 00 mov $0x7,%eax
|
||||||
|
3a0: cd 40 int $0x40
|
||||||
|
3a2: c3 ret
|
||||||
|
|
||||||
|
000003a3 <fstat>:
|
||||||
|
SYSCALL(fstat)
|
||||||
|
3a3: b8 08 00 00 00 mov $0x8,%eax
|
||||||
|
3a8: cd 40 int $0x40
|
||||||
|
3aa: c3 ret
|
||||||
|
|
||||||
|
000003ab <chdir>:
|
||||||
|
SYSCALL(chdir)
|
||||||
|
3ab: b8 09 00 00 00 mov $0x9,%eax
|
||||||
|
3b0: cd 40 int $0x40
|
||||||
|
3b2: c3 ret
|
||||||
|
|
||||||
|
000003b3 <dup>:
|
||||||
|
SYSCALL(dup)
|
||||||
|
3b3: b8 0a 00 00 00 mov $0xa,%eax
|
||||||
|
3b8: cd 40 int $0x40
|
||||||
|
3ba: c3 ret
|
||||||
|
|
||||||
|
000003bb <getpid>:
|
||||||
|
SYSCALL(getpid)
|
||||||
|
3bb: b8 0b 00 00 00 mov $0xb,%eax
|
||||||
|
3c0: cd 40 int $0x40
|
||||||
|
3c2: c3 ret
|
||||||
|
|
||||||
|
000003c3 <sbrk>:
|
||||||
|
SYSCALL(sbrk)
|
||||||
|
3c3: b8 0c 00 00 00 mov $0xc,%eax
|
||||||
|
3c8: cd 40 int $0x40
|
||||||
|
3ca: c3 ret
|
||||||
|
|
||||||
|
000003cb <sleep>:
|
||||||
|
SYSCALL(sleep)
|
||||||
|
3cb: b8 0d 00 00 00 mov $0xd,%eax
|
||||||
|
3d0: cd 40 int $0x40
|
||||||
|
3d2: c3 ret
|
||||||
|
|
||||||
|
000003d3 <uptime>:
|
||||||
|
SYSCALL(uptime)
|
||||||
|
3d3: b8 0e 00 00 00 mov $0xe,%eax
|
||||||
|
3d8: cd 40 int $0x40
|
||||||
|
3da: c3 ret
|
||||||
|
|
||||||
|
000003db <open>:
|
||||||
|
SYSCALL(open)
|
||||||
|
3db: b8 0f 00 00 00 mov $0xf,%eax
|
||||||
|
3e0: cd 40 int $0x40
|
||||||
|
3e2: c3 ret
|
||||||
|
|
||||||
|
000003e3 <write>:
|
||||||
|
SYSCALL(write)
|
||||||
|
3e3: b8 10 00 00 00 mov $0x10,%eax
|
||||||
|
3e8: cd 40 int $0x40
|
||||||
|
3ea: c3 ret
|
||||||
|
|
||||||
|
000003eb <mknod>:
|
||||||
|
SYSCALL(mknod)
|
||||||
|
3eb: b8 11 00 00 00 mov $0x11,%eax
|
||||||
|
3f0: cd 40 int $0x40
|
||||||
|
3f2: c3 ret
|
||||||
|
|
||||||
|
000003f3 <unlink>:
|
||||||
|
SYSCALL(unlink)
|
||||||
|
3f3: b8 12 00 00 00 mov $0x12,%eax
|
||||||
|
3f8: cd 40 int $0x40
|
||||||
|
3fa: c3 ret
|
||||||
|
|
||||||
|
000003fb <link>:
|
||||||
|
SYSCALL(link)
|
||||||
|
3fb: b8 13 00 00 00 mov $0x13,%eax
|
||||||
|
400: cd 40 int $0x40
|
||||||
|
402: c3 ret
|
||||||
|
|
||||||
|
00000403 <mkdir>:
|
||||||
|
SYSCALL(mkdir)
|
||||||
|
403: b8 14 00 00 00 mov $0x14,%eax
|
||||||
|
408: cd 40 int $0x40
|
||||||
|
40a: c3 ret
|
||||||
|
|
||||||
|
0000040b <close>:
|
||||||
|
SYSCALL(close)
|
||||||
|
40b: b8 15 00 00 00 mov $0x15,%eax
|
||||||
|
410: cd 40 int $0x40
|
||||||
|
412: c3 ret
|
||||||
|
|
||||||
|
00000413 <getch>:
|
||||||
|
SYSCALL(getch)
|
||||||
|
413: b8 16 00 00 00 mov $0x16,%eax
|
||||||
|
418: cd 40 int $0x40
|
||||||
|
41a: c3 ret
|
||||||
|
|
||||||
|
0000041b <greeting>:
|
||||||
|
SYSCALL(greeting)
|
||||||
|
41b: b8 17 00 00 00 mov $0x17,%eax
|
||||||
|
420: cd 40 int $0x40
|
||||||
|
422: c3 ret
|
||||||
|
|
||||||
|
00000423 <shutdown>:
|
||||||
|
SYSCALL(shutdown)
|
||||||
|
423: b8 18 00 00 00 mov $0x18,%eax
|
||||||
|
428: cd 40 int $0x40
|
||||||
|
42a: c3 ret
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
// Test that fork fails gracefully.
|
||||||
|
// Tiny executable so that the limit can be filling the proc table.
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "stat.h"
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
#define N 1000
|
||||||
|
|
||||||
|
void printf(int fd, const char *s, ...) {
|
||||||
|
write(fd, s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void forktest(void) {
|
||||||
|
int n, pid;
|
||||||
|
|
||||||
|
printf(1, "fork test\n");
|
||||||
|
|
||||||
|
for (n = 0; n < N; n++) {
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == N) {
|
||||||
|
printf(1, "fork claimed to work N times!\n", N);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; n > 0; n--) {
|
||||||
|
if (wait() < 0) {
|
||||||
|
printf(1, "wait stopped early\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait() != -1) {
|
||||||
|
printf(1, "wait got too many\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(1, "fork test OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
forktest();
|
||||||
|
exit();
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
forktest.o: forktest.c /usr/include/stdc-predef.h types.h stat.h user.h
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,649 @@
|
|||||||
|
// File system implementation. Five layers:
|
||||||
|
// + Blocks: allocator for raw disk blocks.
|
||||||
|
// + Log: crash recovery for multi-step updates.
|
||||||
|
// + Files: inode allocator, reading, writing, metadata.
|
||||||
|
// + Directories: inode with special contents (list of other inodes!)
|
||||||
|
// + Names: paths like /usr/rtm/xv6/fs.c for convenient naming.
|
||||||
|
//
|
||||||
|
// This file contains the low-level file system manipulation
|
||||||
|
// routines. The (higher-level) system call implementations
|
||||||
|
// are in sysfile.c.
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "defs.h"
|
||||||
|
#include "param.h"
|
||||||
|
#include "stat.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "proc.h"
|
||||||
|
#include "spinlock.h"
|
||||||
|
#include "sleeplock.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "buf.h"
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
static void itrunc(struct inode*);
|
||||||
|
// there should be one superblock per disk device, but we run with
|
||||||
|
// only one device
|
||||||
|
struct superblock sb;
|
||||||
|
|
||||||
|
// Read the super block.
|
||||||
|
void readsb(int dev, struct superblock *sb) {
|
||||||
|
struct buf *bp;
|
||||||
|
|
||||||
|
bp = bread(dev, 1);
|
||||||
|
memmove(sb, bp->data, sizeof(*sb));
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero a block.
|
||||||
|
static void bzero(int dev, int bno) {
|
||||||
|
struct buf *bp;
|
||||||
|
|
||||||
|
bp = bread(dev, bno);
|
||||||
|
memset(bp->data, 0, BSIZE);
|
||||||
|
log_write(bp);
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocks.
|
||||||
|
|
||||||
|
// Allocate a zeroed disk block.
|
||||||
|
static uint balloc(uint dev) {
|
||||||
|
int b, bi, m;
|
||||||
|
struct buf *bp;
|
||||||
|
|
||||||
|
bp = 0;
|
||||||
|
for (b = 0; b < sb.size; b += BPB) {
|
||||||
|
bp = bread(dev, BBLOCK(b, sb));
|
||||||
|
for (bi = 0; bi < BPB && b + bi < sb.size; bi++) {
|
||||||
|
m = 1 << (bi % 8);
|
||||||
|
if ((bp->data[bi / 8] & m) == 0) { // Is block free?
|
||||||
|
bp->data[bi / 8] |= m; // Mark block in use.
|
||||||
|
log_write(bp);
|
||||||
|
brelse(bp);
|
||||||
|
bzero(dev, b + bi);
|
||||||
|
return b + bi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
panic("balloc: out of blocks");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free a disk block.
|
||||||
|
static void bfree(int dev, uint b) {
|
||||||
|
struct buf *bp;
|
||||||
|
int bi, m;
|
||||||
|
|
||||||
|
bp = bread(dev, BBLOCK(b, sb));
|
||||||
|
bi = b % BPB;
|
||||||
|
m = 1 << (bi % 8);
|
||||||
|
if ((bp->data[bi / 8] & m) == 0) {
|
||||||
|
panic("freeing free block");
|
||||||
|
}
|
||||||
|
bp->data[bi / 8] &= ~m;
|
||||||
|
log_write(bp);
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inodes.
|
||||||
|
//
|
||||||
|
// An inode describes a single unnamed file.
|
||||||
|
// The inode disk structure holds metadata: the file's type,
|
||||||
|
// its size, the number of links referring to it, and the
|
||||||
|
// list of blocks holding the file's content.
|
||||||
|
//
|
||||||
|
// The inodes are laid out sequentially on disk at
|
||||||
|
// sb.startinode. Each inode has a number, indicating its
|
||||||
|
// position on the disk.
|
||||||
|
//
|
||||||
|
// The kernel keeps a cache of in-use inodes in memory
|
||||||
|
// to provide a place for synchronizing access
|
||||||
|
// to inodes used by multiple processes. The cached
|
||||||
|
// inodes include book-keeping information that is
|
||||||
|
// not stored on disk: ip->ref and ip->valid.
|
||||||
|
//
|
||||||
|
// An inode and its in-memory representation go through a
|
||||||
|
// sequence of states before they can be used by the
|
||||||
|
// rest of the file system code.
|
||||||
|
//
|
||||||
|
// * Allocation: an inode is allocated if its type (on disk)
|
||||||
|
// is non-zero. ialloc() allocates, and iput() frees if
|
||||||
|
// the reference and link counts have fallen to zero.
|
||||||
|
//
|
||||||
|
// * Referencing in cache: an entry in the inode cache
|
||||||
|
// is free if ip->ref is zero. Otherwise ip->ref tracks
|
||||||
|
// the number of in-memory pointers to the entry (open
|
||||||
|
// files and current directories). iget() finds or
|
||||||
|
// creates a cache entry and increments its ref; iput()
|
||||||
|
// decrements ref.
|
||||||
|
//
|
||||||
|
// * Valid: the information (type, size, &c) in an inode
|
||||||
|
// cache entry is only correct when ip->valid is 1.
|
||||||
|
// ilock() reads the inode from
|
||||||
|
// the disk and sets ip->valid, while iput() clears
|
||||||
|
// ip->valid if ip->ref has fallen to zero.
|
||||||
|
//
|
||||||
|
// * Locked: file system code may only examine and modify
|
||||||
|
// the information in an inode and its content if it
|
||||||
|
// has first locked the inode.
|
||||||
|
//
|
||||||
|
// Thus a typical sequence is:
|
||||||
|
// ip = iget(dev, inum)
|
||||||
|
// ilock(ip)
|
||||||
|
// ... examine and modify ip->xxx ...
|
||||||
|
// iunlock(ip)
|
||||||
|
// iput(ip)
|
||||||
|
//
|
||||||
|
// ilock() is separate from iget() so that system calls can
|
||||||
|
// get a long-term reference to an inode (as for an open file)
|
||||||
|
// and only lock it for short periods (e.g., in read()).
|
||||||
|
// The separation also helps avoid deadlock and races during
|
||||||
|
// pathname lookup. iget() increments ip->ref so that the inode
|
||||||
|
// stays cached and pointers to it remain valid.
|
||||||
|
//
|
||||||
|
// Many internal file system functions expect the caller to
|
||||||
|
// have locked the inodes involved; this lets callers create
|
||||||
|
// multi-step atomic operations.
|
||||||
|
//
|
||||||
|
// The icache.lock spin-lock protects the allocation of icache
|
||||||
|
// entries. Since ip->ref indicates whether an entry is free,
|
||||||
|
// and ip->dev and ip->inum indicate which i-node an entry
|
||||||
|
// holds, one must hold icache.lock while using any of those fields.
|
||||||
|
//
|
||||||
|
// An ip->lock sleep-lock protects all ip-> fields other than ref,
|
||||||
|
// dev, and inum. One must hold ip->lock in order to
|
||||||
|
// read or write that inode's ip->valid, ip->size, ip->type, &c.
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct spinlock lock;
|
||||||
|
struct inode inode[NINODE];
|
||||||
|
} icache;
|
||||||
|
|
||||||
|
void iinit(int dev) {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
initlock(&icache.lock, "icache");
|
||||||
|
for (i = 0; i < NINODE; i++) {
|
||||||
|
initsleeplock(&icache.inode[i].lock, "inode");
|
||||||
|
}
|
||||||
|
|
||||||
|
readsb(dev, &sb);
|
||||||
|
cprintf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\
|
||||||
|
inodestart %d bmap start %d\n", sb.size, sb.nblocks,
|
||||||
|
sb.ninodes, sb.nlog, sb.logstart, sb.inodestart,
|
||||||
|
sb.bmapstart);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct inode* iget(uint dev, uint inum);
|
||||||
|
|
||||||
|
|
||||||
|
// Allocate an inode on device dev.
|
||||||
|
// Mark it as allocated by giving it type type.
|
||||||
|
// Returns an unlocked but allocated and referenced inode.
|
||||||
|
struct inode* ialloc(uint dev, short type) {
|
||||||
|
int inum;
|
||||||
|
struct buf *bp;
|
||||||
|
struct dinode *dip;
|
||||||
|
|
||||||
|
for (inum = 1; inum < sb.ninodes; inum++) {
|
||||||
|
bp = bread(dev, IBLOCK(inum, sb));
|
||||||
|
dip = (struct dinode*)bp->data + inum % IPB;
|
||||||
|
if (dip->type == 0) { // a free inode
|
||||||
|
memset(dip, 0, sizeof(*dip));
|
||||||
|
dip->type = type;
|
||||||
|
log_write(bp); // mark it allocated on the disk
|
||||||
|
brelse(bp);
|
||||||
|
return iget(dev, inum);
|
||||||
|
}
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
panic("ialloc: no inodes");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a modified in-memory inode to disk.
|
||||||
|
// Must be called after every change to an ip->xxx field
|
||||||
|
// that lives on disk, since i-node cache is write-through.
|
||||||
|
// Caller must hold ip->lock.
|
||||||
|
void iupdate(struct inode *ip) {
|
||||||
|
struct buf *bp;
|
||||||
|
struct dinode *dip;
|
||||||
|
|
||||||
|
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
||||||
|
dip = (struct dinode*)bp->data + ip->inum % IPB;
|
||||||
|
dip->type = ip->type;
|
||||||
|
dip->major = ip->major;
|
||||||
|
dip->minor = ip->minor;
|
||||||
|
dip->nlink = ip->nlink;
|
||||||
|
dip->size = ip->size;
|
||||||
|
memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
|
||||||
|
log_write(bp);
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the inode with number inum on device dev
|
||||||
|
// and return the in-memory copy. Does not lock
|
||||||
|
// the inode and does not read it from disk.
|
||||||
|
static struct inode* iget(uint dev, uint inum) {
|
||||||
|
struct inode *ip, *empty;
|
||||||
|
|
||||||
|
acquire(&icache.lock);
|
||||||
|
|
||||||
|
// Is the inode already cached?
|
||||||
|
empty = 0;
|
||||||
|
for (ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++) {
|
||||||
|
if (ip->ref > 0 && ip->dev == dev && ip->inum == inum) {
|
||||||
|
ip->ref++;
|
||||||
|
release(&icache.lock);
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
if (empty == 0 && ip->ref == 0) { // Remember empty slot.
|
||||||
|
empty = ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recycle an inode cache entry.
|
||||||
|
if (empty == 0) {
|
||||||
|
panic("iget: no inodes");
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = empty;
|
||||||
|
ip->dev = dev;
|
||||||
|
ip->inum = inum;
|
||||||
|
ip->ref = 1;
|
||||||
|
ip->valid = 0;
|
||||||
|
release(&icache.lock);
|
||||||
|
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment reference count for ip.
|
||||||
|
// Returns ip to enable ip = idup(ip1) idiom.
|
||||||
|
struct inode* idup(struct inode *ip) {
|
||||||
|
acquire(&icache.lock);
|
||||||
|
ip->ref++;
|
||||||
|
release(&icache.lock);
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock the given inode.
|
||||||
|
// Reads the inode from disk if necessary.
|
||||||
|
void ilock(struct inode *ip) {
|
||||||
|
struct buf *bp;
|
||||||
|
struct dinode *dip;
|
||||||
|
|
||||||
|
if (ip == 0 || ip->ref < 1) {
|
||||||
|
panic("ilock");
|
||||||
|
}
|
||||||
|
|
||||||
|
acquiresleep(&ip->lock);
|
||||||
|
|
||||||
|
if (ip->valid == 0) {
|
||||||
|
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
||||||
|
dip = (struct dinode*)bp->data + ip->inum % IPB;
|
||||||
|
ip->type = dip->type;
|
||||||
|
ip->major = dip->major;
|
||||||
|
ip->minor = dip->minor;
|
||||||
|
ip->nlink = dip->nlink;
|
||||||
|
ip->size = dip->size;
|
||||||
|
memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
|
||||||
|
brelse(bp);
|
||||||
|
ip->valid = 1;
|
||||||
|
if (ip->type == 0) {
|
||||||
|
panic("ilock: no type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock the given inode.
|
||||||
|
void iunlock(struct inode *ip) {
|
||||||
|
if (ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1) {
|
||||||
|
panic("iunlock");
|
||||||
|
}
|
||||||
|
|
||||||
|
releasesleep(&ip->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop a reference to an in-memory inode.
|
||||||
|
// If that was the last reference, the inode cache entry can
|
||||||
|
// be recycled.
|
||||||
|
// If that was the last reference and the inode has no links
|
||||||
|
// to it, free the inode (and its content) on disk.
|
||||||
|
// All calls to iput() must be inside a transaction in
|
||||||
|
// case it has to free the inode.
|
||||||
|
void iput(struct inode *ip) {
|
||||||
|
acquiresleep(&ip->lock);
|
||||||
|
if (ip->valid && ip->nlink == 0) {
|
||||||
|
acquire(&icache.lock);
|
||||||
|
int r = ip->ref;
|
||||||
|
release(&icache.lock);
|
||||||
|
if (r == 1) {
|
||||||
|
// inode has no links and no other references: truncate and free.
|
||||||
|
itrunc(ip);
|
||||||
|
ip->type = 0;
|
||||||
|
iupdate(ip);
|
||||||
|
ip->valid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
releasesleep(&ip->lock);
|
||||||
|
|
||||||
|
acquire(&icache.lock);
|
||||||
|
ip->ref--;
|
||||||
|
release(&icache.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common idiom: unlock, then put.
|
||||||
|
void iunlockput(struct inode *ip) {
|
||||||
|
iunlock(ip);
|
||||||
|
iput(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Inode content
|
||||||
|
//
|
||||||
|
// The content (data) associated with each inode is stored
|
||||||
|
// in blocks on the disk. The first NDIRECT block numbers
|
||||||
|
// are listed in ip->addrs[]. The next NINDIRECT blocks are
|
||||||
|
// listed in block ip->addrs[NDIRECT].
|
||||||
|
|
||||||
|
// Return the disk block address of the nth block in inode ip.
|
||||||
|
// If there is no such block, bmap allocates one.
|
||||||
|
static uint bmap(struct inode *ip, uint bn) {
|
||||||
|
uint addr, *a;
|
||||||
|
struct buf *bp;
|
||||||
|
|
||||||
|
if (bn < NDIRECT) {
|
||||||
|
if ((addr = ip->addrs[bn]) == 0) {
|
||||||
|
ip->addrs[bn] = addr = balloc(ip->dev);
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
bn -= NDIRECT;
|
||||||
|
|
||||||
|
if (bn < NINDIRECT) {
|
||||||
|
// Load indirect block, allocating if necessary.
|
||||||
|
if ((addr = ip->addrs[NDIRECT]) == 0) {
|
||||||
|
ip->addrs[NDIRECT] = addr = balloc(ip->dev);
|
||||||
|
}
|
||||||
|
bp = bread(ip->dev, addr);
|
||||||
|
a = (uint*)bp->data;
|
||||||
|
if ((addr = a[bn]) == 0) {
|
||||||
|
a[bn] = addr = balloc(ip->dev);
|
||||||
|
log_write(bp);
|
||||||
|
}
|
||||||
|
brelse(bp);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("bmap: out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate inode (discard contents).
|
||||||
|
// Only called when the inode has no links
|
||||||
|
// to it (no directory entries referring to it)
|
||||||
|
// and has no in-memory reference to it (is
|
||||||
|
// not an open file or current directory).
|
||||||
|
static void itrunc(struct inode *ip) {
|
||||||
|
int i, j;
|
||||||
|
struct buf *bp;
|
||||||
|
uint *a;
|
||||||
|
|
||||||
|
for (i = 0; i < NDIRECT; i++) {
|
||||||
|
if (ip->addrs[i]) {
|
||||||
|
bfree(ip->dev, ip->addrs[i]);
|
||||||
|
ip->addrs[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip->addrs[NDIRECT]) {
|
||||||
|
bp = bread(ip->dev, ip->addrs[NDIRECT]);
|
||||||
|
a = (uint*)bp->data;
|
||||||
|
for (j = 0; j < NINDIRECT; j++) {
|
||||||
|
if (a[j]) {
|
||||||
|
bfree(ip->dev, a[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
brelse(bp);
|
||||||
|
bfree(ip->dev, ip->addrs[NDIRECT]);
|
||||||
|
ip->addrs[NDIRECT] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip->size = 0;
|
||||||
|
iupdate(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy stat information from inode.
|
||||||
|
// Caller must hold ip->lock.
|
||||||
|
void stati(struct inode *ip, struct stat *st) {
|
||||||
|
st->dev = ip->dev;
|
||||||
|
st->ino = ip->inum;
|
||||||
|
st->type = ip->type;
|
||||||
|
st->nlink = ip->nlink;
|
||||||
|
st->size = ip->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Read data from inode.
|
||||||
|
// Caller must hold ip->lock.
|
||||||
|
int readi(struct inode *ip, char *dst, uint off, uint n) {
|
||||||
|
uint tot, m;
|
||||||
|
struct buf *bp;
|
||||||
|
|
||||||
|
if (ip->type == T_DEV) {
|
||||||
|
if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return devsw[ip->major].read(ip, dst, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (off > ip->size || off + n < off) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (off + n > ip->size) {
|
||||||
|
n = ip->size - off;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (tot = 0; tot < n; tot += m, off += m, dst += m) {
|
||||||
|
bp = bread(ip->dev, bmap(ip, off / BSIZE));
|
||||||
|
m = min(n - tot, BSIZE - off % BSIZE);
|
||||||
|
memmove(dst, bp->data + off % BSIZE, m);
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data to inode.
|
||||||
|
// Caller must hold ip->lock.
|
||||||
|
int writei(struct inode *ip, char *src, uint off, uint n) {
|
||||||
|
uint tot, m;
|
||||||
|
struct buf *bp;
|
||||||
|
|
||||||
|
if (ip->type == T_DEV) {
|
||||||
|
if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return devsw[ip->major].write(ip, src, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (off > ip->size || off + n < off) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (off + n > MAXFILE * BSIZE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (tot = 0; tot < n; tot += m, off += m, src += m) {
|
||||||
|
bp = bread(ip->dev, bmap(ip, off / BSIZE));
|
||||||
|
m = min(n - tot, BSIZE - off % BSIZE);
|
||||||
|
memmove(bp->data + off % BSIZE, src, m);
|
||||||
|
log_write(bp);
|
||||||
|
brelse(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0 && off > ip->size) {
|
||||||
|
ip->size = off;
|
||||||
|
iupdate(ip);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Directories
|
||||||
|
|
||||||
|
int namecmp(const char *s, const char *t) {
|
||||||
|
return strncmp(s, t, DIRSIZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a directory entry in a directory.
|
||||||
|
// If found, set *poff to byte offset of entry.
|
||||||
|
struct inode* dirlookup(struct inode *dp, char *name, uint *poff) {
|
||||||
|
uint off, inum;
|
||||||
|
struct dirent de;
|
||||||
|
|
||||||
|
if (dp->type != T_DIR) {
|
||||||
|
panic("dirlookup not DIR");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (off = 0; off < dp->size; off += sizeof(de)) {
|
||||||
|
if (readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||||
|
panic("dirlookup read");
|
||||||
|
}
|
||||||
|
if (de.inum == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (namecmp(name, de.name) == 0) {
|
||||||
|
// entry matches path element
|
||||||
|
if (poff) {
|
||||||
|
*poff = off;
|
||||||
|
}
|
||||||
|
inum = de.inum;
|
||||||
|
return iget(dp->dev, inum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a new directory entry (name, inum) into the directory dp.
|
||||||
|
int dirlink(struct inode *dp, char *name, uint inum) {
|
||||||
|
int off;
|
||||||
|
struct dirent de;
|
||||||
|
struct inode *ip;
|
||||||
|
|
||||||
|
// Check that name is not present.
|
||||||
|
if ((ip = dirlookup(dp, name, 0)) != 0) {
|
||||||
|
iput(ip);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for an empty dirent.
|
||||||
|
for (off = 0; off < dp->size; off += sizeof(de)) {
|
||||||
|
if (readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||||
|
panic("dirlink read");
|
||||||
|
}
|
||||||
|
if (de.inum == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(de.name, name, DIRSIZ);
|
||||||
|
de.inum = inum;
|
||||||
|
if (writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||||
|
panic("dirlink");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
|
||||||
|
// Copy the next path element from path into name.
|
||||||
|
// Return a pointer to the element following the copied one.
|
||||||
|
// The returned path has no leading slashes,
|
||||||
|
// so the caller can check *path=='\0' to see if the name is the last one.
|
||||||
|
// If no name to remove, return 0.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// skipelem("a/bb/c", name) = "bb/c", setting name = "a"
|
||||||
|
// skipelem("///a//bb", name) = "bb", setting name = "a"
|
||||||
|
// skipelem("a", name) = "", setting name = "a"
|
||||||
|
// skipelem("", name) = skipelem("////", name) = 0
|
||||||
|
//
|
||||||
|
static char* skipelem(char *path, char *name) {
|
||||||
|
char *s;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
while (*path == '/') {
|
||||||
|
path++;
|
||||||
|
}
|
||||||
|
if (*path == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
s = path;
|
||||||
|
while (*path != '/' && *path != 0) {
|
||||||
|
path++;
|
||||||
|
}
|
||||||
|
len = path - s;
|
||||||
|
if (len >= DIRSIZ) {
|
||||||
|
memmove(name, s, DIRSIZ);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memmove(name, s, len);
|
||||||
|
name[len] = 0;
|
||||||
|
}
|
||||||
|
while (*path == '/') {
|
||||||
|
path++;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up and return the inode for a path name.
|
||||||
|
// If parent != 0, return the inode for the parent and copy the final
|
||||||
|
// path element into name, which must have room for DIRSIZ bytes.
|
||||||
|
// Must be called inside a transaction since it calls iput().
|
||||||
|
static struct inode* namex(char *path, int nameiparent, char *name) {
|
||||||
|
struct inode *ip, *next;
|
||||||
|
|
||||||
|
if (*path == '/') {
|
||||||
|
ip = iget(ROOTDEV, ROOTINO);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ip = idup(myproc()->cwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((path = skipelem(path, name)) != 0) {
|
||||||
|
ilock(ip);
|
||||||
|
if (ip->type != T_DIR) {
|
||||||
|
iunlockput(ip);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (nameiparent && *path == '\0') {
|
||||||
|
// Stop one level early.
|
||||||
|
iunlock(ip);
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
if ((next = dirlookup(ip, name, 0)) == 0) {
|
||||||
|
iunlockput(ip);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
iunlockput(ip);
|
||||||
|
ip = next;
|
||||||
|
}
|
||||||
|
if (nameiparent) {
|
||||||
|
iput(ip);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct inode* namei(char *path) {
|
||||||
|
char name[DIRSIZ];
|
||||||
|
return namex(path, 0, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct inode*nameiparent(char *path, char *name) {
|
||||||
|
return namex(path, 1, name);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fs.o: fs.c /usr/include/stdc-predef.h types.h defs.h param.h stat.h mmu.h \
|
||||||
|
proc.h spinlock.h sleeplock.h fs.h buf.h file.h
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// On-disk file system format.
|
||||||
|
// Both the kernel and user programs use this header file.
|
||||||
|
|
||||||
|
|
||||||
|
#define ROOTINO 1 // root i-number
|
||||||
|
#define BSIZE 512 // block size
|
||||||
|
|
||||||
|
// Disk layout:
|
||||||
|
// [ boot block | super block | log | inode blocks |
|
||||||
|
// free bit map | data blocks]
|
||||||
|
//
|
||||||
|
// mkfs computes the super block and builds an initial file system. The
|
||||||
|
// super block describes the disk layout:
|
||||||
|
struct superblock {
|
||||||
|
uint size; // Size of file system image (blocks)
|
||||||
|
uint nblocks; // Number of data blocks
|
||||||
|
uint ninodes; // Number of inodes.
|
||||||
|
uint nlog; // Number of log blocks
|
||||||
|
uint logstart; // Block number of first log block
|
||||||
|
uint inodestart; // Block number of first inode block
|
||||||
|
uint bmapstart; // Block number of first free map block
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NDIRECT 12
|
||||||
|
#define NINDIRECT (BSIZE / sizeof(uint))
|
||||||
|
#define MAXFILE (NDIRECT + NINDIRECT)
|
||||||
|
|
||||||
|
// On-disk inode structure
|
||||||
|
struct dinode {
|
||||||
|
short type; // File type
|
||||||
|
short major; // Major device number (T_DEV only)
|
||||||
|
short minor; // Minor device number (T_DEV only)
|
||||||
|
short nlink; // Number of links to inode in file system
|
||||||
|
uint size; // Size of file (bytes)
|
||||||
|
uint addrs[NDIRECT + 1]; // Data block addresses
|
||||||
|
};
|
||||||
|
|
||||||
|
// Inodes per block.
|
||||||
|
#define IPB (BSIZE / sizeof(struct dinode))
|
||||||
|
|
||||||
|
// Block containing inode i
|
||||||
|
#define IBLOCK(i, sb) ((i) / IPB + sb.inodestart)
|
||||||
|
|
||||||
|
// Bitmap bits per block
|
||||||
|
#define BPB (BSIZE * 8)
|
||||||
|
|
||||||
|
// Block of free map containing bit for block b
|
||||||
|
#define BBLOCK(b, sb) (b / BPB + sb.bmapstart)
|
||||||
|
|
||||||
|
// Directory is a file containing a sequence of dirent structures.
|
||||||
|
#define DIRSIZ 14
|
||||||
|
|
||||||
|
struct dirent {
|
||||||
|
ushort inum;
|
||||||
|
char name[DIRSIZ];
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
# -*- gdb-script -*-
|
||||||
|
|
||||||
|
# Utility functions to pretty-print x86 segment/interrupt descriptors.
|
||||||
|
# To load this file, run "source gdbutil" in gdb.
|
||||||
|
# printdesc and printdescs are the main entry points.
|
||||||
|
|
||||||
|
# IA32 2007, Volume 3A, Table 3-2
|
||||||
|
set $STS_T16A = 0x1
|
||||||
|
set $STS_LDT = 0x2
|
||||||
|
set $STS_T16B = 0x3
|
||||||
|
set $STS_CG16 = 0x4
|
||||||
|
set $STS_TG = 0x5
|
||||||
|
set $STS_IG16 = 0x6
|
||||||
|
set $STS_TG16 = 0x7
|
||||||
|
set $STS_T32A = 0x9
|
||||||
|
set $STS_T32B = 0xB
|
||||||
|
set $STS_CG32 = 0xC
|
||||||
|
set $STS_IG32 = 0xE
|
||||||
|
set $STS_TG32 = 0xF
|
||||||
|
|
||||||
|
define outputsts
|
||||||
|
while 1
|
||||||
|
if $arg0 == $STS_T16A
|
||||||
|
echo STS_T16A
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_LDT
|
||||||
|
echo STS_LDT\
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_T16B
|
||||||
|
echo STS_T16B
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_CG16
|
||||||
|
echo STS_CG16
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_TG
|
||||||
|
echo STS_TG\ \
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_IG16
|
||||||
|
echo STS_IG16
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_TG16
|
||||||
|
echo STS_TG16
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_T32A
|
||||||
|
echo STS_T32A
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_T32B
|
||||||
|
echo STS_T32B
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_CG32
|
||||||
|
echo STS_CG32
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_IG32
|
||||||
|
echo STS_IG32
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
if $arg0 == $STS_TG32
|
||||||
|
echo STS_TG32
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
echo Reserved
|
||||||
|
loop_break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# IA32 2007, Volume 3A, Table 3-1
|
||||||
|
set $STA_X = 0x8
|
||||||
|
set $STA_E = 0x4
|
||||||
|
set $STA_C = 0x4
|
||||||
|
set $STA_W = 0x2
|
||||||
|
set $STA_R = 0x2
|
||||||
|
set $STA_A = 0x1
|
||||||
|
|
||||||
|
define outputsta
|
||||||
|
if $arg0 & $STA_X
|
||||||
|
# Code segment
|
||||||
|
echo code
|
||||||
|
if $arg0 & $STA_C
|
||||||
|
echo |STA_C
|
||||||
|
end
|
||||||
|
if $arg0 & $STA_R
|
||||||
|
echo |STA_R
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# Data segment
|
||||||
|
echo data
|
||||||
|
if $arg0 & $STA_E
|
||||||
|
echo |STA_E
|
||||||
|
end
|
||||||
|
if $arg0 & $STA_W
|
||||||
|
echo |STA_W
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if $arg0 & $STA_A
|
||||||
|
echo |STA_A
|
||||||
|
else
|
||||||
|
printf " "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# xv6-specific
|
||||||
|
set $SEG_KCODE = 1
|
||||||
|
set $SEG_KDATA = 2
|
||||||
|
set $SEG_KCPU = 3
|
||||||
|
set $SEG_UCODE = 4
|
||||||
|
set $SEG_UDATA = 5
|
||||||
|
set $SEG_TSS = 6
|
||||||
|
|
||||||
|
define outputcs
|
||||||
|
if ($arg0 & 4) == 0
|
||||||
|
if $arg0 >> 3 == $SEG_KCODE
|
||||||
|
printf "SEG_KCODE<<3"
|
||||||
|
end
|
||||||
|
if $arg0 >> 3 == $SEG_KDATA
|
||||||
|
printf "SEG_KDATA<<3"
|
||||||
|
end
|
||||||
|
if $arg0 >> 3 == $SEG_KCPU
|
||||||
|
printf "SEG_KCPU<<3"
|
||||||
|
end
|
||||||
|
if $arg0 >> 3 == $SEG_UCODE
|
||||||
|
printf "SEG_UCODE<<3"
|
||||||
|
end
|
||||||
|
if $arg0 >> 3 == $SEG_UDATA
|
||||||
|
printf "SEG_UDATA<<3"
|
||||||
|
end
|
||||||
|
if $arg0 >> 3 == $SEG_TSS
|
||||||
|
printf "SEG_TSS<<3"
|
||||||
|
end
|
||||||
|
if ($arg0 >> 3 < 1) + ($arg0 >> 3 > 6)
|
||||||
|
printf "GDT[%d]", $arg0 >> 3
|
||||||
|
end
|
||||||
|
else
|
||||||
|
printf "LDT[%d]", $arg0 >> 3
|
||||||
|
end
|
||||||
|
if ($arg0 & 3) > 0
|
||||||
|
printf "|"
|
||||||
|
outputdpl ($arg0&3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define outputdpl
|
||||||
|
if $arg0 == 0
|
||||||
|
printf "DPL_KERN"
|
||||||
|
else
|
||||||
|
if $arg0 == 3
|
||||||
|
printf "DPL_USER"
|
||||||
|
else
|
||||||
|
printf "DPL%d", $arg0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define printdesc
|
||||||
|
if $argc != 1
|
||||||
|
echo Usage: printdesc expr
|
||||||
|
else
|
||||||
|
_printdesc ((uint*)&($arg0))[0] ((uint*)&($arg0))[1]
|
||||||
|
printf "\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
document printdesc
|
||||||
|
Print an x86 segment or gate descriptor.
|
||||||
|
printdesc EXPR
|
||||||
|
EXPR must evaluate to a descriptor value. It can be of any C type.
|
||||||
|
end
|
||||||
|
|
||||||
|
define _printdesc
|
||||||
|
_printdesc1 $arg0 $arg1 ($arg1>>15&1) ($arg1>>13&3) ($arg1>>12&1) ($arg1>>8&15)
|
||||||
|
end
|
||||||
|
|
||||||
|
define _printdesc1
|
||||||
|
# 2:P 3:DPL 4:S 5:Type
|
||||||
|
if $arg2 == 0
|
||||||
|
printf "P = 0 (Not present)"
|
||||||
|
else
|
||||||
|
printf "type = "
|
||||||
|
if $arg4 == 0
|
||||||
|
# System segment
|
||||||
|
outputsts $arg5
|
||||||
|
printf " (0x%x) ", $arg5
|
||||||
|
_printsysdesc $arg0 $arg1 $arg5
|
||||||
|
else
|
||||||
|
# Code/data segment
|
||||||
|
outputsta $arg5
|
||||||
|
printf " "
|
||||||
|
_printsegdesc $arg0 $arg1
|
||||||
|
end
|
||||||
|
|
||||||
|
printf " DPL = "
|
||||||
|
outputdpl $arg3
|
||||||
|
printf " (%d)", $arg3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define _printsysdesc
|
||||||
|
# 2:Type
|
||||||
|
# GDB's || is buggy
|
||||||
|
if ($arg2 == $STS_TG) + (($arg2&7) == $STS_IG16) + (($arg2&7) == $STS_TG16)
|
||||||
|
# Gate descriptor
|
||||||
|
_printgate $arg2 ($arg0>>16) ($arg0&0xFFFF) ($arg1>>16)
|
||||||
|
else
|
||||||
|
# System segment descriptor
|
||||||
|
_printsegdesc $arg0 $arg1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define _printgate
|
||||||
|
# IA32 2007, Voume 3A, Figure 5-2
|
||||||
|
# 0:Type 1:CS 2:Offset 15..0 3:Offset 31..16
|
||||||
|
printf "CS = "
|
||||||
|
outputcs $arg1
|
||||||
|
printf " (%d)", $arg1
|
||||||
|
|
||||||
|
if (($arg0&7) == $STS_IG16) + (($arg0&7) == $STS_TG16)
|
||||||
|
printf " Offset = "
|
||||||
|
output/a $arg3 << 16 | $arg2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define _printsegdesc
|
||||||
|
# IA32 20007, Volume 3A, Figure 3-8 and Figure 4-1
|
||||||
|
_printsegdesc1 ($arg0>>16) ($arg1&0xFF) ($arg1>>24) ($arg0&0xFFFF) ($arg1>>16&15) ($arg1>>23&1)
|
||||||
|
if ($arg1>>12&1) == 1
|
||||||
|
printf " AVL = %d", $arg1>>20&1
|
||||||
|
if ($arg1>>11&1) == 0
|
||||||
|
# Data segment
|
||||||
|
if ($arg1>>22&1) == 0
|
||||||
|
printf " B = small (0) "
|
||||||
|
else
|
||||||
|
printf " B = big (1) "
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# Code segment
|
||||||
|
printf " D = "
|
||||||
|
if ($arg1>>22&1) == 0
|
||||||
|
printf "16-bit (0)"
|
||||||
|
else
|
||||||
|
printf "32-bit (1)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define _printsegdesc1
|
||||||
|
# 0:Base 0..15 1:Base 16..23 2:Base 24..32 3:Limit 0..15 4:Limit 16..19 5:G
|
||||||
|
printf "base = 0x%08x", $arg0 | ($arg1<<16) | ($arg2<<24)
|
||||||
|
printf " limit = 0x"
|
||||||
|
if $arg5 == 0
|
||||||
|
printf "%08x", $arg3 | ($arg4<<16)
|
||||||
|
else
|
||||||
|
printf "%08x", (($arg3 | ($arg4<<16)) << 12) | 0xFFF
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define printdescs
|
||||||
|
if $argc < 1 || $argc > 2
|
||||||
|
echo Usage: printdescs expr [count]
|
||||||
|
else
|
||||||
|
if $argc == 1
|
||||||
|
_printdescs ($arg0) (sizeof($arg0)/sizeof(($arg0)[0]))
|
||||||
|
else
|
||||||
|
_printdescs ($arg0) ($arg1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
document printdescs
|
||||||
|
Print an array of x86 segment or gate descriptors.
|
||||||
|
printdescs EXPR [COUNT]
|
||||||
|
EXPR must evaluate to an array of descriptors.
|
||||||
|
end
|
||||||
|
|
||||||
|
define _printdescs
|
||||||
|
set $i = 0
|
||||||
|
while $i < $arg1
|
||||||
|
printf "[%d] ", $i
|
||||||
|
printdesc $arg0[$i]
|
||||||
|
set $i = $i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
# Generate syscall.h, syscalltable.h or usys.S. These are the header and assembly
|
||||||
|
# files for system calls.
|
||||||
|
#
|
||||||
|
# Generating these files from one script avoids them getting out of sync.
|
||||||
|
#
|
||||||
|
# Specify an argument of -h to generate syscall.h
|
||||||
|
# Specify an argument of -c to generate syscalltable.h
|
||||||
|
# Specify an argument of -a to generate usys.S
|
||||||
|
#
|
||||||
|
# Note that you also need to update user.h with the declarations for these functions that
|
||||||
|
# user programs will use. This ensures that the C compiler generates the correct code to
|
||||||
|
# push the parameters on to the stack.
|
||||||
|
|
||||||
|
my @syscalls = (
|
||||||
|
"fork",
|
||||||
|
"exit",
|
||||||
|
"wait",
|
||||||
|
"pipe",
|
||||||
|
"read",
|
||||||
|
"kill",
|
||||||
|
"exec",
|
||||||
|
"fstat",
|
||||||
|
"chdir",
|
||||||
|
"dup",
|
||||||
|
"getpid",
|
||||||
|
"sbrk",
|
||||||
|
"sleep",
|
||||||
|
"uptime",
|
||||||
|
"open",
|
||||||
|
"write",
|
||||||
|
"mknod",
|
||||||
|
"unlink",
|
||||||
|
"link",
|
||||||
|
"mkdir",
|
||||||
|
"close",
|
||||||
|
"getch",
|
||||||
|
"greeting",
|
||||||
|
"shutdown"
|
||||||
|
);
|
||||||
|
|
||||||
|
my $i;
|
||||||
|
if ($#ARGV == -1)
|
||||||
|
{
|
||||||
|
print 'Error: No argument supplied to gensyscalls.pl';
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (($ARGV[0] ne '-h') && ($ARGV[0] ne '-a') && ($ARGV[0] ne '-c'))
|
||||||
|
{
|
||||||
|
print 'Error: Invalid argument to gensyscalls.pl';
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ($ARGV[0] eq '-h'|| $ARGV[0] eq '-c')
|
||||||
|
{
|
||||||
|
print "// Generated by gensyscalls.pl. Do not edit.\n";
|
||||||
|
print "// To change syscall numbers or add new syscalls, edit gensyscalls.pl\n";
|
||||||
|
print "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print "# Generated by gensyscalls.pl. Do not edit.\n";
|
||||||
|
print "# To change syscall numbers or add new syscalls, edit gensyscalls.pl\n";
|
||||||
|
print "\n";
|
||||||
|
}
|
||||||
|
for ($i = 0; $i < scalar(@syscalls); $i++)
|
||||||
|
{
|
||||||
|
my $index = $i + 1;
|
||||||
|
if ($ARGV[0] eq '-h')
|
||||||
|
{
|
||||||
|
print "#define SYS_$syscalls[$i]\t\t$index\n";
|
||||||
|
}
|
||||||
|
elsif ($ARGV[0] eq '-c')
|
||||||
|
{
|
||||||
|
print "extern int sys_$syscalls[$i](void);\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($ARGV[0] eq '-a')
|
||||||
|
{
|
||||||
|
print "#include \"syscall.h\"\n";
|
||||||
|
print "#include \"traps.h\"\n";
|
||||||
|
print "\n";
|
||||||
|
print "#define SYSCALL(name) \\\n";
|
||||||
|
print ".globl name; \\\n";
|
||||||
|
print "name: \\\n";
|
||||||
|
print "\tmovl\t\$SYS_ ## name, \%eax; \\\n";
|
||||||
|
print "\tint\t\$T_SYSCALL; \\\n";
|
||||||
|
print "\tret\n";
|
||||||
|
print "\n";
|
||||||
|
for ($i = 0; $i < scalar(@syscalls); $i++)
|
||||||
|
{
|
||||||
|
print "SYSCALL($syscalls[$i])\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ($ARGV[0] eq '-c')
|
||||||
|
{
|
||||||
|
print "\n";
|
||||||
|
print "static int(*syscalls[])(void) = {\n";
|
||||||
|
for ($i = 0; $i < scalar(@syscalls); $i++)
|
||||||
|
{
|
||||||
|
print "[SYS_$syscalls[$i]]\tsys_$syscalls[$i],\n";
|
||||||
|
}
|
||||||
|
print "};\n"
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
// Simple grep. Only supports ^ . * $ operators.
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "stat.h"
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
int match(char*, char*);
|
||||||
|
|
||||||
|
void grep(char *pattern, int fd) {
|
||||||
|
int n, m;
|
||||||
|
char *p, *q;
|
||||||
|
|
||||||
|
m = 0;
|
||||||
|
while ((n = read(fd, buf + m, sizeof(buf) - m - 1)) > 0) {
|
||||||
|
m += n;
|
||||||
|
buf[m] = '\0';
|
||||||
|
p = buf;
|
||||||
|
while ((q = strchr(p, '\n')) != 0) {
|
||||||
|
*q = 0;
|
||||||
|
if (match(pattern, p)) {
|
||||||
|
*q = '\n';
|
||||||
|
write(1, p, q + 1 - p);
|
||||||
|
}
|
||||||
|
p = q + 1;
|
||||||
|
}
|
||||||
|
if (p == buf) {
|
||||||
|
m = 0;
|
||||||
|
}
|
||||||
|
if (m > 0) {
|
||||||
|
m -= p - buf;
|
||||||
|
memmove(buf, p, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int fd, i;
|
||||||
|
char *pattern;
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
printf(2, "usage: grep pattern [file ...]\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
pattern = argv[1];
|
||||||
|
|
||||||
|
if (argc <= 2) {
|
||||||
|
grep(pattern, 0);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 2; i < argc; i++) {
|
||||||
|
if ((fd = open(argv[i], 0)) < 0) {
|
||||||
|
printf(1, "grep: cannot open %s\n", argv[i]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
grep(pattern, fd);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regexp matcher from Kernighan & Pike,
|
||||||
|
// The Practice of Programming, Chapter 9.
|
||||||
|
|
||||||
|
int matchhere(char*, char*);
|
||||||
|
int matchstar(int, char*, char*);
|
||||||
|
|
||||||
|
int match(char *re, char *text) {
|
||||||
|
if (re[0] == '^') {
|
||||||
|
return matchhere(re + 1, text);
|
||||||
|
}
|
||||||
|
do { // must look at empty string
|
||||||
|
if (matchhere(re, text)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (*text++ != '\0');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchhere: search for re at beginning of text
|
||||||
|
int matchhere(char *re, char *text){
|
||||||
|
if (re[0] == '\0') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (re[1] == '*') {
|
||||||
|
return matchstar(re[0], re + 2, text);
|
||||||
|
}
|
||||||
|
if (re[0] == '$' && re[1] == '\0') {
|
||||||
|
return *text == '\0';
|
||||||
|
}
|
||||||
|
if (*text != '\0' && (re[0] == '.' || re[0] == *text)) {
|
||||||
|
return matchhere(re + 1, text + 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchstar: search for c*re at beginning of text
|
||||||
|
int matchstar(int c, char *re, char *text) {
|
||||||
|
do { // a * matches zero or more instances
|
||||||
|
if (matchhere(re, text)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (*text != '\0' && (*text++ == c || c == '.'));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
00000000 grep.c
|
||||||
|
00000000 ulib.c
|
||||||
|
00000000 printf.c
|
||||||
|
00000680 printint
|
||||||
|
00000af0 digits.0
|
||||||
|
00000000 umalloc.c
|
||||||
|
000012a0 freep
|
||||||
|
000012a4 base
|
||||||
|
00000370 strcpy
|
||||||
|
00000730 printf
|
||||||
|
0000066b greeting
|
||||||
|
00000590 memmove
|
||||||
|
000000c0 matchhere
|
||||||
|
0000063b mknod
|
||||||
|
00000490 gets
|
||||||
|
0000060b getpid
|
||||||
|
000001d0 grep
|
||||||
|
00000960 malloc
|
||||||
|
0000061b sleep
|
||||||
|
000005d3 pipe
|
||||||
|
00000663 getch
|
||||||
|
00000633 write
|
||||||
|
000005f3 fstat
|
||||||
|
000005e3 kill
|
||||||
|
000005fb chdir
|
||||||
|
000005eb exec
|
||||||
|
000005cb wait
|
||||||
|
000005db read
|
||||||
|
00000643 unlink
|
||||||
|
000005bb fork
|
||||||
|
00000613 sbrk
|
||||||
|
00000623 uptime
|
||||||
|
00000e90 __bss_start
|
||||||
|
00000430 memset
|
||||||
|
00000000 main
|
||||||
|
00000310 matchstar
|
||||||
|
000003a0 strcmp
|
||||||
|
00000673 shutdown
|
||||||
|
00000603 dup
|
||||||
|
00000ea0 buf
|
||||||
|
00000500 stat
|
||||||
|
00000e90 _edata
|
||||||
|
000012ac _end
|
||||||
|
00000170 match
|
||||||
|
0000064b link
|
||||||
|
000005c3 exit
|
||||||
|
00000550 atoi
|
||||||
|
00000400 strlen
|
||||||
|
0000062b open
|
||||||
|
00000450 strchr
|
||||||
|
00000653 mkdir
|
||||||
|
0000065b close
|
||||||
|
000008d0 free
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "user.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
greeting();
|
||||||
|
exit();
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user