Commit graph

2344 commits

Author SHA1 Message Date
Ioannis Glaropoulos
e08dfec77c arch: arm: cortex-m: add ARM-only API to set all IRQS to Non-Secure
We implement an ARM-only API for ARM Secure Firmware,
to set all NVIC IRQ lines to target the Non-Secure state.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-09-02 15:01:30 +02:00
Ioannis Glaropoulos
4ec7725110 arch: arm: cortex-m: Modify ARM-only API for IRQ target state mgmt
we modify the ARM Cortex-M only API for managing the
security target state of the NVIC IRQs. We remove the
internal ASSERT checking allowing to call the API for
non-implemented NVIC IRQ lines. However we still give the
option to the user to check the success of the IRQ target
state setting operation by allowing the API function to
return the resulting target state.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-09-02 15:01:30 +02:00
Tomasz Bursztyka
93cd336204 arch: Apply dynamic IRQ API change
Switching to constant parameter.

Fixes #27399

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2020-09-02 13:48:13 +02:00
Tomasz Bursztyka
7def6eeaee arch: Apply IRQ offload API change
Switching to constant parameter.

Fixes #27399

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2020-09-02 13:48:13 +02:00
Tomasz Bursztyka
e18fcbba5a device: Const-ify all device driver instance pointers
Now that device_api attribute is unmodified at runtime, as well as all
the other attributes, it is possible to switch all device driver
instance to be constant.

A coccinelle rule is used for this:

@r_const_dev_1
  disable optional_qualifier
@
@@
-struct device *
+const struct device *

@r_const_dev_2
 disable optional_qualifier
@
@@
-struct device * const
+const struct device *

Fixes #27399

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2020-09-02 13:48:13 +02:00
Chris Coleman
99a268fa16 arch: arm: Collect full register state in Cortex-M Exception Stack Frame
To debug hard-to-reproduce faults/panics, it's helpful to get the full
register state at the time a fault occurred. This enables recovering
full backtraces and the state of local variables at the time of a
crash.

This PR introduces a new Kconfig option, CONFIG_EXTRA_EXCEPTION_INFO,
to facilitate this use case. The option enables the capturing of the
callee-saved register state (r4-r11 & exc_return) during a fault. The
info is forwarded to `k_sys_fatal_error_handler` in the z_arch_esf_t
parameter. From there, the data can be saved for post-mortem analysis.

To test the functionality a new unit test was added to
tests/arch/arm_interrupt which verifies the register contents passed
in the argument match the state leading up to a crash.

Signed-off-by: Chris Coleman <chris@memfault.com>
2020-08-31 10:13:27 +02:00
Andrew Boie
00f71b0d63 kernel: add CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API
Saves us a few bytes of program text on arches that don't need
these implemented, currently all uniprocessor MPU-based systems.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-08-26 20:35:02 -04:00
Andrew Boie
2222fa1426 arm: fix memory domain arch_ API implementations
All of these should be no-ops for the following reasons:

1. User threads cannot configure memory domains, only supervisor
   threads.
2. The scope of memory domains is user thread memory access,
   supervisor threads can access the entire memory map.

Hence it's never required to reprogram the MPU when a memory domain
API is called.

Fixes a problem where an assertion would fail if a supervisor thread
added a partition and then immediately removes it, and possibly
other problems.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-08-26 20:35:02 -04:00
Andrew Boie
91f1bb5414 arm: clarify a memory domain assertion
Dump the partition information to make this assertion
less ambiguous.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-08-26 20:35:02 -04:00
Daniel Leung
181d07321f coredump: add support for ARM Cortex-M
This adds the necessary bits in arch code, and Python scripts
to enable coredump support for ARM Cortex-M.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2020-08-24 20:28:24 -04:00
Anas Nashif
b234660f4f tracing: cortex_a53: fix order of swap tracing
We had switched_in and switched_out mixed up.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2020-08-24 13:21:12 +02:00
Carlo Caione
310057d641 arch: arm64: Parametrize registers usage for z_arm64_{enter,exit}_exc
Make explicit what registers we are going to be touched / modified when
using z_arm64_enter_exc and z_arm64_exit_exc.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2020-08-18 15:17:39 +02:00
Carlo Caione
d187830929 arch: arm64: Rework registers allocation
Rationalize the registers usage trying to reuse the smallest set of
registers possible.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
2020-08-18 15:17:39 +02:00
Andrew Boie
ed972b9582 arm: remove custom k_thread_abort() for Cortex-R
The default implementation is the same as this custom
one now, as the assertion that the context switch occurs
at the end of the ISR is true for all arches.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-08-18 08:36:35 +02:00
Henrik Brix Andersen
e7f51fa918 arch: arm: aarch32: add support for Cortex-M1
Add support for the ARM Cortex-M1 CPU.

