1 | /* |
2 | * Copyright (c) 2003-2012 Apple 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 | |
29 | #ifndef _I386_COMMPAGE_H |
30 | #define _I386_COMMPAGE_H |
31 | |
32 | #ifndef __ASSEMBLER__ |
33 | #include <stdint.h> |
34 | #include <mach/boolean.h> |
35 | #include <mach/vm_types.h> |
36 | #include <machine/cpu_capabilities.h> |
37 | #endif /* __ASSEMBLER__ */ |
38 | |
39 | /* When trying to acquire a spinlock or mutex, we will spin in |
40 | * user mode for awhile, before entering the kernel to relinquish. |
41 | * MP_SPIN_TRIES is the initial value of _COMM_PAGE_SPIN_COUNT. |
42 | * The idea is that _COMM_PAGE_SPIN_COUNT will be adjusted up or |
43 | * down as the machine is plugged in/out, etc. |
44 | * At present spinlocks do not use _COMM_PAGE_SPIN_COUNT. |
45 | * They use MP_SPIN_TRIES directly. |
46 | */ |
47 | #define MP_SPIN_TRIES 1000 |
48 | |
49 | |
50 | /* The following macro is used to generate the 64-bit commpage address for a given |
51 | * routine, based on its 32-bit address. This is used in the kernel to compile |
52 | * the 64-bit commpage. Since the kernel can be a 32-bit object, cpu_capabilities.h |
53 | * only defines the 32-bit address. |
54 | */ |
55 | #define _COMM_PAGE_32_TO_64( ADDRESS ) ( ADDRESS + _COMM_PAGE64_START_ADDRESS - _COMM_PAGE32_START_ADDRESS ) |
56 | |
57 | |
58 | #ifdef __ASSEMBLER__ |
59 | |
60 | #define COMMPAGE_DESCRIPTOR_NAME(label) _commpage_ ## label |
61 | |
62 | #define COMMPAGE_DESCRIPTOR_FIELD_POINTER .quad |
63 | #define COMMPAGE_DESCRIPTOR_REFERENCE(label) \ |
64 | .quad COMMPAGE_DESCRIPTOR_NAME(label) |
65 | |
66 | #define COMMPAGE_FUNCTION_START(label,codetype,alignment) \ |
67 | .text ;\ |
68 | .code ## codetype ;\ |
69 | .align alignment, 0x90 ;\ |
70 | L ## label ## : |
71 | |
72 | #define COMMPAGE_DESCRIPTOR(label,address) \ |
73 | L ## label ## _end: ;\ |
74 | .set L ## label ## _size, L ## label ## _end - L ## label ;\ |
75 | .const_data ;\ |
76 | .private_extern COMMPAGE_DESCRIPTOR_NAME(label) ;\ |
77 | COMMPAGE_DESCRIPTOR_NAME(label) ## : ;\ |
78 | COMMPAGE_DESCRIPTOR_FIELD_POINTER L ## label ;\ |
79 | .long L ## label ## _size ;\ |
80 | .long address ;\ |
81 | .text |
82 | |
83 | |
84 | /* COMMPAGE_CALL(target,from,start) |
85 | * |
86 | * This macro compiles a relative near call to one |
87 | * commpage routine from another. |
88 | * The assembler cannot handle this directly because the code |
89 | * is not being assembled at the address at which it will execute. |
90 | * The alternative to this macro would be to use an |
91 | * indirect call, which is slower because the target of an |
92 | * indirect branch is poorly predicted. |
93 | * The macro arguments are: |
94 | * target = the commpage routine we are calling |
95 | * from = the commpage routine we are in now |
96 | * start = the label at the start of the code for this func |
97 | * This is admitedly ugly and fragile. Is there a better way? |
98 | */ |
99 | #define COMMPAGE_CALL(target,from,start) \ |
100 | COMMPAGE_CALL_INTERNAL(target,from,start,__LINE__) |
101 | |
102 | #define COMMPAGE_CALL_INTERNAL(target,from,start,unique) \ |
103 | .byte 0xe8 ;\ |
104 | .set UNIQUEID(unique), L ## start - . + target - from - 4 ;\ |
105 | .long UNIQUEID(unique) |
106 | |
107 | #define UNIQUEID(name) L ## name |
108 | |
109 | /* COMMPAGE_JMP(target,from,start) |
110 | * |
111 | * This macro perform a jump to another commpage routine. |
112 | * Used to return from the PFZ by jumping via a return outside the PFZ. |
113 | */ |
114 | #define COMMPAGE_JMP(target,from,start) \ |
115 | jmp L ## start - from + target |
116 | |
117 | #else /* __ASSEMBLER__ */ |
118 | |
119 | /* Each potential commpage routine is described by one of these. |
120 | * Note that the COMMPAGE_DESCRIPTOR macro (above), used in |
121 | * assembly language, must agree with this. |
122 | */ |
123 | |
124 | typedef struct commpage_descriptor { |
125 | void *code_address; // address of code |
126 | uint32_t code_length; // length in bytes |
127 | uint32_t commpage_address; // put at this address (_COMM_PAGE_BCOPY etc) |
128 | } commpage_descriptor; |
129 | |
130 | |
131 | /* Warning: following structure must match the layout of the commpage. */ |
132 | /* This is the data starting at _COMM_PAGE_TIME_DATA_START, ie for nanotime() and gettimeofday() */ |
133 | |
134 | typedef volatile struct commpage_time_data { |
135 | uint64_t nt_tsc_base; // _COMM_PAGE_NT_TSC_BASE |
136 | uint32_t nt_scale; // _COMM_PAGE_NT_SCALE |
137 | uint32_t nt_shift; // _COMM_PAGE_NT_SHIFT |
138 | uint64_t nt_ns_base; // _COMM_PAGE_NT_NS_BASE |
139 | uint32_t nt_generation; // _COMM_PAGE_NT_GENERATION |
140 | uint32_t gtod_generation; // _COMM_PAGE_GTOD_GENERATION |
141 | uint64_t gtod_ns_base; // _COMM_PAGE_GTOD_NS_BASE |
142 | uint64_t gtod_sec_base; // _COMM_PAGE_GTOD_SEC_BASE |
143 | } commpage_time_data; |
144 | |
145 | extern char *commPagePtr32; // virt address of 32-bit commpage in kernel map |
146 | extern char *commPagePtr64; // ...and of 64-bit commpage |
147 | |
148 | extern void commpage_set_timestamp(uint64_t abstime, uint64_t sec, uint64_t frac, uint64_t scale, uint64_t tick_per_sec); |
149 | #define commpage_disable_timestamp() commpage_set_timestamp( 0, 0, 0, 0, 0 ); |
150 | extern void commpage_set_nanotime(uint64_t tsc_base, uint64_t ns_base, uint32_t scale, uint32_t shift); |
151 | extern void commpage_set_memory_pressure(unsigned int pressure); |
152 | extern void commpage_set_spin_count(unsigned int count); |
153 | extern void commpage_sched_gen_inc(void); |
154 | extern void commpage_update_active_cpus(void); |
155 | extern void commpage_update_mach_approximate_time(uint64_t abstime); |
156 | extern void commpage_update_mach_continuous_time(uint64_t sleeptime); |
157 | extern void commpage_update_boottime(uint64_t boottime_usec); |
158 | extern void commpage_update_kdebug_state(void); |
159 | extern void commpage_update_atm_diagnostic_config(uint32_t); |
160 | |
161 | extern uint32_t commpage_is_in_pfz32(uint32_t); |
162 | extern uint32_t commpage_is_in_pfz64(addr64_t); |
163 | |
164 | #endif /* __ASSEMBLER__ */ |
165 | |
166 | #endif /* _I386_COMMPAGE_H */ |
167 | |