Skip to content

Commit 05a8aa2

Browse files
authored
Merge pull request #2851 from particle-iot/fix/cxa-acquire-atexit-and-gen3-stack
[Gen 3] stack size fixes, __cxa_acquire/release/atexit refactoring
2 parents a3f2fea + 7ce7da1 commit 05a8aa2

33 files changed

+368
-211
lines changed

bootloader/src/nRF52840/linker.ld

+4
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,7 @@ ASSERT (
196196
"Stack should be 8-byte aligned!"
197197
);
198198

199+
ASSERT (
200+
(platform_bootloader_stack_size == __STACKSIZE__),
201+
"platform_bootloader_stack_size does not match __STACKSIZE__"
202+
);

bootloader/src/nRF52840/newlib.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ int __cxa_atexit(void (*f)(void *), void *p, void *d) {
101101
return 0;
102102
}
103103

104+
void __register_exitproc(int type, void (*fn)(void), void* arg, void* d) {
105+
}
106+
104107
int _write(int file, char *ptr, int len) { return 0; }
105108
int _read(int file, char *ptr, int len) { return 0; }
106109
int _close(int file) { return 0; }

bootloader/src/rtl872x/linker.ld

+5
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,8 @@ link_stack_location = platform_bootloader_stack_start;
265265
link_stack_end = platform_bootloader_stack_end;
266266

267267
INCLUDE linker_rtl872x_rom_s.ld
268+
269+
ASSERT (
270+
(platform_bootloader_stack_size == __STACKSIZE__),
271+
"platform_bootloader_stack_size does not match __STACKSIZE__"
272+
);

bootloader/src/rtl872x/newlib.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ int __cxa_atexit(void (*f)(void *), void *p, void *d) {
101101
return 0;
102102
}
103103

104+
void __register_exitproc(int type, void (*fn)(void), void* arg, void* d) {
105+
}
106+
104107
int _write(int file, char *ptr, int len) { return 0; }
105108
int _read(int file, char *ptr, int len) { return 0; }
106109
int _close(int file) { return 0; }

build/arm/linker/nrf52840/platform_ram.ld

+5-5
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,22 @@ platform_system_backup_ram_start = platform_system_backup_ram_end - platform_sys
5959

6060

6161
/* Modular firmware main stack
62-
* platform_modular_firmware_stack_size is equal to 2K, which is defined in part1_build.mk and user_build.mk under modules/shared/nRF52840.
62+
* platform_modular_firmware_stack_size is equal to 4K, which is defined in part1_build.mk and user_build.mk under modules/shared/nRF52840.
6363
* platform_modular_firmware_stack_start is the lowest address of the stack. */
64-
platform_modular_firmware_stack_size = __STACKSIZE__;
64+
platform_modular_firmware_stack_size = 4K;
6565
platform_modular_firmware_stack_end = platform_system_backup_ram_start;
6666
platform_modular_firmware_stack_start = platform_modular_firmware_stack_end - platform_modular_firmware_stack_size;
6767

6868
/* Monolithic firmware main stack
69-
* platform_monolithic_firmware_stack_size is equal to 2K, which is defined in include.mk under hal/src/nRF52840.
69+
* platform_monolithic_firmware_stack_size is equal to 4K, which is defined in include.mk under hal/src/nRF52840.
7070
* platform_monolithic_firmware_stack_start is the lowest address of the stack. */
71-
platform_monolithic_firmware_stack_size = __STACKSIZE__;
71+
platform_monolithic_firmware_stack_size = 4K;
7272
platform_monolithic_firmware_stack_end = platform_system_backup_ram_start;
7373
platform_monolithic_firmware_stack_start = platform_monolithic_firmware_stack_end - platform_monolithic_firmware_stack_size;
7474