Signed-off-by: Henrik Brix Andersen <henrik@brixandersen.dk>
2020-08-14 13:35:39 -05:00
Anas Nashif
ce59510127 arch: xip: cleanup XIP Kconfig
unify how XIP is configured across architectures. Use imply instead of
setting defaults per architecture and imply XIP on riscv arch and remove
XIP configuration from individual defconfig files to match other
architectures.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2020-08-07 09:50:22 -04:00
Ioannis Glaropoulos
fa04bf615c arch: arm: cortex-m: hw stack protection under no multi-threading
This commit adds the support for HW Stack Protection when
building Zephyr without support for multi-threading. The
single MPU guard (if the feature is enabled) is set to
guard the Main stack area. The stack fail check is also
updated.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-08-07 13:06:04 +02:00
Ioannis Glaropoulos
4338552175 arch: arm: cortex-m: introduce custom switch to main function
For the case of building Zephy with no-multithreading
support (CONFIG_MULTITHREADING=n) we introduce a
custom (ARCH-specific) function to switch to main()
from cstart(). This is required, since the Cortex-M
initialization code is temporarily using the interrupt
stack and main() should be using the z_main_stack,
instead. The function performs the PSP switching,
the PSPLIM setting (for ARMv8-M), FPU initialization
and static memory region initialization, to mimic
what the normal (CONFIG_MULTITHREADING=y) case does.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-08-07 13:06:04 +02:00
Ioannis Glaropoulos
e9a85eec28 arch: arm: cortex-m: extract common code block into a static function
We extract the common code for both multithreading and
non-multithreading cases into a common static function
which will get called in Cortex-M archictecture initialization.
This commit does not introduce behavioral changes.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-08-07 13:06:04 +02:00
Ioannis Glaropoulos
1a5390f438 arch: arm: cortex-m: fix the accounted size of IRQ stack in reset.S
This patch is simply adding the guard area (if applicable) to
the calculations for the size of the interrupt stack in reset.S
for ARM Cortex-M architecture. If exists, the GUARD area is
always reserved aside from CONFIG_ISR_STACK_SIZE, since the
interrupt stack is defined using the K_KERNEL_STACK_DEFINE.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-08-07 13:06:04 +02:00
Andrew Boie
8b4b0d6264 kernel: z_interrupt_stacks are now kernel stacks
This will save memory on many platforms that enable
user mode.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-07-30 21:11:14 -04:00
Andrew Boie
8ce260d8df kernel: introduce supervisor-only stacks
These stacks are appropriate for threads that run purely in
supervisor mode, and also as stacks for interrupt and exception
handling.

Two new arch defines are introduced:

- ARCH_KERNEL_STACK_GUARD_SIZE
- ARCH_KERNEL_STACK_OBJ_ALIGN

New public declaration macros:

- K_KERNEL_STACK_RESERVED
- K_KERNEL_STACK_EXTERN
- K_KERNEL_STACK_DEFINE
- K_KERNEL_STACK_ARRAY_DEFINE
- K_KERNEL_STACK_MEMBER
- K_KERNEL_STACK_SIZEOF

If user mode is not enabled, K_KERNEL_STACK_* and K_THREAD_STACK_*
are equivalent.

Separately generated privilege elevation stacks are now declared
like kernel stacks, removing the need for K_PRIVILEGE_STACK_ALIGN.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-07-30 21:11:14 -04:00
Andrew Boie
e4cc84a537 kernel: update arch_switch_to_main_thread()
This now takes a stack pointer as an argument with TLS
and random offsets accounted for properly.

Based on #24467 authored by Flavio Ceolin.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-07-30 21:11:14 -04:00
Andrew Boie
b0c155f3ca kernel: overhaul stack specification
The core kernel computes the initial stack pointer
for a thread, properly aligning it and subtracting out
any random offsets or thread-local storage areas.
arch_new_thread() no longer needs to make any calculations,
an initial stack frame may be placed at the bounds of
the new 'stack_ptr' parameter passed in. This parameter
replaces 'stack_size'.

