Add support for the CUDA_RESTART_SYSTEM command

There are cases where when it's necessary (e.g. given uninitialized NVRAM,
the Beige G3 with the 10.2 install CD inserted will update the boot
device and restart to boot from it).

Restart support was done by wrapping the ppc_exec function in a loop and
checking for a restart power off reason. We also need to disconnect all
event listeners, since they will be recreated when the machine is
re-initialized.
This commit is contained in:
Mihai Parparita 2024-03-07 23:30:55 -08:00
parent c7d2eb87ac
commit 57e6e90002
6 changed files with 53 additions and 13 deletions

View File

@ -58,6 +58,14 @@ public:
}
}
void disconnect(int id) {
_slots.erase(id);
}
void disconnect_all() {
_slots.clear();
}
private:
mutable std::map<int, std::function<void(Args...)>> _slots;
mutable unsigned int _current_id { 0 };

View File

@ -94,6 +94,13 @@ public:
_post_signal.connect_method(inst, func);
}
void disconnect_handlers() {
_window_signal.disconnect_all();
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_post_signal.disconnect_all();
}
private:
static EventManager* event_manager;
EventManager() {}; // private constructor to implement a singleton

View File

@ -322,6 +322,8 @@ enum Po_Cause : int {
po_starting_up,
po_shut_down,
po_shutting_down,
po_restarting,
po_restart,
po_disassemble_on,
po_disassemble_off,
po_enter_debugger,

View File

@ -458,6 +458,10 @@ void enter_debugger() {
power_off_reason = po_shutting_down;
break;
}
if (power_off_reason == po_restart) {
power_off_reason = po_restarting;
break;
}
power_on = true;
if (power_off_reason == po_starting_up) {

View File

@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/hostevents.h>
#include <core/timermanager.h>
#include <devices/common/adb/adbbus.h>
#include <cpu/ppc/ppcemu.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/viacuda.h>
#include <devices/deviceregistry.h>
@ -654,10 +655,14 @@ void ViaCuda::pseudo_command(int cmd, int data_count) {
LOG_F(INFO, "Cuda: send %d to PB0", (int)(this->in_buf[2]));
response_header(CUDA_PKT_PSEUDO, 0);
break;
case CUDA_RESTART_SYSTEM:
LOG_F(INFO, "Cuda: system restart");
power_on = false;
power_off_reason = po_restart;
break;
case CUDA_WARM_START:
case CUDA_POWER_DOWN:
case CUDA_MONO_STABLE_RESET:
case CUDA_RESTART_SYSTEM:
/* really kludge temp code */
LOG_F(INFO, "Cuda: Restart/Shutdown signal sent with command 0x%x!", cmd);
//exit(0);

View File

@ -61,6 +61,8 @@ static string appDescription = string(
"\n"
);
void run_machine(std::string machine_str, std::string bootrom_path, uint32_t execution_mode);
int main(int argc, char** argv) {
uint32_t execution_mode = interpreter;
@ -166,10 +168,6 @@ int main(int argc, char** argv) {
// initialize global profiler object
gProfilerObj.reset(new Profiler());
if (MachineFactory::create_machine_for_id(machine_str, bootrom_path) < 0) {
goto bail;
}
// graceful handling of fatal errors
loguru::set_fatal_handler([](const loguru::Message& message) {
// Make sure the reason for the failure is visible (it may have been
@ -187,9 +185,29 @@ int main(int argc, char** argv) {
// redirect SIGABRT to our own handler
signal(SIGABRT, sigabrt_handler);
while (true) {
run_machine(machine_str, bootrom_path, execution_mode);
if (power_off_reason == po_restarting) {
LOG_F(INFO, "Restarting...");
power_on = true;
continue;
}
break;
}
cleanup();
return 0;
}
void run_machine(std::string machine_str, std::string bootrom_path, uint32_t execution_mode) {
if (MachineFactory::create_machine_for_id(machine_str, bootrom_path) < 0) {
return;
}
// set up system wide event polling using
// default Macintosh polling rate of 11 ms
TimerManager::get_instance()->add_cyclic_timer(MSECS_TO_NSECS(11), [] {
uint32_t event_timer = TimerManager::get_instance()->add_cyclic_timer(MSECS_TO_NSECS(11), [] {
EventManager::get_instance()->poll_events();
});
@ -204,15 +222,11 @@ int main(int argc, char** argv) {
break;
default:
LOG_F(ERROR, "Invalid EXECUTION MODE");
return 1;
return;
}
bail:
LOG_F(INFO, "Cleaning up...");
TimerManager::get_instance()->cancel_timer(event_timer);
EventManager::get_instance()->disconnect_handlers();
delete gMachineObj.release();
cleanup();
return 0;
}