.section .text.user_wait,"ax" .balign 4 .global __user_task_blob_start __user_task_blob_start: // Parent A and child B run this blob in separate TTBR0 roots. mov x19, x0 movz x20, #0x1000 movk x20, #0x8000, lsl #16 mov x21, #0x55 str x19, [x20] sub sp, sp, #16 str x19, [sp] movz x9, #0xa11a cmp x19, x9 b.eq .Lwait_parent movz x9, #0xb22b cmp x19, x9 b.ne .Lwait_fail b .Lwait_child .Lwait_parent: mov x7, #1 // Self is not a child even if its TaskId is otherwise valid. mov x0, #0 mov x1, #1 mov x8, #16 svc #0x42 movn x9, #9 cmp x0, x9 b.ne .Lwait_fail // A recycled generation cannot stand in for the live child. mov x0, #1 mov x1, #3 mov x8, #16 svc #0x42 movn x9, #9 cmp x0, x9 b.ne .Lwait_fail // Exact child slot=1/generation=2 blocks A and runs B. The same // syscall eventually returns B's single-use exit code 0x2a. mov x0, #1 mov x1, #2 mov x8, #16 svc #0x42 cmp x0, #0x2a b.ne .Lwait_fail cmp x21, #0x55 b.ne .Lwait_fail ldr x9, [x20] cmp x9, x19 b.ne .Lwait_fail ldr x9, [sp] cmp x9, x19 b.ne .Lwait_fail // The child slot was reaped when the blocked wait returned. mov x0, #1 mov x1, #2 mov x8, #16 svc #0x42 movn x9, #9 cmp x0, x9 b.ne .Lwait_fail mov x0, x19 mov x8, #2 svc #0x42 b .Lwait_fail .Lwait_child: mov x7, #1 // B cannot wait on A: correct slot/generation is still foreign. mov x0, #0 mov x1, #1 mov x8, #16 svc #0x42 movn x9, #9 cmp x0, x9 b.ne .Lwait_fail cmp x21, #0x55 b.ne .Lwait_fail ldr x9, [x20] cmp x9, x19 b.ne .Lwait_fail ldr x9, [sp] cmp x9, x19 b.ne .Lwait_fail mov x0, #0x2a mov x8, #2 svc #0x42 .Lwait_fail: brk #0xbad b .Lwait_fail .global __user_task_blob_end __user_task_blob_end: