diff --git a/Makefile b/Makefile index 2584e4a..08117e8 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,7 @@ $U/initcode: $U/initcode.S tags: $(OBJS) _init etags *.S *.c -ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o +ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/guy2.o $U/umalloc.o _%: %.o $(ULIB) $(LD) $(LDFLAGS) -T $U/user.ld -o $@ $^ @@ -103,7 +103,7 @@ $U/usys.o : $U/usys.S $U/_forktest: $U/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 $U/_forktest $U/forktest.o $U/ulib.o $U/usys.o $U/umalloc.o $U/printf.o + $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $U/_forktest $U/forktest.o $U/ulib.o $U/usys.o $U/guy2.o $U/umalloc.o $U/printf.o $(OBJDUMP) -S $U/_forktest > $U/forktest.asm mkfs/mkfs: mkfs/mkfs.c $K/fs.h $K/param.h @@ -120,6 +120,7 @@ UPROGS=\ $U/_echo\ $U/_forktest\ $U/_grep\ + $U/_guy\ $U/_init\ $U/_kill\ $U/_ln\ diff --git a/docs/guy.md b/docs/guy.md new file mode 100644 index 0000000..85274b8 --- /dev/null +++ b/docs/guy.md @@ -0,0 +1,20 @@ +Documentation for guy: + +For project01, I created a guy.c file that connects to a guy2.c file containing a graphics library for anyone to use. + +All of the functions within user.h under guy.c are available for use directly in any program that you would wish. + +When starting up FogOS, you will see the first animation of guy, and you can see more by typing guy.info. You can also use ls or rm to see more animations I added in to xv6. + +To create this guy library, I had to add a sleep_ms() system call to the kernel, which uses ceiling division to calculate the number of misk rotations in a milisecond, and in turn, sleep for +one milisecond. This is used within each animation, giving the code time to gather each image before printing it out. I also utilized a clear_screen() function, which works the same way as colors do for +this OS. + +The animations execute by running sleep, clear screen and print in a loop. If the CPU is struggling or already handling a lot, sleep_ms may lag some, resulting in a less pretty animation. + +To fix this, quit other applications on your machine. + +Challenges and road blocks in creating this: + +Reduced the lag in my animation by writing the entire thing to a buffer, then printing the buffer rather than running a few individual loops at once. See man_run() for an example of this. +Furhter, I really wanted the animation to work when a seg fault occurs, but this is pretty difficult since FogOS doesn't have signals yet. I spent around 2 hours troubleshooting possible ways to get this to work. Since a seg faulting is caught and handled in the hardware and kernel, having the usertrap() function communicate with the user space would take a lot of extra work. diff --git a/kernel/syscall.c b/kernel/syscall.c index ed65409..9e5ecaf 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -93,6 +93,7 @@ extern uint64 sys_dup(void); extern uint64 sys_getpid(void); extern uint64 sys_sbrk(void); extern uint64 sys_sleep(void); +extern uint64 sys_sleep_ms(void); extern uint64 sys_uptime(void); extern uint64 sys_open(void); extern uint64 sys_write(void); @@ -118,6 +119,7 @@ static uint64 (*syscalls[])(void) = { [SYS_getpid] sys_getpid, [SYS_sbrk] sys_sbrk, [SYS_sleep] sys_sleep, +[SYS_sleep_ms] sys_sleep_ms, [SYS_uptime] sys_uptime, [SYS_open] sys_open, [SYS_write] sys_write, diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..c9779a5 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,4 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_sleep_ms 22 diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 1de184e..6d82c77 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -67,6 +67,29 @@ sys_sleep(void) release(&tickslock); return 0; } +uint64 +sys_sleep_ms(void) +{ + int n; + uint ticks0; + + argint(0, &n); + acquire(&tickslock); + + uint target_ticks = (n + 1000 - 1) / 1000; + + ticks0 = ticks; + + while(ticks - ticks0 < target_ticks){ + if(killed(myproc())){ + release(&tickslock); + return -1; + } + sleep(&ticks, &tickslock); + } + release(&tickslock); + return 0; +} uint64 sys_kill(void) diff --git a/user/FogOSGraphix b/user/FogOSGraphix new file mode 100644 index 0000000..f0d62c5 --- /dev/null +++ b/user/FogOSGraphix @@ -0,0 +1,193 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "kernel/fcntl.h" +#include "user/user.h" + +// +// wrapper so that it's OK if main() does not call exit(). +// +void +_main() +{ + extern int main(); + main(); + exit(0); +} + +char* +strcpy(char *s, const char *t) +{ + char *os; + + os = s; + while((*s++ = *t++) != 0) + ; + return os; +} + +int +strcmp(const char *p, const char *q) +{ + while(*p && *p == *q) + p++, q++; + return (uchar)*p - (uchar)*q; +} + +uint +strlen(const char *s) +{ + int n; + + for(n = 0; s[n]; n++) + ; + return n; +} + +void* +memset(void *dst, int c, uint n) +{ + char *cdst = (char *) dst; + int i; + for(i = 0; i < n; i++){ + cdst[i] = c; + } + return dst; +} + +char* +strchr(const char *s, char c) +{ + for(; *s; s++) + if(*s == c) + return (char*)s; + return 0; +} + +char* +gets(char *buf, int max) +{ + fgets(0, buf, max); + return buf; +} + +int +fgets(int fd, char *buf, int max) +{ + int i, cc; + char c; + + for(i=0; i+1 < max; ){ + cc = read(fd, &c, 1); + if(cc < 1) + break; + buf[i++] = c; + if(c == '\n' || c == '\r') + break; + } + buf[i] = '\0'; + return i; +} + +int +getline(char **lineptr, uint *n, int fd) +{ + if (*lineptr == 0 && *n == 0) { + *n = 128; + *lineptr = malloc(*n); + } + + char *buf = *lineptr; + uint total_read = 0; + while (1) { + int read_sz = fgets(fd, buf + total_read, *n - total_read); + if (read_sz == 0) { + return total_read; + } else if (read_sz == -1) { + // error + return -1; + } + + total_read += read_sz; + if (buf[total_read - 1] == '\n') { + break; + } + + uint new_n = *n * 2; + char *new_buf = malloc(new_n); + memcpy(new_buf, buf, *n); + free(buf); + + buf = new_buf; + + *n = new_n; + *lineptr = buf; + } + + return total_read; +} + + +int +stat(const char *n, struct stat *st) +{ + int fd; + int r; + + fd = open(n, O_RDONLY); + if(fd < 0) + return -1; + r = fstat(fd, st); + close(fd); + return r; +} + +int +atoi(const char *s) +{ + int n; + + n = 0; + while('0' <= *s && *s <= '9') + n = n*10 + *s++ - '0'; + return n; +} + +void* +memmove(void *vdst, const void *vsrc, int n) +{ + char *dst; + const char *src; + + dst = vdst; + src = vsrc; + if (src > dst) { + while(n-- > 0) + *dst++ = *src++; + } else { + dst += n; + src += n; + while(n-- > 0) + *--dst = *--src; + } + return vdst; +} + +int +memcmp(const void *s1, const void *s2, uint n) +{ + const char *p1 = s1, *p2 = s2; + while (n-- > 0) { + if (*p1 != *p2) { + return *p1 - *p2; + } + p1++; + p2++; + } + return 0; +} + +void * +memcpy(void *dst, const void *src, uint n) +{ + return memmove(dst, src, n); +} diff --git a/user/guy.c b/user/guy.c new file mode 100644 index 0000000..f39f3e1 --- /dev/null +++ b/user/guy.c @@ -0,0 +1,19 @@ +#include "user/user.h" +#include "kernel/types.h" + +int main (int argc, char *argv[]) { + if (argc == 1) { + print_guy(); + } else if (strcmp(argv[1], "run") == 0) { + guy_run(); + } else if ((strcmp(argv[1], "gets") == 0) && (strcmp(argv[2], "mad") == 0)) { + guy_mad(); + } else if (strcmp(argv[1], "info") == 0) { + guy_info(); + } else if (strcmp(argv[1], "celebrate") == 0) { + guy_celebrate(); + } else { + printf("Mistyped, try again"); + } + return 0; +} diff --git a/user/guy.h b/user/guy.h new file mode 100644 index 0000000..af3264f --- /dev/null +++ b/user/guy.h @@ -0,0 +1,6 @@ +#ifndef MYFILE_H +#define MYFILE_H + +void guy_color(); + +#endif // MYFILE_H diff --git a/user/guy2.c b/user/guy2.c new file mode 100644 index 0000000..49418ce --- /dev/null +++ b/user/guy2.c @@ -0,0 +1,174 @@ +#include "user/user.h" +#include "kernel/types.h" +#define RED "\033[31m" +#define RESET "\033[0m" +#define GREEN "\033[32m" + + +void clear_screen() { + printf("\033[H\033[J"); +} + +void print_guy() { + char *buffer = (char *)malloc(128*20); + strcpy(buffer, " O \n /|\\ \n / \\ \n\0"); + printf(buffer); + free(buffer); +} + +void print_guy_U() { + char *buffer = (char *)malloc(128*20); + strcpy(buffer, "\n O \n /|\\ \n / \\ \n\0"); + printf(buffer); + free(buffer); +} + +void print_guy_L() { + char *buffer = (char *)malloc(128*20); + strcpy(buffer, " O \n /|\\ \n / \\ \n\0"); + printf(buffer); + free(buffer); +} + +void print_guy_R() { + char *buffer = (char *)malloc(128*20); + strcpy(buffer, " O \n /|\\ \n / \\ \n\0"); + printf(buffer); + free(buffer); +} + + +void print_guy_run(int pos) { + //initializing final buffer and buffer for pos number of spaces + char *buffer = (char *)malloc((pos*3 + 30)*sizeof(char)); + char *spaces = (char *)malloc(pos*sizeof(char)); + //Creating body + for (int i = 0; i < pos; i++) { + spaces[i] = ' '; + } + char *head = (char *)malloc(10 * sizeof(char)); + strcpy(head, " O \n"); + memcpy(buffer, spaces, strlen(spaces) +1); + memcpy(buffer + pos, head, strlen(head) + 1); + memcpy(buffer + pos + strlen(head), spaces, strlen(spaces) + 1); + char *torso = (char *)malloc(10 * sizeof(char)); + strcpy(torso, " /|\\ \n"); + char *legs = (char *)malloc(10 * sizeof(char)); + strcpy(legs, " / \\ \n"); + //Coping body with pos number of spaces into buffer + memcpy(buffer + (pos * 2) + strlen(head), torso, strlen(torso) + 1); + memcpy(buffer + (pos * 2) + strlen(head) + strlen(torso), spaces, strlen(spaces) + 1); + memcpy(buffer + (pos * 3) + strlen(head) + strlen(torso), legs, strlen(legs) + 1); + //Freeing everything + printf(buffer); + free(buffer); + free(head); + free(torso); + free(legs); + free(spaces); + +} + +void guy_mad() { + printf("%s", RED); + for (int i = 0; i < 15; i++) { + clear_screen(); + if (i % 2 == 0) { + print_guy_L(); + } else { + print_guy_R(); + } + sleep_ms(10); + } + clear_screen(); + print_guy(); + printf("RAHHHHHHHHHH!!\n"); + printf("%s", RESET); +} + +void guy_move_head() { + for (int i = 0; i < 15; i++) { + clear_screen(); + if (i % 2 == 0) { + print_guy_L(); + } else { + print_guy_R(); + } + sleep_ms(10); + } + clear_screen(); + print_guy(); +} + + + +void guy_run() { + for (int i = 0; i < 20; i++) { + clear_screen(); + print_guy_run(i); + sleep_ms(10); + } + for (int i = 20; i >0; i--) { + clear_screen(); + print_guy_run(i); + sleep_ms(10); + } + printf("OS ROCKS!!\n"); +} + +void guy_celebrate() { + clear_screen(); + print_guy_U(); + printf("%s", GREEN); + for (int i = 0; i < 15; i++) { + clear_screen(); + if (i % 2 == 0) { + print_guy_U(); + } else { + print_guy(); + } + sleep_ms(10); + } + clear_screen(); + print_guy(); + printf("%s", RESET); +} + +void guy_info() { + print_guy(); + guy_celebrate(); + printf("%s", GREEN); + printf("I'm your OS buddy! As you interact with the OS, you can type \n\"guy celebrate\", \"guy gets mad\", or \"guy run\" \nas you get bored/frustrated.\nYou will also find me scattered across various functions in the OS that call on the \"guy\" library !!\nTry calling ls to see an example.\n"); + printf("%s", RESET); +} + +void print_mes(char* str) { + print_guy(); + printf(" ^"); + printf(" / \\n"); + printf(" | | \n"); + printf(" | | \n"); + printf("%s", str); + free(str); +} + +void guy_celebrate_intro() { + clear_screen(); + print_guy_U(); + printf("%s", GREEN); + for (int i = 0; i < 15; i++) { + clear_screen(); + if (i % 2 == 0) { + print_guy_U(); + } else { + print_guy(); + } + sleep_ms(10); + } + clear_screen(); + sleep(1); + guy_run(); + guy_move_head(); + printf("WELCOME TO FogOS !! Type \"guy info\" to see more of me.\n"); + printf("%s", RESET); +} diff --git a/user/init.c b/user/init.c index 55d27d3..956c579 100644 --- a/user/init.c +++ b/user/init.c @@ -23,14 +23,7 @@ main(void) dup(0); // stdout dup(0); // stderr - printf(" __________________\n"); - printf("< Welcome to FogOS >\n"); - printf(" ------------------\n"); - printf(" \\ ^__^\n"); - printf(" \\ (**)\\_______\n"); - printf(" (__)\\ )\\/\\\n"); - printf(" U ||----w |\n"); - printf(" || ||\n"); + guy_celebrate_intro(); for(;;){ printf("init: starting sh\n"); @@ -51,7 +44,7 @@ main(void) wpid = wait((int *) 0); if(wpid == pid){ // the shell exited; restart it. - break; + break; } else if(wpid < 0){ printf("init: wait returned an error\n"); exit(1); diff --git a/user/ls.c b/user/ls.c index c67b84b..2645c34 100644 --- a/user/ls.c +++ b/user/ls.c @@ -2,6 +2,8 @@ #include "kernel/stat.h" #include "user/user.h" #include "kernel/fs.h" +#define RESET "\033[0m" +#define GREEN "\033[32m" char* fmtname(char *path) @@ -41,6 +43,11 @@ ls(char *path) return; } + guy_celebrate(); + printf("%s", GREEN); + printf("WOO! All the files!\n"); + printf("%s", RESET); + switch(st.type){ case T_DEVICE: case T_FILE: diff --git a/user/rm.c b/user/rm.c index 26b8f1f..8452869 100644 --- a/user/rm.c +++ b/user/rm.c @@ -1,6 +1,8 @@ #include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" +#define RED "\033[31m" +#define RESET "\033[0m" int main(int argc, char *argv[]) @@ -12,6 +14,11 @@ main(int argc, char *argv[]) exit(1); } + guy_mad(); + printf("%s", RED); + printf("REMOVE IT !!\n"); + printf("%s", RESET); + for(i = 1; i < argc; i++){ if(unlink(argv[i]) < 0){ fprintf(2, "rm: %s failed to delete\n", argv[i]); diff --git a/user/user.h b/user/user.h index 2e6fc55..e5d1e1a 100644 --- a/user/user.h +++ b/user/user.h @@ -1,3 +1,4 @@ +#include "kernel/types.h" struct stat; // system calls @@ -22,6 +23,7 @@ int getpid(void); char* sbrk(int); int sleep(int); int uptime(void); +int sleep_ms(int); // ulib.c int stat(const char*, struct stat*); @@ -41,3 +43,19 @@ void free(void*); int atoi(const char*); int memcmp(const void *, const void *, uint); void *memcpy(void *, const void *, uint); + +//guy2.c +void guy_celebrate_intro(void); +void clear_screen(void); +void print_guy(void); +void print_guy(void); +void print_guy_U(void); +void print_guy_L(void); +void print_guy_R(void); +void print_guy_run(int pos); +void guy_mad(void); +void guy_move_head(void); +void guy_run(void); +void guy_celebrate(void); +void guy_info(void); +void guy_mes(char* str); diff --git a/user/usys.pl b/user/usys.pl index 01e426e..123c3b6 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,4 @@ sub entry { entry("sbrk"); entry("sleep"); entry("uptime"); +entry("sleep_ms");