Initial Upload

This commit is contained in:
iDunnoDev
2022-12-06 11:49:47 +00:00
committed by iDunnoDev
commit 0ee33aaa97
274 changed files with 60109 additions and 0 deletions

16
.cvsignore Normal file
View File

@ -0,0 +1,16 @@
*.asm
*.d
*.sym
_*
kernel
user1
userfs
usertests
xv6.img
vectors.S
bochsout.txt
bootblock
bootother
bootother.out
parport.out
fmt

4
.dir-locals.el Normal file
View File

@ -0,0 +1,4 @@
((c-mode
(indent-tabs-mode . nil)
(c-file-style . "bsd")
(c-basic-offset . 2)))

27
.gdbinit.tmpl Normal file
View File

@ -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

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.img filter=lfs diff=lfs merge=lfs -text

28
.vscode/launch.json vendored Normal file
View File

@ -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"
}
]
}

35
.vscode/tasks.json vendored Normal file
View File

@ -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": []
}
]
}

24
LICENSE Normal file
View File

@ -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.

250
Makefile Normal file
View File

@ -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
_argtest Normal file

Binary file not shown.

BIN
_cat Normal file

Binary file not shown.

BIN
_echo Normal file

Binary file not shown.

BIN
_forktest Normal file

Binary file not shown.

BIN
_grep Normal file

Binary file not shown.

BIN
_hello Normal file

Binary file not shown.

BIN
_init Normal file

Binary file not shown.

BIN
_kill Normal file

Binary file not shown.

BIN
_ln Normal file

Binary file not shown.

BIN
_ls Normal file

Binary file not shown.

BIN
_mkdir Normal file

Binary file not shown.

BIN
_rm Normal file

Binary file not shown.

BIN
_screen Normal file

Binary file not shown.

BIN
_sh Normal file

Binary file not shown.

BIN
_shutdown Normal file

Binary file not shown.

BIN
_stressfs Normal file

Binary file not shown.

BIN
_usertests Normal file

Binary file not shown.

BIN
_wc Normal file

Binary file not shown.

BIN
_zombie Normal file

Binary file not shown.

1162
argtest.asm Normal file

File diff suppressed because it is too large Load Diff

10
argtest.c Normal file
View File

@ -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();
}

1
argtest.d Normal file
View File

@ -0,0 +1 @@
argtest.o: argtest.c /usr/include/stdc-predef.h types.h user.h

BIN
argtest.o Normal file

Binary file not shown.

48
argtest.sym Normal file
View File

@ -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

18
asm.h Normal file
View File

@ -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)

140
bio.c Normal file
View File

@ -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);
}

2
bio.d Normal file
View File

@ -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

BIN
bio.o Normal file

Binary file not shown.

81
bootasm.S Normal file
View File

@ -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

1
bootasm.d Normal file
View File

@ -0,0 +1 @@
bootasm.o: bootasm.S asm.h memlayout.h mmu.h

BIN
bootasm.o Normal file

Binary file not shown.

BIN
bootblock Normal file

Binary file not shown.

341
bootblock.asm Normal file
View File

@ -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
bootblock.o Normal file

Binary file not shown.

BIN
bootblockother.o Normal file

Binary file not shown.

93
bootmain.c Normal file
View File

@ -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);
}
}

1
bootmain.d Normal file
View File

@ -0,0 +1 @@
bootmain.o: bootmain.c types.h elf.h x86.h memlayout.h

BIN
bootmain.o Normal file

Binary file not shown.

14
buf.h Normal file
View File

@ -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

1256
cat.asm Normal file

File diff suppressed because it is too large Load Diff

39
cat.c Normal file
View File

@ -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();
}

1
cat.d Normal file
View File

@ -0,0 +1 @@
cat.o: cat.c /usr/include/stdc-predef.h types.h stat.h user.h

BIN
cat.o Normal file

Binary file not shown.

50
cat.sym Normal file
View File

@ -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

2
config.xlaunch Normal file
View File

@ -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"/>

332
console.c Normal file
View File

@ -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);
}

3
console.d Normal file
View File

@ -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

BIN
console.o Normal file

Binary file not shown.

48
cuth Normal file
View File

@ -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");
}

8
date.h Normal file
View File

@ -0,0 +1,8 @@
struct rtcdate {
uint second;
uint minute;
uint hour;
uint day;
uint month;
uint year;
};

191
defs.h Normal file
View File

@ -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]))

1169
echo.asm Normal file

File diff suppressed because it is too large Load Diff

12
echo.c Normal file
View File

@ -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();
}

1
echo.d Normal file
View File

@ -0,0 +1 @@
echo.o: echo.c /usr/include/stdc-predef.h types.h stat.h user.h

BIN
echo.o Normal file

Binary file not shown.

48
echo.sym Normal file
View File

@ -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

42
elf.h Normal file
View File

@ -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

68
entry.S Normal file
View File

@ -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
entry.o Normal file

Binary file not shown.

BIN
entryother Normal file

Binary file not shown.

89
entryother.S Normal file
View File

@ -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
entryother.asm Normal file
View File

@ -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)
...

1
entryother.d Normal file
View File

@ -0,0 +1 @@
entryother.o: entryother.S asm.h memlayout.h mmu.h

BIN
entryother.o Normal file

Binary file not shown.

142
exec.c Normal file
View File

@ -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;
}

2
exec.d Normal file
View File

@ -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

BIN
exec.o Normal file

Binary file not shown.

4
fcntl.h Normal file
View File

@ -0,0 +1,4 @@
#define O_RDONLY 0x000
#define O_WRONLY 0x001
#define O_RDWR 0x002
#define O_CREATE 0x200

155
file.c Normal file
View File

@ -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");
}

2
file.d Normal file
View File

@ -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

37
file.h Normal file
View File

@ -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

BIN
file.o Normal file

Binary file not shown.

673
forktest.asm Normal file
View File

@ -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
forktest.c Normal file
View File

@ -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();
}

1
forktest.d Normal file
View File

@ -0,0 +1 @@
forktest.o: forktest.c /usr/include/stdc-predef.h types.h stat.h user.h

BIN
forktest.o Normal file

Binary file not shown.

649
fs.c Normal file
View File

@ -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);
}

2
fs.d Normal file
View File

@ -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

57
fs.h Normal file
View File

@ -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];
};

BIN
fs.img (Stored with Git LFS) Normal file

Binary file not shown.

BIN
fs.o Normal file

Binary file not shown.

291
gdbutil Normal file
View File

@ -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
gensyscalls.pl Normal file
View File

@ -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"
}

1583
grep.asm Normal file

File diff suppressed because it is too large Load Diff

109
grep.c Normal file
View File

@ -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;
}

1
grep.d Normal file
View File

@ -0,0 +1 @@
grep.o: grep.c /usr/include/stdc-predef.h types.h stat.h user.h

BIN
grep.o Normal file

Binary file not shown.

53
grep.sym Normal file
View File

@ -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

1129
hello.asm Normal file

File diff suppressed because it is too large Load Diff

7
hello.c Normal file
View File

@ -0,0 +1,7 @@
#include "types.h"
#include "user.h"
int main(int argc, char *argv[]) {
greeting();
exit();
}

1
hello.d Normal file
View File

@ -0,0 +1 @@
hello.o: hello.c /usr/include/stdc-predef.h types.h user.h

BIN
hello.o Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More