I've long moaned about how my Go3 can't reboot. Woe is me. Now that kettenis@ landed some scaffolding for efi(4), I would love to get my Go3 working in the reboot department.
The approach I'm thinking, in the diff below, is to hook in via comparing the FirmwareVendor "string" to make sure we're doing this on amd64-based Microsoft EFI systems. The last time we went down this route, we found reports of arbitrarily switching EFI systems over to efi_reset caused reboots to break on machines that had been happily using acpi_reset. The struggle is real. I only have access to my Go3, so would appreciate someone else with a Surface brand device check for regression before I ask for OK. Feedback from kettenis@ also welcome. If your Surface has the same problem as mine, what you experience is having to do a powerdown (e.g. halt -p) in order to reset the machine. A reboot causes the machine to reset, but get stuck bringing itself back up and you stare at the MSFT logo splash until your battery runs out or you die of boredom. -dv diff refs/heads/master refs/heads/efi-powerdown commit - 009dd187d54193e7f98e87ccd11c616924278c5e commit + c6f9dc35c81aa79313b1ad12bfcdacfb6074803d blob - 502bd70a7eddbb271ee54b5888867c4ffd7a8426 blob + c53604d2c38321bd3151a9008560ce52d3034fec --- sys/arch/amd64/amd64/acpi_machdep.c +++ sys/arch/amd64/amd64/acpi_machdep.c @@ -334,7 +334,8 @@ acpi_attach_machdep(struct acpi_softc *sc) sc->sc_interrupt = isa_intr_establish(NULL, sc->sc_fadt->sci_int, IST_LEVEL, IPL_BIO, acpi_interrupt, sc, sc->sc_dev.dv_xname); - cpuresetfn = acpi_reset; + if (!cpuresetfn) + cpuresetfn = acpi_reset; #ifndef SMALL_KERNEL /* blob - a5f4563ce7d54e53c9aaadf2823b35d36cd3b1e9 blob + 88aa3f343f059136b1cfd842717ac1ff1fcec3c0 --- sys/arch/amd64/amd64/efi_machdep.c +++ sys/arch/amd64/amd64/efi_machdep.c @@ -39,12 +39,18 @@ void efi_map_runtime(struct efi_softc *); sizeof(struct efi_softc), efi_match, efi_attach }; +extern struct cfdriver efi_cd; + void efi_map_runtime(struct efi_softc *); int efi_gettime(struct todr_chip_handle *, struct timeval *); int efi_settime(struct todr_chip_handle *, struct timeval *); +void efi_reset(void); label_t efi_jmpbuf; +const CHAR16 fv_msft[5] = { 'M', 'S', 'F', 'T', 0 }; +extern void (*cpuresetfn)(void); + int efi_match(struct device *parent, void *match, void *aux) { @@ -119,6 +125,9 @@ efi_attach(struct device *parent, struct device *self, for (i = 0; st->FirmwareVendor[i]; i++) printf("%c", st->FirmwareVendor[i]); printf(" rev 0x%x\n", st->FirmwareRevision); + + if (memcmp(st->FirmwareVendor, fv_msft, sizeof(fv_msft)) == 0) + cpuresetfn = efi_reset; } efi_leave(sc); @@ -305,3 +314,14 @@ efi_settime(struct todr_chip_handle *handle, struct ti return EIO; return 0; } + +void +efi_reset(void) +{ + struct efi_softc *sc = efi_cd.cd_devs[0]; + + printf("%s\n", __func__); + efi_enter(sc); + sc->sc_rs->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + efi_leave(sc); +}