zircon/kernel/lib/syscalls/system_x86.cc
// This thread performs the work for suspend/resume.  We use a separate thread
// rather than the invoking thread to let us lean on the context switch code
// path to persist all of the usermode thread state that is not saved on a plain
// mode switch.
This thread performs the work for suspend/resume.  We use a separate thread
rather than the invoking thread to let us lean on the context switch code
path to persist all of the usermode thread state that is not saved on a plain
mode switch.
This thread performs the work for suspend / resume . We use a separate thread rather than the invoking thread to let us lean on the context switch code path to persist all of the usermode thread state that is not saved on a plain mode switch .
zx_status_t suspend_thread(void* raw_arg) {
  auto arg = reinterpret_cast<const zx_system_powerctl_arg_t*>(raw_arg);
  uint8_t target_s_state = arg->acpi_transition_s_state.target_s_state;
  uint8_t sleep_type_a = arg->acpi_transition_s_state.sleep_type_a;
  uint8_t sleep_type_b = arg->acpi_transition_s_state.sleep_type_b;
  fbl::RefPtr<VmAspace> temp_aspace;
  x86_realmode_entry_data* bootstrap_data;
  struct x86_realmode_entry_data_registers regs;
  paddr_t bootstrap_ip;
  zx_status_t status;
  status = x86_bootstrap16_acquire(reinterpret_cast<uintptr_t>(_x86_suspend_wakeup), &temp_aspace,
                                   reinterpret_cast<void**>(&bootstrap_data), &bootstrap_ip);
  if (status != ZX_OK) {
    return status;
  }
  auto bootstrap_cleanup =
      fbl::MakeAutoCall([&bootstrap_data]() { x86_bootstrap16_release(bootstrap_data); });
  ACPI_TABLE_FACS* facs = nullptr;
  ACPI_STATUS acpi_status =
      AcpiGetTable((char*)ACPI_SIG_FACS, 1, reinterpret_cast<ACPI_TABLE_HEADER**>(&facs));
  if (acpi_status != AE_OK) {
    return ZX_ERR_BAD_STATE;
  }
  acpi_status = AcpiHwSetFirmwareWakingVector(facs, bootstrap_ip, 0);
  if (acpi_status != AE_OK) {
    return ZX_ERR_BAD_STATE;
  }
  auto wake_vector_cleanup =
      fbl::MakeAutoCall([facs]() { AcpiHwSetFirmwareWakingVector(facs, 0, 0); });
  bootstrap_data->registers_ptr = reinterpret_cast<uintptr_t>(&regs);
  interrupt_saved_state_t int_state = arch_interrupt_save();
  platform_suspend();
  arch_suspend();
  TRACEF("Entering x86_acpi_transition_s_state\n");
  acpi_status = x86_acpi_transition_s_state(&regs, target_s_state, sleep_type_a, sleep_type_b);
  if (acpi_status != AE_OK) {
    arch_interrupt_restore(int_state);
    TRACEF("x86_acpi_transition_s_state failed: %x\n", acpi_status);
    return ZX_ERR_INTERNAL;
  }
  TRACEF("Left x86_acpi_transition_s_state\n");
  DEBUG_ASSERT(arch_ints_disabled());
  arch_resume();
  platform_resume();
  percpu::Get(arch_curr_cpu_num()).timer_queue.ThawPercpu();
  DEBUG_ASSERT(arch_ints_disabled());
  arch_interrupt_restore(int_state);
  return ZX_OK;
}
zx_status_t suspend_thread ( void * raw_arg ) { auto arg = reinterpret_cast < const zx_system_powerctl_arg_t * > ( raw_arg ) ; uint8_t target_s_state = arg -> acpi_transition_s_state . target_s_state ; uint8_t sleep_type_a = arg -> acpi_transition_s_state . sleep_type_a ; uint8_t sleep_type_b = arg -> acpi_transition_s_state . sleep_type_b ; fbl :: RefPtr < VmAspace > temp_aspace ; x86_realmode_entry_data * bootstrap_data ; struct x86_realmode_entry_data_registers regs ; paddr_t bootstrap_ip ; zx_status_t status ; status = x86_bootstrap16_acquire ( reinterpret_cast < uintptr_t > ( _x86_suspend_wakeup ) , & temp_aspace , reinterpret_cast < void * * > ( & bootstrap_data ) , & bootstrap_ip ) ; if ( status != ZX_OK ) { return status ; } auto bootstrap_cleanup = fbl :: MakeAutoCall ( [ & bootstrap_data ] ( ) { x86_bootstrap16_release ( bootstrap_data ) ; } ) ; ACPI_TABLE_FACS * facs = nullptr ; ACPI_STATUS acpi_status = AcpiGetTable ( ( char * ) ACPI_SIG_FACS , 1 , reinterpret_cast < ACPI_TABLE_HEADER * * > ( & facs ) ) ; if ( acpi_status != AE_OK ) { return ZX_ERR_BAD_STATE ; } acpi_status = AcpiHwSetFirmwareWakingVector ( facs , bootstrap_ip , 0 ) ; if ( acpi_status != AE_OK ) { return ZX_ERR_BAD_STATE ; } auto wake_vector_cleanup = fbl :: MakeAutoCall ( [ facs ] ( ) { AcpiHwSetFirmwareWakingVector ( facs , 0 , 0 ) ; } ) ; bootstrap_data -> registers_ptr = reinterpret_cast < uintptr_t > ( & regs ) ; interrupt_saved_state_t int_state = arch_interrupt_save ( ) ; platform_suspend ( ) ; arch_suspend ( ) ; TRACEF ( " \n " ) ; acpi_status = x86_acpi_transition_s_state ( & regs , target_s_state , sleep_type_a , sleep_type_b ) ; if ( acpi_status != AE_OK ) { arch_interrupt_restore ( int_state ) ; TRACEF ( " \n " , acpi_status ) ; return ZX_ERR_INTERNAL ; } TRACEF ( " \n " ) ; DEBUG_ASSERT ( arch_ints_disabled ( ) ) ; arch_resume ( ) ; platform_resume ( ) ; percpu :: Get ( arch_curr_cpu_num ( ) ) . timer_queue . ThawPercpu ( ) ; DEBUG_ASSERT ( arch_ints_disabled ( ) ) ; arch_interrupt_restore ( int_state ) ; return ZX_OK ; }
This thread performs the work for suspend/resume.
This thread performs the work for suspend / resume .
// Acquire resources for suspend and resume if necessary. // Setup our resume path // Save system state. // Do the actual suspend // If we're here, we've resumed and need to restore our CPU context