diff --git a/README.adoc b/README.adoc index 4c6672e..5a63eee 100644 --- a/README.adoc +++ b/README.adoc @@ -12990,6 +12990,23 @@ ls /mnt/9p/rootfs_overlay This way you can just hack away the scripts and try them out immediately without any further operations. +==== lkmc.c + +The files: + +* link:lkmc.c[] +* link:lkmc.h[] + +contain common C function helpers that can be used both in userland and baremetal. Oh, the infinite <>. + +Those files also contain arch specific helpers under ifdefs like: + +.... +#if defined(__aarch64__) +.... + +We try to keep as much as possible in those files. It bloats builds a little, but just makes everything simpler to understand. + === Test this repo ==== Automated tests diff --git a/baremetal/lib/aarch64.S b/baremetal/lib/aarch64.S index cd97272..79203fd 100644 --- a/baremetal/lib/aarch64.S +++ b/baremetal/lib/aarch64.S @@ -23,7 +23,7 @@ LKMC_VECTOR_TABLE /* Default trap handler that does nothing. * - * Weak means that if any other file deinfes it as a non-weak global, + * Weak means that if any other file defines it as a non-weak global, * that one will take precedence. * * We need this one to not get undefined references. diff --git a/build-baremetal b/build-baremetal index b76e211..b2aa9ec 100755 --- a/build-baremetal +++ b/build-baremetal @@ -19,9 +19,7 @@ Build the baremetal examples with crosstool-NG. def build(self): build_dir = self.get_build_dir() bootloader_obj = os.path.join(self.env['baremetal_build_lib_dir'], 'bootloader{}'.format(self.env['obj_ext'])) - common_basename_noext = 'lkmc' - common_src = os.path.join(self.env['root_dir'], common_basename_noext + self.env['c_ext']) - common_obj = os.path.join(self.env['baremetal_build_lib_dir'], common_basename_noext + self.env['obj_ext']) + common_obj = os.path.join(self.env['baremetal_build_lib_dir'], self.env['common_basename_noext'] + self.env['obj_ext']) syscalls_basename_noext = 'syscalls' syscalls_src = os.path.join(self.env['baremetal_source_lib_dir'], syscalls_basename_noext + self.env['c_ext']) syscalls_obj = os.path.join(self.env['baremetal_build_lib_dir'], syscalls_basename_noext + self.env['obj_ext']) @@ -34,6 +32,7 @@ Build the baremetal examples with crosstool-NG. '-mcpu={}'.format(self.env['mcpu']), LF, '-nostartfiles', LF, ] + cflags_after = ['-lm'] gcc = self.get_toolchain_tool('gcc') if self.env['emulator'] == 'gem5': if self.env['machine'] == 'VExpress_GEM5_V1': @@ -59,10 +58,11 @@ Build the baremetal examples with crosstool-NG. '-c', LF, '-o', bootloader_obj, LF, src, LF, - ] + ] + + cflags_after ) for src, obj in [ - (common_src, common_obj), + (self.env['common_c'], common_obj), (syscalls_src, syscalls_obj), ]: if self.need_rebuild([src], obj): @@ -74,12 +74,14 @@ Build the baremetal examples with crosstool-NG. '-D', 'UART0_ADDR={:#x}'.format(uart_address), LF, '-o', obj, LF, src, LF, - ] + ] + + cflags_after ) self._build_dir( '', gcc=gcc, cflags=cflags, + cflags_after=cflags_after, entry_address=entry_address, bootloader_obj=bootloader_obj, common_objs=common_objs, @@ -88,6 +90,7 @@ Build the baremetal examples with crosstool-NG. 'interactive', gcc=gcc, cflags=cflags, + cflags_after=cflags_after, entry_address=entry_address, bootloader_obj=bootloader_obj, common_objs=common_objs, @@ -97,6 +100,7 @@ Build the baremetal examples with crosstool-NG. self.env['baremetal_source_arch_subpath'], gcc=gcc, cflags=cflags, + cflags_after=cflags_after, entry_address=entry_address, bootloader_obj=bootloader_obj, common_objs=common_objs, @@ -107,6 +111,7 @@ Build the baremetal examples with crosstool-NG. arch_dir, gcc=gcc, cflags=cflags, + cflags_after=cflags_after, entry_address=entry_address, bootloader_obj=bootloader_obj, common_objs=common_objs, @@ -121,6 +126,7 @@ Build the baremetal examples with crosstool-NG. subpath, gcc, cflags, + cflags_after, entry_address, bootloader_obj, common_objs, @@ -152,7 +158,8 @@ Build the baremetal examples with crosstool-NG. '-c', LF, '-o', main_obj, LF, src, LF, - ] + ] + + cflags_after ) objs = common_objs + [main_obj] out = os.path.join(self.env['baremetal_build_dir'], subpath, in_name + self.env['baremetal_build_ext']) @@ -166,7 +173,8 @@ Build the baremetal examples with crosstool-NG. '-o', out, LF, '-T', link_script, LF, ] + - self.sh.add_newlines(objs) + self.sh.add_newlines(objs) + + cflags_after ) if __name__ == '__main__': diff --git a/common.py b/common.py index 14dd401..ed1e168 100644 --- a/common.py +++ b/common.py @@ -726,6 +726,17 @@ Valid emulators: {} env['baremetal_build_lib_dir'] = join(env['baremetal_build_dir'], env['baremetal_lib_basename']) env['baremetal_build_ext'] = '.elf' + # Userland / baremetal common source. + env['common_basename_noext'] = 'lkmc' + env['common_c'] = common_c = os.path.join( + env['root_dir'], + env['common_basename_noext'] + env['c_ext'] + ) + env['common_h'] = common_c = os.path.join( + env['root_dir'], + env['common_basename_noext'] + env['header_ext'] + ) + # Docker env['docker_build_dir'] = join(env['out_dir'], 'docker', env['arch']) env['docker_tar_dir'] = join(env['docker_build_dir'], 'export') diff --git a/lkmc.c b/lkmc.c index bc11c30..23d56d7 100644 --- a/lkmc.c +++ b/lkmc.c @@ -1,3 +1,6 @@ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#lkmc-c */ + +#include #include #include @@ -9,8 +12,21 @@ void lkmc_assert(bool condition) { } void lkmc_assert_fail() { - puts("lkmc_test_fail"); - exit(1); + puts("lkmc_test_fail"); + exit(1); +} + +bool lkmc_vector_equal(size_t n, double *v1, double *v2, double max_err) { + double sum = 0.0; + double diff; + size_t i; + for (i = 0; i < n; ++i) { + diff = v1[i] - v2[i]; + sum += diff * diff; + } + if (sqrt(sum)/n > max_err) + return false; + return true; } #if defined(__aarch64__) diff --git a/lkmc.h b/lkmc.h index affa151..a6f46a6 100644 --- a/lkmc.h +++ b/lkmc.h @@ -1,13 +1,17 @@ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#lkmc-c */ + #ifndef LKMC_H #define LKMC_H /* Common C definitions. */ #if !defined(__ASSEMBLER__) -#include #include +#include +#include void lkmc_assert(bool); void lkmc_assert_fail(); +bool lkmc_vector_equal(size_t n, double *v1, double *v2, double max_err); #endif /* https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg */ diff --git a/userland/common_userland.h b/userland/common_userland.h index b8caee3..fbee7f4 100644 --- a/userland/common_userland.h +++ b/userland/common_userland.h @@ -3,23 +3,20 @@ #define _XOPEN_SOURCE 700 #include /* open */ -#include /* fabs */ #include /* uint64_t */ -#include /* size_t */ #include /* snprintf */ #include #include /* pread, sysconf */ -#include /* Format documented at: * https://github.com/torvalds/linux/blob/v4.9/Documentation/vm/pagemap.txt */ typedef struct { - uint64_t pfn : 54; - unsigned int soft_dirty : 1; - unsigned int file_page : 1; - unsigned int swapped : 1; - unsigned int present : 1; + uint64_t pfn : 54; + unsigned int soft_dirty : 1; + unsigned int file_page : 1; + unsigned int swapped : 1; + unsigned int present : 1; } PagemapEntry; /* Parse the pagemap entry for the given virtual address. @@ -31,31 +28,31 @@ typedef struct { */ int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr) { - size_t nread; - ssize_t ret; - uint64_t data; - uintptr_t vpn; + size_t nread; + ssize_t ret; + uint64_t data; + uintptr_t vpn; - vpn = vaddr / sysconf(_SC_PAGE_SIZE); - nread = 0; - while (nread < sizeof(data)) { - ret = pread( - pagemap_fd, - &data, - sizeof(data) - nread, - vpn * sizeof(data) + nread - ); - nread += ret; - if (ret <= 0) { - return 1; - } - } - entry->pfn = data & (((uint64_t)1 << 54) - 1); - entry->soft_dirty = (data >> 54) & 1; - entry->file_page = (data >> 61) & 1; - entry->swapped = (data >> 62) & 1; - entry->present = (data >> 63) & 1; - return 0; + vpn = vaddr / sysconf(_SC_PAGE_SIZE); + nread = 0; + while (nread < sizeof(data)) { + ret = pread( + pagemap_fd, + &data, + sizeof(data) - nread, + vpn * sizeof(data) + nread + ); + nread += ret; + if (ret <= 0) { + return 1; + } + } + entry->pfn = data & (((uint64_t)1 << 54) - 1); + entry->soft_dirty = (data >> 54) & 1; + entry->file_page = (data >> 61) & 1; + entry->swapped = (data >> 62) & 1; + entry->present = (data >> 63) & 1; + return 0; } /* Convert the given virtual address to physical using /proc/PID/pagemap. @@ -67,35 +64,21 @@ int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr) */ int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr) { - char pagemap_file[BUFSIZ]; - int pagemap_fd; + char pagemap_file[BUFSIZ]; + int pagemap_fd; - snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid); - pagemap_fd = open(pagemap_file, O_RDONLY); - if (pagemap_fd < 0) { - return 1; - } - PagemapEntry entry; - if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) { - return 1; - } - close(pagemap_fd); - *paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE)); - return 0; -} - -bool common_vector_equal(size_t n, double * v1, double * v2, double max_err) -{ - double sum = 0.0; - double diff; - size_t i; - for (i = 0; i < n; ++i) { - diff = v1[i] - v2[i]; - sum += diff * diff; - } - if (sqrt(sum)/n > max_err) - return false; - return true; + snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid); + pagemap_fd = open(pagemap_file, O_RDONLY); + if (pagemap_fd < 0) { + return 1; + } + PagemapEntry entry; + if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) { + return 1; + } + close(pagemap_fd); + *paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE)); + return 0; } #endif diff --git a/userland/openblas_hello.c b/userland/openblas_hello.c index c6e00e6..581bcfb 100644 --- a/userland/openblas_hello.c +++ b/userland/openblas_hello.c @@ -1,16 +1,15 @@ /* https://github.com/cirosantilli/linux-kernel-module-cheat#blas * Adapted from: https://github.com/xianyi/OpenBLAS/wiki/User-Manual/59b62f98e7400270fb03ad1d85fba5b64ebbff2b#call-cblas-interface */ -#include "common_userland.h" +#include "lkmc.h" #include #include -int main(void) -{ - double A[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0}; - double B[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0}; - double C[9] = {0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5}; - cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, 3, 3, 2, 1, A, 3, B, 3, 2, C, 3); - assert(common_vector_equal(9, C, (double[]){11.0, -9.0, 5.0, -9.0, 21.0, -1.0, 5.0, -1.0, 3.0}, 1e-6)); +int main(void) { + double A[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0}; + double B[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0}; + double C[9] = {0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5}; + cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, 3, 3, 2, 1, A, 3, B, 3, 2, C, 3); + assert(lkmc_vector_equal(9, C, (double[]){11.0, -9.0, 5.0, -9.0, 21.0, -1.0, 5.0, -1.0, 3.0}, 1e-6)); }