Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions so3/arch/arm32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ obj-y += vfp.o
obj-y += backtrace.o backtrace_asm.o
obj-y += smccc-call.o
obj-y += syscalls.o
obj-y += kuser_helper.o

obj-y += lib/

Expand Down
99 changes: 99 additions & 0 deletions so3/arch/arm32/kuser_helper.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2026 Clément Dieperink <clement.dieperink@heig-vd.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/*
* This file is copied from the Linux kernel with some small adaptation for SO3.
* Original file from Linux 6.18 : linux/arch/arm/kernel/entry-armv.S:652-842
*/


/*
* User helpers.
*
* Each segment is 32-byte aligned and will be moved to the top of the high
* vector page. New segments (if ever needed) must be added in front of
* existing ones. This mechanism should be used only for things that are
* really small and justified, and not be abused freely.
*
* See Documentation/arch/arm/kernel_user_helpers.rst for formal definitions.
*/
.macro usr_ret, reg
ret \reg
.endm

.macro kuser_pad, sym, size
.if (. - \sym) & 3
.rept 4 - (. - \sym) & 3
.byte 0
.endr
.endif
.rept (\size - (. - \sym)) / 4
.word 0xe7fddef1
.endr
.endm

.align 5
.globl __kuser_helper_start
__kuser_helper_start:

/*
* Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular
* kuser "slots", therefore 0xffff0f80 is not used as a valid entry point.
*/

@ Not implemented as eorseq doesn't compile
__kuser_cmpxchg64: @ 0xffff0f60

kuser_pad __kuser_cmpxchg64, 64

__kuser_memory_barrier: @ 0xffff0fa0
dmb ish
mov pc, lr

kuser_pad __kuser_memory_barrier, 32

__kuser_cmpxchg: @ 0xffff0fc0

dmb ish
1: ldrex r3, [r2]
subs r3, r3, r0
strexeq r3, r1, [r2]
teqeq r3, #1
beq 1b
rsbs r0, r3, #0
/* beware -- each __kuser slot must be 8 instructions max */
b __kuser_memory_barrier

kuser_pad __kuser_cmpxchg, 32

@ Not implemented here as syscall already exist
__kuser_get_tls: @ 0xffff0fe0
mov r0, #0
mov pc, lr
kuser_pad __kuser_get_tls, 16
.rep 3
.word 0 @ 0xffff0ff0 software TLS value, then
.endr @ pad up to __kuser_helper_version

__kuser_helper_version: @ 0xffff0ffc
.word ((__kuser_helper_end - __kuser_helper_start) >> 5)

