First commit
This commit is contained in:
commit
e7ccf2e72a
567 changed files with 68348 additions and 0 deletions
120
GNUmakefile
Normal file
120
GNUmakefile
Normal file
|
@ -0,0 +1,120 @@
|
|||
RM= rm
|
||||
CC= $(CONFIG_TARGET_CC)
|
||||
AS= $(CONFIG_TARGET_CC)
|
||||
# NOTE(dinosaure): we must use [aarch64-none-elf-gcc] to compile assembly code
|
||||
# to be able to include some files and define some macros.
|
||||
LD= $(CONFIG_TARGET_LD)
|
||||
AR= aarch64-none-elf-ar # TODO
|
||||
OBJDUMP= aarch64-none-elf-objdump # TODO
|
||||
OBJCOPY= $(CONFIG_TARGET_OBJCOPY)
|
||||
|
||||
export TOPDIR := $(abspath .)
|
||||
|
||||
$(TOPDIR)/Makeconf:
|
||||
$(error Makeconf not found, please run ./configure.sh)
|
||||
|
||||
include $(TOPDIR)/Makeconf
|
||||
|
||||
# armstub8.bin: armstub8.S
|
||||
# @echo "CC -DGIC=1 $<"
|
||||
# @$(CC) -DGIC=1 -o ${<:S=o} -c $<
|
||||
# @echo "LD --section-start=.text=0 ${<:S=o}"
|
||||
# @$(LD) --section-start=.text=0 -o ${<:S=elf} ${<:S=o}
|
||||
# @echo "DUMP ${<:S=elf}"
|
||||
# @$(OBJDUMP) -D ${<:S=elf} > ${<:S=lst}
|
||||
# @echo "COPY ${<:S=elf}"
|
||||
# @$(OBJCOPY) ${<:S=elf} -O binary $@
|
||||
|
||||
include/$(CONFIG_TARGET_TRIPLE):
|
||||
@echo "GEN $@"
|
||||
@./gen-headers.sh $@
|
||||
|
||||
CPU ?= -mcpu=cortex-a76 -mlittle-endian
|
||||
ARCH += -DAARCH=64 $(CPU)
|
||||
TARGET ?= kernel_2712
|
||||
|
||||
DEFINE += -DSSP_GUARD_SYMBOL=__stack_chk_guard \
|
||||
-DSSP_FAIL_SYMBOL=__stack_chk_fail
|
||||
|
||||
INCLUDE += -I $(TOPDIR)/include -I $(TOPDIR)/include/$(CONFIG_TARGET_TRIPLE) \
|
||||
-I $(TOPDIR)/nolibc/include
|
||||
|
||||
AFLAGS += $(ARCH) $(DEFINE) $(INCLUDE)
|
||||
|
||||
CFLAGS += -std=c11 -ffreestanding -fstack-protector-strong -nostdlib \
|
||||
-nostartfiles -mstrict-align -Wall \
|
||||
$(ARCH) $(DEFINE) $(INCLUDE) $(CONFIG_TARGET_CC_CFLAGS)
|
||||
|
||||
LDFLAGS += -nostdlib -static -Wl,--no-warn-rwx-segments \
|
||||
-Wl,--section-start=.init=0x80000 -Wl,--build-id=none \
|
||||
-Wl,--start-group -L . -lgilbraltar -L nolibc -lnolibc -L openlibm -lopenlibm -lgcc -Wl,--end-group
|
||||
|
||||
SRCS= kernel.c timer.c led.c interrupt_handler.c exception_handler.c \
|
||||
mbox.c clock.c crt.c serial.c log.c
|
||||
|
||||
ASMS= startup.S exception_stub.S
|
||||
|
||||
OBJS= $(SRCS:c=o) $(ASMS:S=o)
|
||||
|
||||
%.o: %.S
|
||||
@echo "AS $@"
|
||||
@$(AS) $(AFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.c include/$(CONFIG_TARGET_TRIPLE)
|
||||
@echo "CC $@"
|
||||
@$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
libgilbraltar.a: $(OBJS)
|
||||
@echo "AR $@"
|
||||
@rm -f $@
|
||||
@$(AR) cr $@ $^
|
||||
|
||||
.PHONY: phony-openlibm
|
||||
phony-openlibm: include/$(CONFIG_TARGET_TRIPLE)
|
||||
@$(MAKE) -C openlibm \
|
||||
"CC=$(CC)" "CPPFLAGS=$(CFLAGS)" libopenlibm.a
|
||||
|
||||
openlibm/libopenlibm.a: phony-openlibm
|
||||
|
||||
NOLIBC_CFLAGS= $(CFLAGS) -I $(TOPDIR)/nolibc/include -I $(TOPDIR)/openlibm/src -I $(TOPDIR)/openlibm/include
|
||||
|
||||
.PHONY: phony-nolibc
|
||||
phony-nolibc: include/$(CONFIG_TARGET_TRIPLE)
|
||||
$(MAKE) -C nolibc libnolibc.a \
|
||||
"CC=$(CC)" "FREESTANDING_CFLAGS=$(NOLIBC_CFLAGS)"
|
||||
|
||||
nolibc/libnolibc.a: phony-nolibc
|
||||
|
||||
.PHONY: all
|
||||
all: libgilbraltar.a
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) -f *.o *.a *.elf *.bin *.lst *.img
|
||||
$(RM) -rf include/$(CONFIG_TARGET_TRIPLE)
|
||||
$(RM) -f test/*.o
|
||||
$(MAKE) -C openlibm clean
|
||||
$(MAKE) -C nolibc clean FREESTANDING_CFLAGS=_
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
$(RM) -f Makeconf
|
||||
|
||||
test/%.o: test/%.c
|
||||
@echo "CC $@"
|
||||
@$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
test01.img: libgilbraltar.a nolibc/libnolibc.a openlibm/libopenlibm.a test/test01.o
|
||||
@echo "LD ${@:img=elf}"
|
||||
@$(LD) test/${@:img=o} -o ${@:img=elf} $(LDFLAGS) -Wl,-T gilbraltar.ld
|
||||
@$(OBJCOPY) ${@:img=elf} -O binary $@
|
||||
|
||||
test02.img: libgilbraltar.a nolibc/libnolibc.a openlibm/libopenlibm.a test/test02.o
|
||||
@echo "LD ${@:img=elf}"
|
||||
@$(LD) test/${@:img=o} -o ${@:img=elf} $(LDFLAGS) -Wl,-T gilbraltar.ld
|
||||
@$(OBJCOPY) ${@:img=elf} -O binary $@
|
||||
|
||||
test03.img: libgilbraltar.a nolibc/libnolibc.a openlibm/libopenlibm.a test/test03.o
|
||||
@echo "LD ${@:img=elf}"
|
||||
@$(LD) test/${@:img=o} -o ${@:img=elf} $(LDFLAGS) -Wl,-T gilbraltar.ld
|
||||
@$(OBJCOPY) ${@:img=elf} -O binary $@
|
213
armstub8.S
Normal file
213
armstub8.S
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Romain Calascibetta <romain.calascibetta@gmail.com>
|
||||
* Copyright (c) 2016-2019 Raspberry Pi (Trading) Ltd.
|
||||
* Copyright (c) 2016 Stephen Warren <swarren@wwwdotorg.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* 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 HOLDER 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.
|
||||
*/
|
||||
|
||||
#define BIT(x) (1 << (x))
|
||||
|
||||
#define LOCAL_CONTROL 0xff800000
|
||||
#define LOCAL_PRESCALER 0xff800008
|
||||
#define GIC_DISTB 0xff841000
|
||||
#define GIC_CPUB 0xff842000
|
||||
#define OSC_FREQ 54000000
|
||||
|
||||
#define SCR_RW BIT(10)
|
||||
#define SCR_HCE BIT(8)
|
||||
#define SCR_SMD BIT(7)
|
||||
#define SCR_RES1_5 BIT(5)
|
||||
#define SCR_RES1_4 BIT(4)
|
||||
#define SCR_NS BIT(0)
|
||||
#define SCR_VAL \
|
||||
(SCR_RW | SCR_HCE | SCR_SMD | SCR_RES1_5 | SCR_RES1_4 | SCR_NS)
|
||||
|
||||
#define ACTLR_VAL \
|
||||
(BIT(0) | BIT(1) | BIT(4) | BIT(5) | BIT(6))
|
||||
|
||||
#define CPUECTLR_EL1 S3_1_C15_C2_1
|
||||
#define CPUECTLR_EL1_SMPEN BIT(6)
|
||||
|
||||
#define SPSR_EL3_D BIT(9)
|
||||
#define SPSR_EL3_A BIT(8)
|
||||
#define SPSR_EL3_I BIT(7)
|
||||
#define SPSR_EL3_F BIT(6)
|
||||
#define SPSR_EL3_MODE_EL2H 9
|
||||
#define SPSR_EL3_VAL \
|
||||
(SPSR_EL3_D | SPSR_EL3_A | SPSR_EL3_I | SPSR_EL3_F | SPSR_EL3_MODE_EL2H)
|
||||
|
||||
#define L2CTLR_EL1 S3_1_C11_C0_2
|
||||
#define GICC_CTRLR 0x0
|
||||
#define GICC_PMR 0x4
|
||||
#define IT_NR 0x8 // Number of interrupt enable registers (256 total irqs)
|
||||
#define GICD_CTRLR 0x0
|
||||
#define GICD_IGROUPR 0x80
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
// LOCAL_CONTROL:
|
||||
// Bit 9 clear: Increment by 1 (vs. 2).
|
||||
// Bit 8 clear: Timer source is 19.2MHz crystal (vs. APB).
|
||||
ldr x0, =LOCAL_CONTROL
|
||||
str wzr, [x0]
|
||||
// LOCAL_PRESCALER; divide-by (0x80000000 / register_val) == 1
|
||||
mov w1, 0x80000000
|
||||
str w1, [x0, #(LOCAL_PRESCALER - LOCAL_CONTROL)]
|
||||
|
||||
// Set L2 read/write cache latency to 3
|
||||
mrs x0, L2CTLR_EL1
|
||||
mov x1, #0x22
|
||||
orr x0, x0, x1
|
||||
msr L2CTLR_EL1, x0
|
||||
|
||||
// Set up CNTFRQ_EL0
|
||||
ldr x0, =OSC_FREQ
|
||||
msr CNTFRQ_EL0, x0
|
||||
|
||||
// Set up CNTVOFF_EL2
|
||||
msr CNTVOFF_EL2, xzr
|
||||
|
||||
// Enable FP/SIMD
|
||||
// Bit 10 (TFP) is set to 0
|
||||
msr CPTR_EL3, xzr
|
||||
|
||||
// Set up SCR
|
||||
mov x0, #SCR_VAL
|
||||
msr SCR_EL3, x0
|
||||
|
||||
// Set up ACTLR
|
||||
mov x0, #ACTLR_VAL
|
||||
msr ACTLR_EL3, x0
|
||||
|
||||
// Set SMPEN
|
||||
mov x0, #CPUECTLR_EL1_SMPEN
|
||||
msr CPUECTLR_EL1, x0
|
||||
|
||||
#ifdef GIC
|
||||
bl setup_gic
|
||||
#endif
|
||||
// Set up SCTLR_EL2
|
||||
// All set bits below are res1. LE, no WXN/I/SA/C/A/M
|
||||
ldr x0, =0x30c50830
|
||||
msr SCTLR_EL2, x0
|
||||
|
||||
// Switch to EL2
|
||||
mov x0, #SPSR_EL3_VAL
|
||||
msr spsr_el3, x0
|
||||
adr x0, in_el2
|
||||
msr elr_el3, x0
|
||||
eret
|
||||
in_el2:
|
||||
mrs x6, MPIDR_EL1
|
||||
and x6, x6, #0x3
|
||||
cbz x6, primary_cpu
|
||||
|
||||
adr x5, spin_cpu0
|
||||
secondary_spin:
|
||||
wfe
|
||||
ldr x4, [x5, x6, lsl #3]
|
||||
cbz x4, secondary_spin
|
||||
mov x0, #0
|
||||
b boot_kernel
|
||||
|
||||
primary_cpu:
|
||||
ldr w4, kernel_entry32
|
||||
ldr w0, dtb_ptr32
|
||||
|
||||
boot_kernel:
|
||||
mov x1, #0
|
||||
mov x2, #0
|
||||
mov x3, #0
|
||||
br x4
|
||||
|
||||
.ltorg
|
||||
|
||||
.org 0xd8
|
||||
.globl spin_cpu0
|
||||
spin_cpu0:
|
||||
.quad 0
|
||||
.org 0xe0
|
||||
.globl spin_cpu1
|
||||
spin_cpu1:
|
||||
.quad 0
|
||||
.org 0xe8
|
||||
.globl spin_cpu2
|
||||
spin_cpu2:
|
||||
.quad 0
|
||||
.org 0xf0
|
||||
.globl spin_cpu3
|
||||
spin_cpu3:
|
||||
# Shared with next two symbols/.word
|
||||
# FW clears the next 8 bytes after reading the initial value, leaving
|
||||
# the location suitable for use as spin_cpu3
|
||||
.org 0xf0
|
||||
.globl stub_magic
|
||||
stub_magic:
|
||||
.word 0x5afe570b
|
||||
.org 0xf4
|
||||
.globl stub_version
|
||||
stub_version:
|
||||
.word 0
|
||||
.org 0xf8
|
||||
.globl dtb_ptr32
|
||||
dtb_ptr32:
|
||||
.word 0x0
|
||||
.org 0xfc
|
||||
.globl kernel_entry32
|
||||
kernel_entry32:
|
||||
.word 0x0
|
||||
|
||||
.org 0x100
|
||||
|
||||
#ifdef GIC
|
||||
|
||||
setup_gic: // Called from secure mode - set all interrupts to group 1 and enable.
|
||||
mrs x0, MPIDR_EL1
|
||||
ldr x2, =GIC_DISTB
|
||||
tst x0, #0x3
|
||||
b.eq 2f // primary core
|
||||
|
||||
mov w0, #3 // Enable group 0 and 1 IRQs from distributor
|
||||
str w0, [x2, #GICD_CTRLR]
|
||||
2:
|
||||
add x1, x2, #(GIC_CPUB - GIC_DISTB)
|
||||
mov w0, #0x1e7
|
||||
str w0, [x1, #GICC_CTRLR] // Enable group 1 IRQs from CPU interface
|
||||
mov w0, #0xff
|
||||
str w0, [x1, #GICC_PMR] // priority mask
|
||||
add x2, x2, #GICD_IGROUPR
|
||||
mov x0, #(IT_NR * 4)
|
||||
mov w1, #~0 // group 1 all the things
|
||||
3:
|
||||
subs x0, x0, #4
|
||||
str w1, [x2, x0]
|
||||
b.ne 3b
|
||||
ret
|
||||
|
||||
#endif
|
||||
|
||||
.globl dtb_space
|
||||
dtb_space:
|
41
clock.c
Normal file
41
clock.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include <mem.h>
|
||||
#include <mbox.h>
|
||||
#include <tag.h>
|
||||
|
||||
#define PROPTAG_GET_CLOCK_RATE 0x00030002
|
||||
#define PROPTAG_GET_CLOCK_RATE_MEASURED 0x00030047
|
||||
|
||||
uint32_t gilbraltar_get_clock(uint32_t cid) {
|
||||
uint32_t proptag0[] __attribute__ ((aligned(16))) =
|
||||
{
|
||||
8.4,
|
||||
CODE_REQUEST,
|
||||
PROPTAG_GET_CLOCK_RATE,
|
||||
4*4,
|
||||
1*4,
|
||||
cid,
|
||||
0,
|
||||
PROPTAG_END
|
||||
};
|
||||
|
||||
gilbraltar_mbox_write_read((uintptr_t) &proptag0);
|
||||
|
||||
if (proptag0[6] != 0)
|
||||
return proptag0[6];
|
||||
|
||||
uint32_t proptag1[] __attribute__ ((aligned(16))) =
|
||||
{
|
||||
8*4,
|
||||
CODE_REQUEST,
|
||||
PROPTAG_GET_CLOCK_RATE_MEASURED,
|
||||
4*4,
|
||||
1*4,
|
||||
cid,
|
||||
0,
|
||||
PROPTAG_END
|
||||
};
|
||||
|
||||
gilbraltar_mbox_write_read((uintptr_t) &proptag1);
|
||||
|
||||
return proptag1[6];
|
||||
}
|
456
configure.sh
Executable file
456
configure.sh
Executable file
|
@ -0,0 +1,456 @@
|
|||
#!/bin/sh
|
||||
# Copyright (c) 2015-2020 Solo5 Contributors
|
||||
# Copyright (c) 2024 Romain Calascibetta
|
||||
#
|
||||
# This file is part of Gilbraltar, a bare-metal OS for Raspberry Pi.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
TARGET_CC="${TARGET_CC:-aarch64-none-elf-gcc}"
|
||||
TARGET_LD="${TARGET_LD:-aarch64-none-elf-gcc}"
|
||||
TARGET_OBJCOPY="${TARGET_OBJCOPY:-aarch64-none-elf-objcopy}"
|
||||
|
||||
prog_NAME="$(basename $0)"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
rm -f conftmp.c conftmp.d conftmp*.o
|
||||
}
|
||||
|
||||
err()
|
||||
{
|
||||
echo "${prog_NAME}: ERROR: $@" 1>&2
|
||||
}
|
||||
|
||||
die()
|
||||
{
|
||||
echo "${prog_NAME}: ERROR: $@" 1>&2
|
||||
cleanup
|
||||
exit 1
|
||||
}
|
||||
|
||||
warn()
|
||||
{
|
||||
echo "${prog_NAME}: WARNING: $@" 1>&2
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOM 1>&2
|
||||
usage: ${prog_NAME} [ OPTIONS ]
|
||||
|
||||
Configures the Gilbraltar build system.
|
||||
|
||||
Options:
|
||||
--prefix=DIR
|
||||
Installation prefix (default: /usr/local).
|
||||
|
||||
Environment variables affecting the build system configuration:
|
||||
HOST_CC
|
||||
C compiler used for host tools.
|
||||
|
||||
TARGET_CC (= $TARGET_CC)
|
||||
TARGET_LD (= $TARGET_LD)
|
||||
TARGET_OBJCOPY (= $TARGET_OBJCOPY)
|
||||
C compiler, linker and objcopy used for target toolchain.
|
||||
|
||||
Experimental: If a cross-toolchain is specified here, the resulting
|
||||
target toolchain and bindings will be cross-compiled to its
|
||||
architecture.
|
||||
EOM
|
||||
exit 1
|
||||
}
|
||||
|
||||
cc_maybe_gcc()
|
||||
{
|
||||
${CC} -dM -E - </dev/null | \
|
||||
grep -Eq '^#define __GNUC__ ([4-9]$|[1-9][0-9]+$)'
|
||||
}
|
||||
|
||||
cc_is_clang()
|
||||
{
|
||||
${CC} -dM -E - </dev/null | grep -Eq '^#define __clang__ 1$'
|
||||
}
|
||||
|
||||
cc_has_pie()
|
||||
{
|
||||
${CC} -dM -E - </dev/null | grep -Eq '^#define __PIE__ [1-9]$'
|
||||
}
|
||||
|
||||
cc_is_gcc()
|
||||
{
|
||||
cc_maybe_gcc && ! cc_is_clang
|
||||
}
|
||||
|
||||
cc_check_option()
|
||||
{
|
||||
${CC} "$@" -x c -c -o /dev/null - <<EOM >/dev/null 2>&1
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EOM
|
||||
}
|
||||
|
||||
cc_check_header()
|
||||
{
|
||||
${CC} ${PKG_CFLAGS} -x c -o /dev/null - <<EOM >/dev/null 2>&1
|
||||
#include <$@>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EOM
|
||||
}
|
||||
|
||||
cc_check_lib()
|
||||
{
|
||||
${CC} -x c -o /dev/null - "$@" ${PKG_LIBS} <<EOM >/dev/null 2>&1
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EOM
|
||||
}
|
||||
|
||||
ld_is_lld()
|
||||
{
|
||||
${LD} --version 2>&1 | grep -q '^LLD'
|
||||
}
|
||||
|
||||
# Check that the linker ${LD} is available and suitable for our purposes.
|
||||
check_ld()
|
||||
{
|
||||
echo -n "${prog_NAME}: Checking if ${LD} is available: "
|
||||
if [ -x "$(command -v ${LD})" ]; then
|
||||
echo "yes"
|
||||
else
|
||||
echo "no"
|
||||
return 1
|
||||
fi
|
||||
echo -n "${prog_NAME}: Checking if ${LD} is LLD: "
|
||||
if ld_is_lld; then
|
||||
echo "yes"
|
||||
# LLD < 8 chokes on the Xen ldscript, so refuse to use it.
|
||||
echo -n "${prog_NAME}: Checking if LLD ${LD} is LLVM 8 or newer: "
|
||||
if ${LD} --version 2>&1 | grep -q '^LLD [1-7]\.'; then
|
||||
echo "no"
|
||||
return 1
|
||||
else
|
||||
echo "yes"
|
||||
fi
|
||||
else
|
||||
echo "no"
|
||||
fi
|
||||
|
||||
cat >conftmp.c <<EOM
|
||||
int foo(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
EOM
|
||||
${CC} -c conftmp.c -o conftmp.o || return 1
|
||||
|
||||
echo -n "${prog_NAME}: Checking if ${LD} understands ${TARGET_ARCH}: "
|
||||
if ! ${LD} -r -o conftmp1.o conftmp.o >/dev/null 2>&1; then
|
||||
echo "no"
|
||||
return 1
|
||||
else
|
||||
echo "yes"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check that the objcopy ${OBJCOPY} is available and suitable for our purposes.
|
||||
check_objcopy()
|
||||
{
|
||||
echo -n "${prog_NAME}: Checking if ${OBJCOPY} is available: "
|
||||
if [ -x "$(command -v ${OBJCOPY})" ]; then
|
||||
echo "yes"
|
||||
else
|
||||
echo "no"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cat >conftmp.c <<EOM
|
||||
int KEEP_ME(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int local(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
EOM
|
||||
${CC} -c conftmp.c -o conftmp.o || return 1
|
||||
|
||||
# [Clang] A LLVM objcopy will understand any LLVM-supported architecture.
|
||||
# [GCC] A GNU objcopy will only understand the architecture it was
|
||||
# targetted for.
|
||||
echo -n "${prog_NAME}: Checking if ${OBJCOPY} understands ${TARGET_ARCH}: "
|
||||
if ! ${OBJCOPY} conftmp.o conftmp.o >/dev/null 2>&1; then
|
||||
echo "no"
|
||||
return 1
|
||||
else
|
||||
echo "yes"
|
||||
fi
|
||||
# [Clang] For LLVM objcopy, -w was introduced in
|
||||
# https://reviews.llvm.org/D66613 (release/12.x) and -G was introduced in
|
||||
# https://reviews.llvm.org/D50589 (release/8.x).
|
||||
echo -n "${prog_NAME}: Checking if ${OBJCOPY} understands -w -G: "
|
||||
if ! ${OBJCOPY} -w -G KEEP\* conftmp.o conftmp.o >/dev/null 2>&1; then
|
||||
echo "no"
|
||||
return 1
|
||||
else
|
||||
echo "yes"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
OPT_PREFIX=/usr/local
|
||||
while [ $# -gt 0 ]; do
|
||||
OPT="$1"
|
||||
|
||||
case "${OPT}" in
|
||||
--prefix=*)
|
||||
OPT_PREFIX="${OPT##*=}"
|
||||
;;
|
||||
--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
err "Unknown option: '${OPT}'"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
#
|
||||
# Configure host tools based on HOST_CC.
|
||||
#
|
||||
HOST_CC=${HOST_CC:-cc}
|
||||
HOST_CC_MACHINE=$(${HOST_CC} -dumpmachine)
|
||||
[ $? -ne 0 ] &&
|
||||
die "Could not run '${HOST_CC} -dumpmachine', is your compiler working?"
|
||||
echo "${prog_NAME}: Using ${HOST_CC} for host compiler (${HOST_CC_MACHINE})"
|
||||
|
||||
case ${HOST_CC_MACHINE} in
|
||||
x86_64-*linux*)
|
||||
CONFIG_HOST_ARCH=x86_64 CONFIG_HOST=Linux
|
||||
;;
|
||||
aarch64-*linux*)
|
||||
CONFIG_HOST_ARCH=aarch64 CONFIG_HOST=Linux
|
||||
;;
|
||||
powerpc64le-*linux*|ppc64le-*linux*)
|
||||
CONFIG_HOST_ARCH=ppc64le CONFIG_HOST=Linux
|
||||
;;
|
||||
x86_64-*freebsd*)
|
||||
CONFIG_HOST_ARCH=x86_64 CONFIG_HOST=FreeBSD
|
||||
;;
|
||||
amd64-*openbsd*)
|
||||
CONFIG_HOST_ARCH=x86_64 CONFIG_HOST=OpenBSD
|
||||
;;
|
||||
*)
|
||||
die "Unsupported host toolchain: ${HOST_CC_MACHINE}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# If no toolchain was requested, stop here.
|
||||
# XXX De-duplicate the generation of Makeconf*?
|
||||
if [ -n "${OPT_DISABLE_TOOLCHAIN}" ]; then
|
||||
cat <<EOM >Makeconf
|
||||
# Generated by configure.sh
|
||||
CONFIG_PREFIX=${OPT_PREFIX}
|
||||
CONFIG_HOST_ARCH=${CONFIG_HOST_ARCH}
|
||||
CONFIG_HOST=${CONFIG_HOST}
|
||||
CONFIG_HOST_CC=${HOST_CC}
|
||||
EOM
|
||||
sed -Ee 's/^([A-Z_]+)=(.*)$/\1="\2"/' Makeconf >Makeconf.sh
|
||||
cleanup
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# Configure target toolchain and bindings based on TARGET_{CC,LD,OBJCOPY}.
|
||||
#
|
||||
TARGET_CC="${TARGET_CC:-cc}"
|
||||
|
||||
echo -n "${prog_NAME}: Checking that ${TARGET_CC} works: "
|
||||
cat >conftmp.c <<EOM
|
||||
int foo(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
EOM
|
||||
if ! ${TARGET_CC} -c conftmp.c -o conftmp.o >/dev/null 2>&1; then
|
||||
echo "no"
|
||||
die "Could not find a working compiler for target toolchain"
|
||||
else
|
||||
echo "yes"
|
||||
fi
|
||||
TARGET_CC_MACHINE=$(${TARGET_CC} -dumpmachine)
|
||||
|
||||
CONFIG_HVT= CONFIG_SPT= CONFIG_VIRTIO= CONFIG_MUEN= CONFIG_XEN=
|
||||
case ${TARGET_CC_MACHINE} in
|
||||
x86_64-*|amd64-*)
|
||||
TARGET_ARCH=x86_64
|
||||
TARGET_LD_MAX_PAGE_SIZE=0x1000
|
||||
;;
|
||||
aarch64-*)
|
||||
TARGET_ARCH=aarch64
|
||||
TARGET_LD_MAX_PAGE_SIZE=0x1000
|
||||
;;
|
||||
powerpc64le-*|ppc64le-*)
|
||||
TARGET_ARCH=ppc64le
|
||||
TARGET_LD_MAX_PAGE_SIZE=0x10000
|
||||
;;
|
||||
*)
|
||||
die "Unsupported target toolchain: ${TARGET_CC_MACHINE}"
|
||||
;;
|
||||
esac
|
||||
|
||||
TARGET_CC_CFLAGS=
|
||||
TARGET_CC_IS_OPENBSD=
|
||||
if CC="${TARGET_CC}" cc_is_clang; then
|
||||
TARGET_CC_CFLAGS=-nostdlibinc
|
||||
# XXX Clang warns for no good reason if -nostdlibinc is used and no
|
||||
# compliation is performed. We could work around this by using --config
|
||||
# which "claims" all command line arguments as "used", but this is easier
|
||||
# for now.
|
||||
TARGET_CC_CFLAGS="${TARGET_CC_CFLAGS} -Wno-unused-command-line-argument"
|
||||
else
|
||||
TARGET_CC_CFLAGS=-nostdinc
|
||||
fi
|
||||
case ${TARGET_CC_MACHINE} in
|
||||
x86_64-*linux*|powerpc64le-*linux*|ppc64le-*linux*)
|
||||
# On x86_64 and PPC we need to ensure that TLS is not used for the
|
||||
# stack protector:
|
||||
# [GCC] -mstack-protector-guard=global is available from GCC 4.9.0.
|
||||
# [Clang] -mstack-protector-guard=global was introduced in
|
||||
# https://reviews.llvm.org/D88631 (release/12.x).
|
||||
CC="${TARGET_CC}" cc_check_option -mstack-protector-guard=global || \
|
||||
die "${TARGET_CC} does not support -mstack-protector-guard="
|
||||
TARGET_CC_CFLAGS="${TARGET_CC_CFLAGS} -mstack-protector-guard=global"
|
||||
;;
|
||||
*openbsd*)
|
||||
# [Clang] OpenBSD's Clang needs to be told to switch off mitigations.
|
||||
TARGET_CC_CFLAGS="${TARGET_CC_CFLAGS} -mno-retpoline -fno-ret-protector"
|
||||
# [Clang] OpenBSD's LLVM/Clang uses a global stack protector guard, but
|
||||
# different symbols; see bindings/GNUmakefile.
|
||||
TARGET_CC_IS_OPENBSD=1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "${prog_NAME}:" \
|
||||
"Using ${TARGET_CC} for target compiler (${TARGET_CC_MACHINE})"
|
||||
|
||||
# TARGET_CC_LDFLAGS are used by "cc as linker"; TARGET_LD_LDFLAGS are used by
|
||||
# the plain "ld" wrapper.
|
||||
# TODO: Are there Linux distributions with toolchains configured to force PIE
|
||||
# even if -static is used? If yes, these will need treatment similar to OpenBSD
|
||||
# below, and/or disabling PIE in "cc".
|
||||
TARGET_CC_LDFLAGS=
|
||||
TARGET_LD_LDFLAGS=
|
||||
case ${CONFIG_HOST} in
|
||||
Linux)
|
||||
# The "--build-id=none" nonsense is needed for "cc as a linker" to suppress any
|
||||
# generation of a .note.gnu.build-id, since our linker scripts don't
|
||||
# support it and Linux "cc" toolchains insist on adding it by default
|
||||
# which leads to linkers warning if it is enabled but the input section
|
||||
# is subsequently discarded.
|
||||
TARGET_LD="${TARGET_LD:-ld}"
|
||||
TARGET_OBJCOPY="${TARGET_OBJCOPY:-objcopy}"
|
||||
TARGET_CC_LDFLAGS="-Wl,--build-id=none"
|
||||
;;
|
||||
FreeBSD)
|
||||
TARGET_LD="${TARGET_LD:-ld.lld}"
|
||||
TARGET_OBJCOPY="${TARGET_OBJCOPY:-objcopy}"
|
||||
# FreeBSD's GNU ld is old and broken, refuse to use it.
|
||||
if ! LD="${TARGET_LD}" ld_is_lld; then
|
||||
err "${TARGET_LD} is not LLVM LLD"
|
||||
die "Using GNU LD is not supported on FreeBSD"
|
||||
fi
|
||||
;;
|
||||
OpenBSD)
|
||||
TARGET_LD="${TARGET_LD:-ld.lld}"
|
||||
TARGET_OBJCOPY="${TARGET_OBJCOPY:-objcopy}"
|
||||
# OpenBSD's GNU ld is old and broken, refuse to use it.
|
||||
if ! LD="${TARGET_LD}" ld_is_lld; then
|
||||
err "${TARGET_LD} is not LLVM LLD"
|
||||
die "Using GNU LD is not supported on OpenBSD"
|
||||
fi
|
||||
# [LLD] OpenBSD's LLD needs to be explicitly told not to produce PIE
|
||||
# executables.
|
||||
TARGET_CC_LDFLAGS="-Wl,-nopie"
|
||||
TARGET_LD_LDFLAGS="-nopie"
|
||||
;;
|
||||
*)
|
||||
die "Unsupported host system: ${CONFIG_HOST}"
|
||||
;;
|
||||
esac
|
||||
# [Clang] Force Clang to use the right TARGET_LD when run as "cc as linker".
|
||||
# -fuse-ld= is braindead and accepts either a "flavour" (e.g. "lld") or an
|
||||
# absolute path; we try with the latter.
|
||||
# TODO XXX: This is fragile, but works for the default cases for now.
|
||||
# TODO document: This won't work with clang "bare metal" targets.
|
||||
if CC="${TARGET_CC}" cc_is_clang; then
|
||||
REAL_TARGET_LD="$(command -v ${TARGET_LD})"
|
||||
[ ! -x "${REAL_TARGET_LD}" ] && \
|
||||
die "Cannot determine absolute path for ${TARGET_LD}"
|
||||
TARGET_CC_LDFLAGS="${TARGET_CC_LDFLAGS} -fuse-ld=${REAL_TARGET_LD}"
|
||||
fi
|
||||
if ! CC="${TARGET_CC}" LD="${TARGET_LD}" check_ld; then
|
||||
die "Could not find a working target linker"
|
||||
fi
|
||||
if ! CC="${TARGET_CC}" OBJCOPY="${TARGET_OBJCOPY}" check_objcopy; then
|
||||
die "Could not find a working target objcopy"
|
||||
fi
|
||||
|
||||
echo "${prog_NAME}: Using ${TARGET_LD} for target linker"
|
||||
echo "${prog_NAME}: Using ${TARGET_OBJCOPY} for target objcopy"
|
||||
|
||||
TARGET_TRIPLE="${TARGET_ARCH}-gilbraltar-none-static"
|
||||
echo "${prog_NAME}: Target toolchain triple is ${TARGET_TRIPLE}"
|
||||
|
||||
#
|
||||
# Generate Makeconf, to be included by Makefiles.
|
||||
#
|
||||
cat <<EOM >Makeconf
|
||||
# Generated by configure.sh
|
||||
CONFIG_PREFIX=${OPT_PREFIX}
|
||||
CONFIG_HOST_ARCH=${CONFIG_HOST_ARCH}
|
||||
CONFIG_HOST=${CONFIG_HOST}
|
||||
CONFIG_HOST_CC=${HOST_CC}
|
||||
CONFIG_TARGET_ARCH=${TARGET_ARCH}
|
||||
CONFIG_TARGET_TRIPLE=${TARGET_TRIPLE}
|
||||
CONFIG_TARGET_CC=${TARGET_CC}
|
||||
CONFIG_TARGET_CC_CFLAGS=${TARGET_CC_CFLAGS}
|
||||
CONFIG_TARGET_CC_LDFLAGS=${TARGET_CC_LDFLAGS}
|
||||
CONFIG_TARGET_CC_IS_OPENBSD=${TARGET_CC_IS_OPENBSD}
|
||||
CONFIG_TARGET_LD=${TARGET_LD}
|
||||
CONFIG_TARGET_LD_LDFLAGS=${TARGET_LD_LDFLAGS}
|
||||
CONFIG_TARGET_LD_MAX_PAGE_SIZE=${TARGET_LD_MAX_PAGE_SIZE}
|
||||
CONFIG_TARGET_OBJCOPY=${TARGET_OBJCOPY}
|
||||
EOM
|
||||
|
||||
#
|
||||
# Generate Makeconf.sh, to be included by shell scripts.
|
||||
#
|
||||
sed -Ee 's/^([A-Z_]+)=(.*)$/\1="\2"/' Makeconf >Makeconf.sh
|
||||
|
||||
cleanup
|
44
crt.c
Normal file
44
crt.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2019 Contributors as noted in the AUTHORS file
|
||||
*
|
||||
* This file is part of Gilbraltar, a bare-metal OS for RPi4.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software
|
||||
* for any purpose with or without fee is hereby granted, provided
|
||||
* that the above copyright notice and this permission notice appear
|
||||
* in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* The stack canary value will be initialised to a pseudo-random value by
|
||||
* crt_init_early(), keep an easily recognisable "terminator" value here to
|
||||
* flag if that did not happen as expected.
|
||||
*/
|
||||
uintptr_t SSP_GUARD_SYMBOL = 0x00deadbeef0d0a00;
|
||||
|
||||
/*
|
||||
* Called by compiler-generated code when corruption of the canary value is
|
||||
* detected. There is very little we can do here safely, so just print a
|
||||
* message and abort, taking care to make minimal use of the stack.
|
||||
*/
|
||||
static const char stack_chk_fail_message[] =
|
||||
"ABORT: Stack corruption detected\n";
|
||||
|
||||
extern void uart_puts(const char *str);
|
||||
|
||||
__attribute__((noreturn)) void SSP_FAIL_SYMBOL(void) {
|
||||
for (;;)
|
||||
;
|
||||
}
|
58
doc.txt
Normal file
58
doc.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
# How to make a simple unikernel on RBPi
|
||||
|
||||
File required on Raspberry Pi 5:
|
||||
- bcm2712-rpi-5-b.dtb
|
||||
- overlays/bcm2712d0.dtdo
|
||||
- config.txt
|
||||
|
||||
CPU used by Raspberry Pi 5: Cortex-A76
|
||||
BCM2712 is the Broadcom chip used by Raspberry Pi 5
|
||||
|
||||
# Memory layout
|
||||
|
||||
| Base | Size | Contents | Remarks |
|
||||
|------------|----------------------|----------------------------|---------|
|
||||
| 00000000 | 32 KByte | ARM Trusted Firmware | BL31 |
|
||||
| 0006F000 | 4 KByte | EL3 Stack |
|
||||
| 00070000 | 2 KByte | Exception vector table EL3 |
|
||||
| ...
|
||||
| 00080000 | max. 6 MByte | Kernel image |
|
||||
| | .init | startup code |
|
||||
| | .text | |
|
||||
| | .rodata | |
|
||||
| | .data | |
|
||||
| | .bss | |
|
||||
| ...
|
||||
| | Kernel stacks | |
|
||||
| 00280000 | 128 KByte | for Core 0 |
|
||||
| 002A0000 | 128 KByte | for Core 1 |
|
||||
| 002C0000 | 128 KByte | for Core 2 |
|
||||
| 002E0000 | 128 KByte | for Core 3 |
|
||||
| 00300000 | | End of stacks |
|
||||
| | Exception stacks | |
|
||||
| 00300000 | 32 KByte | for Core 0 |
|
||||
| 00308000 | 32 KByte | for Core 1 |
|
||||
| 00310000 | 32 KByte | for Core 2 |
|
||||
| 00318000 | 32 KByte | for Core 3 |
|
||||
| 00320000 | | End of exception stacks |
|
||||
| | IRQ stack | |
|
||||
| 00320000 | 32 KByte | for Core 0 |
|
||||
| 00328000 | 32 KByte | for Core 1 |
|
||||
| 00330000 | 32 KByte | for Core 2 |
|
||||
| 00338000 | 32 KByte | for Core 3 |
|
||||
| 00340000 | | End of IRQ stacks |
|
||||
| | FIQ stack | |
|
||||
| 00340000 | 32 KByte | for Core 0 |
|
||||
| 00348000 | 32 KByte | for Core 1 |
|
||||
| 00350000 | 32 KByte | for Core 2 |
|
||||
| 00358000 | 32 KByte | for Core 3 |
|
||||
| 00360000 | | End of FIQ stacks |
|
||||
| | Page Table | |
|
||||
| 00360000 | 16 KByte | |
|
||||
| 00364000 | | End of page table |
|
||||
| 00500000 | 4 MByte | Coherent region |
|
||||
| 00900000 | | |
|
||||
| 40000000 | | Heap |
|
||||
| ...
|
||||
| 1FFFFFFFF | 8192 MB | Heap |
|
||||
| 1000000000 | 16 MByte | AXI peripherals |
|
6
exception_handler.c
Normal file
6
exception_handler.c
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <exception_handler.h>
|
||||
|
||||
void gilbraltar_exception_handler(uint64_t exn, struct frame *frame) {
|
||||
while (1)
|
||||
__asm__ __volatile("wfi");
|
||||
}
|
298
exception_stub.S
Normal file
298
exception_stub.S
Normal file
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* exceptionstub.S
|
||||
*
|
||||
* Copyright (C) 2014-2020 R. Stange <rsta2@o2online.de>
|
||||
* Copyright (C) 2024 Romain Calascibetta <romain.calascibetta@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "exception_stub.h"
|
||||
#include "bcm.h"
|
||||
|
||||
.macro vector handler
|
||||
.align 7
|
||||
b \handler
|
||||
.endm
|
||||
|
||||
.macro stub name, exception
|
||||
.globl \name
|
||||
\name:
|
||||
mrs x0, esr_el1
|
||||
mrs x1, spsr_el1
|
||||
mov x2, x30 // lr
|
||||
mrs x3, elr_el1
|
||||
mrs x4, sp_el0
|
||||
mov x5, sp
|
||||
mrs x6, far_el1
|
||||
|
||||
str x6, [sp, #-16]!
|
||||
stp x4, x5, [sp, #-16]!
|
||||
stp x2, x3, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
mov x0, #\exception
|
||||
mov x1, sp
|
||||
b gilbraltar_exception_handler // never returns
|
||||
.endm
|
||||
|
||||
.text
|
||||
.align 11
|
||||
.globl VectorTable
|
||||
VectorTable:
|
||||
// from current EL with sp_el0
|
||||
vector synchronous_stub
|
||||
vector IRQ_stub
|
||||
vector FIQ_stub
|
||||
vector system_error_stub
|
||||
|
||||
// from current EL with sp_elx, x != 0
|
||||
vector synchronous_stub
|
||||
vector IRQ_stub
|
||||
vector FIQ_stub
|
||||
vector system_error_stub
|
||||
|
||||
// from lower EL, target EL minus 1 is AArch64
|
||||
vector HVC_stub
|
||||
vector unexpected_stub
|
||||
vector unexpected_stub
|
||||
vector unexpected_stub
|
||||
|
||||
// from lower EL, target EL minus 1 is AArch32
|
||||
vector unexpected_stub
|
||||
vector unexpected_stub
|
||||
vector unexpected_stub
|
||||
vector unexpected_stub
|
||||
|
||||
// Abort stubs
|
||||
stub unexpected_stub, EXCEPTION_UNEXPECTED
|
||||
stub synchronous_stub, EXCEPTION_SYNCHRONOUS
|
||||
stub system_error_stub,EXCEPTION_SYSTEM_ERROR
|
||||
|
||||
// IRQ stub
|
||||
.globl IRQ_stub
|
||||
IRQ_stub:
|
||||
stp x29, x30, [sp, #-16]! // save x29, x30 onto stack
|
||||
|
||||
mrs x29, elr_el1 // save elr_el1, spsr_el1 onto stack
|
||||
mrs x30, spsr_el1
|
||||
stp x29, x30, [sp, #-16]!
|
||||
msr DAIFClr, #1 // enable FIQ
|
||||
|
||||
#ifdef SAVE_VFP_REGS_ON_IRQ
|
||||
stp q30, q31, [sp, #-32]! // save q0-q31 onto stack
|
||||
stp q28, q29, [sp, #-32]!
|
||||
stp q26, q27, [sp, #-32]!
|
||||
stp q24, q25, [sp, #-32]!
|
||||
stp q22, q23, [sp, #-32]!
|
||||
stp q20, q21, [sp, #-32]!
|
||||
stp q18, q19, [sp, #-32]!
|
||||
stp q16, q17, [sp, #-32]!
|
||||
stp q14, q15, [sp, #-32]!
|
||||
stp q12, q13, [sp, #-32]!
|
||||
stp q10, q11, [sp, #-32]!
|
||||
stp q8, q9, [sp, #-32]!
|
||||
stp q6, q7, [sp, #-32]!
|
||||
stp q4, q5, [sp, #-32]!
|
||||
stp q2, q3, [sp, #-32]!
|
||||
stp q0, q1, [sp, #-32]!
|
||||
#endif
|
||||
stp x27, x28, [sp, #-16]! // save x0-x28 onto stack
|
||||
stp x25, x26, [sp, #-16]!
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x19, x20, [sp, #-16]!
|
||||
stp x17, x18, [sp, #-16]!
|
||||
stp x15, x16, [sp, #-16]!
|
||||
stp x13, x14, [sp, #-16]!
|
||||
stp x11, x12, [sp, #-16]!
|
||||
stp x9, x10, [sp, #-16]!
|
||||
stp x7, x8, [sp, #-16]!
|
||||
stp x5, x6, [sp, #-16]!
|
||||
stp x3, x4, [sp, #-16]!
|
||||
stp x1, x2, [sp, #-16]!
|
||||
str x0, [sp, #-16]!
|
||||
|
||||
ldr x0, =IRQ_return_address // store return address for profiling
|
||||
str x29, [x0]
|
||||
|
||||
bl gilbraltar_interrupt_handler
|
||||
|
||||
ldr x0, [sp], #16 // restore x0-x28 from stack
|
||||
ldp x1, x2, [sp], #16
|
||||
ldp x3, x4, [sp], #16
|
||||
ldp x5, x6, [sp], #16
|
||||
ldp x7, x8, [sp], #16
|
||||
ldp x9, x10, [sp], #16
|
||||
ldp x11, x12, [sp], #16
|
||||
ldp x13, x14, [sp], #16
|
||||
ldp x15, x16, [sp], #16
|
||||
ldp x17, x18, [sp], #16
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x27, x28, [sp], #16
|
||||
#ifdef SAVE_VFP_REGS_ON_IRQ
|
||||
ldp q0, q1, [sp], #32 // restore q0-q31 from stack
|
||||
ldp q2, q3, [sp], #32
|
||||
ldp q4, q5, [sp], #32
|
||||
ldp q6, q7, [sp], #32
|
||||
ldp q8, q9, [sp], #32
|
||||
ldp q10, q11, [sp], #32
|
||||
ldp q12, q13, [sp], #32
|
||||
ldp q14, q15, [sp], #32
|
||||
ldp q16, q17, [sp], #32
|
||||
ldp q18, q19, [sp], #32
|
||||
ldp q20, q21, [sp], #32
|
||||
ldp q22, q23, [sp], #32
|
||||
ldp q24, q25, [sp], #32
|
||||
ldp q26, q27, [sp], #32
|
||||
ldp q28, q29, [sp], #32
|
||||
ldp q30, q31, [sp], #32
|
||||
#endif
|
||||
|
||||
msr DAIFSet, #1 // disable FIQ
|
||||
ldp x29, x30, [sp], #16 // restore elr_el1, spsr_el1 from stack
|
||||
msr elr_el1, x29
|
||||
msr spsr_el1, x30
|
||||
|
||||
ldp x29, x30, [sp], #16 // restore x29, x30 from stack
|
||||
|
||||
eret
|
||||
|
||||
// FIQ stub
|
||||
.globl FIQ_stub
|
||||
FIQ_stub:
|
||||
#ifdef SAVE_VFP_REGS_ON_FIQ
|
||||
stp q30, q31, [sp, #-32]!
|
||||
stp q28, q29, [sp, #-32]!
|
||||
stp q26, q27, [sp, #-32]!
|
||||
stp q24, q25, [sp, #-32]!
|
||||
stp q22, q23, [sp, #-32]!
|
||||
stp q20, q21, [sp, #-32]!
|
||||
stp q18, q19, [sp, #-32]!
|
||||
stp q16, q17, [sp, #-32]!
|
||||
stp q14, q15, [sp, #-32]!
|
||||
stp q12, q13, [sp, #-32]!
|
||||
stp q10, q11, [sp, #-32]!
|
||||
stp q8, q9, [sp, #-32]!
|
||||
stp q6, q7, [sp, #-32]!
|
||||
stp q4, q5, [sp, #-32]!
|
||||
stp q2, q3, [sp, #-32]!
|
||||
stp q0, q1, [sp, #-32]!
|
||||
#endif
|
||||
stp x29, x30, [sp, #-16]!
|
||||
stp x27, x28, [sp, #-16]!
|
||||
stp x25, x26, [sp, #-16]!
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x19, x20, [sp, #-16]!
|
||||
stp x17, x18, [sp, #-16]!
|
||||
stp x15, x16, [sp, #-16]!
|
||||
stp x13, x14, [sp, #-16]!
|
||||
stp x11, x12, [sp, #-16]!
|
||||
stp x9, x10, [sp, #-16]!
|
||||
stp x7, x8, [sp, #-16]!
|
||||
stp x5, x6, [sp, #-16]!
|
||||
stp x3, x4, [sp, #-16]!
|
||||
stp x1, x2, [sp, #-16]!
|
||||
str x0, [sp, #-16]!
|
||||
|
||||
ldr x2, =FIQ_data
|
||||
ldr x1, [x2] // get FIQ_data.pHandler
|
||||
cmp x1, #0 // is handler set?
|
||||
b.eq 2f
|
||||
ldr x0, [x2, #8] // get FIQ_data.pParam
|
||||
blr x1 // call handler
|
||||
|
||||
1:
|
||||
ldr x0, [sp], #16
|
||||
ldp x1, x2, [sp], #16
|
||||
ldp x3, x4, [sp], #16
|
||||
ldp x5, x6, [sp], #16
|
||||
ldp x7, x8, [sp], #16
|
||||
ldp x9, x10, [sp], #16
|
||||
ldp x11, x12, [sp], #16
|
||||
ldp x13, x14, [sp], #16
|
||||
ldp x15, x16, [sp], #16
|
||||
ldp x17, x18, [sp], #16
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x27, x28, [sp], #16
|
||||
ldp x29, x30, [sp], #16
|
||||
#ifdef SAVE_VFP_REGS_ON_FIQ
|
||||
ldp q0, q1, [sp], #32
|
||||
ldp q2, q3, [sp], #32
|
||||
ldp q4, q5, [sp], #32
|
||||
ldp q6, q7, [sp], #32
|
||||
ldp q8, q9, [sp], #32
|
||||
ldp q10, q11, [sp], #32
|
||||
ldp q12, q13, [sp], #32
|
||||
ldp q14, q15, [sp], #32
|
||||
ldp q16, q17, [sp], #32
|
||||
ldp q18, q19, [sp], #32
|
||||
ldp q20, q21, [sp], #32
|
||||
ldp q22, q23, [sp], #32
|
||||
ldp q24, q25, [sp], #32
|
||||
ldp q26, q27, [sp], #32
|
||||
ldp q28, q29, [sp], #32
|
||||
ldp q30, q31, [sp], #32
|
||||
#endif
|
||||
|
||||
eret
|
||||
|
||||
2:
|
||||
ldr x1, =ARM_IC_FIQ_CONTROL // disable FIQ (if handler is not set)
|
||||
mov w0, #0
|
||||
str w0, [x1]
|
||||
b 1b
|
||||
|
||||
// SMC stub
|
||||
.globl SMC_stub
|
||||
SMC_stub:
|
||||
ldr x2, =SMC_stack
|
||||
mov sp, x2
|
||||
str x30, [sp, #-16]!
|
||||
bl gilbraltar_secure_monitor_handler
|
||||
ldr x30, [sp], #16
|
||||
eret
|
||||
|
||||
// HVC stub
|
||||
HVC_stub: // return to EL2h mode
|
||||
mrs x0, spsr_el2
|
||||
bic x0, x0, #0xF
|
||||
mov x1, #9
|
||||
orr x0, x0, x1
|
||||
msr spsr_el2, x0
|
||||
eret
|
||||
|
||||
.data
|
||||
.align 3
|
||||
.globl FIQ_data
|
||||
FIQ_data:
|
||||
.quad 0 // handler
|
||||
.quad 0 // param
|
||||
.word 0 // FIQ_number (unused)
|
||||
|
||||
.align 3
|
||||
.globl IRQ_return_address
|
||||
IRQ_return_address:
|
||||
.quad 0
|
||||
|
||||
.bss
|
||||
.align 4
|
||||
.space 128
|
||||
SMC_stack:
|
104
gen-headers.sh
Executable file
104
gen-headers.sh
Executable file
|
@ -0,0 +1,104 @@
|
|||
#!/bin/sh
|
||||
# Copyright (c) 2015-2021 Contributors as noted in the AUTHORS file
|
||||
#
|
||||
# This file is part of Gilbraltar, a bare-metal OS for RPi4.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# gen-headers.sh: Appropriate internal "C runtime" header files needed for the
|
||||
# target toolchain from the origin compiler.
|
||||
|
||||
prog_NAME="$(basename $0)"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
rm -f conftmp.c conftmp.d conftmp*.o
|
||||
}
|
||||
|
||||
die()
|
||||
{
|
||||
echo "${prog_NAME}: ERROR: $@" 1>&2
|
||||
cleanup
|
||||
exit 1
|
||||
}
|
||||
|
||||
cc_is_clang()
|
||||
{
|
||||
${CC} -dM -E - </dev/null | grep -Eq '^#define __clang__ 1$'
|
||||
}
|
||||
|
||||
# Arguments: PATH, FILES...
|
||||
# For the header FILES..., all of which must be relative to PATH, resolve their
|
||||
# dependencies using the C preprocessor and output a list of FILES... plus all
|
||||
# their unique dependencies, also relative to PATH.
|
||||
cc_get_header_deps()
|
||||
{
|
||||
temp="$PWD/conftmp.d"
|
||||
local path="$1"
|
||||
shift
|
||||
(
|
||||
cd ${path} || return 1
|
||||
${CC} -M "$@" >${temp} || return 1
|
||||
sed -e 's!.*\.o:!!g' -e "s!${path}/!!g" ${temp} \
|
||||
| tr ' \\' '\n' \
|
||||
| sort \
|
||||
| uniq
|
||||
rm ${temp}
|
||||
)
|
||||
}
|
||||
|
||||
[ "$#" -ne 1 ] && die "Missing DESTDIR"
|
||||
DESTDIR=$1
|
||||
. ./Makeconf.sh || die "Can't find . ./Makeconf.sh"
|
||||
|
||||
mkdir -p ${DESTDIR} || die "mkdir failed"
|
||||
|
||||
if CC=${CONFIG_TARGET_CC} cc_is_clang; then
|
||||
case ${CONFIG_HOST} in
|
||||
# The BSDs don't ship some standard headers that we need in Clang's
|
||||
# resource directory. Appropriate these from the host system.
|
||||
FreeBSD|OpenBSD)
|
||||
SRCDIR=/usr/include
|
||||
SRCS="float.h stddef.h stdint.h stdbool.h stdarg.h"
|
||||
DEPS="$(mktemp)"
|
||||
CC=${CONFIG_TARGET_CC} cc_get_header_deps ${SRCDIR} ${SRCS} \
|
||||
>${DEPS} || \
|
||||
die "Failure getting dependencies of host headers"
|
||||
# cpio will fail if CRT_INCDIR is below a symlink, so squash that
|
||||
DESTDIR="$(readlink -f ${DESTDIR})"
|
||||
Q=
|
||||
[ "${CONFIG_HOST}" = "FreeBSD" ] && Q="--quiet"
|
||||
(cd ${SRCDIR} && cpio ${Q} -Lpdm ${DESTDIR} <${DEPS}) || \
|
||||
die "Failure copying host headers"
|
||||
rm ${DEPS}
|
||||
;;
|
||||
# Other known Clang toolchains don't require anything special here as
|
||||
# -nostdlibinc will pick up all we need from the compiler's resource
|
||||
# directory.
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
else
|
||||
# For GCC there isn't an equivalent of -nostdlibinc, so we need to
|
||||
# appropriate all of its internal headers.
|
||||
SRCDIR="$(${CONFIG_TARGET_CC} -print-file-name=include)"
|
||||
[ -d "${SRCDIR}" ] || die "Cannot determine gcc include directory"
|
||||
cp -R "${SRCDIR}/." ${DESTDIR} || \
|
||||
die "Failure copying host headers"
|
||||
fi
|
||||
|
||||
echo "uint64_t tscclock_monotonic(void);" > ${DESTDIR}/rpi4.h
|
||||
|
||||
cleanup
|
52
gilbraltar.ld
Normal file
52
gilbraltar.ld
Normal file
|
@ -0,0 +1,52 @@
|
|||
ENTRY(_start)
|
||||
|
||||
PHDRS {
|
||||
tdata PT_LOAD FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.init : {
|
||||
*(.init)
|
||||
}
|
||||
|
||||
.text : {
|
||||
*(.text*)
|
||||
_etext = .;
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
|
||||
.ARM.exidx : {
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
__exidx_end = .;
|
||||
}
|
||||
|
||||
.eh_frame : {
|
||||
*(.eh_frame*)
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
.tdata : {
|
||||
_stdata = .;
|
||||
*(.tdata)
|
||||
} :tdata
|
||||
_edata = .;
|
||||
|
||||
.tbss : {
|
||||
*(.tbss)
|
||||
} : tbss
|
||||
|
||||
.bss : {
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
_end = .;
|
||||
}
|
||||
}
|
23
include/bcm.h
Normal file
23
include/bcm.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef __GILBRALTAR_BCM__
|
||||
#define __GILBRALTAR_BCM__
|
||||
|
||||
#define ARM_IO_BASE 0x107c000000UL
|
||||
|
||||
// System timers
|
||||
#define ARM_SYSTIMER_BASE (ARM_IO_BASE + 0x3000)
|
||||
#define ARM_SYSTIMER_CS (ARM_SYSTIMER_BASE + 0x00)
|
||||
#define ARM_SYSTIMER_CLO (ARM_SYSTIMER_BASE + 0x04)
|
||||
#define ARM_SYSTIMER_CHI (ARM_SYSTIMER_BASE + 0x08)
|
||||
|
||||
// Interrupt Controller
|
||||
#define ARM_IC_BASE (ARM_IO_BASE + 0xb000)
|
||||
|
||||
#define ARM_IC_FIQ_CONTROL (ARM_IO_BASE + 0x20c)
|
||||
|
||||
// General Purpose I/O #2
|
||||
#define ARM_GPIO2_BASE (ARM_IO_BASE + 0x1517c00)
|
||||
|
||||
#define ARM_GPIO2_DATA0 (ARM_GPIO2_BASE + 0x04)
|
||||
#define ARM_GPIO2_IODIR0 (ARM_GPIO2_BASE + 0x08)
|
||||
|
||||
#endif
|
6
include/clock.h
Normal file
6
include/clock.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef __GILBRALTAR_CLOCK__
|
||||
#define __GILBRALTAR_CLOCK__
|
||||
|
||||
uint32_t gilbraltar_get_clock(uint32_t);
|
||||
|
||||
#endif
|
32
include/exception_handler.h
Normal file
32
include/exception_handler.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef __GILBRALTAR_EXCEPTION_HANDLER__
|
||||
#define __GILBRALTAR_EXCEPTION_HANDLER__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct frame {
|
||||
uint32_t sp_irq;
|
||||
uint32_t lr_irq;
|
||||
uint32_t sp_fiq;
|
||||
uint32_t lr_fiq;
|
||||
uint32_t r0;
|
||||
uint32_t r1;
|
||||
uint32_t r2;
|
||||
uint32_t r3;
|
||||
uint32_t r4;
|
||||
uint32_t r5;
|
||||
uint32_t r6;
|
||||
uint32_t r7;
|
||||
uint32_t r8;
|
||||
uint32_t r9;
|
||||
uint32_t r10;
|
||||
uint32_t r11;
|
||||
uint32_t r12;
|
||||
uint32_t sp;
|
||||
uint32_t lr;
|
||||
uint32_t spsr;
|
||||
uint32_t pc;
|
||||
};
|
||||
|
||||
void gilbraltar_exception_handler(uint64_t, struct frame *);
|
||||
|
||||
#endif
|
8
include/exception_stub.h
Normal file
8
include/exception_stub.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef __GILBRALTAR_EXCEPTION_STUB__
|
||||
#define __GILBRALTAR_EXCEPTION_STUB__
|
||||
|
||||
#define EXCEPTION_UNEXPECTED 0
|
||||
#define EXCEPTION_SYNCHRONOUS 1
|
||||
#define EXCEPTION_SYSTEM_ERROR 2
|
||||
|
||||
#endif
|
6
include/gpio.h
Normal file
6
include/gpio.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef __GILBRALTAR_GPIO__
|
||||
#define __GILBRALTAR_GPIO__
|
||||
|
||||
#include <bcm.h>
|
||||
|
||||
#endif
|
8
include/led.h
Normal file
8
include/led.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef __GILBRALTAR_LED__
|
||||
#define __GILBRALTAR_LED__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void gilbraltar_led(bool);
|
||||
|
||||
#endif
|
19
include/log.h
Normal file
19
include/log.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef __GILBRALTAR_LOG__
|
||||
#define __GILBRALTAR_LOG__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum log_level {
|
||||
ERROR= 0,
|
||||
WARN,
|
||||
INFO,
|
||||
DEBUG
|
||||
};
|
||||
|
||||
size_t gilbraltar_log(enum log_level, const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
void gilbraltar_log_set(enum log_level);
|
||||
|
||||
#endif
|
21
include/mbox.h
Normal file
21
include/mbox.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef __GILBRALTAR_MBOX__
|
||||
#define __GILBRALTAR_MBOX__
|
||||
|
||||
#include <bcm.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAILBOX_BASE (ARM_IO_BASE + 0x13880)
|
||||
|
||||
#define MAILBOX0_READ (MAILBOX_BASE + 0x00)
|
||||
#define MAILBOX0_STATUS (MAILBOX_BASE + 0x18)
|
||||
#define MAILBOX1_WRITE (MAILBOX_BASE + 0x20)
|
||||
#define MAILBOX1_STATUS (MAILBOX_BASE + 0x38)
|
||||
|
||||
#define MAILBOX_STATUS_EMPTY 0x40000000
|
||||
#define MAILBOX_STATUS_FULL 0x80000000
|
||||
|
||||
#define BCM_MAILBOX_PROP_OUT 8
|
||||
|
||||
uint32_t gilbraltar_mbox_write_read(uintptr_t data);
|
||||
|
||||
#endif
|
23
include/mem.h
Normal file
23
include/mem.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef __GILBRALTAR_MEM__
|
||||
#define __GILBRALTAR_MEM__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint8_t read8(uintptr_t addr) {
|
||||
return *(uint8_t volatile *)addr;
|
||||
}
|
||||
|
||||
static inline void write8(uintptr_t addr, uint8_t v) {
|
||||
*(uint8_t volatile *)addr = v;
|
||||
}
|
||||
|
||||
static inline uint32_t read32(uintptr_t addr) {
|
||||
return *(uint32_t volatile *)addr;
|
||||
}
|
||||
|
||||
static inline void write32(uintptr_t addr, uint32_t v) {
|
||||
*(uint32_t volatile *)addr = v;
|
||||
}
|
||||
|
||||
#endif
|
57
include/memory_map.h
Normal file
57
include/memory_map.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ifndef __GILBRALTAR_MEMORY_MAP__
|
||||
#define __GILBRALTAR_MEMORY_MAP__
|
||||
|
||||
#ifndef __GILBRALTAR_MEMORY_MAP__
|
||||
#error Do not include memory_map.h file directly!
|
||||
#endif
|
||||
|
||||
#ifndef MEGABYTE
|
||||
#define MEGABYTE 0x100000
|
||||
#endif
|
||||
|
||||
#ifndef GIGABYTE
|
||||
#define GIGABYTE 0x40000000UL
|
||||
#endif
|
||||
|
||||
#define CORES 4 // must be a power of 2
|
||||
#define MEM_SIZE (512 * MEGABYTE) // default size
|
||||
#define GPU_MEM_SIZE (64 * MEGABYTE) // set in config.txt
|
||||
#define ARM_MEM_SIZE (MEM_SIZE - GPU_MEM_SIZE) // normally overwritten
|
||||
#define PAGE_SIZE 0x10000 // page size used by us
|
||||
#define PAGE_SHIFT 16
|
||||
#define PAGE_MASK ~(0xffff)
|
||||
#define EXCEPTION_STACK_SIZE 0x8000
|
||||
#define PAGE_RESERVE (16 * MEGABYTE)
|
||||
|
||||
// Kernel
|
||||
#define MEM_KERNEL_START 0x80000 // main code starts here
|
||||
#define MEM_KERNEL_END (MEM_KERNEL_START + KERNEL_MAX_SIZE)
|
||||
#define MEM_KERNEL_STACK (MEM_KERNEL_END + KERNEL_STACK_SIZE) // expands down
|
||||
|
||||
#define MEM_EXCEPTION_STACK \
|
||||
(MEM_KERNEL_STACK + KERNEL_STACK_SIZE * (CORES - 1) + EXCEPTION_STACK_SIZE)
|
||||
#define MEM_EXCEPTION_STACK_END \
|
||||
(MEM_EXCEPTION_STACK + EXCEPTION_STACK_SIZE * (CORES - 1))
|
||||
|
||||
// Coherent Memory Region (4 MB)
|
||||
#define MEM_COHERENT_REGION \
|
||||
((MEM_EXCEPTION_STACK_END + 2 * MEGABYTE) & ~(MEGABYTE - 1))
|
||||
|
||||
// Heap
|
||||
#define MEM_HEAP_START GIGABYTE
|
||||
#define MEM_HEAP_END (8 * GIGABYTE - 1)
|
||||
|
||||
// IRQ & FIC stacks
|
||||
#define MEM_ABORT_STACK (MEM_KERNEL_STACK + KERNEL_STACK_SIZE * (CORES - 1))
|
||||
#define MEM_IRQ_STACK (MEM_EXCEPTION_STACK_END + EXCEPTION_STACK_SIZE)
|
||||
#define MEM_FIQ_STACK \
|
||||
(MEM_IRQ_STACK + EXCEPTION_STACK_SIZE * (CORES - 1) + EXCEPTION_STACK_SIZE)
|
||||
|
||||
// Page table
|
||||
#define MEM_PAGE_TABLE1 \
|
||||
(MEM_FIQ_STACK + EXCEPTION_STACK_SIZE * (CORES - 1))
|
||||
|
||||
#define PAGE_TABLE1_SIZE 0x4000
|
||||
#define MEM_PAGE_TABLE1_END (MEM_PAGE_TABLE1 + PAGE_TABLE1_SIZE)
|
||||
|
||||
#endif
|
29
include/serial.h
Normal file
29
include/serial.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef __GILBRALTAR_SERIAL__
|
||||
#define __GILBRALTAR_SERIAL__
|
||||
|
||||
#include <bcm.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define ARM_UART0_BASE (ARM_IO_BASE + 0x1001000)
|
||||
|
||||
#define ARM_UART0_DR (ARM_UART0_BASE + 0x00)
|
||||
#define ARM_UART0_FR (ARM_UART0_BASE + 0x18)
|
||||
#define ARM_UART0_IBRD (ARM_UART0_BASE + 0x24)
|
||||
#define ARM_UART0_FBRD (ARM_UART0_BASE + 0x28)
|
||||
#define ARM_UART0_LCRH (ARM_UART0_BASE + 0x2c)
|
||||
#define ARM_UART0_CR (ARM_UART0_BASE + 0x30)
|
||||
#define ARM_UART0_IFLS (ARM_UART0_BASE + 0x34)
|
||||
#define ARM_UART0_IMSC (ARM_UART0_BASE + 0x38)
|
||||
#define ARM_UART0_RIS (ARM_UART0_BASE + 0x3c)
|
||||
#define ARM_UART0_MIS (ARM_UART0_BASE + 0x40)
|
||||
#define ARM_UART0_ICR (ARM_UART0_BASE + 0x44)
|
||||
|
||||
void gilbraltar_serial_init(void);
|
||||
void gilbraltar_serial_send(uint8_t);
|
||||
uint8_t gilbraltar_serial_recv(void);
|
||||
void gilbraltar_serial_puts(const char *);
|
||||
void gilbraltar_serial_putchar(int);
|
||||
void gilbraltar_serial_write(const char *, size_t);
|
||||
|
||||
#endif
|
44
include/sysconfig.h
Normal file
44
include/sysconfig.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef __GILBRALTAR_SYSCONFIG__
|
||||
#define __GILBRALTAR_SYSCONFIG__
|
||||
|
||||
#define MEGABYTE 0x100000
|
||||
|
||||
/* KERNEL_MAX_SIZE is the maximum allowed size of a built kernel image. If your
|
||||
* kernel image contains big data areas it may be required to increase this
|
||||
* value. This value must be a multiple of 16 KByte.
|
||||
*/
|
||||
#ifndef KERNEL_MAX_SIZE
|
||||
#define KERNEL_MAX_SIZE (6 * MEGABYTE)
|
||||
#endif
|
||||
|
||||
/* KERNEL_STACK_SIZE is the size of the stack set on startup for the main
|
||||
* thread. This must be a multiple of 16 KByte.
|
||||
*/
|
||||
#ifndef KERNEL_STACK_SIZE
|
||||
#define KERNEL_STACK_SIZE 0x20000
|
||||
#endif
|
||||
|
||||
#define USE_PHYSICAL_COUNTER
|
||||
#define SERIAL_GPIO_SELECT 14 // and 15
|
||||
|
||||
#if __GNUC__ >= 12
|
||||
// GNU-C 12.x uses floating point registers for optimizations. This may occur
|
||||
// anywhere in the code, even in IRQ and FIQ handlers.
|
||||
|
||||
#ifndef SAVE_VFP_REGS_ON_IRQ
|
||||
#define SAVE_VFP_REGS_ON_IRQ
|
||||
#endif
|
||||
|
||||
#ifndef SAVE_VFP_REGS_ON_FIQ
|
||||
#define SAVE_VFP_REGS_ON_FIQ
|
||||
#endif
|
||||
|
||||
#ifndef __FAST_MATH__
|
||||
#define __FAST_MATH__
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "memory_map.h"
|
||||
|
||||
#endif
|
10
include/tag.h
Normal file
10
include/tag.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef __GILBRALTAR_TAG__
|
||||
#define __GILBRALTAR_TAG__
|
||||
|
||||
#define CODE_REQUEST 0x00000000
|
||||
#define CODE_RESPONSE_SUCCESS 0x80000000
|
||||
#define CODE_RESPONSE_FAILURE 0x80000001
|
||||
|
||||
#define PROPTAG_END 0x00000000
|
||||
|
||||
#endif
|
13
include/timer.h
Normal file
13
include/timer.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef __GILBRALTAR_TIMER__
|
||||
#define __GILBRALTAR_TIMER__
|
||||
|
||||
#include <bcm.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define CLOCKHZ 1000000
|
||||
|
||||
void gilbraltar_delay_hot_loop(uint32_t);
|
||||
void gilbraltar_delay_us(uint32_t);
|
||||
void gilbraltar_delay_ms(uint32_t);
|
||||
|
||||
#endif
|
9
interrupt_handler.c
Normal file
9
interrupt_handler.c
Normal file
|
@ -0,0 +1,9 @@
|
|||
void gilbraltar_interrupt_handler(void) {
|
||||
while (1)
|
||||
__asm__ __volatile("wfi");
|
||||
}
|
||||
|
||||
void gilbraltar_secure_monitor_handler(void) {
|
||||
while (1)
|
||||
__asm__ __volatile("wfi");
|
||||
}
|
3
kernel.c
Normal file
3
kernel.c
Normal file
|
@ -0,0 +1,3 @@
|
|||
extern void main(void);
|
||||
|
||||
void gilbraltar_sysinit(void) { main(); }
|
14
led.c
Normal file
14
led.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <bcm.h>
|
||||
#include <mem.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void gilbraltar_led(bool s) {
|
||||
uint32_t reg = read32(ARM_GPIO2_DATA0);
|
||||
|
||||
if (s)
|
||||
reg |= 0x200; // set bit 9 to 1
|
||||
else
|
||||
reg &= ~0x200; // set bit 9 to 0
|
||||
|
||||
write32(ARM_GPIO2_DATA0, reg);
|
||||
}
|
32
log.c
Normal file
32
log.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include <serial.h>
|
||||
#include <stdio.h>
|
||||
#include <log.h>
|
||||
|
||||
static enum log_level actual_level = INFO;
|
||||
|
||||
size_t gilbraltar_log(enum log_level level, const char *fmt, ...) {
|
||||
if (actual_level < level)
|
||||
return 0;
|
||||
|
||||
va_list args;
|
||||
size_t size;
|
||||
char buffer[320];
|
||||
|
||||
va_start(args, fmt);
|
||||
size = vsnprintf(buffer, sizeof buffer, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (size >= sizeof buffer) {
|
||||
const char trunc[] = "(truncated)\n";
|
||||
gilbraltar_serial_write(buffer, sizeof buffer - 1);
|
||||
gilbraltar_serial_write(trunc, sizeof buffer - 1);
|
||||
return (sizeof buffer - 1);
|
||||
} else {
|
||||
gilbraltar_serial_write(buffer, size);
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
void gilbraltar_log_set(enum log_level level) {
|
||||
actual_level = level;
|
||||
}
|
18
mbox.c
Normal file
18
mbox.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <mem.h>
|
||||
#include <mbox.h>
|
||||
|
||||
uint32_t gilbraltar_mbox_write_read(uintptr_t dma) {
|
||||
dma |= 0xc0000000U;
|
||||
|
||||
while (read32(MAILBOX1_STATUS) & MAILBOX_STATUS_FULL);
|
||||
write32(MAILBOX1_WRITE, BCM_MAILBOX_PROP_OUT | dma);
|
||||
|
||||
uint32_t result;
|
||||
|
||||
do {
|
||||
while (read32(MAILBOX0_STATUS) & MAILBOX_STATUS_EMPTY);
|
||||
result = read32(MAILBOX0_READ);
|
||||
} while ((result & 0xf) != BCM_MAILBOX_PROP_OUT);
|
||||
|
||||
return (result & ~0xf);
|
||||
}
|
58
nolibc/GNUmakefile
Normal file
58
nolibc/GNUmakefile
Normal file
|
@ -0,0 +1,58 @@
|
|||
ifeq ($(FREESTANDING_CFLAGS),)
|
||||
$(error FREESTANDING_CFLAGS not set)
|
||||
endif
|
||||
|
||||
all: libnolibc.a test-headers
|
||||
|
||||
.PHONY: all test-headers clean
|
||||
|
||||
clean:
|
||||
$(RM) libnolibc.a *.o test-include/*.[co] test-include/sys/*.[co]
|
||||
|
||||
CC=cc
|
||||
CFLAGS=-O2 -std=c99 -Wall -Wno-parentheses -Werror
|
||||
CFLAGS+=$(FREESTANDING_CFLAGS)
|
||||
|
||||
OBJS=assert.o \
|
||||
ctype.o \
|
||||
dtoa.o \
|
||||
errlist.o strerror_r.o \
|
||||
memchr.o memcmp.o memcpy.o memmove.o memset.o \
|
||||
strcmp.o strlen.o strnlen.o strtol.o strchr.o strchrnul.o strncpy.o stpncpy.o \
|
||||
strstr.o strncmp.o puts.o \
|
||||
stubs.o \
|
||||
vfprintf.o vsnprintf.o snprintf.o fprintf.o printf.o \
|
||||
sysconf.o \
|
||||
mmap.o
|
||||
|
||||
SYSOBJS=sysdeps.o
|
||||
|
||||
dtoa.o: CFLAGS+=-fno-strict-aliasing
|
||||
|
||||
libnolibc.a: $(OBJS) $(SYSOBJS)
|
||||
$(AR) rcs $@ $(OBJS) $(SYSOBJS)
|
||||
|
||||
# The following test ensures that each header file provided by nolibc is both
|
||||
# self-contained and compile-tested. Note that headers in include/_freestanding
|
||||
# are not intended to be included directly, thus are exempt from this check.
|
||||
|
||||
HEADERS=$(wildcard include/*.h include/sys/*.h)
|
||||
|
||||
# For each HEADER we want to test, produce test-include/HEADER.o. Note that
|
||||
# HEADER will include subdirectories, if matched.
|
||||
TEST_H_OBJS=$(patsubst %.h,test-%.o,$(HEADERS))
|
||||
|
||||
# For each HEADER we want to test, generate a C source file including only
|
||||
# that HEADER. As above, HEADER may include subdirectories.
|
||||
test-include/%.c: include/%.h | test-include/sys/
|
||||
echo "#include \"../$<\"" >$@
|
||||
|
||||
.PRECIOUS: test-include/%.c
|
||||
|
||||
test-include/:
|
||||
mkdir -p $@
|
||||
|
||||
test-include/sys/: test-include/
|
||||
mkdir -p $@
|
||||
|
||||
test-headers: $(TEST_H_OBJS) | test-include/sys/
|
18
nolibc/assert.c
Normal file
18
nolibc/assert.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* These functions deliberately do not call printf() or malloc() in order to
|
||||
* abort as quickly as possible without triggering further errors.
|
||||
*/
|
||||
|
||||
void _assert_fail(const char *file, const char *line, const char *e)
|
||||
{
|
||||
puts(file);
|
||||
puts(":");
|
||||
puts(line);
|
||||
puts(": Assertion `");
|
||||
puts(e);
|
||||
puts("' failed\n");
|
||||
abort();
|
||||
}
|
26
nolibc/ctype.c
Normal file
26
nolibc/ctype.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <ctype.h>
|
||||
|
||||
int isalpha(int c)
|
||||
{
|
||||
return ((unsigned)c|32)-'a' < 26;
|
||||
}
|
||||
|
||||
int isdigit(int c)
|
||||
{
|
||||
return (unsigned)c-'0' < 10;
|
||||
}
|
||||
|
||||
int isprint(int c)
|
||||
{
|
||||
return (unsigned)c-0x20 < 0x5f;
|
||||
}
|
||||
|
||||
int isspace(int c)
|
||||
{
|
||||
return c == ' ' || (unsigned)c-'\t' < 5;
|
||||
}
|
||||
|
||||
int isupper(int c)
|
||||
{
|
||||
return (unsigned)c-'A' < 26;
|
||||
}
|
6339
nolibc/dlmalloc.i
Normal file
6339
nolibc/dlmalloc.i
Normal file
File diff suppressed because it is too large
Load diff
6234
nolibc/dtoa.c
Normal file
6234
nolibc/dtoa.c
Normal file
File diff suppressed because it is too large
Load diff
64
nolibc/errlist.c
Normal file
64
nolibc/errlist.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* This code is mostly an extract from OpenBSD sources, keeping only the needed
|
||||
* errno values
|
||||
*
|
||||
* NOTE: the list of errors must be kept in sync with errno.h */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1985, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
const char *const sys_errlist[] = {
|
||||
"Undefined error: 0", /* ENOERROR */
|
||||
"No such file or directory", /* ENOENT */
|
||||
"Interrupted system call", /* EINTR */
|
||||
"Bad file descriptor", /* EBADF */
|
||||
"Cannot allocate memory", /* ENOMEM */
|
||||
"Device busy", /* EBUSY */
|
||||
"Invalid argument", /* EINVAL */
|
||||
"Too many open files", /* EMFILE */
|
||||
"Broken pipe", /* EPIPE */
|
||||
|
||||
/* math software */
|
||||
"Result too large", /* ERANGE */
|
||||
|
||||
/* non-blocking and interrupt i/o */
|
||||
"Resource temporarily unavailable", /* EAGAIN */
|
||||
|
||||
/* ipc/network software -- operational errors */
|
||||
"Connection reset by peer", /* ECONNRESET */
|
||||
|
||||
"Function not implemented", /* ENOSYS */
|
||||
/* EOVERFLOW */
|
||||
"Value too large to be stored in data type",
|
||||
};
|
||||
|
||||
static_assert((sizeof sys_errlist/sizeof sys_errlist[0]) == NB_ERRORS,
|
||||
"errlist.c and errno.h are out of sync");
|
12
nolibc/fprintf.c
Normal file
12
nolibc/fprintf.c
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
int fprintf(FILE *restrict f, const char *restrict fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
ret = vfprintf(f, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
16
nolibc/include/_gilbraltar/byteorder.h
Normal file
16
nolibc/include/_gilbraltar/byteorder.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef __FREESTANDING_BYTEORDER_H
|
||||
#define __FREESTANDING_BYTEORDER_H
|
||||
|
||||
#if !defined(__BYTE_ORDER__)
|
||||
#error C compiler does not define __BYTE_ORDER__
|
||||
#endif
|
||||
|
||||
#if defined(BYTE_ORDER) || defined(LITTLE_ENDIAN) || defined(BIG_ENDIAN)
|
||||
#error BYTE_ORDER, LITTLE_ENDIAN or BIG_ENDIAN must not be defined here
|
||||
#endif
|
||||
|
||||
#define BYTE_ORDER __BYTE_ORDER__
|
||||
#define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
|
||||
#define BIG_ENDIAN __ORDER_BIG_ENDIAN__
|
||||
|
||||
#endif /* __FREESTANDING_BYTEORDER_H */
|
13
nolibc/include/_gilbraltar/overrides.h
Normal file
13
nolibc/include/_gilbraltar/overrides.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef __FREESTANDING_OVERRIDES_H
|
||||
#define __FREESTANDING_OVERRIDES_H
|
||||
|
||||
#undef __FreeBSD__
|
||||
#undef __OpenBSD__
|
||||
#undef __gnu_linux__
|
||||
#undef __linux
|
||||
#undef __linux__
|
||||
#undef linux
|
||||
|
||||
#define __ocaml_solo5__
|
||||
|
||||
#endif /* __FREESTANDING_OVERRIDES_H */
|
20
nolibc/include/assert.h
Normal file
20
nolibc/include/assert.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef _ASSERT_H
|
||||
#define _ASSERT_H
|
||||
|
||||
extern void _assert_fail(const char *, const char *, const char *)
|
||||
__attribute__((noreturn));
|
||||
|
||||
#define _ASSERT_STR_EXPAND(y) #y
|
||||
#define _ASSERT_STR(x) _ASSERT_STR_EXPAND(x)
|
||||
|
||||
#define assert(e) \
|
||||
do { \
|
||||
if (!(e)) \
|
||||
_assert_fail(__FILE__, _ASSERT_STR(__LINE__), #e); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef static_assert
|
||||
# define static_assert _Static_assert
|
||||
#endif
|
12
nolibc/include/ctype.h
Normal file
12
nolibc/include/ctype.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef _CTYPE_H
|
||||
#define _CTYPE_H
|
||||
|
||||
int isalpha(int);
|
||||
int isdigit(int);
|
||||
int isprint(int);
|
||||
int isspace(int);
|
||||
int isupper(int);
|
||||
int isalnum(int);
|
||||
int tolower(int);
|
||||
|
||||
#endif
|
12
nolibc/include/dirent.h
Normal file
12
nolibc/include/dirent.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef _DIRENT_H
|
||||
#define _DIRENT_H
|
||||
|
||||
typedef int DIR;
|
||||
int closedir(DIR *);
|
||||
DIR *opendir(const char *);
|
||||
struct dirent {
|
||||
char *d_name;
|
||||
};
|
||||
struct dirent *readdir(DIR *);
|
||||
|
||||
#endif
|
45
nolibc/include/endian.h
Normal file
45
nolibc/include/endian.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef _ENDIAN_H
|
||||
#define _ENDIAN_H
|
||||
|
||||
#include <_gilbraltar/byteorder.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define bswap16(x) __builtin_bswap16(x)
|
||||
#define bswap32(x) __builtin_bswap32(x)
|
||||
#define bswap64(x) __builtin_bswap64(x)
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
|
||||
#define htobe16(x) bswap16(x)
|
||||
#define htobe32(x) bswap32(x)
|
||||
#define htobe64(x) bswap64(x)
|
||||
#define htole16(x) (uint16_t)(x)
|
||||
#define htole32(x) (uint32_t)(x)
|
||||
#define htole64(x) (uint64_t)(x)
|
||||
|
||||
#define be16toh(x) bswap16(x)
|
||||
#define be32toh(x) bswap32(x)
|
||||
#define be64toh(x) bswap64(x)
|
||||
#define le16toh(x) (uint16_t)(x)
|
||||
#define le32toh(x) (uint32_t)(x)
|
||||
#define le64toh(x) (uint64_t)(x)
|
||||
|
||||
#else /* BYTE_ORDER != LITTLE_ENDIAN */
|
||||
|
||||
#define htobe16(x) (uint16_t)(x)
|
||||
#define htobe32(x) (uint32_t)(x)
|
||||
#define htobe64(x) (uint64_t)(x)
|
||||
#define htole16(x) bswap16(x)
|
||||
#define htole32(x) bswap32(x)
|
||||
#define htole64(x) bswap64(x)
|
||||
|
||||
#define be16toh(x) (uint16_t)(x)
|
||||
#define be32toh(x) (uint32_t)(x)
|
||||
#define be64toh(x) (uint64_t)(x)
|
||||
#define le16toh(x) bswap16(x)
|
||||
#define le32toh(x) bswap32(x)
|
||||
#define le64toh(x) bswap64(x)
|
||||
|
||||
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
||||
|
||||
#endif /* _ENDIAN_H */
|
26
nolibc/include/errno.h
Normal file
26
nolibc/include/errno.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef _ERRNO_H
|
||||
#define _ERRNO_H
|
||||
|
||||
extern int errno;
|
||||
|
||||
/* This list of errors must be kept in sync with errlist.c */
|
||||
|
||||
#define ENOERROR 0 /* Actual error codes should be > 0 */
|
||||
|
||||
#define ENOENT 1
|
||||
#define EINTR 2
|
||||
#define EBADF 3
|
||||
#define ENOMEM 4
|
||||
#define EBUSY 5
|
||||
#define EINVAL 6
|
||||
#define EMFILE 7
|
||||
#define EPIPE 8
|
||||
#define ERANGE 9
|
||||
#define EAGAIN 10
|
||||
#define ECONNRESET 11
|
||||
#define ENOSYS 12
|
||||
#define EOVERFLOW 13
|
||||
|
||||
#define NB_ERRORS 14
|
||||
|
||||
#endif
|
18
nolibc/include/fcntl.h
Normal file
18
nolibc/include/fcntl.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef _FCNTL_H
|
||||
#define _FCNTL_H
|
||||
|
||||
int fcntl(int, int, ...);
|
||||
int open(const char *, int, ...);
|
||||
|
||||
/* The following values are taken from:
|
||||
* https://github.com/openbsd/src/blob/master/sys/sys/fcntl.h
|
||||
*/
|
||||
#define O_RDONLY 0x0000 /* open for reading only */
|
||||
#define O_WRONLY 0x0001 /* open for writing only */
|
||||
#define O_RDWR 0x0002 /* open for reading and writing */
|
||||
#define O_APPEND 0x0008 /* set append mode */
|
||||
#define O_CREAT 0x0200 /* create if nonexistent */
|
||||
#define O_TRUNC 0x0400 /* truncate to zero length */
|
||||
#define O_EXCL 0x0800 /* error if already exists */
|
||||
|
||||
#endif
|
6
nolibc/include/features.h
Normal file
6
nolibc/include/features.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef _FEATURES_H
|
||||
#define _FEATURES_H
|
||||
|
||||
/* No features, isn't that nice? */
|
||||
|
||||
#endif
|
122
nolibc/include/inttypes.h
Normal file
122
nolibc/include/inttypes.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
#ifndef _INTTYPES_H
|
||||
#define _INTTYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(UINTPTR_MAX) || !defined(UINT64_MAX)
|
||||
#error UINTPTR_MAX and UINT64_MAX must be defined here
|
||||
#endif
|
||||
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
#define __PRI64 "l"
|
||||
#define __PRIPTR "l"
|
||||
#else
|
||||
#define __PRI64 "ll"
|
||||
#define __PRIPTR ""
|
||||
#endif
|
||||
|
||||
#define PRId8 "d"
|
||||
#define PRId16 "d"
|
||||
#define PRId32 "d"
|
||||
#define PRId64 __PRI64 "d"
|
||||
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIdLEAST16 "d"
|
||||
#define PRIdLEAST32 "d"
|
||||
#define PRIdLEAST64 __PRI64 "d"
|
||||
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIdFAST16 "d"
|
||||
#define PRIdFAST32 "d"
|
||||
#define PRIdFAST64 __PRI64 "d"
|
||||
|
||||
#define PRIi8 "i"
|
||||
#define PRIi16 "i"
|
||||
#define PRIi32 "i"
|
||||
#define PRIi64 __PRI64 "i"
|
||||
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIiLEAST16 "i"
|
||||
#define PRIiLEAST32 "i"
|
||||
#define PRIiLEAST64 __PRI64 "i"
|
||||
|
||||
#define PRIiFAST8 "i"
|
||||
#define PRIiFAST16 "i"
|
||||
#define PRIiFAST32 "i"
|
||||
#define PRIiFAST64 __PRI64 "i"
|
||||
|
||||
#define PRIo8 "o"
|
||||
#define PRIo16 "o"
|
||||
#define PRIo32 "o"
|
||||
#define PRIo64 __PRI64 "o"
|
||||
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIoLEAST16 "o"
|
||||
#define PRIoLEAST32 "o"
|
||||
#define PRIoLEAST64 __PRI64 "o"
|
||||
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIoFAST16 "o"
|
||||
#define PRIoFAST32 "o"
|
||||
#define PRIoFAST64 __PRI64 "o"
|
||||
|
||||
#define PRIu8 "u"
|
||||
#define PRIu16 "u"
|
||||
#define PRIu32 "u"
|
||||
#define PRIu64 __PRI64 "u"
|
||||
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIuLEAST16 "u"
|
||||
#define PRIuLEAST32 "u"
|
||||
#define PRIuLEAST64 __PRI64 "u"
|
||||
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIuFAST16 "u"
|
||||
#define PRIuFAST32 "u"
|
||||
#define PRIuFAST64 __PRI64 "u"
|
||||
|
||||
#define PRIx8 "x"
|
||||
#define PRIx16 "x"
|
||||
#define PRIx32 "x"
|
||||
#define PRIx64 __PRI64 "x"
|
||||
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIxLEAST16 "x"
|
||||
#define PRIxLEAST32 "x"
|
||||
#define PRIxLEAST64 __PRI64 "x"
|
||||
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIxFAST16 "x"
|
||||
#define PRIxFAST32 "x"
|
||||
#define PRIxFAST64 __PRI64 "x"
|
||||
|
||||
#define PRIX8 "X"
|
||||
#define PRIX16 "X"
|
||||
#define PRIX32 "X"
|
||||
#define PRIX64 __PRI64 "X"
|
||||
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIXLEAST16 "X"
|
||||
#define PRIXLEAST32 "X"
|
||||
#define PRIXLEAST64 __PRI64 "X"
|
||||
|
||||
#define PRIXFAST8 "X"
|
||||
#define PRIXFAST16 "X"
|
||||
#define PRIXFAST32 "X"
|
||||
#define PRIXFAST64 __PRI64 "X"
|
||||
|
||||
#define PRIdMAX __PRI64 "d"
|
||||
#define PRIiMAX __PRI64 "i"
|
||||
#define PRIoMAX __PRI64 "o"
|
||||
#define PRIuMAX __PRI64 "u"
|
||||
#define PRIxMAX __PRI64 "x"
|
||||
#define PRIXMAX __PRI64 "X"
|
||||
|
||||
#define PRIdPTR __PRIPTR "d"
|
||||
#define PRIiPTR __PRIPTR "i"
|
||||
#define PRIoPTR __PRIPTR "o"
|
||||
#define PRIuPTR __PRIPTR "u"
|
||||
#define PRIxPTR __PRIPTR "x"
|
||||
#define PRIXPTR __PRIPTR "X"
|
||||
|
||||
#endif
|
23
nolibc/include/limits.h
Normal file
23
nolibc/include/limits.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef _LIMITS_H
|
||||
#define _LIMITS_H
|
||||
|
||||
#define INT_MAX 0x7fffffff
|
||||
#define INT_MIN (-1-0x7fffffff)
|
||||
#define UINT_MAX 0xffffffffU
|
||||
#define SHRT_MAX 0x7fff
|
||||
#define SHRT_MIN (-1-0x7fff)
|
||||
#define USHRT_MAX 0xffff
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
#define LONG_MAX 0x7fffffffffffffffL
|
||||
#define LLONG_MAX 0x7fffffffffffffffLL
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
#define LONG_MIN (-LONG_MAX-1)
|
||||
#define LLONG_MIN (-LLONG_MAX-1)
|
||||
#define ULONG_MAX (2UL*LONG_MAX+1)
|
||||
#define NL_ARGMAX 9
|
||||
#define UCHAR_MAX 255
|
||||
#define CHAR_BIT 8
|
||||
|
||||
#endif
|
1
nolibc/include/math.h
Normal file
1
nolibc/include/math.h
Normal file
|
@ -0,0 +1 @@
|
|||
#include <openlibm.h>
|
57
nolibc/include/pthread.h
Normal file
57
nolibc/include/pthread.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ifndef _PTHREAD_H
|
||||
#define _PTHREAD_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef unsigned long int pthread_t;
|
||||
typedef int cpu_set_t;
|
||||
|
||||
int pthread_getaffinity_np(pthread_t, size_t, cpu_set_t *);
|
||||
|
||||
pthread_t pthread_self(void);
|
||||
|
||||
typedef int pthread_attr_t;
|
||||
|
||||
int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
|
||||
int pthread_join(pthread_t, void **);
|
||||
int pthread_attr_init(pthread_attr_t *);
|
||||
void pthread_cleanup_push(void (*)(void *), void *);
|
||||
void pthread_cleanup_pop(int);
|
||||
|
||||
typedef int pthread_mutex_t;
|
||||
typedef int pthread_cond_t;
|
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t *);
|
||||
int pthread_mutex_trylock(pthread_mutex_t *);
|
||||
int pthread_mutex_unlock(pthread_mutex_t *);
|
||||
|
||||
#define PTHREAD_MUTEX_INITIALIZER 0
|
||||
#define PTHREAD_COND_INITIALIZER 0
|
||||
|
||||
int pthread_sigmask(int, const sigset_t *, sigset_t *);
|
||||
int pthread_detach(pthread_t);
|
||||
int pthread_equal(pthread_t, pthread_t);
|
||||
|
||||
typedef int pthread_mutexattr_t;
|
||||
|
||||
int pthread_mutexattr_init(pthread_mutexattr_t *);
|
||||
int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
|
||||
|
||||
#define PTHREAD_MUTEX_ERRORCHECK 0
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
|
||||
int pthread_mutexattr_destroy(pthread_mutexattr_t *);
|
||||
int pthread_mutex_destroy(pthread_mutex_t *);
|
||||
|
||||
typedef int pthread_condattr_t;
|
||||
|
||||
int pthread_condattr_init(pthread_condattr_t *);
|
||||
int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
|
||||
int pthread_cond_broadcast(pthread_cond_t *);
|
||||
int pthread_cond_signal(pthread_cond_t *);
|
||||
int pthread_cond_destroy(pthread_cond_t *);
|
||||
|
||||
#endif
|
8
nolibc/include/sched.h
Normal file
8
nolibc/include/sched.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef _SCHED_H
|
||||
#define _SCHED_H
|
||||
|
||||
typedef int cpu_set_t;
|
||||
|
||||
#define CPU_ZERO (x) 0
|
||||
|
||||
#endif
|
5
nolibc/include/setjmp.h
Normal file
5
nolibc/include/setjmp.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include <signal.h>
|
||||
|
||||
void longjmp(int, int) __attribute__ ((__noreturn__));
|
||||
|
||||
#define setjmp(buf) 0
|
27
nolibc/include/signal.h
Normal file
27
nolibc/include/signal.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef _SIGNAL_H
|
||||
#define _SIGNAL_H
|
||||
|
||||
/*
|
||||
* The following definitions are required not only to build the OCaml runtime
|
||||
* but also the freestanding version of GMP used by Mirage.
|
||||
* Note though that Solo5 does not implement signals, so we should not trigger a
|
||||
* situation where these values are really used.
|
||||
*/
|
||||
|
||||
typedef int jmp_buf;
|
||||
int setjmp(jmp_buf);
|
||||
void (*signal(int sig, void (*func)(int)))(int);
|
||||
#define SIG_DFL 0
|
||||
#define SIG_IGN 0
|
||||
#define SIG_ERR 0
|
||||
#define SIG_BLOCK 0
|
||||
#define SIG_SETMASK 0
|
||||
|
||||
#define SIGFPE 1
|
||||
int raise(int);
|
||||
|
||||
typedef int sigset_t;
|
||||
int sigfillset(sigset_t *);
|
||||
int sigwait(const sigset_t *restrict set, int *restrict sig);
|
||||
|
||||
#endif
|
42
nolibc/include/stdio.h
Normal file
42
nolibc/include/stdio.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef _STDIO_H
|
||||
#define _STDIO_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct _FILE;
|
||||
typedef struct _FILE {
|
||||
size_t (*write)(struct _FILE *f, const char *, size_t);
|
||||
char *wpos;
|
||||
char *wend;
|
||||
} FILE;
|
||||
int fflush(FILE *);
|
||||
int fprintf(FILE *, const char *, ...);
|
||||
int printf(const char *, ...);
|
||||
int rename(const char *, const char *);
|
||||
extern FILE *stdout;
|
||||
extern FILE *stderr;
|
||||
int sscanf(const char *, const char *, ...);
|
||||
int snprintf(char *, size_t, const char *, ...);
|
||||
int vfprintf(FILE *, const char *, va_list);
|
||||
int vsnprintf(char *, size_t, const char *, va_list);
|
||||
/*
|
||||
* The following definitions are not required by the OCaml runtime, but are
|
||||
* needed to build the freestanding version of GMP used by Mirage.
|
||||
*/
|
||||
#define EOF (-1)
|
||||
extern FILE *stdin;
|
||||
size_t fread(void *, size_t, size_t, FILE *);
|
||||
int getc(FILE *);
|
||||
int ungetc(int, FILE *);
|
||||
size_t fwrite(const void *, size_t, size_t, FILE *);
|
||||
int fputc(int, FILE *);
|
||||
int putc(int, FILE *);
|
||||
int ferror(FILE *);
|
||||
int fputs(const char *, FILE *);
|
||||
FILE *fopen(const char *, const char *);
|
||||
int fclose(FILE *);
|
||||
int puts(const char *);
|
||||
int putchar(int);
|
||||
|
||||
#endif
|
39
nolibc/include/stdlib.h
Normal file
39
nolibc/include/stdlib.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef _STDLIB_H
|
||||
#define _STDLIB_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void abort(void) __attribute__((noreturn));
|
||||
void exit(int) __attribute__((noreturn));
|
||||
void *malloc(size_t);
|
||||
void free(void *);
|
||||
void *calloc(size_t, size_t);
|
||||
void *realloc(void *, size_t);
|
||||
int posix_memalign(void **, size_t, size_t);
|
||||
|
||||
struct mallinfo {
|
||||
size_t arena; /* non-mmapped space allocated from system */
|
||||
size_t ordblks; /* number of free chunks */
|
||||
size_t smblks; /* always 0 */
|
||||
size_t hblks; /* always 0 */
|
||||
size_t hblkhd; /* space in mmapped regions */
|
||||
size_t usmblks; /* maximum total allocated space */
|
||||
size_t fsmblks; /* always 0 */
|
||||
size_t uordblks; /* total allocated space */
|
||||
size_t fordblks; /* total free space */
|
||||
size_t keepcost; /* releasable (via malloc_trim) space */
|
||||
};
|
||||
struct mallinfo mallinfo(void);
|
||||
|
||||
char *getenv(const char *);
|
||||
char *secure_getenv(const char *);
|
||||
int system(const char *);
|
||||
double strtod(const char *, char **);
|
||||
long strtol(const char *, char **, int);
|
||||
|
||||
void qsort(void *base, size_t nmemb, size_t size,
|
||||
int (*compare)(const void *, const void *));
|
||||
|
||||
char *mktemp(char *);
|
||||
|
||||
#endif
|
29
nolibc/include/string.h
Normal file
29
nolibc/include/string.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef _STRING_H
|
||||
#define _STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int memcmp(const void *, const void *, size_t);
|
||||
void *memchr(const void *, int, size_t);
|
||||
void *memcpy(void *, const void *, size_t);
|
||||
void *memmove(void *, const void *, size_t);
|
||||
void *memset(void *, int, size_t);
|
||||
int strcmp(const char *, const char *);
|
||||
size_t strlen(const char *);
|
||||
size_t strnlen(const char *, size_t);
|
||||
char *strerror(int);
|
||||
int strerror_r(int errnum, char *buf, size_t buflen);
|
||||
/*
|
||||
* The following definitions are not required by the OCaml runtime, but are
|
||||
* needed to build the freestanding version of GMP used by Mirage.
|
||||
*/
|
||||
char *strncpy(char *, const char *, size_t);
|
||||
char *strcpy(char *, const char *);
|
||||
char *strchr(const char *, int);
|
||||
char *strstr(const char *, const char *);
|
||||
/*
|
||||
* The following definitions are required for the OCaml bytecode runtime.
|
||||
*/
|
||||
int strncmp(const char*, const char*, size_t);
|
||||
|
||||
#endif
|
4
nolibc/include/sys/ioctl.h
Normal file
4
nolibc/include/sys/ioctl.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef _SYS_IOCTL_H
|
||||
#define _SYS_IOCTL_H
|
||||
|
||||
#endif
|
26
nolibc/include/sys/mman.h
Normal file
26
nolibc/include/sys/mman.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef _MMAP_H
|
||||
#define _MMAP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
|
||||
|
||||
#define PROT_NONE 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
|
||||
#define MAP_SHARED 0x01
|
||||
#define MAP_PRIVATE 0x02
|
||||
#define MAP_FIXED 0x10
|
||||
#define MAP_ANONYMOUS 0x20
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
|
||||
// the MAP_FAILED comply with the mmap manual page
|
||||
#define MAP_FAILED (void*)-1
|
||||
|
||||
#define OCAML_SOLO5_PAGESIZE (1 << 12)
|
||||
|
||||
int munmap(void *addr, size_t len);
|
||||
|
||||
#endif
|
6
nolibc/include/sys/param.h
Normal file
6
nolibc/include/sys/param.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef _SYS_PARAM_H
|
||||
#define _SYS_PARAM_H
|
||||
|
||||
#include <_solo5/byteorder.h>
|
||||
|
||||
#endif /* _SYS_PARAM_H */
|
20
nolibc/include/sys/stat.h
Normal file
20
nolibc/include/sys/stat.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef _SYS_STAT_H
|
||||
#define _SYS_STAT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct stat {
|
||||
int st_mode;
|
||||
int st_size;
|
||||
};
|
||||
#define S_IFDIR 0
|
||||
#define S_IFMT 0
|
||||
#define S_IFREG 0
|
||||
#define S_ISREG(x) (0)
|
||||
#define S_IRUSR 0
|
||||
#define S_IWUSR 0
|
||||
int stat(const char *, struct stat *);
|
||||
int mkdir(const char *, mode_t);
|
||||
int fstat(int, struct stat *);
|
||||
|
||||
#endif
|
16
nolibc/include/sys/time.h
Normal file
16
nolibc/include/sys/time.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef _SYS_TIME_H
|
||||
#define _SYS_TIME_H
|
||||
|
||||
typedef long time_t;
|
||||
typedef long suseconds_t;
|
||||
struct timeval {
|
||||
time_t tv_sec;
|
||||
suseconds_t tv_usec;
|
||||
};
|
||||
struct timezone {
|
||||
int tz_minuteswest;
|
||||
int tz_dsttime;
|
||||
};
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
|
||||
#endif
|
13
nolibc/include/sys/times.h
Normal file
13
nolibc/include/sys/times.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef _SYS_TIMES_H
|
||||
#define _SYS_TIMES_H
|
||||
|
||||
typedef int clock_t;
|
||||
struct tms {
|
||||
clock_t tms_utime;
|
||||
clock_t tms_stime;
|
||||
clock_t tms_cutime;
|
||||
clock_t tms_cstime;
|
||||
};
|
||||
clock_t times(struct tms *buf);
|
||||
|
||||
#endif
|
13
nolibc/include/sys/types.h
Normal file
13
nolibc/include/sys/types.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef _SYS_TYPES_H
|
||||
#define _SYS_TYPES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int pid_t;
|
||||
typedef int off_t;
|
||||
typedef int ssize_t;
|
||||
typedef int mode_t;
|
||||
typedef int useconds_t;
|
||||
|
||||
#endif
|
4
nolibc/include/sys/wait.h
Normal file
4
nolibc/include/sys/wait.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef _SYS_WAIT_H
|
||||
#define _SYS_WAIT_H
|
||||
|
||||
#endif
|
1
nolibc/include/time.h
Symbolic link
1
nolibc/include/time.h
Symbolic link
|
@ -0,0 +1 @@
|
|||
sys/time.h
|
26
nolibc/include/unistd.h
Normal file
26
nolibc/include/unistd.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef _UNISTD_H
|
||||
#define _UNISTD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
int chdir(const char *);
|
||||
int close(int);
|
||||
char *getcwd(char *, size_t);
|
||||
pid_t getpid(void);
|
||||
pid_t getppid(void);
|
||||
int isatty(int);
|
||||
off_t lseek(int, off_t, int); /* SEEK_ */
|
||||
ssize_t read(int, void *, size_t);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
ssize_t readlink(const char *, char *, size_t);
|
||||
int unlink(const char *);
|
||||
int rmdir(const char *);
|
||||
int usleep(useconds_t);
|
||||
int ftruncate(int, off_t);
|
||||
long sysconf(int);
|
||||
int execv(const char *, char *const []);
|
||||
|
||||
#define _SC_PAGESIZE 1
|
||||
#define _SC_PAGE_SIZE _SC_PAGESIZE
|
||||
|
||||
#endif
|
23
nolibc/memchr.c
Normal file
23
nolibc/memchr.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define SS (sizeof(size_t))
|
||||
#define ALIGN (sizeof(size_t)-1)
|
||||
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||
|
||||
void *memchr(const void *src, int c, size_t n)
|
||||
{
|
||||
const unsigned char *s = src;
|
||||
c = (unsigned char)c;
|
||||
for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--);
|
||||
if (n && *s != c) {
|
||||
const size_t *w;
|
||||
size_t k = ONES * c;
|
||||
for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS);
|
||||
for (s = (const void *)w; n && *s != c; s++, n--);
|
||||
}
|
||||
return n ? (void *)s : 0;
|
||||
}
|
8
nolibc/memcmp.c
Normal file
8
nolibc/memcmp.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include <string.h>
|
||||
|
||||
int memcmp(const void *vl, const void *vr, size_t n)
|
||||
{
|
||||
const unsigned char *l=vl, *r=vr;
|
||||
for (; n && *l == *r; n--, l++, r++);
|
||||
return n ? *l-*r : 0;
|
||||
}
|
124
nolibc/memcpy.c
Normal file
124
nolibc/memcpy.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <endian.h>
|
||||
|
||||
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
|
||||
{
|
||||
unsigned char *d = dest;
|
||||
const unsigned char *s = src;
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define LS >>
|
||||
#define RS <<
|
||||
#else
|
||||
#define LS <<
|
||||
#define RS >>
|
||||
#endif
|
||||
|
||||
typedef uint32_t __attribute__((__may_alias__)) u32;
|
||||
uint32_t w, x;
|
||||
|
||||
for (; (uintptr_t)s % 4 && n; n--) *d++ = *s++;
|
||||
|
||||
if ((uintptr_t)d % 4 == 0) {
|
||||
for (; n>=16; s+=16, d+=16, n-=16) {
|
||||
*(u32 *)(d+0) = *(u32 *)(s+0);
|
||||
*(u32 *)(d+4) = *(u32 *)(s+4);
|
||||
*(u32 *)(d+8) = *(u32 *)(s+8);
|
||||
*(u32 *)(d+12) = *(u32 *)(s+12);
|
||||
}
|
||||
if (n&8) {
|
||||
*(u32 *)(d+0) = *(u32 *)(s+0);
|
||||
*(u32 *)(d+4) = *(u32 *)(s+4);
|
||||
d += 8; s += 8;
|
||||
}
|
||||
if (n&4) {
|
||||
*(u32 *)(d+0) = *(u32 *)(s+0);
|
||||
d += 4; s += 4;
|
||||
}
|
||||
if (n&2) {
|
||||
*d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&1) {
|
||||
*d = *s;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (n >= 32) switch ((uintptr_t)d % 4) {
|
||||
case 1:
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
n -= 3;
|
||||
for (; n>=17; s+=16, d+=16, n-=16) {
|
||||
x = *(u32 *)(s+1);
|
||||
*(u32 *)(d+0) = (w LS 24) | (x RS 8);
|
||||
w = *(u32 *)(s+5);
|
||||
*(u32 *)(d+4) = (x LS 24) | (w RS 8);
|
||||
x = *(u32 *)(s+9);
|
||||
*(u32 *)(d+8) = (w LS 24) | (x RS 8);
|
||||
w = *(u32 *)(s+13);
|
||||
*(u32 *)(d+12) = (x LS 24) | (w RS 8);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
n -= 2;
|
||||
for (; n>=18; s+=16, d+=16, n-=16) {
|
||||
x = *(u32 *)(s+2);
|
||||
*(u32 *)(d+0) = (w LS 16) | (x RS 16);
|
||||
w = *(u32 *)(s+6);
|
||||
*(u32 *)(d+4) = (x LS 16) | (w RS 16);
|
||||
x = *(u32 *)(s+10);
|
||||
*(u32 *)(d+8) = (w LS 16) | (x RS 16);
|
||||
w = *(u32 *)(s+14);
|
||||
*(u32 *)(d+12) = (x LS 16) | (w RS 16);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
n -= 1;
|
||||
for (; n>=19; s+=16, d+=16, n-=16) {
|
||||
x = *(u32 *)(s+3);
|
||||
*(u32 *)(d+0) = (w LS 8) | (x RS 24);
|
||||
w = *(u32 *)(s+7);
|
||||
*(u32 *)(d+4) = (x LS 8) | (w RS 24);
|
||||
x = *(u32 *)(s+11);
|
||||
*(u32 *)(d+8) = (w LS 8) | (x RS 24);
|
||||
w = *(u32 *)(s+15);
|
||||
*(u32 *)(d+12) = (x LS 8) | (w RS 24);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (n&16) {
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&8) {
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&4) {
|
||||
*d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&2) {
|
||||
*d++ = *s++; *d++ = *s++;
|
||||
}
|
||||
if (n&1) {
|
||||
*d = *s;
|
||||
}
|
||||
return dest;
|
||||
#endif
|
||||
|
||||
for (; n; n--) *d++ = *s++;
|
||||
return dest;
|
||||
}
|
36
nolibc/memmove.c
Normal file
36
nolibc/memmove.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define WT size_t
|
||||
#define WS (sizeof(WT))
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
|
||||
if (d==s) return d;
|
||||
if (s+n <= d || d+n <= s) return memcpy(d, s, n);
|
||||
|
||||
if (d<s) {
|
||||
if ((uintptr_t)s % WS == (uintptr_t)d % WS) {
|
||||
while ((uintptr_t)d % WS) {
|
||||
if (!n--) return dest;
|
||||
*d++ = *s++;
|
||||
}
|
||||
for (; n>=WS; n-=WS, d+=WS, s+=WS) *(WT *)d = *(WT *)s;
|
||||
}
|
||||
for (; n; n--) *d++ = *s++;
|
||||
} else {
|
||||
if ((uintptr_t)s % WS == (uintptr_t)d % WS) {
|
||||
while ((uintptr_t)(d+n) % WS) {
|
||||
if (!n--) return dest;
|
||||
d[n] = s[n];
|
||||
}
|
||||
while (n>=WS) n-=WS, *(WT *)(d+n) = *(WT *)(s+n);
|
||||
}
|
||||
while (n) n--, d[n] = s[n];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
86
nolibc/memset.c
Normal file
86
nolibc/memset.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void *memset(void *dest, int c, size_t n)
|
||||
{
|
||||
unsigned char *s = dest;
|
||||
size_t k;
|
||||
|
||||
/* Fill head and tail with minimal branching. Each
|
||||
* conditional ensures that all the subsequently used
|
||||
* offsets are well-defined and in the dest region. */
|
||||
|
||||
if (!n) return dest;
|
||||
s[0] = s[n-1] = c;
|
||||
if (n <= 2) return dest;
|
||||
s[1] = s[n-2] = c;
|
||||
s[2] = s[n-3] = c;
|
||||
if (n <= 6) return dest;
|
||||
s[3] = s[n-4] = c;
|
||||
if (n <= 8) return dest;
|
||||
|
||||
/* Advance pointer to align it at a 4-byte boundary,
|
||||
* and truncate n to a multiple of 4. The previous code
|
||||
* already took care of any head/tail that get cut off
|
||||
* by the alignment. */
|
||||
|
||||
k = -(uintptr_t)s & 3;
|
||||
s += k;
|
||||
n -= k;
|
||||
n &= -4;
|
||||
|
||||
#ifdef __GNUC__
|
||||
typedef uint32_t __attribute__((__may_alias__)) u32;
|
||||
typedef uint64_t __attribute__((__may_alias__)) u64;
|
||||
|
||||
u32 c32 = ((u32)-1)/255 * (unsigned char)c;
|
||||
|
||||
/* In preparation to copy 32 bytes at a time, aligned on
|
||||
* an 8-byte bounary, fill head/tail up to 28 bytes each.
|
||||
* As in the initial byte-based head/tail fill, each
|
||||
* conditional below ensures that the subsequent offsets
|
||||
* are valid (e.g. !(n<=24) implies n>=28). */
|
||||
|
||||
*(u32 *)(s+0) = c32;
|
||||
*(u32 *)(s+n-4) = c32;
|
||||
if (n <= 8) return dest;
|
||||
*(u32 *)(s+4) = c32;
|
||||
*(u32 *)(s+8) = c32;
|
||||
*(u32 *)(s+n-12) = c32;
|
||||
*(u32 *)(s+n-8) = c32;
|
||||
if (n <= 24) return dest;
|
||||
*(u32 *)(s+12) = c32;
|
||||
*(u32 *)(s+16) = c32;
|
||||
*(u32 *)(s+20) = c32;
|
||||
*(u32 *)(s+24) = c32;
|
||||
*(u32 *)(s+n-28) = c32;
|
||||
*(u32 *)(s+n-24) = c32;
|
||||
*(u32 *)(s+n-20) = c32;
|
||||
*(u32 *)(s+n-16) = c32;
|
||||
|
||||
/* Align to a multiple of 8 so we can fill 64 bits at a time,
|
||||
* and avoid writing the same bytes twice as much as is
|
||||
* practical without introducing additional branching. */
|
||||
|
||||
k = 24 + ((uintptr_t)s & 4);
|
||||
s += k;
|
||||
n -= k;
|
||||
|
||||
/* If this loop is reached, 28 tail bytes have already been
|
||||
* filled, so any remainder when n drops below 32 can be
|
||||
* safely ignored. */
|
||||
|
||||
u64 c64 = c32 | ((u64)c32 << 32);
|
||||
for (; n >= 32; n-=32, s+=32) {
|
||||
*(u64 *)(s+0) = c64;
|
||||
*(u64 *)(s+8) = c64;
|
||||
*(u64 *)(s+16) = c64;
|
||||
*(u64 *)(s+24) = c64;
|
||||
}
|
||||
#else
|
||||
/* Pure C fallback with no aliasing violations. */
|
||||
for (; n; n--, s++) *s = c;
|
||||
#endif
|
||||
|
||||
return dest;
|
||||
}
|
77
nolibc/mmap.c
Normal file
77
nolibc/mmap.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) {
|
||||
|
||||
/* man page for mmap says:
|
||||
* If addr is NULL, then the kernel chooses the (page-aligned) address at
|
||||
* which to create the mapping; this is the most portable method of creating a
|
||||
* new mapping.
|
||||
*
|
||||
* For our purpose (Solo5 & OCaml), OCaml might use a NULL addr and force us to
|
||||
* use posix_memalign.
|
||||
* OCaml calls mmap with a non-null address and with the MAP_FIXED flag only
|
||||
* on already reserved memory to commit or decommit that memory block, ie to
|
||||
* set its protection to PROT_READ|PROT_WRITE or to PROT_NONE, in the
|
||||
* caml_mem_commit and caml_mem_decommit functions.
|
||||
* So we accept this particular case without allocating memory that would leak
|
||||
* since the OCaml code base simply ignores the returned value (as MAP_FIXED
|
||||
* enforces the returned value to be either addr or MAP_FAILED).
|
||||
*
|
||||
* The OCaml runtime uses [mmap()] only to allocate memory, so only
|
||||
* [fildes == 1] is handled.
|
||||
*/
|
||||
(void)prot; // unused argument
|
||||
|
||||
if (fildes != -1) {
|
||||
printf("mmap: file descriptor is unsupported.\n");
|
||||
abort();
|
||||
}
|
||||
if (!(flags & MAP_ANONYMOUS) || off != 0) {
|
||||
printf("mmap: only MAP_ANONYMOUS (and offset is 0) is supported.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
void *ptr = NULL;
|
||||
|
||||
if (addr == NULL) {
|
||||
/* posix_memalign doesn't modify ptr on error: ptr will still be NULL and
|
||||
* so we will return MAP_FAILED with no need to check explicitly the value
|
||||
* returned by posix_memalign */
|
||||
posix_memalign(&ptr, OCAML_SOLO5_PAGESIZE, len);
|
||||
} else {
|
||||
if ((flags & MAP_FIXED) != 0) {
|
||||
/* Case where mmap is called to commit or decommit already reserved
|
||||
* memory. Since we ignore prot, we can simply let it go through */
|
||||
return addr;
|
||||
} else {
|
||||
/* We cannot handle this case */
|
||||
errno = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr == NULL) {
|
||||
return MAP_FAILED;
|
||||
} else {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
int munmap(void *addr, size_t length)
|
||||
{
|
||||
(void)length; // unused argument
|
||||
|
||||
/* man page for munmap says:
|
||||
* The address addr must be a multiple of the page size (but length need not be).
|
||||
*/
|
||||
if ((uintptr_t)addr & OCAML_SOLO5_PAGESIZE != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(addr);
|
||||
return 0;
|
||||
}
|
12
nolibc/printf.c
Normal file
12
nolibc/printf.c
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
int printf(const char *restrict fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
ret = vfprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
17
nolibc/puts.c
Normal file
17
nolibc/puts.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern void solo5_console_write(const char *, size_t);
|
||||
|
||||
int puts(const char *s)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
solo5_console_write(s, len);
|
||||
return (int)(len); // We should never have a string length above MAX_INT, do we?
|
||||
}
|
||||
|
||||
int putchar(int chr)
|
||||
{
|
||||
solo5_console_write((char *) &chr, 1);
|
||||
return (1);
|
||||
}
|
13
nolibc/snprintf.c
Normal file
13
nolibc/snprintf.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(s, n, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
27
nolibc/stpncpy.c
Normal file
27
nolibc/stpncpy.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define ALIGN (sizeof(size_t)-1)
|
||||
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||
|
||||
char *__stpncpy(char *restrict d, const char *restrict s, size_t n)
|
||||
{
|
||||
size_t *wd;
|
||||
const size_t *ws;
|
||||
|
||||
if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
|
||||
for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++);
|
||||
if (!n || !*s) goto tail;
|
||||
wd=(void *)d; ws=(const void *)s;
|
||||
for (; n>=sizeof(size_t) && !HASZERO(*ws);
|
||||
n-=sizeof(size_t), ws++, wd++) *wd = *ws;
|
||||
d=(void *)wd; s=(const void *)ws;
|
||||
}
|
||||
for (; n && (*d=*s); n--, s++, d++);
|
||||
tail:
|
||||
memset(d, 0, n);
|
||||
return d;
|
||||
}
|
9
nolibc/strchr.c
Normal file
9
nolibc/strchr.c
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include <string.h>
|
||||
|
||||
char *__strchrnul(const char *, int);
|
||||
|
||||
char *strchr(const char *s, int c)
|
||||
{
|
||||
char *r = __strchrnul(s, c);
|
||||
return *(unsigned char *)r == (unsigned char)c ? r : 0;
|
||||
}
|
23
nolibc/strchrnul.c
Normal file
23
nolibc/strchrnul.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define ALIGN (sizeof(size_t))
|
||||
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||
|
||||
char *__strchrnul(const char *s, int c)
|
||||
{
|
||||
size_t *w, k;
|
||||
|
||||
c = (unsigned char)c;
|
||||
if (!c) return (char *)s + strlen(s);
|
||||
|
||||
for (; (uintptr_t)s % ALIGN; s++)
|
||||
if (!*s || *(unsigned char *)s == c) return (char *)s;
|
||||
k = ONES * c;
|
||||
for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
|
||||
for (s = (void *)w; *s && *(unsigned char *)s != c; s++);
|
||||
return (char *)s;
|
||||
}
|
7
nolibc/strcmp.c
Normal file
7
nolibc/strcmp.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include <string.h>
|
||||
|
||||
int strcmp(const char *l, const char *r)
|
||||
{
|
||||
for (; *l==*r && *l; l++, r++);
|
||||
return *(unsigned char *)l - *(unsigned char *)r;
|
||||
}
|
19
nolibc/strerror_r.c
Normal file
19
nolibc/strerror_r.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
extern const char *const sys_errlist[];
|
||||
|
||||
int strerror_r(int num, char *buf, size_t buflen)
|
||||
{
|
||||
if (num < 0 || num >= NB_ERRORS) {
|
||||
errno = EINVAL;
|
||||
return EINVAL;
|
||||
}
|
||||
if (snprintf(buf, buflen, "%s", sys_errlist[num]) >= (int)buflen) {
|
||||
errno = ERANGE;
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
18
nolibc/strlen.c
Normal file
18
nolibc/strlen.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define ALIGN (sizeof(size_t))
|
||||
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||
|
||||
size_t strlen(const char *s)
|
||||
{
|
||||
const char *a = s;
|
||||
const size_t *w;
|
||||
for (; (uintptr_t)s % ALIGN; s++) if (!*s) return s-a;
|
||||
for (w = (const void *)s; !HASZERO(*w); w++);
|
||||
for (s = (const void *)w; *s; s++);
|
||||
return s-a;
|
||||
}
|
9
nolibc/strncmp.c
Normal file
9
nolibc/strncmp.c
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include <string.h>
|
||||
|
||||
int strncmp(const char *_l, const char *_r, size_t n)
|
||||
{
|
||||
const unsigned char *l=(void *)_l, *r=(void *)_r;
|
||||
if (!n--) return 0;
|
||||
for (; *l && *r && n && *l == *r ; l++, r++, n--);
|
||||
return *l - *r;
|
||||
}
|
9
nolibc/strncpy.c
Normal file
9
nolibc/strncpy.c
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include <string.h>
|
||||
|
||||
char *__stpncpy(char *, const char *, size_t);
|
||||
|
||||
char *strncpy(char *restrict d, const char *restrict s, size_t n)
|
||||
{
|
||||
__stpncpy(d, s, n);
|
||||
return d;
|
||||
}
|
20
nolibc/strnlen.c
Normal file
20
nolibc/strnlen.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define ALIGN (sizeof(size_t))
|
||||
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||
|
||||
size_t strnlen(const char *s, size_t maxlen)
|
||||
{
|
||||
const char *a = s;
|
||||
const size_t *w;
|
||||
size_t over = maxlen;
|
||||
for (; ((uintptr_t)s % ALIGN) && over; s++, over--) if (!*s) return s-a;
|
||||
for (w = (const void *)s; over>ALIGN && !HASZERO(*w); w++,over-=ALIGN);
|
||||
for (s = (const void *)w; *s && over; s++, over--);
|
||||
if (over) return s-a;
|
||||
else return maxlen;
|
||||
}
|
155
nolibc/strstr.c
Normal file
155
nolibc/strstr.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static char *twobyte_strstr(const unsigned char *h, const unsigned char *n)
|
||||
{
|
||||
uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
|
||||
for (h++; *h && hw != nw; hw = hw<<8 | *++h);
|
||||
return *h ? (char *)h-1 : 0;
|
||||
}
|
||||
|
||||
static char *threebyte_strstr(const unsigned char *h, const unsigned char *n)
|
||||
{
|
||||
uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8;
|
||||
uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8;
|
||||
for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8);
|
||||
return *h ? (char *)h-2 : 0;
|
||||
}
|
||||
|
||||
static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n)
|
||||
{
|
||||
uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
|
||||
uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
|
||||
for (h+=3; *h && hw != nw; hw = hw<<8 | *++h);
|
||||
return *h ? (char *)h-3 : 0;
|
||||
}
|
||||
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
|
||||
#define BITOP(a,b,op) \
|
||||
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
|
||||
|
||||
static char *twoway_strstr(const unsigned char *h, const unsigned char *n)
|
||||
{
|
||||
const unsigned char *z;
|
||||
size_t l, ip, jp, k, p, ms, p0, mem, mem0;
|
||||
size_t byteset[32 / sizeof(size_t)] = { 0 };
|
||||
size_t shift[256];
|
||||
|
||||
/* Computing length of needle and fill shift table */
|
||||
for (l=0; n[l] && h[l]; l++)
|
||||
BITOP(byteset, n[l], |=), shift[n[l]] = l+1;
|
||||
if (n[l]) return 0; /* hit the end of h */
|
||||
|
||||
/* Compute maximal suffix */
|
||||
ip = -1; jp = 0; k = p = 1;
|
||||
while (jp+k<l) {
|
||||
if (n[ip+k] == n[jp+k]) {
|
||||
if (k == p) {
|
||||
jp += p;
|
||||
k = 1;
|
||||
} else k++;
|
||||
} else if (n[ip+k] > n[jp+k]) {
|
||||
jp += k;
|
||||
k = 1;
|
||||
p = jp - ip;
|
||||
} else {
|
||||
ip = jp++;
|
||||
k = p = 1;
|
||||
}
|
||||
}
|
||||
ms = ip;
|
||||
p0 = p;
|
||||
|
||||
/* And with the opposite comparison */
|
||||
ip = -1; jp = 0; k = p = 1;
|
||||
while (jp+k<l) {
|
||||
if (n[ip+k] == n[jp+k]) {
|
||||
if (k == p) {
|
||||
jp += p;
|
||||
k = 1;
|
||||
} else k++;
|
||||
} else if (n[ip+k] < n[jp+k]) {
|
||||
jp += k;
|
||||
k = 1;
|
||||
p = jp - ip;
|
||||
} else {
|
||||
ip = jp++;
|
||||
k = p = 1;
|
||||
}
|
||||
}
|
||||
if (ip+1 > ms+1) ms = ip;
|
||||
else p = p0;
|
||||
|
||||
/* Periodic needle? */
|
||||
if (memcmp(n, n+p, ms+1)) {
|
||||
mem0 = 0;
|
||||
p = MAX(ms, l-ms-1) + 1;
|
||||
} else mem0 = l-p;
|
||||
mem = 0;
|
||||
|
||||
/* Initialize incremental end-of-haystack pointer */
|
||||
z = h;
|
||||
|
||||
/* Search loop */
|
||||
for (;;) {
|
||||
/* Update incremental end-of-haystack pointer */
|
||||
if (z-h < l) {
|
||||
/* Fast estimate for MIN(l,63) */
|
||||
size_t grow = l | 63;
|
||||
const unsigned char *z2 = memchr(z, 0, grow);
|
||||
if (z2) {
|
||||
z = z2;
|
||||
if (z-h < l) return 0;
|
||||
} else z += grow;
|
||||
}
|
||||
|
||||
/* Check last byte first; advance by shift on mismatch */
|
||||
if (BITOP(byteset, h[l-1], &)) {
|
||||
k = l-shift[h[l-1]];
|
||||
//printf("adv by %zu (on %c) at [%s] (%zu;l=%zu)\n", k, h[l-1], h, shift[h[l-1]], l);
|
||||
if (k) {
|
||||
if (mem0 && mem && k < p) k = l-p;
|
||||
h += k;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
h += l;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compare right half */
|
||||
for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
|
||||
if (n[k]) {
|
||||
h += k-ms;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
/* Compare left half */
|
||||
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
|
||||
if (k <= mem) return (char *)h;
|
||||
h += p;
|
||||
mem = mem0;
|
||||
}
|
||||
}
|
||||
|
||||
char *strstr(const char *h, const char *n)
|
||||
{
|
||||
/* Return immediately on empty needle */
|
||||
if (!n[0]) return (char *)h;
|
||||
|
||||
/* Use faster algorithms for short needles */
|
||||
h = strchr(h, *n);
|
||||
if (!h || !n[1]) return (char *)h;
|
||||
if (!h[1]) return 0;
|
||||
if (!n[2]) return twobyte_strstr((void *)h, (void *)n);
|
||||
if (!h[2]) return 0;
|
||||
if (!n[3]) return threebyte_strstr((void *)h, (void *)n);
|
||||
if (!h[3]) return 0;
|
||||
if (!n[4]) return fourbyte_strstr((void *)h, (void *)n);
|
||||
|
||||
return twoway_strstr((void *)h, (void *)n);
|
||||
}
|
150
nolibc/strtol.c
Normal file
150
nolibc/strtol.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
/* $OpenBSD: strtol.c,v 1.11 2015/09/13 08:31:48 guenther Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* Convert a string to a long integer.
|
||||
*
|
||||
* Ignores `locale' stuff. Assumes that the upper and lower case
|
||||
* alphabets and digits are each contiguous.
|
||||
*/
|
||||
long
|
||||
strtol(const char *nptr, char **endptr, int base)
|
||||
{
|
||||
const char *s;
|
||||
long acc, cutoff;
|
||||
int c;
|
||||
int neg, any, cutlim;
|
||||
|
||||
/*
|
||||
* Ensure that base is between 2 and 36 inclusive, or the special
|
||||
* value of 0.
|
||||
*/
|
||||
if (base < 0 || base == 1 || base > 36) {
|
||||
if (endptr != 0)
|
||||
*endptr = (char *)nptr;
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip white space and pick up leading +/- sign if any.
|
||||
* If base is 0, allow 0x for hex and 0 for octal, else
|
||||
* assume decimal; if base is already 16, allow 0x.
|
||||
*/
|
||||
s = nptr;
|
||||
do {
|
||||
c = (unsigned char) *s++;
|
||||
} while (isspace(c));
|
||||
if (c == '-') {
|
||||
neg = 1;
|
||||
c = *s++;
|
||||
} else {
|
||||
neg = 0;
|
||||
if (c == '+')
|
||||
c = *s++;
|
||||
}
|
||||
if ((base == 0 || base == 16) &&
|
||||
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
|
||||
/*
|
||||
* Compute the cutoff value between legal numbers and illegal
|
||||
* numbers. That is the largest legal value, divided by the
|
||||
* base. An input number that is greater than this value, if
|
||||
* followed by a legal input character, is too big. One that
|
||||
* is equal to this value may be valid or not; the limit
|
||||
* between valid and invalid numbers is then based on the last
|
||||
* digit. For instance, if the range for longs is
|
||||
* [-2147483648..2147483647] and the input base is 10,
|
||||
* cutoff will be set to 214748364 and cutlim to either
|
||||
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
|
||||
* a value > 214748364, or equal but the next digit is > 7 (or 8),
|
||||
* the number is too big, and we will return a range error.
|
||||
*
|
||||
* Set any if any `digits' consumed; make it negative to indicate
|
||||
* overflow.
|
||||
*/
|
||||
cutoff = neg ? LONG_MIN : LONG_MAX;
|
||||
cutlim = cutoff % base;
|
||||
cutoff /= base;
|
||||
if (neg) {
|
||||
if (cutlim > 0) {
|
||||
cutlim -= base;
|
||||
cutoff += 1;
|
||||
}
|
||||
cutlim = -cutlim;
|
||||
}
|
||||
for (acc = 0, any = 0;; c = (unsigned char) *s++) {
|
||||
if (isdigit(c))
|
||||
c -= '0';
|
||||
else if (isalpha(c))
|
||||
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||
else
|
||||
break;
|
||||
if (c >= base)
|
||||
break;
|
||||
if (any < 0)
|
||||
continue;
|
||||
if (neg) {
|
||||
if (acc < cutoff || (acc == cutoff && c > cutlim)) {
|
||||
any = -1;
|
||||
acc = LONG_MIN;
|
||||
errno = ERANGE;
|
||||
} else {
|
||||
any = 1;
|
||||
acc *= base;
|
||||
acc -= c;
|
||||
}
|
||||
} else {
|
||||
if (acc > cutoff || (acc == cutoff && c > cutlim)) {
|
||||
any = -1;
|
||||
acc = LONG_MAX;
|
||||
errno = ERANGE;
|
||||
} else {
|
||||
any = 1;
|
||||
acc *= base;
|
||||
acc += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (endptr != 0)
|
||||
*endptr = (char *) (any ? s - 1 : nptr);
|
||||
return (acc);
|
||||
}
|
152
nolibc/stubs.c
Normal file
152
nolibc/stubs.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define STUB_ABORT(function) \
|
||||
int __unsup_##function(void) __asm__(#function) __attribute__((noreturn)); \
|
||||
int __unsup_##function(void) \
|
||||
{ \
|
||||
printf("STUB: abort: %s() called\n", #function); \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Warnings are deliberately disabled here to reduce unnecessary verbosity under
|
||||
* normal operation. To enable, replace "called = 1" with "called = 0" and
|
||||
* rebuild.
|
||||
*/
|
||||
#define STUB_WARN_ONCE(type, function, ret) \
|
||||
type __unsup_##function(void) __asm__(#function); \
|
||||
type __unsup_##function(void) \
|
||||
{ \
|
||||
static int called = 1; \
|
||||
if (!called) {\
|
||||
printf("STUB: %s() called\n", #function); \
|
||||
called = 1; \
|
||||
} \
|
||||
errno = ENOSYS; \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define STUB_IGNORE(type, function, ret) \
|
||||
type __unsup_##function(void) __asm__(#function); \
|
||||
type __unsup_##function(void) \
|
||||
{ \
|
||||
errno = ENOSYS; \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
/* stdio.h */
|
||||
STUB_WARN_ONCE(int, fflush, 0);
|
||||
STUB_ABORT(rename);
|
||||
STUB_ABORT(sscanf); /* Used only for parsing OCAMLRUNPARAM, never called */
|
||||
/*
|
||||
* The following stubs are not required by the OCaml runtime, but are
|
||||
* needed to build the freestanding version of GMP used by Mirage.
|
||||
*/
|
||||
STUB_WARN_ONCE(int, fread, 0);
|
||||
STUB_WARN_ONCE(int, getc, EOF);
|
||||
STUB_WARN_ONCE(int, ungetc, EOF);
|
||||
STUB_WARN_ONCE(int, fwrite, 0);
|
||||
STUB_WARN_ONCE(int, fputc, EOF);
|
||||
STUB_WARN_ONCE(int, fputs, EOF);
|
||||
STUB_WARN_ONCE(int, putc, EOF);
|
||||
STUB_WARN_ONCE(int, ferror, 1);
|
||||
STUB_WARN_ONCE(int, fopen, 1);
|
||||
STUB_WARN_ONCE(int, fclose, 1);
|
||||
|
||||
/* stdlib.h */
|
||||
STUB_WARN_ONCE(char *, getenv, NULL);
|
||||
STUB_WARN_ONCE(char *, secure_getenv, NULL);
|
||||
STUB_ABORT(system);
|
||||
|
||||
/* unistd.h */
|
||||
STUB_WARN_ONCE(int, chdir, -1);
|
||||
STUB_ABORT(close);
|
||||
STUB_ABORT(getcwd);
|
||||
STUB_WARN_ONCE(pid_t, getpid, 2);
|
||||
STUB_WARN_ONCE(pid_t, getppid, 1);
|
||||
STUB_IGNORE(int, isatty, 0);
|
||||
STUB_IGNORE(off_t, lseek, -1);
|
||||
STUB_ABORT(read);
|
||||
STUB_IGNORE(int, readlink, -1);
|
||||
STUB_ABORT(unlink);
|
||||
STUB_ABORT(rmdir);
|
||||
STUB_ABORT(ftruncate);
|
||||
STUB_ABORT(execv);
|
||||
|
||||
/* dirent.h */
|
||||
STUB_WARN_ONCE(int, closedir, -1);
|
||||
STUB_WARN_ONCE(void *, opendir, NULL);
|
||||
STUB_WARN_ONCE(struct dirent *, readdir, NULL);
|
||||
|
||||
/* fcntl.h */
|
||||
STUB_ABORT(fcntl);
|
||||
STUB_WARN_ONCE(int, open, -1);
|
||||
|
||||
/* signal.h */
|
||||
STUB_IGNORE(int, setjmp, 0);
|
||||
STUB_ABORT(signal);
|
||||
/*
|
||||
* The following stubs are not required by the OCaml runtime, but are
|
||||
* needed to build the freestanding version of GMP used by Mirage.
|
||||
*/
|
||||
STUB_ABORT(raise);
|
||||
|
||||
/* string.h */
|
||||
STUB_ABORT(strerror);
|
||||
|
||||
/* sys/stat.h */
|
||||
STUB_WARN_ONCE(int, stat, -1);
|
||||
STUB_ABORT(mkdir);
|
||||
|
||||
/* pthread.h */
|
||||
STUB_IGNORE(int, pthread_join, 0);
|
||||
STUB_IGNORE(int, pthread_create, EAGAIN);
|
||||
STUB_IGNORE(int, pthread_attr_init, 0);
|
||||
STUB_ABORT(pthread_cleanup_push);
|
||||
STUB_ABORT(pthread_cleanup_pop);
|
||||
|
||||
/* above that line, for OCaml 5, those are only required (i guess) for the configure step */
|
||||
STUB_IGNORE(int, pthread_mutex_lock, 0);
|
||||
STUB_IGNORE(int, pthread_mutex_trylock, 0);
|
||||
STUB_IGNORE(int, pthread_mutex_unlock, 0);
|
||||
STUB_IGNORE(int, pthread_mutex_destroy, 0);
|
||||
STUB_IGNORE(int, pthread_mutex_init, 0);
|
||||
|
||||
STUB_IGNORE(int, pthread_mutexattr_init, 0);
|
||||
STUB_IGNORE(int, pthread_mutexattr_destroy, 0);
|
||||
STUB_IGNORE(int, pthread_mutexattr_settype, 0);
|
||||
|
||||
STUB_IGNORE(int, pthread_sigmask, 0);
|
||||
|
||||
STUB_IGNORE(int, pthread_equal, 1);
|
||||
|
||||
STUB_IGNORE(int, pthread_condattr_init, 0);
|
||||
/* pthread_condattr_destroy: not used by Ocaml 5 (pthread_condattr_init is only used in
|
||||
ocaml/runtime/platform.c with a function local variable as argument)
|
||||
*/
|
||||
|
||||
STUB_IGNORE(int, pthread_cond_init, 0);
|
||||
STUB_IGNORE(int, pthread_cond_destroy, 0);
|
||||
/* it's possible to create a [Stdlib.Condition.t] but an execution path exists
|
||||
* where we don't really use it. However, OCaml will try to destroy this
|
||||
* [Stdlib.Condition.t] and we must ignore such execution path which is still
|
||||
* safe for unikernels (with one core). The real issue with [pthread_cond_*] is
|
||||
* when we would like to suspend the execution with [pthread_cond_wait] but
|
||||
* [pthread_cond_init] and [pthread_cond_destroy] are safe to just ignore. */
|
||||
STUB_ABORT(pthread_cond_wait);
|
||||
STUB_ABORT(pthread_cond_signal);
|
||||
STUB_IGNORE(int, pthread_cond_broadcast, 0);
|
||||
STUB_ABORT(pthread_self);
|
||||
STUB_ABORT(pthread_detach);
|
||||
|
||||
STUB_IGNORE(int, sigfillset, 0);
|
||||
STUB_ABORT(sigwait);
|
||||
STUB_ABORT(usleep);
|
11
nolibc/sysconf.c
Normal file
11
nolibc/sysconf.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
long sysconf(int x) {
|
||||
switch (x) {
|
||||
case _SC_PAGESIZE: /* _SC_PAGE_SIZE */
|
||||
return OCAML_SOLO5_PAGESIZE;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
47
nolibc/sysdeps.c
Normal file
47
nolibc/sysdeps.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int errno;
|
||||
|
||||
extern void gilbraltar_serial_write(const char *, size_t);
|
||||
extern void gilbraltar_serial_puts(const char *);
|
||||
|
||||
static size_t console_write(FILE *f __attribute__((unused)), const char *str, size_t len) {
|
||||
gilbraltar_serial_write(str, len);
|
||||
return (len);
|
||||
}
|
||||
|
||||
static FILE console = { .write = console_write };
|
||||
FILE *stderr = &console;
|
||||
FILE *stdout = &console;
|
||||
|
||||
ssize_t write(int fd, const void *buf, size_t count) {
|
||||
if (fd == 1 || fd == 2) {
|
||||
gilbraltar_serial_write(buf, count);
|
||||
return (count);
|
||||
}
|
||||
errno = ENOSYS;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void exit(int status) {
|
||||
while (1)
|
||||
__asm__ __volatile("wfi");
|
||||
}
|
||||
|
||||
void abort(void) {
|
||||
gilbraltar_serial_puts("Aborted\r\n");
|
||||
|
||||
while (1)
|
||||
__asm__ __volatile("wfi");
|
||||
}
|
||||
|
||||
#if defined(__aarch64__)
|
||||
int __getauxval(int unused) {
|
||||
errno = ENOENT;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
650
nolibc/vfprintf.c
Normal file
650
nolibc/vfprintf.c
Normal file
|
@ -0,0 +1,650 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Some useful macros */
|
||||
|
||||
#define MAX(a,b) ((a)>(b) ? (a) : (b))
|
||||
#define MIN(a,b) ((a)<(b) ? (a) : (b))
|
||||
|
||||
/* Convenient bit representation for modifier flags, which all fall
|
||||
* within 31 codepoints of the space character. */
|
||||
|
||||
#define ALT_FORM (1U<<'#'-' ')
|
||||
#define ZERO_PAD (1U<<'0'-' ')
|
||||
#define LEFT_ADJ (1U<<'-'-' ')
|
||||
#define PAD_POS (1U<<' '-' ')
|
||||
#define MARK_POS (1U<<'+'-' ')
|
||||
#define GROUPED (1U<<'\''-' ')
|
||||
|
||||
#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
|
||||
|
||||
#if UINT_MAX == ULONG_MAX
|
||||
#define LONG_IS_INT
|
||||
#endif
|
||||
|
||||
#if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX
|
||||
#define ODD_TYPES
|
||||
#endif
|
||||
|
||||
/* State machine to accept length modifiers + conversion specifiers.
|
||||
* Result is 0 on failure, or an argument type to pop on success. */
|
||||
|
||||
enum {
|
||||
BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
|
||||
ZTPRE, JPRE,
|
||||
STOP,
|
||||
PTR, INT, UINT, ULLONG,
|
||||
#ifndef LONG_IS_INT
|
||||
LONG, ULONG,
|
||||
#else
|
||||
#define LONG INT
|
||||
#define ULONG UINT
|
||||
#endif
|
||||
SHORT, USHORT, CHAR, UCHAR,
|
||||
#ifdef ODD_TYPES
|
||||
LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
|
||||
#else
|
||||
#define LLONG ULLONG
|
||||
#define SIZET ULONG
|
||||
#define IMAX LLONG
|
||||
#define UMAX ULLONG
|
||||
#define PDIFF LONG
|
||||
#define UIPTR ULONG
|
||||
#endif
|
||||
DBL, LDBL,
|
||||
NOARG,
|
||||
MAXSTATE
|
||||
};
|
||||
|
||||
#define S(x) [(x)-'A']
|
||||
|
||||
static const unsigned char states[]['z'-'A'+1] = {
|
||||
{ /* 0: bare types */
|
||||
S('d') = INT, S('i') = INT,
|
||||
S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
|
||||
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
|
||||
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
|
||||
S('c') = CHAR, S('C') = INT,
|
||||
S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
|
||||
S('m') = NOARG,
|
||||
S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
|
||||
S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
|
||||
}, { /* 1: l-prefixed */
|
||||
S('d') = LONG, S('i') = LONG,
|
||||
S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
|
||||
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
|
||||
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
|
||||
S('c') = INT, S('s') = PTR, S('n') = PTR,
|
||||
S('l') = LLPRE,
|
||||
}, { /* 2: ll-prefixed */
|
||||
S('d') = LLONG, S('i') = LLONG,
|
||||
S('o') = ULLONG, S('u') = ULLONG,
|
||||
S('x') = ULLONG, S('X') = ULLONG,
|
||||
S('n') = PTR,
|
||||
}, { /* 3: h-prefixed */
|
||||
S('d') = SHORT, S('i') = SHORT,
|
||||
S('o') = USHORT, S('u') = USHORT,
|
||||
S('x') = USHORT, S('X') = USHORT,
|
||||
S('n') = PTR,
|
||||
S('h') = HHPRE,
|
||||
}, { /* 4: hh-prefixed */
|
||||
S('d') = CHAR, S('i') = CHAR,
|
||||
S('o') = UCHAR, S('u') = UCHAR,
|
||||
S('x') = UCHAR, S('X') = UCHAR,
|
||||
S('n') = PTR,
|
||||
}, { /* 5: L-prefixed */
|
||||
S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
|
||||
S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
|
||||
S('n') = PTR,
|
||||
}, { /* 6: z- or t-prefixed (assumed to be same size) */
|
||||
S('d') = PDIFF, S('i') = PDIFF,
|
||||
S('o') = SIZET, S('u') = SIZET,
|
||||
S('x') = SIZET, S('X') = SIZET,
|
||||
S('n') = PTR,
|
||||
}, { /* 7: j-prefixed */
|
||||
S('d') = IMAX, S('i') = IMAX,
|
||||
S('o') = UMAX, S('u') = UMAX,
|
||||
S('x') = UMAX, S('X') = UMAX,
|
||||
S('n') = PTR,
|
||||
}
|
||||
};
|
||||
|
||||
#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
|
||||
|
||||
union arg
|
||||
{
|
||||
uintmax_t i;
|
||||
long double f;
|
||||
void *p;
|
||||
};
|
||||
|
||||
static void pop_arg(union arg *arg, int type, va_list *ap)
|
||||
{
|
||||
/* Give the compiler a hint for optimizing the switch. */
|
||||
if ((unsigned)type > MAXSTATE) return;
|
||||
switch (type) {
|
||||
case PTR: arg->p = va_arg(*ap, void *);
|
||||
break; case INT: arg->i = va_arg(*ap, int);
|
||||
break; case UINT: arg->i = va_arg(*ap, unsigned int);
|
||||
#ifndef LONG_IS_INT
|
||||
break; case LONG: arg->i = va_arg(*ap, long);
|
||||
break; case ULONG: arg->i = va_arg(*ap, unsigned long);
|
||||
#endif
|
||||
break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
|
||||
break; case SHORT: arg->i = (short)va_arg(*ap, int);
|
||||
break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int);
|
||||
break; case CHAR: arg->i = (signed char)va_arg(*ap, int);
|
||||
break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int);
|
||||
#ifdef ODD_TYPES
|
||||
break; case LLONG: arg->i = va_arg(*ap, long long);
|
||||
break; case SIZET: arg->i = va_arg(*ap, size_t);
|
||||
break; case IMAX: arg->i = va_arg(*ap, intmax_t);
|
||||
break; case UMAX: arg->i = va_arg(*ap, uintmax_t);
|
||||
break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t);
|
||||
break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *);
|
||||
#endif
|
||||
break; case DBL: arg->f = va_arg(*ap, double);
|
||||
break; case LDBL: arg->f = va_arg(*ap, long double);
|
||||
}
|
||||
}
|
||||
|
||||
static void out(FILE *f, const char *s, size_t l)
|
||||
{
|
||||
f->write(f, s, l);
|
||||
}
|
||||
|
||||
static void pad(FILE *f, char c, int w, int l, int fl)
|
||||
{
|
||||
char pad[256];
|
||||
if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
|
||||
l = w - l;
|
||||
memset(pad, c, l>sizeof pad ? sizeof pad : l);
|
||||
for (; l >= sizeof pad; l -= sizeof pad)
|
||||
out(f, pad, sizeof pad);
|
||||
out(f, pad, l);
|
||||
}
|
||||
|
||||
static const char xdigits[16] = {
|
||||
"0123456789ABCDEF"
|
||||
};
|
||||
|
||||
static char *fmt_x(uintmax_t x, char *s, int lower)
|
||||
{
|
||||
for (; x; x>>=4) *--s = xdigits[(x&15)]|lower;
|
||||
return s;
|
||||
}
|
||||
|
||||
static char *fmt_o(uintmax_t x, char *s)
|
||||
{
|
||||
for (; x; x>>=3) *--s = '0' + (x&7);
|
||||
return s;
|
||||
}
|
||||
|
||||
static char *fmt_u(uintmax_t x, char *s)
|
||||
{
|
||||
unsigned long y;
|
||||
for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
|
||||
for (y=x; y; y/=10) *--s = '0' + y%10;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Do not override this check. The floating point printing code below
|
||||
* depends on the float.h constants being right. If they are wrong, it
|
||||
* may overflow the stack. */
|
||||
#if LDBL_MANT_DIG == 53
|
||||
typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
|
||||
#endif
|
||||
|
||||
static int fmt_fp(FILE *f, double y, int w, int p, int fl, int t)
|
||||
{
|
||||
uint32_t big[(DBL_MANT_DIG+28)/29 + 1 // mantissa expansion
|
||||
+ (DBL_MAX_EXP+DBL_MANT_DIG+28+8)/9]; // exponent expansion
|
||||
uint32_t *a, *d, *r, *z;
|
||||
int e2=0, e, i, j, l;
|
||||
char buf[9+DBL_MANT_DIG/4], *s;
|
||||
const char *prefix="-0X+0X 0X-0x+0x 0x";
|
||||
int pl;
|
||||
char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
|
||||
|
||||
pl=1;
|
||||
if (signbit(y)) {
|
||||
y=-y;
|
||||
} else if (fl & MARK_POS) {
|
||||
prefix+=3;
|
||||
} else if (fl & PAD_POS) {
|
||||
prefix+=6;
|
||||
} else prefix++, pl=0;
|
||||
|
||||
if (!isfinite(y)) {
|
||||
char *s = (t&32)?"inf":"INF";
|
||||
if (y!=y) s=(t&32)?"nan":"NAN";
|
||||
pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
|
||||
out(f, prefix, pl);
|
||||
out(f, s, 3);
|
||||
pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
|
||||
return MAX(w, 3+pl);
|
||||
}
|
||||
|
||||
y = frexp(y, &e2) * 2;
|
||||
if (y) e2--;
|
||||
|
||||
if ((t|32)=='a') {
|
||||
double round = 8.0;
|
||||
int re;
|
||||
|
||||
if (t&32) prefix += 9;
|
||||
pl += 2;
|
||||
|
||||
if (p<0 || p>=DBL_MANT_DIG/4-1) re=0;
|
||||
else re=DBL_MANT_DIG/4-1-p;
|
||||
|
||||
if (re) {
|
||||
while (re--) round*=16;
|
||||
if (*prefix=='-') {
|
||||
y=-y;
|
||||
y-=round;
|
||||
y+=round;
|
||||
y=-y;
|
||||
} else {
|
||||
y+=round;
|
||||
y-=round;
|
||||
}
|
||||
}
|
||||
|
||||
estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
|
||||
if (estr==ebuf) *--estr='0';
|
||||
*--estr = (e2<0 ? '-' : '+');
|
||||
*--estr = t+('p'-'a');
|
||||
|
||||
s=buf;
|
||||
do {
|
||||
int x=y;
|
||||
*s++=xdigits[x]|(t&32);
|
||||
y=16*(y-x);
|
||||
if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
|
||||
} while (y);
|
||||
|
||||
if (p && s-buf-2 < p)
|
||||
l = (p+2) + (ebuf-estr);
|
||||
else
|
||||
l = (s-buf) + (ebuf-estr);
|
||||
|
||||
pad(f, ' ', w, pl+l, fl);
|
||||
out(f, prefix, pl);
|
||||
pad(f, '0', w, pl+l, fl^ZERO_PAD);
|
||||
out(f, buf, s-buf);
|
||||
pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
|
||||
out(f, estr, ebuf-estr);
|
||||
pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
|
||||
return MAX(w, pl+l);
|
||||
}
|
||||
if (p<0) p=6;
|
||||
|
||||
if (y) y *= 0x1p28, e2-=28;
|
||||
|
||||
if (e2<0) a=r=z=big;
|
||||
else a=r=z=big+sizeof(big)/sizeof(*big) - DBL_MANT_DIG - 1;
|
||||
|
||||
do {
|
||||
*z = y;
|
||||
y = 1000000000*(y-*z++);
|
||||
} while (y);
|
||||
|
||||
while (e2>0) {
|
||||
uint32_t carry=0;
|
||||
int sh=MIN(29,e2);
|
||||
for (d=z-1; d>=a; d--) {
|
||||
uint64_t x = ((uint64_t)*d<<sh)+carry;
|
||||
*d = x % 1000000000;
|
||||
carry = x / 1000000000;
|
||||
}
|
||||
if (carry) *--a = carry;
|
||||
while (z>a && !z[-1]) z--;
|
||||
e2-=sh;
|
||||
}
|
||||
while (e2<0) {
|
||||
uint32_t carry=0, *b;
|
||||
int sh=MIN(9,-e2), need=1+(p+DBL_MANT_DIG/3+8)/9;
|
||||
for (d=a; d<z; d++) {
|
||||
uint32_t rm = *d & (1<<sh)-1;
|
||||
*d = (*d>>sh) + carry;
|
||||
carry = (1000000000>>sh) * rm;
|
||||
}
|
||||
if (!*a) a++;
|
||||
if (carry) *z++ = carry;
|
||||
/* Avoid (slow!) computation past requested precision */
|
||||
b = (t|32)=='f' ? r : a;
|
||||
if (z-b > need) z = b+need;
|
||||
e2+=sh;
|
||||
}
|
||||
|
||||
if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
|
||||
else e=0;
|
||||
|
||||
/* Perform rounding: j is precision after the radix (possibly neg) */
|
||||
j = p - ((t|32)!='f')*e - ((t|32)=='g' && p);
|
||||
if (j < 9*(z-r-1)) {
|
||||
uint32_t x;
|
||||
/* We avoid C's broken division of negative numbers */
|
||||
d = r + 1 + ((j+9*DBL_MAX_EXP)/9 - DBL_MAX_EXP);
|
||||
j += 9*DBL_MAX_EXP;
|
||||
j %= 9;
|
||||
for (i=10, j++; j<9; i*=10, j++);
|
||||
x = *d % i;
|
||||
/* Are there any significant digits past j? */
|
||||
if (x || d+1!=z) {
|
||||
double round = 2/DBL_EPSILON;
|
||||
double small;
|
||||
if (*d/i & 1) round += 2;
|
||||
if (x<i/2) small=0x0.8p0;
|
||||
else if (x==i/2 && d+1==z) small=0x1.0p0;
|
||||
else small=0x1.8p0;
|
||||
if (pl && *prefix=='-') round*=-1, small*=-1;
|
||||
*d -= x;
|
||||
/* Decide whether to round by probing round+small */
|
||||
if (round+small != round) {
|
||||
*d = *d + i;
|
||||
while (*d > 999999999) {
|
||||
*d--=0;
|
||||
if (d<a) *--a=0;
|
||||
(*d)++;
|
||||
}
|
||||
for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
|
||||
}
|
||||
}
|
||||
if (z>d+1) z=d+1;
|
||||
}
|
||||
for (; z>a && !z[-1]; z--);
|
||||
|
||||
if ((t|32)=='g') {
|
||||
if (!p) p++;
|
||||
if (p>e && e>=-4) {
|
||||
t--;
|
||||
p-=e+1;
|
||||
} else {
|
||||
t-=2;
|
||||
p--;
|
||||
}
|
||||
if (!(fl&ALT_FORM)) {
|
||||
/* Count trailing zeros in last place */
|
||||
if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
|
||||
else j=9;
|
||||
if ((t|32)=='f')
|
||||
p = MIN(p,MAX(0,9*(z-r-1)-j));
|
||||
else
|
||||
p = MIN(p,MAX(0,9*(z-r-1)+e-j));
|
||||
}
|
||||
}
|
||||
l = 1 + p + (p || (fl&ALT_FORM));
|
||||
if ((t|32)=='f') {
|
||||
if (e>0) l+=e;
|
||||
} else {
|
||||
estr=fmt_u(e<0 ? -e : e, ebuf);
|
||||
while(ebuf-estr<2) *--estr='0';
|
||||
*--estr = (e<0 ? '-' : '+');
|
||||
*--estr = t;
|
||||
l += ebuf-estr;
|
||||
}
|
||||
|
||||
pad(f, ' ', w, pl+l, fl);
|
||||
out(f, prefix, pl);
|
||||
pad(f, '0', w, pl+l, fl^ZERO_PAD);
|
||||
|
||||
if ((t|32)=='f') {
|
||||
if (a>r) a=r;
|
||||
for (d=a; d<=r; d++) {
|
||||
char *s = fmt_u(*d, buf+9);
|
||||
if (d!=a) while (s>buf) *--s='0';
|
||||
else if (s==buf+9) *--s='0';
|
||||
out(f, s, buf+9-s);
|
||||
}
|
||||
if (p || (fl&ALT_FORM)) out(f, ".", 1);
|
||||
for (; d<z && p>0; d++, p-=9) {
|
||||
char *s = fmt_u(*d, buf+9);
|
||||
while (s>buf) *--s='0';
|
||||
out(f, s, MIN(9,p));
|
||||
}
|
||||
pad(f, '0', p+9, 9, 0);
|
||||
} else {
|
||||
if (z<=a) z=a+1;
|
||||
for (d=a; d<z && p>=0; d++) {
|
||||
char *s = fmt_u(*d, buf+9);
|
||||
if (s==buf+9) *--s='0';
|
||||
if (d!=a) while (s>buf) *--s='0';
|
||||
else {
|
||||
out(f, s++, 1);
|
||||
if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
|
||||
}
|
||||
out(f, s, MIN(buf+9-s, p));
|
||||
p -= buf+9-s;
|
||||
}
|
||||
pad(f, '0', p+18, 18, 0);
|
||||
out(f, estr, ebuf-estr);
|
||||
}
|
||||
|
||||
pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
|
||||
|
||||
return MAX(w, pl+l);
|
||||
}
|
||||
|
||||
static int getint(char **s) {
|
||||
int i;
|
||||
for (i=0; isdigit(**s); (*s)++)
|
||||
i = 10*i + (**s-'0');
|
||||
return i;
|
||||
}
|
||||
|
||||
int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
|
||||
{
|
||||
char *a, *z, *s=(char *)fmt;
|
||||
unsigned l10n=0, fl;
|
||||
int w, p;
|
||||
union arg arg;
|
||||
int argpos;
|
||||
unsigned st, ps;
|
||||
int cnt=0, l=0;
|
||||
int i;
|
||||
char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
|
||||
const char *prefix;
|
||||
int t, pl;
|
||||
|
||||
for (;;) {
|
||||
/* Update output count, end loop when fmt is exhausted */
|
||||
if (cnt >= 0) {
|
||||
if (l > INT_MAX - cnt) {
|
||||
errno = EOVERFLOW;
|
||||
cnt = -1;
|
||||
} else cnt += l;
|
||||
}
|
||||
if (!*s) break;
|
||||
|
||||
/* Handle literal text and %% format specifiers */
|
||||
for (a=s; *s && *s!='%'; s++);
|
||||
for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
|
||||
l = z-a;
|
||||
if (f) out(f, a, l);
|
||||
if (l) continue;
|
||||
|
||||
if (isdigit(s[1]) && s[2]=='$') {
|
||||
l10n=1;
|
||||
argpos = s[1]-'0';
|
||||
s+=3;
|
||||
} else {
|
||||
argpos = -1;
|
||||
s++;
|
||||
}
|
||||
|
||||
/* Read modifier flags */
|
||||
for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
|
||||
fl |= 1U<<*s-' ';
|
||||
|
||||
/* Read field width */
|
||||
if (*s=='*') {
|
||||
if (isdigit(s[1]) && s[2]=='$') {
|
||||
l10n=1;
|
||||
nl_type[s[1]-'0'] = INT;
|
||||
w = nl_arg[s[1]-'0'].i;
|
||||
s+=3;
|
||||
} else if (!l10n) {
|
||||
w = f ? va_arg(*ap, int) : 0;
|
||||
s++;
|
||||
} else return -1;
|
||||
if (w<0) fl|=LEFT_ADJ, w=-w;
|
||||
} else if ((w=getint(&s))<0) return -1;
|
||||
|
||||
/* Read precision */
|
||||
if (*s=='.' && s[1]=='*') {
|
||||
if (isdigit(s[2]) && s[3]=='$') {
|
||||
nl_type[s[2]-'0'] = INT;
|
||||
p = nl_arg[s[2]-'0'].i;
|
||||
s+=4;
|
||||
} else if (!l10n) {
|
||||
p = f ? va_arg(*ap, int) : 0;
|
||||
s+=2;
|
||||
} else return -1;
|
||||
} else if (*s=='.') {
|
||||
s++;
|
||||
p = getint(&s);
|
||||
} else p = -1;
|
||||
|
||||
/* Format specifier state machine */
|
||||
st=0;
|
||||
do {
|
||||
if (OOB(*s)) return -1;
|
||||
ps=st;
|
||||
st=states[st]S(*s++);
|
||||
} while (st-1<STOP);
|
||||
if (!st) return -1;
|
||||
|
||||
/* Check validity of argument type (nl/normal) */
|
||||
if (st==NOARG) {
|
||||
if (argpos>=0) return -1;
|
||||
} else {
|
||||
if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
|
||||
else if (f) pop_arg(&arg, st, ap);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
if (!f) continue;
|
||||
|
||||
z = buf + sizeof(buf);
|
||||
prefix = "-+ 0X0x";
|
||||
pl = 0;
|
||||
t = s[-1];
|
||||
|
||||
/* Transform ls,lc -> S,C */
|
||||
if (ps && (t&15)==3) t&=~32;
|
||||
|
||||
/* - and 0 flags are mutually exclusive */
|
||||
if (fl & LEFT_ADJ) fl &= ~ZERO_PAD;
|
||||
|
||||
switch(t) {
|
||||
case 'n':
|
||||
switch(ps) {
|
||||
case BARE: *(int *)arg.p = cnt; break;
|
||||
case LPRE: *(long *)arg.p = cnt; break;
|
||||
case LLPRE: *(long long *)arg.p = cnt; break;
|
||||
case HPRE: *(unsigned short *)arg.p = cnt; break;
|
||||
case HHPRE: *(unsigned char *)arg.p = cnt; break;
|
||||
case ZTPRE: *(size_t *)arg.p = cnt; break;
|
||||
case JPRE: *(uintmax_t *)arg.p = cnt; break;
|
||||
}
|
||||
continue;
|
||||
case 'p':
|
||||
p = MAX(p, 2*sizeof(void*));
|
||||
t = 'x';
|
||||
fl |= ALT_FORM;
|
||||
case 'x': case 'X':
|
||||
a = fmt_x(arg.i, z, t&32);
|
||||
if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2;
|
||||
if (0) {
|
||||
case 'o':
|
||||
a = fmt_o(arg.i, z);
|
||||
if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1;
|
||||
} if (0) {
|
||||
case 'd': case 'i':
|
||||
pl=1;
|
||||
if (arg.i>INTMAX_MAX) {
|
||||
arg.i=-arg.i;
|
||||
} else if (fl & MARK_POS) {
|
||||
prefix++;
|
||||
} else if (fl & PAD_POS) {
|
||||
prefix+=2;
|
||||
} else pl=0;
|
||||
case 'u':
|
||||
a = fmt_u(arg.i, z);
|
||||
}
|
||||
if (p>=0) fl &= ~ZERO_PAD;
|
||||
if (!arg.i && !p) {
|
||||
a=z;
|
||||
break;
|
||||
}
|
||||
p = MAX(p, z-a + !arg.i);
|
||||
break;
|
||||
case 'c':
|
||||
*(a=z-(p=1))=arg.i;
|
||||
fl &= ~ZERO_PAD;
|
||||
break;
|
||||
case 'm':
|
||||
if (1) a = strerror(errno); else
|
||||
case 's':
|
||||
a = arg.p ? arg.p : "(null)";
|
||||
z = memchr(a, 0, p);
|
||||
if (!z) z=a+p;
|
||||
else p=z-a;
|
||||
fl &= ~ZERO_PAD;
|
||||
break;
|
||||
case 'e': case 'f': case 'g': case 'a':
|
||||
case 'E': case 'F': case 'G': case 'A':
|
||||
l = fmt_fp(f, arg.f, w, p, fl, t);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p < z-a) p = z-a;
|
||||
if (w < pl+p) w = pl+p;
|
||||
|
||||
pad(f, ' ', w, pl+p, fl);
|
||||
out(f, prefix, pl);
|
||||
pad(f, '0', w, pl+p, fl^ZERO_PAD);
|
||||
pad(f, '0', p, z-a, 0);
|
||||
out(f, a, z-a);
|
||||
pad(f, ' ', w, pl+p, fl^LEFT_ADJ);
|
||||
|
||||
l = w;
|
||||
}
|
||||
|
||||
if (f) return cnt;
|
||||
if (!l10n) return 0;
|
||||
|
||||
for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
|
||||
pop_arg(nl_arg+i, nl_type[i], ap);
|
||||
for (; i<=NL_ARGMAX && !nl_type[i]; i++);
|
||||
if (i<=NL_ARGMAX) return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
|
||||
{
|
||||
va_list ap2;
|
||||
int nl_type[NL_ARGMAX+1] = {0};
|
||||
union arg nl_arg[NL_ARGMAX+1];
|
||||
int ret;
|
||||
|
||||
/* the copy allows passing va_list* even if va_list is an array */
|
||||
va_copy(ap2, ap);
|
||||
if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
|
||||
va_end(ap2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
|
||||
va_end(ap2);
|
||||
return ret;
|
||||
}
|
41
nolibc/vsnprintf.c
Normal file
41
nolibc/vsnprintf.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static size_t sn_write(FILE *f, const char *s, size_t l)
|
||||
{
|
||||
size_t k = f->wend - f->wpos;
|
||||
if (k > l) k = l;
|
||||
memcpy(f->wpos, s, k);
|
||||
f->wpos += k;
|
||||
/* pretend to succeed, but discard extra data */
|
||||
return l;
|
||||
}
|
||||
|
||||
int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
|
||||
{
|
||||
int r;
|
||||
char b;
|
||||
FILE f = { .write = sn_write };
|
||||
|
||||
if (n-1 > INT_MAX-1) {
|
||||
if (n) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
s = &b;
|
||||
n = 1;
|
||||
}
|
||||
|
||||
/* Ensure pointers don't wrap if "infinite" n is passed in */
|
||||
if (n > (char *)0+SIZE_MAX-s-1) n = (char *)0+SIZE_MAX-s-1;
|
||||
f.wpos = s;
|
||||
f.wend = (s+n);
|
||||
r = vfprintf(&f, fmt, ap);
|
||||
|
||||
/* Null-terminate, overwriting last char if dest buffer is full */
|
||||
if (n) f.wpos[-(f.wpos == f.wend)] = 0;
|
||||
return r;
|
||||
}
|
7
openlibm/.gitignore
vendored
Normal file
7
openlibm/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
*.o
|
||||
*~
|
||||
*.a
|
||||
*.dll*
|
||||
*.so*
|
||||
*.dylib*
|
||||
*.pc
|
61
openlibm/.mailmap
Normal file
61
openlibm/.mailmap
Normal file
|
@ -0,0 +1,61 @@
|
|||
JuliaLang <julia-dev@googlegroups.com> <julia-dev@googlegroups.com>
|
||||
JuliaLang <julia-dev@googlegroups.com> <julia-math@googlegroups.com>
|
||||
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <jeff.bezanson@gmail.com>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@beagle.darwinproject.mit.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@caspian.caspian.mit.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@evolution.local>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@mathstation045.mit.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@mathstation049.mit.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@mathstation186.mit.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@post.harvard.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@scooby-doo.csail.mit.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@shaggy.csail.mit.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <jeff@lagann.(none)>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <julia@beowulf1.csail.mit.edu>
|
||||
Jeff Bezanson <jeff.bezanson@gmail.com> <vcloud@julia02.domain.local>
|
||||
|
||||
Stefan Karpinski <stefan@karpinski.org> <stefan@karpinski.org>
|
||||
Stefan Karpinski <stefan@karpinski.org> <stefan.karpinski@gmail.com>
|
||||
Stefan Karpinski <stefan@karpinski.org> <stefan.karpinski@post.harvard.edu>
|
||||
|
||||
Viral B. Shah <viral@mayin.org> <viral@mayin.org>
|
||||
Viral B. Shah <viral@mayin.org> <viral@beowulf1.csail.mit.edu>
|
||||
Viral B. Shah <viral@mayin.org> <viral@neumann.cs.ucsb.edu>
|
||||
Viral B. Shah <viral@mayin.org> <viral@ubuntu-VirtualBox.(none)>
|
||||
|
||||
George Xing <gxing@mit.edu> <gxing@mit.edu>
|
||||
George Xing <gxing@mit.edu> <noobiecubie@gmail.com>
|
||||
|
||||
Stephan Boyer <boyers@mit.edu> <boyers@mit.edu>
|
||||
Stephan Boyer <boyers@mit.edu> <stephan@julialang.xvm.mit.edu>
|
||||
Stephan Boyer <boyers@mit.edu> <stephan@ubuntu.(none)>
|
||||
Stephan Boyer <boyers@mit.edu> <stephan@ubuntu.ubuntu-domain>
|
||||
|
||||
Giuseppe Zingales <giuseppe.pet.zingales@gmail.com> <giuseppe.pet.zingales@gmail.com>
|
||||
Giuseppe Zingales <giuseppe.pet.zingales@gmail.com> <g3@ubuntu.ubuntu-domain>
|
||||
|
||||
Jameson Nash <jameson@mit.edu> <jameson@mit.edu>
|
||||
Jameson Nash <jameson@mit.edu> <vtjnash@comcast.net>
|
||||
Jameson Nash <jameson@mit.edu> <vtjnash@gmail.com>
|
||||
|
||||
Alan Edelman <mit.edelman@gmail.com> <mit.edelman@gmail.com>
|
||||
|
||||
PlayMyCode <joe@playmycode.com> <joe@playmycode.com>
|
||||
PlayMyCode <joe@playmycode.com> <hello@playmycode.com>
|
||||
|
||||
Corey M. Hoffstein <corey@hoffstein.com> <corey@hoffstein.com>
|
||||
Corey M. Hoffstein <corey@hoffstein.com> <corey@newfoundresearch.com>
|
||||
|
||||
Stefan Kroboth <stefan.kroboth@gmail.com> <stefan.kroboth@gmail.com>
|
||||
|
||||
Tim Holy <tim.holy@gmail.com> <tim.holy@gmail.com>
|
||||
Tim Holy <tim.holy@gmail.com> <holy@wustl.edu>
|
||||
|
||||
Patrick O'Leary <patrick.oleary@gmail.com> <patrick.oleary@gmail.com>
|
||||
|
||||
Ivan Mantova <horphus@gmail.com> <horphus@gmail.com>
|
||||
|
||||
Keno Fischer <kfischer@college.harvard.edu> <kfischer@college.harvard.edu>
|
||||
Keno Fischer <kfischer@college.harvard.edu> <kfischer+github@college.harvard.edu>
|
||||
Keno Fischer <kfischer@college.harvard.edu> <kenof@stanford.edu>
|
73
openlibm/.travis.yml
Normal file
73
openlibm/.travis.yml
Normal file
|
@ -0,0 +1,73 @@
|
|||
# We require a full (virtual) machine to load the kernel module for
|
||||
# binfmt support, which is needed to test other architectures besides
|
||||
# x86 using qemu user emulation. (This will not work in a container.)
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: c
|
||||
|
||||
script:
|
||||
- make $FLAGS
|
||||
- make check $FLAGS $TEST_FLAGS
|
||||
- make clean && git status --ignored --porcelain && test -z "$(git status --ignored --porcelain)"
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: clang
|
||||
os: linux
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.7
|
||||
packages:
|
||||
- clang-3.7
|
||||
env: FLAGS="CC=clang-3.7 CXX=clang++-3.7"
|
||||
|
||||
- os: osx
|
||||
env: FLAGS="CC=clang"
|
||||
|
||||
- os: linux
|
||||
env: FLAGS="CC=gcc"
|
||||
|
||||
- os: linux
|
||||
env: FLAGS="CC=gcc ARCH=i686" # implies -m32 -march=i686
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
|
||||
- os: linux
|
||||
env: FLAGS="CC=aarch64-linux-gnu-gcc" TEST_FLAGS="LDFLAGS=-static"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-aarch64-linux-gnu
|
||||
- libc6-dev-arm64-cross
|
||||
- qemu-user-static
|
||||
- binfmt-support
|
||||
|
||||
- os: linux
|
||||
env: FLAGS="CC=arm-linux-gnueabihf-gcc" TEST_FLAGS="LDFLAGS=-static"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-arm-linux-gnueabihf
|
||||
- libc6-dev-armhf-cross
|
||||
- qemu-user-static
|
||||
- binfmt-support
|
||||
|
||||
# This works, but only if qemu-user-static is >= v2.4. This is not the
|
||||
# case on the default trusty images, so we add a PPA that has qemu 2.5
|
||||
- os: linux
|
||||
env: FLAGS="CC=powerpc64le-linux-gnu-gcc" TEST_FLAGS="LDFLAGS=-static"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: "ppa:gns3/qemu"
|
||||
packages:
|
||||
- gcc-powerpc64le-linux-gnu
|
||||
- libc6-dev-ppc64el-cross
|
||||
- qemu-user-static
|
||||
- binfmt-support
|
||||
notifications:
|
||||
email: false
|
576
openlibm/CMakeLists.txt
Executable file
576
openlibm/CMakeLists.txt
Executable file
|
@ -0,0 +1,576 @@
|
|||
cmake_minimum_required(VERSION 3.25)
|
||||
|
||||
# Get version string from Make.inc
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/Make.inc" MAKE_FILE)
|
||||
string(REGEX MATCH "VERSION = ([0-9\.]+)" _ ${MAKE_FILE})
|
||||
|
||||
project(openlibm
|
||||
VERSION ${CMAKE_MATCH_1}
|
||||
LANGUAGES C ASM)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
|
||||
|
||||
add_library("${PROJECT_NAME}")
|
||||
|
||||
# Find the relevant folder depending on the architecture
|
||||
set(OPENLIBM_ARCH_FOLDER ${CMAKE_SYSTEM_PROCESSOR})
|
||||
string(TOLOWER "${OPENLIBM_ARCH_FOLDER}" OPENLIBM_ARCH_FOLDER)
|
||||
|
||||
if(${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "x86_64")
|
||||
set(OPENLIBM_ARCH_FOLDER "amd64")
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "arm64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64")
|
||||
set(OPENLIBM_ARCH_FOLDER "aarch64")
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "armv7-a")
|
||||
set(OPENLIBM_ARCH_FOLDER "arm")
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "x86" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "i686")
|
||||
set(OPENLIBM_ARCH_FOLDER "i387")
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc")
|
||||
set(OPENLIBM_ARCH_FOLDER "powerpc")
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64")
|
||||
set(OPENLIBM_ARCH_FOLDER "riscv64")
|
||||
else()
|
||||
message(FATAL_ERROR "${PROJECT_NAME} not set up for detected architecture: ${OPENLIBM_ARCH_FOLDER}")
|
||||
endif()
|
||||
|
||||
|
||||
# Compile flags
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-ffp-contract=off" "-fno-fast-math" "-fno-rounding-math" "-fno-math-errno")
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-fPIC" "-std=c99" "-fno-builtin")
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-Wall" "-Wno-implicit-function-declaration")
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-DASSEMBLER" "-D__BSD_VISIBLE" "-O3")
|
||||
|
||||
# Compiler-specific compile flags
|
||||
if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang")
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-fno-strict-aliasing" "-ffp-exception-behavior=strict")
|
||||
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-fno-gnu89-inline")
|
||||
else()
|
||||
message(FATAL_ERROR "${PROJECT_NAME} not set up to be compiled with ${CMAKE_C_COMPILER_ID}")
|
||||
endif()
|
||||
|
||||
# Architecture-specific compile flags - take advantage of sse on x86
|
||||
if(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387")
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-march=i686" "-m32" "-msse2" "-mfpmath=sse")
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64")
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-m64" "-msse2" "-mfpmath=sse")
|
||||
endif()
|
||||
|
||||
# Suppress warnings if requested
|
||||
if(OPENLIBM_SUPPRESS_WARNINGS)
|
||||
list(APPEND C_ASM_COMPILE_FLAGS "-w")
|
||||
endif()
|
||||
|
||||
# Add compile flags
|
||||
target_compile_options("${PROJECT_NAME}" PUBLIC ${C_ASM_COMPILE_FLAGS})
|
||||
|
||||
# Project Source
|
||||
set(PROJECT_SRC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
# Common
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
# src
|
||||
"${PROJECT_SRC}/src/common.c"
|
||||
"${PROJECT_SRC}/src/e_acos.c"
|
||||
"${PROJECT_SRC}/src/e_acosf.c"
|
||||
"${PROJECT_SRC}/src/e_acosh.c"
|
||||
"${PROJECT_SRC}/src/e_acoshf.c"
|
||||
"${PROJECT_SRC}/src/e_asin.c"
|
||||
"${PROJECT_SRC}/src/e_asinf.c"
|
||||
"${PROJECT_SRC}/src/e_atan2.c"
|
||||
"${PROJECT_SRC}/src/e_atan2f.c"
|
||||
"${PROJECT_SRC}/src/e_atanh.c"
|
||||
"${PROJECT_SRC}/src/e_atanhf.c"
|
||||
"${PROJECT_SRC}/src/e_cosh.c"
|
||||
"${PROJECT_SRC}/src/e_coshf.c"
|
||||
"${PROJECT_SRC}/src/e_exp.c"
|
||||
"${PROJECT_SRC}/src/e_expf.c"
|
||||
"${PROJECT_SRC}/src/e_fmod.c"
|
||||
"${PROJECT_SRC}/src/e_fmodf.c"
|
||||
"${PROJECT_SRC}/src/e_hypot.c"
|
||||
"${PROJECT_SRC}/src/e_hypotf.c"
|
||||
"${PROJECT_SRC}/src/e_j0.c"
|
||||
"${PROJECT_SRC}/src/e_j0f.c"
|
||||
"${PROJECT_SRC}/src/e_j1.c"
|
||||
"${PROJECT_SRC}/src/e_j1f.c"
|
||||
"${PROJECT_SRC}/src/e_jn.c"
|
||||
"${PROJECT_SRC}/src/e_jnf.c"
|
||||
"${PROJECT_SRC}/src/e_lgamma.c"
|
||||
"${PROJECT_SRC}/src/e_lgamma_r.c"
|
||||
"${PROJECT_SRC}/src/e_lgammaf.c"
|
||||
"${PROJECT_SRC}/src/e_lgammaf_r.c"
|
||||
"${PROJECT_SRC}/src/e_log.c"
|
||||
"${PROJECT_SRC}/src/e_log10.c"
|
||||
"${PROJECT_SRC}/src/e_log10f.c"
|
||||
"${PROJECT_SRC}/src/e_log2.c"
|
||||
"${PROJECT_SRC}/src/e_log2f.c"
|
||||
"${PROJECT_SRC}/src/e_logf.c"
|
||||
"${PROJECT_SRC}/src/e_pow.c"
|
||||
"${PROJECT_SRC}/src/e_powf.c"
|
||||
"${PROJECT_SRC}/src/e_remainder.c"
|
||||
"${PROJECT_SRC}/src/e_remainderf.c"
|
||||
"${PROJECT_SRC}/src/e_rem_pio2.c"
|
||||
"${PROJECT_SRC}/src/e_rem_pio2f.c"
|
||||
"${PROJECT_SRC}/src/e_sinh.c"
|
||||
"${PROJECT_SRC}/src/e_sinhf.c"
|
||||
"${PROJECT_SRC}/src/e_sqrt.c"
|
||||
"${PROJECT_SRC}/src/e_sqrtf.c"
|
||||
"${PROJECT_SRC}/src/k_cos.c"
|
||||
"${PROJECT_SRC}/src/k_exp.c"
|
||||
"${PROJECT_SRC}/src/k_expf.c"
|
||||
"${PROJECT_SRC}/src/k_rem_pio2.c"
|
||||
"${PROJECT_SRC}/src/k_sin.c"
|
||||
"${PROJECT_SRC}/src/k_tan.c"
|
||||
"${PROJECT_SRC}/src/k_cosf.c"
|
||||
"${PROJECT_SRC}/src/k_sinf.c"
|
||||
"${PROJECT_SRC}/src/k_tanf.c"
|
||||
"${PROJECT_SRC}/src/s_asinh.c"
|
||||
"${PROJECT_SRC}/src/s_asinhf.c"
|
||||
"${PROJECT_SRC}/src/s_atan.c"
|
||||
"${PROJECT_SRC}/src/s_atanf.c"
|
||||
"${PROJECT_SRC}/src/s_carg.c"
|
||||
"${PROJECT_SRC}/src/s_cargf.c"
|
||||
"${PROJECT_SRC}/src/s_cbrt.c"
|
||||
"${PROJECT_SRC}/src/s_cbrtf.c"
|
||||
"${PROJECT_SRC}/src/s_ceil.c"
|
||||
"${PROJECT_SRC}/src/s_ceilf.c"
|
||||
"${PROJECT_SRC}/src/s_copysign.c"
|
||||
"${PROJECT_SRC}/src/s_copysignf.c"
|
||||
"${PROJECT_SRC}/src/s_cos.c"
|
||||
"${PROJECT_SRC}/src/s_cosf.c"
|
||||
"${PROJECT_SRC}/src/s_csqrt.c"
|
||||
"${PROJECT_SRC}/src/s_csqrtf.c"
|
||||
"${PROJECT_SRC}/src/s_erf.c"
|
||||
"${PROJECT_SRC}/src/s_erff.c"
|
||||
"${PROJECT_SRC}/src/s_exp2.c"
|
||||
"${PROJECT_SRC}/src/s_exp2f.c"
|
||||
"${PROJECT_SRC}/src/s_expm1.c"
|
||||
"${PROJECT_SRC}/src/s_expm1f.c"
|
||||
"${PROJECT_SRC}/src/s_fabs.c"
|
||||
"${PROJECT_SRC}/src/s_fabsf.c"
|
||||
"${PROJECT_SRC}/src/s_fdim.c"
|
||||
"${PROJECT_SRC}/src/s_floor.c"
|
||||
"${PROJECT_SRC}/src/s_floorf.c"
|
||||
"${PROJECT_SRC}/src/s_fmax.c"
|
||||
"${PROJECT_SRC}/src/s_fmaxf.c"
|
||||
"${PROJECT_SRC}/src/s_fmin.c"
|
||||
"${PROJECT_SRC}/src/s_fminf.c"
|
||||
"${PROJECT_SRC}/src/s_fpclassify.c"
|
||||
"${PROJECT_SRC}/src/s_frexp.c"
|
||||
"${PROJECT_SRC}/src/s_frexpf.c"
|
||||
"${PROJECT_SRC}/src/s_ilogb.c"
|
||||
"${PROJECT_SRC}/src/s_ilogbf.c"
|
||||
"${PROJECT_SRC}/src/s_isinf.c"
|
||||
"${PROJECT_SRC}/src/s_isfinite.c"
|
||||
"${PROJECT_SRC}/src/s_isnormal.c"
|
||||
"${PROJECT_SRC}/src/s_isnan.c"
|
||||
"${PROJECT_SRC}/src/s_log1p.c"
|
||||
"${PROJECT_SRC}/src/s_log1pf.c"
|
||||
"${PROJECT_SRC}/src/s_logb.c"
|
||||
"${PROJECT_SRC}/src/s_logbf.c"
|
||||
"${PROJECT_SRC}/src/s_modf.c"
|
||||
"${PROJECT_SRC}/src/s_modff.c"
|
||||
"${PROJECT_SRC}/src/s_nextafter.c"
|
||||
"${PROJECT_SRC}/src/s_nextafterf.c"
|
||||
"${PROJECT_SRC}/src/s_nexttowardf.c"
|
||||
"${PROJECT_SRC}/src/s_remquo.c"
|
||||
"${PROJECT_SRC}/src/s_remquof.c"
|
||||
"${PROJECT_SRC}/src/s_rint.c"
|
||||
"${PROJECT_SRC}/src/s_rintf.c"
|
||||
"${PROJECT_SRC}/src/s_round.c"
|
||||
"${PROJECT_SRC}/src/s_roundf.c"
|
||||
"${PROJECT_SRC}/src/s_scalbln.c"
|
||||
"${PROJECT_SRC}/src/s_scalbn.c"
|
||||
"${PROJECT_SRC}/src/s_scalbnf.c"
|
||||
"${PROJECT_SRC}/src/s_signbit.c"
|
||||
"${PROJECT_SRC}/src/s_signgam.c"
|
||||
"${PROJECT_SRC}/src/s_sin.c"
|
||||
"${PROJECT_SRC}/src/s_sincos.c"
|
||||
"${PROJECT_SRC}/src/s_sinf.c"
|
||||
"${PROJECT_SRC}/src/s_sincosf.c"
|
||||
"${PROJECT_SRC}/src/s_tan.c"
|
||||
"${PROJECT_SRC}/src/s_tanf.c"
|
||||
"${PROJECT_SRC}/src/s_tanh.c"
|
||||
"${PROJECT_SRC}/src/s_tanhf.c"
|
||||
"${PROJECT_SRC}/src/s_tgammaf.c"
|
||||
"${PROJECT_SRC}/src/s_trunc.c"
|
||||
"${PROJECT_SRC}/src/s_truncf.c"
|
||||
"${PROJECT_SRC}/src/s_cpow.c"
|
||||
"${PROJECT_SRC}/src/s_cpowf.c"
|
||||
"${PROJECT_SRC}/src/w_cabs.c"
|
||||
"${PROJECT_SRC}/src/w_cabsf.c"
|
||||
|
||||
"${PROJECT_SRC}/src/s_fma.c"
|
||||
"${PROJECT_SRC}/src/s_fmaf.c"
|
||||
"${PROJECT_SRC}/src/s_lrint.c"
|
||||
"${PROJECT_SRC}/src/s_lrintf.c"
|
||||
"${PROJECT_SRC}/src/s_lround.c"
|
||||
"${PROJECT_SRC}/src/s_lroundf.c"
|
||||
"${PROJECT_SRC}/src/s_llrint.c"
|
||||
"${PROJECT_SRC}/src/s_llrintf.c"
|
||||
"${PROJECT_SRC}/src/s_llround.c"
|
||||
"${PROJECT_SRC}/src/s_llroundf.c"
|
||||
"${PROJECT_SRC}/src/s_nearbyint.c"
|
||||
|
||||
# C99 complex functions
|
||||
"${PROJECT_SRC}/src/s_ccosh.c"
|
||||
"${PROJECT_SRC}/src/s_ccoshf.c"
|
||||
"${PROJECT_SRC}/src/s_cexp.c"
|
||||
"${PROJECT_SRC}/src/s_cexpf.c"
|
||||
"${PROJECT_SRC}/src/s_cimag.c"
|
||||
"${PROJECT_SRC}/src/s_cimagf.c"
|
||||
"${PROJECT_SRC}/src/s_conj.c"
|
||||
"${PROJECT_SRC}/src/s_conjf.c"
|
||||
"${PROJECT_SRC}/src/s_cproj.c"
|
||||
"${PROJECT_SRC}/src/s_cprojf.c"
|
||||
"${PROJECT_SRC}/src/s_creal.c"
|
||||
"${PROJECT_SRC}/src/s_crealf.c"
|
||||
"${PROJECT_SRC}/src/s_csinh.c"
|
||||
"${PROJECT_SRC}/src/s_csinhf.c"
|
||||
"${PROJECT_SRC}/src/s_ctanh.c"
|
||||
"${PROJECT_SRC}/src/s_ctanhf.c"
|
||||
"${PROJECT_SRC}/src/s_cacos.c"
|
||||
"${PROJECT_SRC}/src/s_cacosf.c"
|
||||
"${PROJECT_SRC}/src/s_cacosh.c"
|
||||
"${PROJECT_SRC}/src/s_cacoshf.c"
|
||||
"${PROJECT_SRC}/src/s_casin.c"
|
||||
"${PROJECT_SRC}/src/s_casinf.c"
|
||||
"${PROJECT_SRC}/src/s_casinh.c"
|
||||
"${PROJECT_SRC}/src/s_casinhf.c"
|
||||
"${PROJECT_SRC}/src/s_catan.c"
|
||||
"${PROJECT_SRC}/src/s_catanf.c"
|
||||
"${PROJECT_SRC}/src/s_catanh.c"
|
||||
"${PROJECT_SRC}/src/s_catanhf.c"
|
||||
"${PROJECT_SRC}/src/s_clog.c"
|
||||
"${PROJECT_SRC}/src/s_clogf.c"
|
||||
|
||||
# bsdsrc
|
||||
"${PROJECT_SRC}/bsdsrc/b_exp.c"
|
||||
"${PROJECT_SRC}/bsdsrc/b_log.c"
|
||||
"${PROJECT_SRC}/bsdsrc/b_tgamma.c"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/src/s_nan.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Determine if long double and double are the same size
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles("
|
||||
#include <float.h>
|
||||
#if (LDBL_MANT_DIG == DBL_MANT_DIG)
|
||||
#error \"long double and double are the same size\"
|
||||
#endif
|
||||
int main(void ) { return 0; }
|
||||
" LONG_DOUBLE_NOT_DOUBLE)
|
||||
|
||||
# Add in long double functions for x86, x64 and aarch64
|
||||
if(LONG_DOUBLE_NOT_DOUBLE)
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/src/s_copysignl.c"
|
||||
"${PROJECT_SRC}/src/s_fabsl.c"
|
||||
"${PROJECT_SRC}/src/s_llrintl.c"
|
||||
"${PROJECT_SRC}/src/s_lrintl.c"
|
||||
"${PROJECT_SRC}/src/s_modfl.c"
|
||||
|
||||
"${PROJECT_SRC}/src/e_acosl.c"
|
||||
"${PROJECT_SRC}/src/e_asinl.c"
|
||||
"${PROJECT_SRC}/src/e_atan2l.c"
|
||||
"${PROJECT_SRC}/src/e_fmodl.c"
|
||||
"${PROJECT_SRC}/src/s_fmaxl.c"
|
||||
"${PROJECT_SRC}/src/s_fminl.c"
|
||||
"${PROJECT_SRC}/src/s_ilogbl.c"
|
||||
"${PROJECT_SRC}/src/e_hypotl.c"
|
||||
"${PROJECT_SRC}/src/e_lgammal.c"
|
||||
"${PROJECT_SRC}/src/e_remainderl.c"
|
||||
"${PROJECT_SRC}/src/e_sqrtl.c"
|
||||
"${PROJECT_SRC}/src/s_atanl.c"
|
||||
"${PROJECT_SRC}/src/s_ceill.c"
|
||||
"${PROJECT_SRC}/src/s_cosl.c"
|
||||
"${PROJECT_SRC}/src/s_cprojl.c"
|
||||
"${PROJECT_SRC}/src/s_csqrtl.c"
|
||||
"${PROJECT_SRC}/src/s_floorl.c"
|
||||
"${PROJECT_SRC}/src/s_fmal.c"
|
||||
"${PROJECT_SRC}/src/s_frexpl.c"
|
||||
"${PROJECT_SRC}/src/s_logbl.c"
|
||||
"${PROJECT_SRC}/src/s_nexttoward.c"
|
||||
"${PROJECT_SRC}/src/s_remquol.c"
|
||||
"${PROJECT_SRC}/src/s_roundl.c"
|
||||
"${PROJECT_SRC}/src/s_lroundl.c"
|
||||
"${PROJECT_SRC}/src/s_llroundl.c"
|
||||
"${PROJECT_SRC}/src/s_cpowl.c"
|
||||
"${PROJECT_SRC}/src/s_cargl.c"
|
||||
"${PROJECT_SRC}/src/s_sinl.c"
|
||||
"${PROJECT_SRC}/src/s_sincosl.c"
|
||||
"${PROJECT_SRC}/src/s_tanl.c"
|
||||
"${PROJECT_SRC}/src/s_truncl.c"
|
||||
"${PROJECT_SRC}/src/w_cabsl.c"
|
||||
"${PROJECT_SRC}/src/s_nextafterl.c"
|
||||
"${PROJECT_SRC}/src/s_rintl.c"
|
||||
"${PROJECT_SRC}/src/s_scalbnl.c"
|
||||
"${PROJECT_SRC}/src/polevll.c"
|
||||
"${PROJECT_SRC}/src/s_casinl.c"
|
||||
"${PROJECT_SRC}/src/s_ctanl.c"
|
||||
"${PROJECT_SRC}/src/s_cimagl.c"
|
||||
"${PROJECT_SRC}/src/s_conjl.c"
|
||||
"${PROJECT_SRC}/src/s_creall.c"
|
||||
"${PROJECT_SRC}/src/s_cacoshl.c"
|
||||
"${PROJECT_SRC}/src/s_catanhl.c"
|
||||
"${PROJECT_SRC}/src/s_casinhl.c"
|
||||
"${PROJECT_SRC}/src/s_catanl.c"
|
||||
"${PROJECT_SRC}/src/s_csinl.c"
|
||||
"${PROJECT_SRC}/src/s_cacosl.c"
|
||||
"${PROJECT_SRC}/src/s_cexpl.c"
|
||||
"${PROJECT_SRC}/src/s_csinhl.c"
|
||||
"${PROJECT_SRC}/src/s_ccoshl.c"
|
||||
"${PROJECT_SRC}/src/s_clogl.c"
|
||||
"${PROJECT_SRC}/src/s_ctanhl.c"
|
||||
"${PROJECT_SRC}/src/s_ccosl.c"
|
||||
"${PROJECT_SRC}/src/s_cbrtl.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LONG_DOUBLE_NOT_DOUBLE)
|
||||
if (${OPENLIBM_ARCH_FOLDER} STREQUAL "i387" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
# ld80
|
||||
"${PROJECT_SRC}/ld80/invtrig.c"
|
||||
"${PROJECT_SRC}/ld80/e_acoshl.c"
|
||||
"${PROJECT_SRC}/ld80/e_powl.c"
|
||||
"${PROJECT_SRC}/ld80/k_tanl.c"
|
||||
"${PROJECT_SRC}/ld80/s_exp2l.c"
|
||||
"${PROJECT_SRC}/ld80/e_atanhl.c"
|
||||
"${PROJECT_SRC}/ld80/e_lgammal_r.c"
|
||||
"${PROJECT_SRC}/ld80/e_sinhl.c"
|
||||
"${PROJECT_SRC}/ld80/s_asinhl.c"
|
||||
"${PROJECT_SRC}/ld80/s_expm1l.c"
|
||||
"${PROJECT_SRC}/ld80/e_coshl.c"
|
||||
"${PROJECT_SRC}/ld80/e_log10l.c"
|
||||
"${PROJECT_SRC}/ld80/e_tgammal.c"
|
||||
"${PROJECT_SRC}/ld80/e_expl.c"
|
||||
"${PROJECT_SRC}/ld80/e_log2l.c"
|
||||
"${PROJECT_SRC}/ld80/k_cosl.c"
|
||||
"${PROJECT_SRC}/ld80/s_log1pl.c"
|
||||
"${PROJECT_SRC}/ld80/s_tanhl.c"
|
||||
"${PROJECT_SRC}/ld80/e_logl.c"
|
||||
"${PROJECT_SRC}/ld80/k_sinl.c"
|
||||
"${PROJECT_SRC}/ld80/s_erfl.c"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/ld80/s_nanl.c"
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
if(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
# ld128
|
||||
"${PROJECT_SRC}/ld128/invtrig.c"
|
||||
"${PROJECT_SRC}/ld128/e_acoshl.c"
|
||||
"${PROJECT_SRC}/ld128/e_powl.c"
|
||||
"${PROJECT_SRC}/ld128/k_tanl.c"
|
||||
"${PROJECT_SRC}/ld128/s_exp2l.c"
|
||||
"${PROJECT_SRC}/ld128/e_atanhl.c"
|
||||
"${PROJECT_SRC}/ld128/e_lgammal_r.c"
|
||||
"${PROJECT_SRC}/ld128/e_sinhl.c"
|
||||
"${PROJECT_SRC}/ld128/s_asinhl.c"
|
||||
"${PROJECT_SRC}/ld128/s_expm1l.c"
|
||||
"${PROJECT_SRC}/ld128/e_coshl.c"
|
||||
"${PROJECT_SRC}/ld128/e_log10l.c"
|
||||
"${PROJECT_SRC}/ld128/e_tgammal.c"
|
||||
"${PROJECT_SRC}/ld128/e_expl.c"
|
||||
"${PROJECT_SRC}/ld128/e_log2l.c"
|
||||
"${PROJECT_SRC}/ld128/k_cosl.c"
|
||||
"${PROJECT_SRC}/ld128/s_log1pl.c"
|
||||
"${PROJECT_SRC}/ld128/s_tanhl.c"
|
||||
"${PROJECT_SRC}/ld128/e_logl.c"
|
||||
"${PROJECT_SRC}/ld128/k_sinl.c"
|
||||
"${PROJECT_SRC}/ld128/s_erfl.c"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/ld128/s_nanl.c"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Architecture-specific sources
|
||||
if (${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/amd64/fenv.c"
|
||||
)
|
||||
|
||||
list(APPEND OPENLIBM_ASM_SOURCE
|
||||
"${PROJECT_SRC}/amd64/e_remainder.S"
|
||||
"${PROJECT_SRC}/amd64/e_remainderf.S"
|
||||
"${PROJECT_SRC}/amd64/e_remainderl.S"
|
||||
"${PROJECT_SRC}/amd64/e_sqrt.S"
|
||||
"${PROJECT_SRC}/amd64/e_sqrtf.S"
|
||||
"${PROJECT_SRC}/amd64/e_sqrtl.S"
|
||||
"${PROJECT_SRC}/amd64/s_llrint.S"
|
||||
"${PROJECT_SRC}/amd64/s_llrintf.S"
|
||||
"${PROJECT_SRC}/amd64/s_llrintl.S"
|
||||
"${PROJECT_SRC}/amd64/s_logbl.S"
|
||||
"${PROJECT_SRC}/amd64/s_lrint.S"
|
||||
"${PROJECT_SRC}/amd64/s_lrintf.S"
|
||||
"${PROJECT_SRC}/amd64/s_lrintl.S"
|
||||
"${PROJECT_SRC}/amd64/s_remquo.S"
|
||||
"${PROJECT_SRC}/amd64/s_remquof.S"
|
||||
"${PROJECT_SRC}/amd64/s_remquol.S"
|
||||
"${PROJECT_SRC}/amd64/s_rintl.S"
|
||||
"${PROJECT_SRC}/amd64/s_scalbn.S"
|
||||
"${PROJECT_SRC}/amd64/s_scalbnf.S"
|
||||
"${PROJECT_SRC}/amd64/s_scalbnl.S"
|
||||
"${PROJECT_SRC}/amd64/e_fmod.S"
|
||||
"${PROJECT_SRC}/amd64/e_fmodf.S"
|
||||
"${PROJECT_SRC}/amd64/e_fmodl.S"
|
||||
)
|
||||
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/aarch64/fenv.c"
|
||||
)
|
||||
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "arm")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/${OPENLIBM_ARCH_FOLDER}/fenv.c"
|
||||
)
|
||||
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/i387/fenv.c"
|
||||
)
|
||||
|
||||
list(APPEND OPENLIBM_ASM_SOURCE
|
||||
"${PROJECT_SRC}/i387/e_exp.S"
|
||||
"${PROJECT_SRC}/i387/e_fmod.S"
|
||||
"${PROJECT_SRC}/i387/e_log.S"
|
||||
"${PROJECT_SRC}/i387/e_log10.S"
|
||||
"${PROJECT_SRC}/i387/e_remainder.S"
|
||||
"${PROJECT_SRC}/i387/e_sqrt.S"
|
||||
"${PROJECT_SRC}/i387/s_ceil.S"
|
||||
"${PROJECT_SRC}/i387/s_copysign.S"
|
||||
"${PROJECT_SRC}/i387/s_floor.S"
|
||||
"${PROJECT_SRC}/i387/s_llrint.S"
|
||||
"${PROJECT_SRC}/i387/s_logb.S"
|
||||
"${PROJECT_SRC}/i387/s_lrint.S"
|
||||
"${PROJECT_SRC}/i387/s_remquo.S"
|
||||
"${PROJECT_SRC}/i387/s_rint.S"
|
||||
"${PROJECT_SRC}/i387/s_tan.S"
|
||||
"${PROJECT_SRC}/i387/s_trunc.S"
|
||||
|
||||
# float counterparts
|
||||
"${PROJECT_SRC}/i387/e_log10f.S"
|
||||
"${PROJECT_SRC}/i387/e_logf.S"
|
||||
"${PROJECT_SRC}/i387/e_remainderf.S"
|
||||
"${PROJECT_SRC}/i387/e_sqrtf.S"
|
||||
"${PROJECT_SRC}/i387/s_ceilf.S"
|
||||
"${PROJECT_SRC}/i387/s_copysignf.S"
|
||||
"${PROJECT_SRC}/i387/s_floorf.S"
|
||||
"${PROJECT_SRC}/i387/s_llrintf.S"
|
||||
"${PROJECT_SRC}/i387/s_logbf.S"
|
||||
"${PROJECT_SRC}/i387/s_lrintf.S"
|
||||
"${PROJECT_SRC}/i387/s_remquof.S"
|
||||
"${PROJECT_SRC}/i387/s_rintf.S"
|
||||
"${PROJECT_SRC}/i387/s_truncf.S"
|
||||
|
||||
# long double counterparts
|
||||
"${PROJECT_SRC}/i387/e_remainderl.S"
|
||||
"${PROJECT_SRC}/i387/e_sqrtl.S"
|
||||
"${PROJECT_SRC}/i387/s_ceill.S"
|
||||
"${PROJECT_SRC}/i387/s_copysignl.S"
|
||||
"${PROJECT_SRC}/i387/s_floorl.S"
|
||||
"${PROJECT_SRC}/i387/s_llrintl.S"
|
||||
"${PROJECT_SRC}/i387/s_logbl.S"
|
||||
"${PROJECT_SRC}/i387/s_lrintl.S"
|
||||
"${PROJECT_SRC}/i387/s_remquol.S"
|
||||
"${PROJECT_SRC}/i387/s_rintl.S"
|
||||
"${PROJECT_SRC}/i387/s_truncl.S"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
list(APPEND OPENLIBM_ASM_SOURCE
|
||||
"${PROJECT_SRC}/i387/s_scalbn.S"
|
||||
"${PROJECT_SRC}/i387/s_scalbnf.S"
|
||||
"${PROJECT_SRC}/i387/s_scalbnl.S"
|
||||
)
|
||||
endif()
|
||||
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/powerpc/fenv.c"
|
||||
)
|
||||
elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64")
|
||||
list(APPEND OPENLIBM_C_SOURCE
|
||||
"${PROJECT_SRC}/riscv64/fenv.c")
|
||||
else()
|
||||
message(FATAL_ERROR "${PROJECT_NAME} CMake build is not set up for ${OPENLIBM_ARCH_FOLDER}")
|
||||
endif()
|
||||
|
||||
|
||||
# Filter out C implementation from compilation list if a native implementation exists
|
||||
foreach(FILE_TO_REMOVE ${OPENLIBM_ASM_SOURCE})
|
||||
# Get filename and strip out extension
|
||||
cmake_path(GET FILE_TO_REMOVE FILENAME FILENAME_TO_REMOVE)
|
||||
cmake_path(REMOVE_EXTENSION FILENAME_TO_REMOVE OUTPUT_VARIABLE FILENAME_TO_REMOVE)
|
||||
message(DEBUG "Filename to remove: ${FILENAME_TO_REMOVE}")
|
||||
|
||||
# Go through files and remove one with the same name
|
||||
foreach(CUR_FILE ${OPENLIBM_C_SOURCE})
|
||||
cmake_path(GET CUR_FILE FILENAME CUR_FILENAME)
|
||||
cmake_path(REMOVE_EXTENSION CUR_FILENAME OUTPUT_VARIABLE CUR_FILENAME)
|
||||
|
||||
if(${CUR_FILENAME} STREQUAL ${FILENAME_TO_REMOVE})
|
||||
list(REMOVE_ITEM OPENLIBM_C_SOURCE ${CUR_FILE})
|
||||
message(DEBUG "Removed source file from compilation list: ${CUR_FILE}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
|
||||
# Add sources
|
||||
target_sources("${PROJECT_NAME}" PRIVATE ${OPENLIBM_C_SOURCE}
|
||||
${OPENLIBM_ASM_SOURCE}
|
||||
)
|
||||
|
||||
|
||||
# Include directories
|
||||
list(APPEND OPENLIBM_INCLUDE_DIRS
|
||||
"${PROJECT_SRC}"
|
||||
"${PROJECT_SRC}/include"
|
||||
"${PROJECT_SRC}/${OPENLIBM_ARCH_FOLDER}"
|
||||
"${PROJECT_SRC}/src"
|
||||
)
|
||||
|
||||
if(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc")
|
||||
list(APPEND OPENLIBM_INCLUDE_DIRS "${PROJECT_SRC}/ld80")
|
||||
else()
|
||||
if(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64")
|
||||
list(APPEND OPENLIBM_INCLUDE_DIRS "${PROJECT_SRC}/ld128")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_include_directories("${PROJECT_NAME}" PUBLIC ${OPENLIBM_INCLUDE_DIRS})
|
||||
|
||||
file(GLOB PUBLIC_HEADERS "*.h" "include/*.h" "${OPENLIBM_ARCH_FOLDER}/*.h" "src/*.h")
|
||||
set_target_properties("${PROJECT_NAME}" PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}")
|
||||
install (TARGETS "${PROJECT_NAME}")
|
||||
|
||||
# Can't use configure_file because openlibm.pc.in uses $var instead of CMake configure @var's
|
||||
# Would rather string replace variables here instead of editing .pc.in, because editing .pc.in
|
||||
# might build break autotools build.
|
||||
file(READ "${PROJECT_SRC}/openlibm.pc.in" PC_FILE)
|
||||
string(REPLACE "\${version}" ${CMAKE_PROJECT_VERSION} PC_FILE ${PC_FILE})
|
||||
string(PREPEND PC_FILE "prefix=${CMAKE_INSTALL_PREFIX}
|
||||
includedir=\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}
|
||||
libdir=\${prefix}/${CMAKE_INSTALL_LIBDIR}\n
|
||||
")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc" ${PC_FILE})
|
||||
install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
115
openlibm/LICENSE.md
Normal file
115
openlibm/LICENSE.md
Normal file
|
@ -0,0 +1,115 @@
|
|||
## OpenLibm
|
||||
|
||||
OpenLibm contains code that is covered by various licenses.
|
||||
|
||||
The OpenLibm code derives from the FreeBSD msun and OpenBSD libm
|
||||
implementations, which in turn derives from FDLIBM 5.3. As a result, it
|
||||
has a number of fixes and updates that have accumulated over the years
|
||||
in msun, and also optimized assembly versions of many functions. These
|
||||
improvements are provided under the BSD and ISC licenses. The msun
|
||||
library also includes work placed under the public domain, which is
|
||||
noted in the individual files. Further work on making a standalone
|
||||
OpenLibm library from msun, as part of the Julia project is covered
|
||||
under the MIT license. The test files, test-double.c and test-float.c
|
||||
are under the LGPL.
|
||||
|
||||
## Parts copyrighted by the Julia project (MIT License)
|
||||
|
||||
> Copyright (c) 2011-14 The Julia Project.
|
||||
> https://github.com/JuliaMath/openlibm/graphs/contributors
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining
|
||||
> a copy of this software and associated documentation files (the
|
||||
> "Software"), to deal in the Software without restriction, including
|
||||
> without limitation the rights to use, copy, modify, merge, publish,
|
||||
> distribute, sublicense, and/or sell copies of the Software, and to
|
||||
> permit persons to whom the Software is furnished to do so, subject to
|
||||
> the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be
|
||||
> included in all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## Parts copyrighted by Stephen L. Moshier (ISC License)
|
||||
|
||||
> Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
|
||||
>
|
||||
> Permission to use, copy, modify, and distribute this software for any
|
||||
> purpose with or without fee is hereby granted, provided that the above
|
||||
> copyright notice and this permission notice appear in all copies.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
> OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
## FREEBSD MSUN (FreeBSD/2-clause BSD/Simplified BSD License)
|
||||
|
||||
> Copyright 1992-2011 The FreeBSD Project. All rights reserved.
|
||||
>
|
||||
> 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 FREEBSD PROJECT ``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 FREEBSD PROJECT 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.
|
||||
>
|
||||
> The views and conclusions contained in the software and documentation
|
||||
> are those of the authors and should not be interpreted as representing
|
||||
> official policies, either expressed or implied, of the FreeBSD
|
||||
> Project.
|
||||
|
||||
## FDLIBM
|
||||
|
||||
> Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
>
|
||||
> Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
> Permission to use, copy, modify, and distribute this
|
||||
> software is freely granted, provided that this notice
|
||||
> is preserved.
|
||||
|
||||
## Tests
|
||||
|
||||
> Copyright (C) 1997, 1999 Free Software Foundation, Inc.
|
||||
> This file is part of the GNU C Library.
|
||||
> Contributed by Andreas Jaeger <aj@suse.de>, 1997.
|
||||
>
|
||||
> The GNU C Library is free software; you can redistribute it and/or
|
||||
> modify it under the terms of the GNU Lesser General Public
|
||||
> License as published by the Free Software Foundation; either
|
||||
> version 2.1 of the License, or (at your option) any later version.
|
||||
>
|
||||
> The GNU C Library 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
|
||||
> Lesser General Public License for more details.
|
||||
>
|
||||
> You should have received a copy of the GNU Lesser General Public
|
||||
> License along with the GNU C Library; if not, write to the Free
|
||||
> Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
> 02111-1307 USA.
|
190
openlibm/Make.inc
Normal file
190
openlibm/Make.inc
Normal file
|
@ -0,0 +1,190 @@
|
|||
# -*- mode: makefile-gmake -*-
|
||||
|
||||
# Default build rule for any Makefile in this project: all
|
||||
default: all
|
||||
|
||||
OS := $(shell uname)
|
||||
# Do not forget to bump SOMINOR when changing VERSION,
|
||||
# and SOMAJOR when breaking ABI in a backward-incompatible way
|
||||
VERSION = 0.8.0
|
||||
SOMAJOR = 4
|
||||
SOMINOR = 0
|
||||
DESTDIR =
|
||||
prefix ?= /usr/local
|
||||
bindir ?= $(prefix)/bin
|
||||
libdir ?= $(prefix)/lib
|
||||
includedir ?= $(prefix)/include
|
||||
|
||||
ifeq ($(OS), FreeBSD)
|
||||
pkgconfigdir ?= $(prefix)/libdata/pkgconfig
|
||||
else
|
||||
pkgconfigdir ?= $(libdir)/pkgconfig
|
||||
endif
|
||||
|
||||
# Build with Code Coverage
|
||||
# Only test with Ubuntu + gcc + lcov, may not work for other platform.
|
||||
# deps: https://github.com/linux-test-project/lcov
|
||||
# You don't need to set this flag manually, `make coverage` will do it for you.
|
||||
# Just Run: make clean && make coverage -j
|
||||
CODE_COVERAGE ?= 0
|
||||
|
||||
USEGCC ?= 1
|
||||
USECLANG ?= 0
|
||||
TOOLPREFIX ?=
|
||||
|
||||
ifneq (,$(findstring $(OS),Darwin FreeBSD OpenBSD))
|
||||
USEGCC ?= 0
|
||||
USECLANG ?= 1
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),wasm32)
|
||||
USECLANG = 1
|
||||
USEGCC = 0
|
||||
TOOLPREFIX = llvm-
|
||||
endif
|
||||
|
||||
AR := $(TOOLPREFIX)ar
|
||||
|
||||
ifeq ($(USECLANG),1)
|
||||
USEGCC ?= 0
|
||||
CC = clang
|
||||
CFLAGS_add += -fno-builtin -fno-strict-aliasing
|
||||
endif
|
||||
|
||||
ifeq ($(USEGCC),1)
|
||||
CC := $(TOOLPREFIX)gcc
|
||||
CFLAGS_add += -fno-gnu89-inline -fno-builtin
|
||||
endif
|
||||
|
||||
ARCH ?= $(shell $(CC) -dumpmachine | sed "s/\([^-]*\).*$$/\1/")
|
||||
|
||||
ifeq ($(ARCH),mingw32)
|
||||
$(error "the mingw32 compiler you are using fails the openblas testsuite. please see the Julia README.windows.md document for a replacement")
|
||||
endif
|
||||
|
||||
# OS-specific stuff
|
||||
ifeq ($(ARCH),arm64)
|
||||
override ARCH := aarch64
|
||||
endif
|
||||
ifeq ($(findstring arm,$(ARCH)),arm)
|
||||
override ARCH := arm
|
||||
MARCH ?= armv7-a+fp
|
||||
CFLAGS_add += -mhard-float
|
||||
endif
|
||||
ifeq ($(findstring powerpc,$(ARCH)),powerpc)
|
||||
override ARCH := powerpc
|
||||
endif
|
||||
ifeq ($(findstring ppc,$(ARCH)),ppc)
|
||||
override ARCH := powerpc
|
||||
endif
|
||||
ifeq ($(findstring s390,$(ARCH)),s390)
|
||||
override ARCH := s390
|
||||
endif
|
||||
ifneq ($(filter $(ARCH),i386 i486 i586 i686 i387 i487 i587 i687),)
|
||||
override ARCH := i387
|
||||
MARCH ?= i686
|
||||
endif
|
||||
ifeq ($(ARCH),x86_64)
|
||||
override ARCH := amd64
|
||||
endif
|
||||
ifeq ($(findstring mips,$(ARCH)),mips)
|
||||
override ARCH := mips
|
||||
endif
|
||||
ifeq ($(findstring riscv64,$(ARCH)),riscv64)
|
||||
override ARCH := riscv64
|
||||
endif
|
||||
ifeq ($(findstring loongarch64,$(ARCH)),loongarch64)
|
||||
override ARCH := loongarch64
|
||||
endif
|
||||
|
||||
# If CFLAGS does not contain a -O optimization flag, default to -O3
|
||||
ifeq ($(findstring -O,$(CFLAGS)),)
|
||||
CFLAGS_add += -O3
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring MINGW,$(OS)))
|
||||
override OS=WINNT
|
||||
endif
|
||||
|
||||
#keep these if statements separate
|
||||
ifeq ($(OS), WINNT)
|
||||
SHLIB_EXT = dll
|
||||
SONAME_FLAG =
|
||||
shlibdir = $(bindir)
|
||||
else
|
||||
ifeq ($(OS), Darwin)
|
||||
SHLIB_EXT = dylib
|
||||
SONAME_FLAG = -install_name
|
||||
else
|
||||
SHLIB_EXT = so
|
||||
SONAME_FLAG = -soname
|
||||
endif
|
||||
CFLAGS_add += -fPIC
|
||||
shlibdir = $(libdir)
|
||||
endif
|
||||
|
||||
# Add `-march` to our CFLAGS if it's defined
|
||||
ifneq ($(MARCH),)
|
||||
CFLAGS_arch += -march=$(MARCH)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),i387)
|
||||
CFLAGS_arch += -m32
|
||||
SFLAGS_arch += -m32
|
||||
LDFLAGS_arch += -m32
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),amd64)
|
||||
CFLAGS_arch += -m64
|
||||
SFLAGS_arch += -m64
|
||||
LDFLAGS_arch += -m64
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),wasm32)
|
||||
CFLAGS_arch += -ffreestanding -nostdlib -nostdinc --target=wasm32-unknown-unknown
|
||||
endif
|
||||
|
||||
# Add our "arch"-related FLAGS in. We separate arch-related flags out so that
|
||||
# we can conveniently get at them for targets that don't want the rest of
|
||||
# *FLAGS_add, such as the testing Makefile targets
|
||||
CFLAGS_add += $(CFLAGS_arch)
|
||||
SFLAGS_add += $(SFLAGS_arch)
|
||||
LDFLAGS_add += $(LDFLAGS_arch)
|
||||
|
||||
CFLAGS_add += -std=c99 -Wall -I$(OPENLIBM_HOME) -I$(OPENLIBM_HOME)/include -I$(OPENLIBM_HOME)/$(ARCH) -I$(OPENLIBM_HOME)/src -DASSEMBLER -D__BSD_VISIBLE -Wno-implicit-function-declaration
|
||||
ifneq ($(filter $(ARCH),i387 amd64 powerpc),)
|
||||
CFLAGS_add += -I$(OPENLIBM_HOME)/ld80
|
||||
else
|
||||
ifneq ($(filter $(ARCH),aarch64 riscv64),)
|
||||
CFLAGS_add += -I$(OPENLIBM_HOME)/ld128
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(ARCH),i387 amd64),)
|
||||
# Determines whether `long double` is the same as `double` on this arch.
|
||||
# linux x86_64, for instance, `long double` is 80 bits wide, whereas on macOS aarch64,
|
||||
# `long double` is the same as `double`.
|
||||
LONG_DOUBLE_NOT_DOUBLE := 1
|
||||
else ifeq ($(ARCH), aarch64 riscv64)
|
||||
ifeq ($(filter $(OS),Darwin WINNT),)
|
||||
LONG_DOUBLE_NOT_DOUBLE := 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CODE_COVERAGE),1)
|
||||
CFLAGS_add += -g -O0 --coverage
|
||||
LDFLAGS_add += --coverage
|
||||
endif # CODE_COVERAGE==1
|
||||
|
||||
|
||||
%.c.o: %.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) -c $< -o $@
|
||||
|
||||
%.S.o: %.S
|
||||
$(CC) $(CPPFLAGS) $(SFLAGS) $(SFLAGS_add) $(filter -m% -B% -I% -D%,$(CFLAGS_add)) -c $< -o $@
|
||||
|
||||
|
||||
# Makefile debugging trick:
|
||||
# call print-VARIABLE to see the runtime value of any variable
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
137
openlibm/Makefile
Normal file
137
openlibm/Makefile
Normal file
|
@ -0,0 +1,137 @@
|
|||
OPENLIBM_HOME=$(abspath .)
|
||||
include ./Make.inc
|
||||
|
||||
SUBDIRS = src $(ARCH) bsdsrc
|
||||
ifeq ($(LONG_DOUBLE_NOT_DOUBLE),1)
|
||||
# Add ld80 directory on x86 and x64
|
||||
ifneq ($(filter $(ARCH),i387 amd64),)
|
||||
SUBDIRS += ld80
|
||||
else
|
||||
ifneq ($(filter $(ARCH),aarch64),)
|
||||
SUBDIRS += ld128
|
||||
else
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
define INC_template
|
||||
TEST=test
|
||||
override CUR_SRCS = $(1)_SRCS
|
||||
include $(1)/Make.files
|
||||
SRCS += $$(addprefix $(1)/,$$($(1)_SRCS))
|
||||
endef
|
||||
|
||||
DIR=test
|
||||
|
||||
$(foreach dir,$(SUBDIRS),$(eval $(call INC_template,$(dir))))
|
||||
|
||||
DUPLICATE_NAMES = $(filter $(patsubst %.S,%,$($(ARCH)_SRCS)),$(patsubst %.c,%,$(src_SRCS)))
|
||||
DUPLICATE_SRCS = $(addsuffix .c,$(DUPLICATE_NAMES))
|
||||
|
||||
OBJS = $(patsubst %.f,%.f.o,\
|
||||
$(patsubst %.S,%.S.o,\
|
||||
$(patsubst %.c,%.c.o,$(filter-out $(addprefix src/,$(DUPLICATE_SRCS)),$(SRCS)))))
|
||||
|
||||
# If we're on windows, don't do versioned shared libraries. Also, generate an import library
|
||||
# for the DLL. If we're on OSX, put the version number before the .dylib. Otherwise,
|
||||
# put it after.
|
||||
ifeq ($(OS), WINNT)
|
||||
OLM_MAJOR_MINOR_SHLIB_EXT := $(SHLIB_EXT)
|
||||
LDFLAGS_add += -Wl,--out-implib,libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT).a
|
||||
else
|
||||
ifeq ($(OS), Darwin)
|
||||
OLM_MAJOR_MINOR_SHLIB_EXT := $(SOMAJOR).$(SOMINOR).$(SHLIB_EXT)
|
||||
OLM_MAJOR_SHLIB_EXT := $(SOMAJOR).$(SHLIB_EXT)
|
||||
else
|
||||
OLM_MAJOR_MINOR_SHLIB_EXT := $(SHLIB_EXT).$(SOMAJOR).$(SOMINOR)
|
||||
OLM_MAJOR_SHLIB_EXT := $(SHLIB_EXT).$(SOMAJOR)
|
||||
endif
|
||||
LDFLAGS_add += -Wl,$(SONAME_FLAG),libopenlibm.$(OLM_MAJOR_SHLIB_EXT)
|
||||
endif
|
||||
|
||||
.PHONY: all check test clean distclean \
|
||||
install install-static install-shared install-pkgconfig install-headers
|
||||
|
||||
|
||||
OLM_LIBS := libopenlibm.a
|
||||
ifneq ($(ARCH), wasm32)
|
||||
OLM_LIBS += libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT)
|
||||
endif
|
||||
|
||||
all : $(OLM_LIBS)
|
||||
|
||||
check test: test/test-double test/test-float
|
||||
test/test-double
|
||||
test/test-float
|
||||
|
||||
libopenlibm.a: $(OBJS)
|
||||
$(AR) -rcs libopenlibm.a $(OBJS)
|
||||
|
||||
libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT): $(OBJS)
|
||||
$(CC) -shared $(OBJS) $(LDFLAGS) $(LDFLAGS_add) -o $@
|
||||
ifneq ($(OS),WINNT)
|
||||
ln -sf $@ libopenlibm.$(OLM_MAJOR_SHLIB_EXT)
|
||||
ln -sf $@ libopenlibm.$(SHLIB_EXT)
|
||||
endif
|
||||
|
||||
test/test-double: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT)
|
||||
$(MAKE) -C test test-double
|
||||
|
||||
test/test-float: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT)
|
||||
$(MAKE) -C test test-float
|
||||
|
||||
COVERAGE_DIR:=cov-html
|
||||
COVERAGE_FILE:=$(COVERAGE_DIR)/libopenlibm.info
|
||||
# Gen cov report with: make clean && make coverage -j
|
||||
coverage: clean-coverage
|
||||
mkdir $(COVERAGE_DIR)
|
||||
$(MAKE) test CODE_COVERAGE=1
|
||||
lcov -d amd64 -d bsdsrc -d ld80 -d src \
|
||||
--rc lcov_branch_coverage=1 --capture --output-file $(COVERAGE_FILE)
|
||||
genhtml --legend --branch-coverage \
|
||||
--title "Openlibm commit `git rev-parse HEAD`" \
|
||||
--output-directory $(COVERAGE_DIR)/ \
|
||||
$(COVERAGE_FILE)
|
||||
|
||||
# Zero coverage statistics and Delete report
|
||||
clean-coverage:
|
||||
-lcov -d amd64 -d bsdsrc -d ld80 -d src --zerocounters
|
||||
rm -f ./*/*.gcda
|
||||
rm -rf $(COVERAGE_DIR)/
|
||||
|
||||
clean: clean-coverage
|
||||
rm -f aarch64/*.o amd64/*.o arm/*.o bsdsrc/*.o i387/*.o loongarch64/*.o ld80/*.o ld128/*.o src/*.o powerpc/*.o mips/*.o s390/*.o riscv64/*.o
|
||||
rm -f libopenlibm.a libopenlibm.*$(SHLIB_EXT)*
|
||||
rm -f ./*/*.gcno
|
||||
$(MAKE) -C test clean
|
||||
|
||||
openlibm.pc: openlibm.pc.in Make.inc Makefile
|
||||
echo "version=${VERSION}" > openlibm.pc
|
||||
echo "libdir=$(DESTDIR)$(libdir)" >> openlibm.pc
|
||||
echo "includedir=$(DESTDIR)$(includedir)/openlibm" >> openlibm.pc
|
||||
cat openlibm.pc.in >> openlibm.pc
|
||||
|
||||
install-static: libopenlibm.a
|
||||
mkdir -p $(DESTDIR)$(libdir)
|
||||
cp -RpP -f libopenlibm.a $(DESTDIR)$(libdir)/
|
||||
|
||||
install-shared: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT)
|
||||
mkdir -p $(DESTDIR)$(shlibdir)
|
||||
ifeq ($(OS), WINNT)
|
||||
mkdir -p $(DESTDIR)$(libdir)
|
||||
cp -RpP -f libopenlibm.*$(SHLIB_EXT) $(DESTDIR)$(shlibdir)/
|
||||
cp -RpP -f libopenlibm.*$(SHLIB_EXT).a $(DESTDIR)$(libdir)/
|
||||
else
|
||||
cp -RpP -f libopenlibm.*$(SHLIB_EXT)* $(DESTDIR)$(shlibdir)/
|
||||
endif
|
||||
|
||||
install-pkgconfig: openlibm.pc
|
||||
mkdir -p $(DESTDIR)$(pkgconfigdir)
|
||||
cp -RpP -f openlibm.pc $(DESTDIR)$(pkgconfigdir)/
|
||||
|
||||
install-headers:
|
||||
mkdir -p $(DESTDIR)$(includedir)/openlibm
|
||||
cp -RpP -f include/*.h $(DESTDIR)$(includedir)/openlibm
|
||||
cp -RpP -f src/*.h $(DESTDIR)$(includedir)/openlibm
|
||||
|
||||
install: install-static install-shared install-pkgconfig install-headers
|
71
openlibm/README.md
Normal file
71
openlibm/README.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
# OpenLibm
|
||||
|
||||
[](https://codecov.io/gh/JuliaMath/openlibm)
|
||||
|
||||
[OpenLibm](https://openlibm.org/) is an effort to have a high quality, portable, standalone
|
||||
C mathematical library ([`libm`](http://en.wikipedia.org/wiki/libm)).
|
||||
It can be used standalone in applications and programming language
|
||||
implementations.
|
||||
|
||||
The project was born out of a need to have a good `libm` for the
|
||||
[Julia programming language](http://www.julialang.org) that worked
|
||||
consistently across compilers and operating systems, and in 32-bit and
|
||||
64-bit environments.
|
||||
|
||||
## Platform support
|
||||
|
||||
OpenLibm builds on Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, and
|
||||
DragonFly BSD. It builds with both GCC and clang. Although largely
|
||||
tested and widely used on the x86 and x86-64 architectures, OpenLibm
|
||||
also supports arm, aarch64, ppc64le, mips, wasm32, riscv, s390(x) and
|
||||
loongarch64.
|
||||
|
||||
## Build instructions
|
||||
|
||||
### GNU Make
|
||||
|
||||
1. Use GNU Make to build OpenLibm. This is `make` on most systems, but `gmake` on BSDs.
|
||||
2. Use `make USEGCC=1` to build with GCC. This is the default on
|
||||
Linux and Windows.
|
||||
3. Use `make USECLANG=1` to build with clang. This is the default on OS X, FreeBSD,
|
||||
and OpenBSD.
|
||||
4. Use `make ARCH=wasm32` to build the wasm32 library with clang.
|
||||
5. Architectures are auto-detected. Use `make ARCH=i386` to force a
|
||||
build for i386. Other supported architectures are i486, i586, and
|
||||
i686. GCC 4.8 is the minimum requirement for correct codegen on
|
||||
older 32-bit architectures.
|
||||
|
||||
|
||||
**Cross Build**
|
||||
Take `riscv64` as example:
|
||||
1. install `qemu-riscv64-static`, `gcc-riscv64-linux-gnu`
|
||||
2. Cross build:
|
||||
```sh
|
||||
ARCH=riscv64
|
||||
TRIPLE=$ARCH-linux-gnu
|
||||
make ARCH=$ARCH TOOLPREFIX=$TRIPLE- -j
|
||||
make -C test ARCH=$ARCH TOOLPREFIX=$TRIPLE- -j
|
||||
```
|
||||
|
||||
3. Run test with qemu:
|
||||
```sh
|
||||
qemu-$ARCH-static -L . -L /usr/$TRIPLE/ test/test-float
|
||||
qemu-$ARCH-static -L . -L /usr/$TRIPLE/ test/test-double
|
||||
```
|
||||
|
||||
|
||||
### CMake
|
||||
|
||||
1. Create build directory with `mkdir build` and navigate into it with `cd build`.
|
||||
2. Run CMake to configure project and generate native build system with `cmake /path/to/openlibm/`
|
||||
or generate project with build system of choice e.g. `cmake /path/to/openlib/ -G "MinGW Makefiles"`.
|
||||
3. Build with the build system with `cmake --build .`.
|
||||
|
||||
Default CMake configuration builds a shared library, this can easily be configured using
|
||||
[BUILD_SHARED_LIBS](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html)
|
||||
configuration option.
|
||||
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
PowerPC support for openlibm was graciously sponsored by IBM.
|
1
openlibm/aarch64/Make.files
Normal file
1
openlibm/aarch64/Make.files
Normal file
|
@ -0,0 +1 @@
|
|||
$(CUR_SRCS) = fenv.c
|
51
openlibm/aarch64/fenv.c
Normal file
51
openlibm/aarch64/fenv.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*-
|
||||
* Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 AUTHOR 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 AUTHOR 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.
|
||||
*
|
||||
* $FreeBSD: src/lib/msun/arm/fenv.c,v 1.3 2011/10/16 05:37:56 das Exp $
|
||||
*/
|
||||
|
||||
#include <openlibm_fenv.h>
|
||||
|
||||
#ifdef __GNUC_GNU_INLINE__
|
||||
#error "This file must be compiled with C99 'inline' semantics"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Hopefully the system ID byte is immutable, so it's valid to use
|
||||
* this as a default environment.
|
||||
*/
|
||||
const fenv_t __fe_dfl_env = 0;
|
||||
|
||||
extern inline int feclearexcept(int __excepts);
|
||||
extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
|
||||
extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
|
||||
extern inline int feraiseexcept(int __excepts);
|
||||
extern inline int fetestexcept(int __excepts);
|
||||
extern inline int fegetround(void);
|
||||
extern inline int fesetround(int __round);
|
||||
extern inline int fegetenv(fenv_t *__envp);
|
||||
extern inline int feholdexcept(fenv_t *__envp);
|
||||
extern inline int fesetenv(const fenv_t *__envp);
|
||||
extern inline int feupdateenv(const fenv_t *__envp);
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue