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.
==== 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
==== Automated tests

View File

@@ -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.

View File

@@ -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__':

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_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')

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 <stdlib.h>
@@ -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__)

6
lkmc.h
View File

@@ -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 <stdbool.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
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 */

View File

@@ -3,23 +3,20 @@
#define _XOPEN_SOURCE 700
#include <fcntl.h> /* open */
#include <math.h> /* fabs */
#include <stdint.h> /* uint64_t */
#include <stdlib.h> /* size_t */
#include <stdio.h> /* snprintf */
#include <sys/types.h>
#include <unistd.h> /* pread, sysconf */
#include <stdbool.h>
/* 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

View File

@@ -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 <assert.h>
#include <cblas.h>
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));
}