]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/startup.h
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / kern / startup.h
index 58389f73fdc11df24379a80feb382ae41b526045..83f26c45ef4794b64d557b8103b7bdf778374e45 100644 (file)
@@ -1,15 +1,20 @@
 /*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * @OSF_COPYRIGHT@
  */
 
-#ifdef XNU_KERNEL_PRIVATE
+#ifdef  XNU_KERNEL_PRIVATE
+
+#ifndef _KERN_STARTUP_H_
+#define _KERN_STARTUP_H_
 
-#ifndef        _KERN_STARTUP_H_
-#define        _KERN_STARTUP_H_
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <libkern/section_keywords.h>
 
-#include <sys/cdefs.h>
 __BEGIN_DECLS
 
+#pragma GCC visibility push(hidden)
+
+/*!
+ * @enum startup_subsystem_id_t
+ *
+ * @abstract
+ * Represents a stage of kernel intialization, ubnd allows for subsystems
+ * to register initializers for a specific stage.
+ *
+ * @discussion
+ * Documentation of each subsystem initialization sequence exists in
+ * @file doc/startup.md.
+ */
+__enum_decl(startup_subsystem_id_t, uint32_t, {
+       STARTUP_SUB_NONE = 0,         /**< reserved for the startup subsystem  */
+
+       STARTUP_SUB_TUNABLES,         /**< support for the tunables subsystem  */
+       STARTUP_SUB_LOCKS_EARLY,      /**< early locking, before zalloc        */
+       STARTUP_SUB_KPRINTF,          /**< kprintf initialization              */
+
+       STARTUP_SUB_PMAP_STEAL,       /**< to perform various pmap carveouts   */
+       STARTUP_SUB_VM_KERNEL,        /**< once the kernel VM is ready         */
+       STARTUP_SUB_KMEM,             /**< once kmem is ready                  */
+       STARTUP_SUB_KMEM_ALLOC,       /**< once kmem_alloc is ready            */
+       STARTUP_SUB_ZALLOC,           /**< initialize zalloc and kalloc        */
+       STARTUP_SUB_PERCPU,           /**< initialize the percpu subsystem     */
+       STARTUP_SUB_LOCKS,            /**< various subsystem locks             */
+
+       STARTUP_SUB_CODESIGNING,      /**< codesigning subsystem               */
+       STARTUP_SUB_OSLOG,            /**< oslog and kernel loggging           */
+       STARTUP_SUB_MACH_IPC,         /**< Mach IPC                            */
+       STARTUP_SUB_SYSCTL,           /**< registers sysctls                   */
+       STARTUP_SUB_EARLY_BOOT,       /**< interrupts/premption are turned on  */
+
+       STARTUP_SUB_LOCKDOWN = ~0u,   /**< reserved for the startup subsystem  */
+});
+
+/*!
+ * Stores the last subsystem to have been fully initialized;
+ */
+extern startup_subsystem_id_t startup_phase;
+
+/*!
+ * @enum startup_debug_t
+ *
+ * @abstract
+ * Flags set in the @c startup_debug global to configure startup debugging.
+ */
+__options_decl(startup_debug_t, uint32_t, {
+       STARTUP_DEBUG_NONE    = 0x00000000,
+       STARTUP_DEBUG_VERBOSE = 0x00000001,
+});
+
+#if DEBUG || DEVELOPMENT
+extern startup_debug_t startup_debug;
+#else
+#define startup_debug  STARTUP_DEBUG_NONE
+#endif
+
+/*!
+ * @enum startup_rank
+ *
+ * @abstract
+ * Specifies in which rank a given initializer runs within a given section
+ * to register initializers for a specific rank within the subsystem.
+ *
+ * @description
+ * A startup function, declared with @c STARTUP or @c STARTUP_ARG, can specify
+ * an rank within the subsystem they initialize.
+ *
+ * @c STARTUP_RANK_NTH(n) will let callbacks be run at stage @c n (0-based).
+ *
+ * @c STARTUP_RANK_FIRST, @c STARTUP_RANK_SECOND, @c STARTUP_RANK_THIRD and
+ * @c STARTUP_RANK_FOURTH are given as conveniency names for these.
+ *
+ * @c STARTUP_RANK_MIDDLE is a reserved value that will let startup functions
+ * run after all the @c STARTUP_RANK_NTH(n) ones have.
+ *
+ * @c STARTUP_RANK_NTH_LATE_NTH(n) will let callbacks be run then in @c n rank
+ * after the @c STARTUP_RANK_MIDDLE ones (0-based).
+ *
+ * @c STARTUP_RANK_LAST callbacks will run absolutely last after everything
+ * else did for this subsystem.
+ */
+__enum_decl(startup_rank_t, uint32_t, {
+#define STARTUP_RANK_NTH(n) \
+       (enum startup_rank)(n)
+       STARTUP_RANK_FIRST          = 0,
+       STARTUP_RANK_SECOND         = 1,
+       STARTUP_RANK_THIRD          = 2,
+       STARTUP_RANK_FOURTH         = 3,
+
+       STARTUP_RANK_MIDDLE         = 0x7fffffff,
+
+#define STARTUP_RANK_LATE_NTH(n) \
+       (enum startup_rank)(STARTUP_RANK_MIDDLE + 1 + (n))
+
+       STARTUP_RANK_LAST           = 0xffffffff,
+});
+
+#if KASAN
+/*
+ * The use of weird sections that get unmapped confuse the hell out of kasan,
+ * so for KASAN leave things in regular __TEXT/__DATA segments
+ */
+#define STARTUP_CODE_SEGSECT "__TEXT,__text"
+#define STARTUP_DATA_SEGSECT "__DATA,__init"
+#define STARTUP_HOOK_SEGMENT "__DATA"
+#define STARTUP_HOOK_SECTION "__init_entry_set"
+#elif defined(__x86_64__)
+/* Intel doesn't have a __BOOTDATA but doesn't protect __KLD */
+#define STARTUP_CODE_SEGSECT "__TEXT,__text"
+#define STARTUP_DATA_SEGSECT "__KLDDATA,__init"
+#define STARTUP_HOOK_SEGMENT "__KLDDATA"
+#define STARTUP_HOOK_SECTION "__init_entry_set"
+#else
+/* arm protects __KLD early, so use __BOOTDATA for data */
+#define STARTUP_CODE_SEGSECT "__TEXT,__text"
+#define STARTUP_DATA_SEGSECT "__BOOTDATA,__init"
+#define STARTUP_HOOK_SEGMENT "__BOOTDATA"
+#define STARTUP_HOOK_SECTION "__init_entry_set"
+#endif
+
+/*!
+ * @macro __startup_func
+ *
+ * @abstract
+ * Attribute to place on functions used only during the kernel startup phase.
+ *
+ * @description
+ * Code marked with this attribute will be unmapped after kernel lockdown.
+ */
+#define __startup_func \
+       __PLACE_IN_SECTION(STARTUP_CODE_SEGSECT) \
+       __attribute__((cold, visibility("hidden")))
+
+/*!
+ * @macro __startup_data
+ *
+ * @abstract
+ * Attribute to place on globals used during the kernel startup phase.
+ *
+ * @description
+ * Data marked with this attribute will be unmapped after kernel lockdown.
+ */
+#define __startup_data \
+       __PLACE_IN_SECTION(STARTUP_DATA_SEGSECT)
+
+/*!
+ * @macro STARTUP
+ *
+ * @abstract
+ * Declares a kernel startup callback.
+ */
+#define STARTUP(subsystem, rank, func) \
+       __STARTUP(func, __LINE__, subsystem, rank, func)
+
+/*!
+ * @macro STARTUP_ARG
+ *
+ * @abstract
+ * Declares a kernel startup callback that takes an argument.
+ */
+#define STARTUP_ARG(subsystem, rank, func, arg) \
+       __STARTUP_ARG(func, __LINE__, subsystem, rank, func, arg)
+
+/*!
+ * @macro TUNABLE
+ *
+ * @abstract
+ * Declares a read-only kernel tunable that is read from a boot-arg with
+ * a default value, without further processing.
+ *
+ * @param type_t
+ * Should be an integer type or bool.
+ *
+ * @param var
+ * The name of the C variable to use for storage.
+ *
+ * @param key
+ * The name of the boot-arg to parse for initialization
+ *
+ * @param default_value
+ * The default value for the tunable if the boot-arg is absent.
+ */
+#define TUNABLE(type_t, var, key, default_value) \
+       SECURITY_READ_ONLY_LATE(type_t) var = default_value; \
+       __TUNABLE(type_t, var, key)
+
+/*!
+ * @macro TUNABLE_WRITEABLE
+ *
+ * @abstract
+ * Declares a writeable kernel tunable that is read from a boot-arg with
+ * a default value, without further processing.
+ *
+ * @param type_t
+ * Should be an integer type or bool.
+ *
+ * @param var
+ * The name of the C variable to use for storage.
+ *
+ * @param key
+ * The name of the boot-arg to parse for initialization
+ *
+ * @param default_value
+ * The default value for the tunable if the boot-arg is absent.
+ */
+#define TUNABLE_WRITEABLE(type_t, var, key, default_value) \
+       type_t var = default_value; \
+       __TUNABLE(type_t, var, key)
+
+#pragma mark - internals
+
+#define __TUNABLE(type_t, var, key) \
+       static __startup_data char __startup_TUNABLES_name_ ## var[] = key; \
+       static __startup_data struct startup_tunable_spec \
+       __startup_TUNABLES_spec_ ## var = { \
+           .name = __startup_TUNABLES_name_ ## var, \
+           .var_addr = (void *)&var, \
+           .var_len = sizeof(type_t), \
+           .var_is_bool = __builtin_types_compatible_p(bool, type_t), \
+       }; \
+       __STARTUP_ARG(var, __LINE__, TUNABLES, STARTUP_RANK_FIRST, \
+           kernel_startup_tunable_init, &__startup_TUNABLES_spec_ ## var)
+
+#ifdef __cplusplus
+#define __STARTUP_FUNC_CAST(func, a) \
+           (void(*)(const void *))func
+#else
+#define __STARTUP_FUNC_CAST(func, a) \
+           (typeof(func(a))(*)(const void *))func
+#endif
+
+
+#define __STARTUP1(name, line, subsystem, rank, func, a, b) \
+       __PLACE_IN_SECTION(STARTUP_HOOK_SEGMENT "," STARTUP_HOOK_SECTION) \
+       static const struct startup_entry \
+       __startup_ ## subsystem ## _entry_ ## name ## _ ## line = { \
+           STARTUP_SUB_ ## subsystem, \
+           rank, __STARTUP_FUNC_CAST(func, a), b, \
+       }
+
+#define __STARTUP(name, line, subsystem, rank, func) \
+       __STARTUP1(name, line, subsystem, rank, func, , NULL)
+
+#define __STARTUP_ARG(name, line, subsystem, rank, func, arg) \
+       __STARTUP1(name, line, subsystem, rank, func, arg, arg)
+
+struct startup_entry {
+       startup_subsystem_id_t subsystem;
+       startup_rank_t         rank;
+       void                 (*func)(const void *);
+       const void            *arg;
+};
+
+struct startup_tunable_spec {
+       const char *name;
+       void       *var_addr;
+       int         var_len;
+       bool        var_is_bool;
+};
+
 /*
  * Kernel and machine startup declarations
  */
 
 /* Initialize kernel */