7575
/* Bootloader main stack
7676
* platform_bootloader_stack_size is equal to 8K, which is defined in bootloader/src/nRF52840/include.mk. */
77-
platform_bootloader_stack_size = __STACKSIZE__;
77+
platform_bootloader_stack_size = 8K;
7878
platform_bootloader_stack_end = platform_system_backup_ram_start;
7979
platform_bootloader_stack_start = platform_bootloader_stack_end - platform_bootloader_stack_size;
8080

build/arm/linker/rtl872x/platform_ram.ld

+7-7
Original file line numberDiff line numberDiff line change
@@ -89,28 +89,28 @@ platform_system_retention_ram_end = platform_system_retention_ram_start + platfo
8989
/* Modular firmware main stack
9090
* platform_modular_firmware_stack_size is equal to 8K, which is defined in part1_build.mk and user_build.mk under modules/shared/rtl872x.
9191
* platform_modular_firmware_stack_start is the lowest address of the stack. */
92-
platform_modular_firmware_stack_size = __STACKSIZE__;
92+
platform_modular_firmware_stack_size = 8K;
9393
platform_modular_firmware_stack_end = platform_ram_start;
9494
platform_modular_firmware_stack_start = platform_modular_firmware_stack_end - platform_modular_firmware_stack_size;
9595

96-
platform_modular_firmware_secure_stack_size = __STACKSIZE__;
96+
platform_modular_firmware_secure_stack_size = 8K;
9797
platform_modular_firmware_secure_stack_end = platform_secure_ram_end;
9898
platform_modular_firmware_secure_stack_start = platform_modular_firmware_secure_stack_end - platform_modular_firmware_secure_stack_size;
9999

100100
/* Monolithic firmware main stack
101-
* platform_monolithic_firmware_stack_size is equal to 4K, which is defined in include.mk under hal/src/rtl872x.
101+
* platform_monolithic_firmware_stack_size is equal to 8K, which is defined in include.mk under hal/src/rtl872x.
102102
* platform_monolithic_firmware_stack_start is the lowest address of the stack. */
103-
platform_monolithic_firmware_stack_size = __STACKSIZE__;
103+
platform_monolithic_firmware_stack_size = 8K;
104104
platform_monolithic_firmware_stack_end = platform_ram_start;
105105
platform_monolithic_firmware_stack_start = platform_monolithic_firmware_stack_end - platform_monolithic_firmware_stack_size;
106106

107-
platform_monolithic_firmware_secure_stack_size = __STACKSIZE__;
107+
platform_monolithic_firmware_secure_stack_size = 8K;
108108
platform_monolithic_firmware_secure_stack_end = platform_secure_ram_end;
109109
platform_monolithic_firmware_secure_stack_start = platform_monolithic_firmware_secure_stack_end - platform_monolithic_firmware_secure_stack_size;
110110

111111
/* Bootloader main stack
112-
* platform_bootloader_stack_size is equal to 4K, which is defined in bootloader/src/rtl872x/include.mk. */
113-
platform_bootloader_stack_size = __STACKSIZE__;
112+
* platform_bootloader_stack_size is equal to 8K, which is defined in bootloader/src/rtl872x/include.mk. */
113+
platform_bootloader_stack_size = 8K;
114114
platform_bootloader_stack_end = platform_secure_ram_end;
115115
platform_bootloader_stack_start = platform_bootloader_stack_end - platform_bootloader_stack_size;
116116

hal/inc/hal_platform.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@
440440
#endif // HAL_PLATFORM_USART_DEFAULT_BUFFER_SIZE
441441

442442
#ifndef HAL_PLATFORM_EXPORT_STDLIB_RT_DYNALIB
443-
#define HAL_PLATFORM_EXPORT_STDLIB_RT_DYNALIB (0)
443+
#define HAL_PLATFORM_EXPORT_STDLIB_RT_DYNALIB (1)
444444
#endif // HAL_PLATFORM_EXPORT_STDLIB_RT_DYNALIB
445445

446446
#ifndef HAL_PLATFORM_POWER_MANAGEMENT_PMIC_WATCHDOG

