2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * Here's what to do if you want to add a new routine to the comm page:
29 * 1. Add a definition for it's address in osfmk/ppc/cpu_capabilities.h,
30 * being careful to reserve room for future expansion.
32 * 2. Write one or more versions of the routine, each with it's own
33 * commpage_descriptor. The tricky part is getting the "special",
34 * "musthave", and "canthave" fields right, so that exactly one
35 * version of the routine is selected for every machine.
36 * The source files should be in osfmk/ppc/commpage/.
38 * 3. Add a ptr to your new commpage_descriptor(s) in the "routines"
39 * array in commpage_populate(). Of course, you'll also have to
40 * declare them "extern" in commpage_populate().
42 * 4. Write the code in Libc to use the new routine.
45 #include <mach/mach_types.h>
46 #include <mach/machine.h>
47 #include <i386/machine_routines.h>
48 #include <machine/cpu_capabilities.h>
49 #include <machine/commpage.h>
50 #include <machine/pmap.h>
51 #include <vm/vm_kern.h>
52 #include <mach/vm_map.h>
54 static uintptr_t next
= 0; // next available byte in comm page
55 static int cur_routine
= 0; // comm page address of "current" routine
56 static int matched
; // true if we've found a match for "current" routine
58 int _cpu_capabilities
= 0; // define the capability vector
60 char *commPagePtr
= NULL
; // virtual address of comm page in kernel map
62 /* Allocate the commpage and add to the shared submap created by vm:
63 * 1. allocate a page in the kernel map (RW)
65 * 3. make a memory entry out of it
66 * 4. map that entry into the shared comm region map (R-only)
70 commpage_allocate( void )
72 extern vm_map_t com_region_map
; // the shared submap, set up in vm init
73 vm_offset_t kernel_addr
; // address of commpage in kernel map
75 vm_size_t size
= _COMM_PAGE_AREA_LENGTH
;
78 if (com_region_map
== NULL
)
79 panic("commpage map is null");
81 if (vm_allocate(kernel_map
,&kernel_addr
,_COMM_PAGE_AREA_LENGTH
,VM_FLAGS_ANYWHERE
))
82 panic("cannot allocate commpage");
84 if (vm_map_wire(kernel_map
,kernel_addr
,kernel_addr
+_COMM_PAGE_AREA_LENGTH
,VM_PROT_DEFAULT
,FALSE
))
85 panic("cannot wire commpage");
87 if (mach_make_memory_entry( kernel_map
, // target map
89 kernel_addr
, // offset (address in kernel map)
90 VM_PROT_DEFAULT
, // map it RW
91 &handle
, // this is the object handle we get
92 NULL
)) // parent_entry (what is this?)
93 panic("cannot make entry for commpage");
95 if (vm_map_64( com_region_map
, // target map (shared submap)
96 &zero
, // address (map into 1st page in submap)
97 _COMM_PAGE_AREA_LENGTH
, // size
99 VM_FLAGS_FIXED
, // flags (it must be 1st page in submap)
100 handle
, // port is the memory entry we just made
101 0, // offset (map 1st page in memory entry)
103 VM_PROT_READ
, // cur_protection (R-only in user map)
104 VM_PROT_READ
, // max_protection
105 VM_INHERIT_SHARE
)) // inheritance
106 panic("cannot map commpage");
108 ipc_port_release(handle
);
110 return (void*) kernel_addr
; // return address in kernel map
113 /* Get address (in kernel map) of a commpage field. */
117 int addr_at_runtime
)
119 return (void*) ((uintptr_t)commPagePtr
+ addr_at_runtime
- _COMM_PAGE_BASE_ADDRESS
);
122 /* Determine number of CPUs on this system. We cannot rely on
123 * machine_info.max_cpus this early in the boot.
126 commpage_cpus( void )
130 cpus
= ml_get_max_cpus(); // NB: this call can block
133 panic("commpage cpus==0");
140 /* Initialize kernel version of _cpu_capabilities vector (used by KEXTs.) */
143 commpage_init_cpu_capabilities( void )
147 ml_cpu_info_t cpu_info
;
150 ml_cpu_get_info(&cpu_info
);
152 switch (cpu_info
.vector_unit
) {
167 switch (cpu_info
.cache_line_size
) {
180 cpus
= commpage_cpus(); // how many CPUs do we have
185 bits
|= (cpus
<< kNumCPUsShift
);
187 _cpu_capabilities
= bits
; // set kernel version for use by drivers etc
190 /* Copy data into commpage. */
198 void *dest
= commpage_addr_of(address
);
200 if ((uintptr_t)dest
< next
)
201 panic("commpage overlap");
203 bcopy(source
,dest
,length
);
205 next
= ((uintptr_t)dest
+ length
);
208 /* Copy a routine into comm page if it matches running machine.
211 commpage_stuff_routine(
212 commpage_descriptor
*rd
)
216 if (rd
->commpage_address
!= cur_routine
) {
217 if ((cur_routine
!=0) && (matched
==0))
218 panic("commpage no match");
219 cur_routine
= rd
->commpage_address
;
223 must
= _cpu_capabilities
& rd
->musthave
;
224 cant
= _cpu_capabilities
& rd
->canthave
;
226 if ((must
== rd
->musthave
) && (cant
== 0)) {
228 panic("commpage duplicate matches");
231 commpage_stuff(rd
->commpage_address
,rd
->code_address
,rd
->code_length
);
235 /* Fill in commpage: called once, during kernel initialization, from the
236 * startup thread before user-mode code is running.
237 * See the top of this file for a list of what you have to do to add
238 * a new routine to the commpage.
242 commpage_populate( void )
244 commpage_descriptor
**rd
;
245 short version
= _COMM_PAGE_THIS_VERSION
;
248 extern char commpage_sigs_begin
[];
249 extern char commpage_sigs_end
[];
251 extern commpage_descriptor commpage_mach_absolute_time
;
252 extern commpage_descriptor commpage_spin_lock_try_mp
;
253 extern commpage_descriptor commpage_spin_lock_try_up
;
254 extern commpage_descriptor commpage_spin_lock_mp
;
255 extern commpage_descriptor commpage_spin_lock_up
;
256 extern commpage_descriptor commpage_spin_unlock
;
257 extern commpage_descriptor commpage_pthread_getspecific
;
258 extern commpage_descriptor commpage_gettimeofday
;
259 extern commpage_descriptor commpage_sys_flush_dcache
;
260 extern commpage_descriptor commpage_sys_icache_invalidate
;
261 extern commpage_descriptor commpage_pthread_self
;
262 extern commpage_descriptor commpage_relinquish
;
263 extern commpage_descriptor commpage_bzero_scalar
;
264 extern commpage_descriptor commpage_bcopy_scalar
;
266 static commpage_descriptor
*routines
[] = {
267 &commpage_mach_absolute_time
,
268 &commpage_spin_lock_try_mp
,
269 &commpage_spin_lock_try_up
,
270 &commpage_spin_lock_mp
,
271 &commpage_spin_lock_up
,
272 &commpage_spin_unlock
,
273 &commpage_pthread_getspecific
,
274 &commpage_gettimeofday
,
275 &commpage_sys_flush_dcache
,
276 &commpage_sys_icache_invalidate
,
277 &commpage_pthread_self
,
278 &commpage_relinquish
,
279 &commpage_bzero_scalar
,
280 &commpage_bcopy_scalar
,
284 commPagePtr
= (char *)commpage_allocate();
286 commpage_init_cpu_capabilities();
288 /* Stuff in the constants. We move things into the comm page in strictly
289 * ascending order, so we can check for overlap and panic if so.
292 commpage_stuff(_COMM_PAGE_VERSION
,&version
,sizeof(short));
293 commpage_stuff(_COMM_PAGE_CPU_CAPABILITIES
,&_cpu_capabilities
,
296 for( rd
= routines
; *rd
!= NULL
; rd
++ )
297 commpage_stuff_routine(*rd
);
300 panic("commpage no match on last routine");
302 if (next
> ((uintptr_t)commPagePtr
+ PAGE_SIZE
))
303 panic("commpage overflow");
305 #define STUFF_SIG(addr, func) \
306 extern char commpage_sig_ ## func []; \
307 sig_addr = (void *)( (uintptr_t)_COMM_PAGE_BASE_ADDRESS + \
308 (uintptr_t)_COMM_PAGE_SIGS_OFFSET + 0x1000 + \
309 (uintptr_t)&commpage_sig_ ## func - \
310 (uintptr_t)&commpage_sigs_begin ); \
311 commpage_stuff(addr + _COMM_PAGE_SIGS_OFFSET, &sig_addr, sizeof(void *));
313 STUFF_SIG(_COMM_PAGE_ABSOLUTE_TIME
, mach_absolute_time
);
314 STUFF_SIG(_COMM_PAGE_SPINLOCK_TRY
, spin_lock_try
);
315 STUFF_SIG(_COMM_PAGE_SPINLOCK_LOCK
, spin_lock
);
316 STUFF_SIG(_COMM_PAGE_SPINLOCK_UNLOCK
, spin_unlock
);
317 STUFF_SIG(_COMM_PAGE_PTHREAD_GETSPECIFIC
, pthread_getspecific
);
318 STUFF_SIG(_COMM_PAGE_GETTIMEOFDAY
, gettimeofday
);
319 STUFF_SIG(_COMM_PAGE_FLUSH_DCACHE
, sys_dcache_flush
);
320 STUFF_SIG(_COMM_PAGE_FLUSH_ICACHE
, sys_icache_invalidate
);
321 STUFF_SIG(_COMM_PAGE_PTHREAD_SELF
, pthread_self
);
322 STUFF_SIG(_COMM_PAGE_BZERO
, bzero
);
323 STUFF_SIG(_COMM_PAGE_BCOPY
, bcopy
);
324 STUFF_SIG(_COMM_PAGE_MEMCPY
, memmove
);
326 commpage_stuff(_COMM_PAGE_BASE_ADDRESS
+ _COMM_PAGE_SIGS_OFFSET
+ 0x1000, &commpage_sigs_begin
,
327 (uintptr_t)&commpage_sigs_end
- (uintptr_t)&commpage_sigs_begin
);