-extern void            kernel_bootstrap(void);
+extern void kernel_startup_bootstrap(void);
+extern void kernel_startup_initialize_upto(startup_subsystem_id_t upto);
+extern void kernel_startup_tunable_init(const struct startup_tunable_spec *);
+extern void kernel_bootstrap(void);
 
 /* Initialize machine dependent stuff */
-extern void    machine_init(void);
+extern void machine_init(void);
 
-extern void    slave_main(void);
+extern void slave_main(void *machine_param);
 
 /*
  * The following must be implemented in machine dependent code.
  */
 
 /* Slave cpu initialization */
-extern void    slave_machine_init(void);
+extern void slave_machine_init(void *machine_param);
 
 /* Device subystem initialization */
-extern void    device_service_create(void);
+extern void device_service_create(void);
 
-#ifdef MACH_BSD
+#ifdef  MACH_BSD
 
 /* BSD subsystem initialization */
-extern void    bsd_init(void);
+extern void bsd_init(void);
+
+#endif  /* MACH_BSD */
 
-#endif /* MACH_BSD */
+#pragma GCC visibility pop
 
 __END_DECLS
 
-#endif /* _KERN_STARTUP_H_ */
+#endif  /* _KERN_STARTUP_H_ */
 
-#endif /* XNU_KERNEL_PRIVATE */
+#endif  /* XNU_KERNEL_PRIVATE */