2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * @OSF_FREE_COPYRIGHT@
32 #include <pexpert/pexpert.h>
33 #include <libkern/section_keywords.h>
34 #include <libkern/kernel_mach_header.h>
36 vm_offset_t kc_highest_nonlinkedit_vmaddr
= 0;
37 int vnode_put(void *vp
);
39 // FIXME: should come from mach-o/fixup_chains.h
40 // Index in basePointers array used by chained rebase in dyld_kernel_fixups.h
41 typedef enum kc_index
{
43 pageable_kc_index
= 1,
44 auxiliary_kc_index
= 3,
47 #if defined(__x86_64__) || defined(__i386__)
48 /* FIXME: This should be locked down during early boot */
49 void *collection_base_pointers
[KCNumKinds
] = {};
50 kernel_mach_header_t
* collection_mach_headers
[KCNumKinds
] = {};
51 uintptr_t collection_slide
[KCNumKinds
] = {};
52 void * collection_vp
[KCNumKinds
] = {};
55 SECURITY_READ_ONLY_LATE(void *) collection_base_pointers
[KCNumKinds
];
56 SECURITY_READ_ONLY_LATE(kernel_mach_header_t
*) collection_mach_headers
[KCNumKinds
];
57 SECURITY_READ_ONLY_LATE(uintptr_t) collection_slide
[KCNumKinds
];
58 SECURITY_READ_ONLY_LATE(void *) collection_vp
[KCNumKinds
];
59 #endif //(__x86_64__) || defined(__i386__)
61 static inline kc_index_t
62 kc_kind2index(kc_kind_t type
)
66 return primary_kc_index
;
68 return pageable_kc_index
;
70 return auxiliary_kc_index
;
72 panic("Invalid KC Kind");
75 __builtin_unreachable();
79 PE_set_kc_header(kc_kind_t type
, kernel_mach_header_t
*header
, uintptr_t slide
)
81 kc_index_t i
= kc_kind2index(type
);
82 assert(!collection_base_pointers
[i
]);
83 assert(!collection_mach_headers
[i
]);
84 collection_mach_headers
[i
] = header
;
85 collection_slide
[i
] = slide
;
87 struct load_command
*lc
;
88 struct segment_command_64
*seg
;
89 uint64_t lowest_vmaddr
= ~0ULL;
91 lc
= (struct load_command
*)((uintptr_t)header
+ sizeof(*header
));
92 for (uint32_t j
= 0; j
< header
->ncmds
; j
++,
93 lc
= (struct load_command
*)((uintptr_t)lc
+ lc
->cmdsize
)) {
94 if (lc
->cmd
!= LC_SEGMENT_64
) {
97 seg
= (struct segment_command_64
*)(uintptr_t)lc
;
98 if (seg
->vmaddr
< lowest_vmaddr
) {
99 lowest_vmaddr
= seg
->vmaddr
;
103 collection_base_pointers
[i
] = (void *)(uintptr_t)lowest_vmaddr
+ slide
;
104 assert((uint64_t)(uintptr_t)collection_base_pointers
[i
] != ~0ULL);
108 PE_reset_kc_header(kc_kind_t type
)
110 if (type
== KCKindPrimary
) {
114 kc_index_t i
= kc_kind2index(type
);
115 collection_mach_headers
[i
] = 0;
116 collection_base_pointers
[i
] = 0;
117 collection_slide
[i
] = 0;
121 PE_set_kc_header_and_base(kc_kind_t type
, kernel_mach_header_t
* header
, void *base
, uintptr_t slide
)
123 kc_index_t i
= kc_kind2index(type
);
124 assert(!collection_base_pointers
[i
]);
125 assert(!collection_mach_headers
[i
]);
126 collection_mach_headers
[i
] = header
;
127 collection_slide
[i
] = slide
;
128 collection_base_pointers
[i
] = base
;
132 PE_get_kc_header(kc_kind_t type
)
134 return collection_mach_headers
[kc_kind2index(type
)];
138 PE_set_kc_vp(kc_kind_t type
, void *vp
)
140 kc_index_t i
= kc_kind2index(type
);
141 assert(collection_vp
[i
] == NULL
);
143 collection_vp
[i
] = vp
;
147 PE_get_kc_vp(kc_kind_t type
)
149 kc_index_t i
= kc_kind2index(type
);
150 return collection_vp
[i
];
154 PE_reset_all_kc_vp(void)
156 for (int i
= 0; i
< KCNumKinds
; i
++) {
157 if (collection_vp
[i
] != NULL
) {
158 vnode_put(collection_vp
[i
]);
159 collection_vp
[i
] = NULL
;
165 PE_get_kc_base_pointers(void)
167 return (const void * const*)collection_base_pointers
;
171 * Prelinked kexts in an MH_FILESET start with address 0,
172 * the slide for such kexts is calculated from the base
173 * address of the first kext mapped in that KC. Return the
174 * slide based on the type of the KC.
176 * Prelinked kexts booted from a non MH_FILESET KC are
177 * marked as KCKindUnknown, for such cases, return
181 PE_get_kc_slide(kc_kind_t type
)
183 if (type
== KCKindUnknown
) {
184 return vm_kernel_slide
;
186 return collection_slide
[kc_kind2index(type
)];
190 PE_get_primary_kc_format(kc_format_t
*type
)
193 kernel_mach_header_t
*mh
= PE_get_kc_header(KCKindPrimary
);
194 if (mh
&& mh
->filetype
== MH_FILESET
) {
195 *type
= KCFormatFileset
;
197 #if defined(__arm__) || defined(__arm64__)
198 /* From osfmk/arm/arm_init.c */
199 extern bool static_kernelcache
;
200 if (static_kernelcache
) {
201 *type
= KCFormatStatic
;
203 *type
= KCFormatKCGEN
;
206 *type
= KCFormatDynamic
;
214 PE_get_kc_baseaddress(kc_kind_t type
)
216 kc_index_t i
= kc_kind2index(type
);
218 #if defined(__arm__) || defined(__arm64__)
219 case KCKindPrimary
: {
220 extern vm_offset_t segLOWESTTEXT
;
221 return (void*)segLOWESTTEXT
;
225 return collection_base_pointers
[i
];