xref: /xnu-10002.81.5/osfmk/arm64/iofilter.c (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
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