diff --git a/devices/common/ofnvram.cpp b/devices/common/ofnvram.cpp new file mode 100644 index 0000000..03c8b6b --- /dev/null +++ b/devices/common/ofnvram.cpp @@ -0,0 +1,222 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-22 divingkatae and maximum + (theweirdo) spatium + +(Contact divingkatae#1017 or powermax#2286 on Discord for more info) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +/** @file Utilities for working with the Apple OpenFirmware NVRAM partition. */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +void OfNvramUtils::init() +{ + this->nvram_obj = dynamic_cast(gMachineObj->get_comp_by_name("NVRAM")); +} + +bool OfNvramUtils::validate() +{ + int i; + OfNvramHdr hdr; + + if (this->nvram_obj == nullptr) + return false; + + // read OF partition header + for (i = 0; i < sizeof(OfNvramHdr); i++) { + ((uint8_t*)&hdr)[i] = this->nvram_obj->read_byte(OF_NVRAM_OFFSET + i); + } + + // validate partition signature and version + if (BYTESWAP_16(hdr.sig) != OF_NVRAM_SIG || hdr.version != 5) + return false; + + this->size = hdr.num_pages * 256; + + if (this->size != 0x800) + return false; + + // read the entire partition into the local buffer + for (i = 0; i < this->size; i++) { + this->buf[i] = this->nvram_obj->read_byte(OF_NVRAM_OFFSET + i); + } + + // verify partition checksum + if (this->checksum_partition() ^ 0xFFFFU) + return false; + + return true; +} + +uint16_t OfNvramUtils::checksum_partition() +{ + uint32_t acc = 0; + + for (int i = 0; i < this->size; i += 2) { + acc += READ_WORD_BE_A(&this->buf[i]); + } + + return acc + (acc >> 16); +} + +void OfNvramUtils::update_partition() +{ + // set checksum in the header to zero + this->buf[4] = 0; + this->buf[5] = 0; + + // calculate new checksum + uint16_t checksum = this->checksum_partition(); + checksum = checksum ? ~checksum : 0xFFFFU; + + // stuff it into the header + WRITE_WORD_BE_A(&this->buf[4], checksum); + + // write the entire partition back to NVRAM + for (int i = 0; i < this->size; i++) { + this->nvram_obj->write_byte(OF_NVRAM_OFFSET + i, this->buf[i]); + } +} + +static const string flag_names[8] = { + "little-endian?", + "real-mode?", + "auto-boot?", + "diag-switch?", + "fcode-debug?", + "oem-banner?", + "oem-logo?", + "use-nvramrc?" +}; + +static const map> of_vars = { + // name, type, offset + {"real-base", {1, 0x10}}, + {"real-size", {1, 0x14}}, + {"virt-base", {1, 0x18}}, + {"virt-size", {1, 0x1C}}, + {"load-base", {1, 0x20}}, + {"pci-probe-list", {1, 0x24}}, + {"screen-#columns", {1, 0x28}}, + {"screen-#rows", {1, 0x2C}}, + {"selftest-#megs", {1, 0x30}}, + {"boot-device", {2, 0x34}}, + {"boot-file", {2, 0x38}}, + {"diag-device", {2, 0x3C}}, + {"diag-file", {2, 0x40}}, + {"input-device", {2, 0x44}}, + {"output-device", {2, 0x48}}, + {"oem-banner", {2, 0x4C}}, + {"oem-logo", {2, 0x50}}, + {"nvramrc", {2, 0x54}}, + {"boot-command", {2, 0x58}}, +}; + +void OfNvramUtils::printenv() +{ + int i; + + if (!this->validate()) { + cout << "Invalid OpenFirmware partition content!" << endl; + return; + } + + uint8_t of_flags = this->buf[12]; + + cout << endl; + + // print flags + for (i = 0; i < 8; i++) { + cout << setw(20) << left << flag_names[i] << + (((of_flags << i) & 0x80) ? "true" : "false") << endl; + } + + // print the remaining variables + for (auto& var : of_vars) { + auto type = std::get<0>(var.second); + auto offset = std::get<1>(var.second); + + cout << setw(20) << left << var.first; + + switch (type) { + case 1: // integer + cout << hex << READ_DWORD_BE_A(&this->buf[offset]) << endl; + break; + case 2: // string + uint16_t str_offset = READ_WORD_BE_A(&this->buf[offset]) - OF_NVRAM_OFFSET; + uint16_t str_len = READ_WORD_BE_A(&this->buf[offset+2]); + if (str_len) { + char value[32] = ""; + std::memcpy(value, (char *)&(this->buf[str_offset]), str_len); + cout << value; + } + cout << endl; + } + } + + cout << endl; +} + +void OfNvramUtils::setenv(string var_name, string value) +{ + int i, flag; + + if (!this->validate()) { + cout << "Invalid OpenFirmware partition content!" << endl; + return; + } + + for (i = 0; i < 8; i++) { + if (var_name == flag_names[i]) { + if (value == "true") + flag = 1; + else if (value == "false") + flag = 0; + else { + cout << "Invalid property value: " << value << endl; + return; + } + uint8_t flag_bit = 0x80U >> i; + uint8_t of_flags = this->buf[12]; + + if (flag) + of_flags |= flag_bit; + else + of_flags &= ~flag_bit; + + this->buf[12] = of_flags; + this->update_partition(); + cout << " ok" << endl; // mimic Forth + return; + } + } + + cout << "Changing of properties not supported yet" << endl; +} diff --git a/devices/common/ofnvram.h b/devices/common/ofnvram.h new file mode 100644 index 0000000..fad61f8 --- /dev/null +++ b/devices/common/ofnvram.h @@ -0,0 +1,61 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-22 divingkatae and maximum + (theweirdo) spatium + +(Contact divingkatae#1017 or powermax#2286 on Discord for more info) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef OF_NVRAM_H +#define OF_NVRAM_H + +#include + +/** @file Utilities for working with the Apple OpenFirmware NVRAM partition. */ + +#define OF_NVRAM_OFFSET 0x1800 +#define OF_NVRAM_SIG 0x1275 + +typedef struct { + uint16_t sig; // partition signature (= 0x1275) + uint8_t version; // header version + uint8_t num_pages; // number of memory pages + uint16_t checksum; // partition checksum + uint16_t here; // offset to the next free byte (bottom-up) + uint16_t top; // offset to the last free byte (top-down) +} OfNvramHdr; + +class OfNvramUtils { +public: + OfNvramUtils() = default; + ~OfNvramUtils() = default; + + void init(); + void printenv(); + void setenv(std::string var_name, std::string value); + +protected: + bool validate(); + uint16_t checksum_partition(); + void update_partition(); + +private: + NVram* nvram_obj = nullptr; + int size = 0; + uint8_t buf[0x800]; +}; + +#endif // OF_NVRAM_H