diff --git a/README.adoc b/README.adoc index c999cc9..458d0a3 100644 --- a/README.adoc +++ b/README.adoc @@ -11659,6 +11659,8 @@ One "downside" of glibc is that it exercises much more kernel functionality on i This section contains userland content, such as <>, <> and <> examples. +Userland assembly content is located at: <>. It was split from this section basically becase we were hitting the HTML `h6` limit, stupid web :-) + This content makes up the bulk of the link:userland/[] directory. Getting started at: <> @@ -11671,14 +11673,30 @@ This section was originally moved in here from: https://github.com/cirosantilli/ Programs under link:userland/c/[] are examples of link:https://en.wikipedia.org/wiki/ANSI_C[ANSI C] programming: +* link:userland/c/hello.c[] +* main` and environment +** link:userland/c/return0.c[] +** link:userland/c/return1.c[] +** link:userland/c/return2.c[] +** link:userland/c/exit0.c[] +** link:userland/c/exit1.c[] +** link:userland/c/exit2.c[] +** link:userland/c/print_argv.c[] * Standard library -** assert.h +** `assert.h` *** link:userland/c/assert_fail.c[] ** `stdlib.h` -*** Exit related +*** exit **** link:userland/c/abort.c[] - -Userland assembly content is located at: <>. It was split from this section basically becase we were hitting the HTML `h6` limit, stupid web :-) +*** malloc +**** link:userland/c/out_of_memory.c[] +** `stdio.h` +*** link:userland/c/stderr.c[] +*** link:userland/c/getchar.c[] +*** File IO +**** link:userland/c/file_write_read.c[] +* Fun +** link:userland/c/infinite_loop.c[] ==== GCC C extensions @@ -13084,7 +13102,7 @@ Note how Sn is weirdly packed inside Dn, and Dn weirdly packed inside Qn, likely And you can't access the higher bytes at D16 or greater with Sn. -===== ARM vadd instruction +===== ARM VADD instruction * link:userland/arch/arm/vadd_scalar.S[]: see also: <> * link:userland/arch/arm/vadd_vector.S[]: see also: <> @@ -13203,20 +13221,20 @@ link:userland/arch/aarch64/add_vector.S[] Good first instruction to learn SIMD: <> -===== ARMv8 aarch64 fadd instruction +===== ARMv8 aarch64 FADD instruction * link:userland/arch/aarch64/fadd_vector.S[]: see also: <> * link:userland/arch/aarch64/fadd_scalar.S[]: see also: <> -====== ARM fadd vs vadd +====== ARM FADD vs VADD It is very confusing, but `fadds` and `faddd` in Aarch32 are <> for `vadd.f32` and `vadd.f64` which we use in this tutorial: <> The same goes for most ARMv7 mnemonics: `f*` is old, and `v*` is the newer better syntax. -But then, in ARMv8, they decided to use <> as the main floating point add name, and get rid of `vadd`! +But then, in ARMv8, they decided to use <> as the main floating point add name, and get rid of VADD! -Also keep in mind that fused multiply add is `fmadd`. +Also keep in mind that fused multiply add is FMADD. Examples at: <> diff --git a/lkmc.h b/lkmc.h index f1664b3..582e3ea 100644 --- a/lkmc.h +++ b/lkmc.h @@ -4,6 +4,7 @@ #define LKMC_H #if !defined(__ASSEMBLER__) +#include #include #include #include @@ -20,6 +21,15 @@ LKMC_ASSERT_EQ_DECLARE(32); LKMC_ASSERT_EQ_DECLARE(64); void lkmc_assert_fail(uint32_t line); void lkmc_assert_memcmp(const void *s1, const void *s2, size_t n, uint32_t line); + +#define LKMC_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) +/* Standard action to take in case of a file IO error. */ +#define LKMC_IO_ERROR(function, path) \ + fprintf(stderr, "error: %s errno = %d, path = %s\n", function, errno, path); \ + exit(EXIT_FAILURE); +#define LKMC_TMP_EXT ".tmp" +#define LKMC_TMP_FILE __FILE__ LKMC_TMP_EXT +#define LKMC_TMP_FILE_NAMED(name) __FILE__ "__" name LKMC_TMP_EXT #endif /* Assert that the given branch instruction is taken. */ diff --git a/path_properties.py b/path_properties.py index 3354a82..b201ba7 100644 --- a/path_properties.py +++ b/path_properties.py @@ -430,6 +430,7 @@ path_properties_tuples = ( 'exit1.c': {'exit_status': 1}, 'exit2.c': {'exit_status': 2}, 'false.c': {'exit_status': 1}, + 'file_write_read.c': {'baremetal': False}, 'getchar.c': {'interactive': True}, 'infinite_loop.c': {'more_than_1s': True}, 'out_of_memory.c': {'disrupts_system': True}, diff --git a/userland/arch/x86_64/dec.S b/userland/arch/x86_64/dec.S index 5d0e277..fba8112 100644 --- a/userland/arch/x86_64/dec.S +++ b/userland/arch/x86_64/dec.S @@ -5,5 +5,5 @@ LKMC_PROLOGUE mov $3, %rax dec %rax - LKMC_ASSERT_EQ_32(%rax, $2) + LKMC_ASSERT_EQ(%rax, $2) LKMC_EPILOGUE diff --git a/userland/c/file_write_read.c b/userland/c/file_write_read.c new file mode 100644 index 0000000..486b65b --- /dev/null +++ b/userland/c/file_write_read.c @@ -0,0 +1,136 @@ +#include + +#include +#include +#include + +/* Returns the size of the given open `FILE*`. + * + * If an error occurs, returns `-1L`. + * + * Does not work for pipes. + */ +long fget_file_size(FILE *fp) { + long oldpos; + long return_value; + oldpos = ftell(fp); + if (oldpos == -1L) { + return -1L; + } + if (fseek(fp, 0, SEEK_END) != 0) { + return -1L; + } + return_value = ftell(fp); + if (return_value == -1L) { + return -1L; + } + /* Restore the old position. */ + if (fseek(fp, oldpos , SEEK_SET) != 0) { + return -1L; + } + return return_value; +} + +/* Same as `file_size`, but takes the path instead of a `FILE*`. */ +long file_size(char *path) { + FILE *fp; + long return_value; + fp = fopen(path, "r"); + if (fp == NULL) { + return -1L; + } + return_value = fget_file_size(fp); + if (fclose(fp) == EOF) { + return -1L; + } + return return_value; +} + +/* Read the entire file to a char[] dynamically allocated inside this function. + * + * Returns a pointer to the start of that array. + * + * In case of any error, returns NULL. + * + * http://stackoverflow.com/questions/174531/easiest-way-to-get-files-contents-in-c + */ +char *file_read(char *path) { + FILE *fp; + char *buffer; + long fsize; + + fp = fopen(path , "rb"); + if (fp == NULL) { + return NULL; + } + fsize = fget_file_size(fp); + if (fsize < 0){ + fprintf(stderr, "could not determine lenght of:\n%s\n", path); + return NULL; + } + buffer = (char*)malloc(fsize); + if (buffer == NULL) { + return NULL; + } + if (fread(buffer, 1, fsize, fp) != (size_t)fsize) { + return NULL; + } + if (fclose(fp) == EOF){ + return NULL; + } + return buffer; +} + +/* Write a null terminated string to file + * + * Return -1 on failure, 0 on success. + */ +int file_write(char *path, char *write_string) { + long len; + FILE *fp; + + fp = fopen(path, "wb"); + if (fp == NULL) { + return -1; + } + len = strlen(write_string); + /* copy the file into the buffer: */ + if (fwrite(write_string, 1, len, fp) != (size_t)len) { + return -1; + } + if (fclose(fp) == EOF) { + return -1; + } + return 0; +} + +int main(void) { + char *path = LKMC_TMP_FILE; + char *input = "asdf\nqwer\n"; + + /* Write entire string to file at once. */ + if (file_write(path, input) == -1) { + LKMC_IO_ERROR("file_write", path); + } + + /* Read entire file at once to a string. */ + { + char *output = file_read(path); + if (output == NULL) { + LKMC_IO_ERROR("file_read", path); + } + assert(strcmp(input, output) == 0); + free(output); + } + + /* Get file size. */ + { + long size = file_size(path); + if (size == -1) { + LKMC_IO_ERROR("file_size", path); + } + assert((size_t)size == strlen(input)); + } + + return EXIT_SUCCESS; +} diff --git a/userland/c/infinite_loop.c b/userland/c/infinite_loop.c index 2ae905f..9c63eb5 100644 --- a/userland/c/infinite_loop.c +++ b/userland/c/infinite_loop.c @@ -1,4 +1,6 @@ -/* Loop infinitely. Print an integer whenever a period is reached: +/* https://github.com/cirosantilli/linux-kernel-module-cheat#c + * + * Loop infinitely. Print an integer whenever a period is reached: * * .... * ./infinite_loop [period]