blob: 73edf541f710d705b71cc2a8abdfe8f0d641740a [file] [log] [blame]
// 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.
constexpr auto as_chars = [](ktl::span<ktl::byte> bytes) -> ktl::span<char> {
return {reinterpret_cast<char*>(bytes.data()), bytes.size()};
};
ktl::span<char> space = as_chars(buffer_->subspan(size_));
// Expand (or initially allocate) the buffer if it's too small.
if (space.size() < str.size()) {
// The buffer is always allocated in whole pages.
constexpr size_t kPageSize = ZX_PAGE_SIZE;
fbl::AllocChecker ac;
if (buffer_) {
buffer_.Resize(ac, buffer_.size_bytes() + kPageSize);
} else {
buffer_ = Allocation::New(ac, memalloc::Type::kPhysLog, kPageSize, kPageSize);
}
if (!ac.check()) {
RestoreStdout();
ZX_PANIC("failed to increase phys log from %#zx to %#zx bytes", buffer_.size_bytes(),
buffer_.size_bytes() + kPageSize);
}
}
size_ += str.copy(space.data(), space.size());
}
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};
}