blob: 2c4302f3a7aae9a9526269f1a476c28a07c56385 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef RAM_CRASHLOG_RAM_CRASHLOG_H_
#define RAM_CRASHLOG_RAM_CRASHLOG_H_
#include <zircon/boot/crash-reason.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
__BEGIN_CDECLS
// Overview:
//
// A "RAM" crashlog is a data structure meant to hold details about a
// kernel-level crash across reboots. It is meant to exist in contiguously
// mapped RAM storage. Ideally, it would use on-die static RAM, but it can also
// use dynamic RAM if there are no other options. In the case of DRAM, systems
// need to take care to enable RAM refresh as early as possible in order to
// avoid degradation and corruption of the crashlog during a reboot.
//
// Logically, a crashlog consists of a header and a user supplied payload. The
// header contains a small amount of common information meant to be updated
// periodically in the case of a spontaneous reboot (such as those caused by
// hardware watchdog timers, brownout detectors, or reboots triggered by higher
// execution levels). In the case that a reboot is triggered by the system
// itself (out-of-memory condition, kernel panic, etc.) the crashlog can also
// hold some amount of additional user supplied data.
//
// In RAM, the crashlog actually holds two copies of the header in order to
// allow for a transactional update of the log. During updates of the header,
// the new header is written and flushed first, and then the magic number is
// flipped in order to indicate a change in the active header. In addition,
// separate CRC32s are stored for the header and payload sections of the
// crashlog. This allows the system to detect and be aware of corruption in the
// payload section of the crashlog, but still deliver some data (along with the
// knowledge that some of the bits in the payload may have been flipped)
//
// CRC integrity checks use CRC32 (ISO 3309)
//
#define RAM_CRASHLOG_MAGIC_0 ((uint64_t)(0x6f8962d66b28504f))
#define RAM_CRASHLOG_MAGIC_1 (~RAM_CRASHLOG_MAGIC_0)
typedef struct {
zx_duration_t uptime; // Best estimate of system uptime.
zircon_crash_reason_t reason; // The system's best guess as to the reason for crash/reboot
uint32_t payload_len;
uint32_t payload_crc32; // A CRC32 of just the payload section of the crashlog.
uint32_t header_crc32; // A CRC32 of just this header, excluding |header_crc32|.
} ram_crashlog_header_t;
typedef struct {
// Magic number sanity check. Also indicates which of the following two
// headers is considered active. A value of MAGIC_0 indicates that hdr[0] is
// active, while MAGIC_1 indicates that hdr[1] is active.
uint64_t magic;
// The two copies of the headers. Check |magic| to see which (if any) is valid.
ram_crashlog_header_t hdr[2];
// Payload comes immediately after the top level header structure.
} ram_crashlog_t;
// A structure used to provide details about a recovered crashlog. When a
// crashlog is recovered successfully, this structure will convey:
// 1) The crash reason
// 2) The uptime estimate
// 3) An indication of the payload's integrity.
// 4) A length of the memory mapped payload.
typedef struct {
zx_duration_t uptime;
zircon_crash_reason_t reason;
bool payload_valid;
const void* payload;
uint32_t payload_len;
} recovered_ram_crashlog_t;
// Stash as much crashlog as we can at the location pointed to by buf. The
// number of bytes stored will never exceed |buf_len|. This operation will
// overwrite any existing crashlog located at |buf|.
//
// A successfully stashed crashlog will hold the user supplied uptime and
// software reboot reason, in addition to any extra user supplied log. This
// allows users to periodically stash an uptime and "unknown" reboot reason in
// the event that the system is spontaneously rebooted by hardware (typically
// because of a watchdog timer), in addition to recording a more complete
// crashlog in the case of a software induced crash (typically due to either
// kernel panic, or a system-wide OOM condition)
//
// User supplied payload data may exist entirely outside of the user supplied
// buffer (in which case it will be copied into the proper position during the
// stow operation), or it may have been pre-rendered into the buffer by the user
// before calling stow. In the latter case, the payload pointer supplied must
// be equal to `buf + sizeof(ram_crashlog_t)`. Any other value supplied for
// |payload| which exists in the buffer region will be rejected as invalid.
//
// Params:
// |buf| : A pointer to the location to actually stow the log
// |buf_len| : The max number of bytes which may be stored at |buf|
// |payload| : The optional pointer to the payload to be stored. May be NULL.
// |payload_len| : The length of the payload buffer. Must be 0 if |payload| is NULL
// |sw_resaon| : The reason that the system crashed, according to software.
// |uptime| : Our best guess as to the uptime of the system before reboot/crash.
//
// Return Values:
// ZX_INVALID_ARGS : Something is wrong with either buf, payload, payload_len, or sw_reason
// ZX_BUFFER_TOO_SMALL : buf_len is too small to hold a crashlog, even if the payload is 0 bytes
// long.
// ZX_OK : Log was successfully stowed.
//
zx_status_t ram_crashlog_stow(void* buf, size_t buf_len, const void* payload, uint32_t payload_len,
zircon_crash_reason_t sw_reason, zx_time_t uptime);
// Attempt to recover the crashlog located at |buf|, returning details about the
// recovered log in the user-supplied log_out structure. Provided that valid
// arguments are supplied, crashlog recovery will only ever completely fail
// because of either a bad internal magic number or a corrupt header. Payloads
// with invalid lengths or invalid CRC will not result in the call to recover
// failing. Instead as much of the payload as possible will be supplied to the
// user, and the "payload_valid" flag in the |recovered_ram_crashlog_t| will be
// set to false to indicate that the bits cannot be completely trusted.
//
// Params:
// |buf| : A pointer to the location to recover the log from.
// |buf_len| : The max number of bytes which may be read from |buf|
// |log_out| : The user supplied structure which will hold the recovered log
// details.
//
// Return Values:
// ZX_INVALID_ARGS : Something is wrong with either buf, log_out.
// ZX_BUFFER_TOO_SMALL : buf_len is too small to hold a crashlog, even if the payload is 0 bytes
// long.
// ZX_IO_DATA_INTEGRITY : The log failed fundamental sanity checks and cannot be recovered.
// ZX_OK : Log was successfully recovered.
//
zx_status_t ram_crashlog_recover(const void* buf, size_t buf_len,
recovered_ram_crashlog_t* log_out);
__END_CDECLS
#endif // RAM_CRASHLOG_RAM_CRASHLOG_H_