Skip to content

Commit b6dd9cd

Browse files
committed
1 parent 24cfb5c commit b6dd9cd

39 files changed

+1038
-659
lines changed

kern/kern_support.c

Lines changed: 108 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,18 @@ lck_attr_t *pthread_lck_attr;
122122

123123
#define C_32_STK_ALIGN 16
124124
#define C_64_STK_ALIGN 16
125-
#define C_64_REDZONE_LEN 128
126125

127126
// WORKQ use the largest alignment any platform needs
128127
#define C_WORKQ_STK_ALIGN 16
129128

129+
#if defined(__arm64__)
130+
/* Pull the pthread_t into the same page as the top of the stack so we dirty one less page.
131+
* <rdar://problem/19941744> The _pthread struct at the top of the stack shouldn't be page-aligned
132+
*/
133+
#define PTHREAD_T_OFFSET (12*1024)
134+
#else
130135
#define PTHREAD_T_OFFSET 0
136+
#endif
131137

132138
/*
133139
* Flags filed passed to bsdthread_create and back in pthread_start
@@ -169,11 +175,13 @@ stack_addr_hint(proc_t p, vm_map_t vmap)
169175
mach_vm_offset_t stackaddr;
170176
mach_vm_offset_t aslr_offset;
171177
bool proc64bit = proc_is64bit(p);
178+
bool proc64bit_data = proc_is64bit_data(p);
172179

173180
// We can't safely take random values % something unless its a power-of-two
174181
_Static_assert(powerof2(PTH_DEFAULT_STACKSIZE), "PTH_DEFAULT_STACKSIZE is a power-of-two");
175182

176183
#if defined(__i386__) || defined(__x86_64__)
184+
(void)proc64bit_data;
177185
if (proc64bit) {
178186
// Matches vm_map_get_max_aslr_slide_pages's image shift in xnu
179187
aslr_offset = random() % (1 << 28); // about 512 stacks
@@ -211,7 +219,13 @@ stack_addr_hint(proc_t p, vm_map_t vmap)
211219
stackaddr = SHARED_REGION_BASE_ARM64 - 64 * PTH_DEFAULT_STACKSIZE - aslr_offset;
212220
} else {
213221
// If you try to slide down from this point, you risk ending up in memory consumed by malloc
214-
stackaddr = SHARED_REGION_BASE_ARM - 32 * PTH_DEFAULT_STACKSIZE + aslr_offset;
222+
if (proc64bit_data) {
223+
stackaddr = SHARED_REGION_BASE_ARM64_32;
224+
} else {
225+
stackaddr = SHARED_REGION_BASE_ARM;
226+
}
227+
228+
stackaddr -= 32 * PTH_DEFAULT_STACKSIZE + aslr_offset;
215229
}
216230
}
217231
#else
@@ -308,7 +322,7 @@ _bsdthread_create(struct proc *p,
308322
.r8 = (uint64_t)user_stack, /* golang wants this */
309323
.r9 = (uint64_t)flags,
310324

311-
.rsp = (uint64_t)(user_stack - C_64_REDZONE_LEN)
325+
.rsp = (uint64_t)user_stack,
312326
};
313327