hal/shared/cxx_abi.cpp

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright (c) 2018 Particle Industries, Inc. All rights reserved.
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation, either
7+
* version 3 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include <cxxabi.h>
19+
#include <stdint.h>
20+
#include "service_debug.h"
21+
#include "static_recursive_mutex.h"
22+
#include "interrupts_hal.h"
23+
#include "static_event_group.h"
24+
#include "concurrent_hal.h"
25+
#include <mutex>
26+
27+
/* __guard type is already defined in cxxabi_tweaks.h for each architecture */
28+
using __cxxabiv1::__guard;
29+
30+
namespace {
31+
32+
/* Using a global recursive mutex, should be enough for our use-cases */
33+
StaticRecursiveMutex s_mutex;
34+
StaticEventGroup s_event_group;
35+
36+
struct __attribute__((packed)) guard_t {
37+
/* Normally this is:
38+
* Guard Object Layout:
39+
* ---------------------------------------------------------------------------
40+
* | a+0: guard byte | a+1: init byte | a+2: unused ... | a+4: thread-id ... |
41+
* ---------------------------------------------------------------------------
42+
* On ARM this is just 4 bytes
43+
* */
44+
uint8_t done;
45+
uint8_t init;
46+
uint8_t wait_count;
47+
48+
enum GuardFlags : uint8_t {
49+
NONE = 0,
50+
COMPLETE = 0x01,
51+
PENDING = 0x02,
52+
WAITING = 0x04
53+
};
54+
};
55+
56+
static_assert(sizeof(guard_t) <= sizeof(__guard), "guard is too large");
57+
58+
} /* anonymous */
59+
60+
/* http://refspecs.linuxbase.org/cxxabi-1.86.html#once-ctor */
61+
62+
extern "C" {
63+
64+
int __cxa_guard_acquire(__guard* g) {
65+
guard_t* guard = reinterpret_cast<guard_t*>(g);
66+
67+
SPARK_ASSERT(!hal_interrupt_is_isr());
68+
69+
/* Acquire mutex */
70+
std::unique_lock<StaticRecursiveMutex> lk(s_mutex);
71+
72+
while (true) {
73+
// Nothing to do here, already initialized
74+
if (guard->done) {
75+
return 0;
76+
}
77+
78+
if (guard->init & guard_t::PENDING) {
79+
// Pending initialization
80+
// We need to wait for initialization to complete
81+
// Scheduler MUST be running
82+
auto scheduler = os_scheduler_get_state(nullptr);
83+
SPARK_ASSERT(scheduler == OS_SCHEDULER_STATE_RUNNING);
84+
85+
guard->init |= guard_t::WAITING;
86+
guard->wait_count++;
87+
lk.unlock();
88+
s_event_group.wait(guard_t::COMPLETE, StaticEventGroup::Flag::CLEAR_ON_EXIT);
89+
lk.lock();
90+
guard->wait_count--;
91+
if (guard->wait_count == 0) {
92+
s_event_group.set(guard_t::WAITING);
93+
}
94+
} else {
95+
// Set pending flag continue with initialization
96+
guard->init |= guard_t::PENDING;
97+
return 1;
98+
}
99+
}
100+
return 0;
101+
}
102+
103+
void __cxa_guard_release(__guard* g) {
104+
guard_t* guard = reinterpret_cast<guard_t*>(g);
105+
SPARK_ASSERT(!hal_interrupt_is_isr());
106+
107+
std::unique_lock<StaticRecursiveMutex> lk(s_mutex);
108+
guard->init &= ~(guard_t::PENDING);
109+
guard->done = guard_t::COMPLETE;
110+
guard->init |= guard_t::COMPLETE;
111+
if ((guard->init & guard_t::WAITING) && guard->wait_count > 0) {
112+
// This will wake all threads waiting on initialization completion
113+
s_event_group.set(guard_t::COMPLETE);
114+
} else {
115+
return;
116+
}
117+
118+
while (guard->wait_count > 0) {
119+
lk.unlock();
120+
// FIXME: not ideal, but we'll spin with 10ms delay
121+
auto ev = s_event_group.sync(guard_t::COMPLETE, guard_t::WAITING, 10);
122+
lk.lock();
123+
if (ev & guard_t::WAITING) {
124+
s_event_group.clear(guard_t::WAITING);
125+
}
126+
}
127+
}
128+
129+
void __cxa_guard_abort (__guard*) {
130+
/* We do not have exceptions enabled. This should not have happened */
131+
SPARK_ASSERT(false);
132+
}
133+
134+
void __cxa_pure_virtual() {
135+
PANIC(PureVirtualCall, "Call on pure virtual");
136+
while (1);
137+
}
138+
139+
} // extern "C"

