lkmc_vector_equal into lkmc.c

Document lkmc.c
This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-02-20 00:00:04 +00:00
parent e44362b394
commit d5e16fd8ae
8 changed files with 118 additions and 80 deletions

View File

@@ -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. 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 <<about-the-baremetal-setup,joys of Newlib>>.
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 === Test this repo
==== Automated tests ==== Automated tests

View File

@@ -23,7 +23,7 @@ LKMC_VECTOR_TABLE
/* Default trap handler that does nothing. /* 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. * that one will take precedence.
* *
* We need this one to not get undefined references. * We need this one to not get undefined references.

View File

@@ -19,9 +19,7 @@ Build the baremetal examples with crosstool-NG.
def build(self): def build(self):
build_dir = self.get_build_dir() build_dir = self.get_build_dir()
bootloader_obj = os.path.join(self.env['baremetal_build_lib_dir'], 'bootloader{}'.format(self.env['obj_ext'])) bootloader_obj = os.path.join(self.env['baremetal_build_lib_dir'], 'bootloader{}'.format(self.env['obj_ext']))
common_basename_noext = 'lkmc' common_obj = os.path.join(self.env['baremetal_build_lib_dir'], self.env['common_basename_noext'] + self.env['obj_ext'])
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'])
syscalls_basename_noext = 'syscalls' syscalls_basename_noext = 'syscalls'
syscalls_src = os.path.join(self.env['baremetal_source_lib_dir'], syscalls_basename_noext + self.env['c_ext']) 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']) 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, '-mcpu={}'.format(self.env['mcpu']), LF,
'-nostartfiles', LF, '-nostartfiles', LF,
] ]
cflags_after = ['-lm']
gcc = self.get_toolchain_tool('gcc') gcc = self.get_toolchain_tool('gcc')
if self.env['emulator'] == 'gem5': if self.env['emulator'] == 'gem5':
if self.env['machine'] == 'VExpress_GEM5_V1': if self.env['machine'] == 'VExpress_GEM5_V1':
@@ -59,10 +58,11 @@ Build the baremetal examples with crosstool-NG.
'-c', LF, '-c', LF,
'-o', bootloader_obj, LF, '-o', bootloader_obj, LF,
src, LF, src, LF,
] ] +
cflags_after
) )
for src, obj in [ for src, obj in [
(common_src, common_obj), (self.env['common_c'], common_obj),
(syscalls_src, syscalls_obj), (syscalls_src, syscalls_obj),
]: ]:
if self.need_rebuild([src], 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, '-D', 'UART0_ADDR={:#x}'.format(uart_address), LF,
'-o', obj, LF, '-o', obj, LF,
src, LF, src, LF,
] ] +
cflags_after
) )
self._build_dir( self._build_dir(
'', '',
gcc=gcc, gcc=gcc,
cflags=cflags, cflags=cflags,
cflags_after=cflags_after,
entry_address=entry_address, entry_address=entry_address,
bootloader_obj=bootloader_obj, bootloader_obj=bootloader_obj,
common_objs=common_objs, common_objs=common_objs,
@@ -88,6 +90,7 @@ Build the baremetal examples with crosstool-NG.
'interactive', 'interactive',
gcc=gcc, gcc=gcc,
cflags=cflags, cflags=cflags,
cflags_after=cflags_after,
entry_address=entry_address, entry_address=entry_address,
bootloader_obj=bootloader_obj, bootloader_obj=bootloader_obj,
common_objs=common_objs, common_objs=common_objs,
@@ -97,6 +100,7 @@ Build the baremetal examples with crosstool-NG.
self.env['baremetal_source_arch_subpath'], self.env['baremetal_source_arch_subpath'],
gcc=gcc, gcc=gcc,
cflags=cflags, cflags=cflags,
cflags_after=cflags_after,
entry_address=entry_address, entry_address=entry_address,
bootloader_obj=bootloader_obj, bootloader_obj=bootloader_obj,
common_objs=common_objs, common_objs=common_objs,
@@ -107,6 +111,7 @@ Build the baremetal examples with crosstool-NG.
arch_dir, arch_dir,
gcc=gcc, gcc=gcc,
cflags=cflags, cflags=cflags,
cflags_after=cflags_after,
entry_address=entry_address, entry_address=entry_address,
bootloader_obj=bootloader_obj, bootloader_obj=bootloader_obj,
common_objs=common_objs, common_objs=common_objs,
@@ -121,6 +126,7 @@ Build the baremetal examples with crosstool-NG.
subpath, subpath,
gcc, gcc,
cflags, cflags,
cflags_after,
entry_address, entry_address,
bootloader_obj, bootloader_obj,
common_objs, common_objs,
@@ -152,7 +158,8 @@ Build the baremetal examples with crosstool-NG.
'-c', LF, '-c', LF,
'-o', main_obj, LF, '-o', main_obj, LF,
src, LF, src, LF,
] ] +
cflags_after
) )
objs = common_objs + [main_obj] objs = common_objs + [main_obj]
out = os.path.join(self.env['baremetal_build_dir'], subpath, in_name + self.env['baremetal_build_ext']) 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, '-o', out, LF,
'-T', link_script, LF, '-T', link_script, LF,
] + ] +
self.sh.add_newlines(objs) self.sh.add_newlines(objs) +
cflags_after
) )
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -726,6 +726,17 @@ Valid emulators: {}
env['baremetal_build_lib_dir'] = join(env['baremetal_build_dir'], env['baremetal_lib_basename']) env['baremetal_build_lib_dir'] = join(env['baremetal_build_dir'], env['baremetal_lib_basename'])
env['baremetal_build_ext'] = '.elf' 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 # Docker
env['docker_build_dir'] = join(env['out_dir'], 'docker', env['arch']) env['docker_build_dir'] = join(env['out_dir'], 'docker', env['arch'])
env['docker_tar_dir'] = join(env['docker_build_dir'], 'export') env['docker_tar_dir'] = join(env['docker_build_dir'], 'export')

20
lkmc.c
View File

@@ -1,3 +1,6 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#lkmc-c */
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -9,8 +12,21 @@ void lkmc_assert(bool condition) {
} }
void lkmc_assert_fail() { void lkmc_assert_fail() {
puts("lkmc_test_fail"); puts("lkmc_test_fail");
exit(1); 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__) #if defined(__aarch64__)

6
lkmc.h
View File

@@ -1,13 +1,17 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#lkmc-c */
#ifndef LKMC_H #ifndef LKMC_H
#define LKMC_H #define LKMC_H
/* Common C definitions. */ /* Common C definitions. */
#if !defined(__ASSEMBLER__) #if !defined(__ASSEMBLER__)
#include <stdbool.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
void lkmc_assert(bool); void lkmc_assert(bool);
void lkmc_assert_fail(); void lkmc_assert_fail();
bool lkmc_vector_equal(size_t n, double *v1, double *v2, double max_err);
#endif #endif
/* https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg */ /* https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg */

View File

@@ -3,23 +3,20 @@
#define _XOPEN_SOURCE 700 #define _XOPEN_SOURCE 700
#include <fcntl.h> /* open */ #include <fcntl.h> /* open */
#include <math.h> /* fabs */
#include <stdint.h> /* uint64_t */ #include <stdint.h> /* uint64_t */
#include <stdlib.h> /* size_t */
#include <stdio.h> /* snprintf */ #include <stdio.h> /* snprintf */
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> /* pread, sysconf */ #include <unistd.h> /* pread, sysconf */
#include <stdbool.h>
/* Format documented at: /* Format documented at:
* https://github.com/torvalds/linux/blob/v4.9/Documentation/vm/pagemap.txt * https://github.com/torvalds/linux/blob/v4.9/Documentation/vm/pagemap.txt
*/ */
typedef struct { typedef struct {
uint64_t pfn : 54; uint64_t pfn : 54;
unsigned int soft_dirty : 1; unsigned int soft_dirty : 1;
unsigned int file_page : 1; unsigned int file_page : 1;
unsigned int swapped : 1; unsigned int swapped : 1;
unsigned int present : 1; unsigned int present : 1;
} PagemapEntry; } PagemapEntry;
/* Parse the pagemap entry for the given virtual address. /* 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) int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr)
{ {
size_t nread; size_t nread;
ssize_t ret; ssize_t ret;
uint64_t data; uint64_t data;
uintptr_t vpn; uintptr_t vpn;
vpn = vaddr / sysconf(_SC_PAGE_SIZE); vpn = vaddr / sysconf(_SC_PAGE_SIZE);
nread = 0; nread = 0;
while (nread < sizeof(data)) { while (nread < sizeof(data)) {
ret = pread( ret = pread(
pagemap_fd, pagemap_fd,
&data, &data,
sizeof(data) - nread, sizeof(data) - nread,
vpn * sizeof(data) + nread vpn * sizeof(data) + nread
); );
nread += ret; nread += ret;
if (ret <= 0) { if (ret <= 0) {
return 1; return 1;
} }
} }
entry->pfn = data & (((uint64_t)1 << 54) - 1); entry->pfn = data & (((uint64_t)1 << 54) - 1);
entry->soft_dirty = (data >> 54) & 1; entry->soft_dirty = (data >> 54) & 1;
entry->file_page = (data >> 61) & 1; entry->file_page = (data >> 61) & 1;
entry->swapped = (data >> 62) & 1; entry->swapped = (data >> 62) & 1;
entry->present = (data >> 63) & 1; entry->present = (data >> 63) & 1;
return 0; return 0;
} }
/* Convert the given virtual address to physical using /proc/PID/pagemap. /* 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) int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr)
{ {
char pagemap_file[BUFSIZ]; char pagemap_file[BUFSIZ];
int pagemap_fd; int pagemap_fd;
snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid); snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
pagemap_fd = open(pagemap_file, O_RDONLY); pagemap_fd = open(pagemap_file, O_RDONLY);
if (pagemap_fd < 0) { if (pagemap_fd < 0) {
return 1; return 1;
} }
PagemapEntry entry; PagemapEntry entry;
if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) { if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
return 1; return 1;
} }
close(pagemap_fd); close(pagemap_fd);
*paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE)); *paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE));
return 0; 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;
} }
#endif #endif

View File

@@ -1,16 +1,15 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#blas /* https://github.com/cirosantilli/linux-kernel-module-cheat#blas
* Adapted from: https://github.com/xianyi/OpenBLAS/wiki/User-Manual/59b62f98e7400270fb03ad1d85fba5b64ebbff2b#call-cblas-interface */ * Adapted from: https://github.com/xianyi/OpenBLAS/wiki/User-Manual/59b62f98e7400270fb03ad1d85fba5b64ebbff2b#call-cblas-interface */
#include "common_userland.h" #include "lkmc.h"
#include <assert.h> #include <assert.h>
#include <cblas.h> #include <cblas.h>
int main(void) int main(void) {
{ double A[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0};
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 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};
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);
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));
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));
} }