├── .gitignore ├── Makefile ├── README.STARTING_P3 ├── README.dox ├── config.mk ├── doxygen.conf ├── kern ├── asm_helpers.S ├── console.c ├── data_structures │ ├── circ_buffer.c │ ├── ht.c │ ├── ll.c │ ├── queue.c │ └── stack.c ├── debug.c ├── dispatcher │ ├── asm_helpers.S │ └── dispatcher.c ├── handlers │ ├── console_io_handlers.c │ ├── exception_handler_wrappers.S │ ├── exception_handlers.c │ ├── life_cycle_handlers.c │ ├── mem_mgmt_handlers.c │ ├── misc_handlers.c │ ├── peripheral_handler_wrappers.S │ ├── peripheral_handlers.c │ ├── syscall_handler_wrappers.S │ └── thr_mgmt_handlers.c ├── inc │ ├── circ_buffer.h │ ├── console.h │ ├── constants.h │ ├── debug.h │ ├── dispatcher.h │ ├── frame_manager.h │ ├── ht.h │ ├── idt_handlers.h │ ├── install_handlers.h │ ├── kern_internals.h │ ├── keyboard.h │ ├── ll.h │ ├── loader.h │ ├── mem_section.h │ ├── mutex.h │ ├── page_directory.h │ ├── pcb.h │ ├── queue.h │ ├── rwlock.h │ ├── sched_mutex.h │ ├── scheduler.h │ ├── sem.h │ ├── special_reg_cntrl.h │ ├── stack.h │ ├── tcb.h │ ├── tcb_pool.h │ ├── thr_helpers.h │ └── virtual_mem_mgmt.h ├── install_handlers.c ├── kernel.c ├── keyboard.c ├── loader │ └── loader.c ├── locks │ ├── mutex.c │ ├── rwlock.c │ ├── sched_mutex.c │ └── sem.c ├── malloc_wrappers.c ├── scheduler │ ├── pcb.c │ ├── scheduler.c │ ├── tcb.c │ ├── tcb_pool.c │ ├── thr_helpers.c │ └── thr_helpers_wrappers.S ├── smp_glue.c ├── special_register_cntrl │ ├── asm_functions.S │ └── spec_reg_wrappers.c └── virtual_mem_mgmt │ ├── frame_manager.c │ ├── mem_section.c │ ├── page_directory.c │ └── virtual_mem_mgmt.c ├── update.sh ├── user ├── files │ ├── dog.txt │ ├── donkey.txt │ └── shrek.txt ├── inc │ ├── README.userinc │ ├── cond_type.h │ ├── mutex_type.h │ ├── rwlock_type.h │ └── sem_type.h ├── libautostack │ └── autostack.c ├── libsyscall │ ├── syscall.c │ ├── syscall_deschedule.S │ ├── syscall_exec.S │ ├── syscall_fork.S │ ├── syscall_get_cursor_pos.S │ ├── syscall_get_ticks.S │ ├── syscall_getchar.S │ ├── syscall_gettid.S │ ├── syscall_halt.S │ ├── syscall_make_runnable.S │ ├── syscall_misbehave.S │ ├── syscall_new_pages.S │ ├── syscall_print.S │ ├── syscall_readfile.S │ ├── syscall_readline.S │ ├── syscall_remove_pages.S │ ├── syscall_set_cursor_pos.S │ ├── syscall_set_status.S │ ├── syscall_set_term_color.S │ ├── syscall_sleep.S │ ├── syscall_swexn.S │ ├── syscall_task_vanish.S │ ├── syscall_vanish.S │ ├── syscall_wait.S │ └── syscall_yield.S ├── libthread │ ├── asm_helpers.S │ ├── cond.c │ ├── ll.c │ ├── ll.h │ ├── malloc.c │ ├── mutex.c │ ├── panic.c │ ├── rwlock.c │ ├── sem.c │ ├── thr_internals.h │ └── thread.c └── progs │ ├── test_agility_drill.c │ ├── test_console_io.c │ ├── test_cs.c │ ├── test_cyclone.c │ ├── test_deschedule.c │ ├── test_div0.c │ ├── test_exec1.c │ ├── test_foo.c │ ├── test_gettid.c │ ├── test_hello.c │ ├── test_mem_mgmt.c │ ├── test_new_pages.c │ ├── test_paraguay.c │ ├── test_readline.c │ ├── test_sleep.c │ ├── test_startle.c │ ├── test_thr_create.c │ └── test_yield.c └── vq_challenge ├── Makefile ├── README.dox ├── variable_queue.h └── vqtest.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | *.dep 7 | 8 | # Precompiled Headers 9 | *.gch 10 | *.pch 11 | 12 | # Libraries 13 | *.lib 14 | *.a 15 | *.la 16 | *.lo 17 | 18 | # Shared objects (inc. Windows DLLs) 19 | *.dll 20 | *.so 21 | *.so.* 22 | *.dylib 23 | 24 | # Executables 25 | *.exe 26 | *.out 27 | *.app 28 | *.i*86 29 | *.x86_64 30 | *.hex 31 | 32 | # Debug files 33 | *.dSYM/ 34 | 35 | # Python Binaries 36 | *.pyc 37 | 38 | # Test Binaries 39 | *_test 40 | *-output 41 | .md5s 42 | 43 | #Swap Files 44 | *.swp 45 | *.swo 46 | *.swn 47 | *.swm 48 | *.__* 49 | 50 | # User Test binaries 51 | user/progs/test_[a-z\w]* 52 | !user/progs/test_[a-z\w]*.c 53 | 54 | # Doxygen Files 55 | doc/ 56 | doxygen.warn 57 | 58 | # Ignored Specifics 59 | kernel* 60 | !kernel.c 61 | *.img 62 | 410kern/* 63 | 410user/* 64 | temp/* 65 | spec/ 66 | update 67 | -------------------------------------------------------------------------------- /README.STARTING_P3: -------------------------------------------------------------------------------- 1 | 0. Introduction 2 | 3 | This README contains some build instrucions and some notes on the 4 | layout of this directory structure. 5 | 6 | 1. Using your P1 code in P3 7 | 8 | We have given you kern/fake_console.c and kern/inc/console.h. 9 | In order for the stdio library to print things, it must 10 | be able to "find" putbytes() and putbyte(), which must 11 | be defined by console.h. The source for those of course 12 | need not be in a file called "fake_console.c"! 13 | 14 | The exact interfaces between your kernel code and your P1 15 | console, timer, and keyboard are up to you--function names 16 | can change if appropriate, etc. 17 | 18 | 2. Build Process 19 | 20 | The build process for this project is somewhat complicated but 21 | it should be easy for you to get it to do things you're supposed 22 | to get it to do. 23 | 24 | In the top-level directory there is a file called config.mk. You 25 | should carefully read all instructions in config.mk before asking 26 | questions about the build process. Also, for reasons explained 27 | below, it is VERY IMPORTANT for you to review your config.mk as 28 | you are preparing to submit your kernel. The definitive instructions 29 | are in config.mk, not here, but in this README we will briefly 30 | mention some considerations relevant to getting started. 31 | 32 | UPDATE_METHOD should be left set to "afs" if possible. 33 | 34 | 410KERNEL_OBJS builds files from 410kern/ into your kernel. 35 | KERNEL_OBJS builds files from kern/ into your kernel. 36 | 37 | 410REQPROGS builds files from 410user/progs into your kernel's 38 | RAM-disk file system. It is VERY IMPORTANT that you list here 39 | only files which must be present for your kernel to boot (e.g., 40 | idle, init, shell). DO NOT INCLUDE ANY TEST PROGRAMS IN 41 | 410REQPROGS, EVER, NOT EVEN JUST FOR A MOMENT. 42 | 43 | STUDENTREQPROGS builds files from user/progs into your kernel's 44 | RAM-disk file system. It is VERY IMPORTANT that you list here 45 | only files which must be present for your kernel to boot. 46 | DO NOT INCLUDE ANY TEST PROGRAMS IN STUDENTREQPROGS, EVER, NOT 47 | EVEN JUST FOR A MOMENT. 48 | 49 | 410TESTS and STUDENTTESTS specify which OPTIONAL programs 50 | from {410user/progs,user/progs}, respectively, will be built 51 | into your kernel's RAM-disk file system. If you want to write 52 | a test program called "test", put test.c into user/progs and 53 | put "test" into STUDENTTESTS. Before we grade your kernel, 54 | we will overwrite the values of 410TESTS and STUDENTTESTS. 55 | If either one contains the name of a program your kernel 56 | needs to operate properly, you will fail the entire test 57 | suite. 58 | 59 | THREAD_OBJS and SYSCALL_OBJS are the names of object (.o) files 60 | in the user/lib{thread,syscall} directories, respectively, 61 | which you wish to be built into libthread.a and libsyscall.a. 62 | 63 | When we grade your submission we will depend on THREAD_OBJS and 64 | SYSCALL_OBJS being correct and we will override the values of 65 | 410TESTS and STUDENTTESTS. 66 | 67 | If you feel you need to edit one or more Makefiles, you should 68 | probably stop and consult the course staff. Before building 69 | and grading your submission, we will wipe out any Makefile 70 | changes which haven't been cleared... 71 | 72 | 3. Getting started 73 | 74 | This tarball contains a fake Makefile. If the update 75 | method setting in config.mk is ok, typing "make" should 76 | populate the directory tree and build a "kernel" which 77 | when booted does nothing but print out a greeting to 78 | the simics log. 79 | 80 | 4. Directory Structure 81 | 82 | ./ 83 | The only files you should ever even think about editing in the 84 | top-level directory is config.mk, and you should not edit 85 | config.mk without carefully reading the instructions for the 86 | part you are editing. 87 | 88 | ./410kern 89 | We have placed some useful support code here (libraries and 90 | include files). Please don't put anything here yourselves. 91 | 92 | ./kern 93 | Your mission, since you have chosen to accept it, will be to 94 | fill in this directory with a kernel implementation. Good luck! 95 | 96 | ./user/inc, ./user/libsyscall, ./user/libthread 97 | You will probably wish to populate these directories with your 98 | Project 2 files. 99 | 100 | ./user/progs 101 | This is where you should put the source files for your tests. 102 | You should not have to edit the Makefile. You should add your 103 | tests to config.mk. 104 | 105 | ./410user/progs 106 | This is where we will stick our tests. Don't touch this directory. 107 | 108 | ./temp 109 | This is a directory where some temp files will go during the build 110 | process that makes the RAM disk. You should not have to touch this 111 | directory. 112 | 113 | ./vq_challenge 114 | This directory contains details of a totally-optional challenge you 115 | may wish to take on, namely using macros to generate embedded 116 | linked-list traversal declarations and code. You really don't have 117 | to do this, but you might like the results. 118 | -------------------------------------------------------------------------------- /kern/asm_helpers.S: -------------------------------------------------------------------------------- 1 | /** 2 | * @file asm_helpers.S 3 | * @brief Assembly helper functions for kernel 4 | * @author Aatish Nayak (aatishn) and Christopher Wei (cjwei) 5 | * @bug No known bugs 6 | */ 7 | 8 | .globl xchng 9 | 10 | xchng: 11 | push %ebx 12 | movl 8(%esp), %ebx // address to lock 13 | movl 12(%esp), %eax // value to be stored into lock 14 | xchg %eax, (%ebx) 15 | pop %ebx 16 | ret 17 | 18 | 19 | -------------------------------------------------------------------------------- /kern/data_structures/circ_buffer.c: -------------------------------------------------------------------------------- 1 | /** @file circ_buffer.c 2 | * @brief implements a circular buffer 3 | * @author Christopher Wei (cjwei) 4 | * @bug No known bugs 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | /* Implementation */ 11 | 12 | /** @brief Initializes a circular buffer of size len 13 | * @param circ_buf The circular buffer 14 | * @param len The maximum length to cap it at 15 | * @return 0 on success, negative integer code on failure 16 | */ 17 | int circ_buf_init(circ_buf_t *circ_buf, uint32_t len){ 18 | if (circ_buf == NULL || len == 0) return -1; 19 | circ_buf->i_r = 0; 20 | circ_buf->i_w = 0; 21 | circ_buf->n = 0; 22 | circ_buf->buf = (void **)malloc(len * sizeof(void *)); 23 | if (circ_buf->buf == NULL) return -2; 24 | circ_buf->len = len; 25 | return 0; 26 | } 27 | 28 | /** @brief Destroys a circular buffer 29 | * @param circ_buf The circular buffer 30 | * @return Void 31 | */ 32 | void circ_buf_destroy(circ_buf_t *circ_buf){ 33 | if (circ_buf == NULL) return; 34 | free((void *)circ_buf->buf); 35 | return; 36 | } 37 | 38 | /** @brief Writes a value to the circular buffer 39 | * @param circ_buf The circular buffer 40 | * @param v The value to write 41 | * @return 0 on success, negative integer code on failure 42 | */ 43 | int circ_buf_write(circ_buf_t *circ_buf, void *v){ 44 | if (circ_buf == NULL) return -1; 45 | /* move i_r to next spot*/ 46 | int next_i_w; 47 | next_i_w = (circ_buf->i_w + 1) % circ_buf->len; 48 | if (circ_buf->n+1 == circ_buf->len){ 49 | /* no space left, ignore character */ 50 | return -1; 51 | } else { 52 | /* save character */ 53 | circ_buf->buf[circ_buf->i_w] = v; 54 | /* advance i_w */ 55 | circ_buf->i_w = next_i_w; 56 | /* increase the size */ 57 | circ_buf->n++; 58 | return 0; 59 | } 60 | } 61 | 62 | /** @brief Reads a value out of the circular buffer 63 | * @param circ_buf The circular buffer 64 | * @param v The value to read into 65 | * @return 0 on success, negative integer code on failure 66 | */ 67 | int circ_buf_read(circ_buf_t *circ_buf, void **v){ 68 | if (circ_buf == NULL) return -1; 69 | if (circ_buf->n == 0) return -2; 70 | /* optionally save character into v */ 71 | if (v != NULL) *v = circ_buf->buf[circ_buf->i_r]; 72 | /* update read position */ 73 | circ_buf->i_r = (circ_buf->i_r + 1) % circ_buf->len; 74 | /* decrease count */ 75 | circ_buf->n--; 76 | return 0; 77 | } 78 | 79 | /** @brief Removes the most recently written value in the circular buffer 80 | * @param circ_buf The circular buffer 81 | * @return 0 on success, negative integer code on failure 82 | */ 83 | int circ_buf_delete_front(circ_buf_t *circ_buf){ 84 | if (circ_buf == NULL) return -1; 85 | if (circ_buf->n == 0) return -2; 86 | circ_buf->i_w = (circ_buf->i_w - 1) % circ_buf->len; 87 | circ_buf->n--; 88 | return 0; 89 | } 90 | 91 | /** @brief Returns the number of values in the circular buffer 92 | * @param circ_buf The circular buffer 93 | * @return 0 on success, negative integer code on failure 94 | */ 95 | int circ_buf_count(circ_buf_t *circ_buf, uint32_t *count){ 96 | if (circ_buf == NULL) return -1; 97 | *count = circ_buf->n; 98 | return 0; 99 | } 100 | 101 | /** @brief Gets the maximum capacity of a circular buffer 102 | * @param circ_buf The circular buffer 103 | * @param len The address to store the result in 104 | * @return 0 on success, negative integer code on failure 105 | */ 106 | int circ_buf_size(circ_buf_t *circ_buf, uint32_t *len){ 107 | if (circ_buf == NULL || len == NULL) return -1; 108 | *len = circ_buf->len; 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /kern/data_structures/ht.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ht.c 3 | * 4 | * @brief Implementation of a generic hash table with seperate chaining 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | /** 16 | * @brief Initializes a hash table with provided parameters 17 | * 18 | * @param ht ht to init 19 | * @param max_size max size to make the table 20 | * @param hash provided hash function 21 | * 22 | * @return 0 on success, negative error code otherwise 23 | * 24 | */ 25 | int ht_init(ht_t *t, uint32_t max_size, int (*hash)(key_t key)) { 26 | if (t == NULL || hash == NULL || max_size == 0) return -1; 27 | 28 | /* Create a new array to hold buckets */ 29 | t->arr = malloc(max_size * sizeof(ll_t)); 30 | if (t->arr == NULL) return -2; 31 | int i; 32 | 33 | /* Init all linked list buckets */ 34 | for (i = 0 ; i < max_size ; i++) { 35 | if (ll_init(&(t->arr[i])) < 0) return -2; 36 | } 37 | 38 | /* Init all fields */ 39 | t->size = 0; 40 | t->max_size = max_size; 41 | t->hash = hash; 42 | 43 | return 0; 44 | } 45 | 46 | void *extract_key(void *entry) { 47 | 48 | ht_entry_t *e = (ht_entry_t *) entry; 49 | return (void*)(e->key); 50 | } 51 | 52 | /** 53 | * @brief Gets the value with the key provided 54 | * 55 | * @param ht Hashtable to access 56 | * @param key Key used to find the data desired 57 | * @param valp Address to store value 58 | * 59 | * @return 0 on success, negative error code otherwise 60 | * 61 | */ 62 | int ht_get(ht_t *t, key_t key, void **valp) { 63 | if (t == NULL || valp == NULL) return -1; 64 | 65 | /* Index into correct bucket */ 66 | int idx = t->hash(key) % t->max_size; 67 | 68 | ht_entry_t *e; 69 | /* Find element in bucket */ 70 | if (ll_find(&(t->arr[idx]), extract_key, (void*) key, (void*) &e) < 0) { 71 | /* Not found */ 72 | return -2; 73 | } 74 | *valp = e->val; 75 | return 0; 76 | } 77 | 78 | /** 79 | * @brief Removes and reports the value with the key provided 80 | * 81 | * @param ht Hashtable to access 82 | * @param key Key used to find the data desired 83 | * @param valp Address to store value 84 | * 85 | * @return 0 on success, negative error code otherwise 86 | * 87 | */ 88 | int ht_remove(ht_t *t, key_t key, void **valp, circ_buf_t *addrs_to_free) { 89 | if(t == NULL) return -1; 90 | 91 | /* Index into correct bucket */ 92 | int idx = t->hash(key) % t->max_size; 93 | 94 | ht_entry_t *e; 95 | /* Remove from bucket */ 96 | if (ll_remove(&(t->arr[idx]), extract_key, (void*) key, (void**) &e, addrs_to_free) < 0) { 97 | /* Not found */ 98 | return -2; 99 | } 100 | /* Store value */ 101 | if (valp != NULL) *valp = e->val; 102 | 103 | /* Save addr to free or free right now */ 104 | if (addrs_to_free != NULL) { 105 | circ_buf_write(addrs_to_free, (void*) e); 106 | } else { 107 | free(e); 108 | } 109 | t->size--; 110 | return 0; 111 | } 112 | 113 | /** 114 | * @brief Inserts the key and value pair in the specified hash table 115 | * 116 | * Uses provided hash function to calculate a bucket index 117 | * 118 | * @param ht Hash table to insert pair into 119 | * @param key key in key-value pair 120 | * @param val value in key-value pair 121 | * 122 | * @return 0 on success, negative error code otherwise 123 | * 124 | */ 125 | int ht_put(ht_t *t, key_t key, void *val) { 126 | if (t == NULL) return -1; 127 | 128 | void *dummy; 129 | /* Check if specified key value pair is already in the ht */ 130 | if (ht_get(t, key, &dummy) != -2) return -4; 131 | 132 | /* Index into correct bucket */ 133 | int idx = t->hash(key) % t->max_size; 134 | 135 | /* Init a new entry */ 136 | ht_entry_t *new_e = malloc(sizeof(ht_entry_t)); 137 | if (new_e == NULL) return -2; 138 | new_e->val = val; 139 | new_e->key = key; 140 | 141 | if(ll_add_last(&(t->arr[idx]), (void*) new_e) < 0) return -3; 142 | t->size++; 143 | return 0; 144 | } 145 | /** 146 | * @brief Inserts a pre-initialized hash table entry into the hash table 147 | * 148 | * Uses provided hash function to calculate a bucket index 149 | * 150 | * @param ht Hash table to insert pair into 151 | * @param entry The entry to insert 152 | * @param entry_node The linked list node to use 153 | * 154 | * @return 0 on success, negative error code otherwise 155 | * 156 | */ 157 | int ht_put_entry(ht_t *t, ht_entry_t *entry, ll_node_t *entry_node) { 158 | if (t == NULL || entry == NULL) return -1; 159 | 160 | void *dummy; 161 | /* Check if specified key value pair is already in the ht */ 162 | if (ht_get(t, entry->key, &dummy) != -2) return -4; 163 | 164 | /* Index into correct bucket */ 165 | int idx = t->hash(entry->key) % t->max_size; 166 | 167 | if(ll_link_node_last(&(t->arr[idx]), entry_node) < 0) return -3; 168 | t->size++; 169 | return 0; 170 | } 171 | 172 | 173 | 174 | /** 175 | * @brief Destroys the specified hash table and frees it's data structures 176 | * 177 | * @param ht Hash table to destroy 178 | * 179 | * @return 0 on success, negative error code otherwise 180 | * 181 | */ 182 | void ht_destroy(ht_t *t) { 183 | if (t == NULL) return; 184 | 185 | int i; 186 | /* Free each bucket chain */ 187 | for (i = 0; i < t->max_size; i++) { 188 | ll_destroy(&(t->arr[i])); 189 | } 190 | /* Free table */ 191 | free(t->arr); 192 | } 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /kern/data_structures/queue.c: -------------------------------------------------------------------------------- 1 | /** @file queue.c 2 | * @brief Implements a queue using linked lists 3 | * @author Christopher Wei (cjwei) 4 | * @author Aatish Nayak (aatishn) 5 | 6 | * @bug No known bugs 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /** 14 | * @brief initializes a queue 15 | * 16 | * @param q The queue 17 | * 18 | * @return 0 on success, negative erorr code otherwise 19 | */ 20 | int queue_init(queue_t *q){ 21 | if (q == NULL) return -1; 22 | ll_t *ll_new = malloc(sizeof(ll_t)); 23 | q->ll = ll_new; 24 | return ll_init(q->ll); 25 | } 26 | /** 27 | * @brief enqueues an element to the queue 28 | * 29 | * @param q The queue 30 | * @param value The value to enqueue 31 | * 32 | * @return 0 on success, negative erorr code otherwise 33 | */ 34 | int queue_enq(queue_t *q, void *value){ 35 | if (q == NULL) return -1; 36 | return ll_add_last(q->ll, value); 37 | } 38 | /** 39 | * @brief dequeues an element from the queue 40 | * 41 | * @param q The queue 42 | * @param value_ptr The pointer to store the value that is dequeued 43 | * 44 | * @return 0 on success, negative erorr code otherwise 45 | */ 46 | int queue_deq(queue_t *q, void **value_ptr){ 47 | if (q == NULL) return -1; 48 | return ll_remove_first(q->ll, value_ptr); 49 | } 50 | /** 51 | * @brief Destroys a queue 52 | * 53 | * @param q The queue 54 | * 55 | * @return 0 on success, negative erorr code otherwise 56 | */ 57 | void queue_destroy(queue_t *q){ 58 | if (q == NULL) return; 59 | ll_destroy(q->ll); 60 | free(q->ll); 61 | } 62 | /** 63 | * @brief Peeks at the next element in a queue 64 | * 65 | * @param q The queue 66 | * @param value_ptr Where to store the value 67 | * 68 | * @return 0 on success, negative erorr code otherwise 69 | */ 70 | int queue_peek(queue_t *q, void **value_ptr){ 71 | if (q == NULL) return -1; 72 | return ll_peek(q->ll, value_ptr); 73 | } 74 | /** 75 | * @brief Returns the number of elements in a queue 76 | * 77 | * @param q The queue 78 | * 79 | * @return number of elements in a queue 80 | */ 81 | int queue_size(queue_t *q){ 82 | if (q == NULL) return -1; 83 | return ll_size(q->ll); 84 | } 85 | -------------------------------------------------------------------------------- /kern/data_structures/stack.c: -------------------------------------------------------------------------------- 1 | /** @file stack.c 2 | * @brief Implements a stack using linked lists 3 | * @author Christopher Wei (cjwei) 4 | * @author Aatish Nayak (aatishn) 5 | 6 | * @bug No known bugs 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | /** 13 | * @brief initializes a stack 14 | * 15 | * @param stk The stack 16 | * 17 | * @return 0 on success, negative erorr code otherwise 18 | */ 19 | int stack_init(stack_t *stk){ 20 | if (stk == NULL) return -1; 21 | ll_t *ll_new = malloc(sizeof(ll_t)); 22 | stk->ll = ll_new; 23 | return ll_init(stk->ll); 24 | } 25 | /** 26 | * @brief pushes an element to the stack 27 | * 28 | * @param stk The stack 29 | * @param value The value to push 30 | * 31 | * @return 0 on success, negative erorr code otherwise 32 | */ 33 | int stack_push(stack_t *stk, void *value){ 34 | if (stk == NULL) return -1; 35 | return ll_add_first(stk->ll, value); 36 | } 37 | /** 38 | * @brief pops an element from the stack 39 | * 40 | * @param stk The stack 41 | * @param value_ptr The pointer to store the value that is popped to 42 | * 43 | * @return 0 on success, negative erorr code otherwise 44 | */ 45 | int stack_pop(stack_t *stk, void **value_ptr){ 46 | if (stk == NULL) return -1; 47 | return ll_remove_first(stk->ll, value_ptr); 48 | } 49 | /** 50 | * @brief Destroys a stack 51 | * 52 | * @param stk The stack 53 | * 54 | * @return 0 on success, negative erorr code otherwise 55 | */ 56 | void stack_destroy(stack_t *stk){ 57 | if (stk == NULL) return; 58 | ll_destroy(stk->ll); 59 | free(stk); 60 | } 61 | /** 62 | * @brief Peeks at the next element in a stack 63 | * 64 | * @param stk The stack 65 | * @param value_ptr Where to store the value 66 | * 67 | * @return 0 on success, negative erorr code otherwise 68 | */ 69 | int stack_peek(stack_t *stk, void **value_ptr){ 70 | if (stk == NULL) return -1; 71 | return ll_peek(stk->ll, value_ptr); 72 | } 73 | 74 | /** 75 | * @brief Returns the number of elements in a stack 76 | * 77 | * @param stk The stack 78 | * 79 | * @return number of elements in a stack 80 | */ 81 | int stack_size(stack_t *stk){ 82 | if (stk == NULL) return -1; 83 | return ll_size(stk->ll); 84 | } 85 | -------------------------------------------------------------------------------- /kern/debug.c: -------------------------------------------------------------------------------- 1 | /** @file debug.c 2 | * @brief Implementation of debugging functions 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | * @bug No known bugs. 7 | */ 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | void print_control_regs(void) { 19 | lprintf("----- Control Registers -----"); 20 | lprintf("cr0 0x%x", (unsigned int) get_cr0()); 21 | lprintf("cr2 0x%x", (unsigned int) get_cr2()); 22 | lprintf("cr3 0x%x", (unsigned int) get_cr3()); 23 | lprintf("cr4 0x%x", (unsigned int) get_cr4()); 24 | 25 | } 26 | 27 | void print_context(unsigned int *stack) { 28 | print_control_regs(); 29 | lprintf("Stack: %p", stack); 30 | lprintf("------- Context --------"); 31 | lprintf("ss: 0x%x", stack[SS_IDX]); 32 | lprintf("esp: 0x%x", stack[ESP_IDX]); 33 | lprintf("eflags: 0x%x", stack[EFLAGS_IDX]); 34 | lprintf("cs: 0x%x", stack[CS_IDX]); 35 | lprintf("eip: 0x%x", stack[EIP_IDX]); 36 | lprintf("ecx: 0x%x", stack[ECX_IDX]); 37 | lprintf("edx: 0x%x", stack[EDX_IDX]); 38 | lprintf("ebx: 0x%x", stack[EBX_IDX]); 39 | lprintf("ebp: 0x%x", stack[EBP_IDX]); 40 | lprintf("esi: 0x%x", stack[ESI_IDX]); 41 | lprintf("edi: 0x%x", stack[EDI_IDX]); 42 | lprintf("ds: 0x%x", stack[DS_IDX]); 43 | lprintf("es: 0x%x", stack[ES_IDX]); 44 | lprintf("fs: 0x%x", stack[FS_IDX]); 45 | lprintf("gs: 0x%x", stack[GS_IDX]); 46 | lprintf("------ End Context -------"); 47 | } 48 | 49 | void print_page_directory(page_directory_t *pd, int start, int len, int verbose){ 50 | uint32_t *directory = pd->directory; 51 | lprintf("----- Page Directory -----"); 52 | lprintf("Page Directory Base Address: %p", directory); 53 | int i, j; 54 | for (i = start+len-1; i >= start; i--){ 55 | if ((directory[i] & 1) != 0){ 56 | lprintf("PDE #%d <%p>", i, (void *)directory[i]); 57 | unsigned int *temp = 58 | (unsigned int *)((unsigned int)directory[i] & MSB_20_MASK); 59 | if (verbose){ 60 | for (j = 1023; j >= 0; j--){ 61 | lprintf("> PTE #%d : 0x%x", j, temp[j]); 62 | } 63 | } else { 64 | lprintf("> PTE #1023 : 0x%x", temp[1023]); 65 | lprintf("> PTE #1022 : 0x%x", temp[1022]); 66 | lprintf("> PTE #1021 : 0x%x", temp[1021]); 67 | lprintf("> PTE #1020 : 0x%x", temp[1020]); 68 | lprintf("> PTE #1019 : 0x%x", temp[1019]); 69 | lprintf("> PTE #1018 : 0x%x", temp[1018]); 70 | lprintf("> ...."); 71 | lprintf("> PTE #0002 : 0x%x", temp[2]); 72 | lprintf("> PTE #0001 : 0x%x", temp[1]); 73 | lprintf("> PTE #0000 : 0x%x", temp[0]); 74 | } 75 | } 76 | } 77 | } 78 | 79 | void translate_addr(page_directory_t *pd, unsigned int addr) { 80 | unsigned int *dir = (unsigned int*)pd->directory; 81 | lprintf("---- Translating Virtual Addr %d ----", addr); 82 | unsigned int top_10 = addr & 0xffc00000; 83 | unsigned int middle_10 = addr & 0x003ff000; 84 | unsigned int pde = top_10 / PAGE_SIZE; 85 | unsigned int pte = middle_10 % 1024; //NUM_ENTRIES removed 86 | lprintf("PDE: 0x%x", pde); 87 | lprintf("PTE: 0x%x", pte); 88 | if ((dir[pte] & 1) == 0) { 89 | lprintf("PDE NOT PRESENT"); 90 | return; 91 | } else { 92 | lprintf("pte:%d %p", pte, (void *)dir[pte]); 93 | unsigned int *temp = 94 | (unsigned int *)((unsigned int)dir[pte] & MSB_20_MASK); 95 | lprintf("-->[%x]", temp[1023]); 96 | lprintf("-->[%x]", temp[1022]); 97 | lprintf(" ...."); 98 | lprintf("-->[%x]", temp[2]); 99 | lprintf("-->[%x]", temp[1]); 100 | lprintf("-->[%x]", temp[0]); 101 | 102 | 103 | } 104 | 105 | } 106 | 107 | void print_elf(simple_elf_t *elf) { 108 | lprintf("---- Elf containing '%s' ----", elf->e_fname); 109 | lprintf("Text Start: 0x%x Len: 0x%x", (unsigned int) elf->e_txtstart, (unsigned int) elf->e_txtlen); 110 | lprintf("Data Start: 0x%x Len: 0x%x", (unsigned int) elf->e_datstart, (unsigned int) elf->e_datlen); 111 | lprintf("BSS Start: 0x%x Len: 0x%x", (unsigned int) elf->e_bssstart, (unsigned int) elf->e_bsslen); 112 | 113 | } 114 | 115 | -------------------------------------------------------------------------------- /kern/dispatcher/asm_helpers.S: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | 5 | .globl restore_context 6 | 7 | restore_context: 8 | movl 4(%esp), %esp 9 | pop %ds 10 | pop %es 11 | pop %fs 12 | pop %gs 13 | popa 14 | addl $4, %esp /* skip error_code */ 15 | iret 16 | -------------------------------------------------------------------------------- /kern/dispatcher/dispatcher.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | 16 | /** 17 | * @brief Disables interrupts and does a context switch (defined below) 18 | * 19 | * @param old_esp esp of the thread you are context switching out of 20 | * @param target_tid tid of thread to switch into (-1 if scheduler should 21 | * determine thread) 22 | * 23 | * @return esp of thread that is to be switched into 24 | * 25 | */ 26 | uint32_t context_switch_safe(uint32_t old_esp, int target_tid) { 27 | sched_mutex_lock(&sched_lock); 28 | uint32_t new_esp = context_switch(old_esp, target_tid); 29 | sched_mutex_unlock(&sched_lock); 30 | return new_esp; 31 | } 32 | 33 | /** 34 | * @brief Saves the old_esp into the current running tcb, gets the next 35 | * tcb to run, and sets it to running 36 | * 37 | * @param old_esp esp of the thread you are context switching out of 38 | * @param target_tid tid of thread to switch into (-1 if scheduler should 39 | * determine thread) 40 | * 41 | * @return esp of thread that is to be switched into 42 | * 43 | */ 44 | uint32_t context_switch(uint32_t old_esp, int target_tid) { 45 | 46 | /* Defer current TCB */ 47 | if (scheduler_defer_current_tcb(&sched, old_esp) < 0) { 48 | panic("Cannot defer current running thread. \ 49 | Scheduler is corrupted and cannot context switch"); 50 | } 51 | 52 | tcb_t *next_tcb; 53 | uint32_t new_esp; 54 | /* Switch to scheduler selected tid */ 55 | if (target_tid < 0) { 56 | /* Get next available TCB */ 57 | if (scheduler_get_next_tcb(&sched, &next_tcb) < 0) { 58 | panic("Scheduler is corrupted and cannot context switch!"); 59 | } 60 | 61 | } else { 62 | /* Get desired tcb */ 63 | if (scheduler_get_tcb_by_tid(&sched, 64 | target_tid, &next_tcb)) { 65 | lprintf("Thread %d does not exist! Running the idle thread...,", target_tid); 66 | if (scheduler_get_idle_tcb(&sched, &next_tcb) < 0) { 67 | panic("Scheduler is corruped, cannot get idle thread!"); 68 | } 69 | } 70 | } 71 | 72 | /* Set current running tcb and get new esp */ 73 | if (scheduler_set_running_tcb(&sched, next_tcb, &new_esp) < 0) { 74 | lprintf("Couldnt set running tcb!!"); 75 | panic("Error trying to run Thread %d. \ 76 | Cannot context switch...", next_tcb->tid); 77 | } 78 | return new_esp; 79 | 80 | } 81 | 82 | -------------------------------------------------------------------------------- /kern/handlers/console_io_handlers.c: -------------------------------------------------------------------------------- 1 | /** @file console_io_handlers.c 2 | * @brief implements thread management syscall handlers 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | * @bug No known bugs. 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | /* access to console mutex and keyboard buffer */ 15 | #include 16 | 17 | /* access to mutex */ 18 | #include 19 | 20 | /* access to KH functions */ 21 | #include 22 | 23 | /**@brief an arbitrary max len */ 24 | #define MAX_SYSCALL_PRINT_LEN 512 25 | 26 | /** @brief Implements the readline syscall 27 | * @param len The maximum characters to read in 28 | * @param buf The buffer to read into 29 | * @return 0 on success, negative integer code on failure 30 | */ 31 | int syscall_readline_c_handler(int len, char *buf){ 32 | uint32_t max_len; 33 | keyboard_buffer_size(&keyboard, &max_len); 34 | if (buf == NULL || len < 0 || (uint32_t)len > max_len) return -1; 35 | pcb_t *pcb; 36 | if (scheduler_get_current_pcb(&sched, &pcb) < 0 ) return -2; 37 | uint32_t priv, access; 38 | /* Ensure the buffer we are writing to is user rw */ 39 | if (pd_get_permissions(&pcb->pd, (uint32_t)buf, &priv, &access) < 0) return -3; 40 | if (priv != PRIV_USER && access != ACC_RW) return -4; 41 | /* attempt to lock the keyboard. only continues when there is an entire 42 | * line to be read from the keyboard */ 43 | return keyboard_read(&keyboard, len, buf); 44 | } 45 | 46 | /** @brief Implements the print system call 47 | * 48 | * Requires the requested length is non-negative and less than our maximum 49 | * print length. 50 | * 51 | * @param len The length of the buffer 52 | * @param buf The buffer to print 53 | * @return 0 on success, -1 on failure 54 | */ 55 | int syscall_print_c_handler(int len, char *buf){ 56 | if (buf == NULL) return -1; 57 | if (len >= MAX_SYSCALL_PRINT_LEN || len < 0) return -2; 58 | mutex_lock(&console_lock); 59 | putbytes(buf, len); 60 | mutex_unlock(&console_lock); 61 | return 0; 62 | } 63 | 64 | 65 | /** @brief Implements the set_term_color system call 66 | * @param color The color to set the terminal color to 67 | * @return 0 on success, negative integer code on failure 68 | */ 69 | int syscall_set_term_color_c_handler(int color){ 70 | return set_term_color(color); 71 | } 72 | 73 | /** @brief Implements the set_cursor_pos system call 74 | * @param row The row to set it to 75 | * @param col The column to set it to 76 | * @return 0 on success, negative integer code on failure 77 | */ 78 | int syscall_set_cursor_pos_c_handler(int row, int col){ 79 | return set_cursor(row, col); 80 | } 81 | 82 | /** @brief Implements the get_cursor_pos system call 83 | * @param row The row pointer to store to 84 | * @param col The column pointer to store to 85 | * @return 0 on success, negative integer code on failure 86 | */ 87 | int syscall_get_cursor_pos_c_handler(int *row, int *col){ 88 | return get_cursor(row, col); 89 | } 90 | -------------------------------------------------------------------------------- /kern/handlers/exception_handler_wrappers.S: -------------------------------------------------------------------------------- 1 | 2 | .macro save_context 3 | pusha 4 | push %gs 5 | push %fs 6 | push %es 7 | push %ds 8 | .endm 9 | .macro restore_context_error_code 10 | pop %ds 11 | pop %es 12 | pop %fs 13 | pop %gs 14 | popa 15 | addl $4, %esp /* skip error_code */ 16 | iret 17 | .endm 18 | 19 | .macro restore_context 20 | pop %ds 21 | pop %es 22 | pop %fs 23 | pop %gs 24 | popa 25 | iret 26 | .endm 27 | 28 | .macro wrapper func 29 | save_context 30 | pushl %esp 31 | call \func 32 | addl $4, %esp 33 | restore_context 34 | .endm 35 | 36 | .macro wrapper_error_code func 37 | save_context 38 | pushl %esp 39 | call \func 40 | addl $4, %esp 41 | restore_context_error_code 42 | .endm 43 | 44 | .globl page_fault_handler 45 | page_fault_handler: 46 | wrapper_error_code page_fault_c_handler 47 | 48 | .globl double_fault_handler 49 | double_fault_handler: 50 | wrapper_error_code double_fault_c_handler 51 | 52 | .globl division_error_handler 53 | division_error_handler: 54 | wrapper division_error_c_handler 55 | 56 | .globl debug_exception_handler 57 | debug_exception_handler: 58 | wrapper debug_exception_c_handler 59 | 60 | .globl breakpoint_handler 61 | breakpoint_handler: 62 | wrapper breakpoint_c_handler 63 | 64 | .globl overflow_handler 65 | overflow_handler: 66 | wrapper overflow_c_handler 67 | 68 | .globl bound_range_handler 69 | bound_range_handler: 70 | wrapper bound_range_c_handler 71 | 72 | .globl undef_op_handler 73 | undef_op_handler: 74 | wrapper undef_op_c_handler 75 | 76 | .globl no_math_handler 77 | no_math_handler: 78 | wrapper no_math_c_handler 79 | 80 | .globl coprocessor_segment_overrun_handler 81 | coprocessor_segment_overrun_handler: 82 | wrapper coprocessor_segment_overrun_c_handler 83 | 84 | .globl invalid_tss_handler 85 | invalid_tss_handler: 86 | wrapper_error_code invalid_tss_c_handler 87 | 88 | .globl segment_not_present_handler 89 | segment_not_present_handler: 90 | wrapper_error_code segment_not_present_c_handler 91 | 92 | .globl ss_fault_handler 93 | ss_fault_handler: 94 | wrapper_error_code ss_fault_c_handler 95 | 96 | .globl gp_fault_handler 97 | gp_fault_handler: 98 | wrapper_error_code gp_fault_c_handler 99 | 100 | .globl math_fault_handler 101 | math_fault_handler: 102 | wrapper math_fault_c_handler 103 | 104 | .globl align_fault_handler 105 | align_fault_handler: 106 | wrapper_error_code align_fault_c_handler 107 | 108 | .globl machine_check_fault_handler 109 | machine_check_fault_handler: 110 | wrapper machine_check_fault_c_handler 111 | 112 | .globl simd_fault_handler 113 | simd_fault_handler: 114 | wrapper simd_fault_c_handler 115 | 116 | -------------------------------------------------------------------------------- /kern/handlers/mem_mgmt_handlers.c: -------------------------------------------------------------------------------- 1 | /** @file misc_handlers.c 2 | * @brief implements miscellaneous syscall handlers 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | * @bug No known bugs. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /** @brief Implements the new_pages system call 15 | * @param base The virtual address of the base for the new page 16 | * @param len The length of the requested pages 17 | * @return 0 on success, negative integer code on failure 18 | */ 19 | int syscall_new_pages_c_handler(void *base, int len){ 20 | /* check for invalid base address */ 21 | if ((uint32_t)base < USER_MEM_START) return -1; 22 | /* check for non-positive and non-page aligned lengths */ 23 | if (len <= 0 || (len % PAGE_SIZE) != 0) return -1; 24 | 25 | /* Get current running pcb */ 26 | pcb_t *cur_pcb; 27 | if(scheduler_get_current_pcb(&sched, &cur_pcb) < 0) { 28 | return -2; 29 | } 30 | 31 | page_directory_t *pd = &(cur_pcb->pd); 32 | 33 | if (vmm_new_user_page(pd, (uint32_t)base, (uint32_t)(len/PAGE_SIZE)) < 0){ 34 | return -2; 35 | } 36 | return 0; 37 | } 38 | 39 | /** @brief Implements the remove_pages system call 40 | * @param base The virtual address of the base for the page to remove 41 | * @return 0 on success, negative integer code on failure 42 | * */ 43 | int syscall_remove_pages_c_handler(void *base){ 44 | /* Get current running pcb */ 45 | pcb_t *cur_pcb; 46 | if(scheduler_get_current_pcb(&sched, &cur_pcb) < 0) { 47 | return -2; 48 | } 49 | page_directory_t *pd = &(cur_pcb->pd); 50 | if (vmm_remove_user_page(pd, (uint32_t)base) < 0) return -1; 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /kern/handlers/misc_handlers.c: -------------------------------------------------------------------------------- 1 | /** @file misc_handlers.c 2 | * @brief implements miscellaneous syscall handlers 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | * @bug No known bugs. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | /** @brief Implements the halt system call 14 | * 15 | * For non simics this does nothing, the halt comes after in the assembly 16 | * wrapper 17 | * 18 | * @return Does not return 19 | */ 20 | void syscall_halt_c_handler(){ 21 | /* ends simics simulation */ 22 | sim_halt(); 23 | } 24 | 25 | /** @brief Implements the readfile system call 26 | * @param filename The filename to read 27 | * @param buf The buffer to read into 28 | * @param count The number of bytes to read 29 | * @param offset The offset into the file 30 | * @return 0 on success, negative integer code on failure 31 | */ 32 | int syscall_readfile_c_handler(char* filename, char *buf, int count, int offset) { 33 | 34 | /* Check if file name is NULL */ 35 | if (filename == NULL) return -1; 36 | 37 | /* Check if count and offset are positive */ 38 | if (count < 0 || offset < 0) return -2; 39 | 40 | /* Get data from appropriate files */ 41 | return getbytes(filename, offset, count, buf); 42 | } 43 | 44 | /** @brief Implements the misbehave system call 45 | * 46 | * Does nothing lol. 47 | * 48 | * @param mode The mode to switch to 49 | * @return Void 50 | */ 51 | void syscall_misbehave_c_handler(int mode){ 52 | return; 53 | } 54 | -------------------------------------------------------------------------------- /kern/handlers/peripheral_handler_wrappers.S: -------------------------------------------------------------------------------- 1 | 2 | 3 | .globl keyboard_handler 4 | keyboard_handler: 5 | // Save Registers 6 | subl $4, %esp /* skip error code */ 7 | pusha 8 | push %gs 9 | push %fs 10 | push %es 11 | push %ds 12 | // Call C handler 13 | call c_keyboard_handler 14 | // Restore Registers 15 | pop %ds 16 | pop %es 17 | pop %fs 18 | pop %gs 19 | popa 20 | addl $4, %esp /* skip error code */ 21 | iret 22 | 23 | .globl timer_handler 24 | timer_handler: 25 | // Save Register Context 26 | subl $4, %esp /* skip error code */ 27 | pusha 28 | push %gs 29 | push %fs 30 | push %es 31 | push %ds 32 | // Pass args 33 | push %esp 34 | // Call C handler 35 | call c_timer_handler 36 | push %eax 37 | call restore_context 38 | /* SHOULD NEVER RETURN */ 39 | -------------------------------------------------------------------------------- /kern/handlers/peripheral_handlers.c: -------------------------------------------------------------------------------- 1 | /** @file peripheral_handlers.c 2 | * @brief Implements handlers for peripheral hardware 3 | * @author Christopher Wei (cjwei) 4 | * @author Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /* access to buffer */ 16 | #include 17 | 18 | /* KEYBOARD_PORT define */ 19 | #include 20 | #include 21 | 22 | /** @brief Implements the timer handler 23 | * @param old_esp The stack pointer of the thread that was just running 24 | * @return The stack pointer of the thread that was selected to run by the 25 | * scheduler 26 | */ 27 | uint32_t c_timer_handler(uint32_t old_esp) { 28 | sched.num_ticks++; 29 | 30 | /* Wake up any sleeping threads */ 31 | scheduler_wakeup(&sched); 32 | 33 | /* Context switch into scheduler determined tcb, 34 | * possibly into a thread that was just woken up */ 35 | uint32_t new_esp = context_switch(old_esp, -1); 36 | 37 | outb(INT_CTL_PORT, INT_ACK_CURRENT); 38 | return new_esp; 39 | } 40 | 41 | /** @brief Implements the keyboard handler 42 | * 43 | * Reads a scancode from the keyboard port and processes it into a character 44 | * 45 | * @return Void 46 | */ 47 | void c_keyboard_handler(){ 48 | unsigned char aug_char = inb(KEYBOARD_PORT); 49 | outb(INT_CTL_PORT, INT_ACK_CURRENT); 50 | 51 | kh_type proc_char = process_scancode((uint32_t)aug_char); 52 | if (KH_HASDATA(proc_char) && KH_ISMAKE(proc_char)){ 53 | if (keyboard_write(&keyboard, KH_GETCHAR(proc_char)) < 0) 54 | lprintf("keyboard buffer overflowed *beep*"); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /kern/inc/circ_buffer.h: -------------------------------------------------------------------------------- 1 | /** @file circ_buffer.h 2 | * @brief Defines interface for a circular buffer 3 | * @author Christopher Wei (cjwei) 4 | * @author Aatish Nayak (aatishn) 5 | 6 | * @bug No known bugs 7 | */ 8 | 9 | 10 | #ifndef _CIRC_BUFFER_H_ 11 | #define _CIRC_BUFFER_H_ 12 | 13 | #include 14 | 15 | typedef struct circular_buffer{ 16 | /** @brief the read index of the buffer */ 17 | uint32_t i_r; 18 | /** @brief the write index of the buffer */ 19 | uint32_t i_w; 20 | /** @brief the internal buffer */ 21 | void **buf; 22 | /** @brief the length of the buffer */ 23 | uint32_t len; 24 | /** @brief the number of elements in the buffer */ 25 | uint32_t n; 26 | } circ_buf_t; 27 | 28 | int circ_buf_init(circ_buf_t *circ_buf, uint32_t len); 29 | void circ_buf_destroy(circ_buf_t *circ_buf); 30 | int circ_buf_write(circ_buf_t *circ_buf, void *v); 31 | int circ_buf_read(circ_buf_t *circ_buf, void **v); 32 | int circ_buf_size(circ_buf_t *circ_buf, uint32_t *len); 33 | int circ_buf_count(circ_buf_t *circ_buf, uint32_t *n); 34 | int circ_buf_delete_front(circ_buf_t *circ_buf); 35 | #endif /* _CIRC_BUFFER_H_ */ 36 | -------------------------------------------------------------------------------- /kern/inc/console.h: -------------------------------------------------------------------------------- 1 | /** @file console.h 2 | * @brief Function prototypes for the console driver. 3 | * 4 | * This contains the prototypes and global variables for the console 5 | * driver 6 | * 7 | * @author Michael Berman (mberman) 8 | * @bug No known bugs. 9 | */ 10 | 11 | #ifndef _CONSOLE_H 12 | #define _CONSOLE_H 13 | 14 | #include 15 | 16 | /** @brief Prints character ch at the current location 17 | * of the cursor. 18 | * 19 | * If the character is a newline ('\n'), the cursor is 20 | * be moved to the beginning of the next line (scrolling if necessary). If 21 | * the character is a carriage return ('\r'), the cursor 22 | * is immediately reset to the beginning of the current 23 | * line, causing any future output to overwrite any existing 24 | * output on the line. If backsapce ('\b') is encountered, 25 | * the previous character is erased. See the main console.c description 26 | * for more backspace behavior. 27 | * 28 | * @param ch the character to print 29 | * @return The input character 30 | */ 31 | int putbyte( char ch ); 32 | 33 | /** @brief Prints the string s, starting at the current 34 | * location of the cursor. 35 | * 36 | * If the string is longer than the current line, the 37 | * string fills up the current line and then 38 | * continues on the next line. If the string exceeds 39 | * available space on the entire console, the screen 40 | * scrolls up one line, and then the string 41 | * continues on the new line. If '\n', '\r', and '\b' are 42 | * encountered within the string, they are handled 43 | * as per putbyte. If len is not a positive integer or s 44 | * is null, the function has no effect. 45 | * 46 | * @param s The string to be printed. 47 | * @param len The length of the string s. 48 | * @return Void. 49 | */ 50 | void putbytes(const char* s, int len); 51 | 52 | /** @brief Changes the foreground and background color 53 | * of future characters printed on the console. 54 | * 55 | * If the color code is invalid, the function has no effect. 56 | * 57 | * @param color The new color code. 58 | * @return 0 on success or integer error code less than 0 if 59 | * color code is invalid. 60 | */ 61 | int set_term_color(int color); 62 | 63 | /** @brief Writes the current foreground and background 64 | * color of characters printed on the console 65 | * into the argument color. 66 | * @param color The address to which the current color 67 | * information will be written. 68 | * @return Void. 69 | */ 70 | void get_term_color(int* color); 71 | 72 | /** @brief Sets the position of the cursor to the 73 | * position (row, col). 74 | * 75 | * Subsequent calls to putbytes should cause the console 76 | * output to begin at the new position. If the cursor is 77 | * currently hidden, a call to set_cursor() does not show 78 | * the cursor. 79 | * 80 | * @param row The new row for the cursor. 81 | * @param col The new column for the cursor. 82 | * @return 0 on success or integer error code less than 0 if 83 | * cursor location is invalid. 84 | */ 85 | int set_cursor(int row, int col); 86 | 87 | /** @brief Writes the current position of the cursor 88 | * into the arguments row and col. 89 | * @param row The address to which the current cursor 90 | * row will be written. 91 | * @param col The address to which the current cursor 92 | * column will be written. 93 | * @return 0 on success, negative integer code on failure. 94 | */ 95 | int get_cursor(int* row, int* col); 96 | 97 | /** @brief Hides the cursor. 98 | * 99 | * Subsequent calls to putbytes do not cause the 100 | * cursor to show again. 101 | * 102 | * @return Void. 103 | */ 104 | void hide_cursor(); 105 | 106 | /** @brief Shows the cursor. 107 | * 108 | * If the cursor is already shown, the function has no effect. 109 | * 110 | * @return Void. 111 | */ 112 | void show_cursor(); 113 | 114 | /** @brief Clears the entire console. 115 | * 116 | * The cursor is reset to the first row and column 117 | * 118 | * @return Void. 119 | */ 120 | void clear_console(); 121 | 122 | /** @brief Prints character ch with the specified color 123 | * at position (row, col). 124 | * 125 | * If any argument is invalid, the function has no effect. 126 | * 127 | * @param row The row in which to display the character. 128 | * @param col The column in which to display the character. 129 | * @param ch The character to display. 130 | * @param color The color to use to display the character. 131 | * @return Void. 132 | */ 133 | void draw_char(int row, int col, int ch, int color); 134 | 135 | /** @brief Returns the character displayed at position (row, col). 136 | * @param row Row of the character. 137 | * @param col Column of the character. 138 | * @return The character at (row, col). 139 | */ 140 | char get_char(int row, int col); 141 | 142 | #endif /* _CONSOLE_H */ 143 | -------------------------------------------------------------------------------- /kern/inc/constants.h: -------------------------------------------------------------------------------- 1 | /** @file constants.h 2 | * @brief some constants about bits and bytes 3 | * @author Christopher Wei (cjwei) 4 | */ 5 | 6 | #ifndef _CONSTANTS_H_ 7 | #define _CONSTANTS_H_ 8 | 9 | 10 | /** @brief lower byte mask */ 11 | #define C_BYTE_MASK 0x000000FF 12 | /** @brief lower 2 byte mask */ 13 | #define C_L2B_MASK 0x0000FFFF 14 | /** @brief upper 2 byte mask */ 15 | #define C_U2B_MASK 0xFFFF0000 16 | /** @brief MSB 20 bit mask */ 17 | #define MSB_20_MASK 0xFFFFF000 18 | /** @brief LSB 12 bit mask */ 19 | #define LSB_12_MASK 0x00000FFF 20 | /** @brief number of bits in a byte */ 21 | #define C_BYTE_WIDTH 8 22 | /** @brief number of bits in 2 bytes */ 23 | #define C_2BYTE_WIDTH 16 24 | 25 | /* Flag Designations */ 26 | /** @brief denotes a set flag */ 27 | #define SET 1 28 | /** @brief denotes an unset flag */ 29 | #define UNSET 0 30 | /** @brief denotes a arbitrary flag */ 31 | #define DONT_CARE 0 32 | 33 | #endif /* _CONSTANTS_H_ */ 34 | -------------------------------------------------------------------------------- /kern/inc/debug.h: -------------------------------------------------------------------------------- 1 | /** @file debug.h 2 | * @brief specifies debug routines for the kernel 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | * @bug No known bugs. 7 | */ 8 | #ifndef _DEBUG_H_ 9 | #define _DEBUG_H_ 10 | 11 | #include 12 | #include 13 | 14 | //#define DEBUG 15 | 16 | #ifdef DEBUG 17 | #define DEBUG_PRINT(...) do{ lprintf(__VA_ARGS__ ); } while( false ) 18 | #else 19 | #define DEBUG_PRINT(...) do{ } while ( false ) 20 | #endif 21 | 22 | void print_page_directory(page_directory_t *pd, int s, int l, int v); 23 | void print_context(unsigned int *stack); 24 | void print_control_regs(void); 25 | void translate_addr(page_directory_t *pd, uint32_t addr); 26 | void print_elf(simple_elf_t *elf); 27 | 28 | #endif /* DEBUG_H_ */ 29 | -------------------------------------------------------------------------------- /kern/inc/dispatcher.h: -------------------------------------------------------------------------------- 1 | /** @file dispatcher.h 2 | * @brief defines the interface for the dispatcher 3 | * @author Christopher Wei (cjwei) 4 | * @author Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | 9 | #ifndef _DISPATCHER_H_ 10 | #define _DISPATCHER_H_ 11 | 12 | #include 13 | 14 | void initial_mode_switch(tcb_t *tcb); 15 | void initial_mode_switch_asm(tcb_t tcb); 16 | void save_context(tcb_t *tcb); 17 | 18 | void restore_context(uint32_t new_esp); 19 | 20 | uint32_t context_switch_safe(uint32_t old_esp, int target_tid); 21 | uint32_t context_switch(uint32_t old_esp, int target_tid); 22 | 23 | 24 | #endif /* _DISPATCHER_H_ */ 25 | 26 | -------------------------------------------------------------------------------- /kern/inc/frame_manager.h: -------------------------------------------------------------------------------- 1 | /** @file frame_manager.h 2 | * @brief interface for a vm frame manager 3 | * 4 | * @author Aatish Nayak (aatishn) 5 | * @author Christopher Wei (cjwei) 6 | * @bug No known bugs. 7 | */ 8 | 9 | #ifndef _FRAME_MANAGER_H_ 10 | #define _FRAME_MANAGER_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | /** @brief defines a frame manager struct */ 17 | typedef struct frame_manager{ 18 | /** @brief internal mutex */ 19 | mutex_t m; 20 | /** @brief hash table for allocated frames */ 21 | ht_t *allocated; 22 | /** @brief hash table for deallocated frames */ 23 | ht_t *deallocated; 24 | /** @brief hash table for parent frames */ 25 | ht_t *parents; 26 | /** @brief array of linked lists that store deallocated frames of various 27 | * sizes */ 28 | ll_t **frame_bins; 29 | /** @brief length of frame_bins */ 30 | uint32_t num_bins; 31 | } frame_manager_t; 32 | 33 | int fm_alloc(frame_manager_t *fm, uint32_t num_pages, uint32_t *addr); 34 | int fm_dealloc(frame_manager_t *fm, uint32_t addr); 35 | int fm_init(frame_manager_t *fm, uint32_t num_bins); 36 | void fm_print(frame_manager_t *fm); 37 | 38 | #endif /* _FRAME_MANAGER_H_ */ 39 | -------------------------------------------------------------------------------- /kern/inc/ht.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ht.h 3 | * 4 | * @brief Interface to a generic hash table with seperate chaining 5 | * 6 | * @author Aatish Nayak (aatishn) 7 | * @bug No known bugs 8 | */ 9 | 10 | #ifndef _HT_H_ 11 | #define _HT_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /** 19 | * @brief typedef of a key 20 | */ 21 | typedef int key_t; 22 | 23 | /** 24 | * @brief defines an entry into a hash table 25 | */ 26 | typedef struct ht_entry { 27 | /** @brief key to the entry */ 28 | key_t key; 29 | /** @brief value stored */ 30 | void *val; 31 | } ht_entry_t; 32 | 33 | typedef struct ht { 34 | /** @brief number of entries in hash table */ 35 | uint32_t size; 36 | /** @brief number of buckets in hash table */ 37 | uint32_t max_size; 38 | /** @brief hashing function used */ 39 | int (*hash)(key_t key); 40 | /** @brief array of buckets */ 41 | ll_t *arr; 42 | } ht_t; 43 | 44 | int ht_init(ht_t *t, uint32_t max_size, int (*hash)(key_t key)); 45 | int ht_get(ht_t *t, key_t key, void **valp); 46 | int ht_remove(ht_t *t, key_t key, void **valp, circ_buf_t *addrs_to_free); 47 | int ht_put(ht_t *t, key_t key, void *val); 48 | int ht_put_entry(ht_t *t, ht_entry_t *entry, ll_node_t *entry_node); 49 | void ht_destroy(ht_t *t); 50 | 51 | #endif /* _HT_H_ */ 52 | 53 | -------------------------------------------------------------------------------- /kern/inc/idt_handlers.h: -------------------------------------------------------------------------------- 1 | /** @file idt_handlers.h 2 | * @brief specifies handlers for system exceptions 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | * @bug No known bugs. 7 | */ 8 | #ifndef _IDT_HANDLERS_H_ 9 | #define _IDT_HANDLERS_H_ 10 | 11 | #include 12 | 13 | /* Exception Handlers */ 14 | 15 | /** @brief assembly wrapper for page fault handler */ 16 | void page_fault_handler(void); 17 | /** @brief assembly wrapper for double fault handler */ 18 | void double_fault_handler(void); 19 | /** @brief assembly wrapper for division error handler */ 20 | void division_error_handler(void); 21 | /** @brief assembly wrapper for debug exception handler */ 22 | void debug_exception_handler(void); 23 | /** @brief assembly wrapper for breakpoint handler */ 24 | void breakpoint_handler(void); 25 | /** @brief assembly wrapper for overflow handler */ 26 | void overflow_handler(void); 27 | /** @brief assembly wrapper for bound range handler */ 28 | void bound_range_handler(void); 29 | /** @brief assembly wrapper for undef op handler */ 30 | void undef_op_handler(void); 31 | /** @brief assembly wrapper for no math handler */ 32 | void no_math_handler(void); 33 | /** @brief assembly wrapper for cso handler */ 34 | void coprocessor_segment_overrun_handler(void); 35 | /** @brief assembly wrapper for invalid tss handler */ 36 | void invalid_tss_handler(void); 37 | /** @brief assembly wrapper for segment not present handler */ 38 | void segment_not_present_handler(void); 39 | /** @brief assembly wrapper for gp fault handler */ 40 | void gp_fault_handler(void); 41 | /** @brief assembly wrapper for math fault handler */ 42 | void math_fault_handler(void); 43 | /** @brief assembly wrapper for align fault handler */ 44 | void align_fault_handler(void); 45 | /** @brief assembly wrapper for machine check fault handler */ 46 | void machine_check_fault_handler(void); 47 | /** @brief assembly wrapper for simd fault handler */ 48 | void simd_fault_handler(void); 49 | 50 | 51 | /* Syscall thread management handlers */ 52 | /** @brief syscall wrapper for gettid */ 53 | int syscall_gettid_handler(void); 54 | /** @brief syscall wrapper for yield */ 55 | int syscall_yield_handler(int); 56 | /** @brief syscall wrapper for deschedule */ 57 | int syscall_deschedule_handler(int *); 58 | /** @brief syscall wrapper for make runnable*/ 59 | int syscall_make_runnable_handler(int); 60 | /** @brief syscall wrapper for get ticks*/ 61 | int syscall_get_ticks_handler(void); 62 | /** @brief syscall wrapper for sleep */ 63 | int syscall_sleep_handler(int); 64 | /** @brief syscall wrapper for swexn */ 65 | int syscall_swexn_handler(void *, void (*)(void *, ureg_t *), void *, ureg_t *); 66 | 67 | /* Syscall life cycle handlers */ 68 | 69 | /** @brief syscall wrapper for fork*/ 70 | int syscall_fork_handler(void); 71 | /** @brief syscall wrapper for vanish*/ 72 | void syscall_vanish_handler(void); 73 | /** @brief syscall wrapper for wait*/ 74 | int syscall_wait_handler(int *status_ptr); 75 | /** @brief syscall wrapper for set status */ 76 | void syscall_set_status_handler(int); 77 | /** @brief syscall wrapper for exec */ 78 | int syscall_exec_handler(char *execname, char **argvec); 79 | /** @brief syscall wrapper for thread fork */ 80 | int syscall_thread_fork_handler(void); 81 | 82 | /* Console IO handlers */ 83 | 84 | /** @brief syscall wrapper for readline */ 85 | int syscall_readline_handler(int len, char *buf); 86 | /** @brief syscall wrapper for print */ 87 | int syscall_print_handler(int len, char *buf); 88 | /** @brief syscall wrapper for set term color */ 89 | int syscall_set_term_color_handler(int color); 90 | /** @brief syscall wrapper for set cursor pos */ 91 | int syscall_set_cursor_pos_handler(int row, int col); 92 | /** @brief syscall wrapper for get cursor pos */ 93 | int syscall_get_cursor_pos_handler(int *row, int *col); 94 | 95 | /* Mem mgmt handlers*/ 96 | 97 | /** @brief syscall wrapper for new pages */ 98 | int syscall_new_pages_handler(void *base, int len); 99 | /** @brief syscall wrapper for remove pages */ 100 | int syscall_remove_pages_handler(void *base); 101 | 102 | /* Misc handlers */ 103 | 104 | /** @brief syscall wrapper for halt */ 105 | void syscall_halt_handler(void); 106 | /** @brief syscall wrapper for readfile */ 107 | int syscall_readfile_handler(char *filename, char *buf, int count, int offset); 108 | /** @brief syscall wrapper for misbehave */ 109 | void syscall_misbehave_handler(int mode); 110 | 111 | /* Hardware handlers */ 112 | 113 | /** @brief peripheral wrapper for timer */ 114 | void timer_handler(void); 115 | /** @brief peripheral wrapper for keyboard */ 116 | void keyboard_handler(void); 117 | 118 | #endif /* IDT_HANDLERS_H_ */ 119 | -------------------------------------------------------------------------------- /kern/inc/install_handlers.h: -------------------------------------------------------------------------------- 1 | /** @file install_handlers.h 2 | * @brief specifications for handler install functions 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | * @bug No known bugs. 7 | */ 8 | 9 | #ifndef _INSTALL_HANDLERS_H_ 10 | #define _INSTALL_HANDLERS_H_ 11 | 12 | 13 | int install_syscall_handlers(void); 14 | 15 | int install_peripheral_handlers(void); 16 | 17 | int install_exception_handlers(void); 18 | 19 | #endif /* _INSTALL_HANDLERS_H_ */ 20 | -------------------------------------------------------------------------------- /kern/inc/kern_internals.h: -------------------------------------------------------------------------------- 1 | /** @file kern_internals.h 2 | * @brief Specifies the global variables shared across the kernel 3 | * 4 | * @author Aatish Nayak (aatishn) 5 | * @author Christopher Wei (cjwei) 6 | * @bug No known bugs. 7 | */ 8 | 9 | #ifndef _KERN_INTERNALS_H_ 10 | #define _KERN_INTERNALS_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /** 19 | * @brief Extern of physical memory manager for the kernel 20 | */ 21 | extern frame_manager_t fm; 22 | 23 | /** 24 | * @brief Extern of global scheduler that manages all kernel PCBs and TCBs 25 | */ 26 | extern scheduler_t sched; 27 | 28 | /** 29 | * @brief Global mutex for the console 30 | */ 31 | extern mutex_t console_lock; 32 | 33 | /** 34 | * @brief Global keyboard buffer 35 | */ 36 | extern keyboard_t keyboard; 37 | /** 38 | * @brief atomically exchanges val into lock and returns previous value of lock 39 | */ 40 | int xchng(int* lock, int val); 41 | 42 | /** 43 | * @brief lock to protect heap (used in malloc, free, etc) 44 | * 45 | */ 46 | extern mutex_t heap_lock; 47 | 48 | /** 49 | * @brief Lock to protect scheduler data structures 50 | * 51 | */ 52 | extern sched_mutex_t sched_lock; 53 | 54 | #endif /* _KERN_INTERNALS_H_ */ 55 | 56 | 57 | -------------------------------------------------------------------------------- /kern/inc/keyboard.h: -------------------------------------------------------------------------------- 1 | /** @file keyboard.h 2 | * @brief Defines interface for a keyboard manager 3 | * @author Christopher Wei (cjwei) 4 | * @bug No known bugs 5 | */ 6 | #ifndef _KEYBOARD_H_ 7 | #define _KEYBOARD_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /** @brief defines the keyboard struct */ 15 | typedef struct keyboard { 16 | /** @brief the character buffer to be stored into */ 17 | circ_buf_t *buf; 18 | /** @brief mutex to protect buf */ 19 | mutex_t m; 20 | /** @brief semaphore to keep track of avaliable resources 21 | * each resource being 1 full line ended by newline */ 22 | sem_t sem; 23 | } keyboard_t; 24 | 25 | int keyboard_init(keyboard_t *k, uint32_t len); 26 | void keyboard_destroy(keyboard_t *k); 27 | int keyboard_write(keyboard_t *k, uint32_t val); 28 | int keyboard_read(keyboard_t *k, int len, char *buf); 29 | int keyboard_buffer_size(keyboard_t *k, uint32_t *len); 30 | #endif /* _KEYBOARD_H_ */ 31 | -------------------------------------------------------------------------------- /kern/inc/ll.h: -------------------------------------------------------------------------------- 1 | /** @file ll.h 2 | * @brief Defines interface for linked list 3 | * @author Christopher Wei (cjwei) 4 | * @author Aatish Nayak (aatishn) 5 | 6 | * @bug No known bugs 7 | */ 8 | 9 | 10 | #ifndef _LL_H_ 11 | #define _LL_H_ 12 | 13 | #include 14 | 15 | /** 16 | * @brief Struct representing a doubly linked linked list node 17 | */ 18 | typedef struct ll_node { 19 | /** @brief Data the ll_node_t holds */ 20 | void *e; 21 | 22 | /** @brief Pointer pointing to next node */ 23 | struct ll_node *next; 24 | 25 | /** @brief Pointer pointing to prev node */ 26 | struct ll_node *prev; 27 | 28 | } ll_node_t; 29 | 30 | int ll_node_init(ll_node_t *node, void *data); 31 | int ll_node_get_data(ll_node_t *node, void **datap); 32 | 33 | /** 34 | * @brief Struct representing a linked list 35 | */ 36 | typedef struct ll { 37 | 38 | /** @brief Pointer to head of the linked list */ 39 | ll_node_t *head; 40 | 41 | /** @brief Pointer to tail of the linked list */ 42 | ll_node_t *tail; 43 | 44 | /** @brief Size of the linked list */ 45 | unsigned int size; 46 | } ll_t; 47 | 48 | int ll_init(ll_t *ll); 49 | 50 | int ll_add_last(ll_t *ll, void *value); 51 | int ll_add_first(ll_t *ll, void *value); 52 | int ll_remove_last(ll_t *ll, void **value_ptr); 53 | int ll_remove_first(ll_t *ll, void **value_ptr); 54 | 55 | int ll_peek(ll_t *ll, void **value_ptr); 56 | int ll_rotate(ll_t *ll); 57 | 58 | int ll_link_node_first(ll_t *ll, ll_node_t *node); 59 | int ll_link_node_last(ll_t *ll, ll_node_t *node); 60 | int ll_link_node_sorted(ll_t *ll, ll_node_t *new_node, 61 | int (*cmp)(void *, void *)); 62 | int ll_unlink_node(ll_t *ll, ll_node_t *node); 63 | 64 | int ll_head(ll_t *ll, ll_node_t **node); 65 | int ll_tail(ll_t *ll, ll_node_t **node); 66 | 67 | int ll_find(ll_t *ll, void *(*func)(void*), void *c_val, void **val_ptr); 68 | int ll_remove(ll_t *ll, void *(*func)(void*), void *c_val, 69 | void **valp, circ_buf_t *addrs_to_free); 70 | 71 | int ll_size(ll_t *ll); 72 | void ll_destroy(ll_t *ll); 73 | 74 | void ll_foreach(ll_t *ll, void (*f)(void *)); 75 | 76 | 77 | #endif /* _LL_H_ */ 78 | -------------------------------------------------------------------------------- /kern/inc/loader.h: -------------------------------------------------------------------------------- 1 | /* The 15-410 kernel project 2 | * 3 | * loader.h 4 | * 5 | * Structure definitions, #defines, and function prototypes 6 | * for the user process loader. 7 | */ 8 | 9 | #ifndef _LOADER_H 10 | #define _LOADER_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define USER_STACK_TOP 0xfffffff0 18 | 19 | #define USER_STACK_BOTTOM 0xffffe000 20 | 21 | #define USER_STACK_SIZE (USER_STACK_TOP - USER_STACK_BOTTOM) 22 | 23 | /* --- Prototypes --- */ 24 | 25 | int getbytes( const char *filename, int offset, int size, char *buf ); 26 | 27 | int load_elf_sections(simple_elf_t *elf, pcb_t *pcb); 28 | int load_elf_exists(const char *filename); 29 | int load_user_stack(pcb_t *pcb); 30 | 31 | #endif /* _LOADER_H */ 32 | -------------------------------------------------------------------------------- /kern/inc/mem_section.h: -------------------------------------------------------------------------------- 1 | /** @file mem_section.h 2 | * @brief interface for a vm memory section 3 | * 4 | * @author Aatish Nayak (aatishn) 5 | * @author Christopher Wei (cjwei) 6 | * @bug No known bugs. 7 | */ 8 | 9 | #ifndef _MEM_SECTION_H_ 10 | #define _MEM_SECTION_H_ 11 | 12 | #include 13 | 14 | /** @brief defines a memory section struct */ 15 | typedef struct mem_section_t { 16 | /** @brief the starting virtual address */ 17 | unsigned long v_addr_start; 18 | /** @brief the length of the memory sectio n*/ 19 | unsigned long len; 20 | /** @brief the page directory flags */ 21 | uint32_t pde_f; 22 | /** @brief the page table flags */ 23 | uint32_t pte_f; 24 | } mem_section_t; 25 | 26 | int ms_init(mem_section_t *ms, uint32_t addr, 27 | uint32_t len, uint32_t pde_f, uint32_t pte_f); 28 | int ms_get_bounding_addr(mem_section_t *secs, uint32_t num_secs, 29 | uint32_t *addr_low, uint32_t *addr_high); 30 | int ms_get_bounding_section(mem_section_t *secs, uint32_t num_secs, 31 | uint32_t addr_low, uint32_t addr_high, mem_section_t **result); 32 | #endif /* _MEM_SECTION_H_ */ 33 | -------------------------------------------------------------------------------- /kern/inc/mutex.h: -------------------------------------------------------------------------------- 1 | /** @file mutex.h 2 | * @brief This file defines mutexes. 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | #ifndef _MUTEX_H 8 | #define _MUTEX_H 9 | 10 | /** @brief Defines a mutex struct and type */ 11 | typedef struct mutex { 12 | /** @brief Represents whether or not mutex is free or taken */ 13 | int lock; 14 | /** @brief Tid of whoever currently holds the mutex */ 15 | int owner; 16 | } mutex_t; 17 | 18 | int mutex_init( mutex_t *mp ); 19 | void mutex_destroy( mutex_t *mp ); 20 | void mutex_lock( mutex_t *mp ); 21 | void mutex_unlock( mutex_t *mp ); 22 | 23 | #endif /* _MUTEX_H */ 24 | -------------------------------------------------------------------------------- /kern/inc/page_directory.h: -------------------------------------------------------------------------------- 1 | /** @file page_directory.h 2 | * @brief Specifies interface for page directory 3 | * 4 | * @author Aatish Nayak (aatishn) 5 | * @author Christopher Wei (cjwei) 6 | * @bug No known bugs. 7 | */ 8 | 9 | #ifndef _PAGE_DIRECTORY_H_ 10 | #define _PAGE_DIRECTORY_H_ 11 | 12 | /* PAGE SIZE */ 13 | #include 14 | /* Constants */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /** @brief the bit flag representing the present flag */ 23 | #define PRESENT_FLAG_BIT 0 24 | /** @brief the bit flag representing the read write flag */ 25 | #define RW_FLAG_BIT 1 26 | /** @brief the bit flag representing the mode flag */ 27 | #define MODE_FLAG_BIT 2 28 | /** @brief the write through flag bit */ 29 | #define WRITE_THROUGH_FLAG_BIT 3 30 | /** @brief the global flag bit */ 31 | #define GLOBAL_FLAG_BIT 8 32 | 33 | /* custom non-x86 flag bits */ 34 | 35 | /** @brief defines the flag bit that we use to denote the beginning of a user 36 | * allocated memory space */ 37 | #define USER_START_FLAG_BIT 9 38 | 39 | /** @brief defines the flag bit that we use to denote the end of a user 40 | * allocated memory space */ 41 | #define USER_END_FLAG_BIT 10 42 | 43 | /* p - SET implies page is present, UNSET implies page is unpresent 44 | * rw - SET implies page is read writable, UNSET implies read only 45 | * md - SET implies user, UNSET implies supervisor 46 | * glb - SET implies global, UNSET implies local 47 | */ 48 | /** @brief creates the flags with the given parameters */ 49 | #define NEW_FLAGS(p,rw,md,glb) ((p << PRESENT_FLAG_BIT) | (rw << RW_FLAG_BIT)\ 50 | | (md << MODE_FLAG_BIT) | (glb << GLOBAL_FLAG_BIT)) 51 | 52 | /** @brief adds the user_start flag to a set of flags */ 53 | #define ADD_USER_START_FLAG(flags) (flags | (SET << USER_START_FLAG_BIT)) 54 | /** @brief adds the user_end flag to a set of flags */ 55 | #define ADD_USER_END_FLAG(flags) (flags | (SET << USER_END_FLAG_BIT)) 56 | 57 | /** @brief checks if a page table entry is user start */ 58 | #define IS_USER_START(pte) ((pte >> USER_START_FLAG_BIT) & 1) 59 | /** @brief checks if a page table entry is user end */ 60 | #define IS_USER_END(pte) ((pte >> USER_END_FLAG_BIT) & 1) 61 | 62 | /** @brief defines a user read only flags */ 63 | #define USER_RO NEW_FLAGS(SET, UNSET, SET, UNSET) 64 | /** @brief defines a user read write flags */ 65 | #define USER_WR NEW_FLAGS(SET, SET, SET, UNSET) 66 | 67 | 68 | /** @brief defines the default page directory entry flags */ 69 | #define PDE_FLAG_DEFAULT (NEW_FLAGS(SET, UNSET, SET, DONT_CARE)) 70 | /* @brief defines the default page table entry flags */ 71 | #define PTE_FLAG_DEFAULT (NEW_FLAGS(SET, UNSET, SET, UNSET)) 72 | 73 | /** @brief defines the size of a page directory */ 74 | #define PD_SIZE PAGE_SIZE 75 | /** @brief defines the number of entries in a page directory */ 76 | #define PD_NUM_ENTRIES (PD_SIZE / sizeof(uint32_t)) 77 | 78 | /** @brief defines the size of a page table */ 79 | #define PT_SIZE PAGE_SIZE 80 | /** @brief defines the number of entries in a page table */ 81 | #define PT_NUM_ENTRIES (PT_SIZE / sizeof(uint32_t)) 82 | 83 | /** @brief checks whether an address is page aligned */ 84 | #define IS_PAGE_ALIGNED(a) (a % PAGE_SIZE == 0) 85 | 86 | /** @brief divides and rounds up */ 87 | #define DIV_ROUND_UP(num, den) ((num + den -1) / den) 88 | /** @brief page aligns an address upwards */ 89 | #define PAGE_ALIGN_UP(addr) (PAGE_SIZE * DIV_ROUND_UP(addr, PAGE_SIZE)) 90 | /** @brief page aligns an address downwards */ 91 | #define PAGE_ALIGN_DOWN(addr) (PAGE_SIZE * (addr / PAGE_SIZE)) 92 | 93 | /** @brief adds flags to an entry */ 94 | #define ADD_FLAGS(v,f) ((uint32_t)v | f) 95 | /** @brief remove flags from an entry */ 96 | #define REMOVE_FLAGS(v) ((uint32_t)v & ~0xFFF) 97 | /** @brief gets the flags from an entry */ 98 | #define EXTRACT_FLAGS(v) ((uint32_t)v & 0xFFF) 99 | 100 | /** @brief defines user privilege flag */ 101 | #define PRIV_USER 1 102 | /** @brief defines kernel privilege flag */ 103 | #define PRIV_KERNEL 0 104 | /** @brief defines read only flag */ 105 | #define ACC_RO 0 106 | /** @brief defines access for read write */ 107 | #define ACC_RW 1 108 | 109 | /** @brief defines a page directory struct */ 110 | typedef struct page_directory { 111 | /** @brief the internal directory */ 112 | uint32_t *directory; 113 | /** @brief the number of pages in the directory */ 114 | uint32_t num_pages; 115 | /** @brief the list of physical addresses given to the directory */ 116 | ll_t *p_addr_list; 117 | /** @brief the list of mapping tasks that are to be committed or aborted */ 118 | ll_t *mapping_tasks; 119 | /** @brief denotes whether or not we should be mapping tasks immediately or 120 | * during commits only */ 121 | bool batch_enabled; 122 | } page_directory_t; 123 | 124 | int pd_init(page_directory_t *pd); 125 | int pd_init_kernel(void); 126 | int pd_get_mapping(page_directory_t *pd, uint32_t v_addr, uint32_t *pte); 127 | 128 | int pd_begin_mapping(page_directory_t *pd); 129 | void pd_abort_mapping(page_directory_t *pd); 130 | void pd_commit_mapping(page_directory_t *pd); 131 | 132 | 133 | int pd_create_mapping(page_directory_t *pd, uint32_t v_addr, uint32_t p_addr, uint32_t pte_flags, uint32_t pde_flags); 134 | int pd_get_permissions(page_directory_t *pd, uint32_t v_addr, 135 | uint32_t *priv, uint32_t *access); 136 | int pd_is_user_read_write(page_directory_t *pd, uint32_t v_addr); 137 | int pd_is_user_readable(page_directory_t *pd, uint32_t v_addr); 138 | int pd_remove_mapping(page_directory_t *pd, uint32_t v_addr); 139 | int pd_entry_present(uint32_t v); 140 | int pd_deep_copy(page_directory_t *pd_dest, page_directory_t *pd_src, uint32_t p_addr_start); 141 | int pd_map_sections(page_directory_t *pd, mem_section_t *secs, 142 | uint32_t num_secs); 143 | void *pd_get_base_addr(page_directory_t *pd); 144 | 145 | int pd_alloc_frame(page_directory_t *pd, uint32_t p_addr, uint32_t num_pages); 146 | int pd_dealloc_frame(page_directory_t *pd, uint32_t p_addr, 147 | uint32_t *frame_size); 148 | int pd_dealloc_all_frames(page_directory_t *pd, uint32_t *addr_list, 149 | uint32_t *size_list); 150 | int pd_num_frames(page_directory_t *pd); 151 | int pd_clear_user_space(page_directory_t *pd); 152 | void pd_destroy(page_directory_t *pd); 153 | 154 | #endif /* _PAGE_DIRECTORY_H_ */ 155 | 156 | 157 | -------------------------------------------------------------------------------- /kern/inc/pcb.h: -------------------------------------------------------------------------------- 1 | /** @file pcb_t.h 2 | * 3 | */ 4 | 5 | #ifndef _PCB_T_H_ 6 | #define _PCB_T_H_ 7 | 8 | /* page directory include */ 9 | #include 10 | /* frame manager include */ 11 | #include 12 | /* semaphore type */ 13 | #include 14 | 15 | /** 16 | * @brief A process control block that holds meta information for a process 17 | * 18 | */ 19 | typedef struct pcb{ 20 | /** @brief unique id of the pcb */ 21 | int pid; 22 | /** @brief pid of this pcb's parent pcb */ 23 | int ppid; 24 | /** @brief the tid of the first thread in this process */ 25 | int original_tid; 26 | /** @brief top of the user stack of this pcb */ 27 | uint32_t stack_top; 28 | /** @brief Starting execution eip of this pcb's program */ 29 | unsigned long entry_point; 30 | /** @brief Page directory of this pcb */ 31 | page_directory_t pd; 32 | /** @brief Number of threads running in this pcb */ 33 | uint32_t num_threads; 34 | /** @brief Number of child processes this pcb has */ 35 | uint32_t num_child_proc; 36 | /** @brief Number of arguments to pcb's program entry point */ 37 | int argc; 38 | /** @brief Array of string args to pcb's program entry point */ 39 | char **argv; 40 | /** 41 | * @brief Semaphore that child processes signal to let the parent pcb know 42 | * it has vanished and to collect its status 43 | */ 44 | sem_t wait_sem; 45 | /** 46 | * @brief Queue that child processes place themselves in to make themselves 47 | * available to the parent pcb 48 | */ 49 | queue_t status_queue; 50 | /** 51 | * @brief Mutex is needed because other threads (not the current one) are 52 | * accessing and changing a pcb possibly simultaneously. For example, 53 | * in the case of a child modifying the parent. In some functions, like 54 | * pcb_load_prog, a lock is not necessary because only the current 55 | * running pcb should be loading a program into the itself. 56 | */ 57 | mutex_t m; 58 | } pcb_t; 59 | 60 | int pcb_init(pcb_t *pcb); 61 | int pcb_set_running(pcb_t *pcb); 62 | int pcb_set_original_tid(pcb_t *pcb, int tid); 63 | int pcb_get_original_tid(pcb_t *pcb, int *tid); 64 | int pcb_destroy_s(pcb_t *pcb); 65 | int pcb_load_prog(pcb_t *pcb, const char *filename, int argc, char** argv); 66 | int pcb_copy(pcb_t *dest_pcb, pcb_t *source_pcb); 67 | int pcb_wait_on_status(pcb_t *pcb, int *status_ptr, int *original_tid); 68 | int pcb_signal_status(pcb_t *pcb, int status, int original_tid); 69 | int pcb_get_ppid(pcb_t *pcb); 70 | 71 | int pcb_inc_children_s(pcb_t *pcb); 72 | int pcb_dec_children_s(pcb_t *pcb); 73 | 74 | int pcb_inc_threads_s(pcb_t *pcb); 75 | int pcb_dec_threads_s(pcb_t *pcb); 76 | 77 | #endif /* _PCB_T_H_ */ 78 | -------------------------------------------------------------------------------- /kern/inc/queue.h: -------------------------------------------------------------------------------- 1 | /** @file queue.h 2 | * @brief Defines interface for a queue 3 | * @author Christopher Wei (cjwei) 4 | * @author Aatish Nayak (aatishn) 5 | 6 | * @bug No known bugs 7 | */ 8 | 9 | 10 | #ifndef _QUEUE_H_ 11 | #define _QUEUE_H_ 12 | 13 | #include 14 | 15 | /** 16 | * @brief Struct representing a singly linked linked list node 17 | */ 18 | typedef struct queue { 19 | /** @brief internal linked list */ 20 | ll_t *ll; 21 | } queue_t; 22 | 23 | int queue_init(queue_t *q); 24 | int queue_enq(queue_t *q, void *value); 25 | int queue_deq(queue_t *q, void **value_ptr); 26 | void queue_destroy(queue_t *q); 27 | int queue_peek(queue_t *q, void **value_ptr); 28 | int queue_size(queue_t *q); 29 | 30 | #endif /* _QUEUE_H_ */ 31 | -------------------------------------------------------------------------------- /kern/inc/rwlock.h: -------------------------------------------------------------------------------- 1 | /** @file rwlock.h 2 | * @brief This file defines the type for reader/writer locks. 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | #ifndef _RWLOCK_H_ 8 | #define _RWLOCK_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | /** @brief defines a read */ 15 | #define RWLOCK_READ 0 16 | /** @brief defines a write */ 17 | #define RWLOCK_WRITE 1 18 | 19 | 20 | /** @brief Defines a struct and type for reader/writer lock */ 21 | typedef struct rwlock { 22 | /** @brief Internal mutex protecting the actual lock */ 23 | mutex_t m; 24 | /** @brief Condition variable used to signal writer */ 25 | cond_t cv; 26 | /** @brief Number of readers currently in critical section */ 27 | int count; 28 | /** @brief Whether or not a writer holds the lock */ 29 | bool writer_locked; 30 | } rwlock_t; 31 | 32 | /* readers/writers lock functions */ 33 | int rwlock_init( rwlock_t *rwlock ); 34 | void rwlock_lock( rwlock_t *rwlock, int type ); 35 | void rwlock_unlock( rwlock_t *rwlock ); 36 | void rwlock_destroy( rwlock_t *rwlock ); 37 | void rwlock_downgrade( rwlock_t *rwlock); 38 | 39 | #endif /* _RWLOCK_H_ */ 40 | 41 | -------------------------------------------------------------------------------- /kern/inc/sched_mutex.h: -------------------------------------------------------------------------------- 1 | /** @file sched_mutex_t.h 2 | * @brief Interface for a scheduler lock 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | #ifndef _SCHED_MUTEX_ 8 | #define _SCHED_MUTEX_ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | /** @brief Defines a mutex struct and type */ 15 | typedef struct sched_mutex { 16 | /** @brief The scheduler to protect */ 17 | scheduler_t *sched; 18 | } sched_mutex_t; 19 | 20 | int sched_mutex_init( sched_mutex_t *mp, scheduler_t *sched); 21 | void sched_mutex_destroy( sched_mutex_t *mp); 22 | void sched_mutex_lock( sched_mutex_t *mp ); 23 | void sched_mutex_unlock( sched_mutex_t *mp ); 24 | 25 | #endif /* _SCHED_MUTEX_ */ 26 | -------------------------------------------------------------------------------- /kern/inc/scheduler.h: -------------------------------------------------------------------------------- 1 | /** @file scheduler.h 2 | * @brief defines the interface for a scheduler 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifndef _SCHEDULER_H_ 15 | #define _SCHEDULER_H_ 16 | 17 | typedef struct scheduler{ 18 | /** @brief whether or not a scheduler has started yet */ 19 | bool started; 20 | 21 | /** @brief the number of ticks since the scheduler has started */ 22 | int num_ticks; 23 | /** @brief the next tid to create */ 24 | int next_tid; 25 | /** @brief the next pid to create */ 26 | int next_pid; 27 | /** @brief the stack bot of a reaper thread */ 28 | void *reaper_stack_bot; 29 | /** @brief the stack top of a reaper thread */ 30 | void *reaper_stack_top; 31 | 32 | /** @brief the init pcb */ 33 | pcb_t *init_pcb; 34 | /** @brief the reaper pcb */ 35 | tcb_t *reaper_tcb; 36 | /** @brief the idle pcb */ 37 | tcb_t *idle_tcb; 38 | 39 | /** @brief the thread pool */ 40 | tcb_pool_t thr_pool; 41 | /** @brief the current running tcb */ 42 | tcb_t *cur_tcb; 43 | } scheduler_t; 44 | 45 | extern uint32_t scheduler_num_ticks; 46 | 47 | 48 | int scheduler_init(scheduler_t *sched, void (*reap_func)(void)); 49 | 50 | int scheduler_add_process(scheduler_t *sched, pcb_t *pcb, uint32_t *regs); 51 | int scheduler_add_new_thread(scheduler_t *sched, uint32_t *regs); 52 | 53 | 54 | int scheduler_start(scheduler_t *sched); 55 | 56 | int scheduler_get_next_tcb(scheduler_t *sched, tcb_t **tcb); 57 | int scheduler_get_tcb_by_tid(scheduler_t *sched, 58 | int target_tid, tcb_t **tcbp); 59 | 60 | int scheduler_get_pcb_by_pid(scheduler_t *sched, 61 | int target_pid, pcb_t **pcbp); 62 | 63 | int scheduler_get_init_pcb(scheduler_t *sched, pcb_t **init_pcbp); 64 | int scheduler_get_idle_tcb(scheduler_t *sched, tcb_t **idle_tcbp); 65 | 66 | 67 | int scheduler_check_is_runnable(scheduler_t *sched, int target_tid); 68 | 69 | int scheduler_set_running_tcb(scheduler_t *sched, 70 | tcb_t *tcb, uint32_t *new_esp); 71 | 72 | int scheduler_get_current_tcb(scheduler_t *sched, tcb_t **tcb); 73 | 74 | int scheduler_get_current_pcb(scheduler_t *sched, pcb_t **pcb); 75 | 76 | int scheduler_deschedule_current_safe(scheduler_t *sched); 77 | int scheduler_make_runnable_safe(scheduler_t *sched, int tid); 78 | int scheduler_make_current_sleeping_safe(scheduler_t *sched, int ticks); 79 | int scheduler_make_current_zombie_safe(scheduler_t *sched); 80 | int scheduler_cleanup_current_safe(scheduler_t *sched); 81 | 82 | int scheduler_wakeup(scheduler_t *sched); 83 | int scheduler_reap(scheduler_t *sched); 84 | 85 | int scheduler_defer_current_tcb(scheduler_t *sched, uint32_t old_esp); 86 | 87 | int scheduler_get_current_tid(scheduler_t *sched, int *tidp); 88 | 89 | #endif /* _SCHEDULER_H_ */ 90 | 91 | -------------------------------------------------------------------------------- /kern/inc/sem.h: -------------------------------------------------------------------------------- 1 | /** @file sem.h 2 | * @brief This file defines the interface to semaphores 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | */ 7 | 8 | #ifndef SEM_H 9 | #define SEM_H 10 | 11 | #include 12 | #include 13 | 14 | /** @brief Defines a semaphore struct and type */ 15 | typedef struct sem { 16 | /** @brief The number of resources currently avaliable from sem */ 17 | int count; 18 | /** @brief The internal mutex that protects q */ 19 | mutex_t m; 20 | /** @brief Queue of waiting threads on sem */ 21 | queue_t q; 22 | } sem_t; 23 | 24 | /* semaphore functions */ 25 | int sem_init( sem_t *sem, int count ); 26 | int sem_get_value(sem_t *sem, int *sval); 27 | void sem_wait( sem_t *sem ); 28 | void sem_signal( sem_t *sem ); 29 | void sem_destroy( sem_t *sem ); 30 | 31 | #endif /* SEM_H */ 32 | -------------------------------------------------------------------------------- /kern/inc/special_reg_cntrl.h: -------------------------------------------------------------------------------- 1 | /** @file special_reg_cntrl.h 2 | * @brief Specifies w 3 | * 4 | * @author Aatish Nayak (aatishn) 5 | * @author Christopher Wei (cjwei) 6 | * @bug No known bugs. 7 | */ 8 | 9 | #ifndef _SPECIAL_REG_CNTRL_H_ 10 | #define _SPECIAL_REG_CNTRL_H_ 11 | 12 | void set_pdbr(uint32_t new_pdbr); 13 | 14 | /** @brief sets the current esp to the new_esp 15 | * @param new_esp the new esp to set to 16 | * @return Void 17 | */ 18 | void set_cur_esp(uint32_t new_esp); 19 | 20 | uint32_t get_pdbr(); 21 | 22 | void enable_paging(void); 23 | 24 | void enable_pge(void); 25 | 26 | uint32_t get_user_eflags(void); 27 | 28 | /** @brief flushes tlb containing address 29 | * @param mem_addr The memory address to flush from 30 | * @return Void */ 31 | void flush_tlb(uint32_t mem_addr); 32 | void flush_all_tlb(void); 33 | 34 | #endif /* SPECIAL_REG_CNTRL_H_ */ 35 | 36 | 37 | -------------------------------------------------------------------------------- /kern/inc/stack.h: -------------------------------------------------------------------------------- 1 | /** @file queue.h 2 | * @brief Defines interface for a queue 3 | * @author Christopher Wei (cjwei) 4 | * @author Aatish Nayak (aatishn) 5 | 6 | * @bug No known bugs 7 | */ 8 | 9 | 10 | #ifndef _STACK_H_ 11 | #define _STACK_H_ 12 | 13 | #include 14 | 15 | /** 16 | * @brief Struct representing a singly linked linked list node 17 | */ 18 | typedef struct stack { 19 | /** @brief the internal linked list representation */ 20 | ll_t *ll; 21 | } stack_t; 22 | 23 | int stack_init(stack_t *stk); 24 | int stack_push(stack_t *stk, void *value); 25 | int stack_pop(stack_t *stk, void **value_ptr); 26 | void stack_destroy(stack_t *stk); 27 | int stack_peek(stack_t *stk, void **value_ptr); 28 | int stack_size(stack_t *stk); 29 | 30 | #endif /* _STACK_H_ */ 31 | -------------------------------------------------------------------------------- /kern/inc/tcb.h: -------------------------------------------------------------------------------- 1 | /** @file tcb.h 2 | * 3 | */ 4 | 5 | #ifndef _TCB_H_ 6 | #define _TCB_H_ 7 | 8 | /* page directory include */ 9 | #include 10 | /* frame manager include */ 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | /** @brief possible tcb statuses */ 17 | #define UNINIT 0 18 | #define RUNNABLE 1 19 | #define WAITING 2 20 | #define ZOMBIE 3 21 | #define RUNNING 4 22 | #define SLEEPING 5 23 | 24 | 25 | /** @brief number of registers saved in tcb */ 26 | #define REGS_SIZE 18 27 | 28 | /** @brief the iret value indexes */ 29 | #define SS_IDX 17 30 | #define ESP_IDX 16 31 | #define EFLAGS_IDX 15 32 | #define CS_IDX 14 33 | #define EIP_IDX 13 34 | #define ERRCODE_IDX 12 35 | 36 | /** @brief the saved context indexes */ 37 | #define EAX_IDX 11 38 | #define ECX_IDX 10 39 | #define EDX_IDX 9 40 | #define EBX_IDX 8 41 | // Skip ESP reg 7 42 | #define EBP_IDX 6 43 | #define ESI_IDX 5 44 | #define EDI_IDX 4 45 | #define GS_IDX 3 46 | #define FS_IDX 2 47 | #define ES_IDX 1 48 | #define DS_IDX 0 49 | 50 | /** 51 | * @brief A thread control block that holds meta information for a thread 52 | * 53 | */ 54 | typedef struct tcb{ 55 | 56 | /** @brief unique id of this tcb */ 57 | int tid; 58 | /** 59 | * @brief Current scheduler status of this tcb (See above for possible 60 | * statuses) 61 | */ 62 | int status; 63 | /** @brief Exit status of this thread. Set with a call to set_status */ 64 | int exit_status; 65 | /** 66 | * @brief If this thread is sleeping, t_wakeup is absolute time to wake up 67 | * at. Measured in number of ticks 68 | */ 69 | uint32_t t_wakeup; 70 | /** 71 | * @brief The pcb that this tcb is running under. Multiple tcbs can have 72 | * the same pcb (multi-threaded) 73 | */ 74 | pcb_t *pcb; 75 | 76 | /** 77 | * @brief Bottom of this tcb's k_stack 78 | */ 79 | uint32_t *k_stack_bot; 80 | 81 | /** 82 | * @brief Top of this tcb's k_stack 83 | */ 84 | uint32_t *k_stack_top; 85 | 86 | /** 87 | * @brief Address of the last meta/context data that was pushed onto the 88 | * k_stack. This is used as a starting point for entering a program. 89 | * 90 | * k_stack_bot < orig_k_stack < k_stack_top 91 | */ 92 | uint32_t *orig_k_stack; 93 | 94 | /** 95 | * @brief Temporary k_stack address that context information is pushed 96 | * onto on every context switch. The tmp_k_stack is saved everytime so a 97 | * thread can be restored when context switched back into. 98 | */ 99 | uint32_t *tmp_k_stack; 100 | 101 | /** 102 | * @brief Generic exception handler for this tcb installed via a call to 103 | * swexn 104 | */ 105 | void (*swexn_handler)(void *arg, ureg_t *ureg); 106 | 107 | /** 108 | * @brief Pointer to the args of the installed exception handler 109 | */ 110 | void *swexn_handler_arg; 111 | /** 112 | * @brief Top of the exception stack to use when calling the installed 113 | * exception handler 114 | */ 115 | void *swexn_handler_esp; 116 | /** 117 | * @brief Pointer to the ureg struct that holds the context when the 118 | * exception occured. Passed into the swexn handler as an argument 119 | */ 120 | ureg_t *swexn_ureg; 121 | } tcb_t; 122 | 123 | int tcb_init(tcb_t *tcb, int tid, pcb_t *pcb, uint32_t *regs); 124 | int tcb_get_pcb(tcb_t *tcb, pcb_t **pcb); 125 | int tcb_get_init_stack(tcb_t *tcb, void **stack); 126 | int tcb_t_wakeup_cmp(void *a, void *b); 127 | int tcb_reload(tcb_t *tcb, pcb_t *pcb); 128 | void tcb_destroy(tcb_t *tcb); 129 | int tcb_get_exit_status(tcb_t *tcb, int *status); 130 | int tcb_deregister_swexn_handler(tcb_t *tcb, void **esp3, 131 | void (**eip)(void *arg, ureg_t *ureg), void **arg); 132 | int tcb_register_swexn_handler(tcb_t *tcb, void *esp3, 133 | void (*eip)(void *arg, ureg_t *ureg), void *arg); 134 | 135 | #endif /* _TCB_H_ */ 136 | -------------------------------------------------------------------------------- /kern/inc/tcb_pool.h: -------------------------------------------------------------------------------- 1 | /** @file tcb_pool.h 2 | * @brief Defines interface for a thread control block pool 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | 7 | * @bug No known bugs 8 | */ 9 | 10 | 11 | #ifndef _TCB_POOL_H_ 12 | #define _TCB_POOL_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define TABLE_SIZE 64 20 | /** 21 | * @brief Struct representing a thread pool 22 | */ 23 | typedef struct tcb_pool { 24 | /** @brief hash table for thread */ 25 | ht_t threads; 26 | /** @brief hash table for processes */ 27 | ht_t processes; 28 | 29 | /** @brief linked list of runnable threads */ 30 | ll_t runnable_pool; 31 | /** @brief linked list of waiting threads */ 32 | ll_t waiting_pool; 33 | /** @brief linke dlist of sleeping threads */ 34 | ll_t sleeping_pool; 35 | /** @brief linked list of zombie threads */ 36 | ll_t zombie_pool; 37 | 38 | /** @brief semaphore for signaling reaper thread */ 39 | sem_t zombies_sem; 40 | 41 | } tcb_pool_t; 42 | 43 | int tcb_pool_init(tcb_pool_t *tp); 44 | int tcb_pool_add_runnable_tcb_safe(tcb_pool_t *tp, tcb_t *tcb); 45 | int tcb_pool_add_pcb_safe(tcb_pool_t *tp, pcb_t *pcb); 46 | int tcb_pool_remove_pcb(tcb_pool_t *tp, int pid, circ_buf_t *addr_to_free); 47 | 48 | int tcb_pool_make_runnable(tcb_pool_t *tp, int tid); 49 | int tcb_pool_make_waiting(tcb_pool_t *tp, int tid); 50 | int tcb_pool_make_sleeping(tcb_pool_t *tp, int tid); 51 | int tcb_pool_make_zombie(tcb_pool_t *tp, int tid); 52 | int tcb_pool_wakeup(tcb_pool_t *tp, uint32_t curr_time); 53 | int tcb_pool_reap(tcb_pool_t *tp); 54 | 55 | int tcb_pool_get_next_tcb(tcb_pool_t *tp, tcb_t **next_tcbp); 56 | int tcb_pool_remove_tcb(tcb_pool_t *tp, int tid, circ_buf_t *addr_to_free); 57 | int tcb_pool_find_tcb(tcb_pool_t *tp, int tid, tcb_t **tcbp); 58 | int tcb_pool_find_pcb(tcb_pool_t *tp, int pid, pcb_t **pcbp); 59 | 60 | 61 | #endif /* _TCB_POOL_H_ */ 62 | -------------------------------------------------------------------------------- /kern/inc/thr_helpers.h: -------------------------------------------------------------------------------- 1 | /** @file thr_helpers.h 2 | * @brief Specifies interface for manipulating threads inside the 3 | * kernel 4 | * 5 | * @author Aatish Nayak (aatishn) 6 | * @author Christopher Wei (cjwei) 7 | * @bug No known bugs. 8 | */ 9 | 10 | #ifndef _THR_HELPERS_H_ 11 | #define _THR_HELPERS_H_ 12 | 13 | #include 14 | 15 | int thr_deschedule(uint32_t old_esp, int *reject); 16 | int thr_make_runnable(int tid); 17 | int thr_yield(uint32_t old_esp, int tid); 18 | int thr_gettid(void); 19 | int thr_sleep(uint32_t old_esp, int ticks); 20 | void thr_vanish(void); 21 | void thr_set_status(int status); 22 | 23 | /** 24 | * @brief Yields execution to the thread with the specified tcb 25 | * 26 | * Used while a thread is in the kernel and needs to yield to another 27 | * thread. Normally, when a thread calls an INT from user land to execute 28 | * the syscall yield, its context information is saved on its stack by the 29 | * syscall handler and the INT. When yielding from inside the kernel, we 30 | * simulate saving this context information on the stack with a series of 31 | * assembly instructions 32 | * 33 | * @return 0 on success, negative error code otherwise 34 | * 35 | * 36 | */ 37 | int thr_kern_yield(int tid); 38 | 39 | /** 40 | * @brief Deschedules the current thread, ending its execution until a 41 | * make_runnable call tells it to wake up. 42 | * 43 | * Used while a thread is in the kernel and needs to deschedule itself. 44 | * Normally, when a thread calls an INT from user land to execute 45 | * the syscall deschedule, its context information is saved on its 46 | * stack by the syscall handler and the INT. When descheduling from inside 47 | * the kernel, we simulate saving this context information on the stack 48 | * with a series of assembly instructions 49 | * 50 | * @return 0 on success, negative error code otherwise 51 | * 52 | */ 53 | int thr_kern_deschedule(int *reject); 54 | 55 | #endif /* _THR_HELPERS_H_ */ 56 | 57 | 58 | -------------------------------------------------------------------------------- /kern/inc/virtual_mem_mgmt.h: -------------------------------------------------------------------------------- 1 | /** @file virtual_mem_mgmt.h 2 | * @brief Defines the interface for a virtual memory manager 3 | * 4 | * @author Christopher Wei (cjwei) 5 | * @author Aatish Nayak (aatishn) 6 | */ 7 | 8 | 9 | #ifndef _VIRTUAL_MEM_MGMT_H_ 10 | #define _VIRTUAL_MEM_MGMT_H_ 11 | 12 | #include 13 | #include 14 | 15 | int vmm_map_sections(page_directory_t *pd, mem_section_t *secs, int num_secs); 16 | int vmm_deep_copy(page_directory_t *pd_dest); 17 | int vmm_new_user_page(page_directory_t *pd, uint32_t base, uint32_t num_pages); 18 | int vmm_remove_user_page(page_directory_t *pd, uint32_t base); 19 | int vmm_clear_user_space(page_directory_t *pd); 20 | 21 | #endif /* _VIRTUAL_MEM_MGMT_H_ */ 22 | -------------------------------------------------------------------------------- /kern/kernel.c: -------------------------------------------------------------------------------- 1 | /** @file kernel.c 2 | * @brief An initial kernel.c 3 | * 4 | * Entry Point for ShrekOS 5 | * 6 | * @author Aatish Nayak (aatishn) 7 | * @author Christopher Wei (cjwei) 8 | * @bug No known bugs. 9 | */ 10 | 11 | #include 12 | 13 | /* libc includes. */ 14 | #include 15 | 16 | /* multiboot header file */ 17 | #include /* boot_info */ 18 | 19 | /* x86 specific includes */ 20 | #include /* enable_interrupts() */ 21 | 22 | /* panic */ 23 | #include 24 | 25 | /* console */ 26 | #include 27 | 28 | /* idt installers */ 29 | #include 30 | /* frame manager include */ 31 | #include 32 | /* process control block include */ 33 | #include 34 | /* control for special register wrapper */ 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | /* Kernel global variables and internals */ 41 | #include 42 | 43 | /* Debugging */ 44 | #include /* lprintf() */ 45 | 46 | /** 47 | * @brief Max size of keyboard buffer 48 | * We arrived at this value because it is the same value provided to us 49 | * in the shell program 50 | */ 51 | #define KEYBOARD_BUFFER_SIZE 1024 52 | 53 | /* Global vars */ 54 | scheduler_t sched; 55 | mutex_t heap_lock; 56 | frame_manager_t fm; 57 | mutex_t console_lock; 58 | keyboard_t keyboard; 59 | sched_mutex_t sched_lock; 60 | 61 | /** @brief Reaper entrypoint 62 | * 63 | * @return Does not return 64 | */ 65 | void reaper_main(){ 66 | while(1){ 67 | scheduler_reap(&sched); 68 | } 69 | } 70 | 71 | 72 | /** @brief Kernel entrypoint. 73 | * 74 | * This is the entrypoint for the kernel. 75 | * 76 | * @return Does not return 77 | */ 78 | int kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) 79 | { 80 | lprintf("Welcome to ShrekOS"); 81 | lprintf("Shrek is love, Shrek is life"); 82 | 83 | /* install IDT entries for system calls */ 84 | install_syscall_handlers(); 85 | 86 | /* install IDT entries for peripherals */ 87 | install_peripheral_handlers(); 88 | 89 | /* Install IDT entres for exceptions */ 90 | install_exception_handlers(); 91 | 92 | /* Clear the console */ 93 | clear_console(); 94 | 95 | /* Init global heap lock */ 96 | mutex_init(&heap_lock); 97 | /* Init console mutex */ 98 | mutex_init(&console_lock); 99 | 100 | /* initialize the keyboard buffer */ 101 | keyboard_init(&keyboard, KEYBOARD_BUFFER_SIZE); 102 | /* init frame manager */ 103 | fm_init(&fm, 15); 104 | /* initialize pd kernel pages */ 105 | pd_init_kernel(); 106 | 107 | /* Init the scheduler lock */ 108 | sched_mutex_init(&sched_lock, &sched); 109 | 110 | /* initialize a scheduler */ 111 | scheduler_init(&sched, reaper_main); 112 | 113 | scheduler_start(&sched); 114 | 115 | while (1) { 116 | continue; 117 | } 118 | 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /kern/keyboard.c: -------------------------------------------------------------------------------- 1 | /** @file keyboard.c 2 | * @brief Implements a keyboard 3 | * @author Christopher Wei (cjwei) 4 | * @bug No known bugs 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | /** @brief Takes a character c and prints it to the console 17 | * @param c The character to be printed 18 | * @return Void 19 | */ 20 | void print_to_console(keyboard_t *k, char c){ 21 | if (k == NULL) return; 22 | uint32_t count; 23 | if (circ_buf_count(k->buf, &count) < 0) return; 24 | switch(c){ 25 | case '\b': 26 | /* if nothing avaliable to backspace, ignore 27 | * and don't print to console */ 28 | if (count == 0){ 29 | break; 30 | } else { 31 | /* we removed a character from the buffer, so now 32 | * we need to remove a character from the console */ 33 | putbyte(c); 34 | } 35 | break; 36 | default: 37 | putbyte(c); 38 | break; 39 | } 40 | } 41 | 42 | /** @brief Writes a character to a keyboard buffer 43 | * @param k The keyboard 44 | * @param c The character to write 45 | * @return 0 on success, negative integer code on failure 46 | */ 47 | int write_to_buffer(keyboard_t *k, char c){ 48 | uint32_t count; 49 | /* write to the keyboard's buffer */ 50 | switch(c){ 51 | case '\b': 52 | circ_buf_count(k->buf, &count); 53 | /* ignore backspaces on empty buffer */ 54 | if (count == 0) break; 55 | /* remove one character */ 56 | if (circ_buf_delete_front(k->buf) < 0){ 57 | return -2; 58 | } 59 | break; 60 | default: 61 | /* write character to buffer */ 62 | if (circ_buf_write(k->buf, (void *)(unsigned int)c) < 0){ 63 | return -3; 64 | } 65 | break; 66 | } 67 | return 0; 68 | } 69 | 70 | /** @brief Initializes a keyboard 71 | * @param k The keyboard 72 | * @param len The size of the keyboard buffer 73 | * @return 0 on success, negative integer code on failure 74 | */ 75 | int keyboard_init(keyboard_t *k, uint32_t len){ 76 | if (k == NULL || len == 0) return -1; 77 | circ_buf_t *cbuf = malloc(sizeof(circ_buf_t)); 78 | if (circ_buf_init(cbuf, len) < 0) return -2; 79 | if (sem_init(&(k->sem), 0) < 0) return -3; 80 | if (mutex_init(&(k->m)) < 0) return -4; 81 | k->buf = cbuf; 82 | return 0; 83 | } 84 | 85 | /** @brief Destroys a keyboard 86 | * @param k The keyboard 87 | * @return Void 88 | */ 89 | void keyboard_destroy(keyboard_t *k){ 90 | circ_buf_destroy(k->buf); 91 | mutex_destroy(&(k->m)); 92 | sem_destroy(&(k->sem)); 93 | free(k->buf); 94 | } 95 | 96 | /** @brief Writes a value to the keyboard 97 | * @param k The keyboard 98 | * @param len The value 99 | * @return 0 on success, negative integer code on failure 100 | */ 101 | int keyboard_write(keyboard_t *k, uint32_t val){ 102 | if (k == NULL) return -1; 103 | mutex_lock(&(k->m)); 104 | 105 | /* see if we should echo to console */ 106 | int num_resources; 107 | if (sem_get_value(&(k->sem), &num_resources) < 0){ 108 | mutex_unlock(&(k->m)); 109 | return -3; 110 | } 111 | 112 | /* atleast one readline is pending - echo val to console */ 113 | if (num_resources < 0){ 114 | print_to_console(k, (char)val); 115 | } 116 | 117 | if (write_to_buffer(k, (char)val) < 0){ 118 | mutex_unlock(&(k->m)); 119 | return -4; 120 | } 121 | 122 | /* if the given character is a new line, increment the number 123 | * of resources avaliable */ 124 | if ((char)val == '\n') sem_signal(&k->sem); 125 | mutex_unlock(&(k->m)); 126 | return 0; 127 | } 128 | 129 | /** @brief Destructively reads a value from the keyboard 130 | * @param k The keyboard 131 | * @param len The number of characters to read 132 | * @param buf The character buffer to read into 133 | * @return 0 on success, negative integer code on failure 134 | */ 135 | int keyboard_read(keyboard_t *k, int len, char *buf){ 136 | if (k == NULL || len <= 0 || buf == NULL) return -1; 137 | sem_wait(&k->sem); 138 | mutex_lock(&(k->m)); 139 | /* read the line in from circ buf */ 140 | char temp_buf[len]; 141 | uint32_t i, val; 142 | for (i = 0; i < len; i++){ 143 | if (circ_buf_read(k->buf, (void **)&val) < 0){ 144 | mutex_unlock(&(k->m)); 145 | return -2; 146 | } 147 | if ((char)val == '\n'){ 148 | if (i == 0){ 149 | temp_buf[i] = (char)val; 150 | i = 1; 151 | } 152 | break; 153 | } 154 | temp_buf[i] = (char)val; 155 | } 156 | 157 | memcpy(buf, temp_buf, i*sizeof(char)); 158 | mutex_unlock(&(k->m)); 159 | return i; 160 | } 161 | 162 | /** @brief Gets the size of the keyboard buffer 163 | * @param k The keyboard 164 | * @param len The pointer to store the size of the keyboard buffer 165 | * @return 0 on success, negative integer code on failure 166 | */ 167 | int keyboard_buffer_size(keyboard_t *k, uint32_t *len){ 168 | if (k == NULL || len == NULL) return -1; 169 | return circ_buf_size(k->buf, len); 170 | } 171 | -------------------------------------------------------------------------------- /kern/loader/loader.c: -------------------------------------------------------------------------------- 1 | /** @file loader.c 2 | * @author Christopher Wei (cjwei) 3 | * @author Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | /* --- Includes --- */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #define NUM_ELF_SECTIONS 4 28 | 29 | 30 | /* --- Local function prototypes --- */ 31 | 32 | 33 | /** 34 | * Copies data from a file into a buffer. 35 | * 36 | * @param filename the name of the file to copy data from 37 | * @param offset the location in the file to begin copying from 38 | * @param size the number of bytes to be copied 39 | * @param buf the buffer to copy the data into 40 | * 41 | * @return returns the number of bytes copied on succes; -1 on failure 42 | */ 43 | int getbytes( const char *filename, int offset, int size, char *buf ) 44 | { 45 | int i; 46 | for (i = 0; i < exec2obj_userapp_count; i++){ 47 | exec2obj_userapp_TOC_entry entry = exec2obj_userapp_TOC[i]; 48 | if (strcmp(entry.execname, filename) == 0){ 49 | 50 | /* Copy all size bytes if possible */ 51 | int num_bytes = size + offset > entry.execlen 52 | ? entry.execlen - offset 53 | : size; 54 | 55 | memcpy(buf, entry.execbytes+offset, num_bytes); 56 | return num_bytes; 57 | } 58 | } 59 | return -1; 60 | } 61 | 62 | /** @brief checks if elf file exists 63 | * @param filename The filename of the elf 64 | * @return whether the elf file exists 65 | */ 66 | int load_elf_exists(const char *filename){ 67 | simple_elf_t elf; 68 | return (elf_check_header(filename) == ELF_SUCCESS && 69 | elf_load_helper(&elf, filename) == ELF_SUCCESS); 70 | } 71 | 72 | /** @brief loads all elf sections into pcb 73 | * @param elf The file file 74 | * @param pcb The pcb to load into 75 | * @return 0 on success, negative integer code on failure 76 | */ 77 | int load_elf_sections(simple_elf_t *elf, pcb_t *pcb){ 78 | mem_section_t secs[NUM_ELF_SECTIONS]; 79 | 80 | ms_init(&secs[0], elf->e_txtstart, 81 | elf->e_txtlen, USER_WR, USER_RO); 82 | ms_init(&secs[1], elf->e_datstart, 83 | elf->e_datlen, USER_WR, USER_WR); 84 | ms_init(&secs[2], elf->e_rodatstart, 85 | elf->e_rodatlen, USER_WR, USER_RO); 86 | ms_init(&secs[3], elf->e_bssstart, 87 | elf->e_bsslen, USER_WR, USER_WR); 88 | 89 | /* Map all appropriate elf binary sections into user space */ 90 | if (vmm_map_sections(&(pcb->pd), secs, NUM_ELF_SECTIONS) < 0) return -1; 91 | 92 | /* Fill in .text section */ 93 | if (getbytes(elf->e_fname, elf->e_txtoff, elf->e_txtlen, 94 | (char*)elf->e_txtstart) != elf->e_txtlen) return -1; 95 | 96 | /* Fill in .data section */ 97 | if (getbytes(elf->e_fname, elf->e_datoff, elf->e_datlen, 98 | (char*)elf->e_datstart) != elf->e_datlen) return -1; 99 | 100 | /* Fill in .rodata section */ 101 | if (getbytes(elf->e_fname, elf->e_rodatoff, elf->e_rodatlen, 102 | (char*)elf->e_rodatstart) != elf->e_rodatlen) return -1; 103 | 104 | /* Clear .bss section */ 105 | memset((void *)elf->e_bssstart, 0, elf->e_bsslen); 106 | 107 | /* Set process entry point */ 108 | pcb->entry_point = elf->e_entry; 109 | return 0; 110 | 111 | } 112 | 113 | /** @brief load the stack into pcb 114 | * @param pcb The pcb 115 | * @return 0 on success, negative integer code on failure 116 | */ 117 | int load_user_stack(pcb_t *pcb) { 118 | if (pcb == NULL) return -1; 119 | 120 | /* Calculate user stack bottom */ 121 | mem_section_t stack_secs[1]; 122 | 123 | ms_init(&stack_secs[0], USER_STACK_BOTTOM, 124 | USER_STACK_SIZE, USER_WR, USER_WR); 125 | 126 | /* Allocate and map space for stack in virtual memory */ 127 | if (vmm_map_sections(&(pcb->pd), stack_secs, 1) < 0) return -2; 128 | 129 | /* Setup user stack for entry point */ 130 | uint32_t *stack_top = (uint32_t *) USER_STACK_TOP; 131 | 132 | /* Loop through argv and allocate data onto user stack */ 133 | char *arg; 134 | /* Will hold addresses of each arg string to be put into memory later */ 135 | 136 | char *new_argv[pcb->argc]; 137 | int arg_idx; 138 | char *esp = (char*)stack_top; 139 | for (arg_idx = 0; arg_idx < pcb->argc ; arg_idx++) { 140 | /* Get arg from provided argv */ 141 | arg = pcb->argv[arg_idx]; 142 | /* Calculate lenght of string arg */ 143 | int arg_len = strlen(arg); 144 | /* Since we are filling in memory backwards, start with null char */ 145 | *esp = '\0'; 146 | 147 | int str_i = arg_len-1; 148 | /* Loop backwards through arg string and fill in esp */ 149 | while(str_i >= 0) { 150 | esp--; 151 | *esp = arg[str_i]; 152 | str_i--; 153 | } 154 | /* Save addr of start of string */ 155 | new_argv[arg_idx] = esp; 156 | /* Make room for next arg */ 157 | esp--; 158 | } 159 | 160 | /* Round esp down to nearest 4-byte boundary */ 161 | stack_top = (uint32_t*)((uint32_t)esp - (uint32_t)((uint32_t)esp % 4)); 162 | 163 | /* Go one space down to make room for first address */ 164 | stack_top--; 165 | int i = pcb->argc - 1; 166 | /* Fill in addresses of strings into memory */ 167 | while(i >= 0) { 168 | *stack_top = (uint32_t)new_argv[i]; 169 | i--; 170 | stack_top--; 171 | } 172 | /* Save final argv value */ 173 | uint32_t *final_argv = stack_top + 1; 174 | /* Specify dummy return address */ 175 | stack_top[-4] = 0; 176 | /* argc for _main */ 177 | stack_top[-3] = pcb->argc; 178 | /* argv for _main */ 179 | stack_top[-2] = (uint32_t) final_argv; 180 | /* stack_high for _main */ 181 | stack_top[-1] = USER_STACK_TOP; 182 | /* stack_low for _main */ 183 | stack_top[0] = USER_STACK_BOTTOM; 184 | 185 | /* Set pcb stack */ 186 | pcb->stack_top = (uint32_t) &(stack_top[-4]); 187 | 188 | return 0; 189 | } 190 | 191 | -------------------------------------------------------------------------------- /kern/locks/mutex.c: -------------------------------------------------------------------------------- 1 | /** @file mutex.c 2 | * @brief This file implements mutexes. 3 | * 4 | * We use a very simple implementation of mutexes which simply tries to 5 | * atomically exchange a 0 into the mutex until it passes. This does not 6 | * ensure unbounded waiting unlike methods such as TestAndSet, but also 7 | * does not need to know exactly how many threads are running in order to 8 | * determine some arbitration method. Indeed a thread could be starved out 9 | * due to purely bad luck or a naughty kernel; this is a consideration we 10 | * made when deciding to not implement a unbounded waiting algorithm 11 | * 12 | * @author Christopher Wei (cjwei) Aatish Nayak (aatishn) 13 | * @bug No known bugs 14 | */ 15 | 16 | /* C Standard Lib specific Includes */ 17 | #include 18 | #include 19 | 20 | 21 | /* P3 Specific includes */ 22 | #include 23 | #include 24 | #include 25 | 26 | /** @brief Initializes a mutex 27 | * @param mp Pointer to mutex to be intialized 28 | * @return 0 on success, negative code on error 29 | */ 30 | int mutex_init( mutex_t *mp ){ 31 | if (mp == NULL) return -1; 32 | mp->lock = 1; 33 | mp->owner = -1; 34 | return 0; 35 | } 36 | 37 | /** @brief Destroys a mutex 38 | * @param mp Pointer to mutex to be destroyed 39 | * @return Void 40 | */ 41 | void mutex_destroy( mutex_t *mp ){ 42 | mp->lock = -1; 43 | return; 44 | } 45 | 46 | /** @brief Locks a mutex and hangs until successful 47 | * @param mp Pointer to mutex to be locked 48 | * @return Void 49 | */ 50 | void mutex_lock( mutex_t *mp ){ 51 | if (!sched.started) return; 52 | 53 | /* Get the current tid */ 54 | int cur_tid; 55 | if (scheduler_get_current_tid(&sched, &cur_tid) < 0){ 56 | /* somethings wrong with the scheduler? */ 57 | cur_tid = -1; 58 | } 59 | /* Keep trying to until lock is free and key is accepted */ 60 | while (!xchng(&mp->lock, 0)) { 61 | if (thr_kern_yield(mp->owner) < 0) { 62 | /* Owner is not runnable, yield to scheduler picked thread */ 63 | thr_kern_yield(-1); 64 | } 65 | } 66 | /* after securing the lock, set the owner to yourself so 67 | * threads that are waiting on this mutex will yield to this 68 | * thread - in a sense, the thread holding this mutex has 69 | * gained a higher priority */ 70 | mp->owner = cur_tid; 71 | return; 72 | } 73 | 74 | /** @brief Unlocks a mutex 75 | * @param mp Pointer to mutex to be unlocked 76 | * @return Void 77 | */ 78 | void mutex_unlock( mutex_t *mp ){ 79 | if (!sched.started) return; 80 | /* update the owner to -1 so we don't prioritize this thread anymore. There 81 | * is a slight race condition (which doesn't affect correctness just 82 | * efficiency when we mutex unlock and then another thread mutex locks but 83 | * is context switched out before it can set the mutex's owner. In this case 84 | * it is better to let the scheduler pick a thread to run instead of 85 | * forcing other threads to yield back to here */ 86 | mp->owner = -1; 87 | xchng(&mp->lock, 1); 88 | return; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /kern/locks/rwlock.c: -------------------------------------------------------------------------------- 1 | /** @file rwlock.c 2 | * @brief This file implements readers/writers locks 3 | * 4 | * We have decide on implementing a reader writer lock that gives priority 5 | * to the writer. The thought process behind this is that a writer request 6 | * means that something in the shared resource has inherently changed and 7 | * future reads should wait until the update has occured before reading. 8 | * We implement this using a mutex to protect internal values, a condition 9 | * variable used to signal sleeping readers and writers, a count to keep 10 | * track of the number of readers currently reading (which is used to signal 11 | * when it reachs 0) and a writer_locked boolean to prevent further requests 12 | * from happening until that writer has been serviced. 13 | * 14 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 15 | * @bug No known bugs 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | /* readers/writers lock functions */ 27 | 28 | /** @brief Initializes a reader writer lock 29 | * 30 | * @param rwlock The pointer to the r/w lock to be initialized 31 | * @return 0 on success, -1 on failure 32 | */ 33 | int rwlock_init( rwlock_t *rwlock ){ 34 | if (rwlock == NULL) return -1; 35 | if (mutex_init(&(rwlock->m)) < 0) return -1; 36 | if (cond_init(&(rwlock->cv)) < 0) return -1; 37 | rwlock->count = 0; 38 | rwlock->writer_locked = false; 39 | return 0; 40 | } 41 | 42 | /** @brief Locks the rwlock 43 | * 44 | * @param rwlock The pointer to the r/w lock to be locked 45 | * @param type The integer code defining the type of lock requested 46 | * @return Void 47 | */ 48 | void rwlock_lock( rwlock_t *rwlock, int type ){ 49 | if (rwlock == NULL) return; 50 | if (type != RWLOCK_WRITE && type != RWLOCK_READ) 51 | panic("Invalid type supplied to rwlock_lock"); 52 | 53 | mutex_lock(&(rwlock->m)); 54 | if (rwlock->count < 0) 55 | panic("Attempted to lock a invalid rwlock"); 56 | 57 | if (type == RWLOCK_READ){ 58 | /* wait until a writer has finished using critical section */ 59 | while(rwlock->writer_locked){ 60 | cond_wait(&(rwlock->cv), &(rwlock->m)); 61 | } 62 | /* increment count to let future writers know we are reading 63 | * the critical section */ 64 | rwlock->count++; 65 | } else { 66 | /* wait until any current writers are finished */ 67 | while (rwlock->writer_locked || rwlock->count > 0){ 68 | cond_wait(&(rwlock->cv), &(rwlock->m)); 69 | } 70 | rwlock->writer_locked = true; 71 | } 72 | mutex_unlock(&(rwlock->m)); 73 | } 74 | 75 | /** @brief unlocks the rwlock 76 | * 77 | * @param rwlock The pointer to the r/w lock to be locked 78 | * @return Void 79 | */ 80 | void rwlock_unlock( rwlock_t *rwlock ){ 81 | if (rwlock == NULL) return; 82 | mutex_lock(&(rwlock->m)); 83 | if (rwlock->count <= 0 && !rwlock->writer_locked) 84 | panic("Attempted to unlock rwlock that is already unlocked"); 85 | if (rwlock->writer_locked){ 86 | rwlock->writer_locked = false; 87 | cond_broadcast(&(rwlock->cv)); 88 | } else { 89 | rwlock->count--; 90 | /* since count > 0, everything waiting on cv is a writer, therefore 91 | * wake up next writer */ 92 | if (rwlock->count == 0) cond_signal(&(rwlock->cv)); 93 | } 94 | mutex_unlock(&(rwlock->m)); 95 | } 96 | 97 | 98 | /** @brief Destroys the rwlock 99 | * 100 | * @param rwlock The lock to be destroyed 101 | * @return Void 102 | */ 103 | void rwlock_destroy( rwlock_t *rwlock ){ 104 | if (rwlock == NULL) return; 105 | mutex_lock(&(rwlock->m)); 106 | rwlock->count = -1; 107 | cond_destroy(&(rwlock->cv)); 108 | mutex_unlock(&(rwlock->m)); 109 | mutex_destroy(&(rwlock->m)); 110 | } 111 | /** @brief Converts a writer lock to a reader lock 112 | * 113 | * @param rwlock The lock to be downgraded 114 | * @return Void 115 | */ 116 | void rwlock_downgrade( rwlock_t *rwlock){ 117 | if (rwlock == NULL) return; 118 | mutex_lock(&(rwlock->m)); 119 | if (!rwlock->writer_locked) 120 | panic("Attempted to downgrade a non-writer thread"); 121 | rwlock->writer_locked = false; 122 | rwlock->count++; 123 | cond_broadcast(&(rwlock->cv)); 124 | mutex_unlock(&(rwlock->m)); 125 | } 126 | 127 | -------------------------------------------------------------------------------- /kern/locks/sched_mutex.c: -------------------------------------------------------------------------------- 1 | /** @file sched_mutex_t.c 2 | * @brief Implementation for a scheduler lock 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /** 12 | * @brief Initializes a scheduler lock 13 | * 14 | * @param mp mutex to init 15 | * @param sched scheduler_t this lock protects 16 | * 17 | * @return 0 on success, negative error code otherwise 18 | * 19 | */ 20 | int sched_mutex_init( sched_mutex_t *mp, scheduler_t *sched) { 21 | if (mp == NULL || sched == NULL) return -1; 22 | mp->sched = sched; 23 | 24 | return 0; 25 | } 26 | 27 | /** 28 | * @brief Locks the scheduler by disabling interrupts only if the 29 | * scheduler has been started. This is to ensure interrupts are not 30 | * enabled/disabled unnecessarily while kernel is initializing 31 | * 32 | * Disabling interrupts ensures only the current thread has access 33 | * to the scheduler data structures. This also ensures that the kernel 34 | * cannot context switch to another thread via a timer interrupt. 35 | * 36 | * This function has no effect if the scheduler the lock protects 37 | * has not been started. 38 | * 39 | * @param mp mutex to lock 40 | * 41 | * @return void 42 | * 43 | */ 44 | void sched_mutex_lock( sched_mutex_t *mp ) { 45 | if (mp == NULL) return; 46 | if (mp->sched == NULL) return; 47 | 48 | /* Check if scheduler is started */ 49 | if (mp->sched->started) { 50 | disable_interrupts(); 51 | } 52 | } 53 | 54 | /** 55 | * @brief Unlocks the scheduler by renabling interrupts. This usually 56 | * follows a sched_mutex_lock(). Renables interrupts so that timer 57 | * interrupt can fire again and schedule threads to run. 58 | * 59 | * This function has no effect if the scheduler the lock protects 60 | * has not been started. 61 | * 62 | * @param mp mutex to lock 63 | * 64 | * @return void 65 | * 66 | */ 67 | void sched_mutex_unlock( sched_mutex_t *mp ) { 68 | if (mp == NULL) return; 69 | if (mp->sched == NULL) return; 70 | 71 | /* Check if scheduler is started */ 72 | if (mp->sched->started) { 73 | enable_interrupts(); 74 | } 75 | } 76 | 77 | /** 78 | * @brief Destroys a sched_mutex_t 79 | * 80 | * (Never called but here for completeness) 81 | * 82 | * @param mp mutex to destroy 83 | * 84 | * @return void 85 | * 86 | */ 87 | void sched_mutex_destroy( sched_mutex_t *mp) { 88 | mp->sched = NULL; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /kern/locks/sem.c: -------------------------------------------------------------------------------- 1 | /** @file sem.c 2 | * @brief This file defines the implementation to semaphores 3 | * 4 | * Our implementation of semaphores uses a linked list queue to store threads 5 | * that are currently waiting on the semaphore, a count to remember how many 6 | * resources are avaliable (or in need) and a mutex to protect the internals. 7 | * Semaphores use the same reject pointer to achieve "atomic unlock and 8 | * deschedule" as mutexes 9 | * 10 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 11 | * @bug No known bugs 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | typedef struct thr_metadata{ 24 | int tid; 25 | int reject; 26 | } thr_metadata_t; 27 | 28 | /* semaphore functions */ 29 | 30 | /** @brief Initializes a semaphore 31 | * 32 | * @param sem Pointer to the semaphore that is to be initialized 33 | * @param count Number of resource locks semaphore is intialized with 34 | * @return 0 on success, negative code on failure 35 | */ 36 | int sem_init( sem_t *sem, int count ) { 37 | if (sem == NULL || count < 0) return -1; 38 | sem->count = count; 39 | if (queue_init(&(sem->q)) < 0) return -1; 40 | if (mutex_init(&(sem->m)) < 0) return -1; 41 | 42 | return 0; 43 | } 44 | 45 | /** @brief Attempts to take a resource lock from semaphore, sleeps on failure 46 | * 47 | * @param sem Pointer to the semaphore 48 | * @return Void 49 | */ 50 | void sem_wait( sem_t *sem ) { 51 | if (sem == NULL) return; 52 | 53 | mutex_lock(&(sem->m)); 54 | 55 | /* declare interest in a resource from semaphore */ 56 | sem->count--; 57 | if (sem->count < 0) { 58 | /* no resources avaliable, sleep until awoken from sem_signal */ 59 | thr_metadata_t metadata = {.tid=thr_gettid(), .reject=0}; 60 | /* add self to waiting queue */ 61 | queue_enq(&(sem->q), (void *)&metadata); 62 | mutex_unlock(&(sem->m)); 63 | /* only deschedules if awoken by sem_signal */ 64 | while(!(metadata.reject)) { 65 | thr_kern_deschedule(&(metadata.reject)); 66 | } 67 | } else { 68 | /* resource avaliable! */ 69 | mutex_unlock(&(sem->m)); 70 | } 71 | } 72 | 73 | /** @brief Signals that a semaphore's resource is now avaliable and the first of 74 | * any threads waiting on a resource should be awoken. 75 | * 76 | * @param sem Pointer to the semaphore 77 | * @return Void 78 | */ 79 | void sem_signal( sem_t *sem ) { 80 | if (sem == NULL) return; 81 | mutex_lock(&(sem->m)); 82 | 83 | /* release a resource */ 84 | sem->count++; 85 | 86 | /* if anything is waiting on a resource, wake it up */ 87 | if (sem->count <= 0) { 88 | thr_metadata_t *temp; 89 | if(queue_deq(&(sem->q), (void **)(&temp)) < 0) { 90 | /* Empty queue, shouldn't happen unless semaphore was destroyed 91 | * in which case we will be lenient and simply unlock 92 | * and return */ 93 | mutex_unlock(&(sem->m)); 94 | return; 95 | } 96 | // Wake up waiting thread if necessary 97 | temp->reject = 1; 98 | thr_make_runnable(temp->tid); 99 | } 100 | mutex_unlock(&(sem->m)); 101 | } 102 | 103 | /** @brief Destroys a semaphore 104 | * 105 | * @param sem Pointer to the semaphore 106 | * @return Void 107 | */ 108 | void sem_destroy( sem_t *sem ) { 109 | if (sem == NULL) return; 110 | mutex_lock(&(sem->m)); 111 | queue_destroy(&(sem->q)); 112 | sem->count = -1; 113 | mutex_unlock(&(sem->m)); 114 | mutex_destroy(&(sem->m)); 115 | } 116 | 117 | int sem_get_value(sem_t *sem, int *sval){ 118 | if (sem == NULL || sval == NULL) return -1; 119 | mutex_lock(&(sem->m)); 120 | *sval = sem->count; 121 | mutex_unlock(&(sem->m)); 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /kern/malloc_wrappers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* safe versions of malloc functions */ 8 | void *malloc(size_t size) 9 | { 10 | 11 | mutex_lock(&heap_lock); 12 | void *ptr = _malloc(size); 13 | mutex_unlock(&heap_lock); 14 | return ptr; 15 | } 16 | 17 | void *memalign(size_t alignment, size_t size) 18 | { 19 | 20 | mutex_lock(&heap_lock); 21 | void *ptr = _memalign(alignment, size); 22 | mutex_unlock(&heap_lock); 23 | return ptr; 24 | } 25 | 26 | void *calloc(size_t nelt, size_t eltsize) 27 | { 28 | mutex_lock(&heap_lock); 29 | void *ptr = _calloc(nelt, eltsize); 30 | mutex_unlock(&heap_lock); 31 | return ptr; 32 | } 33 | 34 | void *realloc(void *buf, size_t new_size) 35 | { 36 | mutex_lock(&heap_lock); 37 | void *ptr = _realloc(buf, new_size); 38 | mutex_unlock(&heap_lock); 39 | return ptr; 40 | } 41 | 42 | void free(void *buf) 43 | { 44 | mutex_lock(&heap_lock); 45 | _free(buf); 46 | mutex_unlock(&heap_lock); 47 | return; 48 | } 49 | 50 | void *smalloc(size_t size) 51 | { 52 | mutex_lock(&heap_lock); 53 | void *ptr = _smalloc(size); 54 | mutex_unlock(&heap_lock); 55 | return ptr; 56 | } 57 | 58 | void *smemalign(size_t alignment, size_t size) 59 | { 60 | mutex_lock(&heap_lock); 61 | void *ptr = _smemalign(alignment, size); 62 | mutex_unlock(&heap_lock); 63 | return ptr; 64 | } 65 | 66 | void sfree(void *buf, size_t size) 67 | { 68 | mutex_lock(&heap_lock); 69 | _sfree(buf, size); 70 | mutex_unlock(&heap_lock); 71 | return; 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /kern/scheduler/thr_helpers_wrappers.S: -------------------------------------------------------------------------------- 1 | 2 | .macro build_iret_stack 3 | movl %esp, %eax /* Save current esp in eax */ 4 | push %ss /* Save ss */ 5 | addl $8, %eax /* Account for rtn address and arg */ 6 | pushl %eax /* Save esp */ 7 | pushf /* Save EFLAGS */ 8 | push %cs /* Save cs */ 9 | subl $8, %eax /* eax now points to rtn address */ 10 | pushl (%eax) /* Save rtn address */ 11 | .endm 12 | 13 | 14 | .macro save_regs 15 | subl $4, %esp /* Skip error code */ 16 | pushl $0 /* Store 0 in eax, in case of success */ 17 | pushl %ecx 18 | pushl %edx 19 | pushl %ebx 20 | subl $4, %esp /* Skip esp save */ 21 | pushl %ebp 22 | pushl %esi 23 | pushl %edi 24 | push %gs 25 | push %fs 26 | push %es 27 | push %ds 28 | .endm 29 | 30 | .macro restore_regs 31 | pop %ds 32 | pop %es 33 | pop %fs 34 | pop %gs 35 | popl %edi 36 | popl %esi 37 | popl %ebp 38 | addl $4, %esp 39 | popl %ebx 40 | popl %edx 41 | popl %ecx 42 | addl $4, %esp /* skip eax */ 43 | addl $4, %esp /* skip error code */ 44 | .endm 45 | 46 | .globl thr_kern_deschedule 47 | thr_kern_deschedule: 48 | /* Construct iret stack so we can context switch back */ 49 | build_iret_stack 50 | /* Save GP registers */ 51 | save_regs 52 | 53 | pushl 4(%eax) /* Push reject arg onto stack */ 54 | movl %esp, %eax 55 | addl $4, %eax /* eax now is esp before arg push */ 56 | pushl %eax /* Push old_esp arg onto stack */ 57 | call thr_deschedule 58 | /* This means that deschedule returned with an error 59 | * eax contains negative error code */ 60 | addl $8, %esp /* Skip two arguments */ 61 | /* Restore GP registers */ 62 | restore_regs 63 | /* Skip eax restore and iret stack arguments */ 64 | addl $20, %esp 65 | ret 66 | 67 | .globl thr_kern_yield 68 | thr_kern_yield: 69 | /* Construct iret stack so we can context switch back */ 70 | build_iret_stack 71 | /* Save GP registers */ 72 | save_regs 73 | 74 | pushl 4(%eax) /* Push tid arg onto stack */ 75 | movl %esp, %eax 76 | addl $4, %eax /* eax now is esp before arg push */ 77 | pushl %eax /* Push old_esp arg onto stack */ 78 | call thr_yield 79 | /* This means that yield returned with an error 80 | * eax contains negative error code */ 81 | addl $8, %esp /* Skip two arguments */ 82 | /* Restore GP registers */ 83 | restore_regs 84 | /* Skip eax restore and iret stack arguments */ 85 | addl $20, %esp 86 | ret 87 | 88 | 89 | -------------------------------------------------------------------------------- /kern/smp_glue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ##### ####### ####### ###### ### 4 | * # # # # # # # ### 5 | * # # # # # # ### 6 | * ##### # # # ###### # 7 | * # # # # # 8 | * # # # # # # ### 9 | * ##### # ####### # ### 10 | * 11 | * This file is included for completeness (having a tss_desc_create() 12 | * function is necessary to link against libsmp) but YOU ARE NOT EXPECTED 13 | * TO ACTUALLY USE IT unless it is the Spring semester of 2012. JUST 14 | * PRETEND YOU NEVER SAW IT HERE. If you have any questions about why 15 | * it is here, DELETE IT BEFORE ASKING, at which point you will be asking 16 | * a question about a file that does not exist, which is unlikely to be 17 | * productive. Fnord. 18 | * 19 | */ 20 | 21 | 22 | 23 | 24 | 25 | 26 | /* 27 | * 28 | * ##### ####### ####### ###### ### 29 | * # # # # # # # ### 30 | * # # # # # # ### 31 | * ##### # # # ###### # 32 | * # # # # # 33 | * # # # # # # ### 34 | * ##### # ####### # ### 35 | * 36 | * 37 | * This file NEEDS WORK or SHOULD BE DELETED (your choice). 38 | * 39 | * You are responsible for making tss_desc_create() work in accordance 40 | * with the specification provided in the handout. Your implementation 41 | * can live in this smp_glue.c file or elsewhere, as you choose. 42 | * 43 | * If you wish, you can add an AP entry-point function to this file, also 44 | * in accordance with the documentation found in the handout. 45 | * 46 | */ 47 | 48 | #include 49 | #include 50 | 51 | uint64_t 52 | tss_desc_create(void *tss, size_t tss_size) 53 | { 54 | uint64_t seg = 0LL; 55 | (void) tss_size; 56 | panic(__FILE__); 57 | return seg; 58 | } 59 | -------------------------------------------------------------------------------- /kern/special_register_cntrl/asm_functions.S: -------------------------------------------------------------------------------- 1 | .globl flush_tlb 2 | 3 | flush_tlb: 4 | movl 4(%esp), %eax 5 | invlpg (%eax) 6 | ret 7 | 8 | .globl set_cur_esp 9 | 10 | set_cur_esp: 11 | /* Save rtn address */ 12 | movl (%esp), %eax 13 | /* Move arg into esp */ 14 | movl 4(%esp), %esp 15 | pushl %eax 16 | ret 17 | -------------------------------------------------------------------------------- /kern/special_register_cntrl/spec_reg_wrappers.c: -------------------------------------------------------------------------------- 1 | /** @file special_reg_cntrl.h 2 | * @brief Specifies w 3 | * 4 | * @author Aatish Nayak (aatishn) 5 | * @author Christopher Wei (cjwei) 6 | * @bug No known bugs. 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #define ENABLE_PAGING_BIT 31 19 | 20 | #define DISABLE_CACHING_BIT 30 21 | 22 | #define PGE_FLAG_BIT 7 23 | 24 | #define EFLAGS_RESERVED_BIT 1 25 | #define EFLAGS_AC_BIT 18 26 | #define EFLAGS_IF_BIT 9 27 | #define EFLAGS_IOPL_BIT 12 28 | /** 29 | * @brief Sets top 20 bit of cr3 to page directory base address 30 | * 31 | * @param address of new page directory (should be page-aligned) 32 | */ 33 | void set_pdbr(uint32_t new_pdbr) { 34 | uint32_t empty_cr3 = get_cr3() & LSB_12_MASK; 35 | uint32_t new_cr3 = new_pdbr | empty_cr3; 36 | 37 | set_cr3(new_cr3); 38 | } 39 | 40 | void flush_all_tlb(void){ 41 | set_cr3(get_cr3()); 42 | } 43 | 44 | uint32_t get_pdbr() { 45 | return get_cr3(); 46 | } 47 | 48 | 49 | void enable_paging(void) { 50 | uint32_t new_cr0 = get_cr0() | (SET << ENABLE_PAGING_BIT) | (SET << DISABLE_CACHING_BIT); 51 | 52 | set_cr0(new_cr0); 53 | } 54 | 55 | void enable_pge(void) { 56 | uint32_t new_cr4 = get_cr4() | (SET << PGE_FLAG_BIT); 57 | 58 | set_cr4(new_cr4); 59 | } 60 | 61 | uint32_t get_user_eflags() { 62 | uint32_t cur_eflags = get_eflags(); 63 | 64 | uint32_t e_f = cur_eflags | (UNSET << EFLAGS_AC_BIT) | 65 | (SET << EFLAGS_RESERVED_BIT) | (SET << EFLAGS_IF_BIT); 66 | 67 | return e_f; 68 | 69 | } 70 | 71 | -------------------------------------------------------------------------------- /kern/virtual_mem_mgmt/mem_section.c: -------------------------------------------------------------------------------- 1 | /** @file mem_section.c 2 | * @brief Implementation of memory section functions 3 | * 4 | * Memory sections provide us an easy way to define a section of memory that we 5 | * can perscribe particular permissions as well as keep track of start and stop 6 | * addresses. 7 | * 8 | * @author Aatish Nayak (aatishn) 9 | * @author Christopher Wei (cjwei) 10 | * @bug No known bugs. 11 | */ 12 | #include 13 | 14 | #include 15 | 16 | /** @brief Initializes a memory section with given parameters 17 | * @param ms The memory section 18 | * @param addr The starting address of the memory section 19 | * @param len The length of the memory section in bytes 20 | * @param pde_flags The flags for the page directory entry 21 | * @param pte_flags The flags for the page table entry 22 | * @return 0 on success, -1 on failure */ 23 | int ms_init(mem_section_t *ms, uint32_t addr, uint32_t len, 24 | uint32_t pde_flags, uint32_t pte_flags) { 25 | if (ms == NULL) return -1; 26 | ms->v_addr_start = addr; 27 | ms->len = len; 28 | ms->pde_f = pde_flags; 29 | ms->pte_f = pte_flags; 30 | 31 | return 0; 32 | } 33 | 34 | /** @brief Gets the bounding addresses of multiple memory sections 35 | * @param secs The array of sections 36 | * @param num_secs The number of sections in the array 37 | * @param addr_low Where the lower bound address is stored 38 | * @param addr_high Where the upper bound address is stored 39 | * @return 0 on success, -1 on failure */ 40 | int ms_get_bounding_addr(mem_section_t *secs, uint32_t num_secs, 41 | uint32_t *addr_low, uint32_t *addr_high){ 42 | if (secs == NULL || num_secs == 0 || addr_low == NULL || 43 | addr_high == NULL) return -1; 44 | int s; 45 | uint32_t low = 0xFFFFFFFF; 46 | uint32_t high = 0x0; 47 | for (s = 0; s < num_secs; s++){ 48 | /* Don't consider section if it is empty */ 49 | if (secs[s].len == 0) continue; 50 | uint32_t c_low = secs[s].v_addr_start; 51 | uint32_t c_high = secs[s].v_addr_start + (secs[s].len - 1); 52 | if (c_low < low) low = c_low; 53 | if (c_high > high) high = c_high; 54 | } 55 | if (low > high) return -1; 56 | *addr_low = low; 57 | *addr_high = high; 58 | return 0; 59 | } 60 | 61 | 62 | /** @brief Given an address range, finds a memory section which contains 63 | * part or all of the given address range from an array of sections 64 | * @param secs The array of memory sections 65 | * @param num_secs The length of secs 66 | * @param addr_low The lower bound range of address space 67 | * @param addr_high The upper bound range of address space 68 | * @param result Where the result is stored 69 | * @return 0 on success, -1 on invalid input, 1 on valid input but no bounding 70 | * section found */ 71 | int ms_get_bounding_section(mem_section_t *secs, uint32_t num_secs, 72 | uint32_t addr_low, uint32_t addr_high, mem_section_t **result){ 73 | /* low and high are inclusive */ 74 | if (secs == NULL || num_secs == 0 || (addr_low > addr_high) || 75 | result == NULL) return -1; 76 | int i; 77 | for (i=0; i < num_secs; i++){ 78 | uint32_t c_low = secs[i].v_addr_start; 79 | uint32_t c_high = secs[i].v_addr_start + (secs[i].len - 1); 80 | if ((c_low <= addr_low && addr_low <= c_high) || 81 | (c_low <= addr_high && addr_high <= c_high)){ 82 | *result = &(secs[i]); 83 | return 0; 84 | } 85 | } 86 | /* no result found */ 87 | return 1; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This is a shell script for keeping the support code 4 | # for the 15-410 kernel up to date. 5 | # 6 | # Ivan Jager (aij) 7 | # 8 | ########################################################### 9 | # Usage: 10 | # update.sh [query] 11 | # 12 | # : 13 | # afs - update files by comparing md5sums 14 | # taken from course afs space. If 15 | # files don't match digests, grab 16 | # updated files from course afs space. 17 | # 18 | # web - same but from course webspace. 19 | # 20 | # offline - build support libraries using 21 | # code present in local directories. 22 | # This method is *not* recommended for 23 | # typical use. 24 | # 25 | ########################################################### 26 | 27 | 28 | # location of official support code and libraries 29 | AFS_PATH=${AFS_PATH-/afs/cs.cmu.edu/academic/class/15410-s16/Web/update/proj3} 30 | WEB_URL=${WEB_URL-'http://www.cs.cmu.edu/~410-s16/update/proj3'} 31 | 32 | # the name of the file containing the MD5s for the files we want to update 33 | WHAT=all.md5s 34 | 35 | #fetches a file from the update area, either to a specific destination, or 36 | # to the same relative filename if no destination is specified 37 | function fetch () { 38 | local mode=$1 39 | local from=$2 40 | local to=${3:-$2} 41 | # make the directory to put the file in if it doesn't exist 42 | test -d `dirname "$to"` || mkdir -p `dirname "$to"` 43 | 44 | case "$METHOD" in 45 | afs) 46 | cp "$AFS_PATH/$from" "$to.tmp" && mv "$to.tmp" "$to" ;; 47 | web) 48 | wget -nv "$WEB_URL/$from" -O "$to.tmp" && mv "$to.tmp" "$to" ;; 49 | query) 50 | test -f "$to" && echo "$from hasn't been updated since `stat -c %y $to`" || echo "File $to is missing" 51 | NEEDS_UPDATING=true 52 | return ;; 53 | *) echo fetch: method invalid: $METHOD; exit 2 ;; 54 | esac && 55 | chmod $mode "$to" 56 | } 57 | 58 | # reads a list of md5s to check and update from stdin 59 | function do_update () { 60 | rc=0 61 | while read mode md5 filename 62 | #for filename in `md5sum -c | tee >(cat >&3) | grep -v OK$ | sed 's/: FAILED.*//g'` 63 | do 64 | current=`md5sum "$filename" | cut -d ' ' -f 1` 65 | if [ "$current" != "$md5" ] 66 | then 67 | echo Update "$filename" 68 | fetch $mode "$filename" || rc=$? 69 | fi 70 | done 3>&1 71 | test -z "$NEEDS_UPDATING" || { /bin/echo -e '****\nUpdates are available. Please run make update sometime soon.\n****\7'; sleep 1; /bin/echo -e '\7'; sleep 1; /bin/echo -e '\7'; } 72 | return $rc 73 | } 74 | 75 | 76 | # find out what method we were told to use 77 | # One of afs, web, or offline. (rsync coming "soon") 78 | case $1 in 79 | '') 80 | { test -d $AFS_PATH && METHOD=afs ; } || \ 81 | { which wget >/dev/null 2>&1 && METHOD=web ; } || \ 82 | METHOD=offline 83 | ;; 84 | afs|web|offline) 85 | METHOD=$1 86 | ;; 87 | *) 88 | echo usage: $0 'afs|web|offline' '[query]' 89 | exit 9 90 | ;; 91 | esac 92 | 93 | if [ "$METHOD" = offline ] ; then 94 | echo UPDATE METHOD IS OFFLINE. This is not recommended. 95 | echo Be sure to update and make sure your code works before handing it in. 96 | sleep 3 97 | exit 98 | fi 99 | 100 | # this could be changed to not make a copy when updating from AFS 101 | fetch 644 $WHAT .md5s || { echo Failed to fetch the list of MD5s.; exit 1; } 102 | echo "# Fetched by $0 $@ at `date`" >>.md5s 103 | 104 | test "$2" = query && METHOD=query 105 | 106 | grep -v '^#' .md5s | do_update 107 | 108 | -------------------------------------------------------------------------------- /user/files/dog.txt: -------------------------------------------------------------------------------- 1 | Woof! Woof! 2 | ^__^ 3 | |..| 4 | 5 | \__/ 6 | 7 | (Translation: "A cat is here") 8 | 9 | -------------------------------------------------------------------------------- /user/files/donkey.txt: -------------------------------------------------------------------------------- 1 | ,--._ 2 | `. `. ,-. 3 | `.`. `. ,' ) 4 | \`: \ ,' / 5 | \`: ),. ,-' , / 6 | ( : |:::. ,-' ,' ,' 7 | `.;: |:::: ,' ,:' ,-' 8 | ,^-. `,--.-/ ,' _,' 9 | (__ ^ ( _,' 10 | __((o\ __ ,-' 11 | ,',-. ((o) / 12 | ,',' `. `-- ( 13 | |' ,` \ hrrrr DONKEY 14 | | ,:' ` | 15 | ( `-- :-. | 16 | `,.__ ,-,' ; 17 | (_/ `,__,-' / ,' 18 | |\`--|_/,' ,' _,' 19 | \_^--^,',-' -'( 20 | (_`--',' `-. 21 | ;;;;' ::::.`------. -------------------------------------------------------------------------------- /user/files/shrek.txt: -------------------------------------------------------------------------------- 1 | _____ 2 | ,-' `._ 3 | ,' `. ,-. 4 | ,' \ ),.\ 5 | ,. / \ /( \; 6 | /'\\ ,o. ,ooooo. \ ,' `-') 7 | )) )`. d8P"Y8. ,8P"""""Y8. `' .--"' 8 | (`-' `Y' `Y8 dP `' / 9 | `----.( __ ` ,' ,---. ( 10 | ),--.`. ( ;,---. ) 11 | / \O_,' ) \ \O_,' | 12 | ; `-- ,' `---' | 13 | | -' `. | 14 | _; , ) : 15 | _.'| `.:._ ,.::" `.. | 16 | --' | .' """ ` |`. 17 | | :; : : _. |`.`.-'--. 18 | | ' . : :__.,'|/ | \ 19 | ` \--.__.-'|_|_|-/ / ) 20 | \ \_ `--^"__,' , | 21 | -hrr- ; ` `--^---' ,' | 22 | \ ` / / 23 | \ ` _ _ / 24 | \ ` / 25 | \ ' ,' 26 | `. , _,' 27 | `-.___.---' 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /user/inc/README.userinc: -------------------------------------------------------------------------------- 1 | This directory exists for you to store header files that are not 2 | private to your libraries; those can go in user/libfoo/. 3 | -------------------------------------------------------------------------------- /user/inc/cond_type.h: -------------------------------------------------------------------------------- 1 | /** @file cond_type.h 2 | * @brief This file defines the type for condition variables. 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | #ifndef _COND_TYPE_H 8 | #define _COND_TYPE_H 9 | 10 | #include 11 | #include 12 | 13 | /** @brief defines a conditional variable struct and type */ 14 | typedef struct cond { 15 | /** @brief The internal conditional variable mutex for it's queue */ 16 | mutex_t m; 17 | /** @brief The queue of waiting threads */ 18 | ll_t q; 19 | } cond_t; 20 | 21 | #endif /* _COND_TYPE_H */ 22 | -------------------------------------------------------------------------------- /user/inc/mutex_type.h: -------------------------------------------------------------------------------- 1 | /** @file mutex_type.h 2 | * @brief This file defines the type for mutexes. 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | #ifndef _MUTEX_TYPE_H 8 | #define _MUTEX_TYPE_H 9 | 10 | /* C Standard Lib includes */ 11 | #include 12 | 13 | /** @brief Defines a mutex struct and type */ 14 | typedef struct mutex { 15 | /** @brief Represents whether or not mutex is free or taken */ 16 | int lock; 17 | } mutex_t; 18 | 19 | #endif /* _MUTEX_TYPE_H */ 20 | -------------------------------------------------------------------------------- /user/inc/rwlock_type.h: -------------------------------------------------------------------------------- 1 | /** @file rwlock_type.h 2 | * @brief This file defines the type for reader/writer locks. 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | #ifndef _RWLOCK_TYPE_H 8 | #define _RWLOCK_TYPE_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | /** @brief Defines a struct and type for reader/writer lock */ 15 | typedef struct rwlock { 16 | /** @brief Internal mutex protecting the actual lock */ 17 | mutex_t m; 18 | /** @brief Condition variable used to signal writer */ 19 | cond_t cv; 20 | /** @brief Number of readers currently in critical section */ 21 | int count; 22 | /** @brief Whether or not a writer holds the lock */ 23 | bool writer_locked; 24 | } rwlock_t; 25 | 26 | #endif /* _RWLOCK_TYPE_H */ 27 | -------------------------------------------------------------------------------- /user/inc/sem_type.h: -------------------------------------------------------------------------------- 1 | /** @file sem_type.h 2 | * @brief This file defines the type for semaphores. 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | #ifndef _SEM_TYPE_H 8 | #define _SEM_TYPE_H 9 | 10 | #include 11 | #include 12 | 13 | /** @brief Defines a semaphore struct and type */ 14 | typedef struct sem { 15 | /** @brief The number of resources currently avaliable from sem */ 16 | int count; 17 | /** @brief The internal mutex that protects q */ 18 | mutex_t m; 19 | /** @brief Queue of waiting threads on sem */ 20 | ll_t q; 21 | } sem_t; 22 | 23 | #endif /* _SEM_TYPE_H */ 24 | -------------------------------------------------------------------------------- /user/libautostack/autostack.c: -------------------------------------------------------------------------------- 1 | /** @file autostack.c 2 | * @brief Contains implementation for autostack growth handler 3 | * 4 | * For legacy single-threaded programs, this registers an exception handler 5 | * that overwrites the default exception handler and looks for page faults. 6 | * This allows us to extend the stack space by essentially doubling the 7 | * amount of stack allocated with calls to newpage. We chose this method of 8 | * increasing stack space as it allows us to quickly resolve page faults 9 | * with a minimal calls to new_pages. In the case that the exception is not 10 | * a pagefault or not related to stack growth (such as a dereference of NULL) 11 | * then our custom exception handler will not be reinstalled and the program 12 | * will resume at the faulting address thus causing the default handler to be 13 | * called. 14 | * 15 | * Another interesting design choice is to malloc the exception stack, which 16 | * is given a stack size of 1 page which is plenty. The reasoning behind this 17 | * design decision is that it would be incredibly messy and hard to either 18 | * shift the stack down by 1 page to make room for an exception stack, or 19 | * fragmenting the parent thread's stack by sticking it directly underneath 20 | * the current stack pointeer. The exception stack will be freed in thr_init. 21 | * In the off chance thr_init is never called, we will have memory leaks: 22 | * which is not okay, but I guess it happens. 23 | * 24 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 25 | * @bug No known bugs 26 | */ 27 | 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | #include "contracts.h" 37 | 38 | #define STACK_GROWTH_THRESHOLD (PAGE_SIZE * 32) 39 | 40 | /** @brief External address to the top of the user space stack */ 41 | extern void *STACK_TOP; 42 | /** @brief External address to the bottom of the user space stack */ 43 | extern void *STACK_BOTTOM; 44 | 45 | /** @brief Pointer to the top of the exception stack */ 46 | void *exception_stack; 47 | 48 | /** @brief A custom page fault handler that increases stack space on 49 | * page fault related exceptions 50 | * @param args The arguments passed in to page_fault_handler 51 | * @param ureg The context saved before fault occured 52 | * @return Void 53 | */ 54 | void page_fault_handler(void* args, ureg_t *ureg) { 55 | if (ureg->cause == SWEXN_CAUSE_PAGEFAULT && (void *)ureg->cr2 != NULL) { 56 | 57 | /* ensure that args.stack_high is never lower than args.stack_low */ 58 | ASSERT((uint32_t)STACK_TOP >= (uint32_t)STACK_BOTTOM); 59 | 60 | /* Check to see if we can resolve address access by extending stack 61 | * by one page */ 62 | if ((uint32_t)STACK_BOTTOM - STACK_GROWTH_THRESHOLD >= ureg->cr2 63 | || ureg->cr2 < 0x1000000){ 64 | /* probably not a stack address, then */ 65 | swexn(NULL,NULL, args, ureg); 66 | } 67 | 68 | lprintf("Autostack grown encountered!"); 69 | 70 | void *new_stack_low = 71 | (void *)((uint32_t)STACK_BOTTOM - PAGE_SIZE); 72 | 73 | /* if unable to allocate more pages restore context without 74 | * reregistering */ 75 | if (new_pages(new_stack_low, PAGE_SIZE) < 0) 76 | swexn(NULL,NULL, args, ureg); 77 | 78 | STACK_BOTTOM = new_stack_low; 79 | 80 | /* only re-register the handler if we catch a page fault 81 | * after registering handler, restore context */ 82 | if (swexn((void*) exception_stack, page_fault_handler, 83 | (void*) args, ureg) < 0){ 84 | panic("Couldn't register autostack handler after page fault"); 85 | } 86 | /* SHOULD NEVER GET HERE */ 87 | panic("Should never get here"); 88 | } 89 | /* restore context, do not register another handler */ 90 | swexn(NULL,NULL, args, ureg); 91 | } 92 | 93 | /** @brief Sets up automatic stack growth handler 94 | * @param stack_high The top of the currently allocated stack 95 | * @param stack_low The bottom of the currently allocated stack 96 | * @return Void 97 | */ 98 | void install_autostack(void *stack_high, void *stack_low) { 99 | /* update the global variables */ 100 | STACK_TOP = stack_high; 101 | STACK_BOTTOM = stack_low; 102 | /* allocate a exception stack in the heap */ 103 | exception_stack = _malloc(PAGE_SIZE); 104 | /* install custom exception handler */ 105 | if (swexn(exception_stack, page_fault_handler, NULL, NULL) < 0) 106 | panic("Couldn't register autostack handler"); 107 | } 108 | -------------------------------------------------------------------------------- /user/libsyscall/syscall.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * ##### ####### ####### ###### ### 4 | * # # # # # # # ### 5 | * # # # # # # ### 6 | * ##### # # # ###### # 7 | * # # # # # 8 | * # # # # # # ### 9 | * ##### # ####### # ### 10 | * 11 | * 12 | * You should probably NOT EDIT THIS FILE in any way! 13 | * 14 | * You should probably DELETE this file, insert all of your 15 | * Project 2 stub files, and edit config.mk accordingly. 16 | * 17 | * Alternatively, you can DELETE pieces from this file as 18 | * you write your stubs. But if you forget half-way through 19 | * that that's the plan, you'll have a fun debugging problem! 20 | * 21 | */ 22 | 23 | #include 24 | 25 | int fork(void) 26 | { 27 | return -1; 28 | } 29 | 30 | int exec(char *execname, char *argvec[]) 31 | { 32 | return -1; 33 | } 34 | 35 | void set_status(int status) 36 | { 37 | return; 38 | } 39 | 40 | volatile int placate_the_compiler; 41 | void vanish(void) 42 | { 43 | int blackhole = 867-5309; 44 | 45 | blackhole ^= blackhole; 46 | blackhole /= blackhole; 47 | *(int *) blackhole = blackhole; /* won't get here */ 48 | while (1) 49 | ++placate_the_compiler; 50 | } 51 | 52 | int wait(int *status_ptr) 53 | { 54 | return -1; 55 | } 56 | 57 | int yield(int pid) 58 | { 59 | return -1; 60 | } 61 | 62 | int deschedule(int *flag) 63 | { 64 | return -1; 65 | } 66 | 67 | int make_runnable(int pid) 68 | { 69 | return -1; 70 | } 71 | 72 | int gettid(void) 73 | { 74 | return -1; 75 | } 76 | 77 | int sleep(int ticks) 78 | { 79 | return -1; 80 | } 81 | 82 | int swexn(void *esp3, swexn_handler_t eip, void *arg, ureg_t *newureg) 83 | { 84 | return -1; 85 | } 86 | 87 | char getchar(void) 88 | { 89 | return -1; 90 | } 91 | 92 | int readline(int size, char *buf) 93 | { 94 | return -1; 95 | } 96 | 97 | int print(int size, char *buf) 98 | { 99 | return -1; 100 | } 101 | 102 | int set_term_color(int color) 103 | { 104 | return -1; 105 | } 106 | 107 | int get_cursor_pos(int *row, int *col) 108 | { 109 | return -1; 110 | } 111 | 112 | int set_cursor_pos(int row, int col) 113 | { 114 | return -1; 115 | } 116 | 117 | void halt(void) 118 | { 119 | while (1) 120 | continue; 121 | } 122 | 123 | int readfile(char *filename, char *buf, int count, int offset) 124 | { 125 | return -1; 126 | } 127 | 128 | void task_vanish(int status) 129 | { 130 | status ^= status; 131 | status /= status; 132 | while (1) 133 | continue; 134 | } 135 | 136 | int new_pages(void * addr, int len) 137 | { 138 | return -1; 139 | } 140 | 141 | int remove_pages(void * addr) 142 | { 143 | return -1; 144 | } 145 | 146 | unsigned int get_ticks() 147 | { 148 | return 1; 149 | } 150 | 151 | void misbehave(int mode) 152 | { 153 | return; 154 | } 155 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_deschedule.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_deschedule.S 2 | * 3 | * @brief implements deschedule stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl deschedule 11 | 12 | deschedule: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $DESCHEDULE_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_exec.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_exec.S 2 | * 3 | * @brief implements exec stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl exec 11 | 12 | 13 | exec: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $EXEC_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_fork.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_fork.S 2 | * 3 | * @brief implements fork stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl fork 11 | 12 | fork: 13 | int $FORK_INT 14 | ret 15 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_get_cursor_pos.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_get_cursor_pos.S 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl get_cursor_pos 11 | 12 | 13 | get_cursor_pos: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $GET_CURSOR_POS_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_get_ticks.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_get_ticks.S 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl get_ticks 11 | 12 | get_ticks: 13 | int $GET_TICKS_INT 14 | ret 15 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_getchar.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_getchar.S 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl getchar 11 | 12 | getchar: 13 | int $GETCHAR_INT 14 | ret 15 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_gettid.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_gettid.S 2 | * 3 | * @brief implements gettid stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl gettid 11 | 12 | 13 | gettid: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $GETTID_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_halt.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_halt.S 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl halt 11 | 12 | halt: 13 | int $HALT_INT 14 | ret 15 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_make_runnable.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_make_runnable.S 2 | * 3 | * @brief implements make_runnable stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl make_runnable 11 | 12 | make_runnable: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $MAKE_RUNNABLE_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_misbehave.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_misbehave.S 2 | * 3 | * @brief implements misbehave stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl misbehave 11 | 12 | misbehave: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $MISBEHAVE_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_new_pages.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_new_pages.c 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl new_pages 11 | 12 | 13 | new_pages: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $NEW_PAGES_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_print.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_print.S 2 | * 3 | * @brief implements print stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl print 11 | 12 | 13 | print: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $PRINT_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_readfile.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_readfile.S 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl readfile 11 | 12 | 13 | readfile: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $READFILE_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_readline.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_readline.c 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl readline 11 | 12 | 13 | readline: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $READLINE_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_remove_pages.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_remove_pages.c 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl remove_pages 11 | 12 | remove_pages: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $REMOVE_PAGES_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_set_cursor_pos.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_set_cursor_pos.S 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl set_cursor_pos 11 | 12 | 13 | set_cursor_pos: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $SET_CURSOR_POS_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_set_status.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_set_status.S 2 | * 3 | * @brief implements set_status stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl set_status 11 | 12 | set_status: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $SET_STATUS_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_set_term_color.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_set_term_color.c 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl set_term_color 11 | 12 | set_term_color: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $SET_TERM_COLOR_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_sleep.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_sleep.c 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl sleep 11 | 12 | sleep: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $SLEEP_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_swexn.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_swexn.c 2 | * 3 | * @brief 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl swexn 11 | 12 | 13 | swexn: 14 | push %esi /* save esi */ 15 | mov %esp, %esi /* copy stack pointer into esi */ 16 | add $8, %esi /* increment esi by 8 so it points at 1st argument */ 17 | int $SWEXN_INT /* call trap */ 18 | pop %esi /* restore esi */ 19 | ret 20 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_task_vanish.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_task_vanish.S 2 | * 3 | * @brief implements task_vanish stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug 6 | */ 7 | 8 | #include 9 | 10 | .globl task_vanish 11 | 12 | task_vanish: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $TASK_VANISH_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_vanish.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_vanish.S 2 | * 3 | * @brief implements vanish stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl vanish 11 | 12 | vanish: 13 | int $VANISH_INT 14 | ret 15 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_wait.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_wait.S 2 | * 3 | * @brief implements wait stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl wait 11 | 12 | wait: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $WAIT_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libsyscall/syscall_yield.S: -------------------------------------------------------------------------------- 1 | /** @file syscall_yield.S 2 | * 3 | * @brief implements yield stub 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #include 9 | 10 | .globl yield 11 | 12 | yield: 13 | push %esi /* save context */ 14 | mov 8(%esp), %esi /* store 1st argument into esi */ 15 | int $YIELD_INT /* call trap */ 16 | pop %esi /* restore context */ 17 | ret 18 | -------------------------------------------------------------------------------- /user/libthread/asm_helpers.S: -------------------------------------------------------------------------------- 1 | /** 2 | * @file asm_helpers.S 3 | * @brief Assembly helper functions for mutex, cond_vars, and threads 4 | * @author Aatish Nayak (aatishn) and Christopher Wei (cjwei) 5 | * @bug No known bugs 6 | */ 7 | 8 | .globl xchng 9 | 10 | xchng: 11 | push %ebx 12 | movl 8(%esp), %ebx // address to lock 13 | movl 12(%esp), %eax // value to be stored into lock 14 | xchg %eax, (%ebx) 15 | pop %ebx 16 | ret 17 | 18 | #include 19 | 20 | .globl thread_fork 21 | 22 | thread_fork: 23 | // Push callee saved registers 24 | push %ebx 25 | 26 | // Save new_esp in reg 27 | movl 8(%esp), %ebx 28 | // Save func in reg 29 | movl 12(%esp), %ecx 30 | // Save args in reg 31 | movl 16(%esp), %edx 32 | // Save handler install in reg 33 | 34 | int $THREAD_FORK_INT 35 | 36 | cmp $0, %eax // if (eax == 0) 37 | jne parent 38 | // Move new_esp into esp/ebp reg 39 | movl %ebx, %esp 40 | movl %ebx, %ebp 41 | // Save caller saved register 42 | push %edx 43 | // Call handler install 44 | call install_exception_handler 45 | 46 | // "Call" thread function 47 | call %ecx 48 | // CHILD SHOULD NVR GET HERE 49 | push %eax 50 | call thr_exit 51 | 52 | parent: 53 | // Restore callee saved registers 54 | //pop %edi 55 | pop %ebx 56 | ret 57 | 58 | .globl get_esp 59 | get_esp: 60 | movl %esp, %eax // Get current esp 61 | add $4, %eax // Account for pushed rtn addr 62 | ret 63 | -------------------------------------------------------------------------------- /user/libthread/cond.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cond.c 3 | * @brief The implementation for condition variables. 4 | * 5 | * To implement condition variables, we have an internal mutex that protects 6 | * a queue. Threads waiting on a condition variable will enqueue all the 7 | * information needed to awaken the thread in the cv's queue. One interesting 8 | * problem we had while designing cond_wait is that there is a gap between 9 | * the time we unlock the condition variable's mutex, thus allowing for other 10 | * threads to signal the current thread, and the time we deschedule. We have 11 | * to make this "atomic" otherwise our thread could sleep forever. In order 12 | * to prevent a cond_signal from signally a about-to-sleep thread, we have 13 | * a reject pointer that will essentially reject the deschedule if it is set 14 | * due to another thread calling signal. Additionally, we found that some of 15 | * the misbehave modes caused sleeping threads to run without a cond_signal 16 | * so we wrapped this area in a while(!reject) so it can only awaken from a 17 | * cond_signal. 18 | * 19 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 20 | * @bug No known bugs 21 | */ 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /** @brief Initializes a condition variable 32 | * 33 | * @param cv Pointer to the condition variable that is to be initialized 34 | * @return 0 on success, negative code on failure 35 | */ 36 | int cond_init( cond_t *cv ) { 37 | if (cv == NULL) return -1; 38 | if (ll_init(&cv->q) < 0) return -1; 39 | if (mutex_init(&cv->m) < 0) return -1; 40 | return 0; 41 | } 42 | 43 | /** @brief Destroys a condition variable 44 | * 45 | * @param cv Pointer to the condition variable that is to be destroyed 46 | * @return Void 47 | */ 48 | void cond_destroy( cond_t *cv ) { 49 | if (cv == NULL) return; 50 | mutex_lock(&(cv->m)); 51 | ll_destroy(&(cv->q)); 52 | mutex_unlock(&(cv->m)); 53 | mutex_destroy(&(cv->m)); 54 | } 55 | 56 | /** @brief Deschedules current thread until a condition is satisfied 57 | * 58 | * @param cv Pointer to the condition variable that specifies the condition 59 | * that is to be satisfied 60 | * @param world_mp Pointer to the mutex that protects the global resource 61 | * @return Void 62 | */ 63 | void cond_wait( cond_t *cv, mutex_t *world_mp ) { 64 | if (cv == NULL || world_mp == NULL) return; 65 | /* grab the internal cond mutex - we can now safely enqueue to cv queue */ 66 | mutex_lock(&(cv->m)); 67 | 68 | /* create a new thread struct */ 69 | thread_t thread; 70 | thread.k_tid = gettid(); 71 | /* reject is another condition that will ensure that only a call to 72 | * cond_signal can awaken the current thread and any external reasons for 73 | * the thread awakening are essentially ignored and put back to sleep */ 74 | thread.reject = 0; 75 | 76 | ll_add(&(cv->q), &thread); 77 | mutex_unlock(world_mp); 78 | /* let go of cv mutex; current thread can now be preempted by cond_signal */ 79 | mutex_unlock(&(cv->m)); 80 | /* in the case that cond_signal has occured between mutex_unlock(&(cv->mp)) 81 | * and this check, reject will be 1 so the thread will not be descheduled. 82 | * if the thread is made runnable for some other reason besides cond_signal, 83 | * it will simply go back to sleep. */ 84 | while(!(thread.reject)) 85 | deschedule(&(thread.reject)); 86 | 87 | /* upon returning, free allocated struct */ 88 | //free(thread); 89 | mutex_lock(world_mp); 90 | } 91 | 92 | /** @brief Signals that a condition has been updated and a single waiting thread 93 | * should one exist should be awoken 94 | * 95 | * @param cv Pointer to the condition variable that is to be signaled 96 | * @return Void 97 | */ 98 | void cond_signal( cond_t *cv ) { 99 | if (cv == NULL) return; 100 | mutex_lock(&(cv->m)); 101 | thread_t *temp; 102 | /* dequeue cv's linked list into temp */ 103 | if(ll_deq(&(cv->q), (void **)(&temp)) < 0) { 104 | /* no threads waiting to be signaled */ 105 | mutex_unlock(&(cv->m)); 106 | return; 107 | } 108 | /* signal to waiting thread that it should not deschedule itself if it 109 | * has not already and awaken thread */ 110 | temp->reject = 1; 111 | make_runnable(temp->k_tid); 112 | mutex_unlock(&(cv->m)); 113 | } 114 | 115 | 116 | /** @brief Signals that a condition has been updated and all waiting threads 117 | * should be signaled if any exist 118 | * 119 | * @param cv Pointer to the condition variable that is to be signaled 120 | * @return Void 121 | */ 122 | void cond_broadcast( cond_t *cv ) { 123 | if (cv == NULL) return; 124 | mutex_lock(&(cv->m)); 125 | thread_t *thr; 126 | while(ll_deq(&(cv->q), (void **)(&thr)) == 0){ 127 | thr->reject = 1; 128 | make_runnable(thr->k_tid); 129 | } 130 | mutex_unlock(&(cv->m)); 131 | } 132 | 133 | 134 | -------------------------------------------------------------------------------- /user/libthread/ll.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ll.c 3 | * 4 | * @brief Linked List implementation alternatively used as a queue 5 | * 6 | * @author Aatish Nayak (aatishn) and Christopher Wei (cjwei) 7 | * @bug No known bugs 8 | */ 9 | 10 | /* C Standard Library includes */ 11 | #include 12 | #include 13 | #include 14 | 15 | /* Thread Library includes*/ 16 | #include 17 | 18 | /** 19 | * @brief Initializes a linked list with appropriate values 20 | * 21 | * @param ll Pointer to linked list to initialize 22 | * 23 | * @return 0 on success, -1 on error 24 | */ 25 | int ll_init(ll_t *ll) { 26 | if (ll == NULL) return -1; 27 | 28 | ll->size = 0; 29 | ll->head = NULL; 30 | ll->tail = NULL; 31 | return 0; 32 | } 33 | 34 | /** 35 | * @brief Add to end of linked list provided 36 | * Can be used as enqueue operation for a linked list queue 37 | * 38 | * @param ll Pointer to linked list to add to 39 | * @param value Value to add to list 40 | * 41 | * @return 0 on success, negative error code on failure 42 | * -1 if q is NULL 43 | * -2 if malloc() fails 44 | * 45 | */ 46 | int ll_add(ll_t *ll, void *value){ 47 | if (ll == NULL) 48 | return -1; 49 | 50 | /* make a new node */ 51 | ll_node_t *new_node = (ll_node_t *)malloc(sizeof(ll_node_t)); 52 | if (new_node == NULL) 53 | return -2; 54 | new_node->e = value; 55 | new_node->next = NULL; 56 | 57 | if (ll->head == NULL){ 58 | ASSERT(ll->tail == NULL); 59 | /* no elements in queue yet */ 60 | ll->head = new_node; 61 | ll->tail = new_node; 62 | } else { 63 | /* link new node and update queue's back pointer */ 64 | ll->tail->next = new_node; 65 | ll->tail = new_node; 66 | } 67 | ll->size++; 68 | return 0; 69 | } 70 | 71 | /** 72 | * @brief Dequeue an element from the end of a linked list 73 | * 74 | * @param ll Pointer to linked list to dequeue from 75 | * @param val Address to put the dequeued value 76 | * 77 | * @return 0 on success, -1 on error 78 | */ 79 | int ll_deq(ll_t *ll, void **val){ 80 | if (ll == NULL){ 81 | return -1; 82 | } 83 | /* save head of queue */ 84 | ll_node_t *head = ll->head; 85 | if (ll->size == 0) 86 | return -1; 87 | if (head == ll->tail){ 88 | ll->tail = NULL; 89 | } 90 | /* update head of queue */ 91 | ll->head = head->next; 92 | /* save value before freeing struct */ 93 | *val = head->e; 94 | free(head); 95 | ll->size--; 96 | return 0; 97 | } 98 | 99 | /** 100 | * @brief Remove a linked list node with data matching the argument 101 | * 102 | * @param ll Pointer to linked list to remove from 103 | * @param data Data to search for 104 | * 105 | * @return 0 on success, negative error code if node not found or error 106 | * 107 | */ 108 | int ll_remove(ll_t *ll, void* data) { 109 | if (ll == NULL) return -1; 110 | ll_node_t *node = ll->head; 111 | while(node != NULL && node->next != NULL && node->next->e != data) { 112 | node = node->next; 113 | } 114 | if (node == NULL) return -1; 115 | // Only one node with data desired 116 | else if (node->e == data) { 117 | free(node); 118 | ll->head = NULL; 119 | ll->tail = NULL; 120 | } else if (node->next == NULL) { 121 | return -1; 122 | } else { 123 | ll_node_t *next = node->next; 124 | node->next = next->next; 125 | free(next); 126 | } 127 | ll->size--; 128 | return 0; 129 | 130 | } 131 | 132 | /** 133 | * @brief Destroys and frees all nodes of a linked list 134 | * 135 | * @param ll Pointer to linked list to destroy 136 | * 137 | * @return void 138 | */ 139 | void ll_destroy(ll_t *ll){ 140 | if (ll == NULL) return; 141 | ll_node_t *ptr = ll->head; 142 | ll_node_t *next; 143 | while (ptr != NULL){ 144 | next = ptr->next; 145 | free(ptr); 146 | ptr = next; 147 | } 148 | } 149 | 150 | /** 151 | * @brief Finds data in the linked list that satisfies the condition 152 | * func(data) == c_val 153 | * 154 | * @param ll Pointer to linked list 155 | * @param func Generic function that transforms data into form desired 156 | * @param c_val Value to match with return value of func 157 | * @param val_ptr Address to store found data in 158 | * 159 | * @return 0 on success, negative if error or data not found 160 | * 161 | */ 162 | int ll_find(ll_t *ll, void *(*func)(void*), void *c_val, void **val_ptr){ 163 | if (ll == NULL || func == NULL){ 164 | return -1; 165 | } 166 | ll_node_t *node = ll->head; 167 | 168 | /* Loop through linked list */ 169 | while (node != NULL){ 170 | if ((*func)(node->e) == c_val){ 171 | *val_ptr = node->e; 172 | return 0; 173 | } 174 | node = node->next; 175 | } 176 | return -1; /* not found */ 177 | } 178 | 179 | 180 | -------------------------------------------------------------------------------- /user/libthread/ll.h: -------------------------------------------------------------------------------- 1 | /** @file ll.h 2 | * @brief Defines interface for linked list 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | * @bug No known bugs 5 | */ 6 | 7 | 8 | #ifndef _LL_H_ 9 | #define _LL_H_ 10 | 11 | /** 12 | * @brief Struct representing a singly linked linked list node 13 | */ 14 | typedef struct ll_node { 15 | /** @brief Data the ll_node_t holds */ 16 | void *e; 17 | 18 | /** @brief Pointer pointing to next node */ 19 | struct ll_node *next; 20 | } ll_node_t; 21 | 22 | /** 23 | * @brief Struct representing a linked list 24 | */ 25 | typedef struct ll { 26 | 27 | /** @brief Pointer to head of the linked list */ 28 | ll_node_t *head; 29 | 30 | /** @brief Pointer to tail of the linked list */ 31 | ll_node_t *tail; 32 | 33 | /** @brief Size of the linked list */ 34 | unsigned int size; 35 | } ll_t; 36 | 37 | int ll_init(ll_t *ll); 38 | int ll_add(ll_t *ll, void *value); 39 | int ll_deq(ll_t *ll, void **value_ptr); 40 | void ll_destroy(ll_t *ll); 41 | 42 | int ll_find(ll_t *ll, void *(*func)(void*), void *c_val, void **val_ptr); 43 | int ll_remove(ll_t *tt, void* data); 44 | 45 | #endif /* _LL_H_ */ 46 | -------------------------------------------------------------------------------- /user/libthread/malloc.c: -------------------------------------------------------------------------------- 1 | /** @file malloc.c 2 | * @brief This file defines the implementation of thread safe memory 3 | * allocation functions 4 | * 5 | * We make heap memory writes thread safe by using a global heap mutex that 6 | * only allows one thread to make changes to the heap. Although this design 7 | * choice seems to be slow (sequentially slow, to be exact) it would be 8 | * impossible to predict which memory locations _malloc may look through 9 | * without direct access to the implementation and thus improbable to allow 10 | * mutual exclusion to select sections of the heap. 11 | * 12 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 13 | * @bug No known bugs 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /** @brief Thread safe malloc 23 | * @param __size Size of memory to be allocated 24 | * @return Pointer to allocated memeory 25 | */ 26 | void *malloc(size_t __size) 27 | { 28 | mutex_lock(&heap_mutex); 29 | void *ptr = _malloc(__size); 30 | mutex_unlock(&heap_mutex); 31 | return ptr; 32 | } 33 | 34 | /** @brief Thread safe calloc 35 | * @param __nelt Number of elements to be allocated 36 | * @param __eltsize Size of memory to be allocated per element 37 | * @return Pointer to allocated memeory 38 | */ 39 | void *calloc(size_t __nelt, size_t __eltsize) 40 | { 41 | mutex_lock(&heap_mutex); 42 | void *ptr = _calloc(__nelt, __eltsize); 43 | mutex_unlock(&heap_mutex); 44 | return ptr; 45 | } 46 | 47 | /** @brief Thread safe realloc 48 | * @param __buf Pointer to source buffer 49 | * @param __new_size New size to be reallocated 50 | * @return Pointer to allocated memeory 51 | */ 52 | void *realloc(void *__buf, size_t __new_size) 53 | { 54 | mutex_lock(&heap_mutex); 55 | void *ptr = _realloc(__buf, __new_size); 56 | mutex_unlock(&heap_mutex); 57 | return ptr; 58 | } 59 | 60 | /** @brief Thread safe free 61 | * @param __buf Pointer to source buffer to be freed 62 | * @return Void 63 | */ 64 | void free(void *__buf) 65 | { 66 | mutex_lock(&heap_mutex); 67 | _free(__buf); 68 | mutex_unlock(&heap_mutex); 69 | } 70 | -------------------------------------------------------------------------------- /user/libthread/mutex.c: -------------------------------------------------------------------------------- 1 | /** @file mutex.c 2 | * @brief This file implements mutexes. 3 | * 4 | * We use a very simple implementation of mutexes which simply tries to 5 | * atomically exchange a 0 into the mutex until it passes. This does not 6 | * ensure unbounded waiting unlike methods such as TestAndSet, but also 7 | * does not need to know exactly how many threads are running in order to 8 | * determine some arbitration method. Indeed a thread could be starved out 9 | * due to purely bad luck or a naughty kernel; this is a consideration we 10 | * made when deciding to not implement a unbounded waiting algorithm 11 | * 12 | * @author Christopher Wei (cjwei) Aatish Nayak (aatishn) 13 | * @bug No known bugs 14 | */ 15 | 16 | /* C Standard Lib specific Includes */ 17 | #include 18 | #include 19 | #include 20 | 21 | /* P1 Specific includes */ 22 | #include 23 | #include 24 | 25 | /** @brief Initializes a mutex 26 | * @param mp Pointer to mutex to be intialized 27 | * @return 0 on success, negative code on error 28 | */ 29 | int mutex_init( mutex_t *mp ){ 30 | if (mp == NULL) return -1; 31 | mp->lock = 1; 32 | return 0; 33 | } 34 | 35 | /** @brief Destroys a mutex 36 | * @param mp Pointer to mutex to be destroyed 37 | * @return Void 38 | */ 39 | void mutex_destroy( mutex_t *mp ){ 40 | mp->lock = -1; 41 | return; 42 | } 43 | 44 | /** @brief Locks a mutex and hangs until successful 45 | * @param mp Pointer to mutex to be locked 46 | * @return Void 47 | */ 48 | void mutex_lock( mutex_t *mp ){ 49 | /* Keep trying to until lock is free and key is accepted */ 50 | while (!xchng(&mp->lock, 0)) { 51 | /* Yield to next thread to avoid busy waiting */ 52 | yield(-1); 53 | } 54 | mp->lock = 0; 55 | return; 56 | } 57 | 58 | /** @brief Unlocks a mutex 59 | * @param mp Pointer to mutex to be unlocked 60 | * @return Void 61 | */ 62 | void mutex_unlock( mutex_t *mp ){ 63 | xchng(&mp->lock, 1); 64 | return; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /user/libthread/panic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996-1995 The University of Utah and 3 | * the Computer Systems Laboratory at the University of Utah (CSL). 4 | * All rights reserved. 5 | * 6 | * Permission to use, copy, modify and distribute this software is hereby 7 | * granted provided that (1) source code retains these copyright, permission, 8 | * and disclaimer notices, and (2) redistributions including binaries 9 | * reproduce the notices in supporting documentation, and (3) all advertising 10 | * materials mentioning features or use of this software display the following 11 | * acknowledgement: ``This product includes software developed by the 12 | * Computer Systems Laboratory at the University of Utah.'' 13 | * 14 | * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS 15 | * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF 16 | * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 | * 18 | * CSL requests users of this software to return to csl-dist@cs.utah.edu any 19 | * improvements that they make and grant CSL redistribution rights. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | /* @brief Wrapper function that is called on assertion fails 30 | * @param fmt String format to be printed 31 | * @param ... Arguments to string format 32 | * @return Does not return 33 | */ 34 | void panic(const char *fmt, ...) 35 | { 36 | va_list vl; 37 | char buf[80]; 38 | 39 | va_start(vl, fmt); 40 | vsnprintf(buf, sizeof (buf), fmt, vl); 41 | va_end(vl); 42 | lprintf(buf); 43 | 44 | va_start(vl, fmt); 45 | vprintf(fmt, vl); 46 | va_end(vl); 47 | printf("\n"); 48 | /* just halt; something went terribly wrong and the kernel is very 49 | * unlikely to recover, so we should just stop all processes. */ 50 | halt(); 51 | } 52 | -------------------------------------------------------------------------------- /user/libthread/rwlock.c: -------------------------------------------------------------------------------- 1 | /** @file rwlock.c 2 | * @brief This file implements readers/writers locks 3 | * 4 | * We have decide on implementing a reader writer lock that gives priority 5 | * to the writer. The thought process behind this is that a writer request 6 | * means that something in the shared resource has inherently changed and 7 | * future reads should wait until the update has occured before reading. 8 | * We implement this using a mutex to protect internal values, a condition 9 | * variable used to signal sleeping readers and writers, a count to keep 10 | * track of the number of readers currently reading (which is used to signal 11 | * when it reachs 0) and a writer_locked boolean to prevent further requests 12 | * from happening until that writer has been serviced. 13 | * 14 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 15 | * @bug No known bugs 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | /* readers/writers lock functions */ 27 | 28 | /** @brief Initializes a reader writer lock 29 | * 30 | * @param rwlock The pointer to the r/w lock to be initialized 31 | * @return 0 on success, -1 on failure 32 | */ 33 | int rwlock_init( rwlock_t *rwlock ){ 34 | if (rwlock == NULL) return -1; 35 | if (mutex_init(&(rwlock->m)) < 0) return -1; 36 | if (cond_init(&(rwlock->cv)) < 0) return -1; 37 | rwlock->count = 0; 38 | rwlock->writer_locked = false; 39 | return 0; 40 | } 41 | 42 | /** @brief Locks the rwlock 43 | * 44 | * @param rwlock The pointer to the r/w lock to be locked 45 | * @param type The integer code defining the type of lock requested 46 | * @return Void 47 | */ 48 | void rwlock_lock( rwlock_t *rwlock, int type ){ 49 | if (rwlock == NULL) return; 50 | if (type != RWLOCK_WRITE && type != RWLOCK_READ) 51 | panic("Invalid type supplied to rwlock_lock"); 52 | 53 | mutex_lock(&(rwlock->m)); 54 | if (rwlock->count < 0) 55 | panic("Attempted to lock a invalid rwlock"); 56 | 57 | if (type == RWLOCK_READ){ 58 | /* wait until a writer has finished using critical section */ 59 | while(rwlock->writer_locked){ 60 | cond_wait(&(rwlock->cv), &(rwlock->m)); 61 | } 62 | /* increment count to let future writers know we are reading 63 | * the critical section */ 64 | rwlock->count++; 65 | } else { 66 | /* wait until any current writers are finished */ 67 | while (rwlock->writer_locked || rwlock->count > 0){ 68 | cond_wait(&(rwlock->cv), &(rwlock->m)); 69 | } 70 | rwlock->writer_locked = true; 71 | } 72 | mutex_unlock(&(rwlock->m)); 73 | } 74 | 75 | /** @brief unlocks the rwlock 76 | * 77 | * @param rwlock The pointer to the r/w lock to be locked 78 | * @return Void 79 | */ 80 | void rwlock_unlock( rwlock_t *rwlock ){ 81 | if (rwlock == NULL) return; 82 | mutex_lock(&(rwlock->m)); 83 | if (rwlock->count <= 0 && !rwlock->writer_locked) 84 | panic("Attempted to unlock rwlock that is already unlocked"); 85 | if (rwlock->writer_locked){ 86 | rwlock->writer_locked = false; 87 | cond_broadcast(&(rwlock->cv)); 88 | } else { 89 | rwlock->count--; 90 | /* since count > 0, everything waiting on cv is a writer, therefore 91 | * wake up next writer */ 92 | if (rwlock->count == 0) cond_signal(&(rwlock->cv)); 93 | } 94 | mutex_unlock(&(rwlock->m)); 95 | } 96 | 97 | 98 | /** @brief Destroys the rwlock 99 | * 100 | * @param rwlock The lock to be destroyed 101 | * @return Void 102 | */ 103 | void rwlock_destroy( rwlock_t *rwlock ){ 104 | if (rwlock == NULL) return; 105 | mutex_lock(&(rwlock->m)); 106 | rwlock->count = -1; 107 | cond_destroy(&(rwlock->cv)); 108 | mutex_unlock(&(rwlock->m)); 109 | mutex_destroy(&(rwlock->m)); 110 | } 111 | /** @brief Converts a writer lock to a reader lock 112 | * 113 | * @param rwlock The lock to be downgraded 114 | * @return Void 115 | */ 116 | void rwlock_downgrade( rwlock_t *rwlock){ 117 | if (rwlock == NULL) return; 118 | mutex_lock(&(rwlock->m)); 119 | if (!rwlock->writer_locked) 120 | panic("Attempted to downgrade a non-writer thread"); 121 | rwlock->writer_locked = false; 122 | rwlock->count++; 123 | cond_broadcast(&(rwlock->cv)); 124 | mutex_unlock(&(rwlock->m)); 125 | } 126 | 127 | -------------------------------------------------------------------------------- /user/libthread/sem.c: -------------------------------------------------------------------------------- 1 | /** @file sem.c 2 | * @brief This file defines the implementation to semaphores 3 | * 4 | * Our implementation of semaphores uses a linked list queue to store threads 5 | * that are currently waiting on the semaphore, a count to remember how many 6 | * resources are avaliable (or in need) and a mutex to protect the internals. 7 | * Semaphores use the same reject pointer to achieve "atomic unlock and 8 | * deschedule" as mutexes 9 | * 10 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 11 | * @bug No known bugs 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /* semaphore functions */ 23 | 24 | /** @brief Initializes a semaphore 25 | * 26 | * @param sem Pointer to the semaphore that is to be initialized 27 | * @param count Number of resource locks semaphore is intialized with 28 | * @return 0 on success, negative code on failure 29 | */ 30 | int sem_init( sem_t *sem, int count ) { 31 | if (sem == NULL || count <= 0) return -1; 32 | sem->count = count; 33 | if (ll_init(&(sem->q)) < 0) return -1; 34 | if (mutex_init(&(sem->m)) < 0) return -1; 35 | 36 | return 0; 37 | } 38 | 39 | /** @brief Attempts to take a resource lock from semaphore, sleeps on failure 40 | * 41 | * @param sem Pointer to the semaphore 42 | * @return Void 43 | */ 44 | void sem_wait( sem_t *sem ) { 45 | if (sem == NULL) return; 46 | 47 | mutex_lock(&(sem->m)); 48 | 49 | /* declare interest in a resource from semaphore */ 50 | sem->count--; 51 | if (sem->count < 0) { 52 | /* no resources avaliable, sleep until awoken from sem_signal */ 53 | thread_t thread; 54 | thread.k_tid = gettid(); 55 | thread.reject = 0; 56 | 57 | ll_add(&(sem->q), &thread); 58 | 59 | mutex_unlock(&(sem->m)); 60 | /* only deschedules if awoken by sem_signal (see cond.c:cond_wait) */ 61 | while(!(thread.reject)) 62 | deschedule(&(thread.reject)); 63 | } else { 64 | /* resource avaliable! */ 65 | mutex_unlock(&(sem->m)); 66 | } 67 | } 68 | 69 | /** @brief Signals that a semaphore's resource is now avaliable and the first of 70 | * any threads waiting on a resource should be awoken. 71 | * 72 | * @param sem Pointer to the semaphore 73 | * @return Void 74 | */ 75 | void sem_signal( sem_t *sem ) { 76 | if (sem == NULL) return; 77 | mutex_lock(&(sem->m)); 78 | 79 | /* release a resource */ 80 | sem->count++; 81 | 82 | /* if anything is waiting on a resource, wake it up */ 83 | if (sem->count <= 0) { 84 | thread_t *temp; 85 | if(ll_deq(&(sem->q), (void **)(&temp)) < 0) { 86 | /* Empty queue, shouldn't happen unless semaphore was destroyed 87 | * in which case we will be lenient and simply unlock and return */ 88 | mutex_unlock(&(sem->m)); 89 | return; 90 | } 91 | // Wake up waiting thread if necessary 92 | temp->reject = 1; 93 | make_runnable(temp->k_tid); 94 | } 95 | mutex_unlock(&(sem->m)); 96 | } 97 | 98 | /** @brief Destroys a semaphore 99 | * 100 | * @param sem Pointer to the semaphore 101 | * @return Void 102 | */ 103 | void sem_destroy( sem_t *sem ) { 104 | if (sem == NULL) return; 105 | mutex_lock(&(sem->m)); 106 | ll_destroy(&(sem->q)); 107 | sem->count = -1; 108 | mutex_unlock(&(sem->m)); 109 | mutex_destroy(&(sem->m)); 110 | } 111 | 112 | -------------------------------------------------------------------------------- /user/libthread/thr_internals.h: -------------------------------------------------------------------------------- 1 | /** @file thr_internals.h 2 | * @brief Defines internal variables and assembly functions 3 | * 4 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 5 | * @bug No known bugs 6 | */ 7 | 8 | #ifndef THR_INTERNALS_H 9 | #define THR_INTERNALS_H 10 | 11 | /* Standard C library includes */ 12 | #include 13 | 14 | /* Thread Lib specific includes */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | /** @brief Denotes a thread is dead and can be recycled */ 21 | #define THR_STATUS_DEAD 1 22 | /** @brief Denotes a thread has exited but has not been joined on */ 23 | #define THR_STATUS_ZOMBIE 2 24 | /** @brief Denotes a thread is currently running or sleeping */ 25 | #define THR_STATUS_ALIVE 0 26 | 27 | 28 | /** @brief Used to store metadata about a thread */ 29 | typedef struct { 30 | /** 31 | * @brief Whether or not a join has already occured on a thread 32 | * 33 | * Used to ensure multiple threads can't join on the same thread 34 | * at the same time 35 | * */ 36 | bool pending_join; 37 | 38 | /** 39 | * @brief The kernel thread id 40 | * 41 | * The thread library's way of identifying each thread. 42 | * This is the same as the kernel defined id returned by gettid() 43 | * */ 44 | int k_tid; 45 | 46 | /** 47 | * @brief The reject pointer used by semaphores or condition variables 48 | * 49 | * This allows atomicity for mutex unlock and deschedule in condition 50 | * variables and semaphores. 51 | * 52 | * */ 53 | int reject; 54 | 55 | /** 56 | * @brief The thread's current status (running, zombie, dead) 57 | * 58 | * */ 59 | int status; 60 | 61 | /** 62 | * @brief The exit status of a thread 63 | * 64 | * Used in thr_join to report exit status back to calling thread 65 | * */ 66 | void *exit_status; 67 | 68 | /** 69 | * @brief The condition variable used to signal joining threads 70 | * about the current thread's status 71 | * */ 72 | cond_t join_cv; 73 | 74 | /** 75 | * @brief Mutex for protecting struct accesses 76 | * */ 77 | mutex_t m; 78 | 79 | /** 80 | * @brief The top address of a thread's stack 81 | * 82 | * If a thread becomes DEAD, subsequent threads can claim this 83 | * stack space. 84 | * */ 85 | void *stack_top; 86 | 87 | } thread_t; 88 | 89 | /************************************************************* 90 | * Thread Library Global Variables * 91 | * ***********************************************************/ 92 | 93 | /** @brief Amount of stack space given to each thread */ 94 | unsigned int thread_stack_size; 95 | 96 | /** @brief The page aligned stack top of the parent thread after converting to 97 | * multithreaded mode */ 98 | void* parent_stack_top; 99 | 100 | /** @brief Reader-Writer lock that protects the thread_pool linked list */ 101 | rwlock_t thread_pool_lock; 102 | 103 | /** @brief List of all threads that have been allocated space in the stack */ 104 | ll_t thread_pool; 105 | 106 | /** @brief Pointer to top of allocated user stack space */ 107 | void *STACK_TOP; 108 | 109 | /** @brief Pointer to bottom of allocated user stack space */ 110 | void *STACK_BOTTOM; 111 | 112 | /** @brief mutex used to protect the heap from multiple coinciding writes */ 113 | mutex_t heap_mutex; 114 | 115 | /** @brief Stack used in handling thread exception/crashes */ 116 | void *thr_exception_stack; 117 | 118 | /** 119 | * Docs in thread.c 120 | */ 121 | void install_exception_handler(void); 122 | 123 | 124 | 125 | /************************************************************* 126 | * Assembly Functions Headers * 127 | * ***********************************************************/ 128 | 129 | /** @brief Atomically set *lock = val and return previous value 130 | * of lock 131 | * 132 | * @param lock Lock to set 133 | * @param val Value to set lock to 134 | * 135 | * @return Old value of lock 136 | * 137 | */ 138 | int xchng(int* lock, int val); 139 | 140 | /** @brief calls system call thread_fork 141 | * 142 | * @param new_esp The new thread's stack pointer that is to be set 143 | * @param func The function that is to be called in the new thread 144 | * @param args The arguments provided to func 145 | * 146 | * @return thread ID of newly forked thread 147 | */ 148 | int thread_fork(void *new_esp, void *(*func)(void*), void *args); 149 | 150 | /** @brief Gets current thread's stack pointer 151 | * 152 | * @return current esp register 153 | */ 154 | void* get_esp(void); 155 | 156 | #endif /* THR_INTERNALS_H */ 157 | -------------------------------------------------------------------------------- /user/progs/test_console_io.c: -------------------------------------------------------------------------------- 1 | /** @file test_console_io.c 2 | * @author Christopher Wei (cjwei) 3 | * @covers set_term_color get_cursor_pos set_cursor_pos print 4 | * @brief prints "Ho Ho Ho" in various colors at various positions 5 | * @public yes 6 | * @for p3 7 | * @status done 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | int main(){ 16 | lprintf("Starting test"); 17 | int fgnd = 0; 18 | int bgnd = 0; 19 | while(1){ 20 | fgnd = ((fgnd + 1) % 0x10); 21 | bgnd = ((bgnd + 1) % 0x8); 22 | int color = fgnd | (bgnd << 4); 23 | set_term_color(color); 24 | int row, col; 25 | get_cursor_pos(&row, &col); 26 | print(2, "Ho"); 27 | set_cursor_pos(((row+1) % 20), ((col+2) % 78)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /user/progs/test_cs.c: -------------------------------------------------------------------------------- 1 | /** @file test_cs.c 2 | * @author Aatish Nayak (aatishn) 3 | * @brief Tests to see if context switch works 4 | * @public yes 5 | * @for p3 6 | * @status done 7 | */ 8 | 9 | /* Includes */ 10 | #include 11 | #include /* for lprintf */ 12 | #include 13 | #include 14 | 15 | 16 | int j = 5; 17 | /* Main */ 18 | int main() { 19 | while(1){ 20 | j++; 21 | printf("j = %d\n", j); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /user/progs/test_cyclone.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cyclone.c 3 | * @brief A test of basic thread behaviors with misbehavior 4 | * 5 | * This test spawns a thread and then attempts to join it 6 | * with each misbehavior mode. 7 | * 8 | * **> Public: Yes 9 | * **> Covers: thr_create,thr_join,thr_exit 10 | * **> NeedsWork: Yes 11 | * **> For: P2 12 | * **> Authors: mberman,jge 13 | * **> Notes: Looks good 14 | * 15 | * @author Michael Berman (mberman) 16 | * @author Based on thr_join0_test by Joey Echeverria (jge) 17 | * @bug No known bugs. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "410_tests.h" 27 | DEF_TEST_NAME("cyclone:"); 28 | 29 | #define STACK_SIZE 4096 30 | #define MAX_MISBEHAVE 64 31 | 32 | int thread_exited = 0; 33 | int thr_exit_return = 0; 34 | 35 | void* thread1(void* token); 36 | 37 | /** 38 | * @brief Spawns the thread and attempts to join 39 | * 40 | * @param argc The number of arguments 41 | * @param argv The argument array 42 | * @return 1 on success, < 0 on error. 43 | */ 44 | int main(int argc, char *argv[]) 45 | { 46 | int spawn_tid; 47 | int status; 48 | int i; 49 | 50 | REPORT_LOCAL_INIT; 51 | 52 | REPORT_START_CMPLT; 53 | 54 | REPORT_ON_ERR(thr_init(STACK_SIZE)); 55 | 56 | for (i = 0; i < MAX_MISBEHAVE; i++) { 57 | thread_exited = 0; 58 | thr_exit_return = 0; 59 | 60 | lprintf("%s%strying mode %d",TEST_PFX,test_name,i); 61 | //misbehave(i); 62 | 63 | REPORT_FAILOUT_ON_ERR((spawn_tid = thr_create(thread1, (void*)i))); 64 | 65 | REPORT_FAILOUT_ON_ERR(thr_join(spawn_tid, (void**)&status)); 66 | 67 | if(thread_exited == 0) { 68 | REPORT_MISC("Thread joined before exited"); 69 | REPORT_END_FAIL; 70 | thr_exit((void *)-40); 71 | } 72 | 73 | if(status != i) { 74 | REPORT_ERR("wrong token returned as status: ",status); 75 | REPORT_END_FAIL; 76 | thr_exit((void *)-60); 77 | } 78 | 79 | if(thr_exit_return) { 80 | REPORT_MISC("ERR: thr_exit() returned."); 81 | REPORT_END_FAIL; 82 | thr_exit((void *)-80); 83 | } 84 | } 85 | 86 | 87 | REPORT_END_SUCCESS; 88 | thr_exit((void *)0); 89 | 90 | REPORT_MISC("ERR: thr_exit() returned."); 91 | REPORT_END_FAIL; 92 | thr_exit((void *)-80); 93 | return (-80); // getting increasingly desperate here 94 | } 95 | 96 | /** 97 | * @brief Simply exit 98 | * 99 | * @param token An integer token to pass to thr_exit 100 | * @return The passed in token. 101 | */ 102 | void* thread1(void* token) 103 | { 104 | thread_exited = 1; 105 | thr_exit(token); 106 | thr_exit_return = 1; 107 | 108 | return token; 109 | } 110 | -------------------------------------------------------------------------------- /user/progs/test_deschedule.c: -------------------------------------------------------------------------------- 1 | /** @file test_deschedule.c 2 | * @author Christopher Wei (cjwei) 3 | * @covers gettid fork deschedule make_runnable 4 | * @brief forks a new process and deschedules until the new process wakes the 5 | * parent up 6 | * @public yes 7 | * @for p3 8 | * @status done 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | int main(){ 15 | int reject = 0; 16 | int parent_tid = gettid(); 17 | int child_tid = fork(); 18 | if (child_tid != 0) { 19 | lprintf("Parent sleeping!"); 20 | deschedule(&reject); 21 | lprintf("Parent woke up!!"); 22 | } 23 | int j; 24 | for(j = 0 ; j < 10000 ; j++); 25 | if (child_tid == 0 && make_runnable(parent_tid) < 0) { 26 | lprintf("Parent not asleep!"); 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /user/progs/test_div0.c: -------------------------------------------------------------------------------- 1 | /* @file test_div0 2 | * @author Christopher Wei (cjwei) 3 | * @brief Tests divide by zero handler and swexn (div by 0 doesnt generate 4 | * an error code is this is really testing that logic) 5 | * @public yes 6 | * @for p3 7 | * @status done 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "410_tests.h" 15 | 16 | DEF_TEST_NAME("test_div0:"); 17 | 18 | #define STAQ_SIZE (4096) 19 | char exn_staq[STAQ_SIZE]; 20 | #define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-7])) 21 | 22 | void success(){ 23 | REPORT_MISC("Success!"); 24 | exit(0); 25 | } 26 | 27 | 28 | void handler(void *arg, ureg_t *uregs){ 29 | /* catch div by 0 error */ 30 | REPORT_MISC("Hello from a handler"); 31 | if (uregs->cause != SWEXN_CAUSE_DIVIDE){ 32 | REPORT_MISC("not a divide by zero error!"); 33 | } 34 | if (uregs == NULL){ 35 | REPORT_MISC("bad uregs"); 36 | } 37 | /* jump to "success" upon return */ 38 | uregs->eip = (int)success; 39 | swexn(EXN_STAQ_TOP, handler, NULL, uregs); 40 | } 41 | 42 | 43 | int main(){ 44 | int x = 1; 45 | int y = 0; 46 | 47 | /* install handler */ 48 | int ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); 49 | if (ret < 0){ 50 | REPORT_MISC("Uh oh! Swexn failed!"); 51 | } 52 | /* generate div by 0 error */ 53 | int z = x/y; 54 | REPORT_MISC("Oops! Should not have gotten here"); 55 | return z; 56 | } 57 | -------------------------------------------------------------------------------- /user/progs/test_exec1.c: -------------------------------------------------------------------------------- 1 | /** @file user/progs/test_exec1.c 2 | * @author mpa 3 | * @brief Tests basic functionality of exec() 4 | * @public yes 5 | * @for p3 6 | * @covers exec 7 | * @status done 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "410_tests.h" 15 | 16 | DEF_TEST_NAME("exec_basic:"); 17 | 18 | int main(int argc, char** argv) 19 | { 20 | 21 | int tid = fork(); 22 | if (tid == 0) { 23 | char *args[] = {(char*) 0xdeadd00d, (char*)0xdeadbeef, 0}; 24 | int ret = exec("actual_wait", args); 25 | lprintf("Exec returned: %d", ret); 26 | exit(ret); 27 | } 28 | int status; 29 | wait(&status); 30 | exit(0); 31 | } 32 | -------------------------------------------------------------------------------- /user/progs/test_foo.c: -------------------------------------------------------------------------------- 1 | /** @file test_foo.c 2 | * @author Aatish Nayak (aatishn) 3 | * @brief Tests context switch 4 | * @public yes 5 | * @for p3 6 | * @status done 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | int main(){ 14 | int i = fork(); 15 | while(1){ 16 | printf("foo %d\n", i); 17 | yield(-1); 18 | } 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /user/progs/test_gettid.c: -------------------------------------------------------------------------------- 1 | /** @file 410user/progs/getpid_test1.c 2 | * @author zra 3 | * @brief Tests gettid(). 4 | * @public yes 5 | * @for p2 p3 6 | * @covers gettid 7 | * @status done 8 | */ 9 | 10 | /* Includes */ 11 | #include /* for getpid */ 12 | #include /* for exit */ 13 | #include /* for lprintf */ 14 | #include "410_tests.h" 15 | #include 16 | 17 | DEF_TEST_NAME("getpid_test1:"); 18 | 19 | /* Main */ 20 | int main() { 21 | int pid; 22 | 23 | report_start(START_CMPLT); 24 | pid = gettid(); 25 | lprintf("%s my pid is: %d", test_name, pid); 26 | 27 | if(pid == gettid()) { 28 | report_end(END_SUCCESS); 29 | } else { 30 | report_end(END_FAIL); 31 | } 32 | 33 | exit(0); 34 | } 35 | -------------------------------------------------------------------------------- /user/progs/test_hello.c: -------------------------------------------------------------------------------- 1 | /** @file test_hello.c 2 | * @author Aatish Nayak (aatishn) 3 | * @brief forks and execs into "test_foo" and context switches between the 4 | * parent and child process. 5 | * @public yes 6 | * @for p3 7 | * @status done 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main(){ 16 | int tid = fork(); 17 | lprintf("tid = %d", tid); 18 | if (tid == 0){ 19 | while (1){ 20 | printf("Hello\n"); 21 | yield(-1); 22 | } 23 | } else { 24 | char *argv[] = {"test_foo", NULL}; 25 | exec("test_foo", argv); 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /user/progs/test_mem_mgmt.c: -------------------------------------------------------------------------------- 1 | /** @file test_mem_mgmt.c 2 | * @author Christopher Wei 3 | * @brief Tests various cases for new_pages and remove_pages 4 | * @public yes 5 | * @for p3 6 | * @status done 7 | */ 8 | 9 | /* Includes */ 10 | #include 11 | #include /* for lprintf */ 12 | #include 13 | #include 14 | 15 | /* Main */ 16 | int main() { 17 | if (new_pages((void *)0xFFFFE000, PAGE_SIZE) < 0){ 18 | lprintf("failed to allocate a page"); 19 | return -1; 20 | } 21 | lprintf ("Allocated 0xFFFFE000"); 22 | if (new_pages((void *)0xFFFFE000, PAGE_SIZE) == 0){ 23 | lprintf("allocated the same page twice"); 24 | return -1; 25 | } 26 | if (new_pages((void *)0xFFFFB000, 3*PAGE_SIZE) < 0){ 27 | lprintf("failed to allocate multiple pages"); 28 | return -1; 29 | } 30 | lprintf("Allocated 0xFFFFB000 - 0xFFFFDFFF"); 31 | /* now check to see if pages are actually mapped */ 32 | int *foo = (int *)0xFFFFE000; 33 | int i; 34 | for (i = 0; i < PAGE_SIZE/(sizeof(int)); i++){ 35 | foo[i] = i; 36 | } 37 | 38 | if (remove_pages((void *)0x1000000) == 0){ 39 | lprintf("removed a non-user allocated page"); 40 | return -1; 41 | } 42 | if (remove_pages((void *)0xC000000) == 0){ 43 | lprintf("removed a non-allocated page"); 44 | return -1; 45 | } 46 | if (remove_pages((void *)0xFFFFE000) < 0){ 47 | lprintf("failed to remove a single page"); 48 | return -1; 49 | } 50 | lprintf("passed 1"); 51 | if (remove_pages((void *)0xFFFFF000) == 0){ 52 | lprintf("removed a user space, non new_pages page"); 53 | return -1; 54 | } 55 | lprintf("passed 2"); 56 | if (remove_pages((void *)0xFFFFC000) == 0){ 57 | lprintf("removed the middle of a user allocated page"); 58 | return -1; 59 | } 60 | lprintf("passed 3"); 61 | if (remove_pages((void *)0xFFFFD000) == 0){ 62 | lprintf("removed the end of a user allocated page"); 63 | return -1; 64 | } 65 | lprintf("passed 4"); 66 | if (remove_pages((void *)0xFFFFB000) < 0){ 67 | lprintf("failed to remove_pages"); 68 | } 69 | 70 | lprintf("All tests passed if we page fault NOW!"); 71 | int foobar = *((int *)0xFFFFD000); 72 | lprintf("Uh oh, page not really removed"); 73 | return foobar; 74 | } 75 | -------------------------------------------------------------------------------- /user/progs/test_new_pages.c: -------------------------------------------------------------------------------- 1 | /** @file test_cs.c 2 | * @author Aatish 3 | * @brief Tests to see if context switch works 4 | * @public yes 5 | * @for p3 6 | * @status done 7 | */ 8 | 9 | /* Includes */ 10 | #include 11 | #include /* for lprintf */ 12 | #include 13 | #include 14 | 15 | /* Main */ 16 | int main() { 17 | if (new_pages((void *)0x1000, PAGE_SIZE) == 0){ 18 | lprintf("allocated page not in user space"); 19 | return -1; 20 | } 21 | if (new_pages((void *)0x0, PAGE_SIZE) == 0){ 22 | lprintf("allocated 0th page"); 23 | return -1; 24 | } 25 | if (new_pages((void *)0xFFFFF000, PAGE_SIZE) == 0){ 26 | lprintf("allocated preallocated page"); 27 | return -1; 28 | } 29 | if (new_pages((void *)0x1000000, PAGE_SIZE) == 0){ 30 | lprintf("allocated preallocated page"); 31 | return -1; 32 | } 33 | if (new_pages((void *)0x2000000, -PAGE_SIZE) == 0){ 34 | lprintf("allocated negative page size"); 35 | return -1; 36 | } 37 | if (new_pages((void *)0x2000000, 0) == 0){ 38 | lprintf("allocated 0 sized page"); 39 | return -1; 40 | } 41 | if (new_pages((void *)0xFFFFE000, PAGE_SIZE) < 0){ 42 | lprintf("failed to allocate a page"); 43 | return -1; 44 | } 45 | if (new_pages((void *)0xFFFFE000, PAGE_SIZE) == 0){ 46 | lprintf("allocated the same page twice"); 47 | return -1; 48 | } 49 | if (new_pages((void *)0xFFFF0000, 3*PAGE_SIZE) < 0){ 50 | lprintf("failed to allocate multiple pages"); 51 | return -1; 52 | } 53 | 54 | /* now check to see if pages are actually mapped */ 55 | int *foo = (int *)0xFFFFE000; 56 | int i; 57 | for (i = 0; i < PAGE_SIZE/(sizeof(int)); i++){ 58 | foo[i] = i; 59 | } 60 | 61 | lprintf("All tests passed!"); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /user/progs/test_paraguay.c: -------------------------------------------------------------------------------- 1 | /** @file 410user/progs/paraguay.c 2 | * @author mjsulliv 3 | * @brief Tests condition variables in an interesting way. 4 | * @public yes 5 | * @for p2 6 | * @covers cond_wait,cond_signal 7 | * @status done 8 | * 9 | * This makes sure that condition variables work properly even if 10 | * signaled without the associated lock being held. 11 | */ 12 | 13 | /* Includes */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "410_tests.h" 20 | #include 21 | #include 22 | 23 | DEF_TEST_NAME("paraguay:"); 24 | 25 | #define MISBEHAVE_MAX 64 26 | 27 | #define STACK_SIZE 4096 28 | 29 | #define ERR REPORT_FAILOUT_ON_ERR 30 | 31 | mutex_t lock1, lock2; 32 | cond_t cvar1, cvar2; 33 | 34 | int slept1 = 0; /* Whether thread1 has gotten to sleep on cvar1 */ 35 | int signaled1 = 0; /* Set right before main thread signals cvar1 */ 36 | int slept2 = 0; /* Whether thread1 has gotten to sleep on cvar2 */ 37 | int signaled2 = 0; /* Set right before main thread signals cvar2 */ 38 | int failed = 0; 39 | 40 | void *thread1(void *dummy) 41 | { 42 | /* go to sleep on cvar1 */ 43 | mutex_lock(&lock1); 44 | slept1 = 1; 45 | report_misc("thread1 sleeping on cvar1"); 46 | cond_wait(&cvar1, &lock1); 47 | if (!signaled1) { 48 | failed = 1; 49 | report_misc("woke up from cvar1 without a signal!"); 50 | report_end(END_FAIL); 51 | } 52 | mutex_unlock(&lock1); 53 | 54 | /* go to sleep on cvar2 */ 55 | mutex_lock(&lock2); 56 | slept2 = 1; 57 | report_misc("thread1 sleeping on cvar2"); 58 | cond_wait(&cvar2, &lock2); 59 | if (!signaled2) { 60 | failed = 1; 61 | report_misc("woke up from cvar2 without a signal!"); 62 | report_end(END_FAIL); 63 | } 64 | mutex_unlock(&lock2); 65 | 66 | if (!failed) { 67 | report_end(END_SUCCESS); 68 | } 69 | 70 | return NULL; 71 | } 72 | 73 | 74 | int main(void) 75 | { 76 | report_start(START_CMPLT); 77 | 78 | //assuredly_misbehave((rand() % 521) % MISBEHAVE_MAX); 79 | 80 | ERR(thr_init(STACK_SIZE)); 81 | ERR(mutex_init(&lock1)); 82 | ERR(mutex_init(&lock2)); 83 | ERR(cond_init(&cvar1)); 84 | ERR(cond_init(&cvar2)); 85 | 86 | ERR(thr_create(thread1, NULL)); 87 | report_misc("thread1 created"); 88 | 89 | /* Wait for thread1 to get to sleep on cvar1. */ 90 | mutex_lock(&lock1); 91 | while (!slept1) { 92 | mutex_unlock(&lock1); 93 | thr_yield(-1); 94 | mutex_lock(&lock1); 95 | } 96 | /* Indicate that we are about to signal */ 97 | signaled1 = 1; 98 | mutex_unlock(&lock1); 99 | 100 | /* Signal. Note that we know for sure that thread1 is asleep on 101 | * cvar1 (assuming correct cond vars and mutexes...) */ 102 | cond_signal(&cvar1); 103 | report_misc("cvar1 signaled"); 104 | 105 | sleep(10); 106 | 107 | /* Now do it all again for the second set of things. */ 108 | /* Wait for thread1 to get to sleep on cvar2. */ 109 | mutex_lock(&lock2); 110 | while (!slept2) { 111 | mutex_unlock(&lock2); 112 | thr_yield(-1); 113 | mutex_lock(&lock2); 114 | } 115 | /* Indicate that we are about to signal */ 116 | signaled2 = 1; 117 | mutex_unlock(&lock2); 118 | 119 | /* Signal. Note that we know for sure that thread1 is asleep on 120 | * cvar2 (assuming correct cond vars and mutexes...) */ 121 | cond_signal(&cvar2); 122 | report_misc("cvar2 signaled"); 123 | 124 | /* Actual success reporting is by the other thread. */ 125 | sleep(2); 126 | thr_exit((void *)failed); 127 | return failed; 128 | } 129 | -------------------------------------------------------------------------------- /user/progs/test_readline.c: -------------------------------------------------------------------------------- 1 | /** @file test_readline.c 2 | * @author Aatish 3 | * @brief Tests to see if readline is working alright 4 | * @public yes 5 | * @for p3 6 | * @status done 7 | */ 8 | 9 | /* Includes */ 10 | #include 11 | #include /* for lprintf */ 12 | #include 13 | #include 14 | 15 | 16 | int main() { 17 | while (1){ 18 | lprintf("Reading in a line"); 19 | char buf[128]; 20 | int i = readline(128, buf); 21 | print(i, buf); 22 | lprintf("Read in %d characters", i); 23 | } 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /user/progs/test_sleep.c: -------------------------------------------------------------------------------- 1 | /** @file test_sleep.c 2 | * @author Chris 3 | * @brief Tests sleep 4 | * @public yes 5 | * @for p3 6 | * @status done 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | 13 | int main(){ 14 | int tid = fork(); 15 | int i = -1; 16 | if (tid == 0){ 17 | lprintf("Alpha sleeping"); 18 | i = sleep(100); 19 | lprintf("Alpha awoken"); 20 | } else { 21 | tid = fork(); 22 | if (tid == 0){ 23 | lprintf("Beta sleeping"); 24 | i = sleep(50); 25 | lprintf("Beta awoken"); 26 | i = sleep(30); 27 | lprintf("Beta awoken second time"); 28 | } else { 29 | lprintf("Gamma sleeping"); 30 | i = sleep(5); 31 | lprintf("Gamma awoken"); 32 | i = sleep(70); 33 | lprintf("Gamma awoken second time"); 34 | } 35 | } 36 | lprintf("i:%d",i); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /user/progs/test_startle.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file startle.c 3 | * 4 | * @brief simple test of thread creation 5 | * 6 | * @author Dave Eckhardt 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "410_tests.h" 15 | #include 16 | 17 | DEF_TEST_NAME("startle:"); 18 | 19 | void *child(void *param); 20 | 21 | #define STACK_SIZE 3072 22 | 23 | #define NTHREADS 30 24 | #define SOMETIMES 4 25 | 26 | int ktids[NTHREADS]; 27 | 28 | /** @brief Create NTHREADS threads, and test that they all run. */ 29 | int 30 | main(int argc, char *argv[]) 31 | { 32 | int t, done = 0; 33 | 34 | thr_init(STACK_SIZE); 35 | report_start(START_CMPLT); 36 | 37 | for (t = 0; t < NTHREADS; ++t) { 38 | (void) thr_create(child, (void *)t); 39 | if (t % SOMETIMES == 0) 40 | yield(-1); 41 | } 42 | 43 | while (!done) { 44 | int nregistered, slot; 45 | 46 | for (nregistered = 0, slot = 0; slot < NTHREADS; ++slot) 47 | if (ktids[slot] != 0) 48 | ++nregistered; 49 | 50 | if (nregistered == NTHREADS) 51 | done = 1; 52 | else 53 | sleep(1); 54 | } 55 | 56 | printf("Success!\n"); lprintf("Success!\n"); 57 | report_end(END_SUCCESS); 58 | 59 | task_vanish(0); 60 | } 61 | 62 | /** @brief Declare that we have run, then twiddle thumbs. */ 63 | void * 64 | child(void *param) 65 | { 66 | int slot = (int) param; 67 | 68 | ktids[slot] = gettid(); 69 | 70 | while (1) { 71 | yield(-1); 72 | sleep(10); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /user/progs/test_thr_create.c: -------------------------------------------------------------------------------- 1 | /** @file user/progs/test_life_cycle.c 2 | * @brief tests fork, wait 3 | * @author Christopher Wei (cjwei), Aatish Nayak (aatishn) 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #define SIZE 4096 14 | #define CHILD_RETURN 42 15 | #define PARENT_RETURN 43 16 | 17 | /** @brief Makes a child and store index in array 18 | * @param i The index 19 | * @return 0 20 | */ 21 | void* foo(void* i) { 22 | lprintf("Hello from child! %d", gettid()); 23 | int tid = fork(); 24 | lprintf("Good I shouldn't be allowed to fork %d", tid); 25 | return 0; 26 | } 27 | 28 | 29 | /** @brief Tests thr_create 30 | * @return 0 31 | */ 32 | int main() 33 | { 34 | int i = 1; 35 | int ret = thr_init(SIZE); 36 | lprintf("thr_init returned: %d", ret); 37 | 38 | int tid = thr_create(foo, (void*) i); 39 | 40 | lprintf("Created child thread: %d, Now sleeping!", tid); 41 | sleep(200); 42 | return 0; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /user/progs/test_yield.c: -------------------------------------------------------------------------------- 1 | /** @file test_yield.c 2 | * @author Christopher Wei 3 | * @brief tests yielding to specific thread 4 | * @public yes 5 | * @for p2 p3 6 | * @covers 7 | * @status done 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | int main() 15 | { 16 | int parenttid = gettid(); 17 | int id = fork(); 18 | while(1){ 19 | if (id == 0) { 20 | yield(parenttid); 21 | printf("Hello from child!"); 22 | } else { 23 | int ret = yield(id); 24 | printf("Parent yield ret: %d", ret); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /vq_challenge/Makefile: -------------------------------------------------------------------------------- 1 | # This Makefile is for building and testing under Linux. 2 | # Once everything works there, you probably want to move 3 | # variable_queue.h into kern/inc and/or user/inc. 4 | 5 | TEST=vqtest 6 | CC=gcc 7 | CFLAGS = -g -fno-strict-aliasing -Wall -gdwarf-2 -Werror -m32 8 | 9 | all: $(TEST) 10 | 11 | $(TEST): $(TEST).c 12 | $(CC) $(CFLAGS) $< -o $@ 13 | 14 | .PHONY: clean 15 | 16 | clean: 17 | rm -f $(TEST) 18 | -------------------------------------------------------------------------------- /vq_challenge/vqtest.c: -------------------------------------------------------------------------------- 1 | /** @file vqtest.c 2 | * @brief A very simple test suite for variable queues. 3 | * 4 | * @author Ryan Pearl 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "variable_queue.h" 12 | 13 | typedef struct node { 14 | Q_NEW_LINK(node) link; 15 | int data; 16 | } node_t; 17 | 18 | Q_NEW_HEAD(list_t, node); 19 | 20 | #define LIST_LEN 5 21 | 22 | void test_init() { 23 | list_t list; 24 | 25 | Q_INIT_HEAD(&list); 26 | 27 | assert(!Q_GET_FRONT(&list)); 28 | assert(!Q_GET_TAIL(&list)); 29 | } 30 | 31 | void test_insert() { 32 | list_t list; 33 | 34 | Q_INIT_HEAD(&list); 35 | 36 | node_t node; 37 | Q_INIT_ELEM(&node, link); 38 | 39 | node.data = 1; 40 | 41 | Q_INSERT_TAIL(&list, &node, link); 42 | 43 | assert(Q_GET_TAIL(&list) == &node); 44 | assert(Q_GET_FRONT(&list) == &node); 45 | 46 | assert(!Q_GET_NEXT(&node, link)); 47 | assert(!Q_GET_PREV(&node, link)); 48 | } 49 | 50 | void test_remove() { 51 | list_t list; 52 | 53 | Q_INIT_HEAD(&list); 54 | 55 | node_t node; 56 | Q_INIT_ELEM(&node, link); 57 | 58 | Q_INSERT_TAIL(&list, &node, link); 59 | 60 | assert(Q_GET_TAIL(&list) == &node); 61 | assert(Q_GET_FRONT(&list) == &node); 62 | 63 | assert(!Q_GET_NEXT(&node, link)); 64 | assert(!Q_GET_PREV(&node, link)); 65 | 66 | Q_REMOVE(&list, &node, link); 67 | 68 | assert(!Q_GET_FRONT(&list)); 69 | assert(!Q_GET_TAIL(&list)); 70 | } 71 | 72 | void test_insert_fronts() { 73 | list_t list; 74 | 75 | Q_INIT_HEAD(&list); 76 | 77 | node_t nodes[LIST_LEN]; 78 | 79 | int i; 80 | for (i = 0; i < LIST_LEN; i++) { 81 | Q_INIT_ELEM(&nodes[i], link); 82 | nodes[i].data = i; 83 | Q_INSERT_FRONT(&list, &nodes[i], link); 84 | } 85 | 86 | node_t *cur = Q_GET_FRONT(&list); 87 | for (i = 0; i < LIST_LEN; i++) { 88 | assert(cur); 89 | assert(cur->data == LIST_LEN - i - 1); 90 | cur = Q_GET_NEXT(cur, link); 91 | } 92 | 93 | assert(!cur); 94 | 95 | cur = Q_GET_TAIL(&list); 96 | for (i = LIST_LEN-1; i >= 0; i--) { 97 | assert(cur); 98 | assert(cur->data == LIST_LEN - i - 1); 99 | cur = Q_GET_PREV(cur, link); 100 | } 101 | assert(!cur); 102 | } 103 | 104 | void test_insert_tails() { 105 | list_t list; 106 | 107 | Q_INIT_HEAD(&list); 108 | 109 | node_t nodes[LIST_LEN]; 110 | 111 | int i; 112 | for (i = 0; i < LIST_LEN; i++) { 113 | Q_INIT_ELEM(&nodes[i], link); 114 | nodes[i].data = i; 115 | Q_INSERT_TAIL(&list, &nodes[i], link); 116 | } 117 | 118 | node_t *cur = Q_GET_FRONT(&list); 119 | for (i = 0; i < LIST_LEN; i++) { 120 | assert(cur); 121 | assert(cur->data == i); 122 | node_t *next = Q_GET_NEXT(cur, link); 123 | assert(!next || Q_GET_PREV(next, link) == cur); 124 | cur = next; 125 | } 126 | 127 | assert(!cur); 128 | 129 | cur = Q_GET_TAIL(&list); 130 | for (i = LIST_LEN-1; i >= 0; i--) { 131 | assert(cur); 132 | assert(cur->data == i); 133 | node_t *prev = Q_GET_PREV(cur, link); 134 | assert(!prev || Q_GET_NEXT(prev, link) == cur); 135 | cur = prev; 136 | } 137 | assert(!cur); 138 | } 139 | 140 | void test_removes() { 141 | list_t list; 142 | 143 | Q_INIT_HEAD(&list); 144 | 145 | node_t nodes[LIST_LEN]; 146 | 147 | int i; 148 | for (i = 0; i < LIST_LEN; i++) { 149 | Q_INIT_ELEM(&nodes[i], link); 150 | Q_INSERT_FRONT(&list, &nodes[i], link); 151 | } 152 | 153 | assert(Q_GET_FRONT(&list) == &nodes[LIST_LEN-1]); 154 | assert(Q_GET_TAIL(&list) == &nodes[0]); 155 | 156 | node_t *cur = Q_GET_FRONT(&list); 157 | while (cur) { 158 | node_t *next = Q_GET_NEXT(cur, link); 159 | Q_REMOVE(&list, cur, link); 160 | cur = next; 161 | i++; 162 | } 163 | } 164 | 165 | void test_insert_after() { 166 | list_t list; 167 | 168 | Q_INIT_HEAD(&list); 169 | 170 | node_t nodes[LIST_LEN]; 171 | 172 | Q_INIT_ELEM(&nodes[0], link); 173 | nodes[0].data = 0; 174 | Q_INSERT_FRONT(&list, &nodes[0], link); 175 | 176 | int i; 177 | for (i = 1; i < LIST_LEN; i++) { 178 | Q_INIT_ELEM(&nodes[i], link); 179 | Q_INSERT_AFTER(&list, &nodes[i-1], &nodes[i], link); 180 | nodes[i].data = i; 181 | assert(Q_GET_NEXT(&nodes[i-1], link) == &nodes[i]); 182 | assert(Q_GET_PREV(&nodes[i], link) == &nodes[i-1]); 183 | } 184 | assert(Q_GET_FRONT(&list) == &nodes[0]); 185 | assert(Q_GET_TAIL(&list) == &nodes[LIST_LEN-1]); 186 | 187 | node_t *cur = Q_GET_FRONT(&list); 188 | for (i = 0; i < LIST_LEN; i++) { 189 | assert(cur); 190 | assert(cur->data == i); 191 | cur = Q_GET_NEXT(cur, link); 192 | } 193 | assert(!cur); 194 | } 195 | 196 | void test_insert_before() { 197 | list_t list; 198 | 199 | Q_INIT_HEAD(&list); 200 | 201 | node_t nodes[LIST_LEN]; 202 | 203 | Q_INIT_ELEM(&nodes[0], link); 204 | nodes[0].data = 0; 205 | Q_INSERT_FRONT(&list, &nodes[0], link); 206 | 207 | int i; 208 | for (i = 1; i < LIST_LEN; i++) { 209 | Q_INIT_ELEM(&nodes[i], link); 210 | Q_INSERT_BEFORE(&list, &nodes[i-1], &nodes[i], link); 211 | nodes[i].data = i; 212 | assert(Q_GET_PREV(&nodes[i-1], link) == &nodes[i]); 213 | assert(Q_GET_NEXT(&nodes[i], link) == &nodes[i-1]); 214 | } 215 | assert(Q_GET_TAIL(&list) == &nodes[0]); 216 | assert(Q_GET_FRONT(&list) == &nodes[LIST_LEN-1]); 217 | 218 | node_t *cur = Q_GET_FRONT(&list); 219 | for (i = 0; i < LIST_LEN; i++) { 220 | assert(cur); 221 | assert(cur->data == LIST_LEN - i - 1); 222 | cur = Q_GET_NEXT(cur, link); 223 | } 224 | assert(!cur); 225 | } 226 | 227 | #define RUN_TEST(t) do {\ 228 | printf("Running "#t"()...");\ 229 | t();\ 230 | printf(" OK.\n");\ 231 | } while(0) 232 | 233 | int main() { 234 | RUN_TEST(test_init); 235 | RUN_TEST(test_insert); 236 | RUN_TEST(test_insert_fronts); 237 | RUN_TEST(test_insert_tails); 238 | RUN_TEST(test_insert_before); 239 | RUN_TEST(test_insert_after); 240 | RUN_TEST(test_remove); 241 | return 0; 242 | } 243 | --------------------------------------------------------------------------------