hal/shared/cxx_abi.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2024 Particle Industries, Inc. All rights reserved.
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation, either
7+
* version 3 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#pragma once
19+
20+
#ifdef __cplusplus
21+
#include <cxxabi.h>
22+
extern "C" {
23+
using __cxxabiv1::__guard;
24+
#else
25+
typedef void __guard;
26+
#endif // __cplusplus
27+
28+
int __cxa_guard_acquire(__guard* g);
29+
void __cxa_guard_release(__guard* g);
30+
void __cxa_guard_abort(__guard* g);
31+
32+
#ifdef __cplusplus
33+
}
34+
#endif // __cplusplus

hal/shared/static_event_group.h

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2024 Particle Industries, Inc. All rights reserved.
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation, either
7+
* version 3 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#pragma once
19+
#include "hal_platform.h"
20+
#include <FreeRTOS.h>
21+
#include <event_groups.h>
22+
#include "system_tick_hal.h"
23+
#include "enumflags.h"
24+
25+
class StaticEventGroup {
26+
public:
27+
enum class Flag {
28+
NONE = 0x00,
29+
CLEAR_ON_EXIT = 0x01,
30+
WAIT_ALL = 0x02
31+
};
32+
33+
typedef particle::EnumFlags<Flag> Flags;
34+
35+
StaticEventGroup() {
36+
handle_ = xEventGroupCreateStatic(&eventGroupBuffer_);
37+
SPARK_ASSERT(handle_);
38+
}
39+
40+
~StaticEventGroup() {
41+
vEventGroupDelete(handle_);
42+
}
43+
44+
uint32_t wait(uint32_t bits, system_tick_t wait = portMAX_DELAY, Flags f = Flag::NONE) {
45+
SPARK_ASSERT(!hal_interrupt_is_isr());
46+
return xEventGroupWaitBits(handle_, bits, f & Flag::CLEAR_ON_EXIT, f & Flag::WAIT_ALL, wait);
47+
}
48+
49+
uint32_t wait(uint32_t bits, Flags f = Flag::NONE) {
50+
return wait(bits, portMAX_DELAY, f);
51+
}
52+
53+
uint32_t clear(uint32_t bits) {
54+
SPARK_ASSERT(!hal_interrupt_is_isr());
55+
return xEventGroupClearBits(handle_, bits);
56+
}
57+
58+
uint32_t set(uint32_t bits) {
59+
SPARK_ASSERT(!hal_interrupt_is_isr());
60+
return xEventGroupSetBits(handle_, bits);
61+
}
62+
63+
uint32_t sync(uint32_t setBits, uint32_t waitBits, system_tick_t wait = portMAX_DELAY) {
64+
SPARK_ASSERT(!hal_interrupt_is_isr());
65+
return xEventGroupSync(handle_, setBits, waitBits, wait);
66+
}
67+
68+
private:
69+
EventGroupHandle_t handle_;
70+
StaticEventGroup_t eventGroupBuffer_;
71+
};
72+
73+
namespace particle {
74+
75+
ENABLE_ENUM_CLASS_BITWISE(StaticEventGroup::Flag);
76+
77+
} // particle

0 commit comments

Comments
 (0)