.globl __kuser_helper_end
__kuser_helper_end:
21 changes: 14 additions & 7 deletions so3/fs/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ void elf_load_segments(elf_img_info_t *elf_img_info)
{
size_t i;
size_t segment_start, segment_end;
size_t page_start, page_end;
size_t min_segment_start, max_segment_end;

/* Segments */
#ifdef CONFIG_ARCH_ARM32
Expand All @@ -189,7 +189,8 @@ void elf_load_segments(elf_img_info_t *elf_img_info)
LOG_DEBUG("sizeof(struct elf64_phdr): %d bytes\n", sizeof(struct elf64_phdr));
#endif

elf_img_info->segment_page_count = 0;
min_segment_start = -1;
max_segment_end = 0;
for (i = 0; i < elf_img_info->header->e_phnum; i++) {
#ifdef CONFIG_ARCH_ARM32
memcpy(elf_img_info->segments + i,
Expand All @@ -202,16 +203,22 @@ void elf_load_segments(elf_img_info_t *elf_img_info)
#endif

if (elf_img_info->segments[i].p_type == PT_LOAD) {
/* Don't use only p_memsz to get page count as p_vaddr can be unaligned and additionnal page will be needed. */
segment_start = elf_img_info->segments[i].p_vaddr;
segment_end = segment_start + elf_img_info->segments[i].p_memsz;

page_start = segment_start >> PAGE_SHIFT;
page_end = (segment_end + PAGE_SIZE) >> PAGE_SHIFT;

elf_img_info->segment_page_count += page_end - page_start;
min_segment_start = min(min_segment_start, (segment_start & PAGE_MASK));
max_segment_end = max(max_segment_end, segment_end);
}
}

if (max_segment_end != -1) {
elf_img_info->segment_start_vaddr = min_segment_start;
elf_img_info->segment_end_vaddr = max_segment_end;
} else {
elf_img_info->segment_start_vaddr = 0;
elf_img_info->segment_end_vaddr = 0;
}

LOG_DEBUG("segments use %d virtual pages\n", elf_img_info->segment_page_count);

for (i = 0; i < elf_img_info->header->e_phnum; i++) {
Expand Down
6 changes: 4 additions & 2 deletions so3/include/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ struct elf_img_info {
Elf32_Phdr *segments; /* program header */
char **section_names;
void *file_buffer;
uint32_t segment_page_count;
addr_t segment_start_vaddr;
addr_t segment_end_vaddr;
};

typedef Elf32_Off elf_addr_t;
Expand All @@ -46,7 +47,8 @@ struct elf_img_info {
Elf64_Phdr *segments; /* program header */
char **section_names;
void *file_buffer;
uint64_t segment_page_count;
addr_t segment_start_vaddr;
addr_t segment_end_vaddr;
};

typedef Elf64_Off elf_addr_t;
Expand Down
2 changes: 1 addition & 1 deletion so3/kernel/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void kernel_start(void)
{
lprintk("%s", SO3_BANNER);

LOG_INFO("Now bootstraping the kernel ...");
LOG_INFO("Now bootstraping the kernel ...\n");

/* Memory manager subsystem initialization */
memory_init();
Expand Down
96 changes: 23 additions & 73 deletions so3/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,6 @@ char *proc_state_str(proc_state_t state)
static uint32_t pid_current = 1;
static pcb_t *root_process = NULL; /* root process */

/* only the following sections are supported */
#define SUPPORTED_SECTION_COUNT 10
static const char *supported_section_names[SUPPORTED_SECTION_COUNT] = {
".init", ".text", ".rodata", ".data", ".sbss", ".bss", ".scommon", ".fini", ".init_array", ".fini_array",
};

/*
* Find a process (pcb_t) from its pid.
* Return NULL if no process has been found.
Expand Down Expand Up @@ -509,16 +503,13 @@ void post_setup_image(args_env_t *args_env, elf_img_info_t *elf_img_info)
/* This should contains a bitmask of hardware capabilities */
NEW_AUX_ENT(AT_HWCAP, HWCAP_ELF);

/* Those value should come from elf_img_info->header, but as user application
* are compiled with linker option -N, the program header (PHDR) isn't in a PT_LOAD
* segment meaning it will not be copied in userspace.
* The main effect of this is that variable in thread local storage will not be possible.
* Those variable are *flaged* with __thread (i.e `__thread int n;`) and aren't used for now.
* This header is also used for dynamically linking, which isn't supported by SO3 anyway.
/* Set PHDR information, so userspace can retrieve TLS information.
* Due to how userspace application are built the PHDR segments is missing and so
* we need to manually compute its address.
*/
NEW_AUX_ENT(AT_PHDR, 0);
NEW_AUX_ENT(AT_PHENT, 0);
NEW_AUX_ENT(AT_PHNUM, 0);
NEW_AUX_ENT(AT_PHDR, elf_img_info->header->e_phoff + (elf_img_info->segment_start_vaddr & PAGE_MASK));
NEW_AUX_ENT(AT_PHENT, sizeof(*elf_img_info->segments));
NEW_AUX_ENT(AT_PHNUM, elf_img_info->header->e_phnum);

/* NULL termination */
NEW_AUX_ENT(AT_NULL, 0);
Expand Down Expand Up @@ -609,17 +600,18 @@ int setup_proc_image_replace(elf_img_info_t *elf_img_info, pcb_t *pcb, int argc,
* application must start at 0x1000 (at the lowest).
*/

pcb->page_count += elf_img_info->segment_page_count;
page_count = ((elf_img_info->segment_end_vaddr - elf_img_info->segment_start_vaddr) >> PAGE_SHIFT) + 1;
pcb->page_count += page_count;

/* Map the elementary sections (text, data, bss) */
allocate_page(pcb, (uint32_t) (elf_img_info->header->e_entry & PAGE_MASK), elf_img_info->segment_page_count, true);
allocate_page(pcb, elf_img_info->segment_start_vaddr, page_count, true);

LOG_DEBUG("entry point: 0x%08x\n", elf_img_info->header->e_entry);
LOG_DEBUG("page count: 0x%08x\n", pcb->page_count);

/* Maximum heap size */
page_count = ALIGN_UP(HEAP_SIZE, PAGE_SIZE) >> PAGE_SHIFT;
pcb->heap_base = (elf_img_info->header->e_entry & PAGE_MASK) + (pcb->page_count + 1) * PAGE_SIZE;
pcb->heap_base = (elf_img_info->segment_end_vaddr & PAGE_MASK) + PAGE_SIZE;
pcb->heap_pointer = pcb->heap_base;
pcb->page_count += page_count;

Expand All @@ -643,69 +635,27 @@ int setup_proc_image_replace(elf_img_info_t *elf_img_info, pcb_t *pcb, int argc,
/* load sections from each loadable segment into the process' virtual pages */
void load_process(elf_img_info_t *elf_img_info)
{
unsigned long section_start, section_end;
unsigned long segment_start, segment_end;
int i, j, k, l;
bool section_supported;
char section_base_name[16];
int section_name_dots;
int i;

/* Manually copy the PHDR as no segement/section contains it. */
memcpy((void *) (elf_img_info->header->e_phoff + (elf_img_info->segment_start_vaddr & PAGE_MASK)),
elf_img_info->file_buffer + elf_img_info->header->e_phoff,
elf_img_info->header->e_phnum * elf_img_info->header->e_phentsize);

/* Loading the different segments */
for (i = 0; i < elf_img_info->header->e_phnum; i++) {
if (elf_img_info->segments[i].p_type != PT_LOAD)
/* Skip unloadable segments */
continue;

segment_start = elf_img_info->segments[i].p_offset;
segment_end = segment_start + elf_img_info->segments[i].p_memsz;

/* Sections */
for (j = 0; j < elf_img_info->header->e_shnum; j++) {
section_start = elf_img_info->sections[j].sh_offset;
section_end = section_start + elf_img_info->sections[j].sh_size;

/* Verify if the section is part of this segment */
if ((section_start < segment_start) || (section_end > segment_end))
continue;

/* Copy only base name of the section */
l = 0;
section_name_dots = 0;
do {
section_base_name[l] = elf_img_info->section_names[j][l];
if (section_base_name[l] == '.' && section_name_dots++)
break; // Base name stops at second '.'
} while (section_base_name[l++] != '\0');

/* Terminate string correctly (replace second '.' if stopped by it) */
section_base_name[l] = '\0';

/* Not all sections are supported */
section_supported = false;
for (k = 0; k < SUPPORTED_SECTION_COUNT; k++) {
if (!strcmp(section_base_name, supported_section_names[k])) {
section_supported = true;
break;
}
}

if (!section_supported) {
LOG_DEBUG("Section %s not loaded: unsupported name\n", elf_img_info->section_names[j]);
continue;
}
/* Copy all required data. */
memcpy((void *) elf_img_info->segments[i].p_vaddr,
(void *) (elf_img_info->file_buffer + elf_img_info->segments[i].p_offset),
elf_img_info->segments[i].p_filesz);

/* Load this section into the process' virtual memory */
if (elf_img_info->sections[j].sh_type == SHT_NOBITS)
/* unless it were not stored in the file (.bss)
*/
continue;

/* Real load of contents in the user space memory of the
* process */
memcpy((void *) elf_img_info->sections[j].sh_addr,
(void *) (elf_img_info->file_buffer + elf_img_info->sections[j].sh_offset),
elf_img_info->sections[j].sh_size);
}
/* Set remaining byte (bss) to zero. */
memset((void *) (elf_img_info->segments[i].p_vaddr + elf_img_info->segments[i].p_filesz), 0,
elf_img_info->segments[i].p_memsz - elf_img_info->segments[i].p_filesz);
}

/* Make sure all data are flushed for future context switch. */
Expand Down
8 changes: 8 additions & 0 deletions so3/mm/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,11 @@ void memory_init(void)

#if defined(CONFIG_ARCH_ARM32)
addr_t vectors_paddr;

/* kuser helper are special function provided to userspace by the kernel. */
addr_t kuser_sz;
extern char __kuser_helper_start[];
extern char __kuser_helper_end[];
#endif
void *new_sys_root_pgtable;

Expand Down Expand Up @@ -496,6 +501,9 @@ void memory_init(void)
create_mapping(NULL, VECTOR_VADDR, vectors_paddr, PAGE_SIZE, true);

memcpy((void *) VECTOR_VADDR, (void *) &__vectors_start, (void *) &__vectors_end - (void *) &__vectors_start);

kuser_sz = __kuser_helper_end - __kuser_helper_start;
memcpy((void *) (VECTOR_VADDR + PAGE_SIZE - kuser_sz), __kuser_helper_start, kuser_sz);
#endif

set_pgtable(__sys_root_pgtable);
Expand Down
2 changes: 1 addition & 1 deletion usr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

cmake_minimum_required(VERSION 3.16)

project(so3-usr LANGUAGES C ASM)
project(so3-usr LANGUAGES C CXX ASM)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Expand Down
3 changes: 2 additions & 1 deletion usr/aarch64-linux-musl.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ set(CMAKE_CXX_COMPILER "aarch64-linux-musl-g++")
set(CMAKE_ASM_COMPILER "aarch64-linux-musl-gcc")

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c99 -D_GNU_SOURCE -D__ARM64__ -fno-common")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -D_GNU_SOURCE -D__ARM64__ -fno-common")

set(CMAKE_ASM_FLAGS "-D__ARM64__ -D__ASSEMBLY__")

set(CMAKE_LINKER "aarch64-linux-musl-ld")

set(CMAKE_EXE_LINKER_FLAGS "-Os -static" CACHE STRING "SO3 usr LDFLAGS for executables")
set(CMAKE_EXE_LINKER_FLAGS "-Os -static -fno-rtti" CACHE STRING "SO3 usr LDFLAGS for executables")
6 changes: 3 additions & 3 deletions usr/arm-linux-musl.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ set(CMAKE_CXX_COMPILER "arm-linux-musleabihf-g++")
set(CMAKE_ASM_COMPILER "arm-linux-musleabihf-gcc")

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c99 -D_GNU_SOURCE -D__ARM__ -marm -mno-thumb-interwork -ffreestanding -fno-common")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -D_GNU_SOURCE -D__ARM__ -marm -mno-thumb-interwork -ffreestanding -fno-common")

set(CMAKE_ASM_FLAGS "-D__ARM__ -D__ASSEMBLY__")

set(CMAKE_LINKER "arm-linux-musleabihf-ld")


set(CMAKE_EXE_LINKER_FLAGS "-Os -static" CACHE STRING "SO3 usr LDFLAGS for executables")
set(CMAKE_EXE_LINKER_FLAGS "-Os -static -fno-rtti" CACHE STRING "SO3 usr LDFLAGS for executables")
Loading