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(×tamp);
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(¶ms);
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(¶ms, &result);
597
598 return out_smc_result.copy_to_user(result);
599 }
600