1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <err.h>
8 #include <new>
9 #include <platform.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <trace.h>
15 
16 #include <dev/interrupt.h>
17 #include <dev/iommu.h>
18 #include <dev/udisplay.h>
19 #include <fbl/auto_call.h>
20 #include <fbl/inline_array.h>
21 #include <lib/user_copy/user_ptr.h>
22 #include <object/bus_transaction_initiator_dispatcher.h>
23 #include <object/handle.h>
24 #include <object/interrupt_dispatcher.h>
25 #include <object/interrupt_event_dispatcher.h>
26 #include <object/iommu_dispatcher.h>
27 #include <object/process_dispatcher.h>
28 #include <object/resource.h>
29 #include <object/vcpu_dispatcher.h>
30 #include <object/virtual_interrupt_dispatcher.h>
31 #include <object/vm_object_dispatcher.h>
32 #include <vm/vm.h>
33 #include <vm/vm_object_paged.h>
34 #include <vm/vm_object_physical.h>
35 #include <zircon/syscalls/iommu.h>
36 #include <zircon/syscalls/pci.h>
37 #include <zircon/syscalls/smc.h>
38 
39 #if ARCH_X86
40 #include <platform/pc/bootloader.h>
41 #endif
42 
43 #include "ddk_priv.h"
44 #include "priv.h"
45 
46 #define LOCAL_TRACE 0
47 
48 // zx_status_t zx_vmo_create_contiguous
sys_vmo_create_contiguous(zx_handle_t bti,size_t size,uint32_t alignment_log2,user_out_handle * out)49 zx_status_t sys_vmo_create_contiguous(zx_handle_t bti, size_t size, uint32_t alignment_log2,
50                                       user_out_handle* out) {
51     LTRACEF("size 0x%zu\n", size);
52 
53     if (size == 0) {
54         return ZX_ERR_INVALID_ARGS;
55     }
56 
57     if (alignment_log2 == 0) {
58         alignment_log2 = PAGE_SIZE_SHIFT;
59     }
60     // catch obviously wrong values
61     if (alignment_log2 < PAGE_SIZE_SHIFT || alignment_log2 >= (8 * sizeof(uint64_t))) {
62         return ZX_ERR_INVALID_ARGS;
63     }
64 
65     auto up = ProcessDispatcher::GetCurrent();
66     fbl::RefPtr<BusTransactionInitiatorDispatcher> bti_dispatcher;
67     zx_status_t status = up->GetDispatcherWithRights(bti, ZX_RIGHT_MAP, &bti_dispatcher);
68     if (status != ZX_OK) {
69         return status;
70     }
71 
72     auto align_log2_arg = static_cast<uint8_t>(alignment_log2);
73 
74     // create a vm object
75     fbl::RefPtr<VmObject> vmo;
76     status = VmObjectPaged::CreateContiguous(PMM_ALLOC_FLAG_ANY, size, align_log2_arg, &vmo);
77     if (status != ZX_OK) {
78         return status;
79     }
80 
81     // create a Vm Object dispatcher
82     fbl::RefPtr<Dispatcher> dispatcher;
83     zx_rights_t rights;
84     zx_status_t result = VmObjectDispatcher::Create(ktl::move(vmo), &dispatcher, &rights);
85     if (result != ZX_OK) {
86         return result;
87     }
88 
89     // create a handle and attach the dispatcher to it
90     return out->make(ktl::move(dispatcher), rights);
91 }
92 
93 // zx_status_t zx_vmo_create_physical
sys_vmo_create_physical(zx_handle_t hrsrc,zx_paddr_t paddr,size_t size,user_out_handle * out)94 zx_status_t sys_vmo_create_physical(zx_handle_t hrsrc, zx_paddr_t paddr, size_t size,
95                                     user_out_handle* out) {
96     LTRACEF("size 0x%zu\n", size);
97 
98     // Memory should be subtracted from the PhysicalAspace allocators, so it's
99     // safe to assume that if the caller has access to a resource for this specified
100     // region of MMIO space then it is safe to allow the vmo to be created.
101     zx_status_t status;
102     if ((status = validate_resource_mmio(hrsrc, paddr, size)) != ZX_OK) {
103         return status;
104     }
105 
106     size = ROUNDUP_PAGE_SIZE(size);
107 
108     // create a vm object
109     fbl::RefPtr<VmObject> vmo;
110     zx_status_t result = VmObjectPhysical::Create(paddr, size, &vmo);
111     if (result != ZX_OK) {
112         return result;
113     }
114 
115     // create a Vm Object dispatcher
116     fbl::RefPtr<Dispatcher> dispatcher;
117     zx_rights_t rights;
118     result = VmObjectDispatcher::Create(ktl::move(vmo), &dispatcher, &rights);
119     if (result != ZX_OK) {
120         return result;
121     }
122 
123     // create a handle and attach the dispatcher to it
124     return out->make(ktl::move(dispatcher), rights);
125 }
126 
127 // zx_status_t zx_framebuffer_get_info
sys_framebuffer_get_info(zx_handle_t handle,user_out_ptr<uint32_t> format,user_out_ptr<uint32_t> width,user_out_ptr<uint32_t> height,user_out_ptr<uint32_t> stride)128 zx_status_t sys_framebuffer_get_info(zx_handle_t handle, user_out_ptr<uint32_t> format,
129                                      user_out_ptr<uint32_t> width, user_out_ptr<uint32_t> height,
130                                      user_out_ptr<uint32_t> stride) {
131     zx_status_t status;
132     if ((status = validate_resource(handle, ZX_RSRC_KIND_ROOT)) < 0)
133         return status;
134 #if ARCH_X86
135     if (!bootloader.fb.base)
136         return ZX_ERR_INVALID_ARGS;
137     status = format.copy_to_user(bootloader.fb.format);
138     if (status != ZX_OK)
139         return status;
140     status = width.copy_to_user(bootloader.fb.width);
141     if (status != ZX_OK)
142         return status;
143     status = height.copy_to_user(bootloader.fb.height);
144     if (status != ZX_OK)
145         return status;
146     status = stride.copy_to_user(bootloader.fb.stride);
147     if (status != ZX_OK)
148         return status;
149     return ZX_OK;
150 #else
151     return ZX_ERR_NOT_SUPPORTED;
152 #endif
153 }
154 
155 // zx_status_t zx_framebuffer_set_range
sys_framebuffer_set_range(zx_handle_t hrsrc,zx_handle_t vmo_handle,uint32_t len,uint32_t format,uint32_t width,uint32_t height,uint32_t stride)156 zx_status_t sys_framebuffer_set_range(zx_handle_t hrsrc, zx_handle_t vmo_handle, uint32_t len, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) {
157     zx_status_t status;
158     if ((status = validate_resource(hrsrc, ZX_RSRC_KIND_ROOT)) < 0)
159         return status;
160 
161     if (vmo_handle == ZX_HANDLE_INVALID) {
162         udisplay_clear_framebuffer_vmo();
163         return ZX_OK;
164     }
165 
166     auto up = ProcessDispatcher::GetCurrent();
167 
168     // lookup the dispatcher from handle
169     fbl::RefPtr<VmObjectDispatcher> vmo;
170     status = up->GetDispatcher(vmo_handle, &vmo);
171     if (status != ZX_OK)
172         return status;
173 
174     status = udisplay_set_framebuffer(vmo->vmo());
175     if (status != ZX_OK)
176         return status;
177 
178     struct display_info di;
179     memset(&di, 0, sizeof(struct display_info));
180     di.format = format;
181     di.width = width;
182     di.height = height;
183     di.stride = stride;
184     di.flags = DISPLAY_FLAG_HW_FRAMEBUFFER;
185     udisplay_set_display_info(&di);
186 
187     return ZX_OK;
188 }
189 
190 // zx_status_t zx_iommu_create
sys_iommu_create(zx_handle_t resource,uint32_t type,user_in_ptr<const void> desc,size_t desc_size,user_out_handle * out)191 zx_status_t sys_iommu_create(zx_handle_t resource, uint32_t type,
192                              user_in_ptr<const void> desc, size_t desc_size,
193                              user_out_handle* out) {
194     // TODO: finer grained validation
195     zx_status_t status;
196     if ((status = validate_resource(resource, ZX_RSRC_KIND_ROOT)) < 0) {
197         return status;
198     }
199 
200     if (desc_size > ZX_IOMMU_MAX_DESC_LEN) {
201         return ZX_ERR_INVALID_ARGS;
202     }
203 
204     fbl::RefPtr<Dispatcher> dispatcher;
205     zx_rights_t rights;
206 
207     {
208         // Copy the descriptor into the kernel and try to create the dispatcher
209         // using it.
210         fbl::AllocChecker ac;
211         ktl::unique_ptr<uint8_t[]> copied_desc(new (&ac) uint8_t[desc_size]);
212         if (!ac.check()) {
213             return ZX_ERR_NO_MEMORY;
214         }
215         if ((status = desc.copy_array_from_user(copied_desc.get(), desc_size)) != ZX_OK) {
216             return status;
217         }
218         status = IommuDispatcher::Create(type,
219                                          ktl::unique_ptr<const uint8_t[]>(copied_desc.release()),
220                                          desc_size, &dispatcher, &rights);
221         if (status != ZX_OK) {
222             return status;
223         }
224     }
225 
226     return out->make(ktl::move(dispatcher), rights);
227 }
228 
229 #if ARCH_X86
230 #include <arch/x86/descriptor.h>
231 #include <arch/x86/ioport.h>
232 
233 // zx_status_t zx_ioports_request
sys_ioports_request(zx_handle_t hrsrc,uint16_t io_addr,uint32_t len)234 zx_status_t sys_ioports_request(zx_handle_t hrsrc, uint16_t io_addr, uint32_t len) {
235     zx_status_t status;
236     if ((status = validate_resource_ioport(hrsrc, io_addr, len)) != ZX_OK) {
237         return status;
238     }
239 
240     LTRACEF("addr 0x%x len 0x%x\n", io_addr, len);
241 
242     return IoBitmap::GetCurrent().SetIoBitmap(io_addr, len, 1);
243 }
244 #else
245 // zx_status_t zx_ioports_request
sys_ioports_request(zx_handle_t hrsrc,uint16_t io_addr,uint32_t len)246 zx_status_t sys_ioports_request(zx_handle_t hrsrc, uint16_t io_addr, uint32_t len) {
247     // doesn't make sense on non-x86
248     return ZX_ERR_NOT_SUPPORTED;
249 }
250 #endif
251 
252 // zx_status_t zx_pc_firmware_tables
sys_pc_firmware_tables(zx_handle_t hrsrc,user_out_ptr<zx_paddr_t> acpi_rsdp,user_out_ptr<zx_paddr_t> smbios)253 zx_status_t sys_pc_firmware_tables(zx_handle_t hrsrc, user_out_ptr<zx_paddr_t> acpi_rsdp,
254                                    user_out_ptr<zx_paddr_t> smbios) {
255     // TODO(ZX-971): finer grained validation
256     zx_status_t status;
257     if ((status = validate_resource(hrsrc, ZX_RSRC_KIND_ROOT)) < 0) {
258         return status;
259     }
260 #if ARCH_X86
261     if ((status = acpi_rsdp.copy_to_user(bootloader.acpi_rsdp)) != ZX_OK) {
262         return status;
263     }
264     if ((status = smbios.copy_to_user(bootloader.smbios)) != ZX_OK) {
265         return status;
266     }
267 
268     return ZX_OK;
269 #endif
270     return ZX_ERR_NOT_SUPPORTED;
271 }
272 
273 // zx_status_t zx_bti_create
sys_bti_create(zx_handle_t iommu,uint32_t options,uint64_t bti_id,user_out_handle * out)274 zx_status_t sys_bti_create(zx_handle_t iommu, uint32_t options, uint64_t bti_id,
275                            user_out_handle* out) {
276     auto up = ProcessDispatcher::GetCurrent();
277 
278     if (options != 0) {
279         return ZX_ERR_INVALID_ARGS;
280     }
281 
282     fbl::RefPtr<IommuDispatcher> iommu_dispatcher;
283     // TODO(teisenbe): This should probably have a right on it.
284     zx_status_t status = up->GetDispatcherWithRights(iommu, ZX_RIGHT_NONE, &iommu_dispatcher);
285     if (status != ZX_OK) {
286         return status;
287     }
288 
289     fbl::RefPtr<Dispatcher> dispatcher;
290     zx_rights_t rights;
291     // TODO(teisenbe): Migrate BusTransactionInitiatorDispatcher::Create to
292     // taking the iommu_dispatcher
293     status = BusTransactionInitiatorDispatcher::Create(iommu_dispatcher->iommu(), bti_id,
294                                                        &dispatcher, &rights);
295     if (status != ZX_OK) {
296         return status;
297     }
298 
299     return out->make(ktl::move(dispatcher), rights);
300 }
301 
302 // zx_status_t zx_bti_pin
sys_bti_pin(zx_handle_t handle,uint32_t options,zx_handle_t vmo,uint64_t offset,uint64_t size,user_out_ptr<zx_paddr_t> addrs,size_t addrs_count,user_out_handle * pmt)303 zx_status_t sys_bti_pin(zx_handle_t handle, uint32_t options, zx_handle_t vmo, uint64_t offset,
304                         uint64_t size, user_out_ptr<zx_paddr_t> addrs, size_t addrs_count,
305                         user_out_handle* pmt) {
306     auto up = ProcessDispatcher::GetCurrent();
307     fbl::RefPtr<BusTransactionInitiatorDispatcher> bti_dispatcher;
308     zx_status_t status = up->GetDispatcherWithRights(handle, ZX_RIGHT_MAP, &bti_dispatcher);
309     if (status != ZX_OK) {
310         return status;
311     }
312 
313     if (!IS_PAGE_ALIGNED(offset) || !IS_PAGE_ALIGNED(size)) {
314         return ZX_ERR_INVALID_ARGS;
315     }
316 
317     fbl::RefPtr<VmObjectDispatcher> vmo_dispatcher;
318     zx_rights_t vmo_rights;
319     status = up->GetDispatcherAndRights(vmo, &vmo_dispatcher, &vmo_rights);
320     if (status != ZX_OK) {
321         return status;
322     }
323     if (!(vmo_rights & ZX_RIGHT_MAP)) {
324         return ZX_ERR_ACCESS_DENIED;
325     }
326 
327     // Convert requested permissions and check against VMO rights
328     uint32_t iommu_perms = 0;
329     bool compress_results = false;
330     bool contiguous = false;
331     if (options & ZX_BTI_PERM_READ) {
332         if (!(vmo_rights & ZX_RIGHT_READ)) {
333             return ZX_ERR_ACCESS_DENIED;
334         }
335         iommu_perms |= IOMMU_FLAG_PERM_READ;
336         options &= ~ZX_BTI_PERM_READ;
337     }
338     if (options & ZX_BTI_PERM_WRITE) {
339         if (!(vmo_rights & ZX_RIGHT_WRITE)) {
340             return ZX_ERR_ACCESS_DENIED;
341         }
342         iommu_perms |= IOMMU_FLAG_PERM_WRITE;
343         options &= ~ZX_BTI_PERM_WRITE;
344     }
345     if (options & ZX_BTI_PERM_EXECUTE) {
346         // Note: We check ZX_RIGHT_READ instead of ZX_RIGHT_EXECUTE
347         // here because the latter applies to execute permission of
348         // the host CPU, whereas ZX_BTI_PERM_EXECUTE applies to
349         // transactions initiated by the bus device.
350         if (!(vmo_rights & ZX_RIGHT_READ)) {
351             return ZX_ERR_ACCESS_DENIED;
352         }
353         iommu_perms |= IOMMU_FLAG_PERM_EXECUTE;
354         options &= ~ZX_BTI_PERM_EXECUTE;
355     }
356     if (!((options & ZX_BTI_COMPRESS) && (options & ZX_BTI_CONTIGUOUS))) {
357         if (options & ZX_BTI_COMPRESS) {
358             compress_results = true;
359             options &= ~ZX_BTI_COMPRESS;
360         }
361         if (options & ZX_BTI_CONTIGUOUS && vmo_dispatcher->vmo()->is_contiguous()) {
362             contiguous = true;
363             options &= ~ZX_BTI_CONTIGUOUS;
364         }
365     }
366     if (options) {
367         return ZX_ERR_INVALID_ARGS;
368     }
369 
370     constexpr size_t kAddrsLenLimitForStack = 4;
371     fbl::AllocChecker ac;
372     fbl::InlineArray<dev_vaddr_t, kAddrsLenLimitForStack> mapped_addrs(&ac, addrs_count);
373     if (!ac.check()) {
374         return ZX_ERR_NO_MEMORY;
375     }
376 
377     fbl::RefPtr<Dispatcher> new_pmt;
378     zx_rights_t new_pmt_rights;
379     status = bti_dispatcher->Pin(vmo_dispatcher->vmo(), offset, size, iommu_perms, &new_pmt,
380                                  &new_pmt_rights);
381     if (status != ZX_OK) {
382         return status;
383     }
384 
385     status = static_cast<PinnedMemoryTokenDispatcher*>(new_pmt.get())
386                  ->EncodeAddrs(compress_results, contiguous, mapped_addrs.get(), addrs_count);
387     if (status != ZX_OK) {
388         return status;
389     }
390 
391     static_assert(sizeof(dev_vaddr_t) == sizeof(zx_paddr_t), "mismatched types");
392     if ((status = addrs.copy_array_to_user(mapped_addrs.get(), addrs_count)) != ZX_OK) {
393         return status;
394     }
395 
396     return pmt->make(ktl::move(new_pmt), new_pmt_rights);
397 }
398 
399 // zx_status_t zx_bti_release_quarantine
sys_bti_release_quarantine(zx_handle_t handle)400 zx_status_t sys_bti_release_quarantine(zx_handle_t handle) {
401     auto up = ProcessDispatcher::GetCurrent();
402     fbl::RefPtr<BusTransactionInitiatorDispatcher> bti_dispatcher;
403 
404     zx_status_t status = up->GetDispatcherWithRights(handle, ZX_RIGHT_WRITE, &bti_dispatcher);
405     if (status != ZX_OK) {
406         return status;
407     }
408 
409     bti_dispatcher->ReleaseQuarantine();
410     return ZX_OK;
411 }
412 
413 // Having a single-purpose syscall like this is a bit of an anti-pattern in our
414 // syscall API, but we feel there is benefit in this over trying to extend the
415 // semantics of handle closing in sys_handle_close and process death.  In
416 // particular, PMTs are the only objects in the system that track the lifetime
417 // of something external to the process model (external hardware DMA
418 // capabilities).
419 // zx_status_t zx_pmt_unpin
sys_pmt_unpin(zx_handle_t handle)420 zx_status_t sys_pmt_unpin(zx_handle_t handle) {
421     auto up = ProcessDispatcher::GetCurrent();
422 
423     HandleOwner handle_owner = up->RemoveHandle(handle);
424     if (!handle_owner)
425         return ZX_ERR_BAD_HANDLE;
426     fbl::RefPtr<Dispatcher> dispatcher = handle_owner->dispatcher();
427     auto pmt_dispatcher = DownCastDispatcher<PinnedMemoryTokenDispatcher>(&dispatcher);
428     if (!pmt_dispatcher)
429         return ZX_ERR_WRONG_TYPE;
430 
431     pmt_dispatcher->MarkUnpinned();
432 
433     return ZX_OK;
434 }
435 
436 // zx_status_t zx_interrupt_create
sys_interrupt_create(zx_handle_t src_obj,uint32_t src_num,uint32_t options,user_out_handle * out_handle)437 zx_status_t sys_interrupt_create(zx_handle_t src_obj, uint32_t src_num,
438                                  uint32_t options, user_out_handle* out_handle) {
439     LTRACEF("options 0x%x\n", options);
440 
441     // resource not required for virtual interrupts
442     if (!(options & ZX_INTERRUPT_VIRTUAL)) {
443         zx_status_t status;
444         if ((status = validate_resource_irq(src_obj, src_num)) != ZX_OK) {
445             return status;
446         }
447     }
448 
449     fbl::RefPtr<Dispatcher> dispatcher;
450     zx_rights_t rights;
451     zx_status_t result;
452     if (options & ZX_INTERRUPT_VIRTUAL) {
453         result = VirtualInterruptDispatcher::Create(&dispatcher, &rights, options);
454     } else {
455         result = InterruptEventDispatcher::Create(&dispatcher, &rights, src_num, options);
456     }
457     if (result != ZX_OK)
458         return result;
459 
460     return out_handle->make(ktl::move(dispatcher), rights);
461 }
462 
463 // zx_status_t zx_interrupt_bind
sys_interrupt_bind(zx_handle_t handle,zx_handle_t port_handle,uint64_t key,uint32_t options)464 zx_status_t sys_interrupt_bind(zx_handle_t handle, zx_handle_t port_handle,
465                                uint64_t key, uint32_t options) {
466     LTRACEF("handle %x\n", handle);
467     if (options) {
468         return ZX_ERR_INVALID_ARGS;
469     }
470 
471     zx_status_t status;
472     auto up = ProcessDispatcher::GetCurrent();
473     fbl::RefPtr<InterruptDispatcher> interrupt;
474     status = up->GetDispatcherWithRights(handle, ZX_RIGHT_READ, &interrupt);
475     if (status != ZX_OK)
476         return status;
477 
478     fbl::RefPtr<PortDispatcher> port;
479     status = up->GetDispatcherWithRights(port_handle, ZX_RIGHT_WRITE, &port);
480     if (status != ZX_OK)
481         return status;
482 
483     if (!port->can_bind_to_interrupt()) {
484         return ZX_ERR_WRONG_TYPE;
485     }
486 
487     return interrupt->Bind(ktl::move(port), key);
488 }
489 
490 // zx_status_t zx_interrupt_bind_vcpu
sys_interrupt_bind_vcpu(zx_handle_t handle,zx_handle_t vcpu,uint32_t options)491 zx_status_t sys_interrupt_bind_vcpu(zx_handle_t handle, zx_handle_t vcpu,
492                                     uint32_t options) {
493     LTRACEF("handle %x\n", handle);
494 
495     auto up = ProcessDispatcher::GetCurrent();
496     fbl::RefPtr<InterruptDispatcher> interrupt_dispatcher;
497     zx_status_t status = up->GetDispatcherWithRights(handle, ZX_RIGHT_READ, &interrupt_dispatcher);
498     if (status != ZX_OK) {
499         return status;
500     }
501 
502     fbl::RefPtr<VcpuDispatcher> vcpu_dispatcher;
503     status = up->GetDispatcherWithRights(vcpu, ZX_RIGHT_WRITE, &vcpu_dispatcher);
504     if (status != ZX_OK) {
505         return status;
506     }
507 
508     return interrupt_dispatcher->BindVcpu(ktl::move(vcpu_dispatcher));
509 }
510 
511 // zx_status_t zx_interrupt_ack
sys_interrupt_ack(zx_handle_t inth)512 zx_status_t sys_interrupt_ack(zx_handle_t inth) {
513     LTRACEF("handle %x\n", inth);
514 
515     zx_status_t status;
516     auto up = ProcessDispatcher::GetCurrent();
517     fbl::RefPtr<InterruptDispatcher> interrupt;
518     status = up->GetDispatcherWithRights(inth, ZX_RIGHT_WRITE, &interrupt);
519     if (status != ZX_OK)
520         return status;
521     return interrupt->Ack();
522 }
523 
524 // zx_status_t zx_interrupt_wait
sys_interrupt_wait(zx_handle_t handle,user_out_ptr<zx_time_t> out_timestamp)525 zx_status_t sys_interrupt_wait(zx_handle_t handle, user_out_ptr<zx_time_t> out_timestamp) {
526     LTRACEF("handle %x\n", handle);
527 
528     zx_status_t status;
529     auto up = ProcessDispatcher::GetCurrent();
530     fbl::RefPtr<InterruptDispatcher> interrupt;
531     status = up->GetDispatcherWithRights(handle, ZX_RIGHT_WAIT, &interrupt);
532     if (status != ZX_OK)
533         return status;
534 
535     zx_time_t timestamp;
536     status = interrupt->WaitForInterrupt(&timestamp);
537     if (status == ZX_OK && out_timestamp)
538         status = out_timestamp.copy_to_user(timestamp);
539     return status;
540 }
541 
542 // zx_status_t zx_interrupt_destroy
sys_interrupt_destroy(zx_handle_t handle)543 zx_status_t sys_interrupt_destroy(zx_handle_t handle) {
544     LTRACEF("handle %x\n", handle);
545 
546     zx_status_t status;
547     auto up = ProcessDispatcher::GetCurrent();
548     fbl::RefPtr<InterruptDispatcher> interrupt;
549     status = up->GetDispatcher(handle, &interrupt);
550     if (status != ZX_OK)
551         return status;
552     return interrupt->Destroy();
553 }
554 
555 // zx_status_t zx_interrupt_trigger
sys_interrupt_trigger(zx_handle_t handle,uint32_t options,zx_time_t timestamp)556 zx_status_t sys_interrupt_trigger(zx_handle_t handle,
557                                   uint32_t options,
558                                   zx_time_t timestamp) {
559     LTRACEF("handle %x\n", handle);
560 
561     if (options) {
562         return ZX_ERR_INVALID_ARGS;
563     }
564 
565     zx_status_t status;
566     auto up = ProcessDispatcher::GetCurrent();
567     fbl::RefPtr<InterruptDispatcher> interrupt;
568     status = up->GetDispatcherWithRights(handle, ZX_RIGHT_SIGNAL, &interrupt);
569     if (status != ZX_OK)
570         return status;
571 
572     return interrupt->Trigger(timestamp);
573 }
574 
575 // zx_status_t zx_smc_call
sys_smc_call(zx_handle_t handle,user_in_ptr<const zx_smc_parameters_t> parameters,user_out_ptr<zx_smc_result_t> out_smc_result)576 zx_status_t sys_smc_call(zx_handle_t handle,
577                          user_in_ptr<const zx_smc_parameters_t> parameters,
578                          user_out_ptr<zx_smc_result_t> out_smc_result) {
579     if (!parameters || !out_smc_result) {
580         return ZX_ERR_INVALID_ARGS;
581     }
582 
583     zx_smc_parameters_t params;
584     zx_status_t status = parameters.copy_from_user(&params);
585     if (status != ZX_OK) {
586         return status;
587     }
588 
589     uint32_t service_call_num = ARM_SMC_GET_SERVICE_CALL_NUM_FROM_FUNC_ID(params.func_id);
590     if ((status = validate_resource_smc(handle, service_call_num)) != ZX_OK) {
591         return status;
592     }
593 
594     zx_smc_result_t result;
595 
596     arch_smc_call(&params, &result);
597 
598     return out_smc_result.copy_to_user(result);
599 }
600