1/*
2 * Copyright (c) 1991-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28#include <sys/param.h>
29#include <sys/types.h>
30#include <sys/uio.h>
31#include <sys/vnode.h>
32#include <vm/vm_kern.h>
33#include <mach/kern_return.h>
34#include <mach/vm_param.h>
35#include <kern/cpu_number.h>
36#include <mach-o/fat.h>
37#include <kern/mach_loader.h>
38#include <kern/mach_fat.h>
39#include <libkern/OSByteOrder.h>
40#include <machine/exec.h>
41
42/**********************************************************************
43 * Routine:	fatfile_getarch2()
44 *
45 * Function:	Locate the architecture-dependant contents of a fat
46 *		file that match this CPU.
47 *
48 * Args:	vp:		The vnode for the fat file.
49 *		header:		A pointer to the fat file header.
50 *		req_cpu_type:	The required cpu type.
51 *		mask_bits:	Bits to mask from the sub-image type when
52 *				grading it vs. the req_cpu_type
53 *		archret (out):	Pointer to fat_arch structure to hold
54 *				the results.
55 *
56 * Returns:	KERN_SUCCESS:	Valid architecture found.
57 *		KERN_FAILURE:	No valid architecture found.
58 **********************************************************************/
59static load_return_t
60fatfile_getarch2(
61#if 0
62	struct vnode	*vp,
63#else
64	__unused struct vnode	*vp,
65#endif
66	vm_offset_t	data_ptr,
67	cpu_type_t	req_cpu_type,
68	cpu_type_t	mask_bits,
69	struct fat_arch	*archret)
70{
71	/* vm_pager_t		pager; */
72	vm_offset_t		addr;
73	vm_size_t		size;
74	load_return_t		lret;
75	struct fat_arch		*arch;
76	struct fat_arch		*best_arch;
77	int			grade;
78	int			best_grade;
79	int			nfat_arch;
80	off_t			end_of_archs;
81	cpu_type_t		testtype;
82	cpu_type_t		testsubtype;
83	struct fat_header	*header;
84#if 0
85	off_t filesize;
86#endif
87
88	/*
89	 * 	Get the pager for the file.
90	 */
91
92	header = (struct fat_header *)data_ptr;
93
94	/*
95	 *	Map portion that must be accessible directly into
96	 *	kernel's map.
97	 */
98	nfat_arch = OSSwapBigToHostInt32(header->nfat_arch);
99
100	end_of_archs = (off_t)nfat_arch * sizeof(struct fat_arch) +
101			sizeof(struct fat_header);
102#if 0
103	filesize = ubc_getsize(vp);
104	if (end_of_archs > (int)filesize) {
105		return(LOAD_BADMACHO);
106	}
107#endif
108
109	/*
110	 * This check is limited on the top end because we are reading
111	 * only PAGE_SIZE bytes
112	 */
113	if (end_of_archs > PAGE_SIZE ||
114	    end_of_archs < (off_t)(sizeof(struct fat_header)+sizeof(struct fat_arch)))
115		return(LOAD_BADMACHO);
116
117	/*
118	 * 	Round size of fat_arch structures up to page boundry.
119	 */
120	size = round_page(end_of_archs);
121	if (size == 0)
122		return(LOAD_BADMACHO);
123
124	/*
125	 * Ignore LIB64 flag so that binary slices with the flag set
126	 * don't choke in grade_binary.
127	 */
128	mask_bits |= CPU_SUBTYPE_LIB64;
129
130	/*
131	 * Scan the fat_arch's looking for the best one.  */
132	addr = data_ptr;
133	best_arch = NULL;
134	best_grade = 0;
135	arch = (struct fat_arch *) (addr + sizeof(struct fat_header));
136	for (; nfat_arch-- > 0; arch++) {
137
138		/*
139		 *	Collect flags from both cputype and cpusubtype
140		 */
141 		testtype = OSSwapBigToHostInt32(arch->cputype) |
142 				(OSSwapBigToHostInt32(arch->cpusubtype) &
143 					CPU_SUBTYPE_MASK);
144 		testsubtype = OSSwapBigToHostInt32(arch->cpusubtype)
145 			& ~CPU_SUBTYPE_MASK;
146
147		/*
148		 *	Check to see if right cpu type.
149		 */
150 		if((testtype & ~mask_bits) != req_cpu_type) {
151			continue;
152		}
153
154		/*
155		 * 	Get the grade of the cpu subtype (without feature flags)
156		 */
157 		grade = grade_binary(
158				(testtype & ~CPU_SUBTYPE_LIB64),
159				testsubtype);
160
161		/*
162		 *	Remember it if it's the best we've seen.
163		 */
164		if (grade > best_grade) {
165			best_grade = grade;
166			best_arch = arch;
167		}
168	}
169
170	/*
171	 *	Return our results.
172	 */
173	if (best_arch == NULL) {
174		lret = LOAD_BADARCH;
175	} else {
176		archret->cputype	=
177			    OSSwapBigToHostInt32(best_arch->cputype);
178		archret->cpusubtype	=
179			    OSSwapBigToHostInt32(best_arch->cpusubtype);
180		archret->offset		=
181			    OSSwapBigToHostInt32(best_arch->offset);
182		archret->size		=
183			    OSSwapBigToHostInt32(best_arch->size);
184		archret->align		=
185			    OSSwapBigToHostInt32(best_arch->align);
186
187		lret = LOAD_SUCCESS;
188	}
189
190	/*
191	 * Free the memory we allocated and return.
192	 */
193	return(lret);
194}
195
196load_return_t
197fatfile_getarch_affinity(
198		struct vnode		*vp,
199		vm_offset_t		data_ptr,
200		struct fat_arch	*archret,
201		int 				affinity __unused)
202{
203		/*
204		 * Ignore all architectural bits when determining if an image
205		 * in a fat file should be skipped or graded.
206		 */
207		return fatfile_getarch2(vp, data_ptr, cpu_type(),
208				CPU_ARCH_MASK, archret);
209}
210
211/**********************************************************************
212 * Routine:	fatfile_getarch()
213 *
214 * Function:	Locate the architecture-dependant contents of a fat
215 *		file that match this CPU.
216 *
217 * Args:	vp:		The vnode for the fat file.
218 *		header:		A pointer to the fat file header.
219 *		archret (out):	Pointer to fat_arch structure to hold
220 *				the results.
221 *
222 * Returns:	KERN_SUCCESS:	Valid architecture found.
223 *		KERN_FAILURE:	No valid architecture found.
224 **********************************************************************/
225load_return_t
226fatfile_getarch(
227	struct vnode		*vp,
228	vm_offset_t 	data_ptr,
229	struct fat_arch		*archret)
230{
231	return fatfile_getarch2(vp, data_ptr, cpu_type(),
232			CPU_SUBTYPE_LIB64, archret);
233}
234
235/**********************************************************************
236 * Routine:	fatfile_getarch_with_bits()
237 *
238 * Function:	Locate the architecture-dependant contents of a fat
239 *		file that match this CPU.
240 *
241 * Args:	vp:		The vnode for the fat file.
242 *		archbits:	Architecture specific feature bits
243 *		header:		A pointer to the fat file header.
244 *		archret (out):	Pointer to fat_arch structure to hold
245 *				the results.
246 *
247 * Returns:	KERN_SUCCESS:	Valid architecture found.
248 *		KERN_FAILURE:	No valid architecture found.
249 **********************************************************************/
250load_return_t
251fatfile_getarch_with_bits(
252	struct vnode		*vp,
253	integer_t		archbits,
254	vm_offset_t 	data_ptr,
255	struct fat_arch		*archret)
256{
257	return fatfile_getarch2(vp, data_ptr, archbits | cpu_type(),
258			CPU_SUBTYPE_LIB64, archret);
259}
260
261