blob: 7976cebc245ae6191451455834e15df93c834b13 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_VM_INCLUDE_VM_PMM_CHECKER_H_
#define ZIRCON_KERNEL_VM_INCLUDE_VM_PMM_CHECKER_H_
#include <stdio.h>
#include <arch/defines.h>
#include <ktl/atomic.h>
#include <ktl/optional.h>
#include <vm/page.h>
// |PmmChecker| is used to detect memory corruption. It is logically part of |PmmNode|.
//
// Usage is as follows:
//
// PmmChecker checker;
//
// // Check only the first 16 bytes of each page.
// checker.SetFillSize(16);
//
// // For all free pages...
// for (...) {
// checker.FillPattern(page);
// }
//
// // Now that all free pages have been filled with a pattern, we can arm the checker.
// checker.Arm();
// ...
// checker.AssertPattern(page);
//
class PmmChecker {
public:
// The action to take when page validation fails.
enum class Action : uint32_t { OOPS, PANIC };
static constexpr Action DefaultAction = Action::OOPS;
// Returns ktl::nullopt if |action_string| is invalid.
static ktl::optional<Action> ActionFromString(const char* action_string);
static const char* ActionToString(Action action);
// Returns true if |fill_size| is a valid value. Valid values are mutliples of 8 between 8 and
// PAGE_SIZE, inclusive.
static bool IsValidFillSize(size_t fill_size);
// Sets the size of the pattern to be written / validated.
//
// It is an error to call this method with an invalid fill size (see |IsValidFillSize|.
//
// It is an error to call this method if the checker |IsArmed|. After changing the fill size, be
// sure to re-fill any free pages to ensure that a future call to |ValidatePattern| or
// |AssertPattern| won't supriously report corruption.
void SetFillSize(size_t fill_size);
// Returns the fill size.
size_t GetFillSize() const { return fill_size_; }
void SetAction(Action action) { action_ = action; }
Action GetAction() const { return action_; }
// Returns true if armed.
bool IsArmed() const { return armed_; }
void Arm();
void Disarm();
void PrintStatus(FILE* f) const;
// Fills |page| with a pattern.
//
// It is an error to call this method with a page that is not free. In other words,
// page->is_page() must be true.
void FillPattern(vm_page_t* page);
// Returns true if |page| contains the expected fill pattern or |IsArmed| is false.
//
// Otherwise, returns false.
__WARN_UNUSED_RESULT bool ValidatePattern(vm_page_t* page);
// Panics the kernel if |page| does not contain the expected fill pattern and |IsArmed| is true.
//
// Otherwise, does nothing.
void AssertPattern(vm_page_t* page);
static int64_t get_validation_failed_count();
private:
// The number of bytes to fill/validate.
size_t fill_size_ = PAGE_SIZE;
Action action_ = DefaultAction;
bool armed_ = false;
};
#endif // ZIRCON_KERNEL_VM_INCLUDE_VM_PMM_CHECKER_H_