1 /*
2 * Copyright (c) 2022 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <pexpert/arm64/board_config.h>
30
31 #if HAS_GUARDED_IO_FILTER
32
33 #include <vm/pmap.h>
34 #include <arm/pmap/pmap_data.h>
35
36 extern uint64_t io_filter_vtop(uint64_t addr);
37
38 int io_filter_main(uint64_t addr, uint64_t value, uint64_t width, unsigned int io_attr_index, unsigned int io_filter_entry_index);
39
40 MARK_AS_PMAP_TEXT
41 static int
io_filter_write(uint64_t addr,uint64_t value,uint64_t width,unsigned int io_attr_index,unsigned int io_filter_entry_index)42 io_filter_write(uint64_t addr, uint64_t value, uint64_t width, unsigned int io_attr_index, unsigned int io_filter_entry_index)
43 {
44 /* Convert the addr to a physical address. */
45 const pmap_paddr_t pa = (pmap_paddr_t) io_filter_vtop(addr);
46
47 /* Fail out if PA is zero, indicating translation went wrong. */
48 if (__improbable(pa == 0)) {
49 return 0;
50 }
51
52 extern pmap_io_range_t *io_attr_table;
53 extern unsigned int num_io_rgns;
54
55 /* Fail if io_attr_table arguments are bad. */
56 if (__improbable(io_attr_table == NULL || io_attr_index >= (uint64_t) num_io_rgns)) {
57 return 0;
58 }
59
60 extern pmap_io_filter_entry_t *io_filter_table;
61 extern unsigned int num_io_filter_entries;
62
63 /* Fail if io_fitler_table arguments are bad. */
64 if (__improbable(io_filter_table == NULL || io_filter_entry_index >= (uint64_t) num_io_filter_entries)) {
65 return 0;
66 }
67
68 const pmap_io_range_t *io_range = &io_attr_table[io_attr_index];
69 const pmap_io_filter_entry_t *io_filter_entry = &io_filter_table[io_filter_entry_index];
70
71 /* Fail if pa is not described by the io_attr_table entry. */
72 if (__improbable(pa < io_range->addr || (pa + width) > (io_range->addr + io_range->len))) {
73 return 0;
74 }
75
76 const uint32_t signature = io_range->signature;
77
78 /* Fail if the signature doesn't match. */
79 if (__improbable(signature != io_filter_entry->signature)) {
80 return 0;
81 }
82
83 const uint16_t pa_offset = (uint16_t) (pa & PAGE_MASK);
84 const uint16_t pa_length = (uint16_t) width;
85
86 /* Fail if pa is not described by the io_filter_entry. */
87 if (__improbable(pa_offset < io_filter_entry->offset || (pa_offset + pa_length) > (io_filter_entry->offset + io_filter_entry->length))) {
88 return 0;
89 }
90
91 switch (width) {
92 case 1:
93 *(volatile uint8_t *)addr = (uint8_t) value;
94 break;
95 case 2:
96 *(volatile uint16_t *)addr = (uint16_t) value;
97 break;
98 case 4:
99 *(volatile uint32_t *)addr = (uint32_t) value;
100 break;
101 case 8:
102 *(volatile uint64_t *)addr = (uint64_t) value;
103 break;
104 default:
105 return 0;
106 }
107
108 return 1;
109 }
110
111 MARK_AS_PMAP_TEXT
112 int
io_filter_main(uint64_t addr,uint64_t value,uint64_t width,unsigned int io_attr_index,unsigned int io_filter_entry_index)113 io_filter_main(uint64_t addr, uint64_t value, uint64_t width, unsigned int io_attr_index, unsigned int io_filter_entry_index)
114 {
115 // Check if width is supported.
116 if ((width != 1) && (width != 2) && (width != 4) && (width != 8)) {
117 return 0;
118 }
119
120 // Check if addr is width aligned.
121 if ((width != 1) && ((addr & (width - 1)) != 0)) {
122 return 0;
123 }
124
125 return io_filter_write(addr, value, width, io_attr_index, io_filter_entry_index);
126 }
127 #endif /* HAS_GUARDED_IO_FILTER */
128