thread->stack_info is now set before arch_new_thread()
is invoked, z_new_thread_init() has been removed.
The values populated may need to be adjusted on arches
which carve-out MPU guard space from the actual stack
buffer.

thread->stack_info now has a new member 'delta' which
indicates any offset applied for TLS or random offset.
It's used so the calculations don't need to be repeated
if the thread later drops to user mode.

CONFIG_INIT_STACKS logic is now performed inside
z_setup_new_thread(), before arch_new_thread() is called.

thread->stack_info is now defined as the canonical
user-accessible area within the stack object, including
random offsets and TLS. It will never include any
carved-out memory for MPU guards and must be updated at
runtime if guards are removed.

Available stack space is now optimized. Some arches may
need to significantly round up the buffer size to account
for page-level granularity or MPU power-of-two requirements.
This space is now accounted for and used by virtue of
the Z_THREAD_STACK_SIZE_ADJUST() call in z_setup_new_thread.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-07-30 21:11:14 -04:00
Andrew Boie
24825c8667 arches: fix arch_new_thread param names
MISRA-C wants the parameter names in a function implementaion
to match the names used by the header prototype.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-07-30 21:11:14 -04:00
Andrew Boie
0c69561469 arch: remove duplicate docs for arch_new_thread
This interface is documented already in
kernel/include/kernel_arch_interface.h

Other architectural notes were left in place except where
they were incorrect (like the thread struct
being in the low stack addresses)

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-07-30 21:11:14 -04:00
Andrew Boie
62eb7d99dc arch_interface: remove unnecessary params
arch_new_thread() passes along the thread priority and option
flags, but these are already initialized in thread->base and
can be accessed there if needed.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-07-30 21:11:14 -04:00
Ioannis Glaropoulos
b0c5e6335a arch: arm: cortex-m: move the relay table section after vector table
In CPUs with VTOR we are free to place the relay vector table
section anywhere inside ROM_START section (as long as we respect
alignment requirements). This PR moves the relay table towards
the end of ROM_START. This leaves sufficient area for placing
some SoC-specific sections inside ROM_START that need to start
at a fixed address.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-07-27 13:23:36 +02:00
Andrzej Głąbek
ec8cb07da2 arch: arm: Export vector table symbols with GDATA instead of GTEXT
_vector_table and __vector_relay_table symbols were exported with GTEXT
(i.e. as functions). That resulted in bit[0] being incorrectly set in
the addresses they represent (for functions this bit set to 1 specifies
execution in Thumb state).
This commit corrects this by switching to exporting these objects as
objects, i.e. with GDATA.

Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
2020-07-24 12:04:28 +02:00
Daniel Leung
3f6ac9fdfd arm: add include guard for offset files
MISRA-C directive 4.10 requires that files being included must
prevent itself from being included more than once. So add
include guards to the offset files, even though they are C
source files.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2020-07-24 10:01:12 +02:00
David Leach
5803ec1bf0 arch: arm: mpu: Use temporary MPU mapping while reprogramming NXP MPU
Race conditions exist when remapping the NXP MPU. When writing the
start, end, or attribute registers of a MPU descriptor, the hardware
will automatically clear the region's valid bit. If that region gets
accessed before the code is able to set the valid bit, the core will
fault.

Issue #20595 revealled this problem with the code in region_init()
when the compiler options are set to no optimizations. The code
generated by the compiler put local variables on the stack and then
read those stack based variables when writing the MPU descriptor
registers. If that region mapped the stack a memory fault would occur.
Higher compiler optimizations would store these local variables in
CPU registers which avoided the memory access when programming the
MPU descriptor.

Because the NXP MPU uses a logic OR operation of the MPU descriptors,
the fix uses the last descriptor in the MPU hardware to remap all of
dynamic memory for access instead of the first of the dynamic memory
descriptors as was occuring before. This allows reprogramming of the
primary discriptor blocks without having a memory fault. After all
the dynamic memory blocks are mapped, the unused blocks will have
their valid bits cleared including this temporary one, if it wasn't
alread changed during the mapping of the current set.

Fixes #20595

