diff --git a/exosphere/sdmmc_test/Makefile b/exosphere/sdmmc_test/Makefile
new file mode 100644
index 000000000..4bfed891e
--- /dev/null
+++ b/exosphere/sdmmc_test/Makefile
@@ -0,0 +1,108 @@
+#---------------------------------------------------------------------------------
+# Define the atmosphere board and cpu
+#---------------------------------------------------------------------------------
+export ATMOSPHERE_BOARD := nx-hac-001
+export ATMOSPHERE_CPU := arm7tdmi
+
+#---------------------------------------------------------------------------------
+# pull in common atmosphere configuration
+#---------------------------------------------------------------------------------
+include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk
+
+#---------------------------------------------------------------------------------
+# no real need to edit anything past this point unless you need to add additional
+# rules for different file extensions
+#---------------------------------------------------------------------------------
+ifneq ($(BUILD),$(notdir $(CURDIR)))
+#---------------------------------------------------------------------------------
+
+export OUTPUT := $(CURDIR)/$(TARGET)
+export TOPDIR := $(CURDIR)
+export DEPSDIR := $(CURDIR)/$(BUILD)
+
+export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
+ $(foreach dir,$(DATA),$(CURDIR)/$(dir))
+
+CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
+CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
+SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
+
+#---------------------------------------------------------------------------------
+# use CXX for linking C++ projects, CC for standard C
+#---------------------------------------------------------------------------------
+ifeq ($(strip $(CPPFILES)),)
+#---------------------------------------------------------------------------------
+ export LD := $(CC)
+#---------------------------------------------------------------------------------
+else
+#---------------------------------------------------------------------------------
+ export LD := $(CXX)
+#---------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------
+
+export OFILES_BIN := $(addsuffix .o,$(BINFILES))
+export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
+export OFILES := $(OFILES_BIN) $(OFILES_SRC)
+export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES))))
+
+export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
+ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+ -I.
+
+export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib -L$(dir)/$(ATMOSPHERE_LIBRARY_DIR))
+
+.PHONY: $(BUILD) clean all
+
+#---------------------------------------------------------------------------------
+all: $(BUILD) check_libexo
+
+$(BUILD): check_libexo
+ @[ -d $@ ] || mkdir -p $@
+ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
+
+check_libexo:
+ @$(MAKE) --no-print-directory -C ../../libraries/libexosphere arm
+
+#---------------------------------------------------------------------------------
+clean:
+ @echo clean ...
+ @rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf *.lz4
+
+#---------------------------------------------------------------------------------
+else
+.PHONY: all
+
+DEPENDS := $(OFILES:.o=.d)
+
+#---------------------------------------------------------------------------------
+# main targets
+#---------------------------------------------------------------------------------
+all : $(OUTPUT).bin
+
+$(OUTPUT).bin : $(OUTPUT).elf
+ $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
+ @echo built ... $(notdir $@)
+
+$(OUTPUT).elf : $(OFILES) ../../../libraries/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a
+
+%.elf:
+ @echo linking $(notdir $@)
+ $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
+ @$(NM) -CSn $@ > $(notdir $*.lst)
+
+$(OFILES_SRC) : $(HFILES_BIN)
+
+#---------------------------------------------------------------------------------
+# you need a rule like this for each extension you use as binary data
+#---------------------------------------------------------------------------------
+%.bin.o %_bin.h: %.bin
+#---------------------------------------------------------------------------------
+ @echo $(notdir $<)
+ @$(bin2o)
+
+-include $(DEPENDS)
+
+#---------------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------------
diff --git a/exosphere/sdmmc_test/sdmmc_test.ld b/exosphere/sdmmc_test/sdmmc_test.ld
new file mode 100644
index 000000000..181d33330
--- /dev/null
+++ b/exosphere/sdmmc_test/sdmmc_test.ld
@@ -0,0 +1,194 @@
+OUTPUT_ARCH(arm)
+ENTRY(_ZN3ams10sdmmc_test5StartEv)
+
+MEMORY
+{
+ NULL : ORIGIN = 0, LENGTH = 4K
+ test_fw : ORIGIN = 0x40010000, LENGTH = 32K
+}
+
+
+SECTIONS
+{
+ /* =========== CODE section =========== */
+ PROVIDE(__start__ = ORIGIN(test_fw));
+ . = __start__;
+ __code_start = . ;
+
+ .crt0 :
+ {
+ KEEP (*(.crt0 .crt0.*))
+ . = ALIGN(8);
+ } >test_fw
+
+ .vectors :
+ {
+ KEEP (*(.vectors .vectors.*))
+ . = ALIGN(8);
+ } >test_fw
+
+ .text :
+ {
+ *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+ *(.text.exit .text.exit.*)
+ *(.text.startup .text.startup.*)
+ *(.text.hot .text.hot.*)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ . = ALIGN(8);
+ } >test_fw
+
+ .init :
+ {
+ KEEP( *(.init) )
+ . = ALIGN(8);
+ } >test_fw
+
+ .plt :
+ {
+ *(.plt)
+ *(.iplt)
+ . = ALIGN(8);
+ } >test_fw
+
+ .fini :
+ {
+ KEEP( *(.fini) )
+ . = ALIGN(8);
+ } >test_fw
+
+
+ /* =========== RODATA section =========== */
+ . = ALIGN(8);
+ __rodata_start = . ;
+
+ .rodata :
+ {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ . = ALIGN(8);
+ } >test_fw
+
+ .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >test_fw
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >test_fw
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >test_fw
+ .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >test_fw
+
+ .hash : { *(.hash) } >test_fw
+
+ /* =========== DATA section =========== */
+ . = ALIGN(8);
+ __data_start = . ;
+
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >test_fw
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >test_fw
+ .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >test_fw
+ .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >test_fw
+
+ .preinit_array ALIGN(8) :
+ {
+ PROVIDE (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE (__preinit_array_end = .);
+ } >test_fw
+
+ .init_array ALIGN(8) :
+ {
+ PROVIDE (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE (__init_array_end = .);
+ } >test_fw
+
+ .fini_array ALIGN(8) :
+ {
+ PROVIDE (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE (__fini_array_end = .);
+ } >test_fw
+
+ .ctors ALIGN(8) :
+ {
+ KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ } >test_fw
+
+ .dtors ALIGN(8) :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ } >test_fw
+
+ __got_start__ = .;
+
+ .got : { *(.got) *(.igot) } >test_fw
+ .got.plt : { *(.got.plt) *(.igot.plt) } >test_fw
+
+ __got_end__ = .;
+
+ .data ALIGN(8) :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ } >test_fw
+
+ __bss_start__ = .;
+ .bss ALIGN(8) :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN(16);
+ } >test_fw
+ __bss_end__ = .;
+
+ __end__ = ABSOLUTE(.) ;
+
+ __total_size__ = (__end__ - __start__);
+
+ __stack_top__ = 0x40031000;
+ __stack_bottom__ = 0x40030000;
+
+ /* ==================
+ ==== Metadata ====
+ ================== */
+
+ /* Discard sections that difficult post-processing */
+ /DISCARD/ : { *(.group .comment .note .interp) }
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+}
\ No newline at end of file
diff --git a/exosphere/sdmmc_test/sdmmc_test.specs b/exosphere/sdmmc_test/sdmmc_test.specs
new file mode 100644
index 000000000..72d846e06
--- /dev/null
+++ b/exosphere/sdmmc_test/sdmmc_test.specs
@@ -0,0 +1,7 @@
+%rename link old_link
+
+*link:
+%(old_link) -T %:getenv(TOPDIR /sdmmc_test.ld) --gc-sections --nmagic -nostdlib -nostartfiles
+
+*startfile:
+crti%O%s crtbegin%O%s
diff --git a/exosphere/sdmmc_test/source/sdmmc_test_main.cpp b/exosphere/sdmmc_test/source/sdmmc_test_main.cpp
new file mode 100644
index 000000000..e03e672d5
--- /dev/null
+++ b/exosphere/sdmmc_test/source/sdmmc_test_main.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 .
+ */
+#include
+
+namespace ams::sdmmc_test {
+
+ namespace {
+
+ constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
+
+ constexpr inline auto Port = sdmmc::Port_Mmc0;
+ alignas(8) constinit u8 g_mmc_work_buffer[sdmmc::MmcWorkBufferSize];
+
+ constexpr inline u32 SectorIndex = 0;
+ constexpr inline u32 SectorCount = 2;
+
+ NORETURN void PmcMainReboot() {
+ /* Write enable to MAIN_RESET. */
+ reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE));
+
+ /* Wait forever until we're reset. */
+ AMS_INFINITE_LOOP();
+ }
+
+ void CheckResult(const Result result) {
+ volatile u32 * const DEBUG = reinterpret_cast(0x4003C000);
+ if (R_FAILED(result)) {
+ DEBUG[1] = result.GetValue();
+ PmcMainReboot();
+ }
+ }
+
+ }
+
+ void Main() {
+ /* Debug signaler. */
+ volatile u32 * const DEBUG = reinterpret_cast(0x4003C000);
+ DEBUG[0] = 0;
+ DEBUG[1] = 0xAAAAAAAA;
+
+ /* Initialize sdmmc library. */
+ sdmmc::Initialize(Port);
+ DEBUG[0] = 1;
+
+ sdmmc::SetMmcWorkBuffer(Port, g_mmc_work_buffer, sizeof(g_mmc_work_buffer));
+ DEBUG[0] = 2;
+
+ Result result = sdmmc::Activate(Port);
+ DEBUG[0] = 3;
+ CheckResult(result);
+
+ /* Select user data partition. */
+ result = sdmmc::SelectMmcPartition(Port, sdmmc::MmcPartition_UserData);
+ DEBUG[0] = 4;
+ CheckResult(result);
+
+ /* Read the first two sectors from disk. */
+ void * const sector_dst = reinterpret_cast(0x40038000);
+ result = sdmmc::Read(sector_dst, SectorCount * sdmmc::SectorSize, Port, SectorIndex, SectorCount);
+ DEBUG[0] = 5;
+ CheckResult(result);
+
+ /* Perform a reboot. */
+ DEBUG[1] = 0;
+ PmcMainReboot();
+ }
+
+ NORETURN void ExceptionHandler() {
+ PmcMainReboot();
+ }
+
+}
+
+namespace ams::diag {
+
+ void AbortImpl() {
+ sdmmc_test::ExceptionHandler();
+ }
+
+}
diff --git a/exosphere/sdmmc_test/source/sdmmc_test_start.s b/exosphere/sdmmc_test/source/sdmmc_test_start.s
new file mode 100644
index 000000000..69c1204f7
--- /dev/null
+++ b/exosphere/sdmmc_test/source/sdmmc_test_start.s
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 .
+ */
+
+.section .crt0.text._ZN3ams10sdmmc_test5StartEv, "ax", %progbits
+.align 3
+.global _ZN3ams10sdmmc_test5StartEv
+_ZN3ams10sdmmc_test5StartEv:
+ /* Switch to system mode, mask all interrupts, clear all flags */
+ msr cpsr_cxsf, #0xDF
+
+ /* Set the stack pointer. */
+ ldr sp, =__stack_top__
+
+ /* Set our link register to the exception handler. */
+ ldr lr, =_ZN3ams10sdmmc_test16ExceptionHandlerEv
+
+ /* Call init array functions. */
+ bl __libc_init_array
+
+ /* Invoke main. */
+ b _ZN3ams10sdmmc_test4MainEv
+
+ /* Infinite loop. */
+ 2: b 2b
\ No newline at end of file
diff --git a/exosphere/warmboot/source/warmboot_start.s b/exosphere/warmboot/source/warmboot_start.s
index 18070e04a..dc6a56c2e 100644
--- a/exosphere/warmboot/source/warmboot_start.s
+++ b/exosphere/warmboot/source/warmboot_start.s
@@ -30,7 +30,7 @@ _ZN3ams8warmboot5StartEv:
/* Invoke main. */
ldr r0, =_metadata
- bl _ZN3ams8warmboot4MainEPKNS0_8MetadataE
+ b _ZN3ams8warmboot4MainEPKNS0_8MetadataE
/* Infinite loop. */
1: b 1b
\ No newline at end of file
diff --git a/libraries/libexosphere/arm.mk b/libraries/libexosphere/arm.mk
index f82386e0f..a9b50909c 100644
--- a/libraries/libexosphere/arm.mk
+++ b/libraries/libexosphere/arm.mk
@@ -112,6 +112,7 @@ $(OFILES) : $(GCH_FILES)
$(OFILES_SRC) : $(HFILES_BIN)
libc.o: CFLAGS += -fno-builtin -fno-lto
+libgcc_division.arch.arm.o: CFLAGS += -fno-builtin -fno-lto
#---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin
diff --git a/libraries/libexosphere/source/libc/libexo_cxx.cpp b/libraries/libexosphere/source/libc/libexo_cxx.cpp
new file mode 100644
index 000000000..64efc6786
--- /dev/null
+++ b/libraries/libexosphere/source/libc/libexo_cxx.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 .
+ */
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* cxx implementation details to be stubbed here, as needed. */
+void __cxa_pure_virtual() { AMS_ABORT("pure virtual function call"); }
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/libraries/libexosphere/source/libc/libgcc_division.arch.arm.c b/libraries/libexosphere/source/libc/libgcc_division.arch.arm.c
new file mode 100644
index 000000000..22bc673a1
--- /dev/null
+++ b/libraries/libexosphere/source/libc/libgcc_division.arch.arm.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ */
+
+/*
+ * Form ABI specifications:
+ * int __aeabi_idiv(int numerator, int denominator);
+ * unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
+ *
+ * typedef struct { int quot; int rem; } idiv_return;
+ * typedef struct { unsigned quot; unsigned rem; } uidiv_return;
+ *
+ * __value_in_regs idiv_return __aeabi_idivmod(int numerator,
+ * int *denominator);
+ * __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator,
+ * unsigned denominator);
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */
+struct qr {
+ unsigned q; /* computed quotient */
+ unsigned r; /* computed remainder */
+ unsigned q_n; /* specficies if quotient shall be negative */
+ unsigned r_n; /* specficies if remainder shall be negative */
+};
+
+static void uint_div_qr(unsigned numerator, unsigned denominator,
+ struct qr *qr);
+
+/* returns in R0 and R1 by tail calling an asm function */
+unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator);
+
+unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
+
+/* returns in R0 and R1 by tail calling an asm function */
+signed __aeabi_idivmod(signed numerator, signed denominator);
+
+signed __aeabi_idiv(signed numerator, signed denominator);
+
+/*
+ * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator)
+ * Numerator and Denominator are received in R0 and R1.
+ * Where __ste_idivmod_ret_t is returned in R0 and R1.
+ *
+ * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator,
+ * unsigned denominator)
+ * Numerator and Denominator are received in R0 and R1.
+ * Where __ste_uidivmod_ret_t is returned in R0 and R1.
+ */
+#ifdef __GNUC__
+signed ret_idivmod_values(signed quotient, signed remainder);
+unsigned ret_uidivmod_values(unsigned quotient, unsigned remainder);
+#else
+#error "Compiler not supported"
+#endif
+
+static void division_qr(unsigned n, unsigned p, struct qr *qr)
+{
+ unsigned i = 1, q = 0;
+ if (p == 0) {
+ qr->r = 0xFFFFFFFF; /* division by 0 */
+ return;
+ }
+
+ while ((p >> 31) == 0) {
+ i = i << 1; /* count the max division steps */
+ p = p << 1; /* increase p until it has maximum size*/
+ }
+
+ while (i > 0) {
+ q = q << 1; /* write bit in q at index (size-1) */
+ if (n >= p)
+ {
+ n -= p;
+ q++;
+ }
+ p = p >> 1; /* decrease p */
+ i = i >> 1; /* decrease remaining size in q */
+ }
+ qr->r = n;
+ qr->q = q;
+}
+
+static void uint_div_qr(unsigned numerator, unsigned denominator, struct qr *qr)
+{
+
+ division_qr(numerator, denominator, qr);
+
+ /* negate quotient and/or remainder according to requester */
+ if (qr->q_n)
+ qr->q = -qr->q;
+ if (qr->r_n)
+ qr->r = -qr->r;
+}
+
+unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return qr.q;
+}
+
+unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return ret_uidivmod_values(qr.q, qr.r);
+}
+
+signed __aeabi_idiv(signed numerator, signed denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ if (((numerator < 0) && (denominator > 0)) ||
+ ((numerator > 0) && (denominator < 0)))
+ qr.q_n = 1; /* quotient shall be negate */
+ if (numerator < 0) {
+ numerator = -numerator;
+ qr.r_n = 1; /* remainder shall be negate */
+ }
+ if (denominator < 0)
+ denominator = -denominator;
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return qr.q;
+}
+
+signed __aeabi_idivmod(signed numerator, signed denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ if (((numerator < 0) && (denominator > 0)) ||
+ ((numerator > 0) && (denominator < 0)))
+ qr.q_n = 1; /* quotient shall be negate */
+ if (numerator < 0) {
+ numerator = -numerator;
+ qr.r_n = 1; /* remainder shall be negate */
+ }
+ if (denominator < 0)
+ denominator = -denominator;
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return ret_idivmod_values(qr.q, qr.r);
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
\ No newline at end of file
diff --git a/libraries/libexosphere/source/libc/libgcc_division_asm.arch.arm.s b/libraries/libexosphere/source/libc/libgcc_division_asm.arch.arm.s
new file mode 100644
index 000000000..a0acbace0
--- /dev/null
+++ b/libraries/libexosphere/source/libc/libgcc_division_asm.arch.arm.s
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ */
+
+/*
+ * signed ret_idivmod_values(signed quot, signed rem);
+ * return quotient and remaining the EABI way (regs r0,r1)
+ */
+.section .text.ret_idivmod_values, "ax", %progbits
+.globl ret_idivmod_values
+.align 0
+.syntax unified
+ret_idivmod_values:
+ bx lr
+.type ret_idivmod_values, %function
+.size ret_idivmod_values, .-ret_idivmod_values
+
+/*
+ * unsigned ret_uidivmod_values(unsigned quot, unsigned rem);
+ * return quotient and remaining the EABI way (regs r0,r1)
+ */
+.section .text.ret_uidivmod_values, "ax", %progbits
+.globl ret_uidivmod_values
+.align 0
+.syntax unified
+ret_uidivmod_values:
+ bx lr
+.type ret_uidivmod_values, %function
+.size ret_uidivmod_values, .-ret_uidivmod_values
diff --git a/libraries/libexosphere/source/libc/libgcc_thumb_case.arch.arm.s b/libraries/libexosphere/source/libc/libgcc_thumb_case.arch.arm.s
new file mode 100644
index 000000000..2658ad61b
--- /dev/null
+++ b/libraries/libexosphere/source/libc/libgcc_thumb_case.arch.arm.s
@@ -0,0 +1,35 @@
+/* Copyright (C) 1995-2018 Free Software Foundation, Inc.
+This file 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, or (at your option) any
+later version.
+This file 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.
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+. */
+
+
+.section .text.__gnu_thumb1_case_uqi, "ax", %progbits
+.globl __gnu_thumb1_case_uqi
+.align 0
+.thumb_func
+.syntax unified
+__gnu_thumb1_case_uqi:
+ push {r1}
+ mov r1, lr
+ lsrs r1, r1, #1
+ lsls r1, r1, #1
+ ldrb r1, [r1, r0]
+ lsls r1, r1, #1
+ add lr, lr, r1
+ pop {r1}
+ bx lr
+.type __gnu_thumb1_case_uqi, %function
+.size __gnu_thumb1_case_uqi, .-__gnu_thumb1_case_uqi