314328
(void)pthread_kern->thread_set_wq_state64(th, (thread_state_t)&state);
@@ -322,7 +336,41 @@ _bsdthread_create(struct proc *p,
322336
.edi = (uint32_t)user_stack, /* golang wants this */
323337
.esi = (uint32_t)flags,
324338

325-
.esp = (int)((vm_offset_t)(user_stack - C_32_STK_ALIGN))
339+
.esp = (uint32_t)user_stack,
340+
};
341+
342+
(void)pthread_kern->thread_set_wq_state32(th, (thread_state_t)&state);
343+
}
344+
#elif defined(__arm__) || defined(__arm64__)
345+
if (proc_is64bit_data(p)) {
346+
#ifdef __arm64__
347+
arm_thread_state64_t state = {
348+
.pc = (uint64_t)pthread_kern->proc_get_threadstart(p),
349+
.x[0] = (uint64_t)user_pthread,
350+
.x[1] = (uint64_t)th_thport,
351+
.x[2] = (uint64_t)user_func, /* golang wants this */
352+
.x[3] = (uint64_t)user_funcarg, /* golang wants this */
353+
.x[4] = (uint64_t)user_stack, /* golang wants this */
354+
.x[5] = (uint64_t)flags,
355+
356+
.sp = (uint64_t)user_stack,
357+
};
358+
359+
(void)pthread_kern->thread_set_wq_state64(th, (thread_state_t)&state);
360+
#else
361+
panic("Shouldn't have a 64-bit thread on a 32-bit kernel...");
362+
#endif // defined(__arm64__)
363+
} else {
364+
arm_thread_state_t state = {
365+
.pc = (uint32_t)pthread_kern->proc_get_threadstart(p),
366+
.r[0] = (uint32_t)user_pthread,
367+
.r[1] = (uint32_t)th_thport,
368+
.r[2] = (uint32_t)user_func, /* golang wants this */
369+
.r[3] = (uint32_t)user_funcarg, /* golang wants this */
370+
.r[4] = (uint32_t)user_stack, /* golang wants this */
371+
.r[5] = (uint32_t)flags,
372+
373+
.sp = (uint32_t)user_stack,
326374
};
327375

328376
(void)pthread_kern->thread_set_wq_state32(th, (thread_state_t)&state);
@@ -755,63 +803,77 @@ workq_set_register_state(proc_t p, thread_t th,
755803
panic(__func__ ": thread_set_wq_state failed: %d", error);
756804
}
757805
}
806+
#elif defined(__arm__) || defined(__arm64__)
807+
if (!proc_is64bit_data(p)) {
808+
arm_thread_state_t state = {
809+
.pc = (int)wqstart_fnptr,
810+
.r[0] = (unsigned int)addrs->self,
811+
.r[1] = (unsigned int)kport,
812+
.r[2] = (unsigned int)addrs->stack_bottom,
813+
.r[3] = (unsigned int)kevent_list,
814+
// will be pushed onto the stack as arg4/5
815+
.r[4] = (unsigned int)upcall_flags,
816+
.r[5] = (unsigned int)kevent_count,
817+
818+
.sp = (int)(addrs->stack_top)
819+
};
820+
821+
int error = pthread_kern->thread_set_wq_state32(th, (thread_state_t)&state);
822+
if (error != KERN_SUCCESS) {
823+
panic(__func__ ": thread_set_wq_state failed: %d", error);
824+
}
825+
} else {
826+
#if defined(__arm64__)
827+
arm_thread_state64_t state = {
828+
.pc = (uint64_t)wqstart_fnptr,
829+
.x[0] = (uint64_t)addrs->self,
830+
.x[1] = (uint64_t)kport,
831+
.x[2] = (uint64_t)addrs->stack_bottom,
832+
.x[3] = (uint64_t)kevent_list,
833+
.x[4] = (uint64_t)upcall_flags,
834+
.x[5] = (uint64_t)kevent_count,
835+
836+
.sp = (uint64_t)((vm_offset_t)addrs->stack_top),
837+
};
838+
839+
int error = pthread_kern->thread_set_wq_state64(th, (thread_state_t)&state);
840+
if (error != KERN_SUCCESS) {
841+
panic(__func__ ": thread_set_wq_state failed: %d", error);
842+
}
843+
#else /* defined(__arm64__) */
844+
panic("Shouldn't have a 64-bit thread on a 32-bit kernel...");
845+
#endif /* defined(__arm64__) */
846+
}
758847
#else
759848
#error setup_wqthread not defined for this architecture
760849
#endif
761850
}
762851

