.section .text.user_handle_death,"ax" .balign 4 .global __user_task_blob_start __user_task_blob_start: // The same code runs under disjoint A/B TTBR0 roots. Preserve task and // private-page sentinels across every exception return and task switch. 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 .Ldeath_a movz x9, #0xb22b cmp x19, x9 b.ne .Ldeath_fail b .Ldeath_b .Ldeath_a: mov x7, #1 mov x0, #3 mov x8, #8 svc #0x42 cmp x0, #1 b.ne .Ldeath_fail mov x22, x0 movz x9, #0x4241 movk x9, #0x4443, lsl #16 str w9, [x20, #16] mov x0, x22 add x1, x20, #16 mov x2, #4 mov x8, #12 svc #0x42 cmp x0, #4 b.ne .Ldeath_fail mov x0, x22 mov x8, #6 svc #0x42 cbnz x0, .Ldeath_fail cmp x22, #1 b.ne .Ldeath_fail cmp x21, #0x55 b.ne .Ldeath_fail ldr x9, [x20] cmp x9, x19 b.ne .Ldeath_fail ldr x9, [sp] cmp x9, x19 b.ne .Ldeath_fail // A deliberately exits with one live channel handle and queued ABCD. mov x0, x19 mov x8, #2 svc #0x42 b .Ldeath_fail .Ldeath_b: mov x7, #1 mov x0, #1 mov x8, #9 svc #0x42 movn x9, #8 cmp x0, x9 b.ne .Ldeath_fail mov x0, #2 mov x8, #8 svc #0x42 cmp x0, #2 b.ne .Ldeath_fail mov x22, x0 mov x8, #6 svc #0x42 cbnz x0, .Ldeath_fail cmp x22, #2 b.ne .Ldeath_fail cmp x21, #0x55 b.ne .Ldeath_fail ldr x9, [x20] cmp x9, x19 b.ne .Ldeath_fail ldr x9, [sp] cmp x9, x19 b.ne .Ldeath_fail // A's exit must revoke its number and free one table slot. B remains // alive and can open a new, monotonically numbered independent handle. mov x0, #1 mov x8, #9 svc #0x42 movn x9, #8 cmp x0, x9 b.ne .Ldeath_fail mov x0, x22 mov x8, #9 svc #0x42 cmp x0, #2 b.ne .Ldeath_fail mov x0, #1 mov x8, #8 svc #0x42 cmp x0, #3 b.ne .Ldeath_fail mov x23, x0 mov x0, x23 mov x8, #9 svc #0x42 cmp x0, #1 b.ne .Ldeath_fail // B also exits without closing either handle. The exit hook owns cleanup. mov x0, x19 mov x8, #2 svc #0x42 .Ldeath_fail: brk #0xbad b .Ldeath_fail .global __user_task_blob_end __user_task_blob_end: