summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bsps/arm/atsam/console/console.c476
-rw-r--r--bsps/arm/atsam/i2c/atsam_i2c_bus.c146
-rw-r--r--bsps/arm/atsam/include/bsp.h13
-rw-r--r--bsps/arm/atsam/include/bsp/atsam-i2c.h32
-rw-r--r--bsps/m68k/uC5282/start/linkcmds34
-rw-r--r--bsps/powerpc/include/libcpu/io.h8
-rw-r--r--bsps/powerpc/motorola_powerpc/include/bsp.h34
-rw-r--r--cpukit/Makefile.am1
-rw-r--r--cpukit/include/link_elf.h8
-rw-r--r--cpukit/include/linux/rbtree.h10
-rw-r--r--cpukit/include/rtems/capture.h4
-rw-r--r--cpukit/include/rtems/confdefs/percpu.h18
-rw-r--r--cpukit/include/rtems/confdefs/wkspace.h16
-rw-r--r--cpukit/include/rtems/config.h3
-rw-r--r--cpukit/include/rtems/posix/muteximpl.h7
-rw-r--r--cpukit/include/rtems/posix/pthreadattrimpl.h2
-rw-r--r--cpukit/include/rtems/rtl/rtl-obj.h20
-rw-r--r--cpukit/include/rtems/rtl/rtl.h2
-rw-r--r--cpukit/include/rtems/score/cpustdatomic.h6
-rw-r--r--cpukit/include/rtems/score/heapimpl.h10
-rw-r--r--cpukit/include/rtems/score/objectimpl.h29
-rw-r--r--cpukit/include/rtems/score/priority.h4
-rw-r--r--cpukit/include/rtems/score/priorityimpl.h2
-rw-r--r--cpukit/include/rtems/score/scheduleredfimpl.h4
-rw-r--r--cpukit/include/rtems/score/stack.h24
-rw-r--r--cpukit/include/rtems/score/timecounter.h24
-rw-r--r--cpukit/include/rtems/score/tls.h2
-rw-r--r--cpukit/include/rtems/score/watchdogimpl.h2
-rw-r--r--cpukit/include/rtems/termiostypes.h6
-rw-r--r--cpukit/libcsupport/src/posix_devctl.c80
-rw-r--r--cpukit/libcsupport/src/sync.c93
-rw-r--r--cpukit/libcsupport/src/termios.c5
-rw-r--r--cpukit/libfs/src/imfs/imfs_memfile.c3
-rw-r--r--cpukit/libmisc/rtems-fdt/rtems-fdt.c6
-rw-r--r--cpukit/libmisc/shell/main_chmod.c2
-rw-r--r--cpukit/libmisc/shell/main_edit.c18
-rw-r--r--cpukit/libmisc/untar/untar.c57
-rw-r--r--cpukit/posix/src/nanosleep.c31
-rw-r--r--cpukit/rtems/src/ratemoncreate.c1
-rw-r--r--cpukit/score/src/heapallocate.c9
-rw-r--r--cpukit/score/src/kern_tc.c676
-rw-r--r--cpukit/score/src/objectactivecount.c18
-rw-r--r--cpukit/score/src/objectfree.c12
-rw-r--r--cpukit/score/src/stackallocatorforidle.c59
-rw-r--r--cpukit/score/src/threadcreateidle.c12
-rw-r--r--testsuites/libtests/malloctest/init.c4
-rw-r--r--testsuites/libtests/tar01/init.c199
-rw-r--r--testsuites/libtests/tar01/tar01.doc1
-rw-r--r--testsuites/libtests/tar01/tar01.scn54
-rw-r--r--testsuites/libtests/tar01/tar01.tarbin10240 -> 10240 bytes
-rw-r--r--testsuites/psxtests/psxdevctl01/test.c69
-rw-r--r--testsuites/psxtests/psximfs02/init.c30
-rw-r--r--testsuites/sptests/Makefile.am18
-rw-r--r--testsuites/sptests/configure.ac2
-rw-r--r--testsuites/sptests/spstkalloc03/init.c103
-rw-r--r--testsuites/sptests/spstkalloc03/spstkalloc03.doc19
-rw-r--r--testsuites/sptests/spstkalloc03/spstkalloc03.scn2
-rw-r--r--testsuites/sptests/spstkalloc04/init.c82
-rw-r--r--testsuites/sptests/spstkalloc04/spstkalloc04.doc20
-rw-r--r--testsuites/sptests/spstkalloc04/spstkalloc04.scn2
-rw-r--r--testsuites/sptests/sptimecounter01/init.c4
61 files changed, 1793 insertions, 845 deletions
diff --git a/bsps/arm/atsam/console/console.c b/bsps/arm/atsam/console/console.c
index d51d2ace7d..0802ca2155 100644
--- a/bsps/arm/atsam/console/console.c
+++ b/bsps/arm/atsam/console/console.c
@@ -16,6 +16,7 @@
#include <bsp/irq.h>
#include <bsp/fatal.h>
#include <rtems/console.h>
+#include <rtems/seterr.h>
#include <rtems/termiostypes.h>
@@ -23,274 +24,92 @@
#include <unistd.h>
+#define UART_RX_DMA_BUF_SIZE 32l
+
+typedef struct {
+ char buf[UART_RX_DMA_BUF_SIZE];
+ LinkedListDescriporView3 desc;
+} atsam_uart_rx_dma;
+
typedef struct {
rtems_termios_device_context base;
- Usart *regs;
+ Uart *regs;
rtems_vector_number irq;
uint32_t id;
bool console;
+ bool is_usart;
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
bool transmitting;
+ bool rx_dma_enabled;
+ uint32_t rx_dma_channel;
+ atsam_uart_rx_dma *rx_dma;
+ char *volatile*rx_dma_da;
+ char *rx_next_read_pos;
#endif
-} atsam_usart_context;
+} atsam_uart_context;
-static atsam_usart_context atsam_usart_instances[] = {
+static atsam_uart_context atsam_usart_instances[] = {
{
- .regs = USART0,
+ .regs = (Uart *)USART0,
.irq = USART0_IRQn,
- .id = ID_USART0
+ .id = ID_USART0,
+ .is_usart = true,
}
#ifdef USART1
, {
- .regs = USART1,
+ .regs = (Uart *)USART1,
.irq = USART1_IRQn,
- .id = ID_USART1
+ .id = ID_USART1,
+ .is_usart = true,
}
#endif
#ifdef USART2
, {
- .regs = USART2,
+ .regs = (Uart *)USART2,
.irq = USART2_IRQn,
- .id = ID_USART2
- }
-#endif
-};
-
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
-static void atsam_usart_interrupt(void *arg)
-{
- rtems_termios_tty *tty = arg;
- atsam_usart_context *ctx = rtems_termios_get_device_context(tty);
- Usart *regs = ctx->regs;
- uint32_t csr = regs->US_CSR;
-
- while ((csr & US_CSR_RXRDY) != 0) {
- char c = (char) regs->US_RHR;
-
- rtems_termios_enqueue_raw_characters(tty, &c, 1);
-
- csr = regs->US_CSR;
- }
-
- if (ctx->transmitting && (csr & US_CSR_TXEMPTY) != 0) {
- rtems_termios_dequeue_characters(tty, 1);
- }
-}
-#endif
-
-static bool atsam_usart_set_attributes(
- rtems_termios_device_context *base,
- const struct termios *term
-)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
- Usart *regs = ctx->regs;
- rtems_termios_baud_t baud;
- uint32_t mr;
-
- baud = rtems_termios_baud_to_number(term->c_ospeed);
- regs->US_BRGR = (BOARD_MCK / baud) / 16;
-
- if ((term->c_cflag & CREAD) != 0) {
- regs->US_CR = US_CR_RXEN | US_CR_TXEN;
- } else {
- regs->US_CR = US_CR_TXEN;
- }
-
- mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
-
- switch (term->c_cflag & CSIZE) {
- case CS5:
- mr |= US_MR_CHRL_5_BIT;
- break;
- case CS6:
- mr |= US_MR_CHRL_6_BIT;
- break;
- case CS7:
- mr |= US_MR_CHRL_7_BIT;
- break;
- default:
- mr |= US_MR_CHRL_8_BIT;
- break;
- }
-
- if ((term->c_cflag & PARENB) != 0) {
- if ((term->c_cflag & PARODD) != 0) {
- mr |= US_MR_PAR_ODD;
- } else {
- mr |= US_MR_PAR_EVEN;
- }
- } else {
- mr |= US_MR_PAR_NO;
- }
-
- if ((term->c_cflag & CSTOPB) != 0) {
- mr |= US_MR_NBSTOP_2_BIT;
- } else {
- mr |= US_MR_NBSTOP_1_BIT;
- }
-
- regs->US_MR = mr;
-
- return true;
-}
-
-static bool atsam_usart_first_open(
- rtems_termios_tty *tty,
- rtems_termios_device_context *base,
- struct termios *term,
- rtems_libio_open_close_args_t *args
-)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
- Usart *regs = ctx->regs;
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- rtems_status_code sc;
-#endif
-
- regs->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RSTSTA;
- regs->US_IDR = 0xffffffff;
-
- PMC_EnablePeripheral(ctx->id);
-
- rtems_termios_set_initial_baud(tty, ATSAM_CONSOLE_BAUD);
- atsam_usart_set_attributes(base, term);
-
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- regs->US_IER = US_IDR_RXRDY;
- sc = rtems_interrupt_handler_install(
- ctx->irq,
- "USART",
- RTEMS_INTERRUPT_SHARED,
- atsam_usart_interrupt,
- tty
- );
- if (sc != RTEMS_SUCCESSFUL) {
- return false;
- }
-#endif
-
- return true;
-}
-
-static void atsam_usart_last_close(
- rtems_termios_tty *tty,
- rtems_termios_device_context *base,
- rtems_libio_open_close_args_t *args
-)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
-
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- rtems_interrupt_handler_remove(ctx->irq, atsam_usart_interrupt, tty);
-#endif
-
- if (!ctx->console) {
- PMC_DisablePeripheral(ctx->id);
- }
-}
-
-static void atsam_usart_write(
- rtems_termios_device_context *base,
- const char *buf,
- size_t len
-)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
- Usart *regs = ctx->regs;
-
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- if (len > 0) {
- ctx->transmitting = true;
- regs->US_THR = buf[0];
- regs->US_IER = US_IDR_TXEMPTY;
- } else {
- ctx->transmitting = false;
- regs->US_IDR = US_IDR_TXEMPTY;
- }
-#else
- size_t i;
-
- for (i = 0; i < len; ++i) {
- while ((regs->US_CSR & US_CSR_TXEMPTY) == 0) {
- /* Wait */
- }
-
- regs->US_THR = buf[i];
+ .id = ID_USART2,
+ .is_usart = true,
}
#endif
-}
-
-#ifndef ATSAM_CONSOLE_USE_INTERRUPTS
-static int atsam_usart_read(rtems_termios_device_context *base)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
- Usart *regs = ctx->regs;
-
- if ((regs->US_CSR & US_CSR_RXRDY) != 0) {
- return (char) regs->US_RHR;
- } else {
- return -1;
- }
-}
-#endif
-
-static const rtems_termios_device_handler atsam_usart_handler = {
- .first_open = atsam_usart_first_open,
- .last_close = atsam_usart_last_close,
- .write = atsam_usart_write,
- .set_attributes = atsam_usart_set_attributes,
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- .mode = TERMIOS_IRQ_DRIVEN
-#else
- .poll_read = atsam_usart_read,
- .mode = TERMIOS_POLLED
-#endif
};
-typedef struct {
- rtems_termios_device_context base;
- Uart *regs;
- rtems_vector_number irq;
- uint32_t id;
- bool console;
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- bool transmitting;
-#endif
-} atsam_uart_context;
-
static atsam_uart_context atsam_uart_instances[] = {
{
.regs = UART0,
.irq = UART0_IRQn,
- .id = ID_UART0
+ .id = ID_UART0,
+ .is_usart = false,
}
#ifdef UART1
, {
.regs = UART1,
.irq = UART1_IRQn,
- .id = ID_UART1
+ .id = ID_UART1,
+ .is_usart = false,
}
#endif
#ifdef UART2
, {
.regs = UART2,
.irq = UART2_IRQn,
- .id = ID_UART2
+ .id = ID_UART2,
+ .is_usart = false,
}
#endif
#ifdef UART3
, {
.regs = UART3,
.irq = UART3_IRQn,
- .id = ID_UART3
+ .id = ID_UART3,
+ .is_usart = false,
}
#endif
#ifdef UART4
, {
.regs = UART4,
.irq = UART4_IRQn,
- .id = ID_UART4
+ .id = ID_UART4,
+ .is_usart = false,
}
#endif
};
@@ -303,16 +122,32 @@ static void atsam_uart_interrupt(void *arg)
Uart *regs = ctx->regs;
uint32_t sr = regs->UART_SR;
- while ((sr & UART_SR_RXRDY) != 0) {
- char c = (char) regs->UART_RHR;
+ if (!ctx->rx_dma_enabled) {
+ while ((sr & UART_SR_RXRDY) != 0) {
+ char c = (char) regs->UART_RHR;
- rtems_termios_enqueue_raw_characters(tty, &c, 1);
+ rtems_termios_enqueue_raw_characters(tty, &c, 1);
- sr = regs->UART_SR;
+ sr = regs->UART_SR;
+ }
+ } else {
+ while (*ctx->rx_dma_da != ctx->rx_next_read_pos) {
+ char c;
+
+ c = *ctx->rx_next_read_pos;
+
+ ++ctx->rx_next_read_pos;
+ if (ctx->rx_next_read_pos >= &ctx->rx_dma->buf[UART_RX_DMA_BUF_SIZE]) {
+ ctx->rx_next_read_pos = &ctx->rx_dma->buf[0];
+ }
+
+ rtems_termios_enqueue_raw_characters(tty, &c, 1);
+ }
}
- if (ctx->transmitting && (sr & UART_SR_TXEMPTY) != 0) {
+ while (ctx->transmitting && (sr & UART_SR_TXRDY) != 0) {
rtems_termios_dequeue_characters(tty, 1);
+ sr = regs->UART_SR;
}
}
#endif
@@ -336,10 +171,31 @@ static bool atsam_uart_set_attributes(
regs->UART_CR = UART_CR_TXEN;
}
- mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
-
- if ((term->c_cflag & CSIZE) != CS8) {
- return false;
+ if (ctx->is_usart) {
+ mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
+ } else {
+ mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
+ }
+
+ if (ctx->is_usart) {
+ switch (term->c_cflag & CSIZE) {
+ case CS5:
+ mr |= US_MR_CHRL_5_BIT;
+ break;
+ case CS6:
+ mr |= US_MR_CHRL_6_BIT;
+ break;
+ case CS7:
+ mr |= US_MR_CHRL_7_BIT;
+ break;
+ default:
+ mr |= US_MR_CHRL_8_BIT;
+ break;
+ }
+ } else {
+ if ((term->c_cflag & CSIZE) != CS8) {
+ return false;
+ }
}
if ((term->c_cflag & PARENB) != 0) {
@@ -352,8 +208,16 @@ static bool atsam_uart_set_attributes(
mr |= UART_MR_PAR_NO;
}
- if ((term->c_cflag & CSTOPB) != 0) {
- return false;
+ if (ctx->is_usart) {
+ if ((term->c_cflag & CSTOPB) != 0) {
+ mr |= US_MR_NBSTOP_2_BIT;
+ } else {
+ mr |= US_MR_NBSTOP_1_BIT;
+ }
+ } else {
+ if ((term->c_cflag & CSTOPB) != 0) {
+ return false;
+ }
}
regs->UART_MR = mr;
@@ -361,6 +225,118 @@ static bool atsam_uart_set_attributes(
return true;
}
+static void atsam_uart_disable_rx_dma(atsam_uart_context *ctx)
+{
+ if (ctx->rx_dma) {
+ rtems_cache_coherent_free(ctx->rx_dma);
+ ctx->rx_dma = NULL;
+ }
+
+ if (ctx->rx_dma_channel != XDMAD_ALLOC_FAILED) {
+ XDMAD_FreeChannel(&XDMAD_Instance, ctx->rx_dma_channel);
+ }
+
+ ctx->rx_dma_enabled = false;
+}
+
+static rtems_status_code atsam_uart_enable_rx_dma(atsam_uart_context *ctx)
+{
+ eXdmadRC rc;
+ int channel_id;
+
+ if (ctx->rx_dma_enabled) {
+ return RTEMS_SUCCESSFUL;
+ }
+
+ /*
+ * Make sure everything is in a clean default state so that the cleanup works
+ * in an error case.
+ */
+ ctx->rx_dma = NULL;
+ ctx->rx_dma_channel = XDMAD_ALLOC_FAILED;
+
+ ctx->rx_dma = rtems_cache_coherent_allocate(sizeof(*ctx->rx_dma), 0, 0);
+ if (ctx->rx_dma == NULL) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_NO_MEMORY;
+ }
+
+ ctx->rx_next_read_pos = &ctx->rx_dma->buf[0];
+
+ ctx->rx_dma_channel = XDMAD_AllocateChannel(
+ &XDMAD_Instance,
+ XDMAD_TRANSFER_MEMORY,
+ ctx->id
+ );
+
+ if (ctx->rx_dma_channel == XDMAD_ALLOC_FAILED) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_IO_ERROR;
+ }
+
+ rc = XDMAD_PrepareChannel(&XDMAD_Instance, ctx->rx_dma_channel);
+ if (rc != XDMAD_OK) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_IO_ERROR;
+ }
+
+ channel_id = ctx->rx_dma_channel & 0xff;
+ ctx->rx_dma_da =
+ (char *volatile*) &XDMAD_Instance.pXdmacs->XDMAC_CHID[channel_id].XDMAC_CDA;
+
+ ctx->rx_dma->desc.mbr_nda = (uint32_t)&ctx->rx_dma->desc;
+ ctx->rx_dma->desc.mbr_ubc =
+ 1 |
+ XDMA_UBC_NVIEW_NDV3 |
+ XDMA_UBC_NDE_FETCH_EN |
+ XDMA_UBC_NDEN_UPDATED |
+ XDMA_UBC_NSEN_UPDATED;
+ ctx->rx_dma->desc.mbr_sa = (uint32_t) &ctx->regs->UART_RHR;
+ ctx->rx_dma->desc.mbr_da = (uint32_t) &ctx->rx_dma->buf[0];
+ ctx->rx_dma->desc.mbr_cfg =
+ XDMAC_CC_TYPE_PER_TRAN |
+ XDMAC_CC_MBSIZE_SINGLE |
+ XDMAC_CC_DSYNC_PER2MEM |
+ XDMAC_CC_SWREQ_HWR_CONNECTED |
+ XDMAC_CC_MEMSET_NORMAL_MODE |
+ XDMAC_CC_CSIZE_CHK_1 |
+ XDMAC_CC_DWIDTH_BYTE |
+ XDMAC_CC_SIF_AHB_IF1 |
+ XDMAC_CC_DIF_AHB_IF1 |
+ XDMAC_CC_SAM_FIXED_AM |
+ XDMAC_CC_DAM_UBS_AM |
+ XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ctx->id, XDMAD_TRANSFER_RX));
+ ctx->rx_dma->desc.mbr_bc = UART_RX_DMA_BUF_SIZE - 1;
+ ctx->rx_dma->desc.mbr_ds = 0;
+ ctx->rx_dma->desc.mbr_sus = 0;
+ ctx->rx_dma->desc.mbr_dus = 0;
+
+ rc = XDMAD_ConfigureTransfer(
+ &XDMAD_Instance,
+ ctx->rx_dma_channel,
+ NULL,
+ XDMAC_CNDC_NDE_DSCR_FETCH_EN |
+ XDMAC_CNDC_NDVIEW_NDV3 |
+ XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
+ XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED,
+ (uint32_t)&ctx->rx_dma->desc,
+ 0);
+ if (rc != XDMAD_OK) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_IO_ERROR;
+ }
+
+ rc = XDMAD_StartTransfer(&XDMAD_Instance, ctx->rx_dma_channel);
+ if (rc != XDMAD_OK) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_IO_ERROR;
+ }
+
+ ctx->rx_dma_enabled = true;
+
+ return RTEMS_SUCCESSFUL;
+}
+
static bool atsam_uart_first_open(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
@@ -386,7 +362,7 @@ static bool atsam_uart_first_open(
regs->UART_IER = UART_IDR_RXRDY;
sc = rtems_interrupt_handler_install(
ctx->irq,
- "UART",
+ ctx->is_usart ? "USART" : "UART",
RTEMS_INTERRUPT_SHARED,
atsam_uart_interrupt,
tty
@@ -411,6 +387,10 @@ static void atsam_uart_last_close(
rtems_interrupt_handler_remove(ctx->irq, atsam_uart_interrupt, tty);
#endif
+ if (ctx->rx_dma_enabled) {
+ atsam_uart_disable_rx_dma(ctx);
+ }
+
if (!ctx->console) {
PMC_DisablePeripheral(ctx->id);
}
@@ -429,16 +409,16 @@ static void atsam_uart_write(
if (len > 0) {
ctx->transmitting = true;
regs->UART_THR = buf[0];
- regs->UART_IER = UART_IDR_TXEMPTY;
+ regs->UART_IER = UART_IDR_TXRDY;
} else {
ctx->transmitting = false;
- regs->UART_IDR = UART_IDR_TXEMPTY;
+ regs->UART_IDR = UART_IDR_TXRDY;
}
#else
size_t i;
for (i = 0; i < len; ++i) {
- while ((regs->UART_SR & UART_SR_TXEMPTY) == 0) {
+ while ((regs->UART_SR & UART_SR_TXRDY) == 0) {
/* Wait */
}
@@ -461,13 +441,41 @@ static int atsam_uart_read(rtems_termios_device_context *base)
}
#endif
+#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
+static int atsam_uart_ioctl(
+ rtems_termios_device_context *base,
+ ioctl_command_t request,
+ void *buffer
+)
+{
+ atsam_uart_context *ctx = (atsam_uart_context *) base;
+ rtems_status_code sc;
+
+ switch (request) {
+ case ATSAM_UART_ENABLE_RX_DMA:
+ sc = atsam_uart_enable_rx_dma(ctx);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_set_errno_and_return_minus_one(EIO);
+ } else {
+ ctx->rx_dma_enabled = true;
+ }
+ break;
+ default:
+ rtems_set_errno_and_return_minus_one(EINVAL);
+ }
+
+ return 0;
+}
+#endif
+
static const rtems_termios_device_handler atsam_uart_handler = {
.first_open = atsam_uart_first_open,
.last_close = atsam_uart_last_close,
.write = atsam_uart_write,
.set_attributes = atsam_uart_set_attributes,
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- .mode = TERMIOS_IRQ_DRIVEN
+ .mode = TERMIOS_IRQ_DRIVEN,
+ .ioctl = atsam_uart_ioctl,
#else
.poll_read = atsam_uart_read,
.mode = TERMIOS_POLLED
@@ -490,7 +498,7 @@ rtems_status_code console_initialize(
usart[sizeof(usart) - 2] = (char) ('0' + i);
rtems_termios_device_install(
&usart[0],
- &atsam_usart_handler,
+ &atsam_uart_handler,
NULL,
&atsam_usart_instances[i].base
);
diff --git a/bsps/arm/atsam/i2c/atsam_i2c_bus.c b/bsps/arm/atsam/i2c/atsam_i2c_bus.c
index 4425975de8..3451d15bed 100644
--- a/bsps/arm/atsam/i2c/atsam_i2c_bus.c
+++ b/bsps/arm/atsam/i2c/atsam_i2c_bus.c
@@ -33,72 +33,65 @@
static void
atsam_i2c_disable_interrupts(Twihs *regs)
{
- regs->TWIHS_IDR = 0xFFFFFFFF;
+ TWI_DisableIt(regs, 0xFFFFFFFF);
}
-static void
-atsam_i2c_set_transfer_status(transfer_desc *trans_desc, transfer_state state)
+/*
+ * Return true if the message is done right after this. That is the case if all
+ * bytes are received but no stop is requested.
+ */
+static bool
+atsam_i2c_continue_read(Twihs *regs, atsam_i2c_bus *bus)
{
- trans_desc->trans_state = state;
-}
+ bool done = false;
-static void
-atsam_i2c_continue_read(Twihs *regs, transfer_desc *trans_desc)
-{
- trans_desc->data[trans_desc->already_transferred] = TWI_ReadByte(regs);
- trans_desc->already_transferred++;
+ *bus->current_msg_byte = TWI_ReadByte(regs);
+ ++bus->current_msg_byte;
+ --bus->current_msg_todo;
/* check for transfer finish */
- if (trans_desc->already_transferred == trans_desc->data_size) {
- if (trans_desc->stop_request){
+ if (bus->current_msg_todo == 0) {
+ if (bus->stop_request){
TWI_DisableIt(regs, TWIHS_IDR_RXRDY);
TWI_EnableIt(regs, TWIHS_IER_TXCOMP);
- atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT);
} else {
- atsam_i2c_set_transfer_status(trans_desc, RX_CONT_MESSAGE_NEEDED);
+ done = true;
}
}
/* Last byte? */
- else if ((trans_desc->already_transferred == (trans_desc->data_size - 1))
- && (trans_desc->stop_request)){
+ else if (bus->current_msg_todo == 1 && bus->stop_request) {
TWI_Stop(regs);
}
+
+ return done;
}
+/*
+ * Return true if the message is done right after this. That is the case if all
+ * bytes are sent but no stop is requested.
+ */
static bool
-atsam_i2c_is_state(transfer_desc *trans_desc, transfer_state state)
+atsam_i2c_continue_write(Twihs *regs, atsam_i2c_bus *bus)
{
- return (trans_desc->trans_state == state);
-}
+ bool done = false;
-static void
-atsam_i2c_continue_write(Twihs *regs, transfer_desc *trans_desc)
-{
/* Transfer finished ? */
- if (trans_desc->already_transferred == trans_desc->data_size) {
+ if (bus->current_msg_todo == 0) {
TWI_DisableIt(regs, TWIHS_IDR_TXRDY);
- if (trans_desc->stop_request){
+ if (bus->stop_request){
TWI_EnableIt(regs, TWIHS_IER_TXCOMP);
TWI_SendSTOPCondition(regs);
- atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT);
} else {
- atsam_i2c_set_transfer_status(trans_desc, TX_CONT_MESSAGE_NEEDED);
+ done = true;
}
}
/* Bytes remaining */
else {
- TWI_WriteByte(regs,
- trans_desc->data[trans_desc->already_transferred]);
- trans_desc->already_transferred++;
+ TWI_WriteByte(regs, *bus->current_msg_byte);
+ ++bus->current_msg_byte;
+ --bus->current_msg_todo;
}
-}
-
-static void
-atsam_i2c_finish_write_transfer(Twihs *regs, transfer_desc *trans_desc)
-{
- TWI_ReadByte(regs);
- TWI_DisableIt(regs, TWIHS_IDR_TXCOMP);
- trans_desc->status = 0;
+ return done;
}
static void
@@ -115,19 +108,6 @@ atsam_i2c_next_packet(atsam_i2c_bus *bus)
bus->current_msg_byte = msg->buf;
}
-static void
-atsam_i2c_set_td(atsam_i2c_bus *bus, uint32_t already_transferred,
- bool stop_needed)
-{
- transfer_desc *trans_desc = &bus->trans_desc;
-
- trans_desc->status = ASYNC_STATUS_PENDING;
- trans_desc->data = bus->current_msg_byte;
- trans_desc->data_size = bus->current_msg_todo;
- trans_desc->already_transferred = already_transferred;
- trans_desc->stop_request = stop_needed;
-}
-
static bool
atsam_i2c_set_address_size(const i2c_msg *msg)
{
@@ -186,6 +166,8 @@ atsam_i2c_setup_write_transfer(atsam_i2c_bus *bus, Twihs *regs, bool ctrl,
{
atsam_i2c_set_address_regs(regs, slave_addr, ctrl, false);
TWI_WriteByte(regs, *bus->current_msg_byte);
+ ++bus->current_msg_byte;
+ --bus->current_msg_todo;
TWI_EnableIt(regs, TWIHS_IER_TXRDY);
}
@@ -197,8 +179,8 @@ atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs)
uint32_t msg_todo = bus->msg_todo;
uint16_t slave_addr;
bool ten_bit_addr = false;
- uint32_t already_transferred;
bool stop_needed = true;
+ bool read;
ten_bit_addr = atsam_i2c_set_address_size(msgs);
@@ -206,22 +188,17 @@ atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs)
stop_needed = false;
}
- bus->read = (msgs->flags & I2C_M_RD) != 0;
+ read = (msgs->flags & I2C_M_RD) != 0;
slave_addr = msgs->addr;
- already_transferred = (bus->read == true) ? 0 : 1;
- atsam_i2c_set_td(bus, already_transferred, stop_needed);
-
- transfer_desc *trans_desc = &bus->trans_desc;
+ bus->stop_request = stop_needed;
- if (bus->read){
+ if (read){
if (bus->current_msg_todo == 1){
send_stop = true;
}
- atsam_i2c_set_transfer_status(trans_desc, RX_SEND_DATA);
atsam_i2c_setup_read_transfer(regs, ten_bit_addr,
slave_addr, send_stop);
} else {
- atsam_i2c_set_transfer_status(trans_desc, TX_SEND_DATA);
atsam_i2c_setup_write_transfer(bus, regs, ten_bit_addr,
slave_addr);
}
@@ -233,40 +210,28 @@ atsam_i2c_interrupt(void *arg)
atsam_i2c_bus *bus = arg;
uint32_t irqstatus;
bool done = false;
- transfer_desc *trans_desc;
Twihs *regs = bus->regs;
/* read interrupts */
- irqstatus = regs->TWIHS_SR;
+ irqstatus = TWI_GetMaskedStatus(regs);
- if((irqstatus & (TWIHS_SR_ARBLST | TWIHS_SR_NACK)) != 0) {
+ if((irqstatus & ATSAMV_I2C_IRQ_ERROR) != 0) {
done = true;
- }
-
- trans_desc = &bus->trans_desc;
-
- if (((irqstatus & TWIHS_SR_RXRDY) != 0) &&
- (atsam_i2c_is_state(trans_desc, RX_SEND_DATA))){
- /* carry on read transfer */
- atsam_i2c_continue_read(regs, trans_desc);
- } else if (((irqstatus & TWIHS_SR_TXCOMP) != 0) &&
- (atsam_i2c_is_state(trans_desc, TX_RX_STOP_SENT))){
- atsam_i2c_finish_write_transfer(regs, trans_desc);
+ } else if ((irqstatus & TWIHS_SR_RXRDY) != 0) {
+ done = atsam_i2c_continue_read(regs, bus);
+ } else if ((irqstatus & TWIHS_SR_TXCOMP) != 0) {
+ TWI_DisableIt(regs, TWIHS_IDR_TXCOMP);
done = true;
- } else if (((irqstatus & TWIHS_SR_TXRDY) != 0) &&
- (atsam_i2c_is_state(trans_desc, TX_SEND_DATA))){
- atsam_i2c_continue_write(regs, trans_desc);
- if (trans_desc->trans_state == TX_CONT_MESSAGE_NEEDED){
- done = true;
- }
+ } else if ((irqstatus & TWIHS_SR_TXRDY) != 0) {
+ done = atsam_i2c_continue_write(regs, bus);
}
if(done){
- uint32_t err = irqstatus & ATSAMV_I2C_IRQ_ERROR;
+ bus->err = irqstatus & ATSAMV_I2C_IRQ_ERROR;
atsam_i2c_next_packet(bus);
- if (bus->msg_todo == 0 || err != 0) {
+ if (bus->msg_todo == 0 || bus->err != 0) {
atsam_i2c_disable_interrupts(regs);
rtems_binary_semaphore_post(&bus->sem);
} else {
@@ -291,27 +256,38 @@ atsam_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
if ((msgs[i].flags & I2C_M_RECV_LEN) != 0) {
return -EINVAL;
}
+ if (msgs[i].len == 0) {
+ /* Hardware doesn't support zero length messages */
+ return -EINVAL;
+ }
}
bus->msgs = &msgs[0];
bus->msg_todo = msg_count;
bus->current_msg_todo = msgs[0].len;
bus->current_msg_byte = msgs[0].buf;
+ bus->err = 0;
regs = bus->regs;
- atsam_i2c_setup_transfer(bus, regs);
+ /* Start with a clean start. Enable error interrupts. */
+ TWI_ConfigureMaster(bus->regs, bus->output_clock, BOARD_MCK);
+ TWI_EnableIt(regs, ATSAMV_I2C_IRQ_ERROR);
- regs->TWIHS_IER = ATSAMV_I2C_IRQ_ERROR;
+ atsam_i2c_setup_transfer(bus, regs);
eno = rtems_binary_semaphore_wait_timed_ticks(
&bus->sem,
bus->base.timeout
);
- if (eno != 0) {
+ if (eno != 0 || bus->err != 0) {
TWI_ConfigureMaster(bus->regs, bus->output_clock, BOARD_MCK);
rtems_binary_semaphore_try_wait(&bus->sem);
- return -ETIMEDOUT;
+ if (bus->err != 0) {
+ return -EIO;
+ } else {
+ return -ETIMEDOUT;
+ }
}
return 0;
diff --git a/bsps/arm/atsam/include/bsp.h b/bsps/arm/atsam/include/bsp.h
index 2556f6046d..d1b021255c 100644
--- a/bsps/arm/atsam/include/bsp.h
+++ b/bsps/arm/atsam/include/bsp.h
@@ -33,6 +33,7 @@
#include <bspopts.h>
#include <bsp/default-initial-extension.h>
+#include <sys/ioccom.h>
#include <rtems.h>
@@ -109,6 +110,18 @@ void atsam_rtc_get_time(rtems_time_of_day *tod);
void bsp_restart( const void *const addr );
+/*
+ * This ioctl enables the receive DMA for an UART. The DMA can be usefull if you
+ * loose characters in high interrupt load situations.
+ *
+ * Disabling the DMA again is only possible by closing all file descriptors of
+ * that UART.
+ *
+ * Note that every UART needs one DMA channel and the system has only a limited
+ * amount of DMAs. So only use it if you need it.
+ */
+#define ATSAM_UART_ENABLE_RX_DMA _IO('d', 0)
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/bsps/arm/atsam/include/bsp/atsam-i2c.h b/bsps/arm/atsam/include/bsp/atsam-i2c.h
index ae0fe97584..a6a9c27d48 100644
--- a/bsps/arm/atsam/include/bsp/atsam-i2c.h
+++ b/bsps/arm/atsam/include/bsp/atsam-i2c.h
@@ -28,35 +28,23 @@ extern "C" {
#define TWI_AMOUNT_PINS 2
-typedef enum {
- TX_SEND_DATA,
- TX_SEND_STOP,
- TX_CONT_MESSAGE_NEEDED,
- RX_SEND_DATA,
- RX_SEND_STOP,
- RX_CONT_MESSAGE_NEEDED,
- TX_RX_STOP_SENT
-}transfer_state;
-
-typedef struct {
- uint8_t status;
- uint8_t *data;
- bool stop_request;
- uint32_t data_size;
- uint32_t already_transferred;
- transfer_state trans_state;
-} transfer_desc;
-
typedef struct {
i2c_bus base;
- i2c_msg *msgs;
Twihs *regs;
- transfer_desc trans_desc;
+
+ /* First message and number of messages that have to be processed. */
+ i2c_msg *msgs;
uint32_t msg_todo;
+
+ /* Information about the current transfer. */
+ bool stop_request;
uint32_t current_msg_todo;
uint8_t *current_msg_byte;
+
+ /* Error information that can be returned to the task */
+ uint32_t err;
+
uint32_t output_clock;
- bool read;
rtems_binary_semaphore sem;
rtems_vector_number irq;
} atsam_i2c_bus;
diff --git a/bsps/m68k/uC5282/start/linkcmds b/bsps/m68k/uC5282/start/linkcmds
index da97472f1b..af9a69b802 100644
--- a/bsps/m68k/uC5282/start/linkcmds
+++ b/bsps/m68k/uC5282/start/linkcmds
@@ -91,13 +91,13 @@ SECTIONS
* crtn.o are in.
*/
PROVIDE (_init = .);
- *crti.o(.init)
- *(.init)
- *crtn.o(.init)
+ KEEP (*crti.o(.init))
+ KEEP (*(.init))
+ KEEP (*crtn.o(.init))
PROVIDE (_fini = .);
- *crti.o(.fini)
- *(.fini)
- *crtn.o(.fini)
+ KEEP (*crti.o(.fini))
+ KEEP (*(.fini))
+ KEEP (*crtn.o(.fini))
/*
* Special FreeBSD sysctl sections.
@@ -122,18 +122,22 @@ SECTIONS
* crtend.o. The same comments apply to it.
*/
. = ALIGN (16);
- *crtbegin.o(.ctors)
- *(.ctors)
- *crtend.o(.ctors)
- *crtbegin.o(.dtors)
- *(.dtors)
- *crtend.o(.dtors)
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
/*
* Exception frame info
*/
. = ALIGN (16);
- *(.eh_frame)
+ KEEP (*(.eh_frame))
/*
* Read-only data
@@ -141,7 +145,7 @@ SECTIONS
. = ALIGN (16);
_rodata_start = . ;
*(.rodata*)
- KEEP (*(SORT(.rtemsroset.*)))
+ KEEP (*(SORT(.rtemsroset.*)))
*(.gnu.linkonce.r*)
. = ALIGN (16);
@@ -179,7 +183,7 @@ SECTIONS
KEEP (*(SORT(.rtemsrwset.*)))
*(.gnu.linkonce.d*)
*(.gcc_except_table*)
- *(.jcr)
+ KEEP (*(.jcr))
. = ALIGN (16);
PROVIDE (_edata = .);
PROVIDE (_copy_end = .);
diff --git a/bsps/powerpc/include/libcpu/io.h b/bsps/powerpc/include/libcpu/io.h
index 521c97801d..c4e529f4d5 100644
--- a/bsps/powerpc/include/libcpu/io.h
+++ b/bsps/powerpc/include/libcpu/io.h
@@ -107,6 +107,7 @@ static inline void out_be16(volatile uint16_t *addr, uint16_t val)
__asm__ __volatile__("sth%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
}
+#ifndef in_le32
static inline uint32_t in_le32(const volatile uint32_t *addr)
{
uint32_t ret;
@@ -115,7 +116,9 @@ static inline uint32_t in_le32(const volatile uint32_t *addr)
"r" (addr), "m" (*addr));
return ret;
}
+#endif
+#ifndef in_be32
static inline uint32_t in_be32(const volatile uint32_t *addr)
{
uint32_t ret;
@@ -123,17 +126,22 @@ static inline uint32_t in_be32(const volatile uint32_t *addr)
__asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
return ret;
}
+#endif
+#ifndef out_le32
static inline void out_le32(volatile uint32_t *addr, uint32_t val)
{
__asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
"r" (val), "r" (addr));
}
+#endif
+#ifndef out_be32
static inline void out_be32(volatile uint32_t *addr, uint32_t val)
{
__asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
}
+#endif
#endif /* ASM */
#endif /* _LIBCPU_IO_H */
diff --git a/bsps/powerpc/motorola_powerpc/include/bsp.h b/bsps/powerpc/motorola_powerpc/include/bsp.h
index 62e740272a..7d362bf406 100644
--- a/bsps/powerpc/motorola_powerpc/include/bsp.h
+++ b/bsps/powerpc/motorola_powerpc/include/bsp.h
@@ -31,11 +31,11 @@
#include <rtems.h>
#include <libcpu/io.h>
#include <bsp/vectors.h>
-
+
#ifdef qemu
#include <rtems/bspcmdline.h>
#endif
-
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -115,6 +115,36 @@ extern "C" {
#endif
#endif
+/*
+ * The BSP has PCI devices. Enable support in LibBSD.
+ */
+#define BSP_HAS_PC_PCI
+
+/*
+ * Remap the PCI address space for LibBSD
+ */
+#define RTEMS_BSP_PCI_IO_REGION_BASE 0
+#define RTEMS_BSP_PCI_MEM_REGION_BASE PCI_DRAM_OFFSET
+
+/*
+ * Remap the PCI address space for LibBSD
+ */
+#define RTEMS_BSP_ADDR_PTR(_type) uint ## _type ## _t __volatile*
+#define RTEMS_BSP_ADDR_CPTR(_type) const RTEMS_BSP_ADDR_PTR(_type)
+#define RTEMS_BSP_ADDRESS_READ(_addr, _type) \
+ *((RTEMS_BSP_ADDR_CPTR(_type)) (((RTEMS_BSP_ADDR_CPTR(8)) _addr) + PCI_DRAM_OFFSET))
+#define RTEMS_BSP_ADDRESS_WRITE(_addr, _val, _type) \
+ *((RTEMS_BSP_ADDR_PTR(_type)) (((RTEMS_BSP_ADDR_PTR(8)) _addr) + PCI_DRAM_OFFSET)) = (_val)
+
+#define RTEMS_BSP_READ_1(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 8)
+#define RTEMS_BSP_READ_2(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 16)
+#define RTEMS_BSP_READ_4(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 32)
+#define RTEMS_BSP_READ_8(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 64)
+
+#define RTEMS_BSP_WRITE_1(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 8)
+#define RTEMS_BSP_WRITE_2(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 16)
+#define RTEMS_BSP_WRITE_4(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 32)
+#define RTEMS_BSP_WRITE_8(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 64)
/*
* Base address definitions for several devices
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 18eda95543..202cf3c346 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -930,6 +930,7 @@ librtemscpu_a_SOURCES += score/src/schedulercbssetparameters.c
librtemscpu_a_SOURCES += score/src/schedulercbsreleasejob.c
librtemscpu_a_SOURCES += score/src/schedulercbsunblock.c
librtemscpu_a_SOURCES += score/src/stackallocator.c
+librtemscpu_a_SOURCES += score/src/stackallocatorforidle.c
librtemscpu_a_SOURCES += score/src/pheapallocate.c
librtemscpu_a_SOURCES += score/src/pheapextend.c
librtemscpu_a_SOURCES += score/src/pheapfree.c
diff --git a/cpukit/include/link_elf.h b/cpukit/include/link_elf.h
index 6cab3c2c7f..6483c021fd 100644
--- a/cpukit/include/link_elf.h
+++ b/cpukit/include/link_elf.h
@@ -13,6 +13,10 @@
#include <stdint.h>
#include <rtems/rtl/rtl-obj-fwd.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum sections
{
rap_text = 0,
@@ -76,4 +80,8 @@ int _rtld_linkmap_add (rtems_rtl_obj* obj);
* Remove link map from the list.
*/
void _rtld_linkmap_delete (rtems_rtl_obj* obj);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* _LINK_ELF_H_ */
diff --git a/cpukit/include/linux/rbtree.h b/cpukit/include/linux/rbtree.h
index 8fc575240f..ec0fac1af9 100644
--- a/cpukit/include/linux/rbtree.h
+++ b/cpukit/include/linux/rbtree.h
@@ -17,6 +17,10 @@
#include <rtems/score/rbtree.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define rb_node RBTree_Node
#define rb_left Node.rbe_left
@@ -96,7 +100,7 @@ static inline struct rb_node *rb_last( struct rb_root *root )
static inline void rb_replace_node(
struct rb_node *victim,
- struct rb_node *replacement,
+ struct rb_node *replacement,
struct rb_root *root
)
{
@@ -138,4 +142,8 @@ static inline struct rb_node *rb_parent( struct rb_node *node )
node = next \
)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _LINUX_RBTREE_H */
diff --git a/cpukit/include/rtems/capture.h b/cpukit/include/rtems/capture.h
index c37d652211..4ab638ec24 100644
--- a/cpukit/include/rtems/capture.h
+++ b/cpukit/include/rtems/capture.h
@@ -838,7 +838,7 @@ rtems_capture_task_flags (rtems_tcb* tcb)
static inline rtems_capture_control*
rtems_capture_task_control (rtems_tcb* tcb)
{
- return tcb->Capture.control;
+ return (rtems_capture_control*) tcb->Capture.control;
}
/**
@@ -853,7 +853,7 @@ rtems_capture_task_control (rtems_tcb* tcb)
static inline uint32_t
rtems_capture_task_control_flags (rtems_tcb* tcb)
{
- rtems_capture_control* control = tcb->Capture.control;
+ rtems_capture_control* control = rtems_capture_task_control (tcb);
if (!control)
return 0;
return control->flags;
diff --git a/cpukit/include/rtems/confdefs/percpu.h b/cpukit/include/rtems/confdefs/percpu.h
index f3a9a4f3e7..b7baebea05 100644
--- a/cpukit/include/rtems/confdefs/percpu.h
+++ b/cpukit/include/rtems/confdefs/percpu.h
@@ -133,11 +133,19 @@ RTEMS_DEFINE_GLOBAL_SYMBOL(
const size_t _Thread_Idle_stack_size = CONFIGURE_IDLE_TASK_STACK_SIZE;
-char _Thread_Idle_stacks[
- _CONFIGURE_MAXIMUM_PROCESSORS
- * ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
-] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
-RTEMS_SECTION( ".rtemsstack.idle" );
+/*
+ * If the user provides a custom idle stack allocator, then we do not need
+ * memory reserved for the stacks but the symbol is still referenced in
+ * threadcreateidle.c. The code path just never uses it. Make it minimal
+ * size to proceed.
+ */
+#ifndef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
+ char _Thread_Idle_stacks[
+ _CONFIGURE_MAXIMUM_PROCESSORS
+ * ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
+ ] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
+ RTEMS_SECTION( ".rtemsstack.idle" );
+#endif
#if defined(CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION) && \
!defined(CONFIGURE_IDLE_TASK_BODY)
diff --git a/cpukit/include/rtems/confdefs/wkspace.h b/cpukit/include/rtems/confdefs/wkspace.h
index 484dde20ea..9ef9d90b85 100644
--- a/cpukit/include/rtems/confdefs/wkspace.h
+++ b/cpukit/include/rtems/confdefs/wkspace.h
@@ -132,12 +132,14 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
#if defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
&& defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
+ /* Custom allocator may or may not use the work space. */
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
const bool _Stack_Allocator_avoids_workspace = true;
#else
const bool _Stack_Allocator_avoids_workspace = false;
#endif
+ /* Custom allocator may or may not need initialization. */
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_INIT
const Stack_Allocator_initialize _Stack_Allocator_initialize =
CONFIGURE_TASK_STACK_ALLOCATOR_INIT;
@@ -145,16 +147,30 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
const Stack_Allocator_initialize _Stack_Allocator_initialize = NULL;
#endif
+ /* Custom allocator must include allocate and free */
const Stack_Allocator_allocate _Stack_Allocator_allocate =
CONFIGURE_TASK_STACK_ALLOCATOR;
const Stack_Allocator_free _Stack_Allocator_free =
CONFIGURE_TASK_STACK_DEALLOCATOR;
+
+/*
+ * Must provide both a custom stack allocator and deallocator
+ */
#elif defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
|| defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
#error "CONFIGURE_TASK_STACK_ALLOCATOR and CONFIGURE_TASK_STACK_DEALLOCATOR must be both defined or both undefined"
#endif
+/*
+ * Custom IDLE thread stacks allocator. If this is provided, it is assumed
+ * that the allocator is providing its own memory for these stacks.
+ */
+#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
+ const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
+ CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE;
+#endif
+
#ifdef CONFIGURE_DIRTY_MEMORY
RTEMS_SYSINIT_ITEM(
_Memory_Dirty_free_areas,
diff --git a/cpukit/include/rtems/config.h b/cpukit/include/rtems/config.h
index e82c7abf11..a826581658 100644
--- a/cpukit/include/rtems/config.h
+++ b/cpukit/include/rtems/config.h
@@ -129,6 +129,9 @@ uint32_t rtems_configuration_get_maximum_extensions( void );
#define rtems_configuration_get_stack_free_hook() \
(_Stack_Allocator_free)
+#define rtems_configuration_get_stack_allocate_for_idle_hook() \
+ (_Stack_Allocator_allocate_for_idle)
+
/**
* This macro assists in accessing the field which indicates whether
* RTEMS is responsible for zeroing the Executive Workspace.
diff --git a/cpukit/include/rtems/posix/muteximpl.h b/cpukit/include/rtems/posix/muteximpl.h
index 435b43634d..3d717420f2 100644
--- a/cpukit/include/rtems/posix/muteximpl.h
+++ b/cpukit/include/rtems/posix/muteximpl.h
@@ -2,8 +2,8 @@
* @file
*
* @brief Private Inlined Routines for POSIX Mutex's.
- *
- * This include file contains the static inline implementation of the private
+ *
+ * This include file contains the static inline implementation of the private
* inlined routines for POSIX mutex's.
*/
@@ -104,7 +104,7 @@ RTEMS_INLINE_ROUTINE POSIX_Mutex_Protocol _POSIX_Mutex_Get_protocol(
unsigned long flags
)
{
- return flags & POSIX_MUTEX_PROTOCOL_MASK;
+ return (POSIX_Mutex_Protocol) (flags & POSIX_MUTEX_PROTOCOL_MASK);
}
RTEMS_INLINE_ROUTINE bool _POSIX_Mutex_Is_recursive(
@@ -484,4 +484,3 @@ bool _POSIX_Mutex_Auto_initialization( POSIX_Mutex_Control *the_mutex );
#endif
/* end of include file */
-
diff --git a/cpukit/include/rtems/posix/pthreadattrimpl.h b/cpukit/include/rtems/posix/pthreadattrimpl.h
index b5e02ec1c7..7cd69142a6 100644
--- a/cpukit/include/rtems/posix/pthreadattrimpl.h
+++ b/cpukit/include/rtems/posix/pthreadattrimpl.h
@@ -72,7 +72,7 @@ RTEMS_INLINE_ROUTINE void _POSIX_Threads_Get_sched_param_sporadic(
#if defined(RTEMS_POSIX_API)
const POSIX_API_Control *api;
- api = the_thread->API_Extensions[ THREAD_API_POSIX ];
+ api = (const POSIX_API_Control*) the_thread->API_Extensions[ THREAD_API_POSIX ];
param->sched_ss_low_priority = _POSIX_Priority_From_core(
scheduler,
api->Sporadic.Low_priority.priority
diff --git a/cpukit/include/rtems/rtl/rtl-obj.h b/cpukit/include/rtems/rtl/rtl-obj.h
index f27ae3259d..c1fe51306b 100644
--- a/cpukit/include/rtems/rtl/rtl-obj.h
+++ b/cpukit/include/rtems/rtl/rtl-obj.h
@@ -231,7 +231,7 @@ struct rtems_rtl_obj
size_t tramps_size; /**< Size of the trampoline memory. */
void* tramp_brk; /**< Trampoline memory allocator. MD
* relocators can take memory from the
- * break upto the size. */
+ * break up to the size. */
size_t tramp_relocs; /**< Number of slots reserved for
* relocs. The remainder are for
* unresolved symbols. */
@@ -333,7 +333,7 @@ static inline bool rtems_rtl_obj_text_inside (const rtems_rtl_obj* obj,
{
return
(address >= obj->text_base) &&
- (address < (obj->text_base + obj->text_size));
+ ((char*) address < ((char*) obj->text_base + obj->text_size));
}
/**
@@ -374,11 +374,23 @@ static inline bool rtems_rtl_obj_has_symbol (const rtems_rtl_obj* obj,
* @param size The size to be allocated.
* @retval bool Returns @true if the space is available.
*/
+static inline size_t rtems_rtl_obj_tramp_avail_space (const rtems_rtl_obj* obj)
+{
+ return (char*) obj->tramp_brk - (char*) obj->trampoline;
+}
+
+/**
+ * Is there space in the trampoline memory for a trapoline.
+ *
+ * @param obj The object file's descriptor to check for available space.
+ * @param size The size to be allocated.
+ * @retval bool Returns @true if the space is available.
+ */
static inline bool rtems_rtl_obj_has_tramp_space (const rtems_rtl_obj* obj,
const size_t size)
{
return (obj->trampoline != NULL &&
- ((obj->tramp_brk - obj->trampoline) + size) <= obj->tramps_size);
+ (rtems_rtl_obj_tramp_avail_space (obj) + size) <= obj->tramps_size);
}
/**
@@ -402,7 +414,7 @@ static inline size_t rtems_rtl_obj_trampoline_slots (const rtems_rtl_obj* obj)
static inline size_t rtems_rtl_obj_trampolines (const rtems_rtl_obj* obj)
{
return obj->trampoline == NULL || obj->tramp_size == 0 ?
- 0 : (obj->tramp_brk - obj->trampoline) / obj->tramp_size;
+ 0 : rtems_rtl_obj_tramp_avail_space (obj) / obj->tramp_size;
}
/**
diff --git a/cpukit/include/rtems/rtl/rtl.h b/cpukit/include/rtems/rtl/rtl.h
index 67d7e96be3..3c74370187 100644
--- a/cpukit/include/rtems/rtl/rtl.h
+++ b/cpukit/include/rtems/rtl/rtl.h
@@ -88,7 +88,7 @@ extern struct r_debug _rtld_debug;
* Debugger break function. Call when debugging to have it read the _rtld_debug
* variable.
*/
-extern void _rtld_debug_state (void);
+void _rtld_debug_state (void);
/**
* The type of constructor/destructor function.
diff --git a/cpukit/include/rtems/score/cpustdatomic.h b/cpukit/include/rtems/score/cpustdatomic.h
index 31a17932c6..8401f68e31 100644
--- a/cpukit/include/rtems/score/cpustdatomic.h
+++ b/cpukit/include/rtems/score/cpustdatomic.h
@@ -294,7 +294,7 @@ static inline uintptr_t _CPU_atomic_Load_uintptr( const CPU_atomic_Uintptr *obj,
static inline void _CPU_atomic_Store_uint( CPU_atomic_Uint *obj, unsigned int desired, CPU_atomic_Order order )
{
#if defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_ATOMIC)
- obj->store( desired );
+ obj->store( desired, order );
#elif defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_STDATOMIC)
atomic_store_explicit( obj, desired, order );
#else
@@ -314,7 +314,7 @@ static inline void _CPU_atomic_Store_uint( CPU_atomic_Uint *obj, unsigned int de
static inline void _CPU_atomic_Store_ulong( CPU_atomic_Ulong *obj, unsigned long desired, CPU_atomic_Order order )
{
#if defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_ATOMIC)
- obj->store( desired );
+ obj->store( desired, order );
#elif defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_STDATOMIC)
atomic_store_explicit( obj, desired, order );
#else
@@ -334,7 +334,7 @@ static inline void _CPU_atomic_Store_ulong( CPU_atomic_Ulong *obj, unsigned long
static inline void _CPU_atomic_Store_uintptr( CPU_atomic_Uintptr *obj, uintptr_t desired, CPU_atomic_Order order )
{
#if defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_ATOMIC)
- obj->store( desired );
+ obj->store( desired, order );
#elif defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_STDATOMIC)
atomic_store_explicit( obj, desired, order );
#else
diff --git a/cpukit/include/rtems/score/heapimpl.h b/cpukit/include/rtems/score/heapimpl.h
index d3ee0ff88a..f74b5fc562 100644
--- a/cpukit/include/rtems/score/heapimpl.h
+++ b/cpukit/include/rtems/score/heapimpl.h
@@ -407,15 +407,7 @@ Heap_Block *_Heap_Block_allocate(
(*heap->Protection.block_error)( heap, block, reason );
}
- static inline void _Heap_Protection_free_all_delayed_blocks( Heap_Control *heap )
- {
- uintptr_t large = 0
- - (uintptr_t) HEAP_BLOCK_HEADER_SIZE
- - (uintptr_t) HEAP_ALLOC_BONUS
- - (uintptr_t) 1;
- void *p = _Heap_Allocate( heap, large );
- _Heap_Free( heap, p );
- }
+ void _Heap_Protection_free_all_delayed_blocks( Heap_Control *heap );
#endif
/**
diff --git a/cpukit/include/rtems/score/objectimpl.h b/cpukit/include/rtems/score/objectimpl.h
index c540f90166..ed0ce2aa10 100644
--- a/cpukit/include/rtems/score/objectimpl.h
+++ b/cpukit/include/rtems/score/objectimpl.h
@@ -938,6 +938,25 @@ RTEMS_INLINE_ROUTINE void _Objects_Free(
}
/**
+ * @brief Returns true, if the object associated with the zero-based index is
+ * contained in an allocated block of objects, otherwise false.
+ *
+ * @param index is the zero-based object index.
+ * @param objects_per_block is the object count per block.
+ *
+ * @retval true The object associated with the zero-based index is in an
+ * allocated block of objects.
+ * @retval false Otherwise.
+ */
+RTEMS_INLINE_ROUTINE bool _Objects_Is_in_allocated_block(
+ Objects_Maximum index,
+ Objects_Maximum objects_per_block
+)
+{
+ return index >= objects_per_block;
+}
+
+/**
* @brief Activate the object.
*
* This function must be only used in case this objects information supports
@@ -952,15 +971,17 @@ RTEMS_INLINE_ROUTINE void _Objects_Activate_unlimited(
)
{
Objects_Maximum objects_per_block;
- Objects_Maximum block;
+ Objects_Maximum index;
_Assert( _Objects_Is_auto_extend( information ) );
objects_per_block = information->objects_per_block;
- block = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM;
+ index = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM;
+
+ if ( _Objects_Is_in_allocated_block( index, objects_per_block ) ) {
+ Objects_Maximum block;
- if ( block > objects_per_block ) {
- block /= objects_per_block;
+ block = index / objects_per_block;
information->inactive_per_block[ block ]--;
information->inactive--;
diff --git a/cpukit/include/rtems/score/priority.h b/cpukit/include/rtems/score/priority.h
index 54b91a871b..a6c65d3c4c 100644
--- a/cpukit/include/rtems/score/priority.h
+++ b/cpukit/include/rtems/score/priority.h
@@ -24,12 +24,12 @@
#include <rtems/score/cpu.h>
#include <rtems/score/rbtree.h>
-struct _Scheduler_Control;
-
#ifdef __cplusplus
extern "C" {
#endif
+struct _Scheduler_Control;
+
/**
* @defgroup RTEMSScorePriority Priority Handler
*
diff --git a/cpukit/include/rtems/score/priorityimpl.h b/cpukit/include/rtems/score/priorityimpl.h
index b33419acdb..3b92d3375a 100644
--- a/cpukit/include/rtems/score/priorityimpl.h
+++ b/cpukit/include/rtems/score/priorityimpl.h
@@ -389,7 +389,7 @@ RTEMS_INLINE_ROUTINE bool _Priority_Less(
const Priority_Control *the_left;
const Priority_Node *the_right;
- the_left = left;
+ the_left = (const Priority_Control*) left;
the_right = RTEMS_CONTAINER_OF( right, Priority_Node, Node.RBTree );
return *the_left < the_right->priority;
diff --git a/cpukit/include/rtems/score/scheduleredfimpl.h b/cpukit/include/rtems/score/scheduleredfimpl.h
index f2bec2dfbe..fc8c67c163 100644
--- a/cpukit/include/rtems/score/scheduleredfimpl.h
+++ b/cpukit/include/rtems/score/scheduleredfimpl.h
@@ -100,7 +100,7 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_EDF_Less(
Priority_Control prio_left;
Priority_Control prio_right;
- the_left = left;
+ the_left = (const Priority_Control*) left;
the_right = RTEMS_CONTAINER_OF( right, Scheduler_EDF_Node, Node );
prio_left = *the_left;
@@ -128,7 +128,7 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_EDF_Priority_less_equal(
Priority_Control prio_left;
Priority_Control prio_right;
- the_left = left;
+ the_left = (const Priority_Control*) left;
the_right = RTEMS_CONTAINER_OF( right, Scheduler_EDF_Node, Node );
prio_left = *the_left;
diff --git a/cpukit/include/rtems/score/stack.h b/cpukit/include/rtems/score/stack.h
index df1df74867..bad89e66fc 100644
--- a/cpukit/include/rtems/score/stack.h
+++ b/cpukit/include/rtems/score/stack.h
@@ -82,6 +82,23 @@ typedef void *( *Stack_Allocator_allocate )( size_t stack_size );
typedef void ( *Stack_Allocator_free )( void *addr );
/**
+ * @brief Stack allocator allocate for idle handler.
+ *
+ * The allocate for idle handler is optional even when the user thread stack
+ * allocator and deallocator are configured.
+ *
+ * @param cpu Index of the CPU for the IDLE thread using this stack
+ * @param stack_size The size of the stack area to allocate in bytes.
+ *
+ * @retval NULL Not enough memory.
+ * @retval other Pointer to begin of stack area.
+ */
+typedef void *( *Stack_Allocator_allocate_for_idle )(
+ uint32_t cpu,
+ size_t stack_size
+);
+
+/**
* @brief The minimum stack size.
*
* Application provided via <rtems/confdefs.h>.
@@ -124,6 +141,13 @@ extern const Stack_Allocator_allocate _Stack_Allocator_allocate;
extern const Stack_Allocator_free _Stack_Allocator_free;
/** @} */
+/**
+ * @brief The stack allocator allocate stack for idle thread handler.
+ *
+ * Application provided via <rtems/confdefs.h>.
+ */
+extern const Stack_Allocator_allocate_for_idle
+ _Stack_Allocator_allocate_for_idle;
#ifdef __cplusplus
}
diff --git a/cpukit/include/rtems/score/timecounter.h b/cpukit/include/rtems/score/timecounter.h
index b71ccd3948..64429eae7b 100644
--- a/cpukit/include/rtems/score/timecounter.h
+++ b/cpukit/include/rtems/score/timecounter.h
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (c) 2015 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2015, 2021 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -247,6 +247,28 @@ extern volatile int32_t _Timecounter_Time_uptime;
*/
extern struct timecounter *_Timecounter;
+/**
+ * @brief Handler doing the NTP update second processing shall have this type.
+ *
+ * @param[in, out] adjustment is the NTP time adjustment.
+ *
+ * @param[in, out] newsec is the number of seconds since Unix epoch.
+ */
+typedef void ( *Timecounter_NTP_update_second )(
+ int64_t *adjustment,
+ time_t *newsec
+);
+
+/**
+ * @brief Sets the NTP update second handler.
+ *
+ * @param handler is the new NTP update second handler used to carry out the
+ * NTP update second processing.
+ */
+void _Timecounter_Set_NTP_update_second(
+ Timecounter_NTP_update_second handler
+);
+
/** @} */
#ifdef __cplusplus
diff --git a/cpukit/include/rtems/score/tls.h b/cpukit/include/rtems/score/tls.h
index 65a49d87be..322be30c7a 100644
--- a/cpukit/include/rtems/score/tls.h
+++ b/cpukit/include/rtems/score/tls.h
@@ -222,7 +222,7 @@ static inline void *_TLS_TCB_at_area_begin_initialize( void *tls_area )
{
void *tls_block = (char *) tls_area
+ _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
- TLS_Thread_control_block *tcb = tls_area;
+ TLS_Thread_control_block *tcb = (TLS_Thread_control_block*) tls_area;
uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
((char *) tls_block + aligned_size);
diff --git a/cpukit/include/rtems/score/watchdogimpl.h b/cpukit/include/rtems/score/watchdogimpl.h
index a52fb1c2cb..ed9d1ef5cd 100644
--- a/cpukit/include/rtems/score/watchdogimpl.h
+++ b/cpukit/include/rtems/score/watchdogimpl.h
@@ -150,7 +150,7 @@ RTEMS_INLINE_ROUTINE Watchdog_State _Watchdog_Get_state(
const Watchdog_Control *the_watchdog
)
{
- return RB_COLOR( &the_watchdog->Node.RBTree, Node );
+ return (Watchdog_State) RB_COLOR( &the_watchdog->Node.RBTree, Node );
}
/**
diff --git a/cpukit/include/rtems/termiostypes.h b/cpukit/include/rtems/termiostypes.h
index 6930e5958b..59b1b3dd96 100644
--- a/cpukit/include/rtems/termiostypes.h
+++ b/cpukit/include/rtems/termiostypes.h
@@ -367,6 +367,10 @@ typedef struct rtems_termios_tty {
*/
rtems_id rxTaskId;
rtems_id txTaskId;
+ /*
+ * Information for the tx task how many characters have been dequeued.
+ */
+ int txTaskCharsDequeued;
/*
* line discipline related stuff
@@ -482,7 +486,7 @@ struct rtems_termios_linesw {
int (*l_read )(struct rtems_termios_tty *tp,rtems_libio_rw_args_t *args);
int (*l_write)(struct rtems_termios_tty *tp,rtems_libio_rw_args_t *args);
int (*l_rint )(int c,struct rtems_termios_tty *tp);
- int (*l_start)(struct rtems_termios_tty *tp);
+ int (*l_start)(struct rtems_termios_tty *tp,int len);
int (*l_ioctl)(struct rtems_termios_tty *tp,rtems_libio_ioctl_args_t *args);
int (*l_modem)(struct rtems_termios_tty *tp,int flags);
};
diff --git a/cpukit/libcsupport/src/posix_devctl.c b/cpukit/libcsupport/src/posix_devctl.c
index 3ff9dd929f..d875895b84 100644
--- a/cpukit/libcsupport/src/posix_devctl.c
+++ b/cpukit/libcsupport/src/posix_devctl.c
@@ -35,6 +35,7 @@
#include <rtems/seterr.h>
#include <unistd.h>
+#include <fcntl.h>
int posix_devctl(
int fd,
@@ -44,6 +45,15 @@ int posix_devctl(
int *__restrict dev_info_ptr
)
{
+ int rv = 0;
+
+ /*
+ * posix_devctl() is supposed to return an errno. eerno needs to be
+ * preserved in spite of calling methods (e.g., close, fcntl, and ioctl)
+ * that set it.
+ */
+ int errno_copy = errno;
+
/*
* The POSIX 1003.26 standard allows for library implementations
* that implement posix_devctl() using ioctl(). In this case,
@@ -72,15 +82,69 @@ int posix_devctl(
}
/*
- * The FACE Technical Standard Edition 3.0 and newer requires the SOCKCLOSE
- * ioctl command. This is because the Security Profile does not include
- * close() and applications need a way to close sockets. Closing sockets is
- * a minimum requirement so using close() in the implementation meets that
- * requirement but also lets the application close other file types.
+ *
*/
- if (dcmd == SOCKCLOSE ) {
- return close(fd);
+ switch (dcmd) {
+
+ /*
+ * The FACE Technical Standard Edition 3.0 and newer requires the SOCKCLOSE
+ * ioctl command. This is because the Security Profile does not include
+ * close() and applications need a way to close sockets. Closing sockets is
+ * a minimum requirement so using close() in the implementation meets that
+ * requirement but also lets the application close other file types.
+ */
+ case SOCKCLOSE:
+ if (close(fd) != 0) {
+ rv = errno;
+ errno = errno_copy;
+
+ return rv;
+ }
+ break;
+
+ /*
+ * The FACE Technical Standard Edition 3.0 and newer requires the
+ * posix_devctl command to support the FIONBIO subcommand.
+ */
+ case FIONBIO: {
+ int tmp_flag;
+ int flag;
+
+ if (nbyte != sizeof(int)) {
+ return EINVAL;
+ }
+
+ tmp_flag = fcntl(fd, F_GETFL, 0);
+ if (tmp_flag == -1) {
+ rv = errno;
+ errno = errno_copy;
+
+ return rv;
+ }
+
+ flag = *(int *)dev_data_ptr;
+
+ if (flag != 0) {
+ tmp_flag |= O_NONBLOCK;
+ } else {
+ tmp_flag &= ~O_NONBLOCK;
+ }
+
+ (void) fcntl(fd, F_SETFL, tmp_flag);
+ break;
+ }
+
+ default:
+ if (ioctl(fd, dcmd, dev_data_ptr) != 0) {
+ rv = errno;
+ errno = errno_copy;
+
+ return errno;
+ }
+ break;
}
- return ioctl(fd, dcmd, dev_data_ptr);
+ errno = errno_copy;
+
+ return rv;
}
diff --git a/cpukit/libcsupport/src/sync.c b/cpukit/libcsupport/src/sync.c
index 265c6f07c9..0ea77422f1 100644
--- a/cpukit/libcsupport/src/sync.c
+++ b/cpukit/libcsupport/src/sync.c
@@ -1,13 +1,13 @@
/**
- * @file
+ * @file
*
- * @brief Synchronize Data on Disk with Memory
- * @ingroup libcsupport
+ * @ingroup libcsupport
+ *
+ * @brief This source file contains the implementation of sync().
*/
/*
- * COPYRIGHT (c) 1989-2008.
- * On-Line Applications Research Corporation (OAR).
+ * Copyright (C) 2022 embedded brains GmbH
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -18,85 +18,16 @@
#include "config.h"
#endif
-/* Since we compile with strict ANSI we need to undef it to get
- * prototypes for extensions
- */
-#undef __STRICT_ANSI__
-int fdatasync(int); /* still not always prototyped */
-
-
#include <unistd.h>
-#include <stdio.h>
-
-#include <rtems.h>
-#include <rtems/score/thread.h>
-#include <rtems/score/percpu.h>
-
-/* XXX check standards -- Linux version appears to be void */
-void _fwalk(struct _reent *, void *);
-
-
-static void sync_wrapper(FILE *f)
-{
- int fn = fileno(f);
-
- /*
- * There is no way to report errors here. So this is a best-effort approach.
- */
- (void) fsync(fn);
- (void) fdatasync(fn);
-}
-/* iterate over all FILE *'s for this thread */
-static bool sync_per_thread(Thread_Control *t, void *arg)
-{
- struct _reent *current_reent;
- struct _reent *this_reent;
-
- /*
- * The sync_wrapper() function will operate on the current thread's
- * reent structure so we will temporarily use that.
- */
- this_reent = t->libc_reent;
- if ( this_reent ) {
- Thread_Control *executing = _Thread_Get_executing();
- current_reent = executing->libc_reent;
- executing->libc_reent = this_reent;
- _fwalk (t->libc_reent, sync_wrapper);
- executing->libc_reent = current_reent;
- }
-
- return false;
-}
+#include <rtems/libio_.h>
-/*
- * _global_impure_ptr is not prototyped in any .h files.
- * We have to extern it here.
- */
-extern struct _reent * const _global_impure_ptr __ATTRIBUTE_IMPURE_PTR__;
-
-/**
- * This function operates by as follows:
- * for all threads
- * for all FILE *
- * fsync()
- * fdatasync()
- */
-void sync(void)
+void sync( void )
{
+ int fd;
- /*
- * Walk the one used initially by RTEMS.
- */
- _fwalk(_global_impure_ptr, sync_wrapper);
-
- /*
- * XXX Do we walk the one used globally by newlib?
- * XXX Do we need the RTEMS global one?
- */
-
- /*
- * Now walk all the per-thread reentrancy structures.
- */
- rtems_task_iterate(sync_per_thread, NULL);
+ for ( fd = 0; fd < (int) rtems_libio_number_iops; ++fd ) {
+ (void) fsync( fd );
+ (void) fdatasync( fd );
+ }
}
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index 75925cf8ec..2b354203e9 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -1966,6 +1966,7 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
/*
* send wake up to transmitter task
*/
+ tty->txTaskCharsDequeued = len;
sc = rtems_event_send(tty->txTaskId, TERMIOS_TX_START_EVENT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
@@ -1977,7 +1978,7 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
* call PPP line discipline start function
*/
if (rtems_termios_linesw[tty->t_line].l_start != NULL) {
- rtems_termios_linesw[tty->t_line].l_start(tty);
+ rtems_termios_linesw[tty->t_line].l_start(tty, len);
}
return 0; /* nothing to output in IRQ... */
}
@@ -2012,7 +2013,7 @@ static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
* call any line discipline start function
*/
if (rtems_termios_linesw[tty->t_line].l_start != NULL) {
- rtems_termios_linesw[tty->t_line].l_start(tty);
+ rtems_termios_linesw[tty->t_line].l_start(tty, tty->txTaskCharsDequeued);
if (tty->t_line == PPPDISC) {
/*
diff --git a/cpukit/libfs/src/imfs/imfs_memfile.c b/cpukit/libfs/src/imfs/imfs_memfile.c
index 0f19859fac..b6cd7812f2 100644
--- a/cpukit/libfs/src/imfs/imfs_memfile.c
+++ b/cpukit/libfs/src/imfs/imfs_memfile.c
@@ -189,9 +189,10 @@ static int IMFS_memfile_extend(
offset = 0;
}
} else {
- for ( ; block>=old_blocks ; block-- ) {
+ for ( ; block>old_blocks ; block-- ) {
IMFS_memfile_remove_block( memfile, block );
}
+ IMFS_memfile_remove_block( memfile, old_blocks );
rtems_set_errno_and_return_minus_one( ENOSPC );
}
}
diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt.c b/cpukit/libmisc/rtems-fdt/rtems-fdt.c
index b96ccbc1b0..0c8ccfd2c2 100644
--- a/cpukit/libmisc/rtems-fdt/rtems-fdt.c
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.c
@@ -163,7 +163,7 @@ rtems_fdt_init_index (rtems_fdt_handle* fdt, rtems_fdt_blob* blob)
}
names = calloc(1, total_name_memory);
- if (!entries)
+ if (!names)
{
free(entries);
return -RTEMS_FDT_ERR_NO_MEMORY;
@@ -680,14 +680,14 @@ rtems_fdt_unload (rtems_fdt_handle* handle)
rtems_chain_extract_unprotected (&handle->blob->node);
+ rtems_fdt_release_index(&handle->blob->index);
+
free (handle->blob);
handle->blob = NULL;
rtems_fdt_unlock (fdt);
- rtems_fdt_release_index(&handle->blob->index);
-
return 0;
}
diff --git a/cpukit/libmisc/shell/main_chmod.c b/cpukit/libmisc/shell/main_chmod.c
index 0c39072f6b..288fd52f4c 100644
--- a/cpukit/libmisc/shell/main_chmod.c
+++ b/cpukit/libmisc/shell/main_chmod.c
@@ -53,7 +53,7 @@ static int rtems_shell_main_chmod(
* Now change the files modes
*/
for (n=2 ; n < argc ; n++)
- chmod(argv[n++], mode);
+ chmod(argv[n], mode);
return 0;
}
diff --git a/cpukit/libmisc/shell/main_edit.c b/cpukit/libmisc/shell/main_edit.c
index e43ff68d2b..681e8c5f3c 100644
--- a/cpukit/libmisc/shell/main_edit.c
+++ b/cpukit/libmisc/shell/main_edit.c
@@ -407,6 +407,9 @@ static void move_gap(struct editor *ed, int pos, int minsize) {
if (gapsize + MINEXTEND > minsize) minsize = gapsize + MINEXTEND;
newsize = (ed->end - ed->start) - gapsize + minsize;
start = (unsigned char *) malloc(newsize); // TODO check for out of memory
+ if (start == NULL) {
+ return;
+ }
gap = start + pos;
rest = gap + minsize;
end = start + newsize;
@@ -1789,14 +1792,14 @@ static void save_editor(struct editor *ed) {
ed->refresh = 1;
}
-static void close_editor(struct editor *ed) {
+static struct editor* close_editor(struct editor *ed) {
struct env *env = ed->env;
if (ed->dirty) {
display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename);
if (!ask()) {
ed->refresh = 1;
- return;
+ return ed;
}
}
@@ -1808,6 +1811,7 @@ static void close_editor(struct editor *ed) {
new_file(ed, "");
}
ed->refresh = 1;
+ return ed;
}
static void pipe_command(struct editor *ed) {
@@ -2131,15 +2135,7 @@ static void edit(struct editor *ed) {
case ctrl('s'): save_editor(ed); break;
case ctrl('p'): pipe_command(ed); break;
#endif
-#if defined(__rtems__)
- /*
- * Coverity spotted this as using ed after free() so changing
- * the order of the statements.
- */
- case ctrl('w'): ed = ed->env->current; close_editor(ed); break;
-#else
- case ctrl('w'): close_editor(ed); ed = ed->env->current; break;
-#endif
+ case ctrl('w'): ed = close_editor(ed); break;
}
}
}
diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c
index a2f09fb99f..8888ab2c57 100644
--- a/cpukit/libmisc/untar/untar.c
+++ b/cpukit/libmisc/untar/untar.c
@@ -126,30 +126,25 @@ Make_Path(const rtems_printer *printer, char *path)
*p = '\0';
if (p[1] == '\0') {
- /* Speculatively unlink the last component so that it can be re-created */
- unlink(path);
return 0;
}
if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
- if (errno == EEXIST || errno == EISDIR) {
+ if (errno == EEXIST) {
+ /* If it exists already: Check whether it is a directory */
struct stat sb;
-
- if (stat(path, &sb) != 0) {
+ if (lstat(path, &sb) != 0) {
+ Print_Error(printer, "lstat", path);
+ return -1;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ rtems_printf(printer,
+ "untar: mkdir: %s: exists but is not a directory\n",
+ path);
return -1;
}
-
- if (!S_ISDIR(sb.st_mode)) {
- if (unlink(path) != 0) {
- Print_Error(printer, "unlink", path);
- return -1;
- }
-
- if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
- Print_Error(printer, "mkdir (unlink)", path);
- return -1;
- }
- }
+ } else {
+ Print_Error(printer, "mkdir", path);
+ return -1;
}
}
@@ -206,6 +201,12 @@ Untar_ProcessHeader(
if (Make_Path(ctx->printer, ctx->file_path) != 0) {
retval = UNTAR_FAIL;
+ } else {
+ /*
+ * Speculatively unlink. This should unlink everything but non-empty
+ * directories or write protected stuff.
+ */
+ unlink(ctx->file_path);
}
if (ctx->linkflag == SYMTYPE) {
@@ -225,8 +226,22 @@ Untar_ProcessHeader(
rtems_printf(ctx->printer, "untar: dir: %s\n", ctx->file_path);
r = mkdir(ctx->file_path, ctx->mode);
if (r != 0) {
- Print_Error(ctx->printer, "mkdir", ctx->file_path);
- retval = UNTAR_FAIL;
+ if (errno == EEXIST) {
+ /* If it exists already: Check whether it is a directory */
+ struct stat sb;
+ if (lstat(ctx->file_path, &sb) != 0) {
+ Print_Error(ctx->printer, "lstat", ctx->file_path);
+ retval = UNTAR_FAIL;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ rtems_printf(ctx->printer,
+ "untar: mkdir: %s: exists but is not a directory\n",
+ ctx->file_path);
+ retval = UNTAR_FAIL;
+ }
+ } else {
+ Print_Error(ctx->printer, "mkdir", ctx->file_path);
+ retval = UNTAR_FAIL;
+ }
}
}
@@ -426,7 +441,9 @@ Untar_FromFile_Print(
*/
if ((out_fd = creat(ctx.file_path, ctx.mode)) == -1) {
- (void) lseek(fd, SEEK_CUR, 512UL * ctx.nblocks);
+ /* Couldn't create that file. Abort. */
+ retval = UNTAR_FAIL;
+ break;
} else {
for (i = 0; i < ctx.nblocks; i++) {
n = read(fd, bufr, 512);
diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c
index 8d1a4b84e4..792d222e2b 100644
--- a/cpukit/posix/src/nanosleep.c
+++ b/cpukit/posix/src/nanosleep.c
@@ -64,7 +64,7 @@ int clock_nanosleep(
)
{
Thread_queue_Context queue_context;
- struct timespec uptime;
+ struct timespec now;
const struct timespec *end;
Thread_Control *executing;
int eno;
@@ -81,21 +81,22 @@ int clock_nanosleep(
if ( ( flags & TIMER_ABSTIME ) != 0 ) {
end = rqtp;
-
+ } else {
if ( clock_id == CLOCK_REALTIME ) {
- _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
- &queue_context,
- end
- );
+ _Timecounter_Nanotime( &now );
} else {
- _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec(
- &queue_context,
- end
- );
+ _Timecounter_Nanouptime( &now );
}
+
+ end = _Watchdog_Future_timespec( &now, rqtp );
+ }
+
+ if ( clock_id == CLOCK_REALTIME ) {
+ _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
+ &queue_context,
+ end
+ );
} else {
- _Timecounter_Nanouptime( &uptime );
- end = _Watchdog_Future_timespec( &uptime, rqtp );
_Thread_queue_Context_set_enqueue_timeout_monotonic_timespec(
&queue_context,
end
@@ -120,7 +121,11 @@ int clock_nanosleep(
if ( eno == EINTR ) {
struct timespec actual_end;
- _Timecounter_Nanouptime( &actual_end );
+ if ( clock_id == CLOCK_REALTIME ) {
+ _Timecounter_Nanotime( &actual_end );
+ } else {
+ _Timecounter_Nanouptime( &actual_end );
+ }
if ( _Timespec_Less_than( &actual_end, end ) ) {
_Timespec_Subtract( &actual_end, end, rmtp );
diff --git a/cpukit/rtems/src/ratemoncreate.c b/cpukit/rtems/src/ratemoncreate.c
index 3eff5f0716..2e6b434d9e 100644
--- a/cpukit/rtems/src/ratemoncreate.c
+++ b/cpukit/rtems/src/ratemoncreate.c
@@ -53,6 +53,7 @@ rtems_status_code rtems_rate_monotonic_create(
the_period->owner = _Thread_Get_executing();
the_period->state = RATE_MONOTONIC_INACTIVE;
+ the_period->postponed_jobs = 0;
_Watchdog_Preinitialize( &the_period->Timer, _Per_CPU_Get_by_index( 0 ) );
_Watchdog_Initialize( &the_period->Timer, _Rate_monotonic_Timeout );
diff --git a/cpukit/score/src/heapallocate.c b/cpukit/score/src/heapallocate.c
index 4b8b3f0de6..1c71e4a037 100644
--- a/cpukit/score/src/heapallocate.c
+++ b/cpukit/score/src/heapallocate.c
@@ -73,6 +73,15 @@
return search_again;
}
+
+ void _Heap_Protection_free_all_delayed_blocks( Heap_Control *heap )
+ {
+ bool search_again;
+
+ do {
+ search_again = _Heap_Protection_free_delayed_blocks( heap, 0 );
+ } while ( search_again );
+ }
#endif
#ifdef RTEMS_HEAP_DEBUG
diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c
index 1b65cf41ee..56ec4751ce 100644
--- a/cpukit/score/src/kern_tc.c
+++ b/cpukit/score/src/kern_tc.c
@@ -1,4 +1,6 @@
/*-
+ * SPDX-License-Identifier: Beerware
+ *
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
@@ -7,7 +9,6 @@
* ----------------------------------------------------------------------------
*
* Copyright (c) 2011, 2015, 2016 The FreeBSD Foundation
- * All rights reserved.
*
* Portions of this software were developed by Julien Ridoux at the University
* of Melbourne under sponsorship from the FreeBSD Foundation.
@@ -44,9 +45,8 @@
#include <rtems/score/watchdogimpl.h>
#endif /* __rtems__ */
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/kern/kern_tc.c 324528 2017-10-11 11:03:11Z kib $");
+__FBSDID("$FreeBSD$");
-#include "opt_compat.h"
#include "opt_ntp.h"
#include "opt_ffclock.h"
@@ -79,16 +79,7 @@ ISR_LOCK_DEFINE(, _Timecounter_Lock, "Timecounter")
_ISR_lock_Release_and_ISR_enable(&_Timecounter_Lock, lock_context)
#define hz rtems_clock_get_ticks_per_second()
#define printf(...)
-#define bcopy(x, y, z) memcpy(y, x, z);
#define log(...)
-static inline int
-builtin_fls(int x)
-{
- return x ? sizeof(x) * 8 - __builtin_clz(x) : 0;
-}
-#define fls(x) builtin_fls(x)
-/* FIXME: https://devel.rtems.org/ticket/2348 */
-#define ntp_update_second(a, b) do { (void) a; (void) b; } while (0)
static inline void
atomic_thread_fence_acq(void)
@@ -117,6 +108,24 @@ atomic_store_rel_int(Atomic_Uint *i, u_int val)
_Atomic_Store_uint(i, val, ATOMIC_ORDER_RELEASE);
}
+
+static inline void *
+atomic_load_ptr(void *ptr)
+{
+
+ return ((void *)_Atomic_Load_uintptr(ptr, ATOMIC_ORDER_RELAXED));
+}
+
+static Timecounter_NTP_update_second _Timecounter_NTP_update_second;
+
+void
+_Timecounter_Set_NTP_update_second(Timecounter_NTP_update_second handler)
+{
+
+ _Timecounter_NTP_update_second = handler;
+}
+
+#define ntp_update_second(a, b) (*ntp_update_second_handler)(a, b)
#endif /* __rtems__ */
/*
@@ -158,6 +167,7 @@ struct timehands {
struct timecounter *th_counter;
int64_t th_adjustment;
uint64_t th_scale;
+ uint32_t th_large_delta;
uint32_t th_offset_count;
struct bintime th_offset;
struct bintime th_bintime;
@@ -173,6 +183,40 @@ struct timehands {
struct timehands *th_next;
};
+#ifndef __rtems__
+static struct timehands ths[16] = {
+ [0] = {
+ .th_counter = &dummy_timecounter,
+ .th_scale = (uint64_t)-1 / 1000000,
+ .th_large_delta = 1000000,
+ .th_offset = { .sec = 1 },
+ .th_generation = 1,
+ },
+};
+
+static struct timehands *volatile timehands = &ths[0];
+struct timecounter *timecounter = &dummy_timecounter;
+static struct timecounter *timecounters = &dummy_timecounter;
+
+/* Mutex to protect the timecounter list. */
+static struct mtx tc_lock;
+MTX_SYSINIT(tc_lock, &tc_lock, "tc", MTX_DEF);
+
+int tc_min_ticktock_freq = 1;
+#else /* __rtems__ */
+/*
+ * In FreeBSD, the timehands count is a tuning option from two to 16. The
+ * tuning option was added since it is inexpensive and some FreeBSD users asked
+ * for it to play around. The default value is two. One system which did not
+ * work with two timehands was a system with one processor and a specific PPS
+ * device.
+ *
+ * For RTEMS, in uniprocessor configurations, just use one timehand since the
+ * update is done with interrupt disabled.
+ *
+ * In SMP configurations, use a fixed set of two timehands until someone
+ * reports an issue.
+ */
#if defined(RTEMS_SMP)
static struct timehands th0;
static struct timehands th1 = {
@@ -183,7 +227,8 @@ static struct timehands th0 = {
.th_counter = &dummy_timecounter,
.th_scale = (uint64_t)-1 / 1000000,
.th_offset = { .sec = 1 },
- .th_generation = 1,
+ .th_large_delta = 1000000,
+ .th_generation = UINT_MAX,
#ifdef __rtems__
.th_bintime = { .sec = TOD_SECONDS_1970_THROUGH_1988 },
.th_microtime = { TOD_SECONDS_1970_THROUGH_1988, 0 },
@@ -199,10 +244,6 @@ static struct timehands th0 = {
static struct timehands *volatile timehands = &th0;
struct timecounter *timecounter = &dummy_timecounter;
-#ifndef __rtems__
-static struct timecounter *timecounters = &dummy_timecounter;
-
-int tc_min_ticktock_freq = 1;
#endif /* __rtems__ */
#ifndef __rtems__
@@ -214,17 +255,33 @@ volatile int32_t time_uptime = 1;
#endif /* __rtems__ */
#ifndef __rtems__
+/*
+ * The system time is always computed by summing the estimated boot time and the
+ * system uptime. The timehands track boot time, but it changes when the system
+ * time is set by the user, stepped by ntpd or adjusted when resuming. It
+ * is set to new_time - uptime.
+ */
static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS);
-SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD,
- NULL, 0, sysctl_kern_boottime, "S,timeval", "System boottime");
+SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime,
+ CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
+ sysctl_kern_boottime, "S,timeval",
+ "Estimated system boottime");
-SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
-static SYSCTL_NODE(_kern_timecounter, OID_AUTO, tc, CTLFLAG_RW, 0, "");
+SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "");
+static SYSCTL_NODE(_kern_timecounter, OID_AUTO, tc,
+ CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "");
static int timestepwarnings;
-SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RW,
+SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RWTUN,
&timestepwarnings, 0, "Log time steps");
+static int timehands_count = 2;
+SYSCTL_INT(_kern_timecounter, OID_AUTO, timehands_count,
+ CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
+ &timehands_count, 0, "Count of timehands in rotation");
+
struct bintime bt_timethreshold;
struct bintime bt_tickthreshold;
sbintime_t sbt_timethreshold;
@@ -242,6 +299,7 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation,
volatile int rtc_generation = 1;
static int tc_chosen; /* Non-zero if a specific tc was chosen via sysctl. */
+static char tc_from_tunable[16];
#endif /* __rtems__ */
static void tc_windup(struct bintime *new_boottimebin);
@@ -253,6 +311,7 @@ static void _Timecounter_Windup(struct bintime *new_boottimebin,
#endif /* __rtems__ */
void dtrace_getnanotime(struct timespec *tsp);
+void dtrace_getnanouptime(struct timespec *tsp);
#ifndef __rtems__
static int
@@ -262,7 +321,8 @@ sysctl_kern_boottime(SYSCTL_HANDLER_ARGS)
getboottime(&boottime);
-#ifndef __mips__
+/* i386 is the only arch which uses a 32bits time_t */
+#ifdef __amd64__
#ifdef SCTL_MASK32
int tv[2];
@@ -317,20 +377,85 @@ tc_delta(struct timehands *th)
* the comment in <sys/time.h> for a description of these 12 functions.
*/
-#ifdef FFCLOCK
-void
-fbclock_binuptime(struct bintime *bt)
+static __inline void
+bintime_off(struct bintime *bt, u_int off)
{
struct timehands *th;
- unsigned int gen;
+ struct bintime *btp;
+ uint64_t scale, x;
+#ifndef __rtems__
+ u_int delta, gen, large_delta;
+#else /* __rtems__ */
+ uint32_t delta, large_delta;
+ u_int gen;
+#endif /* __rtems__ */
do {
th = timehands;
gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_offset;
- bintime_addx(bt, th->th_scale * tc_delta(th));
+ btp = (struct bintime *)((vm_offset_t)th + off);
+ *bt = *btp;
+ scale = th->th_scale;
+ delta = tc_delta(th);
+ large_delta = th->th_large_delta;
atomic_thread_fence_acq();
+#if defined(RTEMS_SMP)
} while (gen == 0 || gen != th->th_generation);
+#else
+ } while (gen != th->th_generation);
+#endif
+
+ if (__predict_false(delta >= large_delta)) {
+ /* Avoid overflow for scale * delta. */
+ x = (scale >> 32) * delta;
+ bt->sec += x >> 32;
+ bintime_addx(bt, x << 32);
+ bintime_addx(bt, (scale & 0xffffffff) * delta);
+ } else {
+ bintime_addx(bt, scale * delta);
+ }
+}
+#define GETTHBINTIME(dst, member) \
+do { \
+ _Static_assert(_Generic(((struct timehands *)NULL)->member, \
+ struct bintime: 1, default: 0) == 1, \
+ "struct timehands member is not of struct bintime type"); \
+ bintime_off(dst, __offsetof(struct timehands, member)); \
+} while (0)
+
+static __inline void
+getthmember(void *out, size_t out_size, u_int off)
+{
+ struct timehands *th;
+ u_int gen;
+
+ do {
+ th = timehands;
+ gen = atomic_load_acq_int(&th->th_generation);
+ memcpy(out, (char *)th + off, out_size);
+ atomic_thread_fence_acq();
+#if defined(RTEMS_SMP)
+ } while (gen == 0 || gen != th->th_generation);
+#else
+ } while (gen != th->th_generation);
+#endif
+}
+#define GETTHMEMBER(dst, member) \
+do { \
+ _Static_assert(_Generic(*dst, \
+ __typeof(((struct timehands *)NULL)->member): 1, \
+ default: 0) == 1, \
+ "*dst and struct timehands member have different types"); \
+ getthmember(dst, sizeof(*dst), __offsetof(struct timehands, \
+ member)); \
+} while (0)
+
+#ifdef FFCLOCK
+void
+fbclock_binuptime(struct bintime *bt)
+{
+
+ GETTHBINTIME(bt, th_offset);
}
void
@@ -354,16 +479,8 @@ fbclock_microuptime(struct timeval *tvp)
void
fbclock_bintime(struct bintime *bt)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_bintime;
- bintime_addx(bt, th->th_scale * tc_delta(th));
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHBINTIME(bt, th_bintime);
}
void
@@ -387,116 +504,88 @@ fbclock_microtime(struct timeval *tvp)
void
fbclock_getbinuptime(struct bintime *bt)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_offset;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(bt, th_offset);
}
void
fbclock_getnanouptime(struct timespec *tsp)
{
- struct timehands *th;
- unsigned int gen;
+ struct bintime bt;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- bintime2timespec(&th->th_offset, tsp);
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timespec(&bt, tsp);
}
void
fbclock_getmicrouptime(struct timeval *tvp)
{
- struct timehands *th;
- unsigned int gen;
+ struct bintime bt;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- bintime2timeval(&th->th_offset, tvp);
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timeval(&bt, tvp);
}
void
fbclock_getbintime(struct bintime *bt)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_bintime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(bt, th_bintime);
}
void
fbclock_getnanotime(struct timespec *tsp)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tsp = th->th_nanotime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tsp, th_nanotime);
}
void
fbclock_getmicrotime(struct timeval *tvp)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tvp = th->th_microtime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tvp, th_microtime);
}
#else /* !FFCLOCK */
+
void
binuptime(struct bintime *bt)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_offset;
- bintime_addx(bt, th->th_scale * tc_delta(th));
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHBINTIME(bt, th_offset);
}
#ifdef __rtems__
sbintime_t
_Timecounter_Sbinuptime(void)
{
struct timehands *th;
- uint32_t gen;
sbintime_t sbt;
+ uint64_t scale;
+ uint32_t delta;
+ uint32_t large_delta;
+ u_int gen;
do {
th = timehands;
gen = atomic_load_acq_int(&th->th_generation);
sbt = bttosbt(th->th_offset);
- sbt += (th->th_scale * tc_delta(th)) >> 32;
+ scale = th->th_scale;
+ delta = tc_delta(th);
+ large_delta = th->th_large_delta;
atomic_thread_fence_acq();
+#if defined(RTEMS_SMP)
} while (gen == 0 || gen != th->th_generation);
+#else
+ } while (gen != th->th_generation);
+#endif
+
+ if (__predict_false(delta >= large_delta)) {
+ /* Avoid overflow for scale * delta. */
+ sbt += (scale >> 32) * delta;
+ sbt += ((scale & 0xffffffff) * delta) >> 32;
+ } else {
+ sbt += (scale * delta) >> 32;
+ }
return (sbt);
}
@@ -523,16 +612,8 @@ microuptime(struct timeval *tvp)
void
bintime(struct bintime *bt)
{
- struct timehands *th;
- u_int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_bintime;
- bintime_addx(bt, th->th_scale * tc_delta(th));
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHBINTIME(bt, th_bintime);
}
void
@@ -556,85 +637,47 @@ microtime(struct timeval *tvp)
void
getbinuptime(struct bintime *bt)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_offset;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(bt, th_offset);
}
void
getnanouptime(struct timespec *tsp)
{
- struct timehands *th;
- uint32_t gen;
+ struct bintime bt;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- bintime2timespec(&th->th_offset, tsp);
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timespec(&bt, tsp);
}
void
getmicrouptime(struct timeval *tvp)
{
- struct timehands *th;
- uint32_t gen;
+ struct bintime bt;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- bintime2timeval(&th->th_offset, tvp);
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timeval(&bt, tvp);
}
void
getbintime(struct bintime *bt)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_bintime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(bt, th_bintime);
}
void
getnanotime(struct timespec *tsp)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tsp = th->th_nanotime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tsp, th_nanotime);
}
void
getmicrotime(struct timeval *tvp)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tvp = th->th_microtime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tvp, th_microtime);
}
#endif /* FFCLOCK */
@@ -650,15 +693,8 @@ getboottime(struct timeval *boottime)
void
getboottimebin(struct bintime *boottimebin)
{
- struct timehands *th;
- u_int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *boottimebin = th->th_boottime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(boottimebin, th_boottime);
}
#ifdef FFCLOCK
@@ -1175,15 +1211,22 @@ getmicrotime(struct timeval *tvp)
void
dtrace_getnanotime(struct timespec *tsp)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tsp = th->th_nanotime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tsp, th_nanotime);
+}
+
+/*
+ * This is a clone of getnanouptime used for time since boot.
+ * The dtrace_ prefix prevents fbt from creating probes for
+ * it so an uptime that can be safely used in all fbt probes.
+ */
+void
+dtrace_getnanouptime(struct timespec *tsp)
+{
+ struct bintime bt;
+
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timespec(&bt, tsp);
}
#endif /* __rtems__ */
@@ -1364,26 +1407,32 @@ tc_init(struct timecounter *tc)
tc->tc_quality);
}
- tc->tc_next = timecounters;
- timecounters = tc;
/*
* Set up sysctl tree for this counter.
*/
tc_root = SYSCTL_ADD_NODE_WITH_LABEL(NULL,
SYSCTL_STATIC_CHILDREN(_kern_timecounter_tc), OID_AUTO, tc->tc_name,
- CTLFLAG_RW, 0, "timecounter description", "timecounter");
+ CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "timecounter description", "timecounter");
SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
"mask", CTLFLAG_RD, &(tc->tc_counter_mask), 0,
"mask for implemented bits");
SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
- "counter", CTLTYPE_UINT | CTLFLAG_RD, tc, sizeof(*tc),
- sysctl_kern_timecounter_get, "IU", "current timecounter value");
+ "counter", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, tc,
+ sizeof(*tc), sysctl_kern_timecounter_get, "IU",
+ "current timecounter value");
SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
- "frequency", CTLTYPE_U64 | CTLFLAG_RD, tc, sizeof(*tc),
- sysctl_kern_timecounter_freq, "QU", "timecounter frequency");
+ "frequency", CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE, tc,
+ sizeof(*tc), sysctl_kern_timecounter_freq, "QU",
+ "timecounter frequency");
SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
"quality", CTLFLAG_RD, &(tc->tc_quality), 0,
"goodness of time counter");
+
+ mtx_lock(&tc_lock);
+ tc->tc_next = timecounters;
+ timecounters = tc;
+
/*
* Do not automatically switch if the current tc was specifically
* chosen. Never automatically use a timecounter with negative quality.
@@ -1391,21 +1440,31 @@ tc_init(struct timecounter *tc)
* worse since this timecounter may not be monotonic.
*/
if (tc_chosen)
- return;
+ goto unlock;
if (tc->tc_quality < 0)
- return;
-#endif /* __rtems__ */
+ goto unlock;
+ if (tc_from_tunable[0] != '\0' &&
+ strcmp(tc->tc_name, tc_from_tunable) == 0) {
+ tc_chosen = 1;
+ tc_from_tunable[0] = '\0';
+ } else {
+ if (tc->tc_quality < timecounter->tc_quality)
+ goto unlock;
+ if (tc->tc_quality == timecounter->tc_quality &&
+ tc->tc_frequency < timecounter->tc_frequency)
+ goto unlock;
+ }
+ (void)tc->tc_get_timecount(tc);
+ timecounter = tc;
+unlock:
+ mtx_unlock(&tc_lock);
+#else /* __rtems__ */
if (tc->tc_quality < timecounter->tc_quality)
return;
if (tc->tc_quality == timecounter->tc_quality &&
tc->tc_frequency < timecounter->tc_frequency)
return;
-#ifndef __rtems__
- (void)tc->tc_get_timecount(tc);
- (void)tc->tc_get_timecount(tc);
-#endif /* __rtems__ */
timecounter = tc;
-#ifdef __rtems__
tc_windup(NULL);
#endif /* __rtems__ */
}
@@ -1493,6 +1552,40 @@ _Timecounter_Set_clock(const struct bintime *_bt,
}
/*
+ * Recalculate the scaling factor. We want the number of 1/2^64
+ * fractions of a second per period of the hardware counter, taking
+ * into account the th_adjustment factor which the NTP PLL/adjtime(2)
+ * processing provides us with.
+ *
+ * The th_adjustment is nanoseconds per second with 32 bit binary
+ * fraction and we want 64 bit binary fraction of second:
+ *
+ * x = a * 2^32 / 10^9 = a * 4.294967296
+ *
+ * The range of th_adjustment is +/- 5000PPM so inside a 64bit int
+ * we can only multiply by about 850 without overflowing, that
+ * leaves no suitably precise fractions for multiply before divide.
+ *
+ * Divide before multiply with a fraction of 2199/512 results in a
+ * systematic undercompensation of 10PPM of th_adjustment. On a
+ * 5000PPM adjustment this is a 0.05PPM error. This is acceptable.
+ *
+ * We happily sacrifice the lowest of the 64 bits of our result
+ * to the goddess of code clarity.
+ */
+static void
+recalculate_scaling_factor_and_large_delta(struct timehands *th)
+{
+ uint64_t scale;
+
+ scale = (uint64_t)1 << 63;
+ scale += (th->th_adjustment / 1024) * 2199;
+ scale /= th->th_counter->tc_frequency;
+ th->th_scale = scale * 2;
+ th->th_large_delta = MIN(((uint64_t)1 << 63) / scale, UINT_MAX);
+}
+
+/*
* Initialize the next struct timehands in the ring and make
* it the active timehands. Along the way we might switch to a different
* timecounter and/or do seconds processing in NTP. Slightly magic.
@@ -1513,11 +1606,17 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
#endif /* __rtems__ */
{
struct bintime bt;
+ struct timecounter *tc;
struct timehands *th, *tho;
- uint64_t scale;
- uint32_t delta, ncount, ogen;
+ uint32_t delta, ncount;
+#if defined(RTEMS_SMP)
+ u_int ogen;
+#endif
int i;
time_t t;
+#ifdef __rtems__
+ Timecounter_NTP_update_second ntp_update_second_handler;
+#endif
/*
* Make the next timehands a copy of the current one, but do
@@ -1531,14 +1630,12 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
tho = timehands;
#if defined(RTEMS_SMP)
th = tho->th_next;
-#else
- th = tho;
-#endif
ogen = th->th_generation;
th->th_generation = 0;
atomic_thread_fence_rel();
-#if defined(RTEMS_SMP)
- bcopy(tho, th, offsetof(struct timehands, th_generation));
+ memcpy(th, tho, offsetof(struct timehands, th_generation));
+#else
+ th = tho;
#endif
if (new_boottimebin != NULL)
th->th_boottime = *new_boottimebin;
@@ -1548,9 +1645,10 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
* changing timecounters, a counter value from the new timecounter.
* Update the offset fields accordingly.
*/
+ tc = atomic_load_ptr(&timecounter);
delta = tc_delta(th);
- if (th->th_counter != timecounter)
- ncount = timecounter->tc_get_timecount(timecounter);
+ if (th->th_counter != tc)
+ ncount = tc->tc_get_timecount(tc);
else
ncount = 0;
#ifdef FFCLOCK
@@ -1584,7 +1682,7 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
#endif /* __rtems__ */
/*
- * Deal with NTP second processing. The for loop normally
+ * Deal with NTP second processing. The loop normally
* iterates at most once, but in extreme situations it might
* keep NTP sane if timeouts are not run for several seconds.
* At boot, the time step can be large when the TOD hardware
@@ -1594,69 +1692,57 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
*/
bt = th->th_offset;
bintime_add(&bt, &th->th_boottime);
+#ifdef __rtems__
+ ntp_update_second_handler = _Timecounter_NTP_update_second;
+ if (ntp_update_second_handler != NULL) {
+#endif /* __rtems__ */
i = bt.sec - tho->th_microtime.tv_sec;
- if (i > LARGE_STEP)
- i = 2;
- for (; i > 0; i--) {
- t = bt.sec;
- ntp_update_second(&th->th_adjustment, &bt.sec);
- if (bt.sec != t)
- th->th_boottime.sec += bt.sec - t;
+ if (i > 0) {
+ if (i > LARGE_STEP)
+ i = 2;
+
+ do {
+ t = bt.sec;
+ ntp_update_second(&th->th_adjustment, &bt.sec);
+ if (bt.sec != t)
+ th->th_boottime.sec += bt.sec - t;
+ --i;
+ } while (i > 0);
+
+ recalculate_scaling_factor_and_large_delta(th);
}
+#ifdef __rtems__
+ }
+#endif /* __rtems__ */
+
/* Update the UTC timestamps used by the get*() functions. */
th->th_bintime = bt;
bintime2timeval(&bt, &th->th_microtime);
bintime2timespec(&bt, &th->th_nanotime);
/* Now is a good time to change timecounters. */
- if (th->th_counter != timecounter) {
+ if (th->th_counter != tc) {
#ifndef __rtems__
#ifndef __arm__
- if ((timecounter->tc_flags & TC_FLAGS_C2STOP) != 0)
+ if ((tc->tc_flags & TC_FLAGS_C2STOP) != 0)
cpu_disable_c2_sleep++;
if ((th->th_counter->tc_flags & TC_FLAGS_C2STOP) != 0)
cpu_disable_c2_sleep--;
#endif
#endif /* __rtems__ */
- th->th_counter = timecounter;
+ th->th_counter = tc;
th->th_offset_count = ncount;
#ifndef __rtems__
- tc_min_ticktock_freq = max(1, timecounter->tc_frequency /
- (((uint64_t)timecounter->tc_counter_mask + 1) / 3));
+ tc_min_ticktock_freq = max(1, tc->tc_frequency /
+ (((uint64_t)tc->tc_counter_mask + 1) / 3));
#endif /* __rtems__ */
+ recalculate_scaling_factor_and_large_delta(th);
#ifdef FFCLOCK
ffclock_change_tc(th);
#endif
}
- /*-
- * Recalculate the scaling factor. We want the number of 1/2^64
- * fractions of a second per period of the hardware counter, taking
- * into account the th_adjustment factor which the NTP PLL/adjtime(2)
- * processing provides us with.
- *
- * The th_adjustment is nanoseconds per second with 32 bit binary
- * fraction and we want 64 bit binary fraction of second:
- *
- * x = a * 2^32 / 10^9 = a * 4.294967296
- *
- * The range of th_adjustment is +/- 5000PPM so inside a 64bit int
- * we can only multiply by about 850 without overflowing, that
- * leaves no suitably precise fractions for multiply before divide.
- *
- * Divide before multiply with a fraction of 2199/512 results in a
- * systematic undercompensation of 10PPM of th_adjustment. On a
- * 5000PPM adjustment this is a 0.05PPM error. This is acceptable.
- *
- * We happily sacrifice the lowest of the 64 bits of our result
- * to the goddess of code clarity.
- *
- */
- scale = (uint64_t)1 << 63;
- scale += (th->th_adjustment / 1024) * 2199;
- scale /= th->th_counter->tc_frequency;
- th->th_scale = scale * 2;
-
+#if defined(RTEMS_SMP)
/*
* Now that the struct timehands is again consistent, set the new
* generation number, making sure to not make it zero.
@@ -1664,6 +1750,9 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
if (++ogen == 0)
ogen = 1;
atomic_store_rel_int(&th->th_generation, ogen);
+#else
+ atomic_store_rel_int(&th->th_generation, th->th_generation + 1);
+#endif
/* Go live with the new struct timehands. */
#ifdef FFCLOCK
@@ -1701,23 +1790,28 @@ sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
struct timecounter *newtc, *tc;
int error;
+ mtx_lock(&tc_lock);
tc = timecounter;
strlcpy(newname, tc->tc_name, sizeof(newname));
+ mtx_unlock(&tc_lock);
error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
if (error != 0 || req->newptr == NULL)
return (error);
+
+ mtx_lock(&tc_lock);
/* Record that the tc in use now was specifically chosen. */
tc_chosen = 1;
- if (strcmp(newname, tc->tc_name) == 0)
+ if (strcmp(newname, tc->tc_name) == 0) {
+ mtx_unlock(&tc_lock);
return (0);
+ }
for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
if (strcmp(newname, newtc->tc_name) != 0)
continue;
/* Warm up new timecounter. */
(void)newtc->tc_get_timecount(newtc);
- (void)newtc->tc_get_timecount(newtc);
timecounter = newtc;
@@ -1729,16 +1823,16 @@ sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
* use any locking and that it can be called in hard interrupt
* context via 'tc_windup()'.
*/
- return (0);
+ break;
}
- return (EINVAL);
+ mtx_unlock(&tc_lock);
+ return (newtc != NULL ? 0 : EINVAL);
}
-
-SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
- 0, 0, sysctl_kern_timecounter_hardware, "A",
+SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware,
+ CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_MPSAFE, 0, 0,
+ sysctl_kern_timecounter_hardware, "A",
"Timecounter hardware selected");
-
/* Report the available timecounter hardware. */
static int
sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS)
@@ -1747,19 +1841,26 @@ sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS)
struct timecounter *tc;
int error;
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error != 0)
+ return (error);
sbuf_new_for_sysctl(&sb, NULL, 0, req);
+ mtx_lock(&tc_lock);
for (tc = timecounters; tc != NULL; tc = tc->tc_next) {
if (tc != timecounters)
sbuf_putc(&sb, ' ');
sbuf_printf(&sb, "%s(%d)", tc->tc_name, tc->tc_quality);
}
+ mtx_unlock(&tc_lock);
error = sbuf_finish(&sb);
sbuf_delete(&sb);
return (error);
}
-SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD,
- 0, 0, sysctl_kern_timecounter_choice, "A", "Timecounter hardware detected");
+SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice,
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0,
+ sysctl_kern_timecounter_choice, "A",
+ "Timecounter hardware detected");
#endif /* __rtems__ */
#ifndef __rtems__
@@ -1803,10 +1904,10 @@ pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps)
tv.tv_usec = fapi->timeout.tv_nsec / 1000;
timo = tvtohz(&tv);
}
- aseq = pps->ppsinfo.assert_sequence;
- cseq = pps->ppsinfo.clear_sequence;
- while (aseq == pps->ppsinfo.assert_sequence &&
- cseq == pps->ppsinfo.clear_sequence) {
+ aseq = atomic_load_int(&pps->ppsinfo.assert_sequence);
+ cseq = atomic_load_int(&pps->ppsinfo.clear_sequence);
+ while (aseq == atomic_load_int(&pps->ppsinfo.assert_sequence) &&
+ cseq == atomic_load_int(&pps->ppsinfo.clear_sequence)) {
if (abi_aware(pps, 1) && pps->driver_mtx != NULL) {
if (pps->flags & PPSFLAG_MTX_SPIN) {
err = msleep_spin(pps, pps->driver_mtx,
@@ -2144,27 +2245,38 @@ _Timecounter_Tick_simple(uint32_t delta, uint32_t offset,
{
struct bintime bt;
struct timehands *th;
- uint32_t ogen;
+#if defined(RTEMS_SMP)
+ u_int ogen;
+#endif
th = timehands;
+#if defined(RTEMS_SMP)
ogen = th->th_generation;
+ th->th_generation = 0;
+ atomic_thread_fence_rel();
+#endif
+
th->th_offset_count = offset;
bintime_addx(&th->th_offset, th->th_scale * delta);
-
bt = th->th_offset;
bintime_add(&bt, &th->th_boottime);
+
/* Update the UTC timestamps used by the get*() functions. */
th->th_bintime = bt;
bintime2timeval(&bt, &th->th_microtime);
bintime2timespec(&bt, &th->th_nanotime);
+#if defined(RTEMS_SMP)
/*
* Now that the struct timehands is again consistent, set the new
* generation number, making sure to not make it zero.
*/
if (++ogen == 0)
ogen = 1;
- th->th_generation = ogen;
+ atomic_store_rel_int(&th->th_generation, ogen);
+#else
+ atomic_store_rel_int(&th->th_generation, th->th_generation + 1);
+#endif
/* Go live with the new struct timehands. */
time_second = th->th_microtime.tv_sec;
@@ -2218,6 +2330,28 @@ done:
return (0);
}
+/* Set up the requested number of timehands. */
+static void
+inittimehands(void *dummy)
+{
+ struct timehands *thp;
+ int i;
+
+ TUNABLE_INT_FETCH("kern.timecounter.timehands_count",
+ &timehands_count);
+ if (timehands_count < 1)
+ timehands_count = 1;
+ if (timehands_count > nitems(ths))
+ timehands_count = nitems(ths);
+ for (i = 1, thp = &ths[0]; i < timehands_count; thp = &ths[i++])
+ thp->th_next = &ths[i];
+ thp->th_next = &ths[0];
+
+ TUNABLE_STR_FETCH("kern.timecounter.hardware", tc_from_tunable,
+ sizeof(tc_from_tunable));
+}
+SYSINIT(timehands, SI_SUB_TUNABLES, SI_ORDER_ANY, inittimehands, NULL);
+
static void
inittimecounter(void *dummy)
{
@@ -2248,9 +2382,9 @@ inittimecounter(void *dummy)
#ifdef FFCLOCK
ffclock_init();
#endif
+
/* warm up new timecounter (again) and get rolling. */
(void)timecounter->tc_get_timecount(timecounter);
- (void)timecounter->tc_get_timecount(timecounter);
mtx_lock_spin(&tc_setclock_mtx);
tc_windup(NULL);
mtx_unlock_spin(&tc_setclock_mtx);
@@ -2263,8 +2397,8 @@ SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL);
static int cpu_tick_variable;
static uint64_t cpu_tick_frequency;
-static DPCPU_DEFINE(uint64_t, tc_cpu_ticks_base);
-static DPCPU_DEFINE(unsigned, tc_cpu_ticks_last);
+DPCPU_DEFINE_STATIC(uint64_t, tc_cpu_ticks_base);
+DPCPU_DEFINE_STATIC(unsigned, tc_cpu_ticks_last);
static uint64_t
tc_cpu_ticks(void)
@@ -2438,7 +2572,6 @@ tc_fill_vdso_timehands(struct vdso_timehands *vdso_th)
enabled = 0;
return (enabled);
}
-#endif /* __rtems__ */
#ifdef COMPAT_FREEBSD32
uint32_t
@@ -2465,3 +2598,34 @@ tc_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32)
return (enabled);
}
#endif
+
+#include "opt_ddb.h"
+#ifdef DDB
+#include <ddb/ddb.h>
+
+DB_SHOW_COMMAND(timecounter, db_show_timecounter)
+{
+ struct timehands *th;
+ struct timecounter *tc;
+ u_int val1, val2;
+
+ th = timehands;
+ tc = th->th_counter;
+ val1 = tc->tc_get_timecount(tc);
+ __compiler_membar();
+ val2 = tc->tc_get_timecount(tc);
+
+ db_printf("timecounter %p %s\n", tc, tc->tc_name);
+ db_printf(" mask %#x freq %ju qual %d flags %#x priv %p\n",
+ tc->tc_counter_mask, (uintmax_t)tc->tc_frequency, tc->tc_quality,
+ tc->tc_flags, tc->tc_priv);
+ db_printf(" val %#x %#x\n", val1, val2);
+ db_printf("timehands adj %#jx scale %#jx ldelta %d off_cnt %d gen %d\n",
+ (uintmax_t)th->th_adjustment, (uintmax_t)th->th_scale,
+ th->th_large_delta, th->th_offset_count, th->th_generation);
+ db_printf(" offset %jd %jd boottime %jd %jd\n",
+ (intmax_t)th->th_offset.sec, (uintmax_t)th->th_offset.frac,
+ (intmax_t)th->th_boottime.sec, (uintmax_t)th->th_boottime.frac);
+}
+#endif
+#endif /* __rtems__ */
diff --git a/cpukit/score/src/objectactivecount.c b/cpukit/score/src/objectactivecount.c
index c658fc21e3..12c15147c7 100644
--- a/cpukit/score/src/objectactivecount.c
+++ b/cpukit/score/src/objectactivecount.c
@@ -24,14 +24,22 @@ Objects_Maximum _Objects_Active_count(
const Objects_Information *information
)
{
- Objects_Maximum inactive;
- Objects_Maximum maximum;
+ Objects_Maximum active;
+ Objects_Maximum index;
+ Objects_Maximum maximum;
+ Objects_Control **local_table;
_Assert( _Objects_Allocator_is_owner() );
- inactive = (Objects_Maximum)
- _Chain_Node_count_unprotected( &information->Inactive );
+ active = 0;
maximum = _Objects_Get_maximum_index( information );
+ local_table = information->local_table;
- return maximum - inactive;
+ for ( index = 0; index < maximum; ++index ) {
+ if ( local_table[ index ] != NULL ) {
+ ++active;
+ }
+ }
+
+ return active;
}
diff --git a/cpukit/score/src/objectfree.c b/cpukit/score/src/objectfree.c
index 1f7aa37e3f..964adbc62a 100644
--- a/cpukit/score/src/objectfree.c
+++ b/cpukit/score/src/objectfree.c
@@ -30,14 +30,16 @@ void _Objects_Free_unlimited(
if ( _Objects_Is_auto_extend( information ) ) {
Objects_Maximum objects_per_block;
- Objects_Maximum block;
- Objects_Maximum inactive;
+ Objects_Maximum index;
objects_per_block = information->objects_per_block;
- block = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM;
+ index = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM;
- if ( block > objects_per_block ) {
- block /= objects_per_block;
+ if ( _Objects_Is_in_allocated_block( index, objects_per_block ) ) {
+ Objects_Maximum block;
+ Objects_Maximum inactive;
+
+ block = index / objects_per_block;
++information->inactive_per_block[ block ];
diff --git a/cpukit/score/src/stackallocatorforidle.c b/cpukit/score/src/stackallocatorforidle.c
new file mode 100644
index 0000000000..7c4fd10c7d
--- /dev/null
+++ b/cpukit/score/src/stackallocatorforidle.c
@@ -0,0 +1,59 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2021 OAR Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/stack.h>
+#include <rtems/score/thread.h>
+
+/**
+ * @brief Default stack allocator allocate for idle handler.
+ *
+ * The allocate for idle handler is optional even when the user thread stack
+ * allocator and deallocator are configured.
+ *
+ * The default allocator for IDLE thread stacks gets the memory from a
+ * statically allocated area provided via confdefs.h.
+ *
+ * @param cpu Index of the CPU for the IDLE thread using this stack
+ * @param stack_size The size of the stack area to allocate in bytes.
+ *
+ * @retval NULL Not enough memory (never returned).
+ * @retval other Pointer to begin of stack area.
+ */
+static void *_Stack_Allocator_allocate_for_idle_default(
+ uint32_t cpu,
+ size_t stack_size
+)
+{
+ return &_Thread_Idle_stacks[ cpu * stack_size ];
+}
+
+const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
+ _Stack_Allocator_allocate_for_idle_default;
diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c
index 1e18ad07cc..e888aa111f 100644
--- a/cpukit/score/src/threadcreateidle.c
+++ b/cpukit/score/src/threadcreateidle.c
@@ -53,9 +53,15 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
config.is_preemptible = true;
config.stack_size = _Thread_Idle_stack_size
+ CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE;
- config.stack_area = &_Thread_Idle_stacks[
- _Per_CPU_Get_index( cpu ) * config.stack_size
- ];
+
+ /*
+ * The IDLE thread stacks may be statically allocated or there may be a
+ * custom allocator provided just as with user threads.
+ */
+ config.stack_area = (*_Stack_Allocator_allocate_for_idle)(
+ _Per_CPU_Get_index( cpu ),
+ config.stack_size
+ );
/*
* The entire workspace is zeroed during its initialization. Thus, all
diff --git a/testsuites/libtests/malloctest/init.c b/testsuites/libtests/malloctest/init.c
index 1d91385683..1e5c14fe4b 100644
--- a/testsuites/libtests/malloctest/init.c
+++ b/testsuites/libtests/malloctest/init.c
@@ -122,9 +122,13 @@ static void test_heap_default_init(void)
static void test_free( void *addr )
{
+ uint32_t failed_allocs;
+
rtems_test_assert( _Heap_Free( &TestHeap, addr ) );
+ failed_allocs = TestHeap.stats.failed_allocs;
_Heap_Protection_free_all_delayed_blocks( &TestHeap );
+ rtems_test_assert( failed_allocs == TestHeap.stats.failed_allocs );
}
static void test_heap_cases_1(void)
diff --git a/testsuites/libtests/tar01/init.c b/testsuites/libtests/tar01/init.c
index 4cad67a6ae..2deff3a482 100644
--- a/testsuites/libtests/tar01/init.c
+++ b/testsuites/libtests/tar01/init.c
@@ -7,6 +7,33 @@
* http://www.rtems.org/license/LICENSE.
*/
+/*
+ * Note on the used tar file: Generate the file on a system that supports
+ * symlinks with the following commands (tested on Linux - you might have to
+ * adapt on other systems):
+ *
+ * export WORK=some_work_directory
+ * rm -r ${WORK}
+ * mkdir -p ${WORK}/home/abc/def
+ * mkdir -p ${WORK}/home/dir
+ * cd ${WORK}
+ * echo "#! joel" > home/abc/def/test_script
+ * echo "ls -las /dev" >> home/abc/def/test_script
+ * chmod 755 home/abc/def/test_script
+ * echo "This is a test of loading an RTEMS filesystem from an" > home/test_file
+ * echo "initial tar image." >> home/test_file
+ * echo "Hello world" >> home/dir/file
+ * ln -s home/test_file symlink
+ * tar cf tar01.tar --format=ustar \
+ * symlink \
+ * home/test_file \
+ * home/abc/def/test_script \
+ * home/dir
+ *
+ * Note that "home/dir" is in the archive as separate directory. "home/abc" is
+ * only in the archive as a parent of the file "test_script".
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -95,6 +122,84 @@ void test_untar_from_memory(void)
}
+static void assert_file_content(
+ const char *name,
+ const char *expected_content,
+ ssize_t expected_size
+)
+{
+ char buf[16];
+ int fd;
+ int rd;
+
+ fd = open(name, O_RDONLY);
+ rtems_test_assert( fd >= 0 );
+ do {
+ rd = read(fd, buf, sizeof(buf));
+ rtems_test_assert( rd >= 0 );
+ if (rd > 0) {
+ rtems_test_assert( expected_size - rd >= 0 );
+ rtems_test_assert( memcmp(buf, expected_content, rd) == 0 );
+ expected_content += rd;
+ expected_size -= rd;
+ }
+ } while(rd > 0);
+ rtems_test_assert( expected_size == 0 );
+ close(fd);
+}
+
+static void assert_content_like_expected(void)
+{
+ const char *directories[] = {
+ "home",
+ "home/abc",
+ "home/abc/def",
+ "home/dir",
+ };
+ const char *symlinks[] = {
+ "symlink",
+ };
+ const struct {
+ const char *name;
+ const char *content;
+ } files[] = {
+ {
+ .name = "home/abc/def/test_script",
+ .content = "#! joel\nls -las /dev\n",
+ }, {
+ .name = "home/test_file",
+ .content = "This is a test of loading an RTEMS filesystem from an\n"
+ "initial tar image.\n",
+ }, {
+ .name = "home/dir/file",
+ .content = "Hello world\n",
+ }
+ };
+ size_t i;
+ struct stat st;
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(directories); ++i) {
+ lstat(directories[i], &st);
+ rtems_test_assert( S_ISDIR(st.st_mode) );
+ }
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(symlinks); ++i) {
+ lstat(symlinks[i], &st);
+ rtems_test_assert( S_ISLNK(st.st_mode) );
+ }
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(files); ++i) {
+ lstat(files[i].name, &st);
+ rtems_test_assert( S_ISREG(st.st_mode) );
+
+ assert_file_content(
+ files[i].name,
+ files[i].content,
+ strlen(files[i].content)
+ );
+ }
+}
+
void test_untar_from_file(void)
{
int fd;
@@ -119,13 +224,105 @@ void test_untar_from_file(void)
rv = chdir( "/dest" );
rtems_test_assert( rv == 0 );
- /* Untar it */
+ /* Case 1: Untar it into empty directory */
rv = Untar_FromFile( "/test.tar" );
printf("Untaring from file - ");
if (rv != UNTAR_SUCCESSFUL) {
printf ("error: untar failed: %i\n", rv);
exit(1);
}
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 2: Most files exist */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file into existing structure with one missing file - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 3: An empty directory exists where a file should be */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+ rv = mkdir("/dest/home/test_file", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ rtems_test_assert( rv == 0 );
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; overwrite empty directory with file - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 4: A file exists where a parent directory should be created */
+ rv = unlink("/dest/home/abc/def/test_script");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/abc/def");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/abc");
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/abc", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; file exists where parent dir should be created - ");
+ if (rv != UNTAR_FAIL) {
+ printf ("error: untar didn't fail like expected: %i\n", rv);
+ exit(1);
+ }
+ printf ("expected fail\n");
+ /* cleanup so that the next one works */
+ rv = unlink("/dest/home/abc");
+ rtems_test_assert( rv == 0 );
+
+ /* Case 5: A non-empty directory exists where a file should be created */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+ rv = mkdir("/dest/home/test_file", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/test_file/file",
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; non-empty dir where file should be created - ");
+ if (rv != UNTAR_FAIL) {
+ printf ("error: untar didn't fail like expected: %i\n", rv);
+ exit(1);
+ }
+ printf ("expected fail\n");
+ /* cleanup so that the next one works */
+ rv = unlink("/dest/home/test_file/file");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+
+ /* Case 6: A file exists where a directory is explicitly in the archive */
+ rv = unlink("/dest/home/dir/file");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/dir");
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/dir", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; overwrite file with explicit directory - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
printf ("successful\n");
/******************/
diff --git a/testsuites/libtests/tar01/tar01.doc b/testsuites/libtests/tar01/tar01.doc
index 060f98a813..adffdca291 100644
--- a/testsuites/libtests/tar01/tar01.doc
+++ b/testsuites/libtests/tar01/tar01.doc
@@ -20,3 +20,4 @@ directives:
concepts:
+ exercise these routines
++ check whether existing files are overwritten or not overwritten like expected
diff --git a/testsuites/libtests/tar01/tar01.scn b/testsuites/libtests/tar01/tar01.scn
index 68fa951881..dd72f9517b 100644
--- a/testsuites/libtests/tar01/tar01.scn
+++ b/testsuites/libtests/tar01/tar01.scn
@@ -1,9 +1,24 @@
-*** TAR01 TEST ***
-Untaring from memory - successful
+*** BEGIN OF TEST TAR 1 ***
+*** TEST VERSION: 6.0.0.e1efb4eb8a9d6dd5f6f37dafc9feb0a9e6a888f1
+*** TEST STATE: EXPECTED_PASS
+*** TEST BUILD: RTEMS_POSIX_API
+*** TEST TOOLS: 10.3.1 20210409 (RTEMS 6, RSB ad54d1dd3cf8249d9d39deb1dd28b2f294df062d-modified, Newlib eb03ac1)
+Untaring from memory - untar: memory at 0x11ece8 (10240)
+untar: symlink: home/test_file -> symlink
+untar: file: home/test_file (s:73,m:0644)
+untar: file: home/abc/def/test_script (s:21,m:0755)
+untar: dir: home/dir
+untar: file: home/dir/file (s:12,m:0644)
+successful
========= /home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /home/abc/def/test_script: mode: 0755 want: 0755
========= /symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
@@ -11,35 +26,58 @@ initial tar image.
Copy tar image to test.tar
Untaring from file - successful
+Untar from file into existing structure with one missing file - successful
+Untar from file; overwrite empty directory with file - successful
+Untar from file; file exists where parent dir should be created - expected fail
+Untar from file; non-empty dir where file should be created - expected fail
+Untar from file; overwrite file with explicit directory - successful
========= /dest/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-Untaring chunks from memory - untar: dir: home
-untar: file: home/test_file (73)
+Untaring chunks from memory - untar: symlink: home/test_file -> symlink
+untar: file: home/test_file (s:73,m:0644)
+untar: file: home/abc/def/test_script (s:21,m:0755)
+untar: dir: home/dir
+untar: file: home/dir/file (s:12,m:0644)
successful
========= /dest2/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest2/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest2/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest2/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-Untaring chunks from tgz- untar: dir: home
-untar: file: home/test_file (73)
-successful
+Untaring chunks from tgz - successful
========= /dest3/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest3/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest3/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest3/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-*** END OF TAR01 TEST ***
+
+
+*** END OF TEST TAR 1 ***
diff --git a/testsuites/libtests/tar01/tar01.tar b/testsuites/libtests/tar01/tar01.tar
index 6c6952ef18..9874f426d1 100644
--- a/testsuites/libtests/tar01/tar01.tar
+++ b/testsuites/libtests/tar01/tar01.tar
Binary files differ
diff --git a/testsuites/psxtests/psxdevctl01/test.c b/testsuites/psxtests/psxdevctl01/test.c
index b45725cb58..2fe7df1834 100644
--- a/testsuites/psxtests/psxdevctl01/test.c
+++ b/testsuites/psxtests/psxdevctl01/test.c
@@ -53,37 +53,16 @@ int main(
int dev_data;
void *dev_data_ptr;
size_t nbyte;
- int dev_info;
TEST_BEGIN();
- puts( "posix_devctl() FIONBIO on stdin return dev_info -- EBADF" );
- fd = 0;
- dcmd = FIONBIO;
- dev_data_ptr = &dev_data;
- nbyte = sizeof(dev_data);
- status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, &dev_info );
- rtems_test_assert( status == -1 );
- rtems_test_assert( errno == EBADF );
- rtems_test_assert( dev_info == 0 );
-
- puts( "posix_devctl() FIONBIO on stdin NULL dev_info -- EBADF" );
- fd = 0;
- dcmd = FIONBIO;
- dev_data_ptr = NULL;
- nbyte = 0;
- status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
- rtems_test_assert( status == -1 );
- rtems_test_assert( errno == EBADF );
-
puts( "posix_devctl() SOCKCLOSE on invalid file descriptor -- EBADF" );
- fd = 21;
+ fd = -1;
dcmd = SOCKCLOSE;
dev_data_ptr = NULL;
nbyte = 0;
status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
- rtems_test_assert( status == -1 );
- rtems_test_assert( errno == EBADF );
+ rtems_test_assert( status == EBADF );
/*
* Create a file, open it, and close it via posix_devctl().
@@ -102,6 +81,50 @@ int main(
status = close( fd );
rtems_test_assert( status == -1 );
rtems_test_assert( errno == EBADF );
+
+ puts( "posix_devctl() FIONBIO with invalid nbyte -- EINVAL" );
+ fd = 0;
+ dcmd = FIONBIO;
+ dev_data_ptr = NULL;
+ nbyte = 0;
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == EINVAL );
+
+ puts( "posix_devctl() FIONBIO with invalid file descriptor -- EBADF" );
+ fd = -1;
+ dcmd = FIONBIO;
+ dev_data_ptr = NULL;
+ nbyte = sizeof(int);
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == EBADF );
+
+ puts( "posix_devctl() FIONBIO flag not zero -- 0" );
+ fd = 0;
+ dcmd = FIONBIO;
+ dev_data = 1;
+ dev_data_ptr = &dev_data;
+ nbyte = sizeof(int);
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == 0 );
+
+ puts( "posix_devctl() FIONBIO flag is zero -- 0" );
+ fd = 0;
+ dcmd = FIONBIO;
+ dev_data = 0;
+ dev_data_ptr = &dev_data;
+ nbyte = sizeof(int);
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == 0 );
+
+ puts( "posix_devctl() dcmd not valid value -- EBADF" );
+ fd = 0;
+ dcmd = 1;
+ dev_data = 0;
+ dev_data_ptr = &dev_data;
+ nbyte = sizeof(int);
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == EBADF );
+
TEST_END();
exit(0);
}
diff --git a/testsuites/psxtests/psximfs02/init.c b/testsuites/psxtests/psximfs02/init.c
index 15b9137121..04f806f565 100644
--- a/testsuites/psxtests/psximfs02/init.c
+++ b/testsuites/psxtests/psximfs02/init.c
@@ -23,6 +23,8 @@
#include <rtems/malloc.h>
#include <rtems/libcsupport.h>
+#define MEMFILE_BYTES_PER_BLOCK 16
+
const char rtems_test_name[] = "PSXIMFS 2";
/* forward declarations to avoid warnings */
@@ -43,12 +45,17 @@ rtems_task Init(
static const uintptr_t slink_2_name_size [] = {
sizeof( slink_2_name )
};
+ static const uintptr_t some_blocks [] = {
+ MEMFILE_BYTES_PER_BLOCK * 10
+ };
+ static const char some_data[MEMFILE_BYTES_PER_BLOCK * 11];
int status = 0;
void *opaque;
char linkname_n[32] = {0};
char linkname_p[32] = {0};
int i;
+ int fd;
struct stat stat_buf;
TEST_BEGIN();
@@ -102,6 +109,27 @@ rtems_task Init(
rtems_test_assert( status == -1 );
rtems_test_assert( errno == EACCES );
+ puts( "Allocate most of heap with a little bit left" );
+ opaque = rtems_heap_greedy_allocate( some_blocks, 1 );
+
+ puts( "Create an empty file.");
+ status = mknod( "/foo", S_IFREG | S_IRWXU, 0LL );
+ rtems_test_assert( status == 0 );
+
+ puts( "Then increase it's size to more than remaining space" );
+ fd = open( "/foo", O_WRONLY | O_TRUNC);
+ rtems_test_assert( fd >= 0 );
+ status = write(fd, some_data, sizeof(some_data));
+ rtems_test_assert( status == -1);
+ rtems_test_assert( errno == ENOSPC );
+
+ puts( "Clean up again" );
+ status = close(fd);
+ rtems_test_assert( status == 0);
+ status = remove( "/foo" );
+ rtems_test_assert( status == 0);
+ rtems_heap_greedy_free( opaque );
+
puts( "Allocate most of heap" );
opaque = rtems_heap_greedy_allocate( mount_table_entry_size, 1 );
@@ -202,7 +230,7 @@ rtems_task Init(
#define CONFIGURE_FILESYSTEM_IMFS
#define CONFIGURE_MAXIMUM_TASKS 1
-#define CONFIGURE_IMFS_MEMFILE_BYTES_PER_BLOCK 16
+#define CONFIGURE_IMFS_MEMFILE_BYTES_PER_BLOCK MEMFILE_BYTES_PER_BLOCK
#define CONFIGURE_IMFS_ENABLE_MKFIFO
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 4
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
index 62bb1aa685..1ea2501bd7 100644
--- a/testsuites/sptests/Makefile.am
+++ b/testsuites/sptests/Makefile.am
@@ -1783,6 +1783,24 @@ spstkalloc02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spstkalloc02) \
$(support_includes)
endif
+if TEST_spstkalloc03
+sp_tests += spstkalloc03
+sp_screens += spstkalloc03/spstkalloc03.scn
+sp_docs += spstkalloc03/spstkalloc03.doc
+spstkalloc03_SOURCES = spstkalloc03/init.c
+spstkalloc03_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spstkalloc03) \
+ $(support_includes)
+endif
+
+if TEST_spstkalloc04
+sp_tests += spstkalloc04
+sp_screens += spstkalloc04/spstkalloc04.scn
+sp_docs += spstkalloc04/spstkalloc04.doc
+spstkalloc04_SOURCES = spstkalloc04/init.c
+spstkalloc04_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spstkalloc04) \
+ $(support_includes)
+endif
+
if TEST_spsysinit01
sp_tests += spsysinit01
sp_screens += spsysinit01/spsysinit01.scn
diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
index 9476e3b0d7..24ff0383e6 100644
--- a/testsuites/sptests/configure.ac
+++ b/testsuites/sptests/configure.ac
@@ -228,6 +228,8 @@ RTEMS_TEST_CHECK([spsize])
RTEMS_TEST_CHECK([spstdthreads01])
RTEMS_TEST_CHECK([spstkalloc])
RTEMS_TEST_CHECK([spstkalloc02])
+RTEMS_TEST_CHECK([spstkalloc03])
+RTEMS_TEST_CHECK([spstkalloc04])
RTEMS_TEST_CHECK([spsysinit01])
RTEMS_TEST_CHECK([spsyslock01])
RTEMS_TEST_CHECK([sptask_err01])
diff --git a/testsuites/sptests/spstkalloc03/init.c b/testsuites/sptests/spstkalloc03/init.c
new file mode 100644
index 0000000000..348afe7328
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/init.c
@@ -0,0 +1,103 @@
+/*
+ * COPYRIGHT (c) 2021.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <tmacros.h>
+
+#include <rtems/score/percpu.h>
+
+const char rtems_test_name[] = "SPSTKALLOC 3";
+
+static int thread_stacks_count = 0xff;
+
+static rtems_task Init(
+ rtems_task_argument ignored
+)
+{
+ rtems_print_printer_fprintf_putc(&rtems_test_printer);
+ TEST_BEGIN();
+ rtems_test_assert(thread_stacks_count == 2);
+ TEST_END();
+ rtems_test_exit( 0 );
+}
+
+static uint8_t stack_memory[RTEMS_MINIMUM_STACK_SIZE * 4];
+
+static int stack_offset_next;
+
+static void *allocate_helper(size_t size)
+{
+ size_t next;
+ void *alloc;
+
+ next = stack_offset_next + size;
+ rtems_test_assert( next < sizeof(stack_memory) );
+
+ alloc = &stack_memory[stack_offset_next];
+ stack_offset_next = next;
+ return alloc;
+}
+
+static void thread_stacks_initialize(size_t stack_space_size)
+{
+ rtems_test_assert(thread_stacks_count == 0xff);
+ thread_stacks_count = 0;
+}
+
+static void *thread_stacks_allocate(size_t stack_size)
+{
+ rtems_test_assert(thread_stacks_count == 1);
+ thread_stacks_count++;
+ return allocate_helper(stack_size);
+}
+
+static void thread_stacks_free(void *addr)
+{
+ rtems_test_assert(false);
+}
+
+static void *thread_stacks_allocate_for_idle(
+ uint32_t cpu,
+ size_t stack_size
+)
+{
+ rtems_test_assert(thread_stacks_count == 0);
+ thread_stacks_count++;
+ return allocate_helper(stack_size);
+}
+
+/*
+ * Configure the thread stack allocators to not use the workspace. This should
+ * eliminate all uses of the Workspace for most BSPs.
+ */
+#define CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
+#define CONFIGURE_TASK_STACK_ALLOCATOR_INIT thread_stacks_initialize
+#define CONFIGURE_TASK_STACK_ALLOCATOR thread_stacks_allocate
+#define CONFIGURE_TASK_STACK_DEALLOCATOR thread_stacks_free
+#define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE thread_stacks_allocate_for_idle
+
+
+/* NOTICE: the clock driver is explicitly disabled */
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
diff --git a/testsuites/sptests/spstkalloc03/spstkalloc03.doc b/testsuites/sptests/spstkalloc03/spstkalloc03.doc
new file mode 100644
index 0000000000..797716b623
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/spstkalloc03.doc
@@ -0,0 +1,19 @@
+# COPYRIGHT (c) 2021.
+# On-Line Applications Research Corporation (OAR).
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.org/license/LICENSE.
+#
+
+This file describes the directives and concepts tested by this test set.
+
+test set name: spstkalloc03
+
+directives:
+
+concepts:
+
++ Ensure that the task stack allocator including IDLE thread
+ stack allocator works.
+
diff --git a/testsuites/sptests/spstkalloc03/spstkalloc03.scn b/testsuites/sptests/spstkalloc03/spstkalloc03.scn
new file mode 100644
index 0000000000..45c67ef1fb
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/spstkalloc03.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SPSTKALLOC 3 ***
+*** END OF TEST SPSTKALLOC 3 ***
diff --git a/testsuites/sptests/spstkalloc04/init.c b/testsuites/sptests/spstkalloc04/init.c
new file mode 100644
index 0000000000..16f4ec65ca
--- /dev/null
+++ b/testsuites/sptests/spstkalloc04/init.c
@@ -0,0 +1,82 @@
+/*
+ * COPYRIGHT (c) 2021.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <tmacros.h>
+
+#include <rtems/score/percpu.h>
+
+const char rtems_test_name[] = "SPSTKALLOC 4";
+
+static int thread_stacks_count = 0;
+
+static rtems_task Init(
+ rtems_task_argument ignored
+)
+{
+ rtems_print_printer_fprintf_putc(&rtems_test_printer);
+ TEST_BEGIN();
+ rtems_test_assert(thread_stacks_count == 1);
+ TEST_END();
+ rtems_test_exit( 0 );
+}
+
+static uint8_t stack_memory[RTEMS_MINIMUM_STACK_SIZE * 4];
+
+static int stack_offset_next;
+
+static void *allocate_helper(size_t size)
+{
+ size_t next;
+ void *alloc;
+
+ next = stack_offset_next + size;
+ rtems_test_assert( next < sizeof(stack_memory) );
+
+ alloc = &stack_memory[stack_offset_next];
+ stack_offset_next = next;
+ return alloc;
+}
+
+static void *thread_stacks_allocate_for_idle(
+ uint32_t cpu,
+ size_t stack_size
+)
+{
+ rtems_test_assert(thread_stacks_count == 0);
+ thread_stacks_count++;
+ return allocate_helper(stack_size);
+}
+
+/*
+ * Configure the IDLE thread stack allocators. This is a special
+ * case where there is an IDLE thread stack allocator but no custom
+ * allocator set for other threads.
+ */
+#define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE thread_stacks_allocate_for_idle
+
+
+/* NOTICE: the clock driver is explicitly disabled */
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
diff --git a/testsuites/sptests/spstkalloc04/spstkalloc04.doc b/testsuites/sptests/spstkalloc04/spstkalloc04.doc
new file mode 100644
index 0000000000..a1ed5b22cb
--- /dev/null
+++ b/testsuites/sptests/spstkalloc04/spstkalloc04.doc
@@ -0,0 +1,20 @@
+# COPYRIGHT (c) 2021.
+# On-Line Applications Research Corporation (OAR).
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.org/license/LICENSE.
+#
+
+This file describes the directives and concepts tested by this test set.
+
+test set name: spstkalloc04
+
+directives:
+
+concepts:
+
++ Ensure that the task stack allocator including IDLE thread
+ stack allocator works when a custom allocator is NOT provided
+ for other threads.
+
diff --git a/testsuites/sptests/spstkalloc04/spstkalloc04.scn b/testsuites/sptests/spstkalloc04/spstkalloc04.scn
new file mode 100644
index 0000000000..f0919ec2d4
--- /dev/null
+++ b/testsuites/sptests/spstkalloc04/spstkalloc04.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SPSTKALLOC 4 ***
+*** END OF TEST SPSTKALLOC 4 ***
diff --git a/testsuites/sptests/sptimecounter01/init.c b/testsuites/sptests/sptimecounter01/init.c
index 81b705473e..12d5a7820d 100644
--- a/testsuites/sptests/sptimecounter01/init.c
+++ b/testsuites/sptests/sptimecounter01/init.c
@@ -196,11 +196,11 @@ void boot_card(const char *cmdline)
assert(bt.sec == 1);
assert(bt.frac == 18446744073708);
- /* Ensure that the fraction overflows and the second remains constant */
+ /* Check that a large delta yields a correct time */
ctx->counter = (0xf0000000 | 1) + TEST_FREQ;
rtems_bsd_binuptime(&bt);
assert(ctx->counter == (0xf0000000 | 2) + TEST_FREQ);
- assert(bt.sec == 1);
+ assert(bt.sec == 2);
assert(bt.frac == 18446742522092);
test_install(ctx);