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
|
/* Copyright 2020 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* A place to organize workarounds for legacy RO */
#include <assert.h>
#include <stdbool.h>
#include "bkpdata.h"
#include "common.h"
#include "console.h"
#include "ec_commands.h" /* Reset cause */
#include "gpio.h"
#include "hooks.h"
#include "system.h"
#include "task.h"
#include "watchdog.h"
/* Console output macros */
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ##args)
/*
* We only patch RW to ensure that future ROs have correct behavior.
*/
#if defined(APPLY_RESET_LOOP_FIX) && defined(SECTION_IS_RW)
/*
* Add in ap-off flag to be able to detect on next boot.
* No other code in this build uses this ap-off reset flag.
*/
#define FORGE_PORFLAG_FLAGS (EC_RESET_FLAG_POWER_ON | EC_RESET_FLAG_AP_OFF)
static void wp_change_deferred(void)
{
/*
* The normal state of the reset backup register is 0, but
* we know that our override version of bkpdata_write_reset_flags
* will adjust it based on GPIO_WP's status.
*/
bkpdata_write_reset_flags(0);
}
DECLARE_DEFERRED(wp_change_deferred);
/*
* We respond to changes in the hardware write protect line in order to
* ensure this workaround is installed when it is needed and uninstalled
* when it is not needed. This ensures that we are protected during
* unexpected resets, such as pin resets or double faults.
*
* Furthermore, installing and uninstalling when needed minimizes the
* difference between our normal operating conditions and normal operating
* conditions with this ro_workaround source being included. That is to say,
* the system behavior is only altered in the less likely state, when hardware
* write protect deasserted.
*/
void wp_event(enum gpio_signal signal)
{
/*
* We must use a deferred function to call bkpdata_write_reset_flags,
* since the underlying bkpdata_write uses a mutex.
*/
hook_call_deferred(&wp_change_deferred_data, 0);
}
/*
* We intercept all changes to the reset backup register to ensure that
* our reset loop patch stays in place.
*
* This function will be called once in check_reset_cause during
* startup, which ensures proper behavior even when unexpected
* resets occurs (pin reset or exception).
*
* This function is also called from system_reset to set the final save
* reset flags, before an actual planned reset.
*/
__override void bkpdata_write_reset_flags(uint32_t save_flags)
{
/* Preserve flags in case a reset pulse occurs */
if (!gpio_get_level(GPIO_WP))
save_flags |= FORGE_PORFLAG_FLAGS;
bkpdata_write(BKPDATA_INDEX_SAVED_RESET_FLAGS, save_flags & 0xffff);
#ifdef CONFIG_STM32_EXTENDED_RESET_FLAGS
bkpdata_write(BKPDATA_INDEX_SAVED_RESET_FLAGS_2, save_flags >> 16);
#endif
}
/*
* We do not need to explicitly invoke bkpdata_write_reset_flags
* on boot, since check_reset_cause will already invoke it once on boot.
*/
static void board_init_workarounds(void)
{
gpio_disable_interrupt(GPIO_WP);
gpio_clear_pending_interrupt(GPIO_WP);
/*
* Detect our forged power-on flag and correct the current
* system reset flags.
* This does not ensure that all init functions will see
* the corrected system reset flags, so care should be taken.
*/
if ((system_get_reset_flags() & FORGE_PORFLAG_FLAGS) ==
FORGE_PORFLAG_FLAGS) {
CPRINTS("WARNING: Reset flags power-on + ap-off were forged.");
system_clear_reset_flags(FORGE_PORFLAG_FLAGS);
}
gpio_enable_interrupt(GPIO_WP);
}
/* Run one priority level higher than the main board_init in board.c */
DECLARE_HOOK(HOOK_INIT, board_init_workarounds, HOOK_PRIO_DEFAULT - 1);
#endif /* APPLY_RESET_LOOP_FIX && SECTION_IS_RW */
|