1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/* 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
|