Various Qemu Cortex M3 ports now support picolibc (#1364)

* Various Qemu Cortex M3 ports now support picolibc

Allow various Qemu Cortex M3 ports to compile against
picolibc. Also support "-flto" to work correctly.
Tested with picolibc in current Debian 13.
Just use "PICOLIBC=1 make" to switch over from default newlib.

Signed-off-by: Florian La Roche <Florian.LaRoche@gmail.com>

* Add ffreestanding

Signed-off-by: Ubuntu <ubuntu@ip-172-31-15-241.ap-south-1.compute.internal>

* Fix formatting check

Signed-off-by: Ubuntu <ubuntu@ip-172-31-15-241.ap-south-1.compute.internal>

---------

Signed-off-by: Florian La Roche <Florian.LaRoche@gmail.com>
Signed-off-by: Ubuntu <ubuntu@ip-172-31-15-241.ap-south-1.compute.internal>
Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com>
Co-authored-by: Ubuntu <ubuntu@ip-172-31-15-241.ap-south-1.compute.internal>
This commit is contained in:
Florian La Roche 2025-08-13 16:45:54 +02:00 committed by GitHub
parent 51467d89e0
commit 1aa47857a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 96 additions and 34 deletions

View file

@ -51,31 +51,38 @@ SOURCE_FILES += ${FREERTOS_TCP}/source/portable/BufferManagement/BufferAllocatio
SOURCE_FILES += ${FREERTOS_TCP}/source/portable/NetworkInterface/MPS2_AN385/NetworkInterface.c SOURCE_FILES += ${FREERTOS_TCP}/source/portable/NetworkInterface/MPS2_AN385/NetworkInterface.c
SOURCE_FILES += ${FREERTOS_TCP}/source/portable/NetworkInterface/MPS2_AN385/ether_lan9118/smsc9220_eth_drv.c SOURCE_FILES += ${FREERTOS_TCP}/source/portable/NetworkInterface/MPS2_AN385/ether_lan9118/smsc9220_eth_drv.c
DEFINES := -DHEAP3 CPPFLAGS += -DHEAP3
CPPFLAGS += $(DEFINES)
ifeq ($(PICOLIBC), 1)
CFLAGS += --specs=picolibc.specs -DPICOLIBC_INTEGER_PRINTF_SCANF --oslib=semihost
endif
CFLAGS += -mthumb -mcpu=cortex-m3 CFLAGS += -mthumb -mcpu=cortex-m3
ifeq ($(DEBUG), 1) ifeq ($(DEBUG), 1)
CFLAGS += -g3 -Og -ffunction-sections -fdata-sections CFLAGS += -g3 -Og -ffunction-sections -fdata-sections
else else
CFLAGS += -Os -ffunction-sections -fdata-sections CFLAGS += -Os -ffunction-sections -fdata-sections
endif endif
CFLAGS += -MMD #CFLAGS += -flto
CFLAGS += -Wall -Wextra -Wshadow CFLAGS += -Wall -Wextra -Wshadow
#CFLAGS += -Wpedantic -fanalyzer #CFLAGS += -Wpedantic -fanalyzer
#CFLAGS += -flto CFLAGS += -MMD
CFLAGS += $(INCLUDE_DIRS) CFLAGS += $(INCLUDE_DIRS)
LDFLAGS = -T mps2_m3.ld LDFLAGS = -T mps2_m3.ld
LDFLAGS += -Xlinker -Map=${BUILD_DIR}/output.map LDFLAGS += -Xlinker -Map=${BUILD_DIR}/output.map
LDFLAGS += -Xlinker --gc-sections LDFLAGS += -Xlinker --gc-sections
LDFLAGS += -nostartfiles -specs=nano.specs -specs=nosys.specs -specs=rdimon.specs #LDFLAGS += -Xlinker --print-gc-sections
ifeq ($(PICOLIBC), 1)
LDFLAGS += -nostartfiles
else
LDFLAGS += -nostartfiles -specs=nano.specs -specs=nosys.specs -specs=rdimon.specs
endif
OBJ_FILES := $(SOURCE_FILES:%.c=$(BUILD_DIR)/%.o) OBJ_FILES := $(SOURCE_FILES:%.c=$(BUILD_DIR)/%.o)
.PHONY: clean .PHONY: clean
$(BUILD_DIR)/$(BIN) : $(OBJ_FILES) $(BUILD_DIR)/$(BIN): $(OBJ_FILES)
$(CC) $(CFLAGS) $(LDFLAGS) $+ -o $(@) $(CC) $(CFLAGS) $(LDFLAGS) $+ -o $(@)
$(SIZE) $(@) $(SIZE) $(@)
@ -88,7 +95,7 @@ $(BUILD_DIR)/$(BIN) : $(OBJ_FILES)
INCLUDES := $(SOURCE_FILES:%.c=$(BUILD_DIR)/%.d) INCLUDES := $(SOURCE_FILES:%.c=$(BUILD_DIR)/%.d)
-include $(INCLUDES) -include $(INCLUDES)
${BUILD_DIR}/%.o : %.c Makefile ${BUILD_DIR}/%.o: %.c Makefile
-mkdir -p $(@D) -mkdir -p $(@D)
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@

View file

@ -142,7 +142,10 @@ static UBaseType_t ulNextRand;
void main_tcp_echo_client_tasks( void ) void main_tcp_echo_client_tasks( void )
{ {
BaseType_t xReturn; BaseType_t xReturn;
const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL );
#ifndef __PICOLIBC__
const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL );
#endif
/* /*
* Instructions for using this project are provided on: * Instructions for using this project are provided on:
@ -203,7 +206,9 @@ void main_tcp_echo_client_tasks( void )
* really applicable to the Linux simulator port). */ * really applicable to the Linux simulator port). */
for( ; ; ) for( ; ; )
{ {
usleep( ulLongTime_ms * 1000 ); #ifndef __PICOLIBC__
usleep( ulLongTime_ms * 1000 );
#endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -124,8 +124,10 @@ SECTIONS
PROVIDE ( end = . ); PROVIDE ( end = . );
PROVIDE ( _end = . ); PROVIDE ( _end = . );
_heap_bottom = .; _heap_bottom = .;
__heap_start = .;
. = . + _Min_Heap_Size; . = . + _Min_Heap_Size;
_heap_top = .; _heap_top = .;
__heap_end = .;
. = . + _Min_Stack_Size; . = . + _Min_Stack_Size;
. = ALIGN(8); . = ALIGN(8);
} >RAM } >RAM

