| /* Copyright 2020 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "registers.h" |
| |
| .equ PMU_STATUS_PG, (1 << 4) |
| .equ PMU_STATUS_PG_AON, (1 << 5) |
| |
| .equ PMU_PG_EN, (1 << 0) |
| .equ PMU_PG_EXIT_COMPLETE, (1 << 8) |
| |
| .equ FWST_AON_STATE_MASK, (0x7 << 24) |
| .equ FWST_AON_STATE_HALT, (0x2 << 24) |
| |
| .equ EFLAGS_NT, (1 << 14) |
| |
| .equ TSS_ESP0_OFFSET, 0x4 |
| .equ TSS_LDT_SEG_SEL_OFFSET, 0x60 |
| |
| .equ AON_CS, 0x4 |
| .equ AON_DS, 0xc |
| |
| |
| .global ipapg |
| ipapg: |
| push %ebp |
| push %edi |
| push %esi |
| push %ebx |
| mov %cr0, %eax |
| push %eax |
| mov %cr4, %eax |
| push %eax |
| |
| clts |
| |
| #write down return address for ROM |
| movl $(PMU_STATUS_PG|PMU_STATUS_PG_AON), PMU_STATUS_REG_ADDR |
| movl $out_of_pg, %eax |
| movl %eax, PMU_SCRATCHPAD0_REG_ADDR |
| movl (%eax), %eax |
| movl %eax, PMU_SCRATCHPAD1_REG_ADDR |
| |
| #enable IPAPG, we will actually enter PG on the next halt |
| movl $(PMU_PG_EN|PMU_PG_EXIT_COMPLETE), PMU_PG_EN_REG_ADDR |
| |
| #save esp so we can restore stack after returning from ROM |
| lea aon_tss, %eax |
| movl %esp, TSS_ESP0_OFFSET(%eax) |
| |
| sti |
| hlt |
| |
| #unreachable |
| |
| |
| #got out of IPAPG, jumped here from ROM if there was no abort condition |
| out_of_pg: |
| cli |
| |
| #restore stack |
| lea aon_tss, %eax |
| movl TSS_ESP0_OFFSET(%eax), %esp |
| |
| #set the nested task bit in eflags |
| pushfl |
| orl $EFLAGS_NT, (%esp) |
| popfl |
| |
| clts |
| fninit |
| |
| #restore non-volatile registers and CR0 & CR4 |
| pop %eax |
| mov %eax, %cr4 |
| pop %eax |
| mov %eax, %cr0 |
| pop %ebx |
| pop %esi |
| pop %edi |
| pop %ebp |
| |
| #check if we're indeed after IPAPG exit |
| testl $PMU_STATUS_PG, PMU_STATUS_REG_ADDR |
| jz after_pg |
| |
| #we didn't go through ROM, clear PG_EN bit and return an abort condition to AON |
| movl $0, PMU_PG_EN_REG_ADDR |
| movl $0, %eax |
| jmp return_to_aon |
| |
| after_pg: |
| #return to caller that we got ouf of PG |
| movl $1, %eax |
| |
| return_to_aon: |
| movl $0, PMU_STATUS_REG_ADDR |
| |
| #return to AON task (still with ROM GDT and segments in case of PG exit) |
| ret |
| |
| .global pg_exit_save_ctx |
| pg_exit_save_ctx: |
| sgdtl mainfw_gdt |
| str tr |
| ret |
| |
| .global pg_exit_restore_ctx |
| pg_exit_restore_ctx: |
| |
| #load RTOS GDT and AON task |
| lgdtl mainfw_gdt |
| ltr tr |
| |
| #load AON LDT and segments |
| lea aon_tss, %eax |
| lldt TSS_LDT_SEG_SEL_OFFSET(%eax) |
| mov $AON_DS, %ax |
| mov %ax, %ds |
| mov %ax, %es |
| mov %ax, %fs |
| mov %ax, %gs |
| mov %ax, %ss |
| ljmpl $AON_CS, $cont |
| |
| cont: |
| nop |
| ret |