+/*ARGSUSED*/
+int
+oslogioctl(__unused dev_t dev, u_long com, caddr_t data, __unused int flag, __unused struct proc *p)
+{
+ int ret = 0;
+ mach_vm_size_t buffer_size = (FIREHOSE_BUFFER_KERNEL_CHUNK_COUNT * FIREHOSE_CHUNK_SIZE);
+ firehose_buffer_map_info_t map_info = {0, 0};
+ firehose_buffer_t kernel_firehose_buffer = NULL;
+ mach_vm_address_t user_addr = 0;
+ mach_port_t mem_entry_ptr = MACH_PORT_NULL;
+
+ switch (com) {
+
+ /* return number of characters immediately available */
+
+ case LOGBUFFERMAP:
+ kernel_firehose_buffer = kernel_firehose_addr;
+
+ ret = mach_make_memory_entry_64(kernel_map,
+ &buffer_size,
+ (mach_vm_offset_t) kernel_firehose_buffer,
+ ( MAP_MEM_VM_SHARE | VM_PROT_READ ),
+ &mem_entry_ptr,
+ MACH_PORT_NULL);
+ if (ret == KERN_SUCCESS) {
+ ret = mach_vm_map(get_task_map(current_task()),
+ &user_addr,
+ buffer_size,
+ 0, /* mask */
+ VM_FLAGS_ANYWHERE,
+ mem_entry_ptr,
+ 0, /* offset */
+ FALSE, /* copy */
+ VM_PROT_READ,
+ VM_PROT_READ,
+ VM_INHERIT_SHARE);
+ }
+
+ if (ret == KERN_SUCCESS) {
+ map_info.fbmi_addr = (uint64_t) (user_addr);
+ map_info.fbmi_size = buffer_size;
+ bcopy(&map_info, data, sizeof(firehose_buffer_map_info_t));
+ }
+ break;
+ case LOGFLUSHED:
+ LOG_LOCK();
+ os_log_wakeup = 0;
+ LOG_UNLOCK();
+ __firehose_merge_updates(*(firehose_push_reply_t *)(data));
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+oslog_streamioctl(__unused dev_t dev, u_long com, caddr_t data, __unused int flag, __unused struct proc *p)
+{
+ int err = 0;
+
+ lck_spin_lock(&oslog_stream_lock);
+
+ switch (com) {
+ case FIONBIO:
+ if (data && *(int *)data)
+ oslog_streamsoftc.sc_state |= LOG_NBIO;
+ else
+ oslog_streamsoftc.sc_state &= ~LOG_NBIO;
+ break;
+ case FIOASYNC:
+ if (data && *(int *)data)
+ oslog_streamsoftc.sc_state |= LOG_ASYNC;
+ else
+ oslog_streamsoftc.sc_state &= ~LOG_ASYNC;
+ break;
+ default:
+ err = -1;
+ break;
+ }
+
+ lck_spin_unlock(&oslog_stream_lock);
+ return err;
+}
+
+void
+bsd_log_init(void)
+{
+ /* After this point, we must be ready to accept characters */
+}
+
+void
+oslog_init(void)
+{
+ kern_return_t kr;
+ vm_size_t size = FIREHOSE_BUFFER_KERNEL_CHUNK_COUNT * FIREHOSE_CHUNK_SIZE;
+
+ oslog_lock_init();
+
+ kr = kmem_alloc_flags(kernel_map, &kernel_firehose_addr,
+ size + (2 * PAGE_SIZE), VM_KERN_MEMORY_LOG,
+ KMA_GUARD_FIRST | KMA_GUARD_LAST);
+ if (kr != KERN_SUCCESS) {
+ panic("Failed to allocate memory for firehose logging buffer");
+ }
+ kernel_firehose_addr += PAGE_SIZE;
+ bzero(kernel_firehose_addr, size);
+ /* register buffer with firehose */
+ kernel_firehose_addr = __firehose_buffer_create((size_t *) &size);
+
+ kprintf("oslog_init completed\n");
+}
+
+/*
+ * log_putc_locked
+ *
+ * Decription: Output a character to the log; assumes the LOG_LOCK() is held
+ * by the caller.
+ *
+ * Parameters: c Character to output
+ *
+ * Returns: (void)
+ *
+ * Notes: This functions is used for multibyte output to the log; it
+ * should be used preferrentially where possible to ensure that
+ * log entries do not end up interspersed due to preemption or
+ * SMP reentrancy.
+ */
+void
+log_putc_locked(char c)
+{
+ struct msgbuf *mbp;
+
+ mbp = msgbufp;
+ mbp->msg_bufc[mbp->msg_bufx++] = c;
+ if (mbp->msg_bufx >= msgbufp->msg_size)
+ mbp->msg_bufx = 0;
+}
+
+static oslog_stream_buf_entry_t
+oslog_stream_find_free_buf_entry_locked(void)
+{
+ struct msgbuf *mbp;
+ oslog_stream_buf_entry_t buf_entry = NULL;
+
+ lck_spin_assert(&oslog_stream_lock, LCK_ASSERT_OWNED);
+
+ mbp = oslog_streambufp;
+
+ buf_entry = STAILQ_FIRST(&oslog_stream_free_head);
+ if (buf_entry) {
+ STAILQ_REMOVE_HEAD(&oslog_stream_free_head, buf_entries);
+ }
+ else {
+ // If no list elements are available in the free-list,
+ // consume the next log line so we can free up its list element
+ oslog_stream_buf_entry_t prev_entry = NULL;
+
+ buf_entry = STAILQ_FIRST(&oslog_stream_buf_head);
+ while (buf_entry->type == oslog_stream_link_type_metadata) {
+ prev_entry = buf_entry;
+ buf_entry = STAILQ_NEXT(buf_entry, buf_entries);
+ }
+
+ if (prev_entry == NULL) {
+ STAILQ_REMOVE_HEAD(&oslog_stream_buf_head, buf_entries);
+ }
+ else {
+ STAILQ_REMOVE_AFTER(&oslog_stream_buf_head, prev_entry, buf_entries);
+ }
+
+ mbp->msg_bufr += buf_entry->size;
+ oslog_s_dropped_msgcount++;
+ if (mbp->msg_bufr >= mbp->msg_size) {
+ mbp->msg_bufr = (mbp->msg_bufr % mbp->msg_size);
+ }
+ }
+
+ return buf_entry;
+}
+