From 60fc1d7518a3ced9b333223c7e1b06b76e33ce41 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" Date: Wed, 8 Mar 2023 10:02:01 -0500 Subject: [PATCH 01/20] Added shutdown system call, snprintf() function, and start of ps system call --- Makefile | 72 +++++++++++++++++++-------- console.c | 2 +- kalloc.c | 1 + kshutdown.c | 14 ++++++ mkfs.c | 8 +++ mycat2.c | 30 +++++++++++ printf.c | 131 +++++++++++++++++++++++++++++++++++++++---------- ps.c | 11 +++++ sh.c | 4 +- shutdown.c | 10 ++++ snprintftest.c | 45 +++++++++++++++++ syscall.c | 6 +++ sysproc.c | 18 +++++++ usys.S | 3 ++ vm.c | 8 +-- 15 files changed, 309 insertions(+), 54 deletions(-) create mode 100644 kshutdown.c create mode 100644 mycat2.c create mode 100644 ps.c create mode 100644 shutdown.c create mode 100644 snprintftest.c diff --git a/Makefile b/Makefile index 09d790cf63..a3604b5843 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ OBJS = \ ioapic.o\ kalloc.o\ kbd.o\ + kshutdown.o\ lapic.o\ log.o\ main.o\ @@ -76,11 +77,14 @@ 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 = -fno-pic -static -fno-builtin -fno-strict-aliasing -Og -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-delete-null-pointer-checks -std=gnu99 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) +LIBGCC_A = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +FS=fs.img +ASM_INCLUDES=asm.h memlayout.h mmu.h # Disable PIE when possible (for Ubuntu 16.10 toolchain) ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),) @@ -90,6 +94,8 @@ ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]nopie'),) CFLAGS += -fno-pie -nopie endif +all: xv6.img fs.img + xv6.img: bootblock kernel dd if=/dev/zero of=xv6.img count=10000 dd if=bootblock of=xv6.img conv=notrunc @@ -100,7 +106,7 @@ xv6memfs.img: bootblock kernelmemfs dd if=bootblock of=xv6memfs.img conv=notrunc dd if=kernelmemfs of=xv6memfs.img seek=1 conv=notrunc -bootblock: bootasm.S bootmain.c +bootblock: bootasm.S bootmain.c $(ASM_INCLUDES) $(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 @@ -108,16 +114,16 @@ bootblock: bootasm.S bootmain.c $(OBJCOPY) -S -O binary -j .text bootblock.o bootblock ./sign.pl bootblock -entryother: entryother.S +entryother: entryother.S $(ASM_INCLUDES) $(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 +initcode: initcode.S $(ASM_INCLUDES) $(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 + $(OBJCOPY) -S -j .text -O binary initcode.out initcode $(OBJDUMP) -S initcode.o > initcode.asm kernel: $(OBJS) entry.o entryother initcode kernel.ld @@ -145,18 +151,20 @@ vectors.S: vectors.pl ULIB = ulib.o usys.o printf.o umalloc.o +usys.o: usys.S syscall.h traps.h + _%: %.o $(ULIB) - $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^ + $(LD) $(LDFLAGS) -T program.ld --gc-sections -o $@ $^ $(LIBGCC_A) $(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 + $(LD) $(LDFLAGS) -T program.ld -o _forktest forktest.o ulib.o usys.o $(OBJDUMP) -S _forktest > forktest.asm -mkfs: mkfs.c fs.h +mkfs: mkfs.c fs.h param.h gcc -Werror -Wall -o mkfs mkfs.c # Prevent deletion of intermediate files, e.g. cat.o, after first build, so @@ -181,10 +189,24 @@ UPROGS=\ _usertests\ _wc\ _zombie\ + _shutdown\ + _mycat2\ + _snprintftest\ + _ps\ fs.img: mkfs README $(UPROGS) ./mkfs fs.img README $(UPROGS) +fs-%-as-init.img: _% mkfs README $(UPROGS) + rm -rf temp-$< + mkdir -p temp-$< + for filename in README $(UPROGS) _$<; do \ + ln -s ../$$filename ./temp-$<; \ + done + rm ./temp-$ $@ -qemu-gdb: fs.img xv6.img .gdbinit +qemu-gdb: fs.img xv6.img .gdbinit $(FS) @echo "*** Now run 'gdb'." 1>&2 $(QEMU) -serial mon:stdio $(QEMUOPTS) -S $(QEMUGDB) -qemu-nox-gdb: fs.img xv6.img .gdbinit +qemu-nox-gdb: fs.img xv6.img .gdbinit $(FS) @echo "*** Now run 'gdb'." 1>&2 $(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB) @@ -250,9 +272,10 @@ qemu-nox-gdb: fs.img xv6.img .gdbinit EXTRA=\ mkfs.c ulib.c user.h cat.c echo.c forktest.c grep.c kill.c\ ln.c ls.c mkdir.c rm.c stressfs.c usertests.c wc.c zombie.c\ - printf.c umalloc.c\ + printf.c umalloc.c \ README dot-bochsrc *.pl toc.* runoff runoff1 runoff.list\ .gdbinit.tmpl gdbutil\ + kernel.ld dist: rm -rf dist @@ -273,7 +296,7 @@ dist-test: cp dist/* dist-test cd dist-test; $(MAKE) print cd dist-test; $(MAKE) bochs || true - cd dist-test; $(MAKE) qemu + cd dist-test; $(MAKE) qemu-nox # update this rule (change rev#) when it is time to # make a new revision. @@ -281,6 +304,15 @@ tar: rm -rf /tmp/xv6 mkdir -p /tmp/xv6 cp dist/* dist/.gdbinit.tmpl /tmp/xv6 - (cd /tmp; tar cf - xv6) | gzip >xv6-rev10.tar.gz # the next one will be 10 (9/17) + (cd /tmp; tar cf - xv6) | gzip >xv6-rev10-uva1.tar.gz + +SUBMIT_FILENAME=xv6-submission-$(shell date +%Y%m%d%H%M%S).tar.gz + +submit: + @tar -zcf $(SUBMIT_FILENAME) *.c *.h *.S *.ld Makefile $(wildcard *.txt) $(wildcard *.md) $(EXTRA) $(FILES) + @echo "Created $(SUBMIT_FILENAME); please upload and submit this file." + .PHONY: dist-test dist + +.DELETE_ON_ERROR: 1 diff --git a/console.c b/console.c index a280d2ba60..114be2581e 100644 --- a/console.c +++ b/console.c @@ -126,7 +126,7 @@ panic(char *s) //PAGEBREAK: 50 #define BACKSPACE 0x100 #define CRTPORT 0x3d4 -static ushort *crt = (ushort*)P2V(0xb8000); // CGA memory +static ushort *crt = (ushort*)P2V_C(0xb8000); // CGA memory static void cgaputc(int c) diff --git a/kalloc.c b/kalloc.c index 14cd4f43f2..bab73ab8f2 100644 --- a/kalloc.c +++ b/kalloc.c @@ -47,6 +47,7 @@ void freerange(void *vstart, void *vend) { char *p; + if (vend < vstart) panic("freerange"); p = (char*)PGROUNDUP((uint)vstart); for(; p + PGSIZE <= (char*)vend; p += PGSIZE) kfree(p); diff --git a/kshutdown.c b/kshutdown.c new file mode 100644 index 0000000000..57f15f8bf7 --- /dev/null +++ b/kshutdown.c @@ -0,0 +1,14 @@ +/* Kernel part of shutdown/poweroff support */ + +#include "types.h" +#include "x86.h" + +void +shutdown(void) +{ + /* + This only works in QEMU and assumes QEMU was run + with -device isa-debug-exit + */ + outb(0x501, 0x0); +} diff --git a/mkfs.c b/mkfs.c index 8e011a785e..827ca5d350 100644 --- a/mkfs.c +++ b/mkfs.c @@ -170,6 +170,10 @@ main(int argc, char *argv[]) void wsect(uint sec, void *buf) { + if(sec > FSSIZE) { + fprintf(stderr, "failed: trying to write sector %d > FSSIZE = %d\n", sec, FSSIZE); + exit(1); + } if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){ perror("lseek"); exit(1); @@ -210,6 +214,10 @@ rinode(uint inum, struct dinode *ip) void rsect(uint sec, void *buf) { + if(sec > FSSIZE) { + fprintf(stderr, "failed: trying to read sector %d > FSSIZE = %d\n", sec, FSSIZE); + exit(1); + } if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){ perror("lseek"); exit(1); diff --git a/mycat2.c b/mycat2.c new file mode 100644 index 0000000000..2f17cfa1d6 --- /dev/null +++ b/mycat2.c @@ -0,0 +1,30 @@ +#include "types.h" +#include "stat.h" +#include "user.h" + +int main(int argc, const char *argv[]) { + if(1 >= argc) { + write(2, "Usage: \n", 14); + } else { + for(int i = 1; i < argc; i++) { + const char *path = argv[i]; + int fd = open(path, 0); + if(0 > fd) { + write(2, "Error Opening to file:\n", 23); + } else { + char buffer[2] = {0,0}; + int status = 0; + do { + status = read(fd, buffer, 1); + write(1, buffer, 1); + } while(0 < status); + + if(0 > status) { + write(2, "Error: Writing to file:\n", 25); + } + } + close(fd); + } + } + return 0; +} diff --git a/printf.c b/printf.c index b3298aaedd..761043c847 100644 --- a/printf.c +++ b/printf.c @@ -2,17 +2,37 @@ #include "stat.h" #include "user.h" +// Type for functions that can "output" a single character either to a +// file descriptor or a character buffer of at least length characters. +typedef void (*putFunction_t)(int fd, char *outbuffer, uint length, uint index, char c); + +// Output c to fd static void -putc(int fd, char c) +s_putc(int fd, char *outbuffer, uint length, uint index, char c) { write(fd, &c, 1); } -static void -printint(int fd, int xx, int base, int sgn) +// store c at index within outbuffer if index is less than length +void s_sputc(int fd, char *outbuffer, uint length, uint index, char c) +{ + if(index < length) + { + outbuffer[index] = c; + } +} + +// This function stores a reverse text representation of xx expressed in +// base [10 or 16] into outbuf. Reversed means that the most significant digit +// is last in the text representation instead of first. It is necessary to +// output the characters in outbuf from last to first to get the normal +// "most significant digit on teh left" representation. At most length +// characters are written to outbuf. +// \return the number of characters written to outbuf +static uint +s_getReverseDigits(char *outbuf, uint length, int xx, int base, int sgn) { static char digits[] = "0123456789ABCDEF"; - char buf[16]; int i, neg; uint x; @@ -25,40 +45,71 @@ printint(int fd, int xx, int base, int sgn) } i = 0; - do{ - buf[i++] = digits[x % base]; - }while((x /= base) != 0); - if(neg) - buf[i++] = '-'; - - while(--i >= 0) - putc(fd, buf[i]); + while(i + 1 < length && x != 0) { + outbuf[i++] = digits[x % base]; + x /= base; + } + + if(0 == xx && i + 1 < length) { + outbuf[i++] = digits[0]; + } + + if(neg && i < length) { + outbuf[i++] = '-'; + } + + return i; } -// Print to the given fd. Only understands %d, %x, %p, %s. -void -printf(int fd, const char *fmt, ...) +static uint +s_printint(putFunction_t putcFunction, + int fd, char *outbuf, uint length, int xx, int base, int sgn) +{ + static const uint localBufferLength = 16; + char localBuffer[localBufferLength]; + + uint result = + s_getReverseDigits(localBuffer, localBufferLength, xx, base, sgn); + + // Reverse the digits to put them in normal print order with most significant + // to the left + int j = 0; + int i = result; + while(--i >= 0 && j < length) + { + putcFunction(fd, outbuf, length, j, localBuffer[i]); + j++; + } + return result; +} + +static uint s_min(uint a, uint b) { + return (a < b) ? a : b; +} + +static +int s_printf(putFunction_t putcFunction, int fd, char *outbuffer, int n, const char *fmt, uint* ap) { char *s; int c, i, state; - uint *ap; + uint outindex = 0; + const int length = n -1; // leave room for nul termination state = 0; - ap = (uint*)(void*)&fmt + 1; - for(i = 0; fmt[i]; i++){ + for(i = 0; fmt[i] && outindex < length; i++) { c = fmt[i] & 0xff; if(state == 0){ - if(c == '%'){ + if(c == '%') { state = '%'; } else { - putc(fd, c); + putcFunction(fd, outbuffer, length, outindex++, c); } } else if(state == '%'){ if(c == 'd'){ - printint(fd, *ap, 10, 1); + outindex += s_printint(putcFunction, fd, &outbuffer[outindex], length - outindex, *ap, 10, 1); ap++; } else if(c == 'x' || c == 'p'){ - printint(fd, *ap, 16, 0); + outindex += s_printint(putcFunction, fd, &outbuffer[outindex], length - outindex, *ap, 16, 0); ap++; } else if(c == 's'){ s = (char*)*ap; @@ -66,20 +117,46 @@ printf(int fd, const char *fmt, ...) if(s == 0) s = "(null)"; while(*s != 0){ - putc(fd, *s); + putcFunction(fd, outbuffer, length, outindex++, *s); s++; } } else if(c == 'c'){ - putc(fd, *ap); + putcFunction(fd, outbuffer, length, outindex++, *ap); ap++; } else if(c == '%'){ - putc(fd, c); + putcFunction(fd, outbuffer, length, outindex++, c); } else { // Unknown % sequence. Print it to draw attention. - putc(fd, '%'); - putc(fd, c); + putcFunction(fd, outbuffer, length, outindex++, '%'); + putcFunction(fd, outbuffer, length, outindex++, c); } state = 0; } } + + return s_min(length, outindex); +} + +// Print into outbuffer at most n characters. Only understands %d, %x, %p, %s. +// If n is greater than 0, a terminating nul is always stored in outbuffer. +// \return the number of characters written to outbuffer not counting the +// terminating nul. +int snprintf(char *outbuffer, int n, const char *fmt, ...) +{ + uint* ap = (uint*)(void*)&fmt + 1; + const uint count = s_printf(s_sputc, -1, outbuffer, n, fmt, ap); + if(count < n) { + outbuffer[count] = 0; // Assure nul termination + } + + return count; +} + +// Print to the given fd. Only understands %d, %x, %p, %s. +void +printf(int fd, const char *fmt, ...) +{ + static const uint veryLarge = 1<<30; + uint* ap = (uint*)(void*)&fmt + 1; + s_printf(s_putc, fd, 0, veryLarge, fmt, ap); } diff --git a/ps.c b/ps.c new file mode 100644 index 0000000000..1463e2f71d --- /dev/null +++ b/ps.c @@ -0,0 +1,11 @@ +#include "types.h" +#include "stat.h" +#include "user.h" + +int +main(int argc, char *argv[]) +{ + int result = ps(); + printf(1, "ps returned <%d>\n", result); + exit(); +} diff --git a/sh.c b/sh.c index 054bab92b3..fb700b7d23 100644 --- a/sh.c +++ b/sh.c @@ -11,7 +11,7 @@ #define LIST 4 #define BACK 5 -#define MAXARGS 10 +#define MAXARGS 20 struct cmd { int type; @@ -144,7 +144,7 @@ getcmd(char *buf, int nbuf) int main(void) { - static char buf[100]; + static char buf[200]; int fd; // Ensure that three file descriptors are open. diff --git a/shutdown.c b/shutdown.c new file mode 100644 index 0000000000..6975848f0b --- /dev/null +++ b/shutdown.c @@ -0,0 +1,10 @@ +#include "types.h" +#include "stat.h" +#include "user.h" + +int +main(int argc, char *argv[]) +{ + shutdown(); + exit(); +} diff --git a/snprintftest.c b/snprintftest.c new file mode 100644 index 0000000000..b4e67088d4 --- /dev/null +++ b/snprintftest.c @@ -0,0 +1,45 @@ +#include "types.h" +#include "stat.h" +#include "user.h" + +#define bufferSizeBytes (512) +static char buf[bufferSizeBytes]; + +int +main(int argc, char *argv[]) +{ + snprintf(buf, bufferSizeBytes, "Hello, World\n"); + printf(1, "%s", buf); + snprintf(buf, bufferSizeBytes, "%d\n", argc); + printf(1, "%s", buf); + snprintf(buf, bufferSizeBytes, "%x\n", argc); + printf(1, "%s", buf); + snprintf(buf, 6, "Hello, World\n"); + printf(1, "%s", buf); + snprintf(buf, 12, "\n0x%x\n", 0xcafebabe); + printf(1, "%s", buf); + snprintf(buf, 6, "\n0x%x\n", 0xcafebabe); + printf(1, "%s", buf); + snprintf(buf, 0, "\n0x%x\n", 0xdeadbeef); + printf(1, "%s", buf); + snprintf(buf, bufferSizeBytes, "\n%d\n", 0xdeadbeef); + printf(1, "%s", buf); + + snprintf(buf, bufferSizeBytes, "\nprogram is <%s>\n", argv[0]); + printf(1, "%s", buf); + + int index = 0; + for(int i = 1; i < argc; i++) { + index += snprintf(&buf[index], bufferSizeBytes - index, "<%s>\n", argv[i]); + } + printf(1, "%s", buf); + + for(int i = 1; i < argc; i++) { + printf(1, "<%d>\n", i - 3); + } + for(int i = 1; i < argc; i++) { + printf(1, "<%x>\n", i - 3); + } + + exit(); +} diff --git a/syscall.c b/syscall.c index ee85261602..5de4e3fba9 100644 --- a/syscall.c +++ b/syscall.c @@ -103,6 +103,9 @@ extern int sys_unlink(void); extern int sys_wait(void); extern int sys_write(void); extern int sys_uptime(void); +extern int sys_yield(void); +extern int sys_shutdown(void); +extern int sys_ps(void); static int (*syscalls[])(void) = { [SYS_fork] sys_fork, @@ -126,6 +129,9 @@ static int (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_yield] sys_yield, +[SYS_shutdown] sys_shutdown, +[SYS_ps] sys_ps, }; void diff --git a/sysproc.c b/sysproc.c index 0686d295b6..5d0c5021db 100644 --- a/sysproc.c +++ b/sysproc.c @@ -89,3 +89,21 @@ sys_uptime(void) release(&tickslock); return xticks; } + +int +sys_yield(void) +{ + yield(); + return 0; +} + +int sys_shutdown(void) +{ + shutdown(); + return 0; +} + +int sys_ps(void) +{ + return 42; +} diff --git a/usys.S b/usys.S index 8bfd8a1bc4..a693ca1423 100644 --- a/usys.S +++ b/usys.S @@ -29,3 +29,6 @@ SYSCALL(getpid) SYSCALL(sbrk) SYSCALL(sleep) SYSCALL(uptime) +SYSCALL(yield) +SYSCALL(shutdown) +SYSCALL(ps) diff --git a/vm.c b/vm.c index 7134cfffbe..be8ff6a9ae 100644 --- a/vm.c +++ b/vm.c @@ -108,10 +108,10 @@ static struct kmap { uint phys_end; int perm; } kmap[] = { - { (void*)KERNBASE, 0, EXTMEM, PTE_W}, // I/O space - { (void*)KERNLINK, V2P(KERNLINK), V2P(data), 0}, // kern text+rodata - { (void*)data, V2P(data), PHYSTOP, PTE_W}, // kern data+memory - { (void*)DEVSPACE, DEVSPACE, 0, PTE_W}, // more devices + { (void*)KERNBASE, 0, EXTMEM, PTE_W}, // I/O space + { (void*)KERNLINK, V2P_C(KERNLINK), V2P_C(data), 0}, // kern text+rodata + { (void*)data, V2P_C(data), PHYSTOP, PTE_W}, // kern data+memory + { (void*)DEVSPACE, DEVSPACE, 0, PTE_W}, // more devices }; // Set up kernel part of a page table. From a190d58788ba8ade83722e36215b584faf32c94d Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" Date: Wed, 8 Mar 2023 10:03:52 -0500 Subject: [PATCH 02/20] Added shutdown system call, snprintf() function, and start of ps system call --- console.c | 2 +- defs.h | 4 ++++ memlayout.h | 33 +++++++++++++++++++++++++++++++-- mmu.h | 9 ++++++--- param.h | 2 +- syscall.h | 45 ++++++++++++++++++++++++--------------------- user.h | 5 +++++ 7 files changed, 72 insertions(+), 28 deletions(-) diff --git a/console.c b/console.c index 114be2581e..a280d2ba60 100644 --- a/console.c +++ b/console.c @@ -126,7 +126,7 @@ panic(char *s) //PAGEBREAK: 50 #define BACKSPACE 0x100 #define CRTPORT 0x3d4 -static ushort *crt = (ushort*)P2V_C(0xb8000); // CGA memory +static ushort *crt = (ushort*)P2V(0xb8000); // CGA memory static void cgaputc(int c) diff --git a/defs.h b/defs.h index 82fb982837..406afeaf80 100644 --- a/defs.h +++ b/defs.h @@ -1,3 +1,4 @@ +#include "param.h" struct buf; struct context; struct file; @@ -156,6 +157,9 @@ int fetchint(uint, int*); int fetchstr(uint, char**); void syscall(void); +// shutdown.c +void shutdown(void); + // timer.c void timerinit(void); diff --git a/memlayout.h b/memlayout.h index d1615f7abc..217f649f92 100644 --- a/memlayout.h +++ b/memlayout.h @@ -8,8 +8,37 @@ #define KERNBASE 0x80000000 // First kernel virtual address #define KERNLINK (KERNBASE+EXTMEM) // Address where kernel is linked -#define V2P(a) (((uint) (a)) - KERNBASE) -#define P2V(a) ((void *)(((char *) (a)) + KERNBASE)) +#ifndef __ASSEMBLER__ + +// I changed V2P and P2V from macros into functions in order to make sure +// errors occur if pointers are passed to P2V and make sure errors occur +// when user addresses are passed to V2P. - Charles Reiss + +// Convert kernel virtual address to physical address +static inline uint V2P(void *a) { + // define panic() here because memlayout.h is included before defs.h + extern void panic(char*) __attribute__((noreturn)); + if (a < (void*) KERNBASE) + panic("V2P on address < KERNBASE " + "(not a kernel virtual address; consider walking page " + "table to determine physical address of a user virtual address)"); + return (uint)a - KERNBASE; +} + +// Convert physical address to kernel virtual address +static inline void *P2V(uint a) { + extern void panic(char*) __attribute__((noreturn)); + if (a > KERNBASE) + panic("P2V on address > KERNBASE"); + return (char*)a + KERNBASE; +} + +#endif + +// same as P2V, but suitable for a compile-time constant +#define P2V_C(x) (((char*) x) + KERNBASE) +// same as V2P, but suitable for a compile-time constant +#define V2P_C(x) (((uint) x) - KERNBASE) #define V2P_WO(x) ((x) - KERNBASE) // same as V2P, but without casts #define P2V_WO(x) ((x) + KERNBASE) // same as P2V, but without casts diff --git a/mmu.h b/mmu.h index a82d8e26ec..2d6bbd4f86 100644 --- a/mmu.h +++ b/mmu.h @@ -96,11 +96,14 @@ struct segdesc { #define PTE_U 0x004 // User #define PTE_PS 0x080 // Page Size -// Address in page table or page directory entry -#define PTE_ADDR(pte) ((uint)(pte) & ~0xFFF) -#define PTE_FLAGS(pte) ((uint)(pte) & 0xFFF) #ifndef __ASSEMBLER__ +// Address in page table or page directory entry +// I changes these from macros into inline functions to make sure we +// consistently get an error if a pointer is erroneously passed to them. +static inline uint PTE_ADDR(uint pte) { return pte & ~0xFFF; } +static inline uint PTE_FLAGS(uint pte) { return pte & 0xFFF; } + typedef uint pte_t; // Task state segment format diff --git a/param.h b/param.h index a7e90efff4..e8a7290850 100644 --- a/param.h +++ b/param.h @@ -10,5 +10,5 @@ #define MAXOPBLOCKS 10 // max # of blocks any FS op writes #define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log #define NBUF (MAXOPBLOCKS*3) // size of disk block cache -#define FSSIZE 1000 // size of file system in blocks +#define FSSIZE 2000 // size of file system in blocks diff --git a/syscall.h b/syscall.h index bc5f35651c..f29ed13521 100644 --- a/syscall.h +++ b/syscall.h @@ -1,22 +1,25 @@ // System call numbers -#define SYS_fork 1 -#define SYS_exit 2 -#define SYS_wait 3 -#define SYS_pipe 4 -#define SYS_read 5 -#define SYS_kill 6 -#define SYS_exec 7 -#define SYS_fstat 8 -#define SYS_chdir 9 -#define SYS_dup 10 -#define SYS_getpid 11 -#define SYS_sbrk 12 -#define SYS_sleep 13 -#define SYS_uptime 14 -#define SYS_open 15 -#define SYS_write 16 -#define SYS_mknod 17 -#define SYS_unlink 18 -#define SYS_link 19 -#define SYS_mkdir 20 -#define SYS_close 21 +#define SYS_fork 1 +#define SYS_exit 2 +#define SYS_wait 3 +#define SYS_pipe 4 +#define SYS_read 5 +#define SYS_kill 6 +#define SYS_exec 7 +#define SYS_fstat 8 +#define SYS_chdir 9 +#define SYS_dup 10 +#define SYS_getpid 11 +#define SYS_sbrk 12 +#define SYS_sleep 13 +#define SYS_uptime 14 +#define SYS_open 15 +#define SYS_write 16 +#define SYS_mknod 17 +#define SYS_unlink 18 +#define SYS_link 19 +#define SYS_mkdir 20 +#define SYS_close 21 +#define SYS_yield 22 +#define SYS_shutdown 23 +#define SYS_ps 24 diff --git a/user.h b/user.h index 4f99c52ba6..376932a843 100644 --- a/user.h +++ b/user.h @@ -1,3 +1,4 @@ +#include "param.h" struct stat; struct rtcdate; @@ -23,6 +24,9 @@ int getpid(void); char* sbrk(int); int sleep(int); int uptime(void); +int yield(void); +int shutdown(void); +int ps(void); // ulib.c int stat(const char*, struct stat*); @@ -31,6 +35,7 @@ void *memmove(void*, const void*, int); char* strchr(const char*, char c); int strcmp(const char*, const char*); void printf(int, const char*, ...); +int snprintf(char *outbuffer, int n, const char *fmt, ...); char* gets(char*, int max); uint strlen(const char*); void* memset(void*, int, uint); From 9308d5925879999d9b0d23f20618a1b7d2cd8164 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Wed, 8 Mar 2023 10:36:27 -0500 Subject: [PATCH 03/20] Added shutdown system call, snprintf() function, and start of ps system call --- console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console.c b/console.c index a280d2ba60..114be2581e 100644 --- a/console.c +++ b/console.c @@ -126,7 +126,7 @@ panic(char *s) //PAGEBREAK: 50 #define BACKSPACE 0x100 #define CRTPORT 0x3d4 -static ushort *crt = (ushort*)P2V(0xb8000); // CGA memory +static ushort *crt = (ushort*)P2V_C(0xb8000); // CGA memory static void cgaputc(int c) From 8b332e41ed947231c05bd639a589dab4d5c0d9ac Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Wed, 8 Mar 2023 10:43:31 -0500 Subject: [PATCH 04/20] Added linker script --- program.ld | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 program.ld diff --git a/program.ld b/program.ld new file mode 100644 index 0000000000..1330c7a66b --- /dev/null +++ b/program.ld @@ -0,0 +1,17 @@ +/* This linker script tells the linker how the memory + * of xv6 executables should be laid out + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(main) + +SECTIONS { + . = 0x0; + .text : { *(.text .stub .text.* .gnu.linkonce.t.*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .data : { *(.data) } + .bss : { *(.bss) } + /DISCARD/ : { + *(.eh_frame .note.GNU-stack .note.gnu.property) + } +} From ee57661b59e62a57cc03ed94fde40653d2ab6c86 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Wed, 8 Mar 2023 15:19:25 -0500 Subject: [PATCH 05/20] Pass int argument to ps() --- defs.h | 2 ++ proc.c | 17 +++++++++++++++++ ps.c | 2 +- sysproc.c | 6 +++++- user.h | 2 +- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/defs.h b/defs.h index 406afeaf80..00676d6c0f 100644 --- a/defs.h +++ b/defs.h @@ -190,5 +190,7 @@ void switchkvm(void); int copyout(pde_t*, uint, void*, uint); void clearpteu(pde_t *pgdir, char *uva); +int proc_ps(int); + // number of elements in fixed-size array #define NELEM(x) (sizeof(x)/sizeof((x)[0])) diff --git a/proc.c b/proc.c index 806b1b184b..aa697876ae 100644 --- a/proc.c +++ b/proc.c @@ -20,6 +20,23 @@ extern void trapret(void); static void wakeup1(void *chan); +int proc_ps(int numberOfProcs) +{ + struct proc *p; + int result = 0; + + acquire(&ptable.lock); + + for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) { + if(p->state != UNUSED) { + ++result; + } + } + + release(&ptable.lock); + return result + numberOfProcs; +} + void pinit(void) { diff --git a/ps.c b/ps.c index 1463e2f71d..78d3902490 100644 --- a/ps.c +++ b/ps.c @@ -5,7 +5,7 @@ int main(int argc, char *argv[]) { - int result = ps(); + int result = ps(-99); printf(1, "ps returned <%d>\n", result); exit(); } diff --git a/sysproc.c b/sysproc.c index 5d0c5021db..bf071a0183 100644 --- a/sysproc.c +++ b/sysproc.c @@ -105,5 +105,9 @@ int sys_shutdown(void) int sys_ps(void) { - return 42; + int numberOfProcs; + + if(argint(0, &numberOfProcs) < 0) + return -1; + return proc_ps(numberOfProcs); } diff --git a/user.h b/user.h index 376932a843..78d6378ada 100644 --- a/user.h +++ b/user.h @@ -26,7 +26,7 @@ int sleep(int); int uptime(void); int yield(void); int shutdown(void); -int ps(void); +int ps(int); // ulib.c int stat(const char*, struct stat*); From a02bda33eda0d929abfb316a1842dee7d078913e Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Wed, 8 Mar 2023 15:24:37 -0500 Subject: [PATCH 06/20] Added ! --- ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ps.c b/ps.c index 78d3902490..2220c58292 100644 --- a/ps.c +++ b/ps.c @@ -6,6 +6,6 @@ int main(int argc, char *argv[]) { int result = ps(-99); - printf(1, "ps returned <%d>\n", result); + printf(1, "ps returned <%d>!\n", result); exit(); } From 50d2a00a1734957232d3c1440563f976e04020d7 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Fri, 10 Mar 2023 15:28:44 -0500 Subject: [PATCH 07/20] Implemented return of process information from kernel to calling process --- defs.h | 2 +- param.h | 14 ++++++++++++++ proc.c | 7 +++++-- ps.c | 8 +++++++- sysproc.c | 5 ++++- user.h | 2 +- 6 files changed, 32 insertions(+), 6 deletions(-) diff --git a/defs.h b/defs.h index 00676d6c0f..ec1a13cc91 100644 --- a/defs.h +++ b/defs.h @@ -190,7 +190,7 @@ void switchkvm(void); int copyout(pde_t*, uint, void*, uint); void clearpteu(pde_t *pgdir, char *uva); -int proc_ps(int); +int proc_ps(int, struct procInfo*); // number of elements in fixed-size array #define NELEM(x) (sizeof(x)/sizeof((x)[0])) diff --git a/param.h b/param.h index e8a7290850..8f6c1efc9c 100644 --- a/param.h +++ b/param.h @@ -1,3 +1,6 @@ +#ifndef PARAM_H +#define PARAM_H + #define NPROC 64 // maximum number of processes #define KSTACKSIZE 4096 // size of per-process kernel stack #define NCPU 8 // maximum number of CPUs @@ -12,3 +15,14 @@ #define NBUF (MAXOPBLOCKS*3) // size of disk block cache #define FSSIZE 2000 // size of file system in blocks + +#define MAX_PROC_NAME_LENGTH (16) +struct procInfo { + char name[MAX_PROC_NAME_LENGTH]; + int state; + int pid; + int ticksAtStart; + int ticksWhileScheduled; +}; + +#endif // PARAM_H \ No newline at end of file diff --git a/proc.c b/proc.c index aa697876ae..871886cea7 100644 --- a/proc.c +++ b/proc.c @@ -20,21 +20,24 @@ extern void trapret(void); static void wakeup1(void *chan); -int proc_ps(int numberOfProcs) +int proc_ps(int numberOfProcs, struct procInfo* arrayOfProcInfo) { struct proc *p; int result = 0; + int procInfoArrayIndex = 0; acquire(&ptable.lock); for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) { if(p->state != UNUSED) { + safestrcpy(arrayOfProcInfo[procInfoArrayIndex].name, p->name, MAX_PROC_NAME_LENGTH); + ++procInfoArrayIndex; ++result; } } release(&ptable.lock); - return result + numberOfProcs; + return procInfoArrayIndex; } void diff --git a/ps.c b/ps.c index 2220c58292..b886675678 100644 --- a/ps.c +++ b/ps.c @@ -2,10 +2,16 @@ #include "stat.h" #include "user.h" +struct procInfo arrayOfProcInfo[1024]; + int main(int argc, char *argv[]) { - int result = ps(-99); + + int result = ps(1024, arrayOfProcInfo); + for(int i = 0; i < result; ++i) { + printf(1, "%s\n", arrayOfProcInfo[i].name); + } printf(1, "ps returned <%d>!\n", result); exit(); } diff --git a/sysproc.c b/sysproc.c index bf071a0183..403e0941c1 100644 --- a/sysproc.c +++ b/sysproc.c @@ -106,8 +106,11 @@ int sys_shutdown(void) int sys_ps(void) { int numberOfProcs; + struct procInfo* procInfoArray; if(argint(0, &numberOfProcs) < 0) return -1; - return proc_ps(numberOfProcs); + if(argptr(1, (char **)&procInfoArray, sizeof(struct procInfo *)) < 0) + return -1; + return proc_ps(numberOfProcs, procInfoArray); } diff --git a/user.h b/user.h index 78d6378ada..a53d2c1341 100644 --- a/user.h +++ b/user.h @@ -26,7 +26,7 @@ int sleep(int); int uptime(void); int yield(void); int shutdown(void); -int ps(int); +int ps(int, struct procInfo*); // ulib.c int stat(const char*, struct stat*); From 1f4b6c763f0a9c2effd566d7d793a9eb246f46c3 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:21:26 -0400 Subject: [PATCH 08/20] Document procInfo struct used to return information to calling program --- defs.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/defs.h b/defs.h index ec1a13cc91..ffa0dda15c 100644 --- a/defs.h +++ b/defs.h @@ -190,7 +190,17 @@ void switchkvm(void); int copyout(pde_t*, uint, void*, uint); void clearpteu(pde_t *pgdir, char *uva); -int proc_ps(int, struct procInfo*); +struct procInfo; + +/// @brief Call this function to obtain information about existing +/// processes. +/// @param count : the maximum number of elements storable in procInfoArray +/// @param procInfoArray : an array of struct procInfo able to store at least +/// count elements. +/// @return The number of struct procInfo structures stored in procInfoArray +/// by the kernel. This number may be less than count, and if it is, elements +/// at indexes >= count may contain uninitialized memory. +int proc_ps(int count, struct procInfo* procInfoArray); // number of elements in fixed-size array #define NELEM(x) (sizeof(x)/sizeof((x)[0])) From 13901dd76abaccc7d09c9fe705e9afc87629e703 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:21:53 -0400 Subject: [PATCH 09/20] Added simple long running program to help test ps --- longRunner.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 longRunner.c diff --git a/longRunner.c b/longRunner.c new file mode 100644 index 0000000000..11b96bc597 --- /dev/null +++ b/longRunner.c @@ -0,0 +1,24 @@ +#include "types.h" +#include "stat.h" +#include "user.h" + +static volatile int counter = 0; + +int loop(int n) +{ + for(int i = n * 4096; i > 0; --i) { + for(int j = n * 4096; j > 0; --j) { + counter += 1; + } + } + return counter; +} + +int +main(int argc, char *argv[]) +{ + for(int j = 3; j > 0; --j) { + loop(j); + } + exit(); +} From 68ad61b1f739342fa9b9bf54fc98fa08d81219bc Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:22:18 -0400 Subject: [PATCH 10/20] Added simple long running program to help test ps --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index a3604b5843..b5da65ab91 100644 --- a/Makefile +++ b/Makefile @@ -193,6 +193,7 @@ UPROGS=\ _mycat2\ _snprintftest\ _ps\ + _longRunner\ fs.img: mkfs README $(UPROGS) ./mkfs fs.img README $(UPROGS) From 9443b1e7607eeef612e9adf313cf035ffe8867f0 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:24:39 -0400 Subject: [PATCH 11/20] Added procInfo struct used to return information to calling program --- param.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/param.h b/param.h index 8f6c1efc9c..9b8061905d 100644 --- a/param.h +++ b/param.h @@ -15,14 +15,4 @@ #define NBUF (MAXOPBLOCKS*3) // size of disk block cache #define FSSIZE 2000 // size of file system in blocks - -#define MAX_PROC_NAME_LENGTH (16) -struct procInfo { - char name[MAX_PROC_NAME_LENGTH]; - int state; - int pid; - int ticksAtStart; - int ticksWhileScheduled; -}; - -#endif // PARAM_H \ No newline at end of file +#endif // PARAM_H From 61094c534a329a39f08645b854e8d1ce2a5041a0 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:26:15 -0400 Subject: [PATCH 12/20] Added proc_ps to return information about processes to user program --- proc.c | 39 +++++++++++++++++++++++++++++---------- proc.h | 6 +++++- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/proc.c b/proc.c index 871886cea7..99c2162ef4 100644 --- a/proc.c +++ b/proc.c @@ -7,6 +7,15 @@ #include "proc.h" #include "spinlock.h" +static const char * const states[] = { + [UNUSED] "unused", + [EMBRYO] "embryo", + [SLEEPING] "sleep ", + [RUNNABLE] "runble", + [RUNNING] "run ", + [ZOMBIE] "zombie" + }; + struct { struct spinlock lock; struct proc proc[NPROC]; @@ -25,12 +34,25 @@ int proc_ps(int numberOfProcs, struct procInfo* arrayOfProcInfo) struct proc *p; int result = 0; int procInfoArrayIndex = 0; + int currentTicks = ticks; acquire(&ptable.lock); for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) { if(p->state != UNUSED) { - safestrcpy(arrayOfProcInfo[procInfoArrayIndex].name, p->name, MAX_PROC_NAME_LENGTH); + safestrcpy(arrayOfProcInfo[procInfoArrayIndex].name, p->name, + MAX_PROC_NAME_LENGTH); + arrayOfProcInfo[procInfoArrayIndex].pid = p->pid; + arrayOfProcInfo[procInfoArrayIndex].state = p->state; + int elapsedTicks = currentTicks - p->ticksAtStart; + int cpuPercent = 0; + if(elapsedTicks > 0 && 1 < p->ticksScheduled) { + cpuPercent = (p->ticksScheduled * 100) / elapsedTicks; + if(100 < cpuPercent) { + cpuPercent = 100; + } + } + arrayOfProcInfo[procInfoArrayIndex].cpuPercent = cpuPercent; ++procInfoArrayIndex; ++result; } @@ -161,6 +183,8 @@ userinit(void) safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); + p->ticksAtStart = ticks; + p->ticksScheduled = 0; // this assignment to p->state lets other cores // run this process. the acquire forces the above @@ -235,6 +259,8 @@ fork(void) acquire(&ptable.lock); np->state = RUNNABLE; + np->ticksAtStart = ticks; + np->ticksScheduled = 0; release(&ptable.lock); @@ -397,6 +423,7 @@ sched(void) if(readeflags()&FL_IF) panic("sched interruptible"); intena = mycpu()->intena; + p->ticksScheduled += 1; swtch(&p->context, mycpu()->scheduler); mycpu()->intena = intena; } @@ -523,17 +550,9 @@ kill(int pid) void procdump(void) { - static char *states[] = { - [UNUSED] "unused", - [EMBRYO] "embryo", - [SLEEPING] "sleep ", - [RUNNABLE] "runble", - [RUNNING] "run ", - [ZOMBIE] "zombie" - }; int i; struct proc *p; - char *state; + const char *state; uint pc[10]; for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ diff --git a/proc.h b/proc.h index 1647114179..db866412d4 100644 --- a/proc.h +++ b/proc.h @@ -1,3 +1,6 @@ +#include "param.h" +#include "types.h" + // Per-CPU state struct cpu { uchar apicid; // Local APIC ID @@ -32,7 +35,6 @@ struct context { uint eip; }; -enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; // Per-process state struct proc { @@ -49,6 +51,8 @@ struct proc { struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory char name[16]; // Process name (debugging) + int ticksAtStart; + int ticksScheduled; }; // Process memory is laid out contiguously, low addresses first: From e485e5ed48d58f22d872ce75671bc0a2461a5f8d Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:27:08 -0400 Subject: [PATCH 13/20] Added ps program make system call and output information about current processes --- ps.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ps.c b/ps.c index b886675678..51d99a0884 100644 --- a/ps.c +++ b/ps.c @@ -2,16 +2,25 @@ #include "stat.h" #include "user.h" -struct procInfo arrayOfProcInfo[1024]; +static struct procInfo arrayOfProcInfo[1024]; +static const char * const states[] = { + [UNUSED] "unused", + [EMBRYO] "embryo", + [SLEEPING] "sleep ", + [RUNNABLE] "ready ", + [RUNNING] "run ", + [ZOMBIE] "zombie" + }; int main(int argc, char *argv[]) { - int result = ps(1024, arrayOfProcInfo); for(int i = 0; i < result; ++i) { - printf(1, "%s\n", arrayOfProcInfo[i].name); + printf(1, "%d: %s %d %s\n", arrayOfProcInfo[i].pid, + states[arrayOfProcInfo[i].state], + arrayOfProcInfo[i].cpuPercent, + arrayOfProcInfo[i].name); } - printf(1, "ps returned <%d>!\n", result); exit(); } From b308925472a1a33fc6ce9988deb58b92476c7574 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:27:47 -0400 Subject: [PATCH 14/20] Added kernel side of system call, ps --- sysproc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sysproc.c b/sysproc.c index 403e0941c1..e572c585e7 100644 --- a/sysproc.c +++ b/sysproc.c @@ -103,6 +103,14 @@ int sys_shutdown(void) return 0; } +/// @brief This is the kernel side of a system call to obtain information +/// about existing processes in the kernel +/// arg0 is the maximum number of elements storable in procInfoArray +/// arg1 is an array of struct procInfo able to store at least +/// arg0 elements. +/// @return The number of struct procInfo structures stored in arg1. +/// This number may be less than arg0, and if it is, elements +/// at indexes >= arg0 may contain uninitialized memory. int sys_ps(void) { int numberOfProcs; From 47ac0cf0625756542de1d131494d752bd0b60b69 Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:29:50 -0400 Subject: [PATCH 15/20] Defined struct procInfo used inside the kernel and by user program, ps --- types.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/types.h b/types.h index e4adf644ae..02a9b1f498 100644 --- a/types.h +++ b/types.h @@ -1,4 +1,19 @@ +#ifndef TYPES_H +#define TYPES_H + typedef unsigned int uint; typedef unsigned short ushort; typedef unsigned char uchar; typedef uint pde_t; + +enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; + +#define MAX_PROC_NAME_LENGTH (16) +struct procInfo { + int state; + int pid; + int cpuPercent; + char name[MAX_PROC_NAME_LENGTH]; +}; + +#endif // TYPES_H From 498cab6c1c3d0d3b5baebfb98f0d328d20dbd32f Mon Sep 17 00:00:00 2001 From: "Erik M. Buck" <20407477+Make-IT-Wright@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:30:19 -0400 Subject: [PATCH 16/20] Defined ps system call --- user.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/user.h b/user.h index a53d2c1341..321364b11b 100644 --- a/user.h +++ b/user.h @@ -26,7 +26,16 @@ int sleep(int); int uptime(void); int yield(void); int shutdown(void); -int ps(int, struct procInfo*); + +/// @brief This is a system call to obtain information about existing +/// processes in the kernel +/// @param count : the maximum number of elements storable in procInfoArray +/// @param procInfoArray : an array of struct procInfo able to store at least +/// count elements. +/// @return The number of struct procInfo structures stored in procInfoArray +/// by the kernel. This number may be less than count, and if it is, elements +/// at indexes >= count may contain uninitialized memory. +int ps(int count, struct procInfo* procInfoArray); // ulib.c int stat(const char*, struct stat*); From 123131985ccb2e7d3cdb4466c010931814fb8f65 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 30 Aug 2023 00:30:17 +0000 Subject: [PATCH 17/20] reduced qemu memory to 256 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b5da65ab91..8a607de33c 100644 --- a/Makefile +++ b/Makefile @@ -242,7 +242,7 @@ QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \ ifndef CPUS CPUS := 1 endif -QEMUOPTS = -device isa-debug-exit -drive file=$(FS),index=1,media=disk,format=raw -drive file=xv6.img,index=0,media=disk,format=raw -smp $(CPUS) -m 512 $(QEMUEXTRA) +QEMUOPTS = -device isa-debug-exit -drive file=$(FS),index=1,media=disk,format=raw -drive file=xv6.img,index=0,media=disk,format=raw -smp $(CPUS) -m 256 $(QEMUEXTRA) qemu: $(FS) xv6.img $(QEMU) -serial mon:stdio $(QEMUOPTS) || true From 19364ef9e62246d9df5770d56b2f6277f716a062 Mon Sep 17 00:00:00 2001 From: "osboxes.org" Date: Thu, 28 Sep 2023 14:37:42 -0400 Subject: [PATCH 18/20] Added custom device, hello --- Makefile | 1 + defs.h | 3 +++ file.h | 6 ++++++ init.c | 7 +++++++ main.c | 3 +++ 5 files changed, 20 insertions(+) diff --git a/Makefile b/Makefile index 8a607de33c..2b74ac9c9c 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ OBJS = \ uart.o\ vectors.o\ vm.o\ + dhello.o\ # Cross-compiling (e.g., on Mac OS X) # TOOLPREFIX = i386-jos-elf diff --git a/defs.h b/defs.h index ffa0dda15c..1b99c6a895 100644 --- a/defs.h +++ b/defs.h @@ -23,6 +23,9 @@ void cprintf(char*, ...); void consoleintr(int(*)(void)); void panic(char*) __attribute__((noreturn)); +// dhello.c +void helloinit(void); + // exec.c int exec(char*, char**); diff --git a/file.h b/file.h index 0990c82f46..05c14a188b 100644 --- a/file.h +++ b/file.h @@ -35,3 +35,9 @@ struct devsw { extern struct devsw devsw[]; #define CONSOLE 1 + +// This is te Major number for the new custom hello devices +// it probably should not be defiend in file.h, but that's +// where CONSOLE is defined, so we will follow the same +// practice. +#define HELLO 7 diff --git a/init.c b/init.c index 046b551b71..7fd113d5ba 100644 --- a/init.c +++ b/init.c @@ -19,6 +19,13 @@ main(void) dup(0); // stdout dup(0); // stderr + mkdir("dev"); + // Only 10 device major numbers are allowed by param.h + if(open("dev/hello", O_RDWR) < 0){ + mknod("dev/hello", 7, 1); // 7 is major number, 1 is minor number + open("dev/hello", O_RDWR); + } + for(;;){ printf(1, "init: starting sh\n"); pid = fork(); diff --git a/main.c b/main.c index 9924e64ba4..8382df13d6 100644 --- a/main.c +++ b/main.c @@ -31,6 +31,9 @@ main(void) binit(); // buffer cache fileinit(); // file table ideinit(); // disk + + helloinit(); // init our custom device + startothers(); // start other processors kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers() userinit(); // first user process From cb50200b523ed88305deb730ee9b676fdc798c16 Mon Sep 17 00:00:00 2001 From: "osboxes.org" Date: Thu, 28 Sep 2023 14:37:56 -0400 Subject: [PATCH 19/20] Added custom device, hello --- dhello.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 dhello.c diff --git a/dhello.c b/dhello.c new file mode 100644 index 0000000000..f923439f4a --- /dev/null +++ b/dhello.c @@ -0,0 +1,43 @@ +#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" + +int +helloread(struct inode *ip, char *dst, int n) { + static const char *s_charactersToRead = "Hello, World!\n"; + static const int s_lenCharactersToReadcharactersToRead = 15; + + if(n > s_lenCharactersToReadcharactersToRead) { + n = s_lenCharactersToReadcharactersToRead; + } + for(int i = 0; i < n; ++i) { + dst[i] = s_charactersToRead[i]; + } + return n; +} + +int +hellowrite(struct inode *ip, char *src, int n) { + return n; +} + + +void +helloinit(void) +{ + //initlock(&cons.lock, "hello"); + + devsw[HELLO].write = hellowrite; + devsw[HELLO].read = helloread; + //cons.locking = 1; +} + From 1789551eee563935f61aa08799dadeb6048bf0d0 Mon Sep 17 00:00:00 2001 From: erikbuck Date: Tue, 24 Oct 2023 09:54:00 -0400 Subject: [PATCH 20/20] Converted dhello to work like a pipe --- Makefile | 1 + dhello.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++------ sysfile.c | 7 +++++- testhello.c | 33 ++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 testhello.c diff --git a/Makefile b/Makefile index 2b74ac9c9c..aeda1a88b3 100644 --- a/Makefile +++ b/Makefile @@ -195,6 +195,7 @@ UPROGS=\ _snprintftest\ _ps\ _longRunner\ + _testhello\ fs.img: mkfs README $(UPROGS) ./mkfs fs.img README $(UPROGS) diff --git a/dhello.c b/dhello.c index f923439f4a..85ce04355a 100644 --- a/dhello.c +++ b/dhello.c @@ -11,22 +11,76 @@ #include "proc.h" #include "x86.h" +#define BUFFERSIZE (8192) + +struct hello_pipe { + struct spinlock lock; + char data[BUFFERSIZE]; + uint nread; // number of bytes read + uint nwrite; // number of bytes written +}; + +// Storage for one pipe like buffer +static struct hello_pipe s_hello_pipe; + int -helloread(struct inode *ip, char *dst, int n) { - static const char *s_charactersToRead = "Hello, World!\n"; - static const int s_lenCharactersToReadcharactersToRead = 15; +s_hello_pipewrite(struct hello_pipe *p, char *addr, int n) +{ + int i; - if(n > s_lenCharactersToReadcharactersToRead) { - n = s_lenCharactersToReadcharactersToRead; + acquire(&p->lock); + for(i = 0; i < n; i++){ + while(p->nwrite == p->nread + BUFFERSIZE){ //DOC: pipewrite-full + if(myproc()->killed){ + release(&p->lock); + return -1; + } + wakeup(&p->nread); + sleep(&p->nwrite, &p->lock); //DOC: pipewrite-sleep } - for(int i = 0; i < n; ++i) { - dst[i] = s_charactersToRead[i]; + p->data[p->nwrite++ % BUFFERSIZE] = addr[i]; + } + wakeup(&p->nread); //DOC: pipewrite-wakeup1 + release(&p->lock); + return n; +} + +int +s_hello_piperead(struct hello_pipe *p, char *addr, int n) +{ + int i; + + acquire(&p->lock); + while(p->nread == p->nwrite){ //DOC: pipe-empty + if(myproc()->killed){ + release(&p->lock); + return -1; } + sleep(&p->nread, &p->lock); //DOC: piperead-sleep + } + for(i = 0; i < n; i++){ //DOC: piperead-copy + if(p->nread == p->nwrite) + break; + addr[i] = p->data[p->nread++ % BUFFERSIZE]; + } + wakeup(&p->nwrite); //DOC: piperead-wakeup + release(&p->lock); + return i; +} + +int +helloread(struct inode *ip, char *dst, int n) { + iunlock(ip); + n = s_hello_piperead(&s_hello_pipe, dst, n); + ilock(ip); return n; } int hellowrite(struct inode *ip, char *src, int n) { + iunlock(ip); + n = s_hello_pipewrite(&s_hello_pipe, src, n); + ilock(ip); return n; } diff --git a/sysfile.c b/sysfile.c index bfe61b7d99..07f41718f0 100644 --- a/sysfile.c +++ b/sysfile.c @@ -251,8 +251,13 @@ create(char *path, short type, short major, short minor) if((ip = dirlookup(dp, name, 0)) != 0){ iunlockput(dp); ilock(ip); - if(type == T_FILE && ip->type == T_FILE) + if(type == T_FILE && ip->type == T_FILE) { + // File already exists return ip; + } else if(ip->type == T_DEV) { + // Device already exists + return ip; + } iunlockput(ip); return 0; } diff --git a/testhello.c b/testhello.c new file mode 100644 index 0000000000..b5c12453ba --- /dev/null +++ b/testhello.c @@ -0,0 +1,33 @@ +#include "types.h" +#include "stat.h" +#include "user.h" +#include "fcntl.h" + +static const char* message = + "If you see this string then writing to dev/hello works.\n"; +static char s_buffer[4000]; + +int main(int argc, const char *argv[]) { + printf(2, "starting <%s>\n", argv[0]); + int fd = open("dev/hello", O_RDWR); + printf(2, "opened dev/hello\n"); + + int pid = fork(); + if(0 == pid) { + printf(2, "child\n"); + sleep(500); + printf(2, "child writing: %d\n", fd); + write(fd, message, strlen(message)); + } else { + memset(s_buffer, 0, 4000); + printf(2, "parent reading: %d\n", fd); + read(fd, s_buffer, 3999); + printf(2, "%s\n", s_buffer); + wait(); + } + close(fd); + fd = -1; + + exit(); + return 0; +}