first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

@@ -0,0 +1,204 @@
/*
* Copyright (C) 2011-2012 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <drivers/consistent_debug.h>
#include <platform/memmap.h>
#include <arch/arm/arm.h>
#include <platform.h>
#include <platform/timer.h>
#include <platform/soc/pmgr.h>
#include <stdio.h>
static dbg_registry_t * consistent_debug_registry = NULL;
static dbg_cpr_t* ap_cpr;
static dbg_registry_t* init_consistent_debug_registry(void *consistent_debug_base);
static dbg_record_header_t* consistent_debug_allocate_entry();
static void consistent_debug_register_root_pointer(void);
static void consistent_debug_ensure_visibility()
{
platform_memory_barrier();
#if WITH_NON_COHERENT_DMA
// On platforms without coherent DMA, JTAG access is likely incoherent as well.
platform_cache_operation(CACHE_CLEAN, consistent_debug_registry, sizeof(dbg_registry_t));
#endif
}
int consistent_debug_resume(void)
{
// When resuming from hibernate, assume we have a valid Consistent Debug Registry, and
// put the root address back in the PMGR scratch (which gets cleared on hibernate)
dprintf(DEBUG_SPEW, "Restoring consistent debug state, preserving existing entries...\n");
consistent_debug_registry = (dbg_registry_t*)((void*)CONSISTENT_DEBUG_BASE);
ap_cpr = &consistent_debug_registry->ap_cpr_region;
// Ensure the header is visible before publishing it in the scratch register.
consistent_debug_ensure_visibility();
consistent_debug_register_root_pointer();
return 0;
}
int consistent_debug_init(void)
{
dprintf(DEBUG_SPEW, "Enabling consistent debug...\n");
ASSERT(CONSISTENT_DEBUG_SIZE >= sizeof(dbg_registry_t));
consistent_debug_registry = init_consistent_debug_registry((void*)CONSISTENT_DEBUG_BASE);
// Set up the CPR
dbg_record_header_t ap_progress_report;
ap_progress_report.record_id = kDbgIdCPRHeaderAP;
ap_progress_report.physaddr = (uint64_t)(mem_static_map_physical((uintptr_t)(&consistent_debug_registry->ap_cpr_region)));
ap_progress_report.length = sizeof(dbg_cpr_t);
ap_cpr = &consistent_debug_registry->ap_cpr_region;
consistent_debug_update_ap_cpr(DBG_CPR_STATE_BOOTING, 0);
// Set up the XNU PANIC_BASE pointer, so once booted Astris can still unpack the panic string.
dbg_record_header_t panic_region;
panic_region.record_id = kDbgIdXNUPanicRegion;
panic_region.physaddr = (uint64_t)(PANIC_BASE);
panic_region.length = (uint64_t)(PANIC_SIZE);
if(!consistent_debug_register_header(panic_region))
{
dprintf(DEBUG_INFO, "Unable to register XNU panic region in consistent debug.\n");
}
dbg_record_header_t* hdr = (dbg_record_header_t*)consistent_debug_register_header(ap_progress_report);
RELEASE_ASSERT(hdr);
// Ensure the header is visible before publishing it in the scratch register.
consistent_debug_ensure_visibility();
consistent_debug_register_root_pointer();
return 0;
}
static void consistent_debug_register_root_pointer(void)
{
uint32_t root;
uintptr_t consistent_debug_addr = mem_static_map_physical((uintptr_t)consistent_debug_registry);
root = consistent_debug_encode_root_pointer(consistent_debug_addr, 0);
platform_set_consistent_debug_root_pointer(root);
dprintf(DEBUG_SPEW, "Registered consistent debug root pointer (encoded as 0x%x)\n", (unsigned int)root);
}
dbg_registry_t* consistent_debug_get_registry(void)
{
return consistent_debug_registry;
}
void consistent_debug_update_ap_cpr(cp_state_t state, int arg)
{
if(ap_cpr) {
enter_critical_section();
if(ap_cpr->rdptr + 1 == ap_cpr->wrptr)
{
dprintf(DEBUG_SPEW, "AP CPR is full, advancing rdptr\n");
// Eat the oldest entry if buffer gets full.
ap_cpr->rdptr++;
consistent_debug_ensure_visibility();
}
dbg_cpr_state_entry_t* entry = &ap_cpr->cp_state_entries[ap_cpr->wrptr];
entry->cp_state = state;
entry->cp_state_arg = arg;
entry->timestamp = timer_get_ticks();
consistent_debug_ensure_visibility();
ap_cpr->wrptr++;
exit_critical_section();
dprintf(DEBUG_SPEW, "AP CPR updated at time %llu with state %d (argument %d)\n", entry->timestamp, entry->cp_state, entry->cp_state_arg);
}
}
static dbg_registry_t* init_consistent_debug_registry(void* consistent_debug_base)
{
dbg_registry_t* reg = (dbg_registry_t*)(consistent_debug_base);
memset(reg, 0, sizeof(dbg_registry_t));
reg->top_level_header.record_id = kDbgIdTopLevelHeader;
reg->top_level_header.num_records = DEBUG_REGISTRY_MAX_RECORDS;
reg->top_level_header.record_size_bytes = sizeof(dbg_record_header_t);
return reg;
}
/**
* Finds a free entry in the Consistent Debug Registry and
* reserves it.
*
* @author jdong (12/7/2012)
*
* @return NULL if unsuccessful, otherwise a pointer to a
* reserved entry (where the record_id is set to
* kDbgIdReservedEntry)
*/
static dbg_record_header_t* consistent_debug_allocate_entry(void) {
if (!consistent_debug_registry) {
enter_critical_section();
if(!consistent_debug_registry) {
// Check again to make sure someone else didn't enable it already
consistent_debug_init();
}
exit_critical_section();
return consistent_debug_allocate_entry();
}
for (unsigned int i = 0; i < consistent_debug_registry->top_level_header.num_records; i++) {
dbg_record_header_t *record = &consistent_debug_registry->records[i];
if (__sync_bool_compare_and_swap(&record->record_id, kDbgIdUnusedEntry, kDbgIdReservedEntry)) {
// Reserved an entry at position i.
return (dbg_record_header_t*)record;
}
}
return NULL;
}
dbg_record_header_t* consistent_debug_register_header(dbg_record_header_t hdr) {
dbg_record_header_t *allocated_header = consistent_debug_allocate_entry();
if (allocated_header) {
allocated_header->length = hdr.length;
allocated_header->physaddr = hdr.physaddr;
consistent_debug_ensure_visibility();
// Make sure the hdr/length are visible before the record_id.
allocated_header->record_id = hdr.record_id;
consistent_debug_ensure_visibility();
}
return allocated_header;
}
int consistent_debug_unregister_header(dbg_record_header_t *hdr)
{
if (!consistent_debug_registry) {
return -1;
}
if ((hdr < &consistent_debug_registry->records[0]) ||
(hdr >= &consistent_debug_registry->records[consistent_debug_registry->top_level_header.num_records])) {
// Out of range
return -1;
}
// The record ID may be modified by the JTAG observer, and the caller
// loops on the value changing to kDbgIdUnusedEntry. Make sure we read it from memory.
switch (*(volatile uint64_t*)(&hdr->record_id)) {
case kDbgIdUnusedEntry:
return -1;
case kDbgIdFreeReqEntry:
return 0;
case kDbgIdFreeAckEntry:
hdr->record_id = kDbgIdUnusedEntry;
return 1;
default:
hdr->record_id = kDbgIdFreeReqEntry;
return 0;
}
}
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2011-2012 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __CONSISTENT_DEBUG_HELPER_FNS__
#define __CONSISTENT_DEBUG_HELPER_FNS__
#include "consistent_debug_registry.h"
// C Helper functions that should serve as a pseudo-library
// for other codebases that use Consistent Debug
// Root Pointer encoder/decoder
/**
* Encode 64-bit physical address of root pointer into a
* suitable 32-bit format.
*
* @param root_pointer 64-bit pointer to the physical address of
* the consistent debug registry
* @param pointer_type One of the types documented in "Debug
* Root Pointer Scratch Register Format" of
* consistent_debug_registry.h
*
* @return uint32_t 0: Cannot encode address with specified
* type, or invalid type. Otherwise, returns a 32-bit
* representation of the address.
*/
static inline uint32_t consistent_debug_encode_root_pointer(uint64_t root_pointer, unsigned int pointer_type)
{
if (pointer_type != 0) {
return 0; // Only type 0 is supported currently
}
if (root_pointer & 0xFFF) {
return 0; // Not page-aligned, truncation would lose information
}
root_pointer >>= 12;
if (root_pointer >= 0x3FFFFFFFF) {
return 0; // Too large to represent
}
return (uint32_t)root_pointer;
}
/**
* opposite of consistent_debug_encode_root_pointer; decodes a root
* pointer encoded in that manner.
*
* @return uint64_t 0 if cannot be decoded, otherwise the
* physical address.
*/
static inline uint64_t consistent_debug_decode_root_pointer(uint32_t encoded_value)
{
if (encoded_value & 0xC0000000) {
return 0; // Can't decode anything other than a "type 0" address
}
uint64_t ret = encoded_value;
ret <<= 12;
return ret;
}
#endif // __CONSISTENT_DEBUG_HELPER_FNS__
@@ -0,0 +1,235 @@
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __DRIVERS_CONSISTENT_DEBUG_REGISTRY_H
#define __DRIVERS_CONSISTENT_DEBUG_REGISTRY_H
// Consistent Debugging Root Structure Definition.
// See documentation at <TODO: CONSISTENT DEBUGGING WIKI LINK>
// Debug Root Pointer Definitions:
//
// The Debug Root Pointer is used to find the location of the
// Debug Registry. It is currently implemented as a 32-bit PMGR
// scratch register that's reset on boot.
// Debug Root Pointer Scratch Register Format:
// We have 64 bit addresses but a 32-bit scratch register, so
// do a bit of encoding to at least futureproof the use of a
// 32-bit register to the foreseeable future.
//
// Bit: ---31..30-|---- 29...0 -----
// | TYPE | ADDR |
// -------------------------
//
// TYPE:
// 0b00: ADDR is (physical address >> 12). This is good as
// long as our physical address space is within 42 bits,
// which like it will be true for a while.
//
// -other-: Reserved for future encodings. Expected use
// cases are for larger-sized granularity, or indexing off
// another known location like SRAM_BASE/SDRAM_BASE.
//
// Helper functions for producing these encodings are in
// consistent_debug_helper_fns.h
// Debug Registry Definitions:
typedef enum {
DBG_PROCESSOR_AP = 1,
DBG_COPROCESSOR_ANS,
DBG_COPROCESSOR_SEP,
DBG_COPROCESSOR_SIO,
DBG_COPROCESSOR_ISP,
DBG_COPROCESSOR_OSCAR,
DBG_NUM_PROCESSORS
} dbg_processor_t;
#define DEBUG_REGISTRY_MAX_RECORDS 512
#define DEBUG_RECORD_ID_LONG(a, b,c ,d, e, f, g, h) ( ((unsigned long long)((((h) << 24) & 0xFF000000) | (((g) << 16) & 0x00FF0000) | (((f) << 8) & 0x0000FF00) | ((e) & 0x00FF)) << 32) | \
(unsigned long long)((((d) << 24) & 0xFF000000) | (((c) << 16) & 0x00FF0000) | (((b) << 8) & 0x0000FF00) | ((a) & 0x00FF)) )
#define DEBUG_RECORD_ID_SHORT(a,b,c,d) DEBUG_RECORD_ID_LONG(a,b,c,d,0,0,0,0)
/* The Debug Registry lives near the top of SDRAM in a reserved
region. Its size is fixed at compile time and defined as
DEBUG_REGISTRY_MAX_RECORDS. This region holds pointers to
where the actual structures are. This allows more costly data
structures to be allocated at runtime and as needed.
iOS and iBoot will provide APIs for registering records here.
Note that ONLY the AP will be allowed to register entries in
the Consistent Debug Registry. An IOP that wishes to have an
entry have an AP-side handler reserve a record. Once a record
is reserved, anyone may own it.
* |---------------------------|
* | record_id |
* |---------------------------|
* | length |
* |---------------------------|
* | physaddr |
* |---------------------------|
* | next_record_id |
.......
*/
typedef struct {
uint64_t record_id; // 64-bit unique ID identifying the record
uint64_t length; // Length of the payload
uint64_t physaddr; // System physical address of entry
} dbg_record_header_t;
// Life cycle of a record_id:
// Starts out as DbgIdUnusedEntry. When reserved, it becomes
// kDbgIdReservedEntry. Once the correct address/length has been
// filled in, the owner can write the appropriate record ID.
//
// When freeing an entry, the agent should write
// kDbgIdFreeReqEntry to the field. Then, the external reader is
// expected to notice the record_id change and stop using this
// debug region. After the reader no longer is using these
// resources, it will write in kDbgIdFreeAckEntry. Then, the
// consistent debug driver will respond by zeroing the entry.
#define kDbgIdUnusedEntry 0x0ULL
#define kDbgIdReservedEntry DEBUG_RECORD_ID_LONG('R','E','S','E','R','V','E', 'D')
#define kDbgIdFreeReqEntry DEBUG_RECORD_ID_LONG('F','R','E','E','-','R','E','Q')
#define kDbgIdFreeAckEntry DEBUG_RECORD_ID_LONG('F','R','E','E','-','A','C','K')
#define kDbgIdTopLevelHeader DEBUG_RECORD_ID_SHORT('D','B','G','H')
/*
The first entry in the debug area is a "top level header",
which has a different layout than following records. It
describes the size and number of records. Although these
parameters are derivable by looking up the top level
header's magic record ID, this approach lends to more robust
code run-time parsing of the debug area that doesn't have to
be constantly updated for minor format changes.
*/
typedef struct {
uint64_t record_id; // = kDbgIdTopLevelHeader
uint32_t num_records; // = DEBUG_REGISTRY_MAX_RECORDS
uint32_t record_size_bytes; // = sizeof(dbg_record_header_t)
} dbg_top_level_header_t;
/*
* Shared Memory Console Descriptors:
* Record ID: One per SHMConsole
*/
#define DbgIdConsoleHeaderForIOP(which_dbg_processor, which_num) (DEBUG_RECORD_ID_LONG('C','O','N',0,0,0,which_dbg_processor,which_num))
#define kDbgIdConsoleHeaderAP DbgIdConsoleHeaderForIOP(DBG_PROCESSOR_AP, 0)
#define kDbgIdConsoleHeaderANS DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_ANS, 0)
#define kDbgIdConsoleHeaderSIO DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_SIO, 0)
#define kDbgIdConsoleHeaderSEP DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_SEP, 0)
#define kDbgIdConsoleHeaderISP DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_ISP, 0)
#define kDbgIdConsoleHeaderOscar DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_OSCAR, 0)
/*
* Coprocessor Progress Reports
*
* The CPR is a standardized structure across all coprocessors
* that gives brief info as to its state.
*
* Each coprocessor is responsible for updating its state. The
ring buffer is supposed to wrap around when full, ensuring
that the current state is always present.
*/
#define DbgIdCPRHeaderForIOP(which_dbg_processor, which_num) (DEBUG_RECORD_ID_LONG('C','P','R',0,0,0,which_dbg_processor,which_num))
#define kDbgIdCPRHeaderBase DbgIdCPRHeaderForIOP(0, 0)
#define kDbgIdCPRHeaderAP DbgIdCPRHeaderForIOP(DBG_PROCESSOR_AP, 0)
#define kDbgIdCPRHeaderANS DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_ANS, 0)
#define kDbgIdCPRHeaderSIO DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_SIO, 0)
#define kDbgIdCPRHeaderSEP DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_SEP, 0)
#define kDbgIdCPRHeaderISP DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_ISP, 0)
#define kDbgIdCPRHeaderOscar DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_OSCAR, 0)
typedef enum {
DBG_CPR_STATE_POWEROFF,
DBG_CPR_STATE_BOOTING, // In the bootloader
DBG_CPR_STATE_RUNNING, // Somewhere in the kernel
DBG_CPR_STATE_QUIESCING,
DBG_CPR_STATE_ASLEEP,
DBG_CPR_STATE_CRASHED // Panicked / Crashed
} cp_state_t;
typedef enum {
DBG_CPR_AP_PANICKED_IN_IBOOT,
DBG_CPR_AP_PANICKED_IN_DARWIN,
} cp_ap_crash_arg_t;
typedef struct {
uint64_t timestamp;
uint32_t cp_state; // One of the cp_state_t enumerations
uint32_t cp_state_arg; // IOP-defined supplemental value
} dbg_cpr_state_entry_t;
#define CPR_MAX_STATE_ENTRIES 16 // Arbitrary value
// This second-level struct should be what the Debug Registry record (e.g. kDbgIdCPRHeaderANS) points to.
typedef struct {
uint32_t rdptr;
uint32_t wrptr;
uint32_t num_cp_state_entries;
uint32_t checksum;
dbg_cpr_state_entry_t cp_state_entries[CPR_MAX_STATE_ENTRIES];
} dbg_cpr_t;
/*
* Panic String Locator
*
* Points to the location / length of the panic string.
*/
#define DbgIdPanicHeaderForIOP(which_dbg_processor, which_num) (DEBUG_RECORD_ID_LONG('P','A','N','I','C',0,which_dbg_processor,which_num))
#define kDbgIdPanicHeaderAP DbgIdPanicHeaderForIOP(DBG_PROCESSOR_AP, 0)
/*
* Memory Map Hints:
*
* Useful regions (such as those defined in platform/memmap.h) start with magic "MAP"
*
*/
// XNU's PANIC_BASE will be recorded here. This can allow Astris to read the kernel's
#define kDbgIdXNUPanicRegion (DEBUG_RECORD_ID_LONG('M','A','P','P','A','N','I','C'))
// XNU's physical load address for Astris's use in coredumps
#define kDbgIdXNUKernelRegion (DEBUG_RECORD_ID_LONG('M','A','P','K','E','R','N','L'))
typedef struct {
dbg_top_level_header_t top_level_header;
dbg_record_header_t records[DEBUG_REGISTRY_MAX_RECORDS];
// Stuff the AP's Progress Report buffer at the end of this
// structure. It's currently the only processor that doesn't
// have some easier form of persistent memory that survives the
// iBoot->iOS handoff (e.g. ANS has its private heap)
dbg_cpr_t ap_cpr_region;
} dbg_registry_t;
#endif
+22
View File
@@ -0,0 +1,22 @@
# Copyright (C) 2011-2012 Apple Inc. All rights reserved.
#
# This document is the property of Apple Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Inc.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_CONSISTENT_DBG=1
MODULES += \
drivers/apple/consistent_debug
ALL_OBJS += \
$(LOCAL_DIR)/consistent_debug.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include