Signed-off-by: David Leach <david.leach@nxp.com>
2020-07-22 11:27:40 +02:00
Andrew Boie
ff294e02cd arch: add CONFIG_CPU_HAS_MMU
Indicate that the CPU has a memory management unit,
similar to CPU_HAS_MPU for MPUs.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-07-17 11:38:18 +02:00
Rafał Kuźnia
f2b0bfda8f arch: arm: aarch32: Always use VTOR when it is available
Zephyr applications will always use the VTOR register when it is
available on the CPU and the register will always be configured
to point to applications vector table during startup.

SW_VECTOR_RELAY_CLIENT is meant to be used only on baseline ARM cores.

SW_VECTOR_RELAY is intended to be used only by the bootloader.
The bootloader may configure the VTOR to point to the relay table
right before chain-loading the application.

Signed-off-by: Rafał Kuźnia <rafal.kuznia@nordicsemi.no>
2020-07-14 16:17:30 +02:00
Andrzej Puzdrowski
4152ccf124 arch/arm/aarch32: ensured SW IRQ relay modes exclusive
Select either SW_VECTOR_RELAY or SW_VECTOR_RELAY_CLIENT
at the time.

Removed #ifdef-ry in irq_relay.S as SW_VECTOR_RELAY was
refined so it became reserved for the bootloader and it
conditionally includes irq_relay.S for compilation.
See SHA #fde3116f19

Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
Signed-off-by: Rafał Kuźnia <rafal.kuznia@nordicsemi.no>
2020-07-14 16:17:30 +02:00
Rafał Kuźnia
89bf746ebe arch/arm/aarch32: add IRQ relay mechanism to ARMv7/8-M
This patch allows the `SW_VECTOR_RELAY` and
`SW_VECTOR_RELAY_CLIENT` pair to be
enabled on the ARMv7-M and ARMv8-M architectures
and covers all additional interrupt vectors.

Signed-off-by: Rafał Kuźnia <rafal.kuznia@nordicsemi.no>
Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
2020-07-14 16:17:30 +02:00
Ioannis Glaropoulos
e80e655b01 arch: arm: cortex_m: align vector table based on VTOR requirements
Enforce VTOR table offset alignment requirements on Cortex-M
vector table start address.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-07-14 13:03:25 +02:00
Ioannis Glaropoulos
fde3116f19 arch: arm: cortex_m: Add config for SW_VECTOR_RELAY_CLIENT
Define vector relay tables for bootloader only.
If an image is not a bootloader image (such as an MCUboot image)
but it is a standard Zephyr firmware, chain-loadable by a
bootloader, then this image will not need to relay IRQs itself.
In this case SW_VECTOR_RELAY_CLIENT should be used to setting the
vector table pointer in RAM so the parent image can forward the
interrupts to it.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
Co-authored-by: Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no>
Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
2020-07-03 13:34:50 -04:00
Scott Branden
d77fbcb86a arch: arm64: mmu: create macro for TCR_PS_BITS
Create macro for TCR_PS_BITS instead of programmatically looking up
a static value based on a CONFIG option.  Moving to macro
removes logically dead code reported by Coverity static analysis tool.

Signed-off-by: Scott Branden <scott.branden@broadcom.com>
2020-06-18 12:47:30 +02:00
Kumar Gala
a1b77fd589 zephyr: replace zephyr integer types with C99 types
git grep -l 'u\(8\|16\|32\|64\)_t' | \
		xargs sed -i "s/u\(8\|16\|32\|64\)_t/uint\1_t/g"
	git grep -l 's\(8\|16\|32\|64\)_t' | \
		xargs sed -i "s/s\(8\|16\|32\|64\)_t/int\1_t/g"

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
2020-06-08 08:23:57 -05:00
Ioannis Glaropoulos
9d8111c88f arch: arm: cortex-m: fix placement of ARMv7-M-related MPU workaround
The workaround for ARMv7-M architecture (which proactively
decreases the available thread stack by the size of the MPU
guard) needs to be placed before we calculate the pointer of
the user-space local thread data, otherwise this pointer will
fall beyond the boundary of the thread stack area.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-05-27 19:48:27 +02:00
Ioannis Glaropoulos
6b54958a0e arch: arm: aarch32: cortex-m: fix logic for detecting guard violation
We fix (by inverting) the logic of the IS_MPU_GUARD_VIOLATION
macro, with respect to the value of the supplied 'fault_addr'.
We shall only be inspecting the fault_addr value if it is not
set to -EINVAL.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-05-27 10:10:22 +02:00
Ioannis Glaropoulos
7284aee7d7 arch: arm: aarch32: cortex_m: add note in mem_manage_fault()
It is possible that MMFAR address is not written by the
Cortex-M core; this occurs when the stacking error is
not accompanied by a data access violation error (i.e.
when stack overflows due to the exception entry frame
stacking): z_check_thread_stack_fail() shall be able to
handle the case of 'mmfar' holding the -EINVAL value.

