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_getarch()
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_getarch(
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	 * Scan the fat_arch's looking for the best one.  */
126	addr = data_ptr;
127	best_arch = NULL;
128	best_grade = 0;
129	arch = (struct fat_arch *) (addr + sizeof(struct fat_header));
130	for (; nfat_arch-- > 0; arch++) {
131 		testtype = OSSwapBigToHostInt32(arch->cputype);
132 		testsubtype = OSSwapBigToHostInt32(arch->cpusubtype) & ~CPU_SUBTYPE_MASK;
133
134		/*
135		 *	Check to see if right cpu type.
136		 */
137 		if((testtype & ~mask_bits) != (req_cpu_type & ~mask_bits)) {
138			continue;
139		}
140
141		/*
142		 * 	Get the grade of the cpu subtype (without feature flags)
143		 */
144 		grade = grade_binary(testtype, testsubtype);
145
146		/*
147		 *	Remember it if it's the best we've seen.
148		 */
149		if (grade > best_grade) {
150			best_grade = grade;
151			best_arch = arch;
152		}
153	}
154
155	/*
156	 *	Return our results.
157	 */
158	if (best_arch == NULL) {
159		lret = LOAD_BADARCH;
160	} else {
161		archret->cputype	=
162			    OSSwapBigToHostInt32(best_arch->cputype);
163		archret->cpusubtype	=
164			    OSSwapBigToHostInt32(best_arch->cpusubtype);
165		archret->offset		=
166			    OSSwapBigToHostInt32(best_arch->offset);
167		archret->size		=
168			    OSSwapBigToHostInt32(best_arch->size);
169		archret->align		=
170			    OSSwapBigToHostInt32(best_arch->align);
171
172		lret = LOAD_SUCCESS;
173	}
174
175	/*
176	 * Free the memory we allocated and return.
177	 */
178	return(lret);
179}
180
181load_return_t
182fatfile_getarch_affinity(
183		struct vnode		*vp,
184		vm_offset_t		data_ptr,
185		struct fat_arch	*archret,
186		int 				affinity __unused)
187{
188	/*
189	 * Ignore all architectural bits when determining if an image
190	 * in a fat file should be skipped or graded.
191	 */
192	return fatfile_getarch(vp, data_ptr, cpu_type(), CPU_ARCH_MASK, archret);
193}
194
195/**********************************************************************
196 * Routine:	fatfile_getarch_with_bits()
197 *
198 * Function:	Locate the architecture-dependant contents of a fat
199 *		file that match this CPU.
200 *
201 * Args:	vp:		The vnode for the fat file.
202 *		archbits:	Architecture specific feature bits
203 *		header:		A pointer to the fat file header.
204 *		archret (out):	Pointer to fat_arch structure to hold
205 *				the results.
206 *
207 * Returns:	KERN_SUCCESS:	Valid architecture found.
208 *		KERN_FAILURE:	No valid architecture found.
209 **********************************************************************/
210load_return_t
211fatfile_getarch_with_bits(
212	struct vnode		*vp,
213	integer_t		archbits,
214	vm_offset_t 	data_ptr,
215	struct fat_arch		*archret)
216{
217	return fatfile_getarch(vp, data_ptr, archbits | (cpu_type() & ~CPU_ARCH_MASK), 0, archret);
218}
219
220