diff options
| author | klaar36 <klas.arvidsson@liu.se> | 2017-03-20 17:59:45 +0100 |
|---|---|---|
| committer | klaar36 <klas.arvidsson@liu.se> | 2017-03-20 17:59:45 +0100 |
| commit | f9003d89b17c039ab903f622580e61925e137523 (patch) | |
| tree | b46ab4f9745c96a78685ca29b6a18ed2531205d6 /src/standalone | |
| parent | d9ae213323d0a036b7f3594de6822413a4c312c6 (diff) | |
| download | pintos-rs-f9003d89b17c039ab903f622580e61925e137523.tar.gz | |
added given files for standalone labs
Diffstat (limited to 'src/standalone')
| -rw-r--r-- | src/standalone/upg1/basics.c | 6 | ||||
| -rw-r--r-- | src/standalone/upg2/about-main.c | 6 | ||||
| -rw-r--r-- | src/standalone/upg3/fork-wait.c | 95 | ||||
| -rw-r--r-- | src/standalone/upg4/use-list.c | 42 | ||||
| -rw-r--r-- | src/standalone/upg5/pagedir.c | 8 | ||||
| -rw-r--r-- | src/standalone/upg5/pagedir.h | 42 | ||||
| -rw-r--r-- | src/standalone/upg5/thread.h | 16 | ||||
| -rw-r--r-- | src/standalone/upg5/verify_adr.c | 90 | ||||
| -rw-r--r-- | src/standalone/upg6/main.c | 124 | ||||
| -rw-r--r-- | src/standalone/upg6/map.c | 1 | ||||
| -rw-r--r-- | src/standalone/upg6/map.h | 1 | ||||
| -rw-r--r-- | src/standalone/upg7/debug.c | 27 | ||||
| -rw-r--r-- | src/standalone/upg8/setup-argv.c | 265 |
13 files changed, 723 insertions, 0 deletions
diff --git a/src/standalone/upg1/basics.c b/src/standalone/upg1/basics.c new file mode 100644 index 0000000..62bc52c --- /dev/null +++ b/src/standalone/upg1/basics.c @@ -0,0 +1,6 @@ +#include <stdio.h> +#include <stdlib.h> + +int main() +{ +} diff --git a/src/standalone/upg2/about-main.c b/src/standalone/upg2/about-main.c new file mode 100644 index 0000000..2407c23 --- /dev/null +++ b/src/standalone/upg2/about-main.c @@ -0,0 +1,6 @@ +#include <stdio.h> +#include <string.h> + +int main(int argc, char* argv[]) +{ +} diff --git a/src/standalone/upg3/fork-wait.c b/src/standalone/upg3/fork-wait.c new file mode 100644 index 0000000..2e7729d --- /dev/null +++ b/src/standalone/upg3/fork-wait.c @@ -0,0 +1,95 @@ +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +/* The printf text serve as further comments. Read it. */ + +int main(int argc, char* argv[]) +{ + pid_t pid; + char dummy[16]; + + if (argc < 2) + { + printf("You need to specify a program as argument 1.\n"); + exit(1); /* Terminate the process with error (1). */ + } + + printf("P | Switch to a differen terminal.\n" + "P | Execute the command \"ptree $USER\".\n" + "P | It will show a list of processes you are running.\n" + "P | You should see the process '%s' once.\n" + "P | Press enter when you verified that.\n\n", argv[0]); + + /* Wait until enter is pressed (gives you time...) */ + fgets(dummy, 16, stdin); + + printf("P | This process will now clone itself with fork.\n" + "P | One (almost) identical copy will be started.\n" + "P | The only difference is the result of fork()\n\n"); + + pid = fork(); + + if (pid == 0) + { + printf(" C | This is printed by the new process (the CHILD)\n" + " C | The child get a 0 return value from fork.\n\n"); + + printf(" C | Repeat the previous command in the other terminal.\n" + " C | You should see the process '%s' twice now.\n" + " C | (grep for it if you run many processes)\n" + " C | Press enter when you verified that.\n\n", argv[0]); + + /* Wait until enter is pressed (gives you time...) */ + fgets(dummy, 16, stdin); + + printf(" C | The program specified as first argument (%s) on the \n" + " C | command line will now be started by the child process.\n" + " C | This will REPLACE the code of the child with the code\n" + " C | of the specified program.\n\n", argv[1]); + + /* specify a terminal as argument 1 and check ptree again ... + * you will see that the child is replaced, it have the same + * process number, but a new command line + */ + execv(argv[1], argv + 1); + + printf(" C | This will never be printed, since after starting the new\n" + " C | program by calling exec this old program is replaced by\n" + " C | the new. This is only printed if the new program could not\n" + " C | be started for some reason.\n\n"); + + exit(-1); /* Terminate the child with error (-1). */ + } + else + { + int ret = 0; /* Used to save the result of the child. */ + + printf("P | This is printed by the origingal process (the PARENT)\n" + "P | It got the number (%d) from fork to identify the child.\n" + "P | This process will now work for 5 seconds.\n\n", (int)pid); + sleep(5); /* pretend */ + + printf("P | This is printed by the origingal process (the PARENT)\n" + "P | It got the number (%d) from fork to identify the child.\n" + "P | It is now used to wait for the result of that child\n\n", + (int)pid); + + /* Wait for the child to finish and get it's status in ret. */ + waitpid(pid, &ret, 0); + + /* Print the exit status of the child. */ + if (WIFEXITED(ret)) + { + printf("P | Child finished with code %d\n\n", WEXITSTATUS(ret)); + } + else if (WIFSIGNALED(ret)) + { + printf("P | Child finished due to signal %d\n\n", WTERMSIG(ret)); + } + } + + return 0; +} diff --git a/src/standalone/upg4/use-list.c b/src/standalone/upg4/use-list.c new file mode 100644 index 0000000..065f71a --- /dev/null +++ b/src/standalone/upg4/use-list.c @@ -0,0 +1,42 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> + +/* Pintos contain an implementation of a doubly linked list. It is + * found in ../../lib/kernel/list.[ch]. + * + * Recommended compilation commands: + * + * This is done once: + * gcc -Wall -Wextra -std=gnu99 -pedantic -g -c ../../lib/kernel/list.c + * + * Then use the precomplied list.o: + * gcc -Wall -Wextra -std=gnu99 -pedantic -g use-list.c list.o + */ +#error Read comments above, then remove this line. + +#include "../../lib/kernel/list.h" + +int main() +{ + int i, j; + int N = 1000; + + /* create a list */ + for (i = 2; i < N; ++i) + { + /* insert the value of the loop variable 'i' in the list */ + } + + for (i = 2; i < N; ++i) + { + for (j = i*2; j < N; j += i) + { + /* remove every with 'j' even divisible number from the list */ + } + } + + /* print all remaining numbers in the list and free any memory + * allocated */ + return 0; +} diff --git a/src/standalone/upg5/pagedir.c b/src/standalone/upg5/pagedir.c new file mode 100644 index 0000000..7ef78a3 --- /dev/null +++ b/src/standalone/upg5/pagedir.c @@ -0,0 +1,8 @@ +/* The code that simulates and tests your address verification. How + this is done is disclosed. As a student you shall not compile this + file, but instead compile your program with the .o file as: + + gcc -Wall -Wextra -std=c99 -pedantic -g verify_adr.c pagedir.o + */ +#error Read comment above. Leave this line in place. + diff --git a/src/standalone/upg5/pagedir.h b/src/standalone/upg5/pagedir.h new file mode 100644 index 0000000..2919d1a --- /dev/null +++ b/src/standalone/upg5/pagedir.h @@ -0,0 +1,42 @@ +#ifndef PAGEDIR_H +#define PAGEDIR_H + +typedef int bool; +#define false 0 +#define true 1 + +/* Returns true iff 'adr' contains a null-character ('\0'). */ +bool is_end_of_string(char* adr); + +/* Returns the start address of the page that contains 'adr'. */ +void* pg_round_down(const void* adr); + +/* Returns the page number of the page that contains 'adr'. + * Page numbers are counted with start at zero (0). + */ +unsigned pg_no(const void* adr); + +/* Uses the page table to translate from logic to physical + * address. Returns NULL if the translation fail. + * + * The first parameter specify the top level page table to + * use. Normally you will find it in the structure corresponding + * to your operating systems PCB (Process Control Block). + */ +void *pagedir_get_page (void *pagetable, const void *adr); + +/* Page size: The number of bytes in each page. */ +#define PGSIZE 100 + +/* Functions used to simulate a paging system and testing your + * solution. */ +void start_evaluate_algorithm(void* start, int size); +void evaluate(bool result); +void end_evaluate_algorithm(); + +/* Let us decide how costly a simulated page fault is in terms of + * time. Does not exist in Pintos. Set to zero (0) for faster + * testing. */ +void simulator_set_pagefault_time(unsigned i); + +#endif diff --git a/src/standalone/upg5/thread.h b/src/standalone/upg5/thread.h new file mode 100644 index 0000000..62568ab --- /dev/null +++ b/src/standalone/upg5/thread.h @@ -0,0 +1,16 @@ +#ifndef THREAD_H +#define THREAD_H + +struct thread +{ + /* This is just a part of the Pintos Thread. */ + void* pagedir; +}; + +/* Initiate the threading system. */ +void thread_init(); + +/* Return a pointer to the currently active thread. */ +struct thread* thread_current(); + +#endif diff --git a/src/standalone/upg5/verify_adr.c b/src/standalone/upg5/verify_adr.c new file mode 100644 index 0000000..6aba06e --- /dev/null +++ b/src/standalone/upg5/verify_adr.c @@ -0,0 +1,90 @@ +#include <stdlib.h> +#include "pagedir.h" +#include "thread.h" + +/* verfy_*_lenght are intended to be used in a system call that accept + * parameters containing suspisious (user mode) adresses. The + * operating system (executng the system call in kernel mode) must not + * be fooled into using (reading or writing) addresses not available + * to the user mode process performing the system call. + * + * In pagedir.h you can find some supporting functions that will help + * you dermining if a logic address can be translated into a physical + * addrerss using the process pagetable. A single translation is + * costly. Work out a way to perform as few translations as + * possible. + * + * Recommended compilation command: + * + * gcc -Wall -Wextra -std=gnu99 -pedantic -g pagedir.o verify_adr.c + */ +#error Read comment above and then remove this line. + +/* Verify all addresses from and including 'start' up to but excluding + * (start+length). */ +bool verify_fix_length(void* start, int length) +{ + // ADD YOUR CODE HERE +} + +/* Verify all addresses from and including 'start' up to and including + * the address first containg a null-character ('\0'). (The way + * C-strings are stored.) + */ +bool verify_variable_length(char* start) +{ + // ADD YOUR CODE HERE +} + +/* Definition of test cases. */ +struct test_case_t +{ + void* start; + unsigned length; +}; + +#define TEST_CASE_COUNT 6 + +const struct test_case_t test_case[TEST_CASE_COUNT] = +{ + {(void*)100, 100}, /* one full page */ + {(void*)199, 102}, + {(void*)101, 98}, + {(void*)250, 190}, + {(void*)250, 200}, + {(void*)250, 210} +}; + +/* This main program will evalutate your solution. */ +int main(int argc, char* argv[]) +{ + int i; + bool result; + + if ( argc == 2 ) + { + simulator_set_pagefault_time( atoi(argv[1]) ); + } + thread_init(); + + /* Test the algorithm with a given intervall (a buffer). */ + for (i = 0; i < TEST_CASE_COUNT; ++i) + { + start_evaluate_algorithm(test_case[i].start, test_case[i].length); + result = verify_fix_length(test_case[i].start, test_case[i].length); + evaluate(result); + end_evaluate_algorithm(); + } + + /* Test the algorithm with a C-string (start address with + * terminating null-character). + */ + for (i = 0; i < TEST_CASE_COUNT; ++i) + { + start_evaluate_algorithm(test_case[i].start, test_case[i].length); + result = verify_variable_length(test_case[i].start); + evaluate(result); + end_evaluate_algorithm(); + } + return 0; +} diff --git a/src/standalone/upg6/main.c b/src/standalone/upg6/main.c new file mode 100644 index 0000000..c481d40 --- /dev/null +++ b/src/standalone/upg6/main.c @@ -0,0 +1,124 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "map.h" + +/* Recommended compile commmand: + * + * gcc -Wall -Wextra -std=gnu99 -pedantic -g main.c map.c + * + * Recommended way to test your solution: + * + * valgrind --tool=memcheck ./a.out + */ +#error Read comments above, then remove this line. + + +/* Can be used to inform compiler about unused parameters (prevent + * warning). Useful when a funtion pointer expect a certain set of + * parameters, but you only need some of them. */ +#define UNUSED __attribute__((unused)) + +/* The code assumes that key_t is `int' and value_t is `char*' */ + +/* function passed as parameter to map_remove_if in order to free the + * memory for all inseted values, and return true to remove them from + * the map */ +bool do_free(key_t k UNUSED, value_t v, int aux UNUSED) +{ + free(v); /*! free memory */ + return true; /* and remove from collection */ +} + +/* function to display all values in the map that are less than the + * aux argument */ +void print_less(key_t k UNUSED, value_t v, int aux) +{ + /* atoi converst from sequence of character to integer, it will fail + * when the characters are letters, check the manpage to see how */ + if ( atoi(v) < aux) + { + printf("%s ", v); + } +} + + +#define LOOPS 10 + +char* my_strdup(char* str) +{ + /*! calculate the length and add space for '\0' */ + int len = strlen(str) + 1; + /*! allocate memory just large enough */ + char* dst = (char*)malloc(len); + /*! copy all characters in src to dst */ + strncpy(dst, str, len); + + return dst; /*(!) return our deep copy of str */ +} + +int main() +{ + struct map container; + char input_buffer[10]; + char* obj; + int id; + int i; + + map_init(&container); + + /* remember to try to insert more values than you map can hold */ + printf("Insert values: "); + for ( i = 0; i < LOOPS; ++i) + { + /* insecure, scanf may overflow the input buffer array * + * very serious, but we ignore it in this test program */ + scanf("%s", input_buffer); + + /*! allocates a copy of the input and inserts in map */ + obj = my_strdup(input_buffer); + id = map_insert(&container, obj); + } + + /* remember to test with invalid keys (like 4711, or -1) */ + for ( i = 0; i < LOOPS; ++i) + { + printf("Enter id to find value for: "); + scanf("%d", &id); + + /*! find the value for a key in the map */ + obj = map_find(&container, id); + + /*! if it was found, display it */ +YOUR CODE + + /* since we leave the value in the map we may use it again and + * should not free the memory */ + } + + /* remember to test with invalid keys (like 4711, or -1) */ + for ( i = 0; i < LOOPS; ++i) + { + printf("Enter id to remove value for: "); + scanf("%d", &id); + + /*! find and remove a value for a key in the map */ + obj = map_remove(&container, id); + + /*! if it was found, display it */ +YOUR CODE + /* since we removed the value from the map we will never use it again and + * must properly free the memory (if it was allocated) */ + } + + /*! print all strings representing an integer less than N */ + printf("Will now display all values less than N. Choose N: "); + scanf("%d", &i); + map_for_each(&container, print_less, i); + + /*! free all remaining memory and remove from map */ + map_remove_if(&container, do_free, 0); + + return 0; +} diff --git a/src/standalone/upg6/map.c b/src/standalone/upg6/map.c new file mode 100644 index 0000000..b323fbb --- /dev/null +++ b/src/standalone/upg6/map.c @@ -0,0 +1 @@ +#include "map.h" diff --git a/src/standalone/upg6/map.h b/src/standalone/upg6/map.h new file mode 100644 index 0000000..9029ff5 --- /dev/null +++ b/src/standalone/upg6/map.h @@ -0,0 +1 @@ +/* do not forget the guard against multiple includes */ diff --git a/src/standalone/upg7/debug.c b/src/standalone/upg7/debug.c new file mode 100644 index 0000000..d6a3707 --- /dev/null +++ b/src/standalone/upg7/debug.c @@ -0,0 +1,27 @@ +#include <stdio.h> + +int main() +{ + char str[] = "sihtgubed"; + char *stri = &str[8]; + char *buf[9]; + char **bufi, **bufend; + bufi = buf; + bufend = &buf[9]; + + while (bufi != bufend){ + *bufi = stri; + bufi++; + stri--; + } + + while (bufi != buf){ + *(*bufi) -= 32; + bufi--; + } + + while (bufi != bufend){ + printf("%c", **bufi); + bufi++; + } +} diff --git a/src/standalone/upg8/setup-argv.c b/src/standalone/upg8/setup-argv.c new file mode 100644 index 0000000..dd326d2 --- /dev/null +++ b/src/standalone/upg8/setup-argv.c @@ -0,0 +1,265 @@ +#define _POSIX_C_SOURCE 2 +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* + YOUR WORK: + + You will complete the function setup_main_stack below. Missing code + and calculations are expressed with a questionmark (?). The + assignment is mostly about doing the correct math. To do that math + you will need to learn or understand: + + - How the stack is used during program execution + - How the stack is expected to look like at start of a C-program + - What a pointer variable is, how it is used + - How a C-array (pointer to many) is laid-out in memory + - How pointer arithmetic behaves + - How to cast from one pointer type to another + - How to use printf to print good debug information + - How to use a C-struct, both object and pointer to + + Some manual-pages of interest: + + man -s3 printf + man -s3 strlen + man -s3 strncpy + man -s3 strtok_r + + The prototype for above functions: + + int printf(const char *restrict format, ...); + size_t strlen(const char *s); + size_t strncpy(char *dst, const char *src, size_t dstsize); + char *strtok_r(char *s1, const char *s2, char **lasts); + + The above functions exist in Pintos code. Note the Pintos use + 'strlcpy' instead of 'strncpy'. If 'dst' is large enough they behave + identical. You can find Pintos implementations in + /home/TDIU16/labs/skel/pintos/src/lib, see string.c and stdio.c. It + is strongly recommendable to look at the strtok_r examples given in + string.c + + About *restrict: http://en.wikipedia.org/wiki/Pointer_alias + + + Recommended compile command: + + gcc -m32 -Wall -Wextra -std=gnu99 -pedantic -g setup-argv.c + +*/ +#error Read comments above, then remove this line. + +#define true 1 +#define false 0 + +typedef int bool; + +/* "struct main_args" represent the stack as it must look when + * entering main. The only issue: argv must point somewhere... + * + * The members of this structure is is directly related to the + * arguments of main in a C-program, of course. + * + * int main(int argc, char* argv[]); + * + * (char** argv is a more generic form of char* argv[]) + * + * The function pointer is normally handled by the compiler + * automatically, and determine the address at where a function shall + * continue when it returns. The main function does not use it, as the + * operating system arrange for the program to stop execution when + * main is finished. + */ +struct main_args +{ + /* Hint: When try to interpret C-declarations, read from right to + * left! It is often easier to get the correct interpretation, + * altough it does not always work. */ + + /* Variable "ret" that stores address (*ret) to a function taking no + * parameters (void) and returning nothing. */ + void (*ret)(void); + + /* Just a normal integer. */ + int argc; + + /* Variable "argv" that stores address to an address storing char. + * That is: argv is a pointer to char* + */ + char** argv; +}; + +/* A function that dumps 'size' bytes of memory starting at 'ptr' + * it will dump the higher adress first letting the stack grow down. + */ +void dump(void* ptr, int size) +{ + int i; + + printf("Adress \thex-data \tchar-data\n"); + + for (i = size - 1; i >= 0; --i) + { + void** adr = (void**)((unsigned)ptr + i); + unsigned char* byte = (unsigned char*)((unsigned)ptr + i); + + printf("%08x\t", (unsigned)ptr + i); /* address */ + + if ((i % 4) == 0) + /* seems we're actually forbidden to read unaligned adresses */ + printf("%08x\t", (unsigned)*adr); /* content interpreted as address */ + else + printf(" \t"); /* fill */ + + if(*byte >= 32 && *byte < 127) + printf("%c\n", *byte); /* content interpreted as character */ + else + printf("\\%o\n", *byte); + + if ((i % 4) == 0) + printf("------------------------------------------------\n"); + } +} + +/* Read one line of input ... + */ +void custom_getline(char buf[], int size) +{ + int i; + for (i = 0; i < (size - 1); ++i) + { + buf[i] = getchar(); + if (buf[i] == '\n') + break; + } + buf[i] = '\0'; +} + +/* Return true if 'c' is fount in the c-string 'd' + * NOTE: 'd' must be a '\0'-terminated c-string + */ +bool exists_in(char c, const char* d) +{ + int i = 0; + while (d[i] != '\0' && d[i] != c) + ++i; + return (d[i] == c); +} + +/* Return the number of words in 'buf'. A word is defined as a + * sequence of characters not containing any of the characters in + * 'delimeters'. + * NOTE: arguments must be '\0'-terminated c-strings + */ +int count_args(const char* buf, const char* delimeters) +{ + int i = 0; + bool prev_was_delim; + bool cur_is_delim = true; + int argc = 0; + + while (buf[i] != '\0') + { + prev_was_delim = cur_is_delim; + cur_is_delim = exists_in(buf[i], delimeters); + argc += (prev_was_delim && !cur_is_delim); + ++i; + } + return argc; +} + +/* Replace calls to STACK_DEBUG with calls to printf. All such calls + * easily removed later by replacing with nothing. */ +#define STACK_DEBUG(...) printf(__VA_ARGS__) + +void* setup_main_stack(const char* command_line, void* stack_top) +{ + /* Variable "esp" stores an address, and at the memory loaction + * pointed out by that address a "struct main_args" is found. + * That is: "esp" is a pointer to "struct main_args" */ + struct main_args* esp; + int argc; + int total_size; + int line_size; + /* "cmd_line_on_stack" and "ptr_save" are variables that each store + * one address, and at that address (the first) char (of a possible + * sequence) can be found. */ + char* cmd_line_on_stack; + char* ptr_save; + int i = 0; + + /* calculate the bytes needed to store the command_line */ + line_size = ??? ; + STACK_DEBUG("# line_size = %d\n", line_size); + + /* round up to make it even divisible by 4 */ + line_size = ??? ; + STACK_DEBUG("# line_size (aligned) = %d\n", line_size); + + /* calculate how many words the command_line contain */ + argc = ??? ; + STACK_DEBUG("# argc = %d\n", argc); + + /* calculate the size needed on our simulated stack */ + total_size = ??? ; + STACK_DEBUG("# total_size = %d\n", total_size); + + + /* calculate where the final stack top will be located */ + esp = ??? ; + + /* setup return address and argument count */ + esp->ret = ??? ; + esp->argc = ??? ; + /* calculate where in the memory the argv array starts */ + esp->argv = ??? ; + + /* calculate where in the memory the words is stored */ + cmd_line_on_stack = ??? ; + + /* copy the command_line to where it should be in the stack */ + + /* build argv array and insert null-characters after each word */ + + return esp; /* the new stack top */ +} + +/* The C way to do constants ... */ +#define LINE_SIZE 1024 + +int main() +{ + struct main_args* esp; + char line[LINE_SIZE]; + void* simulated_stack = malloc(4096); + void* simulated_stack_top = (void*)((unsigned)simulated_stack + 4096); + int i; + + /* read one line of input, this will be the command-line */ + printf("Mata in en mening: "); + custom_getline(line, LINE_SIZE); + + /* put initial content on our simulated stack */ + esp = setup_main_stack(line, simulated_stack_top); + printf("# esp = %08x\n", (unsigned)esp); + + /* dump memory area for verification */ + dump(esp, (unsigned)simulated_stack_top - (unsigned)esp); + + /* original command-line should not be needed anymore */ + for (i = 0; i < LINE_SIZE; ++i) + line[i] = (char)0xCC; + + /* print the argument vector to see if it worked */ + for (i = 0; i < esp->argc; ++i) + { + printf("argv[%d] = %s\n", i, esp->argv[i]); + } + printf("argv[%d] = %p\n", i, esp->argv[i]); + + free(simulated_stack); + + return 0; +} |