Add this node in mem_manage_fault() function to clarify
that it is valid for z_check_thread_stack_fail() to be
called with invalid mmfar address value.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
2020-05-27 10:10:22 +02:00
Andrew Boie
2873afb7fe aarch32: fix a build failure
Some wires were crossed when an older PR was merged that
had build conflicts with newer code. Update this header
to reflect were the 'nested' member is in the kernel CPU
struct.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-05-08 13:59:17 -05:00
Andrew Boie
a203d21962 kernel: remove legacy fields in _kernel
UP should just use _kernel.cpus[0].

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-05-08 17:42:49 +02:00
Stephanos Ioannidis
aaf93205bb kconfig: Rename CONFIG_FP_SHARING to CONFIG_FPU_SHARING
This commit renames the Kconfig `FP_SHARING` symbol to `FPU_SHARING`,
since this symbol specifically refers to the hardware FPU sharing
support by means of FPU context preservation, and the "FP" prefix is
not fully descriptive of that; leaving room for ambiguity.

Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
2020-05-08 10:58:33 +02:00
Abhishek Shah
2f85c01eaa arch: arm: aarch64: Add Cortex-A72 config
Add Cortex-A72 config in order to set "-mcpu" correctly.

Signed-off-by: Abhishek Shah <abhishek.shah@broadcom.com>
2020-05-08 10:46:23 +02:00
Stephanos Ioannidis
8b27d5c6b9 linker: Clean up section name definitions
This commit cleans up the section name definitions in the linker
sections header file (`include/linker/sections.h`) to have the uniform
format of `_(SECTION)_SECTION_NAME`.

In addition, the scope of the short section reference aliases (e.g.
`TEXT`, `DATA`, `BSS`) are now limited to the ASM code, as they are
currently used (and intended to be used) only by the ASM code to
specify the target section for functions and variables, and these short
names can cause name conflicts with the symbols used in the C code.

Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
2020-04-30 13:42:36 -04:00
Sandeep Tripathy
d4f1f2a07e arch: arm64: add public header for asm macros
Move generic macros to exported assembly header file
'macro.inc'. Rename the existing 'macro.inc' to 'macro_priv.inc'.

Signed-off-by: Sandeep Tripathy <sandeep.tripathy@broadcom.com>
2020-04-28 10:44:42 -07:00
Stephanos Ioannidis
0e6ede8929 kconfig: Rename CONFIG_FLOAT to CONFIG_FPU
This commit renames the Kconfig `FLOAT` symbol to `FPU`, since this
symbol only indicates that the hardware Floating Point Unit (FPU) is
used and does not imply and/or indicate the general availability of
toolchain-level floating point support (i.e. this symbol is not
selected when building for an FPU-less platform that supports floating
point operations through the toolchain-provided software floating point
library).

Moreover, given that the symbol that indicates the availability of FPU
is named `CPU_HAS_FPU`, it only makes sense to use "FPU" in the name of
the symbol that enables the FPU.

Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
2020-04-27 19:03:44 +02:00
Andrew Boie
618426d6e7 kernel: add Z_STACK_PTR_ALIGN ARCH_STACK_PTR_ALIGN
This operation is formally defined as rounding down a potential
stack pointer value to meet CPU and ABI requirments.

This was previously defined ad-hoc as STACK_ROUND_DOWN().

A new architecture constant ARCH_STACK_PTR_ALIGN is added.
Z_STACK_PTR_ALIGN() is defined in terms of it. This used to
be inconsistently specified as STACK_ALIGN or STACK_PTR_ALIGN;
in the latter case, STACK_ALIGN meant something else, typically
a required alignment for the base of a stack buffer.

STACK_ROUND_UP() only used in practice by Risc-V, delete
elsewhere.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2020-04-21 18:45:45 -04:00