+/*
+ * Typefilter(s)
+ *
+ * A typefilter is a 8KB bitmap that is used to selectively filter events
+ * being recorded. It is able to individually address every class & subclass.
+ *
+ * There is a shared typefilter in the kernel which is lazily allocated. Once
+ * allocated, the shared typefilter is never deallocated. The shared typefilter
+ * is also mapped on demand into userspace processes that invoke kdebug_trace
+ * API from Libsyscall. When mapped into a userspace process, the memory is
+ * read only, and does not have a fixed address.
+ *
+ * It is a requirement that the kernel's shared typefilter always pass DBG_TRACE
+ * events. This is enforced automatically, by having the needed bits set any
+ * time the shared typefilter is mutated.
+ */
+
+typedef uint8_t* typefilter_t;
+
+static typefilter_t kdbg_typefilter;
+static mach_port_t kdbg_typefilter_memory_entry;
+
+/*
+ * There are 3 combinations of page sizes:
+ *
+ * 4KB / 4KB
+ * 4KB / 16KB
+ * 16KB / 16KB
+ *
+ * The typefilter is exactly 8KB. In the first two scenarios, we would like
+ * to use 2 pages exactly; in the third scenario we must make certain that
+ * a full page is allocated so we do not inadvertantly share 8KB of random
+ * data to userspace. The round_page_32 macro rounds to kernel page size.
+ */
+#define TYPEFILTER_ALLOC_SIZE MAX(round_page_32(KDBG_TYPEFILTER_BITMAP_SIZE), KDBG_TYPEFILTER_BITMAP_SIZE)
+
+static typefilter_t typefilter_create(void)
+{
+ typefilter_t tf;
+ if (KERN_SUCCESS == kmem_alloc(kernel_map, (vm_offset_t*)&tf, TYPEFILTER_ALLOC_SIZE, VM_KERN_MEMORY_DIAG)) {
+ memset(&tf[KDBG_TYPEFILTER_BITMAP_SIZE], 0, TYPEFILTER_ALLOC_SIZE - KDBG_TYPEFILTER_BITMAP_SIZE);
+ return tf;
+ }
+ return NULL;
+}
+
+static void typefilter_deallocate(typefilter_t tf)
+{
+ assert(tf);
+ assert(tf != kdbg_typefilter);
+ kmem_free(kernel_map, (vm_offset_t)tf, TYPEFILTER_ALLOC_SIZE);
+}
+
+static void typefilter_copy(typefilter_t dst, typefilter_t src)
+{
+ assert(src);
+ assert(dst);
+ memcpy(dst, src, KDBG_TYPEFILTER_BITMAP_SIZE);
+}
+
+static void typefilter_reject_all(typefilter_t tf)
+{
+ assert(tf);
+ memset(tf, 0, KDBG_TYPEFILTER_BITMAP_SIZE);
+}
+
+static void typefilter_allow_class(typefilter_t tf, uint8_t class)
+{
+ assert(tf);
+ const uint32_t BYTES_PER_CLASS = 256 / 8; // 256 subclasses, 1 bit each
+ memset(&tf[class * BYTES_PER_CLASS], 0xFF, BYTES_PER_CLASS);
+}
+
+static void typefilter_allow_csc(typefilter_t tf, uint16_t csc)
+{
+ assert(tf);
+ setbit(tf, csc);
+}
+
+static boolean_t typefilter_is_debugid_allowed(typefilter_t tf, uint32_t id)
+{
+ assert(tf);
+ return isset(tf, KDBG_EXTRACT_CSC(id));
+}
+
+static mach_port_t typefilter_create_memory_entry(typefilter_t tf)
+{
+ assert(tf);
+
+ mach_port_t memory_entry = MACH_PORT_NULL;
+ memory_object_size_t size = TYPEFILTER_ALLOC_SIZE;
+
+ mach_make_memory_entry_64(kernel_map,
+ &size,
+ (memory_object_offset_t)tf,
+ VM_PROT_READ,
+ &memory_entry,
+ MACH_PORT_NULL);
+
+ return memory_entry;
+}
+
+static int kdbg_copyin_typefilter(user_addr_t addr, size_t size);
+static void kdbg_enable_typefilter(void);
+static void kdbg_disable_typefilter(void);
+
+/*
+ * External prototypes
+ */
+