763-
static int
764-
workq_kevent(proc_t p, struct workq_thread_addrs *th_addrs, int upcall_flags,
852+
static inline int
853+
workq_kevent(proc_t p, struct workq_thread_addrs *th_addrs,
765854
user_addr_t eventlist, int nevents, int kevent_flags,
766855
user_addr_t *kevent_list_out, int *kevent_count_out)
767856
{
768-
bool workloop = upcall_flags & WQ_FLAG_THREAD_WORKLOOP;
769-
int kevent_count = WQ_KEVENT_LIST_LEN;
770-
user_addr_t kevent_list = th_addrs->self - WQ_KEVENT_LIST_LEN * sizeof(struct kevent_qos_s);
771-
user_addr_t kevent_id_addr = kevent_list;
772-
kqueue_id_t kevent_id = -1;
773857
int ret;
774858

775-
if (workloop) {
776-
/*
777-
* The kevent ID goes just below the kevent list. Sufficiently new
778-
* userspace will know to look there. Old userspace will just
779-
* ignore it.
780-
*/
781-
kevent_id_addr -= sizeof(kqueue_id_t);
782-
}
859+
user_addr_t kevent_list = th_addrs->self -
860+
WQ_KEVENT_LIST_LEN * sizeof(struct kevent_qos_s);
861+
user_addr_t data_buf = kevent_list - WQ_KEVENT_DATA_SIZE;
862+
user_size_t data_available = WQ_KEVENT_DATA_SIZE;
783863

784-
user_addr_t kevent_data_buf = kevent_id_addr - WQ_KEVENT_DATA_SIZE;
785-
user_size_t kevent_data_available = WQ_KEVENT_DATA_SIZE;
786-
787-
if (workloop) {
788-
kevent_flags |= KEVENT_FLAG_WORKLOOP;
789-
ret = kevent_id_internal(p, &kevent_id,
790-
eventlist, nevents, kevent_list, kevent_count,
791-
kevent_data_buf, &kevent_data_available,
792-
kevent_flags, &kevent_count);
793-
copyout(&kevent_id, kevent_id_addr, sizeof(kevent_id));
794-
} else {
795-
kevent_flags |= KEVENT_FLAG_WORKQ;
796-
ret = kevent_qos_internal(p, -1, eventlist, nevents, kevent_list,
797-
kevent_count, kevent_data_buf, &kevent_data_available,
798-
kevent_flags, &kevent_count);
799-
}
864+
ret = pthread_kern->kevent_workq_internal(p, eventlist, nevents,
865+
kevent_list, WQ_KEVENT_LIST_LEN,
866+
data_buf, &data_available,
867+
kevent_flags, kevent_count_out);
800868

801869
// squash any errors into just empty output
802-
if (ret != 0 || kevent_count == -1) {
870+
if (ret != 0 || *kevent_count_out == -1) {
803871
*kevent_list_out = NULL;
804872
*kevent_count_out = 0;
805873
return ret;
806874
}
807875

808-
if (kevent_data_available == WQ_KEVENT_DATA_SIZE) {
809-
workq_thread_set_top_addr(th_addrs, kevent_id_addr);
810-
} else {
811-
workq_thread_set_top_addr(th_addrs,
812-
kevent_data_buf + kevent_data_available);
813-
}
814-
*kevent_count_out = kevent_count;
876+
workq_thread_set_top_addr(th_addrs, data_buf + data_available);
815877
*kevent_list_out = kevent_list;
816878
return ret;
817879
}
@@ -833,7 +895,7 @@ workq_kevent(proc_t p, struct workq_thread_addrs *th_addrs, int upcall_flags,
833895
* |pthread_t | th_stackaddr + DEFAULT_STACKSIZE + guardsize + PTHREAD_STACK_OFFSET
834896
* |kevent list| optionally - at most WQ_KEVENT_LIST_LEN events
835897
* |kevent data| optionally - at most WQ_KEVENT_DATA_SIZE bytes
836-
* |stack gap | bottom aligned to 16 bytes, and at least as big as stack_gap_min
898+
* |stack gap | bottom aligned to 16 bytes
837899
* | STACK |
838900
* | ⇓ |
839901
* | |
@@ -880,8 +942,7 @@ workq_setup_thread(proc_t p, thread_t th, vm_map_t map, user_addr_t stackaddr,
880942
kevent_count = WORKQ_EXIT_THREAD_NKEVENT;
881943
} else if (upcall_flags & WQ_FLAG_THREAD_KEVENT) {
882944
unsigned int flags = KEVENT_FLAG_STACK_DATA | KEVENT_FLAG_IMMEDIATE;
883-
workq_kevent(p, &th_addrs, upcall_flags, NULL, 0, flags,
884-
&kevent_list, &kevent_count);
945+
workq_kevent(p, &th_addrs, NULL, 0, flags, &kevent_list, &kevent_count);
885946
}
886947

887948
workq_set_register_state(p, th, &th_addrs, kport,
@@ -909,7 +970,7 @@ workq_handle_stack_events(proc_t p, thread_t th, vm_map_t map,
909970

910971
unsigned int flags = KEVENT_FLAG_STACK_DATA | KEVENT_FLAG_IMMEDIATE |
911972
KEVENT_FLAG_PARKING;
912-
error = workq_kevent(p, &th_addrs, upcall_flags, events, nevents, flags,
973+
error = workq_kevent(p, &th_addrs, events, nevents, flags,
913974
&kevent_list, &kevent_count);
914975

915976
if (error || kevent_count == 0) {

kern/kern_synch.c

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ _kwq_use_turnstile(ksyn_wait_queue_t kwq)
246246
#define KW_UNLOCK_PREPOST_READLOCK 0x08
247247
#define KW_UNLOCK_PREPOST_WRLOCK 0x20
248248

249-
static int ksyn_wq_hash_lookup(user_addr_t uaddr, proc_t p, int flags, ksyn_wait_queue_t *kwq, struct pthhashhead **hashptr, uint64_t *object, uint64_t *offset);
249+
static int ksyn_wq_hash_lookup(user_addr_t uaddr, proc_t p, int flags, ksyn_wait_queue_t *kwq, struct pthhashhead **hashptr, uint64_t object, uint64_t offset);
250250
static int ksyn_wqfind(user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint32_t rw_wc, int flags, int wqtype , ksyn_wait_queue_t *wq);
251251
static void ksyn_wqrelease(ksyn_wait_queue_t mkwq, int qfreenow, int wqtype);
252252
static int ksyn_findobj(user_addr_t uaddr, uint64_t *objectp, uint64_t *offsetp);
@@ -509,7 +509,7 @@ _kwq_handle_interrupted_wakeup(ksyn_wait_queue_t kwq, kwq_intr_type_t type,
509509
static void
510510
pthread_list_lock(void)
511511
{
512-
lck_mtx_lock(pthread_list_mlock);
512+
lck_mtx_lock_spin(pthread_list_mlock);
513513
}
514514

515515
static void
@@ -1553,23 +1553,17 @@ _pth_proc_hashinit(proc_t p)
15531553
static int
15541554
ksyn_wq_hash_lookup(user_addr_t uaddr, proc_t p, int flags,
15551555
ksyn_wait_queue_t *out_kwq, struct pthhashhead **out_hashptr,
1556-
uint64_t *out_object, uint64_t *out_offset)
1556+
uint64_t object, uint64_t offset)
15571557
{
15581558
int res = 0;
15591559
ksyn_wait_queue_t kwq;
1560-
uint64_t object = 0, offset = 0;
15611560
struct pthhashhead *hashptr;
15621561
if ((flags & PTHREAD_PSHARED_FLAGS_MASK) == PTHREAD_PROCESS_SHARED) {
15631562
hashptr = pth_glob_hashtbl;
1564-
res = ksyn_findobj(uaddr, &object, &offset);
1565-
if (res == 0) {
1566-
LIST_FOREACH(kwq, &hashptr[object & pthhash], kw_hash) {
1567-
if (kwq->kw_object == object && kwq->kw_offset == offset) {
1568-
break;
1569-
}
1563+
LIST_FOREACH(kwq, &hashptr[object & pthhash], kw_hash) {
1564+
if (kwq->kw_object == object && kwq->kw_offset == offset) {
1565+
break;
15701566
}
1571-
} else {
1572-
kwq = NULL;
15731567
}
15741568
} else {
15751569
hashptr = pthread_kern->proc_get_pthhash(p);
@@ -1580,8 +1574,6 @@ ksyn_wq_hash_lookup(user_addr_t uaddr, proc_t p, int flags,
15801574
}
15811575
}
15821576
*out_kwq = kwq;
1583-
*out_object = object;
1584-
*out_offset = offset;
15851577
*out_hashptr = hashptr;
15861578
return res;
15871579
}
@@ -1692,7 +1684,7 @@ ksyn_wqfind(user_addr_t uaddr, uint32_t mgen, uint32_t ugen, uint32_t sgen,
16921684
while (res == 0) {
16931685
pthread_list_lock();
16941686
res = ksyn_wq_hash_lookup(uaddr, current_proc(), flags, &kwq, &hashptr,
1695-
&object, &offset);
1687+
object, offset);
16961688
if (res != 0) {
16971689
pthread_list_unlock();
16981690
break;

0 commit comments

Comments
 (0)