mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
lkmc_vector_equal into lkmc.c
Document lkmc.c
This commit is contained in:
17
README.adoc
17
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.
|
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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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__':
|
||||||
|
|||||||
11
common.py
11
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_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
20
lkmc.c
@@ -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
6
lkmc.h
@@ -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 */
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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));
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user