View file

@ -30,6 +30,7 @@ extern "C" {
#include <sys/types.h> #include <sys/types.h>
void uart_init( void ); void uart_init( void );
#ifndef __PICOLIBC__
__attribute__( ( used ) ) int _fstat( int file ); __attribute__( ( used ) ) int _fstat( int file );
int _read( int file, int _read( int file,
char * buf, char * buf,
@ -39,6 +40,7 @@ int _write( int file,
int len ); int len );
void * _sbrk( int incr ); void * _sbrk( int incr );
#endif
typedef struct UART_t typedef struct UART_t
{ {
@ -55,10 +57,12 @@ typedef struct UART_t
#define UART_CTRL_TX_EN ( 1 << 0 ) #define UART_CTRL_TX_EN ( 1 << 0 )
#ifndef __PICOLIBC__
extern unsigned long _heap_bottom; extern unsigned long _heap_bottom;
extern unsigned long _heap_top; extern unsigned long _heap_top;
static char * heap_end = ( char * ) &_heap_bottom; static char * heap_end = ( char * ) &_heap_bottom;
#endif
/** /**
* @brief initializes the UART emulated hardware * @brief initializes the UART emulated hardware
@ -69,6 +73,24 @@ void uart_init( void )
UART0_ADDR->CTRL = UART_CTRL_TX_EN; UART0_ADDR->CTRL = UART_CTRL_TX_EN;
} }
#ifdef __PICOLIBC__
#include <stdio.h>
int
_uart_putc(char c, FILE *file)
{
( void ) file;
UART_DR( UART0_ADDR ) = c;
return (unsigned char) c;
}
static FILE __stdio = FDEV_SETUP_STREAM(_uart_putc, NULL, NULL, _FDEV_SETUP_WRITE);
__attribute__( ( used ) ) FILE *const stdout = &__stdio;
#else
/** /**
* @brief not used anywhere in the code * @brief not used anywhere in the code
* @todo implement if necessary * @todo implement if necessary
@ -138,6 +160,7 @@ void * _sbrk( int incr )
return prev_heap_end; return prev_heap_end;
} }
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -9,20 +9,23 @@ LD = arm-none-eabi-gcc
SIZE = arm-none-eabi-size SIZE = arm-none-eabi-size
MAKE = make MAKE = make
CFLAGS += -ffreestanding -mthumb -mcpu=cortex-m3 ifeq ($(PICOLIBC), 1)
CFLAGS += -Wall -Wextra -Wshadow -Wno-unused-value CFLAGS += --specs=picolibc.specs -DPICOLIBC_INTEGER_PRINTF_SCANF
endif
CFLAGS += -mthumb -mcpu=cortex-m3 -ffreestanding
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" -MT $@
#CFLAGS += -std=c99
#CFLAGS += -Wpedantic -fanalyzer
#CFLAGS += -flto #CFLAGS += -flto
CFLAGS += -Wall -Wextra -Wshadow -Wno-unused-value
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" -MT $@
CFLAGS += $(INCLUDE_DIRS) CFLAGS += $(INCLUDE_DIRS)
LDFLAGS = -T ./mps2_m3.ld LDFLAGS = -T ./mps2_m3.ld
LDFLAGS += -Xlinker -Map=$(OUTPUT_DIR)/RTOSDemo.map LDFLAGS += -Xlinker -Map=$(OUTPUT_DIR)/RTOSDemo.map
LDFLAGS += -Xlinker --gc-sections LDFLAGS += -Xlinker --gc-sections
LDFLAGS += -nostartfiles #LDFLAGS += -Xlinker --print-gc-sections
LDFLAGS += -specs=nano.specs -specs=nosys.specs # -specs=rdimon.specs ifneq ($(PICOLIBC), 1)
LDFLAGS += -nostartfiles -specs=nano.specs -specs=nosys.specs # -specs=rdimon.specs
endif
# #
# Kernel build. # Kernel build.

View file

@ -79,7 +79,7 @@ const uint32_t* isr_vector[] __attribute__((section(".isr_vector"), used)) =
void Reset_Handler( void ) void Reset_Handler( void )
{ {
main(); (void) main();
} }
/* Variables used to store the value of registers at the time a hardfault /* Variables used to store the value of registers at the time a hardfault

View file

@ -103,7 +103,7 @@ static void prvUARTInit( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void main( void ) int main( void )
{ {
/* See https://www.freertos.org/freertos-on-qemu-mps2-an385-model.html for /* See https://www.freertos.org/freertos-on-qemu-mps2-an385-model.html for
* instructions. */ * instructions. */
@ -141,6 +141,7 @@ void main( void )
main_full(); main_full();
} }
#endif #endif
return 0;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -313,6 +314,25 @@ static void prvUARTInit( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#ifdef __PICOLIBC__
int
_uart_putc(char c, FILE *file)
{
( void ) file;
while( ( UART0_STATE & TX_BUFFER_MASK ) != 0 )
{
}
UART0_DATA = c;
return (unsigned char) c;
}
static FILE __stdio = FDEV_SETUP_STREAM(_uart_putc, NULL, NULL, _FDEV_SETUP_WRITE);
__attribute__( ( used ) ) FILE *const stdout = &__stdio;
#else
/*-----------------------------------------------------------*/
int __write( int iFile, int __write( int iFile,
char * pcString, char * pcString,
int iStringLength ) int iStringLength )
@ -351,3 +371,4 @@ void * malloc( size_t size )
{ {
} }
} }
#endif

View file

@ -35,29 +35,29 @@ INCLUDE_DIRS += -I$(FREERTOS_DIR)/Demo/CORTEX_MPU_M3_MPS2_QEMU_GCC/C
INCLUDE_DIRS += -I$(KERNEL_DIR)/include INCLUDE_DIRS += -I$(KERNEL_DIR)/include
INCLUDE_DIRS += -I$(KERNEL_DIR)/portable/GCC/ARM_CM3_MPU INCLUDE_DIRS += -I$(KERNEL_DIR)/portable/GCC/ARM_CM3_MPU
DEFINES := -DHEAP4 CPPFLAGS += -DHEAP4
CPPFLAGS += $(DEFINES)
ifeq ($(PICOLIBC), 1)
CFLAGS += --specs=picolibc.specs -DPICOLIBC_INTEGER_PRINTF_SCANF
endif
CFLAGS += -mthumb -mcpu=cortex-m3 CFLAGS += -mthumb -mcpu=cortex-m3
ifeq ($(DEBUG), 1)
CFLAGS += -g3 -Og -ffunction-sections -fdata-sections -save-temps=obj
else
CFLAGS += -Os -ffunction-sections -fdata-sections
endif
#CFLAGS += -flto
CFLAGS += -Wall -Wextra -Wshadow -Wno-unused-parameter CFLAGS += -Wall -Wextra -Wshadow -Wno-unused-parameter
#CFLAGS += -Wpedantic -fanalyzer
CFLAGS += $(INCLUDE_DIRS) CFLAGS += $(INCLUDE_DIRS)
LDFLAGS = -T ./scripts/mps2_m3.ld LDFLAGS = -T ./scripts/mps2_m3.ld
LDFLAGS += -Xlinker -Map=${BUILD_DIR}/output.map LDFLAGS += -Xlinker -Map=${BUILD_DIR}/output.map
LDFLAGS += -Xlinker --gc-sections LDFLAGS += -Xlinker --gc-sections
LDFLAGS += -nostartfiles -nostdlib -nolibc -nodefaultlibs #LDFLAGS += -Xlinker --print-gc-sections
#LDFLAGS += -nostartfiles -nostdlib -nolibc -nodefaultlibs
LDFLAGS += -nostdlib
ifeq ($(DEBUG), 1)
CFLAGS += -g3 -Og -ffunction-sections -fdata-sections -save-temps=obj
else
CFLAGS += -Os -ffunction-sections -fdata-sections
endif
ifeq ($(PICOLIBC), 1)
CFLAGS += --specs=picolibc.specs -DPICOLIBC_INTEGER_PRINTF_SCANF
LDFLAGS += --specs=picolibc.specs -DPICOLIBC_INTEGER_PRINTF_SCANF
endif
OBJ_FILES := $(SOURCE_FILES:%.c=$(BUILD_DIR)/%.o) OBJ_FILES := $(SOURCE_FILES:%.c=$(BUILD_DIR)/%.o)

View file

@ -66,7 +66,8 @@ SECTIONS
*(privileged_functions) *(privileged_functions)
. = ALIGN(4); . = ALIGN(4);
FILL(0xDEAD); FILL(0xDEAD);
/* Ensure that un-privileged code is placed after the region reserved 4 * for privileged kernel code. */ /* Ensure that un-privileged code is placed after the region reserved
* for privileged kernel code. */
/* Note that dot (.) actually refers to the byte offset from the start /* Note that dot (.) actually refers to the byte offset from the start
* of the current section (.privileged_functions in this case). As a * of the current section (.privileged_functions in this case). As a
* result, setting dot (.) to a value sets the size of the section. */ * result, setting dot (.) to a value sets the size of the section. */

View file

@ -76,7 +76,7 @@ _uart_putc(char c, FILE *file)
static FILE __stdio = FDEV_SETUP_STREAM(_uart_putc, NULL, NULL, _FDEV_SETUP_WRITE); static FILE __stdio = FDEV_SETUP_STREAM(_uart_putc, NULL, NULL, _FDEV_SETUP_WRITE);
FILE *const stdout = &__stdio; __attribute__( ( used ) ) FILE *const stdout = &__stdio;
#else #else