@@ -11,11 +11,11 @@ About Linker tables
.. kernel-doc:: include/linux/tables.h
:doc: Introduction
-Linker table provenance
+Linker table provenance and userspace testing
---------------------------------------------
.. kernel-doc:: include/linux/tables.h
- :doc: Linker table provenance
+ :doc: Linker table provenance and userspace testing
Benefits of using Linker tables
===============================
@@ -5210,6 +5210,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux-next.git secti
S: Supported
F: include/asm-generic/tables.h
F: include/linux/tables.h
+F: tools/linker-tables/
F: Documentation/sections/linker-tables.rst
GENERIC PHY FRAMEWORK
@@ -35,12 +35,13 @@
*/
/**
- * DOC: Linker table provenance
+ * DOC: Linker table provenance and userspace testing
*
* The Linux implementation of linker tables was inspired by the iPXE linker
* table's solution (iPXE commit 67a10ef000cb7 "[contrib] Add rom-o-matic to
* contrib "[0]). To see how this code evolved refer to the out of tree
- * userspace linker-table tree [1].
+ * userspace linker-table tree [1]. Linux has a similar userspace application
+ * in tools/linker-tables/ to help more easily test adding new extensions.
*
* Contrary to iPXE's solution which strives to force compilation of
* everything using linker tables, Linux's solution allows for developers to be
@@ -18,6 +18,7 @@ help:
@echo ' iio - IIO tools'
@echo ' kvm_stat - top-like utility for displaying kvm statistics'
@echo ' lguest - a minimal 32-bit x86 hypervisor'
+ @echo ' linker-tables - userspace liker table sandbox and related tools'
@echo ' net - misc networking tools'
@echo ' perf - Linux performance measurement and analysis tool'
@echo ' selftests - various kernel selftests'
@@ -85,7 +86,7 @@ tmon: FORCE
freefall: FORCE
$(call descend,laptop/$@)
-all: acpi cgroup cpupower gpio hv firewire lguest \
+all: acpi cgroup cpupower gpio hv firewire lguest linker-tables \
perf selftests turbostat usb \
virtio vm net x86_energy_perf_policy \
tmon freefall objtool
new file mode 100644
@@ -0,0 +1 @@
+#include <asm-generic/section-core.h>
new file mode 100644
@@ -0,0 +1 @@
+#include <asm-generic/ranges.h>
new file mode 100644
@@ -0,0 +1 @@
+#include <asm-generic/tables.h>
new file mode 100644
@@ -0,0 +1,103 @@
+#ifndef _ASM_GENERIC_RANGES_H_
+#define _ASM_GENERIC_RANGES_H_
+/*
+ * Copyright (C) 2016 Luis R. Rodriguez <mcgrof@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of copyleft-next (version 0.3.1 or later) as published
+ * at http://copyleft-next.org/.
+ */
+#include <asm/section-core.h>
+
+#define SECTION_RNG(section, name) \
+ SECTION_CORE(section, rng, name, \
+ SECTION_ORDER_ANY)
+
+#define SECTION_RNG_LEVEL(section, name, level) \
+ SECTION_CORE(section, rng, name, level)
+
+#define SECTION_RNG_ALL(section) \
+ SECTION_CORE_ALL(section,rng)
+
+#ifndef set_section_rng
+# define set_section_rng(section, name, flags) \
+ set_section_core(section, rng, name, \
+ SECTION_ORDER_ANY, flags)
+#endif
+
+#ifndef set_section_rng_type
+# define set_section_rng_type(section, name, flags, type) \
+ set_section_core_type(section, rng, name, \
+ SECTION_ORDER_ANY, flags, type)
+#endif
+
+#ifndef set_section_rng_level
+# define set_section_rng_level(section, name, level, flags) \
+ set_section_core(section, rng, name, level, flags)
+#endif
+
+#ifndef push_section_rng
+# define push_section_rng(section, name, flags) \
+ push_section_core(section, rng, name, \
+ SECTION_ORDER_ANY, flags)
+#endif
+
+#ifndef push_section_rng_level
+# define push_section_rng_level(section, name, level, flags) \
+ push_section_core(section, rng, name, \
+ level, flags)
+#endif
+
+#ifndef __ASSEMBLY__
+/**
+ * __LINUX_RANGE - short hand association into a section range
+ *
+ * @section: ELF section name to place section range into
+ * @name: section range name
+ *
+ * This helper can be used by subsystems to define their own subsystem
+ * specific helpers to easily associate a piece of code being defined to a
+ * section range.
+ */
+#define __LINUX_RANGE(section, name) \
+ __attribute__((__section__(SECTION_RNG(section, name))))
+
+/**
+ * __LINUX_RANGE_ORDER - short hand association into a section range of order
+ *
+ * @section: ELF section name to place section range into
+ * @name: section range name
+ * @level: order level, a number. The order level gets tucked into the
+ * section as a postfix string. Order levels are sorted using
+ * binutils SORT(), the number is sorted as a string, as such be
+ * sure to fill with zeroes any empty digits. For instance if you are
+ * using 3 levels of digits for order levels, use 001 for the first entry,
+ * 0002 for the second, 999 for the last entry. You can use however many
+ * digits you need.
+ *
+ * This helper can be used by subsystems to define their own subsystem specific
+ * helpers to easily associate a piece of code being defined to a section range
+ * with an associated specific order level. The order level provides the
+ * ability for explicit user ordering of code. Sorting takes place at link
+ * time, after compilation.
+ */
+#define __LINUX_RANGE_ORDER(section, name, level) \
+ __attribute__((__section__(SECTION_RNG_LEVEL(section, name, level))))
+
+#endif /* __ASSEMBLY__ */
+
+#ifdef __ASSEMBLER__
+
+#ifndef DEFINE_SECTION_RANGE
+#define DEFINE_SECTION_RANGE(section, name) \
+ push_section_rng_level(section, name,,) ; \
+ .globl name ; \
+name: ; \
+ .popsection \
+ \
+ push_section_rng_level(section, name, ~,) ; \
+ .popsection
+#endif
+#endif /* __ASSEMBLER__ */
+
+#endif /* _ASM_GENERIC_RANGES_H_ */
new file mode 100644
@@ -0,0 +1,341 @@
+#ifndef _ASM_GENERIC_SECTION_CORE_H_
+#define _ASM_GENERIC_SECTION_CORE_H_
+/*
+ * Linux section core definitions
+ *
+ * Copyright (C) 2016 Luis R. Rodriguez <mcgrof@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of copyleft-next (version 0.3.1 or later) as published
+ * at http://copyleft-next.org/.
+ */
+
+/**
+ * DOC: Custom linker script
+ *
+ * The Linux vmlinux binary uses a custom linker script on each architecture
+ * which it uses to strategically place standard ELF sections and also adds
+ * custom specialized ELF sections. Each architecture defines its own custom
+ * linker defined in arch/$(ARCH)/kernel/vmlinux.lds.S -- these in turn
+ * include and use definitions in include/asm-generic/vmlinux.lds.h as well
+ * as some helpers documented in this chaper.
+ */
+
+/**
+ * DOC: Standard ELF section use in Linux
+ *
+ * Linux makes use of the standard ELF sections, this sections documents
+ * these.
+ */
+
+/**
+ * DOC: SECTION_RODATA
+ *
+ * Macro name for code which must be protected from write access, read only
+ * data.
+ */
+#define SECTION_RODATA .rodata
+
+/**
+ * DOC: SECTION_TEXT
+ *
+ * Macro name used to annotate code (functions) used during regular
+ * kernel run time. This is combined with `SECTION_RODATA`, only this
+ * section also allows for execution.
+ *
+ */
+#define SECTION_TEXT .text
+
+/**
+ * DOC: SECTION_DATA
+ *
+ * Macro name for read-write data.
+ */
+#define SECTION_DATA .data
+
+/**
+ * DOC: Linux init sections
+ *
+ * These sections are used for code and data structures used during boot or
+ * module initialization. On architectures that support it (x86, x86_64), all
+ * this code is freed up by the kernel right before the fist userspace init
+ * process is called when built-in to the kernel, and if modular it is freed
+ * after module initialization. Since the code is freed so early, in theory
+ * there should be no races against freeing this code with other CPUs. Init
+ * section code and data structures should never be exported with
+ * EXPORT_SYMBOL*() as the code will quickly become unavailable to the kernel
+ * after bootup.
+ */
+
+/**
+ * DOC: SECTION_INIT
+ *
+ * Macro name used to annotate code (functions) used only during boot or driver
+ * initialization.
+ *
+ */
+#define SECTION_INIT .init.text
+
+/**
+ * DOC: SECTION_INIT_DATA
+ *
+ * Macro name used to annotate data structures used only during boot or driver
+ * initialization.
+ */
+#define SECTION_INIT_DATA .init.data
+
+/**
+ * DOC: SECTION_INIT_RODATA
+ *
+ * Macro name used to annotate read-only code (functions) used only during boot
+ * or driver initialization.
+ */
+#define SECTION_INIT_RODATA .init.rodata
+
+/**
+ * DOC: SECTION_INIT_CALL
+ *
+ * Special macro name used to annotate subsystem init call. These calls are
+ * are now grouped by functionality into separate subsections. Ordering inside
+ * the subsections is determined by link order.
+ */
+#define SECTION_INIT_CALL .initcall
+
+/**
+ * DOC: Linux exit sections
+ *
+ * These sections are used to declare a functions and data structures which
+ * are only required on exit, the function or data structure will be dropped
+ * if the code declaring this section is not compiled as a module on
+ * architectures that support this (x86, x86_64). There is no special case
+ * handling for this code when built-in to the kernel.
+ */
+
+/**
+ * DOC: SECTION_EXIT
+ *
+ * Macro name used to annotate code (functions) used only during module
+ * unload.
+ */
+#define SECTION_EXIT .exit.text
+
+/**
+ * DOC: SECTION_EXIT_DATA
+ *
+ * Macro name used to annotate data structures used only during module
+ * unload.
+ */
+#define SECTION_EXIT_DATA .exit.data
+
+/**
+ * DOC: SECTION_EXIT_CALL
+ *
+ * Special macro name used to annotate an exit exit routine, order
+ * is important and maintained by link order.
+ */
+#define SECTION_EXIT_CALL .exitcall.exit
+
+/**
+ * DOC: Linux references to init sections
+ *
+ * These sections are used to teach modpost to not warn about possible
+ * misuses of init section code from other sections. If you use this
+ * your use case should document why you are certain such use of init
+ * sectioned code is valid. For more details refer to ``include/linux/init.h``
+ * ``__ref``, ``__refdata``, and ``__refconst`` documentation.
+ */
+
+/**
+ * DOC: SECTION_REF
+ *
+ * Macro name used to annotate that code (functions) declared with this section
+ * has been vetteed as valid for its reference or use of other code (functions)
+ * or data structures which are part of the init sections.
+ */
+#define SECTION_REF .ref.text
+
+/**
+ * DOC: SECTION_REF_DATA
+ *
+ * Macro name used to annotate data structures declared with this section have
+ * been vetteed for its reference or use of other code (functions) or data
+ * structures part of the init sections.
+ */
+#define SECTION_REF_DATA .ref.data
+
+/**
+ * DOC: SECTION_REF_RODATA
+ *
+ * Macro name used to annotate const code (functions) const data structures
+ * which has been vetteed for its reference or use of other code (functions)
+ * or data structures part of the init sections.
+ */
+#define SECTION_REF_RODATA .ref.rodata
+
+/**
+ * DOC: Linux section ordering
+ *
+ * Linux may use binutils linker-script 'SORT()' on sections to sort Linux
+ * sections. Linux has used 'SORT()' in ``include/asm-generic/vmlinux.lds.h``
+ * for years.
+ */
+
+/**
+ * DOC: SECTION_ORDER_ANY
+ *
+ * Macro name which can be used as helper to annotate custom section
+ * ordering at link time is not relevant for specific sections.
+ */
+#define SECTION_ORDER_ANY any
+
+/*
+ * These section _ALL() helpers are for use on linker scripts and helpers
+ */
+#define SECTION_ALL(__section) \
+ __section##.*
+
+#define __SECTION_CORE(__section, __core, __name, __level) \
+ __section.__core.__name.__level
+
+#define SECTION_CORE_ALL(__section, __core) \
+ __section##.##__core##.*
+
+/* Can be used on foo.S for instance */
+#ifndef __set_section_core_type
+# define __set_section_core_type(___section, ___core, ___name, \
+ ___level, ___flags, ___type) \
+ .section ___section.___core.___name.___level, ___flags, ___type
+#endif
+
+#ifndef __set_section_core
+# define __set_section_core(___section, ___core, ___name, ___level, ___flags) \
+ .section ___section.___core.___name.___level, ___flags
+#endif
+
+#ifndef __push_section_core
+# define __push_section_core(__section, __core, __name, __level, __flags) \
+ .pushsection __section.__core.__name.__level, __flags
+#endif
+
+#ifdef __KERNEL__
+#include <linux/stringify.h>
+#endif
+
+#if defined(__ASSEMBLER__) || defined(__ASSEMBLY__)
+
+# ifdef LINKER_SCRIPT
+
+# ifndef SECTION_CORE
+# define SECTION_CORE(__section, __core, __name, __level) \
+ __SECTION_CORE(__section,__core,__name,__level)
+# endif
+
+# else
+
+# ifndef SECTION_CORE
+# define SECTION_CORE(__section, __core, __name, __level) \
+ push_section_core(__section, __core, __name, __level,)
+# endif
+
+# ifndef push_section_core
+# define push_section_core(__section, __core, __name, __level, __flags) \
+ __push_section_core(__section, __core, __name, \
+ __level, __stringify(__flags))
+# endif
+
+# ifndef set_section_core
+# define set_section_core(__section, __core, __name, \
+ __level, __flags) \
+ __set_section_core(__section, __core, __name, \
+ __level, __stringify(__flags))
+# endif
+
+# ifndef set_section_core_type
+# define set_section_core_type(__section, __core, __name, \
+ __level, __flags, __type) \
+ __set_section_core_type(__section, __core, __name, __level, \
+ __stringify(__flags), __type)
+# endif
+
+# endif /* LINKER_SCRIPT */
+#else /* defined(__ASSEMBLER__) || defined(__ASSEMBLY__) */
+
+# ifndef SECTION_CORE
+# define SECTION_CORE(__section, __core, __name, __level) \
+ __stringify(__SECTION_CORE(__section,__core,__name,__level))
+# endif
+
+/*
+ * As per gcc's documentation a common asm separator is a new line followed
+ * by tab [0], it however seems possible to also just use a newline as its
+ * the most commonly empirically observed semantic and folks seem to agree
+ * this even works on S390. In case your architecture disagrees you may
+ * override this and define your own and keep the rest of the macros.
+ *
+ * [0] https://gcc.gnu.org/onlinedocs/gcc/Basic-Asm.html#Basic-Asm
+ */
+# ifndef ASM_CMD_SEP
+# define ASM_CMD_SEP "\n"
+# endif
+
+# ifndef set_section_core
+# define set_section_core(__section, __core, __name, __level, __flags) \
+ __stringify(__set_section_core_type(__section, __core, __name, \
+ __level, __stringify(__flags))) \
+ ASM_CMD_SEP
+# endif
+
+/*
+ * Some architectures (arm, and avr32 are two examples on kprobes) seem
+ * currently explicitly specify the type [0] -- this can be any of the
+ * optional constants on ELF:
+ *
+ * @progbits - section contains data
+ * @nobits - section does not contain data (i.e., section only occupies space)
+ * @note - section contains data which is used by things other than the program
+ * @init_array - section contains an array of pointers to init functions
+ * @fini_array - section contains an array of pointers to finish functions
+ * @preinit_array - section contains an array of pointers to pre-init functions
+ *
+ * ARM requires % instead of @.
+ *
+ * At least as per nasm (x86/x86_64 only), in the absence of qualifiers the
+ * defaults are as follows:
+ *
+ * section .text progbits alloc exec nowrite align=16
+ * section .rodata progbits alloc noexec nowrite align=4
+ * section .lrodata progbits alloc noexec nowrite align=4
+ * section .data progbits alloc noexec write align=4
+ * section .ldata progbits alloc noexec write align=4
+ * section .bss nobits alloc noexec write align=4
+ * section .lbss nobits alloc noexec write align=4
+ * section .tdata progbits alloc noexec write align=4 tls
+ * section .tbss nobits alloc noexec write align=4 tls
+ * section .comment progbits noalloc noexec nowrite align=1
+ * section other progbits alloc noexec nowrite align=1
+ *
+ * gas should have sensible defaults for architectures...
+ *
+ * [0] http://www.nasm.us/doc/nasmdoc7.html
+ */
+# ifndef set_section_core_type
+# define set_section_core_type(__section, __core, __name, __level, \
+ __flags, __type) \
+ __stringify(__set_section_core_type(__section, __core, \
+ __name, __level, \
+ __stringify(__flags), \
+ __type)) \
+ ASM_CMD_SEP
+# endif
+
+# ifndef push_section_core
+# define push_section_core(__section, __core, __name, \
+ __level, __flags) \
+ __stringify(__push_section_core(__section, __core, \
+ __name, __level, \
+ __stringify(__flags))) \
+ ASM_CMD_SEP
+# endif
+
+#endif /* defined(__ASSEMBLER__) || defined(__ASSEMBLY__) */
+#endif /* _ASM_GENERIC_SECTION_CORE_H_ */
new file mode 100644
@@ -0,0 +1,50 @@
+#ifndef _ASM_GENERIC_TABLES_H_
+#define _ASM_GENERIC_TABLES_H_
+/*
+ * Linux linker tables
+ *
+ * Copyright (C) 2016 Luis R. Rodriguez <mcgrof@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of copyleft-next (version 0.3.1 or later) as published
+ * at http://copyleft-next.org/.
+ */
+#include <asm/section-core.h>
+
+#define SECTION_TBL(section, name, level) \
+ SECTION_CORE(section, tbl, name, level)
+
+#define SECTION_TBL_ALL(section) \
+ SECTION_CORE_ALL(section,tbl)
+
+/* Some toolchains are buggy, let them override */
+#ifndef SECTION_TBL_RO
+# define SECTION_TBL_RO SECTION_RODATA
+#endif
+
+#ifndef set_section_tbl
+# define set_section_tbl(section, name, level, flags) \
+ set_section_core(section, tbl, name, level, flags)
+#endif
+
+#ifndef set_section_tbl_any
+# define set_section_tbl_any(section, name, flags) \
+ set_section_core(section, tbl, name, SECTION_ORDER_ANY, flags)
+#endif
+
+#ifndef set_section_tbl_type
+# define set_section_tbl_type(section, name, level, flags, type) \
+ set_section_core_type(section, tbl, name, level, flags, type)
+#endif
+
+#ifndef push_section_tbl
+# define push_section_tbl(section, name, level, flags) \
+ push_section_core(section, tbl, name, level, flags)
+#endif
+
+#ifndef push_section_tbl_any
+# define push_section_tbl_any(section, name, flags) \
+ push_section_core(section, tbl, name, SECTION_ORDER_ANY, flags)
+#endif
+
+#endif /* _ASM_GENERIC_TABLES_H_ */
new file mode 100644
@@ -0,0 +1,128 @@
+#ifndef _LINUX_RANGES_H
+#define _LINUX_RANGES_H
+/*
+ * Linux section ranges
+ *
+ * Copyright (C) 2016 Luis R. Rodriguez <mcgrof@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of copyleft-next (version 0.3.1 or later) as published
+ * at http://copyleft-next.org/.
+ */
+#include <linux/sections.h>
+#include <asm/ranges.h>
+
+#ifndef __ASSEMBLY__
+
+/**
+ * DOC: Introduction
+ *
+ * A section ranges consists of explicitly annotated series executable code
+ * stitched together for the purpose of selective placement into standard or
+ * architecture specific ELF sections. What ELF section is used is utility
+ * specific. Linux has historically implicitly used section ranges, however
+ * they were all built in an adhoc manner and typically required linker script
+ * modifications per architecture. The section range API allows adding new
+ * bundles of stiched executable code into custom ELF sections by only
+ * modifying C or asm code in an architecture agnostic form.
+ *
+ * This documents the set of helpers available to declare, and define section
+ * ranges and associate each section range to a specific Linux ELF section.
+ */
+
+/**
+ * DOC: Section range module support
+ *
+ * Modules can use section ranges, however the section range definition must be
+ * built-in to the kernel. That is, the code that implements
+ * DEFINE_SECTION_RANGE() must be built-in, and modular code cannot add more
+ * items in to the section range (with __LINUX_RANGE() or
+ * __LINUX_RANGE_ORDER()), unless kernel/module.c find_module_sections() and
+ * module-common.lds.S are updated accordingly with a respective module
+ * notifier to account for updates. This restriction may be enhanced in the
+ * future.
+ */
+
+/**
+ * DOC: Section range helpers
+ *
+ * These are helpers for section ranges.
+ */
+
+/**
+ * DECLARE_SECTION_RANGE - Declares a section range
+ *
+ * @name: section range name
+ *
+ * Declares a section range to help code access the range. Typically if
+ * a subsystems needs code to have direct access to the section range the
+ * subsystem's header file would declare the section range. Care should be
+ * taken to only declare the section range in a header file if access to it
+ * is truly needed outside of the code defining it. You typically would
+ * rather instead provide helpers which access the section range with special
+ * code on behalf of the caller.
+ */
+#define DECLARE_SECTION_RANGE(name) \
+ DECLARE_LINUX_SECTION_RO(char, name)
+
+/**
+ * __SECTION_RANGE_BEGIN - Constructs the beginning of a section range
+ *
+ * @name: section range name
+ * @__section: ELF section to place section range into
+ *
+ * Constructs the beginning of a section range. You will typically not need
+ * to use this directly.
+ */
+#define __SECTION_RANGE_BEGIN(name, __section) \
+ const __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ weak, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_RNG_LEVEL(__section, name,))))
+
+/**
+ * __SECTION_RANGE_END - Constructs the end of a section range
+ *
+ * @name: section range name
+ * @__section: ELF section to place section range into
+ *
+ * Constructs the end of a section range. You will typically not need
+ * to use this directly.
+ */
+#define __SECTION_RANGE_END(name, __section) \
+ const __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_RNG_LEVEL(__section, name, ~))))
+
+/**
+ * DEFINE_SECTION_RANGE - Defines a section range
+ *
+ * @name: section range name
+ * @section: ELF section name to place section range into
+ *
+ * Defines a section range, used for executable code. Section ranges are
+ * defined in the code that takes ownership and makes use of the section
+ * range.
+ */
+#define DEFINE_SECTION_RANGE(name, section) \
+ DECLARE_LINUX_SECTION_RO(char, name); \
+ __SECTION_RANGE_BEGIN(name, section) VMLINUX_SYMBOL(name)[0] = {};\
+ __SECTION_RANGE_END(name, section) VMLINUX_SYMBOL(name##__end)[0] = {}
+
+/**
+ * SECTION_ADDR_IN_RANGE - returns true if address is in range
+ *
+ * @name: section range name
+ * @addr: address to query for
+ *
+ * Returns true if the address is in the section range.
+ */
+#define SECTION_ADDR_IN_RANGE(name, addr) \
+ (addr >= (unsigned long) LINUX_SECTION_START(name) && \
+ addr < (unsigned long) LINUX_SECTION_END(name))
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _LINUX_RANGES_H */
new file mode 100644
@@ -0,0 +1,111 @@
+#ifndef _LINUX_SECTIONS_H
+#define _LINUX_SECTIONS_H
+/*
+ * Linux de-facto sections
+ *
+ * Copyright (C) 2016 Luis R. Rodriguez <mcgrof@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of copyleft-next (version 0.3.1 or later) as published
+ * at http://copyleft-next.org/.
+ */
+
+#include <asm/section-core.h>
+#include <linux/export.h>
+
+#ifndef __ASSEMBLY__
+
+/**
+ * DOC: Introduction
+ *
+ * Linux defines a set of common helpers which can be used to against its use
+ * of standard or custom Linux sections, this section is dedicated to these
+ * helpers.
+ */
+
+/**
+ * LINUX_SECTION_ALIGNMENT - get section alignment
+ *
+ * @name: section name
+ *
+ * Gives you the alignment for the section.
+ */
+#define LINUX_SECTION_ALIGNMENT(name) __alignof__(*VMLINUX_SYMBOL(name))
+
+/**
+ * LINUX_SECTION_SIZE - get number of entries in the section
+ *
+ * @name: section name
+ *
+ * This gives you the number of entries in the section.
+ * Example usage:
+ *
+ * unsigned int num_frobs = LINUX_SECTION_SIZE(frobnicator_fns);
+ */
+#define LINUX_SECTION_SIZE(name) \
+ ((VMLINUX_SYMBOL(name##__end)) - (VMLINUX_SYMBOL(name)))
+
+/**
+ * LINUX_SECTION_EMPTY - check if section has no entries
+ *
+ * @name: section name
+ *
+ * Returns true if section is emtpy.
+ *
+ * bool is_empty = LINUX_SECTION_EMPTY(frobnicator_fns);
+ */
+#define LINUX_SECTION_EMPTY(name) (LINUX_SECTION_SIZE(name) == 0)
+
+/**
+ * LINUX_SECTION_START - get address of start of section
+ *
+ * @name: section name
+ *
+ * This gives you the start address of the section.
+ * This should give you the address of the first entry.
+ *
+ */
+#define LINUX_SECTION_START(name) VMLINUX_SYMBOL(name)
+
+/**
+ * LINUX_SECTION_END - get address of end of the section
+ *
+ * @name: section name
+ *
+ * This gives you the end address of the section.
+ * This should give you the address of the end of the
+ * section. This will match the start address if the
+ * section is empty.
+ */
+#define LINUX_SECTION_END(name) VMLINUX_SYMBOL(name##__end)
+
+/**
+ * DECLARE_LINUX_SECTION - Declares a custom Linux section
+ *
+ * @type: type of custom Linux section
+ * @name: custom section name
+ *
+ * Declares a read-write custom Linux section
+ */
+#define DECLARE_LINUX_SECTION(type, name) \
+ extern type VMLINUX_SYMBOL(name)[], \
+ VMLINUX_SYMBOL(name##__end)[]
+
+/**
+ * DECLARE_LINUX_SECTION_RO - Declares a read-only custom Linux section
+ *
+ * @type: type of custom Linux section
+ * @name: custom section name
+ *
+ * Declares a read-only custom Linux section
+ */
+#define DECLARE_LINUX_SECTION_RO(type, name) \
+ extern const type VMLINUX_SYMBOL(name)[], \
+ VMLINUX_SYMBOL(name##__end)[]
+
+#define __SECTION_TYPE(section, type, name, level) \
+ #section "." #type "." #name "." #level
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _LINUX_SECTIONS_H */
@@ -3,6 +3,7 @@
#include <linux/types.h> /* for size_t */
+#include <string.h>
void *memdup(const void *src, size_t len);
new file mode 100644
@@ -0,0 +1,664 @@
+#ifndef _LINUX_LINKER_TABLES_H
+#define _LINUX_LINKER_TABLES_H
+/*
+ * Linux linker tables
+ *
+ * Copyright (C) 2016 Luis R. Rodriguez <mcgrof@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of copyleft-next (version 0.3.1 or later) as published
+ * at http://copyleft-next.org/.
+ */
+#include <linux/export.h>
+#include <linux/sections.h>
+#include <asm/tables.h>
+
+#ifndef __ASSEMBLY__
+
+/**
+ * DOC: Introduction
+ *
+ * A linker table is a data structure that is stitched together from items in
+ * multiple object files for the purpose of selective placement into standard
+ * or architecture specific ELF sections. What section is used is utility
+ * specific. Linux has historically implicitly used linker tables, however they
+ * were all built in an adhoc manner which requires linker script modifications
+ * per architecture. The linker table API provides a general facility so that
+ * data structures can be stitched together and placed into Linux ELF sections
+ * by only changing C or asm code in an architecture agnostic form.
+ *
+ * Linker tables help you group together related data and code in an efficient
+ * way. Linker tables can be used to help simplify init sequences, they
+ * enable linker build time selective sorting (disabled options get ignored),
+ * and can optionally also be used to help you avoid code bit-rot due to
+ * overuse of #ifdef.
+ */
+
+/**
+ * DOC: Linker table provenance and userspace testing
+ *
+ * The Linux implementation of linker tables was inspired by the iPXE linker
+ * table's solution (iPXE commit 67a10ef000cb7 "[contrib] Add rom-o-matic to
+ * contrib "[0]). To see how this code evolved refer to the out of tree
+ * userspace linker-table tree [1]. Linux has a similar userspace application
+ * in tools/linker-tables/ to help more easily test adding new extensions.
+ *
+ * Contrary to iPXE's solution which strives to force compilation of
+ * everything using linker tables, Linux's solution allows for developers to be
+ * selective over where one wishes to force compilation, this then is just an
+ * optional feature for the Linux linker table solution. The main advantages
+ * of using linker-tables then are:
+ *
+ * - Avoiding modifying architecture linker scripts
+ * - Simplifying initialization code
+ * - Avoiding the code bit-rot problem
+ *
+ * [0] git://git.ipxe.org/ipxe.git
+ *
+ * [1] https://git.kernel.org/cgit/linux/kernel/git/mcgrof/linker-tables.git/
+ */
+
+/**
+ * DOC: Avoids modifying architecture linker scripts
+ *
+ * Linker tables enable you to avoid modifying architecture linker scripts
+ * since it has its has extended each core Linux section with a respective
+ * linker table entry in `include/asm-generic/vmlinux.lds.h`. When you add new
+ * linker table entry you aggregate them `into` the existing linker table core
+ * section.
+ */
+
+/**
+ * DOC: How linker tables simplify initialization code
+ *
+ * Traditionally, we would implement features in C code as follows:
+ *
+ * foo_init();
+ *
+ * You'd then have a foo.h which would have::
+ *
+ * #ifndef CONFIG_FOO
+ * static inline void foo_init(void) { }
+ * #endif
+ *
+ * With linker tables this is no longer necessary as your init routines would
+ * be implicit, you'd instead call:
+ *
+ * call_init_fns();
+ *
+ * call_init_fns() would call all functions present in your init table and if
+ * and only if foo.o gets linked in, then its initialisation function will be
+ * called.
+ *
+ * The linker script takes care of assembling the tables for us. All of our
+ * table sections have names of the format `SECTION_NAME.tbl.NAME.N`. Here
+ * `SECTION_NAME` is one of the standard sections in::
+ *
+ * include/asm-generic/section-core.h
+ *
+ * and `NAME` designates the specific use case for the linker table, the table.
+ * `N` is a digit used to help sort entries in the section. `N=` (empty string)
+ * is reserved for the symbol indicating `table start`, and `N=~` is reserved
+ * for the symbol indicating `table end`. In order for the call_init_fns() to
+ * work behind the scenes the custom linker script would need to define the
+ * beginning of the table, the end of the table, and in between it should use
+ * ``SORT()`` to give order to the section. Typically this would require custom
+ * linker script modifications however since linker table are already defined
+ * in ``include/asm-generic/vmlinux.lds.h`` as documented above each new linker
+ * table definition added in C code folds into the respective core Linux
+ * section linker table.
+ *
+ * This is also done to support all architectures. All that is needed then is
+ * to ensure a respective common linker table entry is added to the shared
+ * ``include/asm-generic/vmlinux.lds.h``. There should be a respective::
+ *
+ * *(SORT(SECTION_TBL_ALL(SECTION_NAME)))
+ *
+ * entry for each type of supported section there. If your `SECTION_NAME`
+ * is not yet supported, consider adding support for it.
+ *
+ * Linker tables support ordering entries, it does this using a digit which
+ * is eventually added as a postfix to a section entry name, we refer to this
+ * as the linker table ``order-level``. If order is not important to your
+ * linker table entry you can use the special ``SECTION_ORDER_ANY``. After
+ * ``order-level``, the next contributing factor to order is the order of the
+ * code in the C file, and the order of the objects in the Makefile. Using an
+ * ``order-level`` then should not really be needed in most cases, its use
+ * however enables to compartamentalize code into tables where ordering through
+ * C file or through the Makefile would otherwise be very difficult or if one
+ * wanted to enable very specific initialization semantics.
+ *
+ * As an example, suppose that we want to create a "frobnicator"
+ * feature framework, and allow for several independent modules to
+ * provide frobnicating services. Then we would create a frob.h
+ * header file containing e.g.::
+ *
+ * struct frobnicator {
+ * const char *name;
+ * void (*frob) (void);
+ * };
+ *
+ * DECLARE_LINKTABLE(struct frobnicator, frobnicator_fns);
+ *
+ * Any module providing frobnicating services would look something
+ * like::
+ *
+ * #include "frob.h"
+ *
+ * static void my_frob(void) {
+ * ... Do my frobnicating
+ * }
+ *
+ * LINKTABLE_INIT_DATA(frobnicator_fns, all) my_frobnicator = {
+ * .name = "my_frob",
+ * .frob = my_frob,
+ * };
+ *
+ * The central frobnicator code, say in frob.c, would use the frobnicating
+ * modules as follows::
+ *
+ * #include "frob.h"
+ *
+ * void frob_all(void) {
+ * struct frobnicator *f;
+ *
+ * LINKTABLE_FOR_EACH(f, frobnicator_fns) {
+ * pr_info("Calling frobnicator %s\n", frob->name);
+ * f->frob();
+ * }
+ * }
+ */
+
+
+/**
+ * DOC: The code bit-rot problem
+ *
+ * Overuse of C #ifdefs can be problematic for certain types of code. Linux
+ * provides a rich array of features, but all these features take up valuable
+ * space in a kernel image. The traditional solution to this problem has been
+ * for each feature to have its own Kconfig entry and for the respective code
+ * to be wrapped around #ifdefs, allowing the feature to be compiled in only
+ * if enabled in Kconfig.
+ *
+ * The problem with this is that over time it becomes very difficult and time
+ * consuming to compile, let alone test all possible Kconfig configurations.
+ * Code that is not typically used tends to suffer from bit-rot over time. It
+ * can become difficult to predict which combinations of compile-time options
+ * will result in code that can compile and link correctly.
+ */
+
+/**
+ * DOC: Avoiding the code bit-rot problem when desirable
+ *
+ * Linker tables can be used as one way to help solve the code bit-rot problem,
+ * and in turn diminish Kconfig complexity. To use linker tables and to
+ * optionally take advantage of avoiding code bit-rot, feature code should be
+ * implemented in separate C files, and should be designed to always be
+ * compiled -- they should not be guarded with C code ``#ifdef CONFIG_FOO``
+ * statements, consideration must also be taken for sub-features which depend
+ * on the main ``CONFIG_FOO`` option, as they will be disabled if they depend
+ * on ``CONFIG_FOO`` and therefore not compiled.
+ *
+ * To take advantage of this feature enable ``CONFIG_BUILD_AVOID_BITROT``, and
+ * use special targets for your code. Either ``force-obj-y`` or ``force-lib-y``
+ * can be used for your code instead of ``obj-y`` and ``lib-y``, respectively.
+ * Without ``CONFIG_BUILD_AVOID_BITROT`` enabled these targets will work just
+ * as their respective ``obj-y`` and ``lib-y`` counters work. When
+ * ``CONFIG_BUILD_AVOID_BITROT`` is enabled the code with the special targets
+ * will always compile, even if the respective Kconfig entry for the code in
+ * question has been disabled, this code however will only be linked in to the
+ * final kernel image if the Kconfig entry for the code was enabled.
+ *
+ * Currently only built-in features are supported, modular support is not
+ * yet supported, however you can make use of sub-features for modules
+ * if they are independent and can simply be linked into modules.
+ *
+ * Care should be taken to vet that the code using this feature may also work
+ * without ``CONFIG_BUILD_AVOID_BITROT``, otherwise it must depend on
+ * CONFIG_BUILD_AVOID_BITROT.
+ */
+
+/**
+ * DOC: Using target force-obj-y and force-lib-y
+ *
+ * Let's assume we want to always force compilation of feature ``FOO`` in the
+ * kernel but avoid linking it. When you enable the ``FOO`` feature via Kconfig
+ * you'd end up with::
+ *
+ * #define CONFIG_FOO 1
+ *
+ * You typically would then just use this in your Makefile to selectively
+ * compile and link the feature::
+ *
+ * obj-$(CONFIG_FOO) += foo.o
+ *
+ * You could instead optionally use the new linker table target object::
+ *
+ * force-obj-$(CONFIG_FOO) += foo.o
+ *
+ * Alternatively, this would be the equivalent of listing::
+ *
+ * extra += foo.o
+ * obj-$(CONFIG_FOO) += foo.o
+ *
+ * Both are mechanisms which can be used to take advantage of forcing
+ * compilation with linker tables, however making use of::
+ *
+ * force-obj-$(CONFIG_FOO)
+ *
+ * is encouraged as it helps with annotating linker tables clearly where
+ * compilation is forced. The ``force-lib-y`` target is the equivalent for
+ * ``lib-y`` targets.
+ */
+
+/**
+ * DOC: Linker table module support
+ *
+ * Modules can use linker tables, however the linker table definition
+ * must be built-in to the kernel. That is, the code that implements
+ * ``DEFINE_LINKTABLE*()`` must be built-in, and modular code cannot add
+ * more items in to the table, unless ``kernel/module.c`` find_module_sections()
+ * and module-common.lds.S are updated accordingly with a respective
+ * module notifier to account for updates. This restriction may be enhanced
+ * in the future.
+ */
+
+/**
+ * DOC: Opting out of forcing compilation
+ *
+ * If you want to opt-out of forcing compilation simply disable
+ * ``CONFIG_BUILD_AVOID_BITROT``. Alternatively if your kernel configuration
+ * has it and you must have it enabled and you want to opt-out of forcing
+ * compilation you would use the typical ``obj-$(CONFIG_FOO) += foo.o`` and
+ * ``foo.o`` will only be compiled and linked in when ``CONFIG_FOO`` enabled.
+ * Using both ``force-obj-$(CONFIG_FOO)`` and ``obj-($CONFIG_FOO)`` will result
+ * with the feature on your binary only if you've enabled ``CONFIG_FOO``,
+ * however using ``force-obj-$(CONFIG_FOO)`` will always force compilation if
+ * ``CONFIG_BUILD_AVOID_BITROT`` has been enabled.
+ */
+
+/**
+ * DOC: Linker table helpers
+ *
+ * These are helpers for linker tables.
+ */
+
+/**
+ * LINKTABLE_ADDR_WITHIN - returns true if address is in range
+ *
+ * @tbl: linker table
+ * @addr: address to query for
+ *
+ * Returns true if the address is part of the linker table.
+ */
+#define LINKTABLE_ADDR_WITHIN(tbl, addr) \
+ (addr >= (unsigned long) LINUX_SECTION_START(tbl) && \
+ addr < (unsigned long) LINUX_SECTION_END(tbl))
+
+/**
+ * DOC: Constructing linker tables
+ *
+ * Linker tables constructors are used to build an entry into a linker table.
+ * Linker table constructors exist for each type of supported section.
+ *
+ * You have weak and regular type of link table entry constructors.
+ */
+
+/**
+ * DOC: Weak linker tables constructors
+ *
+ * The weak attribute is desirable if you want an entry you can replace at
+ * link time. A very special use case for linker tables is the first entry.
+ * A weak attribute is used for the first entry to ensure that this entry's
+ * address matches the end address of the table when the linker table is
+ * emtpy, but will also point to the first real entry of the table once not
+ * empty. When the first entry is linked in, it takes place of the first entry.
+ */
+
+/**
+ * LINKTABLE_WEAK - Constructs a weak linker table entry for data
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Constructs a weak linker table for data.
+ */
+#define LINKTABLE_WEAK(name, level) \
+ __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ weak, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_DATA, \
+ name, level))))
+
+/**
+ * LINKTABLE_TEXT_WEAK - Constructs a weak linker table entry for execution
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Constructs a weak linker table for code execution. These will be
+ * read-only.
+ */
+#define LINKTABLE_TEXT_WEAK(name, level) \
+ const __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ weak, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_TEXT, \
+ name, level))))
+
+/**
+ * LINKTABLE_RO_WEAK - Constructs a weak read-only linker table entry
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Constructs a weak linker table which only requires read-only access.
+ */
+#define LINKTABLE_RO_WEAK(name, level) \
+ const __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ weak, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_TBL_RO, \
+ name, level))))
+
+/**
+ * LINKTABLE_INIT_WEAK - Constructs a weak linker table entry for init code
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Constructs a weak linker table for execution. use at init.
+ */
+#define LINKTABLE_INIT_WEAK(name, level) \
+ const __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ weak, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_INIT, \
+ name, level))))
+
+/**
+ * LINKTABLE_INIT_DATA_WEAK - Constructs a weak linker table entry for initdata
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Constructs a weak linker table for data during init.
+ */
+#define LINKTABLE_INIT_DATA_WEAK(name, level) \
+ __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ weak, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_INIT_DATA, \
+ name, level))))
+
+/**
+ * DOC: Regular linker linker table constructors
+ *
+ * Regular constructors are expected to be used for valid linker table entries.
+ * Valid uses of weak entries other than the beginning and is currently
+ * untested but should in theory work.
+ */
+
+/**
+ * LINKTABLE - Declares a data linker table entry
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Declares a data linker table entry. These are read-write.
+ */
+#define LINKTABLE(name, level) \
+ __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_DATA, \
+ name, level))))
+
+/**
+ * LINKTABLE_TEXT - Declares a linker table entry for execution
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Declares a linker table to be used for execution.
+ */
+#define LINKTABLE_TEXT(name, level) \
+ const __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_TEXT, \
+ name, level))))
+
+/**
+ * LINKTABLE_RO - Declares a read-only linker table entry.
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Declares a linker table which only requires read-only access. Contrary
+ * to LINKTABLE_RO_WEAK() which uses SECTION_RODATA this helper uses the
+ * section SECTION_TBL_RO here due to possible toolchains bug on some
+ * architectures, for instance the c6x architicture stuffs non-weak data
+ * into different sections other than the one intended.
+ */
+#define LINKTABLE_RO(name, level) \
+ const __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_TBL_RO, \
+ name, level))))
+
+/**
+ * LINKTABLE_INIT - Declares a linker table entry to be used on init.
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Declares a linker table entry for execution use during init.
+ */
+#define LINKTABLE_INIT(name, level) \
+ const __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ __aligned__(LINUX_SECTION_ALIGN_FUNC), \
+ section(SECTION_TBL(SECTION_INIT, \
+ name, level))))
+
+/**
+ * LINKTABLE_INIT_DATA - Declares a linker table entry to be used on init data.
+ *
+ * @name: linker table name
+ * @level: order level
+ *
+ * Declares a linker table entry for data during init.
+ */
+#define LINKTABLE_INIT_DATA(name, level) \
+ __typeof__(VMLINUX_SYMBOL(name)[0]) \
+ __attribute__((used, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(SECTION_INIT_DATA, \
+ name, level))))
+
+/**
+ * DOC: Declaring Linker tables
+ *
+ * Declarers are used to help code access the linker tables. Typically
+ * header files for subsystems would declare the linker tables to enable
+ * easy access to add new entries, and to iterate over the list of table.
+ * There are only two declarers needed given that the section association
+ * is done by the definition of the linker table using ``DEFINE_LINKTABLE*()``
+ * helpers.
+ */
+
+
+/**
+ * DECLARE_LINKTABLE - Declares a data linker table entry
+ *
+ * @type: data type
+ * @name: table name
+ *
+ * Declares a data linker table entry.
+ */
+#define DECLARE_LINKTABLE(type, name) \
+ DECLARE_LINUX_SECTION(type, name)
+
+/**
+ * DECLARE_LINKTABLE_RO - Declares a read-only linker table entry
+ *
+ * @type: data type
+ * @name: table name
+ *
+ * Declares a read-only linker table entry.
+ */
+#define DECLARE_LINKTABLE_RO(type, name) \
+ DECLARE_LINUX_SECTION_RO(type, name)
+
+/**
+ * DOC: Defining Linker tables
+ *
+ * Linker tables are defined in the code that takes ownership over
+ * the linker table. This is typically done in the same code that is in
+ * charge of iterating over the linker table as well.
+ */
+
+/**
+ * DEFINE_LINKTABLE - Defines a linker table for data
+ *
+ * @type: data type
+ * @name: table name
+ *
+ * Defines a linker table which used for data.
+ */
+#define DEFINE_LINKTABLE(type, name) \
+ DECLARE_LINKTABLE(type, name); \
+ LINKTABLE_WEAK(name,) VMLINUX_SYMBOL(name)[0] = {}; \
+ LINKTABLE(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {}
+
+/**
+ * DEFINE_LINKTABLE_TEXT - Declares linker table entry for exectuion
+ *
+ * @type: data type
+ * @name: table name
+ *
+ * Declares a linker table entry for execution.
+ */
+#define DEFINE_LINKTABLE_TEXT(type, name) \
+ DECLARE_LINKTABLE_RO(type, name); \
+ LINKTABLE_TEXT_WEAK(name,) VMLINUX_SYMBOL(name)[0] = {}; \
+ LINKTABLE_TEXT(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {}
+
+/**
+ * DEFINE_LINKTABLE_RO - Defines a read-only linker table
+ *
+ * @type: data type
+ * @name: table name
+ *
+ * Defines a linker table which we know only requires read-only access.
+ */
+#define DEFINE_LINKTABLE_RO(type, name) \
+ DECLARE_LINKTABLE_RO(type, name); \
+ LINKTABLE_RO_WEAK(name,) VMLINUX_SYMBOL(name)[0] = {}; \
+ LINKTABLE_RO(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {}
+
+/**
+ * DEFINE_LINKTABLE_INIT - Defines an init time linker table for execution
+ *
+ * @type: data type
+ * @name: table name
+ *
+ * Defines a linker table. If you are adding a new type you should
+ * enable ``CONFIG_DEBUG_SECTION_MISMATCH`` and ensure routines that make
+ * use of the linker tables get a respective __ref tag.
+ */
+#define DEFINE_LINKTABLE_INIT(type, name) \
+ DECLARE_LINKTABLE(type, name); \
+ LINKTABLE_INIT_WEAK(name,) VMLINUX_SYMBOL(name)[0] = {}; \
+ LINKTABLE_INIT(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {}
+
+/**
+ * DEFINE_LINKTABLE_INIT_DATA - Defines an init time linker table for data
+ *
+ * @type: data type
+ * @name: table name
+ *
+ * Defines a linker table for init data. If you are adding a new type you
+ * should enable ``CONFIG_DEBUG_SECTION_MISMATCH`` and ensure routines that
+ * make use of the linker tables get a respective __ref tag.
+ */
+#define DEFINE_LINKTABLE_INIT_DATA(type, name) \
+ DECLARE_LINKTABLE(type, name); \
+ LINKTABLE_INIT_DATA_WEAK(name,) VMLINUX_SYMBOL(name)[0] = {}; \
+ LINKTABLE_INIT_DATA(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {}
+
+/**
+ * DOC: Iterating over Linker tables
+ *
+ * To make use of the linker tables you want to be able to iterate over
+ * them. This section documents the different iterators available.
+ */
+
+/**
+ * LINKTABLE_FOR_EACH - iterate through all entries within a linker table
+ *
+ * @pointer: entry pointer
+ * @tbl: linker table
+ *
+ * Example usage::
+ *
+ * struct frobnicator *frob;
+ *
+ * LINKTABLE_FOR_EACH(frob, frobnicator_fns) {
+ * ...
+ * }
+ */
+
+#define LINKTABLE_FOR_EACH(pointer, tbl) \
+ for (pointer = LINUX_SECTION_START(tbl); \
+ pointer < LINUX_SECTION_END(tbl); \
+ pointer++)
+
+/**
+ * LINKTABLE_RUN_ALL - iterate and run through all entries on a linker table
+ *
+ * @tbl: linker table
+ * @func: structure name for the function name we want to call.
+ * @args...: arguments to pass to func
+ *
+ * Example usage::
+ *
+ * LINKTABLE_RUN_ALL(frobnicator_fns, some_run,);
+ */
+#define LINKTABLE_RUN_ALL(tbl, func, args...) \
+do { \
+ size_t i; \
+ for (i = 0; i < LINUX_SECTION_SIZE(tbl); i++) \
+ (VMLINUX_SYMBOL(tbl)[i]).func (args); \
+} while (0)
+
+/**
+ * LINKTABLE_RUN_ERR - run each linker table entry func and return error if any
+ *
+ * @tbl: linker table
+ * @func: structure name for the function name we want to call.
+ * @args...: arguments to pass to func
+ *
+ * Example usage::
+ *
+ * unsigned int err = LINKTABLE_RUN_ERR(frobnicator_fns, some_run,);
+ */
+#define LINKTABLE_RUN_ERR(tbl, func, args...) \
+({ \
+ size_t i; \
+ int err = 0; \
+ for (i = 0; !err && i < LINUX_SECTION_SIZE(tbl); i++) \
+ err = (VMLINUX_SYMBOL(tbl)[i]).func (args); \
+ err; \
+})
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _LINUX_LINKER_TABLES_H */
new file mode 100644
@@ -0,0 +1,2 @@
+arch/x86/kernel/vmlinux.lds
+demo
new file mode 100644
@@ -0,0 +1,184 @@
+include ../scripts/Makefile.include
+
+all:
+
+include ../scripts/utilities.mak
+
+MAKEFLAGS += --no-print-directory
+
+unexport LC_ALL
+LC_COLLATE=C
+LC_NUMERIC=C
+export LC_COLLATE LC_NUMERIC
+
+ifeq ($(srctree),)
+ srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
+endif
+
+ifneq ($(objtree),)
+#$(info Determined 'objtree' to be $(objtree))
+endif
+
+ifneq ($(OUTPUT),)
+#$(info Determined 'OUTPUT' to be $(OUTPUT))
+# Adding $(OUTPUT) as a directory to look for source files,
+# because use generated output files as sources dependency
+# for flex/bison parsers.
+VPATH += $(OUTPUT)
+export VPATH
+endif
+
+export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK
+include $(srctree)/tools/build/Makefile.include
+
+ifeq ($(V),1)
+ Q=
+ NQ=@true
+else
+ Q=@
+ NQ=@echo
+endif
+
+MAKEFLAGS += -r
+
+define allow-override
+ $(if $(or $(findstring environment,$(origin $(1))),\
+ $(findstring command line,$(origin $(1)))),,\
+ $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR and LD, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,LD,$(CROSS_COMPILE)ld)
+
+LD += $(EXTRA_LDFLAGS)
+
+include $(srctree)/tools/scripts/Makefile.arch
+
+# Refer to README to learn how to support your architecture
+SUPPORTED_ARCHS = x86
+
+ifeq ($(filter $(ARCH),$(SUPPORTED_ARCHS)),)
+$(error Unsupported arch: $(ARCH))
+endif
+
+CFLAGS += -O2 -g
+CFLAGS += -std=gnu99 -Wall -Werror
+CFLAGS += -lpthread
+CFLAGS += -DCONFIG_KPROBES
+
+# We confine the includes used below to those we know are safe
+# for this type of hack.
+CFLAGS += -D__KERNEL__
+
+# CFLAGS += -DCONFIG_HAVE_ARCH_PS_CONST
+INCLUDES = \
+ -I include/ \
+ -I arch/$(ARCH)/include/ \
+ -I ../include/ \
+ -I ../arch/$(ARCH)/include/ \
+ -I ../arch/$(ARCH)/include/generated/
+
+CFLAGS += $(INCLUDES)
+CFLAGS +=-Wl,-Tarch/$(ARCH)/kernel/vmlinux.lds
+
+HEADERS = \
+ ../../include/asm-generic/section-core.h \
+ ../../include/asm-generic/ranges.h \
+ ../../include/asm-generic/tables.h \
+ ../../include/linux/sections.h \
+ ../../include/linux/ranges.h \
+ ../../include/linux/tables.h
+
+__check_headers: $(HEADERS)
+ @$(foreach h, $(HEADERS), \
+ (test -f $(h) && ( \
+ (diff -B $(subst ../,../,$(h)) $(h) >/dev/null) \
+ || echo "Warning: $(subst ../../,tools/,$(h)) differs from kernel" >&2 ) || true);)
+
+$(OUTPUT)arch/$(ARCH)/kernel/vmlinux.lds: arch/$(ARCH)/kernel/vmlinux.lds.S
+ $(NQ) ' LD ' $@
+ $(Q)$(CC) $(CFLAGS) $(INCLUDES) -E -P \
+ -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
+
+# Note, we use obj-y as a convenience factor, the cmd build
+# stuff doesn't allow this magic, it resolves our depds but
+# we still need to provide a series of targets for our objects.
+# We stick to the convenient shorthand we're used to in the
+# kernel. The final object resolution build stuff is handled
+# by tool_target_obj and its caller below. This also enables
+# OUTPUT=foo-path support so you can build externally.
+obj-y += \
+ arch/$(ARCH)/kernel/head64.o \
+ arch/$(ARCH)/mm/init.o \
+ kernel/locking/mutex.o \
+ kernel/locking/spinlock.o \
+ kernel/workqueue.o \
+ kernel/main.o \
+ pci.o \
+ lib/string.o \
+ pci-quirks.o \
+ drivers/acme.o \
+ drivers/synth/main.o \
+ drivers/synth/common.o \
+ drivers/synth/or.s \
+ main.o
+
+ifeq ($(ARCH),x86)
+obj-y += \
+ arch/$(ARCH)/kernel/alternative.o \
+ arch/$(ARCH)/kernel/init.o \
+ arch/$(ARCH)/kernel/kprobes.o \
+ arch/$(ARCH)/kernel/kasan.o \
+ arch/$(ARCH)/kernel/beta.o \
+ arch/$(ARCH)/kernel/alpha.o \
+ arch/$(ARCH)/xen/init.o \
+ drivers/xen-driver.o
+endif
+
+obj-y-out = $(patsubst %,$(OUTPUT)%,$(obj-y))
+
+__build-dir = $(subst $(OUTPUT),,$(dir $1))
+build-dir = $(if $(__build-dir),$(__build-dir),.)
+
+build := -f $(srctree)/tools/build/Makefile.build dir=$(build-dir)
+
+define tool_target_obj
+$(1): $(subst .s,.S,$(subst .o,.c,$(patsubst $(OUTPUT)%,%,$(1))))
+ $(Q)$(MAKE) $(build) obj=$(1)
+endef
+
+$(foreach tool_obj, $(obj-y-out), \
+ $(eval $(call tool_target_obj, $(tool_obj))))
+
+$(OUTPUT)demo: $(obj-y-out)
+ $(NQ) ' CC ' $@
+ $(Q)$(CC) $(obj-y-out) -o $@ $(CPPFLAGS) $(CFLAGS)
+
+CHECK_HEADERS := __check_headers
+PHONY += $(CHECK_HEADERS)
+
+CMD_TARGETS = $(OUTPUT)arch/$(ARCH)/kernel/vmlinux.lds $(OUTPUT)demo
+TARGETS = $(CMD_TARGETS)
+
+all: $(CHECK_HEADERS) all_cmd
+
+all_cmd: $(CMD_TARGETS)
+
+ifeq ($(OUTPUT),)
+clean_dir = ./
+else
+clean_dir = $(OUTPUT)
+endif
+
+clean::
+ $(NQ) ' CLEAN deps'
+ $(Q)find $(clean_dir) -name \*.o \
+ -o -name \*.s \
+ -o -name \*.o.d \
+ -o -name \*.o.cmd | xargs rm -f
+ $(NQ) ' CLEAN targets'
+ $(Q)$(foreach f, $(CMD_TARGETS), rm -f $(f);)
new file mode 100644
@@ -0,0 +1,114 @@
+Linux linker table userspace sandbox
+====================================
+
+This is a userspace sandbox to allow easy experimentation and
+test extensions with linker tables. It tries to mimic the Linux
+kernel development flow as much as possible, it however relies
+on and uses libc and is nothing but a simple stupid userspace
+application demo.
+
+You can use the sandbox to modify the kernel's linker table
+solution or add use it in creative ways without having to run
+qemu with a real kernel or user mode linux. You can simply try
+to extend this sandbox as you would for a regular userspace
+application.
+
+History
+=======
+
+This was hacked on first in an external repository, that tree has
+the full set of history of how this work came about. Refer to that
+tree for more details if you are interested in the logic used for
+a lot of decisions made for linker tables:
+
+https://git.kernel.org/cgit/linux/kernel/git/mcgrof/linker-tables.git/
+
+This tree is discontinued now in favor of an upstream solution which
+is kept in sync with the kernel.
+
+Compile
+=======
+
+Run:
+ make
+
+Clean:
+ make clean
+
+If you need to get object files outside of the source tree:
+
+ make OUTPUT=/tmp/path/
+ make OUTPUT=/tmp/path/ clean
+
+Supported architectures
+=======================
+
+x86_64
+
+Currently only x86_64 is supported for the demo. It should be
+relatively easy to add more. To add a new architecture you need
+a toolchain available with libc. You then need to generate a
+respective base template custom linker script for userspace
+as is provided on x86 in arch/x86/kernel/vmlinux.lds.S.
+
+A respective architecture tools/arch/$(ARCH)/include/* file for
+each section-core.h, ranges.h, tables.h will need to be provided
+as well. If your architecture's file is generated copy the generated
+file over.
+
+x86 Simulated boots
+===================
+
+This programs simulates boot on both bare metal and with the
+Xen PV entry on x86.
+
+Emulate bare metal boot:
+
+./demo
+
+Emulate Xen boot (x86):
+
+./demo -x
+
+Testing new features
+====================
+
+A copy of each kernel header file is maintained in tools/include/,
+as well as a respective generated asm file for each sandbox supported
+architecture. This sandbox has a built in checker for when these files
+get out of sync.
+
+If testing new extensions on the files:
+
+ o section-core
+ o ranges.h
+ o tables.h
+
+You'll want to copy them into tools as well. If you are working on
+using these files you can work within the current directory's namespace,
+including its own set of header files, so tools/linker-tables/include/ and
+each respective tools/linker-tables/arch/$(ARCH)/include/asm/.
+
+Features evaluation
+===================
+
+This lists features currently being evaluated in the sandbox, not yet
+present upstream. These make use of the existing set of header files
+without modification.
+
+ o Demo use of initialization on for x86, refer to arch/x86/kernel/init.c
+
+ o Demo use of porting the kernel's init call levels to linker tables, refer
+ to the init_calls linker table use on kernel/main.c
+
+ o Demo use of an asm-generic architecture init family, which could potentially
+ be used to help share initialization sequences on simple architectures.
+ Refer to include/asm-generic/arch_init_fn.h
+
+ o Building synthetic routines with the option to provide enhancements
+ per architecture in asm, refer to drivers/synth/or.S and its use on
+ synth_init_or().
+
+ o User of linker tables for alternatives with consts - refer to
+ use of the ps_set_const_table linker table and its use in
+ arch/x86/kernel/alternative.c
new file mode 100644
@@ -0,0 +1,17 @@
+#ifndef _ASM_X86_ASM_H
+
+#ifdef __ASSEMBLY__
+# define __ASM_FORM(x) x
+# define __ASM_FORM_RAW(x) x
+# define __ASM_FORM_COMMA(x) x,
+#else
+# define __ASM_FORM(x) " " #x " "
+# define __ASM_FORM_RAW(x) #x
+# define __ASM_FORM_COMMA(x) " " #x ","
+#endif
+
+# define __ASM_SEL(a,b) __ASM_FORM(b)
+# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
+#define _ASM_PTR __ASM_SEL(.long, .quad)
+
+#endif /* _ASM_X86_ASM_H */
new file mode 100644
@@ -0,0 +1 @@
+extern struct boot_params boot_params;
new file mode 100644
@@ -0,0 +1,32 @@
+#ifndef __BOOTPARAM_H
+#define __BOOTPARAM_H
+
+#include <linux/types.h>
+
+struct setup_header {
+ __u32 hardware_subarch;
+} __attribute__((packed));
+
+struct boot_params {
+ struct setup_header hdr;
+} __attribute__((packed));
+
+enum {
+ X86_SUBARCH_PC = 0,
+ X86_SUBARCH_LGUEST,
+ X86_SUBARCH_XEN,
+ X86_SUBARCH_INTEL_MID,
+ X86_SUBARCH_CE4100,
+ X86_NR_SUBARCHS,
+};
+
+#define X86_SUBARCH_ALL_SUBARCHS \
+ ( \
+ BIT(X86_SUBARCH_PC) | \
+ BIT(X86_SUBARCH_LGUEST) | \
+ BIT(X86_SUBARCH_XEN) | \
+ BIT(X86_SUBARCH_INTEL_MID) | \
+ BIT(X86_SUBARCH_CE4100) \
+ )
+
+#endif /* __BOOTPARAM_H */
new file mode 100644
@@ -0,0 +1,7 @@
+#ifndef _SANDBOX_ASM_X86_KPROBES_H
+#define _SANDBOX_ASM_X86_KPROBES_H
+
+/* This is all we need for the demo */
+#include <asm-generic/kprobes.h>
+
+#endif /* _SANDBOX_ASM_X86_KPROBES_H */
new file mode 100644
@@ -0,0 +1,21 @@
+#ifndef __X86_PS_CONST
+#define __X86_PS_CONST
+
+#include <linux/tables.h>
+#include <asm/asm.h>
+
+#define ps_shr(_in, _func) \
+({ \
+ __typeof__(_in) _out; \
+ asm volatile( \
+ "shr $0,%0\n" \
+ "1:\n" \
+ SECTION_TBL_STR(SECTION_INIT_DATA, ps_set_const_table, 01)\
+ _ASM_PTR "1b-1, %P2, %P3\n" \
+ ".popsection\n" \
+ : "=rm" (_out) \
+ : "0" (_in), "i" (SET_CONST_U8), "i" (_func)); \
+ (_out); \
+})
+
+#endif /* __X86_PS_CONST */
new file mode 100644
@@ -0,0 +1,6 @@
+#ifndef _ASM_X86_RANGES_H
+#define _ASM_X86_RANGES_H
+
+#include <asm-generic/ranges.h>
+
+#endif /* _ASM_X86_RANGES_H */
new file mode 100644
@@ -0,0 +1 @@
+#include <asm-generic/section-core.h>
new file mode 100644
@@ -0,0 +1,6 @@
+#ifndef __LINUX_X86_USER_SETUP_H
+#define __LINUX_X86_USER_SETUP_H
+
+/* I'm lazy */
+
+#endif /* __LINUX_X86_USER_SETUP_H */
new file mode 100644
@@ -0,0 +1,6 @@
+#ifndef _ASM_X86_TABLES_H
+#define _ASM_X86_TABLES_H
+
+#include <asm-generic/tables.h>
+
+#endif /* _ASM_X86_RANGES_H */
new file mode 100644
@@ -0,0 +1,4 @@
+int startup_64(void);
+int x86_64_start_reservations(void);
+void setup_arch(void);
+void late_init(void);
new file mode 100644
@@ -0,0 +1,169 @@
+#ifndef __X86_INIT_TABLES_H
+#define __X86_INIT_TABLES_H
+
+#include <linux/types.h>
+#include <linux/tables.h>
+
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/bootparam.h>
+
+/**
+ * struct x86_init_fn - x86 generic kernel init call
+ *
+ * Linux x86 features vary in complexity, features may require work done at
+ * different levels of the full x86 init sequence. Today there are also two
+ * different possible entry points for Linux on x86, one for bare metal, KVM
+ * and Xen HVM, and another for Xen PV guests / dom0. Assuming a bootloader
+ * has set up 64-bit mode, roughly the x86 init sequence follows this path:
+ *
+ * Bare metal, KVM, Xen HVM Xen PV / dom0
+ * startup_64() startup_xen()
+ * \ /
+ * x86_64_start_kernel() xen_start_kernel()
+ * \ /
+ * x86_64_start_reservations()
+ * |
+ * start_kernel()
+ * [ ... ]
+ * [ setup_arch() ]
+ * [ ... ]
+ * init
+ *
+ * x86_64_start_kernel() and xen_start_kernel() are the respective first C code
+ * entry starting points. The different entry points exist to enable Xen to
+ * skip a lot of hardware setup already done and managed on behalf of the
+ * hypervisor, we refer to this as "paravirtualization yielding". The different
+ * levels of init calls on the x86 init sequence exist to account for these
+ * slight differences and requirements. These different entry points also share
+ * a common entry x86 specific path, x86_64_start_reservations().
+ *
+ * A generic x86 feature can have different initialization calls, one on each
+ * of the different main x86 init sequences, but must also address both entry
+ * points in order to work properly across the board on all supported x86
+ * subarchitectures. Since x86 features can also have dependencies on other
+ * setup code or features, x86 features can at times be subordinate to other
+ * x86 features, or conditions. struct x86_init_fn enables feature developers
+ * to annotate dependency relationships to ensure subsequent init calls only
+ * run once a subordinate's dependencies have run. When needed custom
+ * dependency requirements can also be spelled out through a custom dependency
+ * checker. In order to account for the dual entry point nature of x86-64 Linux
+ * for "paravirtualization yielding" and to make annotations for support for
+ * these explicit each struct x86_init_fn must specify supported
+ * subarchitectures. The earliest x86-64 code can read the subarchitecture
+ * though is after load_idt(), as such the earliest we can currently rely on
+ * subarchitecture for semantics and a common init sequences is on the shared
+ * common x86_64_start_reservations(). Each struct x86_init_fn is associated
+ * with a specific special link order number which has been careflly thought
+ * out by x86 maintainers. You should pick a link order level associated with
+ * the specific directory your code lies in, a respective macro is used to
+ * build association to a link oder with a routine, you should use one of the
+ * provided x86_init_*() macros. You should not use __x86_init() directly.
+ *
+ * x86_init_fn enables strong semantics and dependencies to be defined and
+ * implemented on the full x86 initialization sequence.
+ *
+ * @supp_hardware_subarch: must be set, it represents the bitmask of supported
+ * subarchitectures. We require each struct x86_init_fn to have this set
+ * to require developer considerations for each supported x86
+ * subarchitecture and to build strong annotations of different possible
+ * run time states particularly in consideration for the two main
+ * different entry points for x86 Linux, to account for paravirtualization
+ * yielding.
+ *
+ * The subarchitecture is read by the kernel at early boot from the
+ * struct boot_params hardware_subarch. Support for the subarchitecture
+ * exists as of x86 boot protocol 2.07. The bootloader would have set up
+ * the respective hardware_subarch on the boot sector as per
+ * Documentation/x86/boot.txt.
+ *
+ * What x86 entry point is used is determined at run time by the
+ * bootloader. Linux pv_ops was designed to help enable to build one Linux
+ * binary to support bare metal and different hypervisors. pv_ops setup
+ * code however is limited in that all pv_ops setup code is run late in
+ * the x86 init sequence, during setup_arch(). In fact cpu_has_hypervisor
+ * only works after early_cpu_init() during setup_arch(). If an x86
+ * feature requires an earlier determination of what hypervisor was used,
+ * or if it needs to annotate only support for certain hypervisors, the
+ * x86 hardware_subarch should be set by the bootloader and
+ * @supp_hardware_subarch set by the x86 feature. Using hardware_subarch
+ * enables x86 features to fill the semantic gap between the Linux x86
+ * entry point used and what pv_ops has to offer through a hypervisor
+ * agnostic mechanism.
+ *
+ * Each supported subarchitecture is set using the respective
+ * X86_SUBARCH_* as a bit in the bitmask. For instance if a feature
+ * is supported on PC and Xen subarchitectures only you would set this
+ * bitmask to:
+ *
+ * BIT(X86_SUBARCH_PC) |
+ * BIT(X86_SUBARCH_XEN);
+ *
+ * @early_init: required, routine which will run in x86_64_start_reservations()
+ * after we ensure boot_params.hdr.hardware_subarch is accessible and
+ * properly set. Memory is not yet available. This the earliest we can
+ * currently define a common shared callback since all callbacks need to
+ * check for boot_params.hdr.hardware_subarch and this becomes accessible
+ * on x86-64 until after load_idt().
+ */
+struct x86_init_fn {
+ __u32 supp_hardware_subarch;
+ void (*early_init)(void);
+};
+
+DECLARE_LINKTABLE(struct x86_init_fn, x86_init_fns);
+
+/* Init order levels, we can start at 0000 but reserve 0000-0999 for now */
+
+/*
+ * X86_INIT_ORDER_EARLY - early kernel init code
+ *
+ * This consists of the first parts of the Linux kernel executed.
+ */
+#define X86_INIT_ORDER_EARLY 1000
+
+/* X86_INIT_ORDER_PLATFORM - platform kernel code
+ *
+ * Code the kernel needs to initialize under arch/x86/platform/
+ * early in boot.
+ */
+#define X86_INIT_ORDER_PLATFORM 3000
+
+#define __x86_init(__level, \
+ __supp_hardware_subarch, \
+ __early_init) \
+ static LINKTABLE_INIT_DATA(x86_init_fns, __level) \
+ __x86_init_fn_##__early_init = { \
+ .supp_hardware_subarch = __supp_hardware_subarch, \
+ .early_init = __early_init, \
+ };
+
+#define x86_init_early(__supp_hardware_subarch, \
+ __early_init) \
+ __x86_init(X86_INIT_ORDER_EARLY, __supp_hardware_subarch, \
+ __early_init);
+
+#define x86_init_platform(__supp_hardware_subarch, \
+ __early_init) \
+ __x86_init(__name, X86_INIT_ORDER_PLATFORM, __supp_hardware_subarch,\
+ __early_init);
+
+#define x86_init_early_all(__early_init) \
+ x86_init_early(X86_SUBARCH_ALL_SUBARCHS, \
+ __early_init);
+
+#define x86_init_early_pc(__early_init) \
+ x86_init_early(BIT(X86_SUBARCH_PC), \
+ __early_init);
+
+#define x86_init_early_xen(__early_init) \
+ x86_init_early(BIT(X86_SUBARCH_XEN), \
+ __early_init);
+/**
+ * x86_init_fn_early_init: call all early_init() callbacks
+ *
+ * This calls all early_init() callbacks on the x86_init_fns linker table.
+ */
+void x86_init_fn_early_init(void);
+
+#endif /* __X86_INIT_TABLES_H */
new file mode 100644
@@ -0,0 +1,9 @@
+#include <linux/kernel.h>
+#include <asm/x86_init_fn.h>
+
+static void early_init_alpha(void) {
+ pr_info("Initializing alpha ...\n");
+ pr_info("Completed initializing alpha !\n");
+}
+
+x86_init_early_pc(early_init_alpha);
new file mode 100644
@@ -0,0 +1,31 @@
+#include <asm/x86_init_fn.h>
+
+#include <linux/kernel.h>
+#include <linux/ps_const.h>
+
+void apply_alternatives_linker_tables(void)
+{
+ unsigned int num_consts = LINUX_SECTION_SIZE(ps_set_const_table);
+ struct ps_set_const *ps_const;
+
+ if (!num_consts)
+ return;
+
+ pr_debug("Number of init entries: %d\n", num_consts);
+
+ LINKTABLE_FOR_EACH(ps_const, ps_set_const_table) {
+ switch(ps_const->type) {
+ case SET_CONST_U8:
+ *ps_const->count = (__u8) ps_const->func();
+ break;
+ case SET_CONST_U16:
+ *ps_const->count = (__u16) ps_const->func();
+ break;
+ case SET_CONST_U32:
+ *ps_const->count = (__u16) ps_const->func();
+ break;
+ }
+ }
+}
+
+x86_init_early_pc(apply_alternatives_linker_tables);
new file mode 100644
@@ -0,0 +1,9 @@
+#include <linux/kernel.h>
+#include <asm/x86_init_fn.h>
+
+static void early_init_beta(void) {
+ pr_info("Initializing beta ...\n");
+ pr_info("Completed initializing beta !\n");
+}
+
+x86_init_early_pc(early_init_beta);
new file mode 100644
@@ -0,0 +1,58 @@
+#include <linux/kernel.h>
+#include <linux/tables.h>
+
+#include <asm/x86_init_fn.h>
+#include <asm/boot.h>
+#include <asm/bootparam.h>
+
+#include <linux/start_kernel.h>
+#include <linux/kasan.h>
+
+void x86_64_start_reservations(void)
+{
+ switch (boot_params.hdr.hardware_subarch) {
+ case X86_SUBARCH_PC:
+ pr_info("Booting bare metal\n");
+ break;
+ case X86_SUBARCH_LGUEST:
+ pr_info("Booting lguest not supported\n");
+ BUG();
+ case X86_SUBARCH_XEN:
+ pr_info("Booting a Xen guest\n");
+ break;
+ case X86_SUBARCH_INTEL_MID:
+ pr_info("Booting Intel MID not supported\n");
+ BUG();
+ case X86_SUBARCH_CE4100:
+ pr_info("Booting Intel CE4100 not supported\n");
+ BUG();
+ default:
+ pr_info("Booting sunsupported x86 hardware subarch\n");
+ BUG();
+ }
+
+ start_kernel();
+}
+
+static void x86_64_start_kernel(void)
+{
+ x86_init_fn_early_init();
+
+ x86_64_start_reservations();
+}
+
+void startup_64(void)
+{
+ pr_info("Initializing x86 bare metal world\n");
+ x86_64_start_kernel();
+}
+
+void setup_arch(void)
+{
+ /* TODO: x86_init_fn_setup_arch(); */
+}
+
+void late_init(void)
+{
+ /* TODO: x86_init_fn_late_init(); */
+}
new file mode 100644
@@ -0,0 +1,42 @@
+#define pr_fmt(fmt) "x86-init: " fmt
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+#include <asm/x86_init_fn.h>
+#include <asm/bootparam.h>
+#include <asm/boot.h>
+#include <asm/setup.h>
+
+DEFINE_LINKTABLE_INIT_DATA(struct x86_init_fn, x86_init_fns);
+
+static bool x86_init_fn_supports_subarch(struct x86_init_fn *fn)
+{
+ if (!fn->supp_hardware_subarch) {
+ //pr_err("Init sequence fails to declares any supported subarchs: %pF\n", fn->early_init);
+ WARN_ON(1);
+ }
+ if (BIT(boot_params.hdr.hardware_subarch) & fn->supp_hardware_subarch)
+ return true;
+ return false;
+}
+
+void __ref x86_init_fn_early_init(void)
+{
+ struct x86_init_fn *init_fn;
+ unsigned int num_inits = LINUX_SECTION_SIZE(x86_init_fns);
+
+ if (!num_inits)
+ return;
+
+ pr_debug("Number of init entries: %d\n", num_inits);
+
+ LINKTABLE_FOR_EACH(init_fn, x86_init_fns) {
+ if (!x86_init_fn_supports_subarch(init_fn))
+ continue;
+
+ //pr_debug("Running early init %pF ...\n", init_fn->early_init);
+ init_fn->early_init();
+ //pr_debug("Completed early init %pF\n", init_fn->early_init);
+ }
+}
new file mode 100644
@@ -0,0 +1,10 @@
+#include <linux/kernel.h>
+#include <asm/x86_init_fn.h>
+
+void kasan_early_init(void) {
+ pr_info("Initializing kasan ...\n");
+ pr_info("Early init for Kasan...\n");
+ pr_info("Completed initializing kasan !\n");
+}
+
+x86_init_early_pc(kasan_early_init);
new file mode 100644
@@ -0,0 +1,51 @@
+#include <linux/kernel.h>
+#include <linux/tables.h>
+#include <asm/x86_init_fn.h>
+#include <linux/ranges.h>
+#include <linux/kprobes.h>
+
+DEFINE_SECTION_RANGE(kprobes, SECTION_TEXT);
+
+void __kprobes test_kprobe_0001(void)
+{
+ pr_info("test_kprobe\n");
+}
+
+void test_kprobe_0002(void)
+{
+ pr_info("test_kprobe\n");
+}
+
+void test_kprobe_addr(const char *test, unsigned long addr, bool should_match)
+{
+ if (SECTION_ADDR_IN_RANGE(kprobes, addr))
+ if (should_match)
+ pr_info("== OK: %s within range!\n", test);
+ else
+ pr_info("== FAIL: %s should not be in range...\n",
+ test);
+ else
+ if (should_match)
+ pr_info("== FAIL: %s should be in range...\n", test);
+ else
+ pr_info("== OK: %s not in range as expected!\n", test);
+}
+
+void early_init_kprobes(void)
+{
+ unsigned long addr;
+
+ pr_info("Initializing kprobes ...\n");
+
+ addr = (unsigned long) &test_kprobe_0001;
+
+ test_kprobe_addr("test_kprobe_0001", addr, true);
+
+ addr = (unsigned long) &test_kprobe_0002;
+
+ test_kprobe_addr("test_kprobe_0002", addr, false);
+
+ pr_info("Completed initializing kprobes !\n");
+}
+
+x86_init_early_all(early_init_kprobes);
new file mode 100644
@@ -0,0 +1,273 @@
+/* Script for -z combreloc: combine and sort reloc sections */
+/* Copyright (C) 2014 Free Software Foundation, Inc.
+ Copying and distribution of this script, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. */
+
+#include <asm/section-core.h>
+#include <asm/ranges.h>
+#include <asm/tables.h>
+
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
+ "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
+ *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
+ *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
+ *(.rela.ifunc)
+ }
+ .rela.plt :
+ {
+ *(.rela.plt)
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .init :
+ {
+ KEEP (*(SORT_NONE(.init)))
+ }
+ .plt : { *(.plt) *(.iplt) }
+ .plt.bnd : { *(.plt.bnd) }
+ SECTION_TEXT :
+ {
+ *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+ *(.text.exit .text.exit.*)
+ *(.text.startup .text.startup.*)
+ *(.text.hot .text.hot.*)
+ *(SORT(SECTION_RNG_ALL(SECTION_TEXT)))
+ *(SORT(SECTION_TBL_ALL(SECTION_TEXT)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_INIT)))
+ *(SORT(SECTION_TBL_ALL(SECTION_INIT)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_INIT_CALL)))
+ *(SORT(SECTION_TBL_ALL(SECTION_INIT_CALL)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_EXIT)))
+ *(SORT(SECTION_TBL_ALL(SECTION_EXIT)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_EXIT_CALL)))
+ *(SORT(SECTION_TBL_ALL(SECTION_EXIT_CALL)))
+ *(SECTION_TEXT .stub SECTION_ALL(SECTION_TEXT) .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ }
+ .fini :
+ {
+ KEEP (*(SORT_NONE(.fini)))
+ }
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(.rodata)
+ *(SORT(.rodata.*))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_RODATA)))
+ *(SORT(SECTION_TBL_ALL(SECTION_RODATA)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_INIT_RODATA)))
+ *(SORT(SECTION_TBL_ALL(SECTION_INIT_RODATA)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_REF_RODATA)))
+ *(SORT(SECTION_TBL_ALL(SECTION_REF_RODATA)))
+ *(.gnu.linkonce.r.*)
+ }
+ .rodata1 : { *(.rodata1) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
+ .gcc_except_table.*) }
+ /* These sections are generated by the Sun/Oracle C++ compiler. */
+ .exception_ranges : ONLY_IF_RO { *(.exception_ranges
+ .exception_ranges*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+ .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ }
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+ KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+ KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ /* We don't want to include the .ctor section from
+ the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got) *(.igot) }
+ . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
+ .got.plt : { *(.got.plt) *(.igot.plt) }
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+
+ *(SORT(SECTION_RNG_ALL(SECTION_DATA)))
+ *(SORT(SECTION_TBL_ALL(SECTION_DATA)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_INIT_DATA)))
+ *(SORT(SECTION_TBL_ALL(SECTION_INIT_DATA)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_REF_DATA)))
+ *(SORT(SECTION_TBL_ALL(SECTION_REF_DATA)))
+
+ *(SORT(SECTION_RNG_ALL(SECTION_EXIT_DATA)))
+ *(SORT(SECTION_TBL_ALL(SECTION_EXIT_DATA)))
+
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .; PROVIDE (edata = .);
+ . = .;
+
+ __bss_start = .;
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 64 / 8 : 1);
+ }
+ .lbss :
+ {
+ *(.dynlbss)
+ *(.lbss .lbss.* .gnu.linkonce.lb.*)
+ *(LARGE_COMMON)
+ }
+ . = ALIGN(64 / 8);
+ . = SEGMENT_START("ldata-segment", .);
+ .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+ {
+ *(.lrodata .lrodata.* .gnu.linkonce.lr.*)
+ }
+ .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+ {
+ *(.ldata .ldata.* .gnu.linkonce.l.*)
+ . = ALIGN(. != 0 ? 64 / 8 : 1);
+ }
+ . = ALIGN(64 / 8);
+ _end = .; PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ /* DWARF Extension. */
+ .debug_macro 0 : { *(.debug_macro) }
+ .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
new file mode 100644
@@ -0,0 +1,10 @@
+#include <linux/kernel.h>
+#include <asm/x86_init_fn.h>
+
+static void early_init_memory(void) {
+ pr_info("Initializing memory ...\n");
+ sleep(1);
+ pr_info("Completed initializing memory !\n");
+}
+
+x86_init_early_all(early_init_memory);
new file mode 100644
@@ -0,0 +1,13 @@
+#include <linux/kernel.h>
+#include <linux/tables.h>
+#include <asm/x86_init_fn.h>
+#include <asm/x86.h>
+
+void startup_xen(void)
+{
+ pr_info("Initializing Xen guest\n");
+
+ x86_init_fn_early_init();
+
+ x86_64_start_reservations();
+}
new file mode 100644
@@ -0,0 +1,32 @@
+#define pr_fmt(fmt) "ACME: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+
+void *acme_todo(void *arg);
+static DECLARE_WORK(acme_work, acme_todo);
+
+void *acme_todo(void *arg)
+{
+ pr_info("Running scheduled work\n");
+ pthread_exit(NULL);
+}
+
+static int acme_init_driver(void) {
+ pr_info("Initializing ...\n");
+ sleep(2);
+ pr_info("Finished init ... !\n");
+
+ init_work(&acme_work);
+ schedule_work(&acme_work);
+
+ return 0;
+}
+module_init(acme_init_driver);
+
+static void acme_exit(void)
+{
+ cancel_work_sync(&acme_work);
+};
+module_exit(acme_exit);
new file mode 100644
@@ -0,0 +1,16 @@
+int demo_or_1(int arg)
+{
+ switch (arg) {
+ case 1:
+ return 0xDEA00000;
+ case 2:
+ return 0X000D0000;
+ default:
+ return arg * 2;
+ }
+}
+
+int demo_or_2(void)
+{
+ return 0x0000BEEF;
+}
new file mode 100644
@@ -0,0 +1,2 @@
+int demo_or_1(int arg);
+int demo_or_2(void);
new file mode 100644
@@ -0,0 +1,35 @@
+#define pr_fmt(fmt) "Synthetics: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ps_const.h>
+
+#include "common.h"
+#include "synth.h"
+
+DEFINE_LINKTABLE_INIT_DATA(struct ps_set_const, ps_set_const_table);
+
+unsigned int get_demo_shr(void)
+{
+ return 16;
+}
+
+static int synth_init(void)
+{
+ int synth_or;
+ int val = 2;
+ const unsigned int reg = ps_shr(0xDEADBEEF, get_demo_shr);
+
+ synth_or = synth_init_or(val);
+ pr_info("synth_init_or(%d) returns: 0x%08X\n", val, synth_or);
+
+ pr_info("ps_shr(0x%08X, get_demo_shr) returns: 0x%08X\n", 0xDEADBEEF, reg);
+
+ return 0;
+}
+module_init(synth_init);
+
+static void synth_exit(void)
+{
+}
+module_exit(synth_exit);
new file mode 100644
@@ -0,0 +1,39 @@
+#include <asm/ranges.h>
+
+ DEFINE_SECTION_RANGE(SECTION_TEXT, synth_init_or)
+
+ push_section_rng_level(SECTION_TEXT, synth_init_or, "01", )
+ /* err = 0; */
+ pushq %rbp
+ movq %rsp,%rbp
+ pushq %rbx
+ xorq %rbx,%rbx
+ .popsection
+
+ push_section_rng_level(SECTION_TEXT, synth_init_or, "99", )
+ /* return err; */
+ movq %rbx,%rax
+ popq %rbx
+ popq %rbp
+ retq
+ .popsection
+
+ push_section_rng_level(SECTION_TEXT, synth_init_or, "50", )
+ /* err |= demo_or_1(1); */
+ movl $1,%edi
+ call demo_or_1
+ orq %rax,%rbx
+ .popsection
+
+ push_section_rng_level(SECTION_TEXT, synth_init_or, "50", )
+ /* err |= demo_or_1(2); */
+ movl $2,%edi
+ call demo_or_1
+ orq %rax,%rbx
+ .popsection
+
+ push_section_rng_level(SECTION_TEXT, synth_init_or, "50", )
+ /* err |= demo_or_2(); */
+ call demo_or_2
+ orq %rax,%rbx
+ .popsection
new file mode 100644
@@ -0,0 +1,2 @@
+/* Synthetic demos go here */
+int synth_init_or(int arg);
new file mode 100644
@@ -0,0 +1,11 @@
+#include <asm/x86_init_fn.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <xen/xen.h>
+
+static void early_xen_init_driver(void) {
+ pr_info("Initializing xen driver\n");
+ sleep(2);
+}
+
+x86_init_early_xen(early_xen_init_driver);
new file mode 100644
@@ -0,0 +1,50 @@
+#ifndef __ARCH_INIT_TABLES_H
+#define __ARCH_INIT_TABLES_H
+
+#include <linux/types.h>
+#include <linux/tables.h>
+#include <linux/init.h>
+
+/**
+ * struct arch_init_fn - architecture-generic kernel init call
+ *
+ * Architectures must initialize a series of things prior to handing off
+ * control to the kernel. This structure can be used if the architecture is
+ * simple and it just needs a basic set of calls on its way up.
+ *
+ * @early_init: required, routine which will run in startup_64(). Memory is
+ * not yet available.
+ */
+struct arch_init_fn {
+ void (*early_init)(void);
+};
+
+DECLARE_LINKTABLE(struct arch_init_fn, arch_init_fns);
+
+/* Init order levels, we can start at 0000 but reserve 0000-0999 for now */
+
+/*
+ * ARCH_INIT_ORDER_EARLY - early kernel init code
+ *
+ * This consists of the first parts of the Linux kernel executed.
+ */
+#define ARCH_INIT_ORDER_EARLY 1000
+
+#define __arch_init(__level, \
+ __early_init) \
+ static LINKTABLE_INIT_DATA(arch_init_fns, __level) \
+ __arch_init_fn_##__early_init = { \
+ .early_init = __early_init, \
+ }
+
+#define arch_init_early(__early_init) \
+ __arch_init(ARCH_INIT_ORDER_EARLY, __early_init)
+
+/**
+ * arch_init_fn_early_init: call all early_init() callbacks
+ *
+ * This calls all early_init() callbacks on the arch_init_fns linker table.
+ */
+void arch_init_fn_early_init(void);
+
+#endif /* __ARCH_INIT_TABLES_H */
new file mode 100644
@@ -0,0 +1,26 @@
+#ifndef _SANDBOX_ASM_GENERIC_KPROBES_H
+#define _SANDBOX_ASM_GENERIC_KPROBES_H
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+#ifdef CONFIG_KPROBES
+#include <linux/tables.h>
+#include <asm/ranges.h>
+/*
+ * Blacklist ganerating macro. Specify functions which is not probed
+ * by using this macro.
+ */
+# define __NOKPROBE_SYMBOL(fname) \
+static LINKTABLE_INIT_DATA(_kprobe_blacklist, all) \
+ _kbl_addr_##fname = (unsigned long)fname;
+# define NOKPROBE_SYMBOL(fname) __NOKPROBE_SYMBOL(fname)
+/* Use this to forbid a kprobes attach on very low level functions */
+# define __kprobes __LINUX_RANGE(SECTION_TEXT, kprobes)
+# define nokprobe_inline __always_inline
+#else
+# define NOKPROBE_SYMBOL(fname)
+# define __kprobes
+# define nokprobe_inline inline
+#endif
+#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
+
+#endif /* _SANDBOX_ASM_GENERIC_KPROBES_H */
new file mode 100644
@@ -0,0 +1,6 @@
+#ifndef _LINUX_BITOPS_H
+#define _LINUX_BITOPS_H
+
+#define BIT(nr) (1UL << (nr))
+
+#endif /* _LINUX_BITOPS_H */
new file mode 100644
@@ -0,0 +1,40 @@
+#ifndef _SANDBOX_LINUX_INIT_H
+#define _SANDBOX_LINUX_INIT_H
+
+#include_next <linux/init.h>
+#include <linux/types.h>
+#include <linux/sections.h>
+
+#define __init __section(SECTION_INIT)
+#define __exit __section(SECTION_EXIT)
+
+#ifndef __ASSEMBLY__
+#include <linux/tables.h>
+typedef int (*initcall_t)(void);
+typedef void (*exitcall_t)(void);
+
+DECLARE_LINKTABLE(initcall_t, init_calls);
+DECLARE_LINKTABLE(exitcall_t, exit_calls);
+
+#define __define_initcall(fn, id) \
+ static LINKTABLE_INIT_DATA(init_calls, id) \
+ __initcall_##fn##id = fn
+
+#define pure_initcall(fn) __define_initcall(fn, 0)
+#define core_initcall(fn) __define_initcall(fn, 1)
+#define postcore_initcall(fn) __define_initcall(fn, 2)
+#define arch_initcall(fn) __define_initcall(fn, 3)
+#define subsys_initcall(fn) __define_initcall(fn, 4)
+#define fs_initcall(fn) __define_initcall(fn, 5)
+#define device_initcall(fn) __define_initcall(fn, 6)
+#define late_initcall(fn) __define_initcall(fn, 7)
+
+#define __initcall(fn) device_initcall(fn)
+
+#define __exitcall(fn) \
+ static LINKTABLE_INIT_DATA(exit_calls, SECTION_ORDER_ANY) \
+ __exitcall_##fn = fn;
+
+#endif
+
+#endif /* _SANDBOX_LINUX_INIT_H */
new file mode 100644
@@ -0,0 +1,5 @@
+#include <linux/types.h>
+
+void kasan_early_init(void);
+int kasan_init(void);
+bool is_kasan_setup(void);
new file mode 100644
@@ -0,0 +1,11 @@
+#ifndef _SANDBOX_LINUX_KPROBES_H
+#define _SANDBOX_LINUX_KPROBES_H
+
+#include <asm/kprobes.h>
+#include <linux/ranges.h>
+
+#ifdef CONFIG_KPROBES
+DECLARE_SECTION_RANGE(kprobes);
+#endif
+
+#endif /* _SANDBOX_LINUX_KPROBES_H */
new file mode 100644
@@ -0,0 +1,14 @@
+#ifndef _LINUX_MODULE_H
+#define _LINUX_MODULE_H
+
+#include <linux/init.h>
+
+#define module_init(x) __initcall(x);
+#define module_exit(x) __exitcall(x);
+
+struct module {
+ int (*init)(void);
+ void (*exit)(void);
+};
+
+#endif /* _LINUX_MODULE_H */
new file mode 100644
@@ -0,0 +1,17 @@
+#ifndef __LINUX_MUTEX_H
+#define __LINUX_MUTEX_H
+
+#include <sys/types.h>
+#include <linux/sched.h>
+#include <pthread.h>
+
+struct mutex {
+ pthread_mutex_t lock;
+};
+
+void mutex_init(struct mutex *lock);
+void mutex_destroy(struct mutex *lock);
+void mutex_lock(struct mutex *lock);
+void mutex_unlock(struct mutex *lock);
+
+#endif /* __LINUX_MUTEX_H */
new file mode 100644
@@ -0,0 +1,7 @@
+#include <linux/types.h>
+
+struct pci_fixup {
+ void (*hook)(void);
+};
+
+bool detect_pci(void);
new file mode 100644
@@ -0,0 +1,46 @@
+#ifndef __PS_CONST
+#define __PS_CONST
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/tables.h>
+
+/* Helpers for partially static settings */
+
+enum ps_static_type {
+ SET_CONST_U8 = 0,
+ SET_CONST_U16,
+ SET_CONST_U32,
+};
+
+struct ps_set_const {
+ unsigned int *count;
+ enum ps_static_type type;
+ unsigned int (*func)(void);
+};
+
+DECLARE_LINKTABLE(struct ps_set_const, ps_set_const_table);
+
+#ifdef CONFIG_HAVE_ARCH_PS_CONST
+#include <asm/ps_const.h>
+#endif
+
+/*
+ * ps_ stands for "partially static", so we "partialloy static shift right"
+ * You can optimize this for your architecture.
+ *
+ * ps_shr(unsigned int in, unsigned char (*func)(void))
+ */
+#ifndef ps_shr
+#define ps_shr(_in, _func) \
+({ \
+ static unsigned int _count; \
+ static LINKTABLE_INIT_DATA(ps_set_const_table, 01) \
+ __ps_shr##__func = \
+ { &_count, SET_CONST_U8, (_func) }; \
+ \
+ (_in) >> _count; \
+})
+#endif /* ps_shr */
+
+#endif /* __PS_CONST */
new file mode 100644
@@ -0,0 +1,9 @@
+#ifndef _LINUX_SCHED_H
+#define _LINUX_SCHED_H
+
+#include <linux/ranges.h>
+
+DECLARE_SECTION_RANGE(sched_text);
+#define __sched __LINUX_RANGE(SECTION_TEXT, sched_text)
+
+#endif /* _LINUX_SCHED_H */
new file mode 100644
@@ -0,0 +1,13 @@
+#ifndef __LINUX_SPINLOCK_H
+#define __LINUX_SPINLOCK_H
+
+#include <pthread.h>
+
+#define spinlock_t pthread_spinlock_t
+
+void spin_lock_init(spinlock_t *lock);
+void spin_lock_destroy(spinlock_t *lock);
+void spin_lock(spinlock_t *lock);
+void spin_unlock(spinlock_t *lock);
+
+#endif /* __LINUX_SPINLOCK_H */
new file mode 100644
@@ -0,0 +1 @@
+int start_kernel(void);
new file mode 100644
@@ -0,0 +1,13 @@
+#ifndef __LINUX_USER_TYPES_H
+#define __LINUX_USER_TYPES_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned int __u32;
+
+#endif /* __LINUX_USER_TYPES_H */
new file mode 100644
@@ -0,0 +1,51 @@
+#ifndef _LINUX_WORKQUEUE_H
+#define _LINUX_WORKQUEUE_H
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <pthread.h>
+
+struct work {
+ bool ready;
+
+ pthread_t thread;
+ struct mutex mutex;
+ pthread_cond_t cond;
+
+ void *arg;
+ void *(*work_cb)(void *arg);
+};
+
+#define DECLARE_WORK(_w, _w_cb) \
+struct work _w = { \
+ .work_cb = _w_cb, \
+ .arg = NULL, \
+};
+
+extern void *run_work(void *arg);
+
+static inline void init_work(struct work *w)
+{
+ w->ready = false;
+
+ mutex_init(&w->mutex);
+ pthread_cond_init(&w->cond, NULL);
+
+ pthread_create(&w->thread, NULL, run_work, (void *) w);
+
+ while (1) {
+ mutex_lock(&w->mutex);
+ if (w->ready) {
+ pthread_mutex_unlock(&w->mutex.lock);
+ break;
+ }
+ mutex_unlock(&w->mutex);
+ }
+}
+
+void schedule_work(struct work *w);
+void cancel_work_sync(struct work *w);
+void init_work(struct work *w);
+
+#endif /* _LINUX_WORKQUEUE_H */
new file mode 100644
@@ -0,0 +1,4 @@
+#include <linux/types.h>
+
+bool booting_xen(void);
+int startup_xen(void);
new file mode 100644
@@ -0,0 +1,28 @@
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+
+DEFINE_SECTION_RANGE(sched_text, SECTION_TEXT);
+
+void __sched mutex_init(struct mutex *lock)
+{
+ int r;
+
+ r = pthread_mutex_init(&lock->lock, NULL);
+ if (r)
+ BUG_ON(r);
+}
+
+void __sched mutex_destroy(struct mutex *lock)
+{
+ pthread_mutex_destroy(&lock->lock);
+}
+
+void __sched mutex_lock(struct mutex *lock)
+{
+ pthread_mutex_lock(&lock->lock);
+}
+
+void __sched mutex_unlock(struct mutex *lock)
+{
+ pthread_mutex_unlock(&lock->lock);
+}
new file mode 100644
@@ -0,0 +1,26 @@
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+void spin_lock_init(spinlock_t *lock)
+{
+ int r;
+
+ r = pthread_spin_init(lock, PTHREAD_PROCESS_SHARED);
+ if (r)
+ BUG_ON(r);
+}
+
+void spin_lock_destroy(spinlock_t *lock)
+{
+ pthread_spin_destroy(lock);
+}
+
+void spin_lock(spinlock_t *lock)
+{
+ pthread_spin_lock(lock);
+}
+
+void spin_unlock(spinlock_t *lock)
+{
+ pthread_spin_unlock(lock);
+}
new file mode 100644
@@ -0,0 +1,32 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/x86_init_fn.h>
+#include <asm/x86.h>
+
+DEFINE_LINKTABLE_INIT_DATA(initcall_t, init_calls);
+
+int do_one_initcall(initcall_t fn)
+{
+ int ret;
+
+ ret = fn();
+
+ return ret;
+}
+
+static void do_initcalls(void)
+{
+ initcall_t *fn;
+
+ LINKTABLE_FOR_EACH(fn, init_calls)
+ do_one_initcall(*fn);
+}
+
+void start_kernel(void)
+{
+ pr_info("Calling start_kernel()...\n");
+
+ setup_arch();
+ late_init();
+ do_initcalls();
+}
new file mode 100644
@@ -0,0 +1,43 @@
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
+
+void schedule_work(struct work *w)
+{
+ mutex_lock(&w->mutex);
+ pthread_cond_signal(&w->cond);
+ mutex_unlock(&w->mutex);
+}
+
+void cancel_work_sync(struct work *w)
+{
+ pthread_exit(NULL);
+}
+
+void *run_work(void *arg)
+{
+ struct work *w;
+ int r;
+
+ w = (struct work *) arg;
+
+ mutex_lock(&w->mutex);
+
+ while (true) {
+ if (!w->ready)
+ w->ready = true;
+ r = pthread_cond_wait(&w->cond, &w->mutex.lock);
+ if (r != 0) {
+ printf("(%s)\n", strerror(r));
+ BUG_ON(r);
+ }
+ w->work_cb(w->arg);
+ }
+
+ mutex_unlock(&w->mutex);
+
+ pthread_exit(NULL);
+}
new file mode 100644
@@ -0,0 +1,26 @@
+/*
+ * linux/lib/string.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Licensed under GPLv2 - taken from linux-next next-20160803
+ */
+
+#include <linux/kernel.h>
+
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ *
+ * Do not use memset() to access IO space, use memset_io() instead.
+ */
+void *memset(void *s, int c, size_t count)
+{
+ char *xs = s;
+
+ while (count--)
+ *xs++ = c;
+ return s;
+}
new file mode 100644
@@ -0,0 +1,20 @@
+#include <linux/string.h>
+#include <xen/xen.h>
+#include <asm/x86.h>
+#include <asm/bootparam.h>
+
+struct boot_params boot_params __attribute__((aligned(16)));
+
+int main(int arg, char *argc[])
+{
+ memset(&boot_params, 0, sizeof(struct boot_params));
+
+ if (arg <= 1)
+ startup_64();
+ else {
+ boot_params.hdr.hardware_subarch = X86_SUBARCH_XEN;
+ startup_xen();
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,13 @@
+#include <linux/kernel.h>
+#include <linux/tables.h>
+#include <linux/pci.h>
+
+DEFINE_LINKTABLE_RO(struct pci_fixup, pci_fixup_early);
+
+static void foo_fixup(void) {
+ pr_info("foo_fixup\n");
+};
+
+LINKTABLE_RO(pci_fixup_early, 50) quirk_foo = {
+ .hook = foo_fixup,
+};
new file mode 100644
@@ -0,0 +1,29 @@
+#include <linux/kernel.h>
+#include <linux/tables.h>
+#include <asm/x86_init_fn.h>
+#include <asm/bootparam.h>
+#include <linux/pci.h>
+
+DECLARE_LINKTABLE(struct pci_fixup, pci_fixup_early);
+
+void early_init_pci(void) {
+
+ const struct pci_fixup *fixup;
+ unsigned int tbl_size = LINUX_SECTION_SIZE(pci_fixup_early);
+
+ pr_info("Initializing pci ...\n");
+
+ pr_info("PCI fixup size: %d\n", tbl_size);
+
+ sleep(1);
+ pr_info("Demo: Using LINKTABLE_FOR_EACH\n");
+ LINKTABLE_FOR_EACH(fixup, pci_fixup_early)
+ fixup->hook();
+
+ pr_info("Demo: Using LINKTABLE_RUN_ALL\n");
+ LINKTABLE_RUN_ALL(pci_fixup_early, hook,);
+
+ pr_info("Completed initializing pci !\n");
+}
+
+x86_init_early_all(early_init_pci);