diff options
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, ×tepwarnings, 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 Binary files differindex 6c6952ef18..9874f426d1 100644 --- a/testsuites/libtests/tar01/tar01.tar +++ b/testsuites/libtests/tar01/tar01.tar 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); |