blob: 83e67840b4ff07a67b7cce98ea71f995751b009f [file] [log] [blame] [edit]
// Copyright 2022 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
#include "log.h"
#include <lib/boot-options/boot-options.h>
#include <zircon/limits.h>
Log* gLog;
int Log::Write(ktl::string_view str) {
// Always write to the live console first.
if (mirror_) {
mirror_.Write(str);
}
AppendToLog(str);
return static_cast<int>(str.size());
}
void Log::SetStdout() {
ZX_ASSERT(*stdout != FILE{this});
ZX_ASSERT(!mirror_);
mirror_ = *stdout;
*stdout = FILE{this};
}
void Log::RestoreStdout() {
if (*stdout == FILE{this}) {
*stdout = mirror_;
mirror_ = FILE{};
}
}
void Log::AppendToLog(ktl::string_view str) {
// Use the remaining space in the existing buffer, or make more space.
auto make_space = [this](size_t needed) -> ktl::span<char> {
if (ktl::span space = buffer_chars_left(); space.size() >= needed) {
return space;
}
// Expand (or initially allocate) the buffer if it's too small.
// The buffer is always allocated in whole pages.
constexpr size_t kPageSize = ZX_PAGE_SIZE;
const size_t expand_size = (needed + kPageSize - 1) & -kPageSize;
fbl::AllocChecker ac;
if (buffer_) {
buffer_.Resize(ac, buffer_.size_bytes() + expand_size);
} else {
buffer_ = Allocation::New(ac, memalloc::Type::kPhysLog, expand_size, kPageSize);
}
if (!ac.check()) {
RestoreStdout();
ZX_PANIC("failed to increase phys log from %#zx to %#zx bytes", buffer_.size_bytes(),
buffer_.size_bytes() + expand_size);
}
return buffer_chars_left();
};
ktl::span<char> space = make_space(str.size());
size_t copied = str.copy(space.data(), space.size());
ZX_DEBUG_ASSERT(copied == str.size());
size_ += copied;
}
FILE Log::LogOnlyFile() {
return FILE{[](void* log, ktl::string_view str) {
static_cast<Log*>(log)->AppendToLog(str);
return static_cast<int>(str.size());
},
this};
}
FILE Log::VerboseOnlyFile() {
if (gBootOptions && !gBootOptions->phys_verbose) {
return LogOnlyFile();
}
return FILE{this};
}