l4re-base-25.08.0

This commit is contained in:
2025-09-12 15:55:45 +02:00
commit d959eaab98
37938 changed files with 9382688 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
requires: drivers_uart libc_minimal l4util cxx_io
requires[arch(arm) || arch(arm64) || arch(riscv)]: libfdt
requires[arch(ppc32)]: drivers_of
optional: gnu-efi zlib libbsd-lite
variants: nofpu
Maintainer: adam@os.inf.tu-dresden.de warg@os.inf.tu-dresden.de

View File

@@ -0,0 +1,56 @@
menu "Bootstrap"
config BOOTSTRAP_ROOTTASK_NX
bool "Support W^X in the root task"
help
Mark the text sections of the root task as non-writeable in the memory
map and mark the data sections as non executable.
This is useful if you want to ensure a requirement to have this
property enforced for the root task. However, be aware that this will
only protect the memory from the binary. Moe will still have large
parts of the memory mapped as both executable and writable due to the
system design.
Also this precludes self-adaptation of Moe when compiled for the wrong
kernel type (virtualization enabled vs. non-virt). So only enable this
when you understand the features limitations and are sure that you
need it.
If you enable this feature and the system fails to boot after loading
Sigma0, ensure the KERNEL_CPU_VIRT option is in sync with the
respective kernel configuration.
If in doubt, choose n.
config BOOTSTRAP_THUMB_ENTRY
bool "Thumb mode entry point"
depends on BUILD_ARCH_arm
help
Assume that bootstrap is started in Thumb mode.
If in doubt, choose n.
config BOOTSTRAP_COMPRESS
bool "Support for compressed modules"
depends on HAVE_BIDPC_ZLIB
help
Allow bootstrap to decompress modules that have been compressed.
Using compressed modules reduces the size of an l4image at the cost of
increased startup time due to the required unpacking.
Modules will not be automatically compressed when building.
config BOOTSTRAP_CHECK_MD5
bool "Enable module integrity check (MD5)"
depends on HAVE_BIDPC_LIBBSD_LITE
help
Enable module integrity check during boot using MD5. Only supported
for modules packed into an l4image.
comment "GZIP/ZLIB decompression not available due to missing zlib package"
depends on !HAVE_BIDPC_ZLIB
source "server/src/platform/Kconfig.s32z"
endmenu

View File

@@ -0,0 +1,42 @@
## This file states the license of this package and possibly its subpackages
## in machine and human readable format. The PackageName refers to the package
## whose license is defined by PackageLicenseConcluded.
## For more information about this file format visit the SPDX website at
## https://spdx.org
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentNamespace: spdx:kernkonzept/bootstrap-06ed57d1-8b41-4651-88f2-3665d521c08f
DocumentName: bootstrap
Creator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
Created: 2018-05-18T00:00:00Z
## Package Information
PackageName: bootstrap
SPDXID: SPDXRef-bootstrap
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
FilesAnalyzed: true
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FileName: ./server/src/gunzip.cc
SPDXID: SPDXRef-bootstrap-gunzip.cc
LicenseConcluded: GPL-2.0-or-later
LicenseInfoInFile: NOASSERTION
FileCopyrightText: 1999 Free Software Foundation, Inc.
FileComment: Only compiled in if the compression feature in bootstrap is enabled
PackageName: bootstrap-libc32
SPDXID: SPDXRef-bootstrap-libc32
PackageFileName: ./server/src/ARCH-amd64/libc32
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
FilesAnalyzed: false
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
## Relationships
Relationship: SPDXRef-bootstrap CONTAINS SPDXRef-bootstrap-libc32

View File

@@ -0,0 +1,4 @@
PKGDIR = .
L4DIR ?= $(PKGDIR)/../..
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,19 @@
# L4Re Bootstrapper
This package contains the boot loader for the L4Re operating system.
# Documentation
This package is part of the L4Re operating system. For documentation and
build instructions see the
[L4Re wiki](https://kernkonzept.com/L4Re/guides/l4re).
# Contributions
We welcome contributions. Please see our contributors guide on
[how to contribute](https://kernkonzept.com/L4Re/contributing/l4re).
# License
Detailed licensing and copyright information can be found in the
[LICENSE](LICENSE.spdx) file.

View File

@@ -0,0 +1,29 @@
# Security Policy
This document outlines security procedures for the open-source projects of the
L4Re Operating System Framework as found on https://github.com/kernkonzept.
# Reporting a vulnerability
Security is very important to us and we take all security vulnerabilities
seriously. Thank you for improving the security of our open source software. If
you have discovered a security issue, we appreciate your efforts and your
responsible disclosure.
Please report a security vulnerability by sending an encrypted email to our
security team using our [public
key](https://www.kernkonzept.com/dl/security-at-kernkonzept.pub)
to **security@kernkonzept.com**. The fingerprint of our public key is
````
C4DC 2909 A22E D080 C012 5373 4055 CBA2 A4FD 855B
````
Please include the following in your report:
* A description of the vulnerability
* Steps to reproduce the vulnerability
A member of Kernkonzept's security team will confirm the vulnerability,
determine its impact, and develop a fix. The fix will be applied to the master
branch, tested, and released.

View File

@@ -0,0 +1,220 @@
// vim: set ft=c: -*- mode: C; -*-
/**
* \page bootstrap Bootstrap, the %L4 kernel bootstrapper
*
* Bootstrap Command Line Options
* ------------------------------
*
* `bootstrap` and the kernel can be configured through command line switches.
* `bootstrap` is responsible for parsing both command lines: `bootstrap`
* options are the ones directly given to bootstrap, whereas kernel options are
* those directly given to the kernel, respectively.
*
* When using Multiboot boot, the first module directly after bootstrap is
* considered the kernel: An example using GRUB2 might look like this:
*
* multiboot /path/to/bootstrap bootstrap -bs-boolean-opt -bs-opt-with-argument=foo
* module /path/to/fiasco fiasco -kernel-opt-with-argument=bar -kernel-boolean-opt
*
* \note The exact way to provide the command line to `bootstrap` is
* platform-dependent. On platforms supporting booting via Multiboot
* Specification the command line can be specified in the boot configuration
* (currently x86/amd64 only, e.g. using GRUB) whereas other platforms need the
* command line to be compiled into the `bootstrap` binary.
*
* \note Platforms utilising flattened device trees usually also allow
* specifying a command line through the DT. This mechanism is **not** currently
* supported in `bootstrap`!
*
* &nbsp; <!-- Don't merge the next note -->
*
* \note `bootstrap` will ignore options it does not understand. For most cases,
* this also holds true if an option's arguments cannot be understood.
*
* ### `bootstrap` options
*
* Command line options directly understood by `bootstrap` itself are as
* follows (passed via `bootstrap` command line):
*
* * `-comirq=<irqno>` (x86/amd64 only)
*
* If serial logging is enabled (default on), `<irqno>` defines which IRQ to
* use for serial port communication. This option is ignored if `-noserial`
* is also specified (see below).
*
* * `-comport=<portspec>` (x86/amd64 only)
*
* If serial logging is enabled (default on), `<portspec>` defines which
* serial port to use, being one of:
*
* - `<number>`
*
* Use legacy port `<number>`, e.g. use `-comport=1` for the port
* commonly known as _COM1_, or
*
* - `pci:<card>:<port>`
*
* Use serial port number `<port>` at PCI card number `<card>`, e.g.
* use `-comport=pci:0:1` for the second port on the first PCI card.
*
* - `pci:probe`
*
* Use this to have `bootstrap` autodiscover all PCI serial lines. On
* each discovered line a message will be displayed, telling the correct
* `<portspec>` to be given to use the respective line.
*
* \note `bootstrap` does not support specifying the serial port's baudrate
* and always uses 115200 bps.
*
* * `-noserial`
*
* Disable serial logging.
*
* * `-wait`
*
* Wait for key press at early startup.
*
* \note This is not to be confused with the kernel's `-wait` option, see
* below.
*
* * `-maxmem=<mbytes>`
*
* Limit the available memory to at most `<mbytes>` MiB.
*
* * `-mem=<size>@<offset>`
*
* Add a region of memory of `<size>` at `<offset>` to the system's memory
* map. Both `<size>` and `<offset>` may be suffixed by either `G`, `M`, or
* `K`/`k` to denote GiB, MiB, or KiB, respectively.
*
* This option may be specified multiple times. If the option is not given,
* a platform-specific method for determining the memory layout will be
* used, if available.
*
* * `-presetmem=<intval>`
*
* Initialise memory regions with `<intval>` before starting the kernel.
*
* * `-modaddr=<paddr>`
*
* Relocate modules to the physical address `<paddr>`. Use this when
* utilising a version of GRUB that lacks support for the `modaddr` command.
*
* ### Kernel Options
*
* Command line options for the kernel (passed on kernel command line, i.e. to
* first module) `bootstrap` understands are as follows.
*
* \note Availability of individual options might depend on used platform and/or
* actual kernel configuration.
*
* * `-wait`
*
* Enter debugger directly after startup, prior to executing any task.
*
* * `-serial_esc`
*
* Enable entering the debugger over serial line by pressing `Esc`.
*
* * `-noserial`
*
* Disable serial logging.
*
* \note If this is given as kernel command line argument, it does not
* affect `bootstrap` but only the kernel.
*
* * `-noscreen`
*
* Disable VGA console.
*
* * `-esc`
*
* Enable entering the debugger by pressing `Esc` on attached
* keyboard.
*
* * `-nojdb`
*
* Disable the kernel debugger.
*
* * `-nohlt`
*
* Enable quirk for broken HLT instruction.
*
* * `-apic`
*
* Use Advanced Programmable Interrupt Controller (APIC) if available and
* known to be well-behaving.
*
* * `-loadcnt`
*
* Use load counter for performance counting.
*
* * `-watchdog`
*
* Enable watchdog timer.
*
* * `-irq0`
*
* Allow IRQ 0 to be used by userland. This enables some sanity checks to
* ensure IRQ 0 is not used by the kernel, e.g. for profiling or scheduling
* purposes. This only has an effect on x86.
*
* * `-nosfn`
*
* Disable SFN (special fully nested) mode of interrupt controller. This
* only has an effect on x86 with PIC8259 interrupt controller.
*
* * `-jdb_never_stop`
*
* Prevent system from stopping to enter JDB. This only has an effect on x86.
*
* * `-kmemsize=<KB>`
*
* Reserve `<KB>` KiB of memory for the kernel.
*
* * `-tbuf_entries=<number>`
*
* Specify the `<number>` of trace buffer entries.
*
* * `-out_buf=<length>`
*
* Specify length of console buffer to be `<length>` bytes.
*
* * `-jdb_cmd=<ctrlseq>`
*
* Execute JDB command sequence `<ctrlseq>` right after start-up. If `-wait`
* is also given, `<ctrlseq>` is executed right before entering JDB.
*
* ### Module options
*
* Bootstrap supports module attributes for sigma0 and the roottask. They need
* to be specified in modules.list, e.g.:
*
* sigma0[attr:nodes=4-7] ...
*
* Attributes are not supported when using multi-boot on platforms that
* support it. The following attributes are supported:
*
* * `nodes`
*
* This is a colon separated list of AMP node ranges. A range can also be a
* single number. Examples:
*
* * `nodes=1` -- Only node 1
* * `nodes=1-3` -- Nodes 1 to 3 (inclusive)
* * `nodes=0:2-3` -- Nodes 0, 2 and 3
*
* If not present, the sigma0/roottask module is applicable to all AMP
* nodes.
*
* * `reloc`
*
* Normally the sigma0 or roottask images are loaded at the preferred load
* address if the RAM is available at the desired location. If this is not
* possible, they will be reloacted to some free RAM region. Setting the
* "reloc" module attribute to a non-empty string will always request the
* dynamic relocation.
*
* This attribute can be used on no-MMU systems to maximize the size of
* contiguous free RAM regions.
*/

View File

@@ -0,0 +1 @@
INPUT += %PKGDIR%/doc/bootstrap.dox

View File

@@ -0,0 +1,4 @@
PKGDIR ?= ..
L4DIR ?= $(PKGDIR)/../..
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2009 Technische Universität Dresden.
* Author(s): Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
/* -*- c -*- */
.globl _start
.p2align 4
_start:
/* The called function expects that the caller had a 16-byte aligned
* stack, has pushed the parameters, re-aligned the stack and then
* performs the call pushing the return address.
* Here we push the 3 parameters, hence we need to subtract 4 from the
* actual value of the stack pointer so that the stack is properly
* aligned before executing the 'call' (push + jmp). */
leal _stack - 4,%esp
pushl %esi /* ptr to real mode */
pushl %eax
pushl %ebx
pushl $0 /* no return address */
jmp bootstrap
.align 4
/* MultiBoot header - see multiboot.h. */
.p2align(2), 0x90
#define MULTIBOOT_MEMORY_INFO 0x00000002
_mb_header:
.long 0x1BADB002 /* magic */
.long MULTIBOOT_MEMORY_INFO /* flags */
.long 0 - 0x1BADB002 - MULTIBOOT_MEMORY_INFO
.bss
.p2align 4
.space 8192
.globl _stack
_stack:

View File

@@ -0,0 +1,477 @@
/*
* Copyright (C) 2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "types.h"
#include "boot_cpu.h"
#include "cpu_info.h"
#include "paging.h"
#include "support.h"
unsigned KERNEL_CS_64 = 0x20; // XXX
// enum of 32-bit size members
enum
{
CR0_PG = 0x80000000,
CR4_PSE = 1U << 4,
CR4_PAE = 1U << 5,
CR4_OSFXSR = 1U << 9,
EFL_AC = 0x00040000,
EFL_ID = 0x00200000,
EFER_LME = 0x00000100,
BASE_TSS = 0x08,
KERNEL_CS = 0x10,
KERNEL_DS = 0x18,
DBF_TSS = 0x28, // XXX check this value
ACC_TSS = 0x09,
ACC_TSS_BUSY = 0x02,
ACC_CODE_R = 0x1a,
ACC_DATA_W = 0x12,
ACC_PL_K = 0x00,
ACC_P = 0x80,
SZ_32 = 0x4,
SZ_16 = 0x0,
SZ_G = 0x8,
SZ_CODE_64 = 0x2, // XXX 64 Bit Code Segment
GDTSZ = (0x30/8), // XXX check this value
IDTSZ = 256,
};
struct pseudo_descriptor
{
l4_uint16_t pad;
l4_uint16_t limit;
l4_uint32_t linear_base;
};
struct x86_desc
{
l4_uint16_t limit_low; /* limit 0..15 */
l4_uint16_t base_low; /* base 0..15 */
l4_uint8_t base_med; /* base 16..23 */
l4_uint8_t access; /* access byte */
l4_uint8_t limit_high:4; /* limit 16..19 */
l4_uint8_t granularity:4; /* granularity */
l4_uint8_t base_high; /* base 24..31 */
} __attribute__((packed));
struct x86_gate
{
l4_uint16_t offset_low; /* offset 0..15 */
l4_uint16_t selector;
l4_uint8_t word_count;
l4_uint8_t access;
l4_uint16_t offset_high; /* offset 16..31 */
} __attribute__((packed));
struct x86_tss
{
l4_uint32_t back_link;
l4_uint32_t esp0, ss0;
l4_uint32_t esp1, ss1;
l4_uint32_t esp2, ss2;
l4_uint32_t cr3;
l4_uint32_t eip, eflags;
l4_uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
l4_uint32_t es, cs, ss, ds, fs, gs;
l4_uint32_t ldt;
l4_uint16_t trace_trap;
l4_uint16_t io_bit_map_offset;
};
struct gate_init_entry
{
l4_uint32_t entrypoint;
l4_uint16_t vector;
l4_uint16_t type;
};
struct trap_state
{
l4_uint32_t gs, fs, es, ds;
l4_uint32_t edi, esi, ebp, cr2, ebx, edx, ecx, eax;
l4_uint32_t trapno, err;
l4_uint32_t eip, cs, eflags, esp, ss;
};
static l4_uint32_t base_pml4_pa;
static struct x86_tss base_tss;
static struct x86_desc base_gdt[GDTSZ];
static struct x86_gate base_idt[IDTSZ];
static void handle_dbf(void);
static char dbf_stack[2048];
static struct x86_tss dbf_tss =
{
0/*back_link*/,
0/*esp0*/, 0/*ss0*/, 0/*esp1*/, 0/*ss1*/, 0/*esp2*/, 0/*ss2*/,
0/*cr3*/,
(l4_uint32_t)handle_dbf/*eip*/, 0x00000082/*eflags*/,
0/*eax*/, 0/*ecx*/, 0/*edx*/, 0/*ebx*/,
(l4_uint32_t)dbf_stack + sizeof(dbf_stack)/*esp*/,
0/*ebp*/, 0/*esi*/, 0/*edi*/,
KERNEL_DS/*es*/, KERNEL_CS/*cs*/, KERNEL_DS/*ss*/,
KERNEL_DS/*ds*/, KERNEL_DS/*fs*/, KERNEL_DS/*gs*/,
0/*ldt*/, 0/*trace_trap*/, 0x8000/*io_bit_map_offset*/
};
static inline l4_uint32_t get_eflags(void)
{ l4_uint32_t efl; asm volatile("pushf ; popl %0" : "=r" (efl)); return efl; }
static inline void set_eflags(l4_uint32_t efl)
{ asm volatile("pushl %0 ; popf" : : "r" (efl) : "memory"); }
static inline void set_ds(l4_uint16_t ds)
{ asm volatile("movw %w0,%%ds" : : "r" (ds)); }
static inline void set_es(l4_uint16_t es)
{ asm volatile("movw %w0,%%es" : : "r" (es)); }
static inline void set_fs(l4_uint16_t fs)
{ asm volatile("movw %w0,%%fs" : : "r" (fs)); }
static inline void set_gs(l4_uint16_t gs)
{ asm volatile("movw %w0,%%gs" : : "r" (gs)); }
static inline void set_ss(l4_uint16_t ss)
{ asm volatile("movw %w0,%%ss" : : "r" (ss)); }
static inline l4_uint16_t get_ss(void)
{ l4_uint16_t ss; asm volatile("movw %%ss,%w0" : "=r" (ss)); return ss; }
#define set_idt(pseudo_desc) \
asm volatile("lidt %0" : : "m" ((pseudo_desc)->limit) : "memory")
#define set_gdt(pseudo_desc) \
asm volatile("lgdt %0" : : "m" ((pseudo_desc)->limit) : "memory")
#define set_tr(seg) \
asm volatile("ltr %0" : : "rm" ((l4_uint16_t)(seg)))
#define get_esp() \
({ register l4_uint32_t _temp__; \
asm("movl %%esp, %0" : "=r" (_temp__)); _temp__; })
#define get_cr0() \
({ register l4_uint32_t _temp__; \
asm volatile("mov %%cr0, %0" : "=r" (_temp__)); _temp__; })
#define set_cr3(value) \
({ register l4_uint32_t _temp__ = (value); \
asm volatile("mov %0, %%cr3" : : "r" (_temp__)); })
#define get_cr4() \
({ register l4_uint32_t _temp__; \
asm volatile("mov %%cr4, %0" : "=r" (_temp__)); _temp__; })
#define set_cr4(value) \
({ register l4_uint32_t _temp__ = (value); \
asm volatile("mov %0, %%cr4" : : "r" (_temp__)); })
static inline void enable_longmode(void)
{
l4_uint32_t dummy;
asm volatile("rdmsr; bts $8, %%eax; wrmsr"
:"=a"(dummy), "=d"(dummy) : "c"(0xc0000080));
}
static inline void
fill_descriptor(struct x86_desc *desc, l4_uint32_t base, l4_uint32_t limit,
l4_uint8_t access, l4_uint8_t sizebits)
{
if (limit > 0xfffff)
{
limit >>= 12;
sizebits |= SZ_G;
}
desc->limit_low = limit & 0xffff;
desc->base_low = base & 0xffff;
desc->base_med = (base >> 16) & 0xff;
desc->access = access | ACC_P;
desc->limit_high = limit >> 16;
desc->granularity = sizebits;
desc->base_high = base >> 24;
}
static inline void
fill_gate(struct x86_gate *gate, l4_uint32_t offset,
l4_uint16_t selector, l4_uint8_t access)
{
gate->offset_low = offset & 0xffff;
gate->selector = selector;
gate->word_count = 0;
gate->access = access | ACC_P;
gate->offset_high = (offset >> 16) & 0xffff;
}
static inline void
paging_enable(l4_uint32_t pml4)
{
/* Enable Physical l4_uint64_t Extension (PAE). */
set_cr4(get_cr4() | CR4_PAE);
/* Load the page map level 4. */
set_cr3(pml4);
/* Enable long mode. */
enable_longmode();
/* Turn on paging and switch to long mode. */
asm volatile("movl %0,%%cr0 ; jmp 1f ; 1:" : : "r" (get_cr0() | CR0_PG));
}
static void
cpuid(void)
{
int orig_eflags = get_eflags();
/* Check for a dumb old 386 by trying to toggle the AC flag. */
set_eflags(orig_eflags ^ EFL_AC);
if ((get_eflags() ^ orig_eflags) & EFL_AC)
{
/* It's a 486 or better. Now try toggling the ID flag. */
set_eflags(orig_eflags ^ EFL_ID);
if ((get_eflags() ^ orig_eflags) & EFL_ID)
{
init_cpu_info();
}
}
set_eflags(orig_eflags);
}
static void
sse_enable(void)
{
/*
* Intel manual:
* - "SSE instructions cannot be used unless XR4.OSFXSR = 1.
* - CPUID.01H: EDX.FXSR[bit 24]: "... Presence of this bit also indicates
* that CR4.OSFXSR is available for an operating system to indicate that it
* supports the FXSAVE/FXRSTOR instructions."
* - CPUID.01H: EDX.SSE[bit 25]: "The processor supports SSE extensions."
*
* So it seem that CPUID.01H/EDX.FXSR is sufficient to signal the presence of
* CR4.OSFXSR while CPUID.01H/EDX.SSE is required to set this bit.
*/
if (cpu_info.feature_flags & (1 << 25))
set_cr4(get_cr4() | CR4_OSFXSR);
}
extern struct gate_init_entry boot_idt_inittab[];
static void
base_idt_init(void)
{
struct x86_gate *dst = base_idt;
const struct gate_init_entry *src = boot_idt_inittab;
while (src->entrypoint)
{
if ((src->type & 0x1f) == 0x05)
// task gate
fill_gate(&dst[src->vector], 0, src->entrypoint, src->type);
else
// interrupt gate
fill_gate(&dst[src->vector], src->entrypoint, KERNEL_CS, src->type);
src++;
}
}
static void
base_gdt_init(void)
{
/* Initialize the base TSS descriptor. */
fill_descriptor(&base_gdt[BASE_TSS / 8],
(l4_uint32_t)&base_tss, sizeof(base_tss) - 1,
ACC_PL_K | ACC_TSS, 0);
/* Initialize the TSS descriptor for the double fault handler */
fill_descriptor(&base_gdt[DBF_TSS / 8],
(l4_uint32_t)&dbf_tss, sizeof(dbf_tss) - 1,
ACC_PL_K | ACC_TSS, 0);
/* Initialize the 32-bit kernel code and data segment descriptors
to point to the base of the kernel linear space region. */
fill_descriptor(&base_gdt[KERNEL_CS / 8], 0, 0xffffffff,
ACC_PL_K | ACC_CODE_R, SZ_32);
fill_descriptor(&base_gdt[KERNEL_DS / 8], 0, 0xffffffff,
ACC_PL_K | ACC_DATA_W, SZ_32);
/* XXX Initialize the 64-bit kernel code segment descriptor */
fill_descriptor(&base_gdt[KERNEL_CS_64 / 8], 0, 0xffffffff,
ACC_PL_K | ACC_CODE_R, SZ_CODE_64);
}
static void
base_tss_init(void)
{
base_tss.ss0 = KERNEL_DS;
base_tss.esp0 = get_esp(); /* only temporary */
base_tss.io_bit_map_offset = sizeof(base_tss);
}
static void
base_gdt_load(void)
{
struct pseudo_descriptor pdesc;
/* Create a pseudo-descriptor describing the GDT. */
pdesc.limit = sizeof(base_gdt) - 1;
pdesc.linear_base = (l4_uint32_t)&base_gdt;
/* Load it into the CPU. */
set_gdt(&pdesc);
/* Reload all the segment registers from the new GDT. */
asm volatile("ljmp %0,$1f ; 1:" : : "i" (KERNEL_CS));
set_ds(KERNEL_DS);
set_es(KERNEL_DS);
set_ss(KERNEL_DS);
set_fs(0);
set_gs(0);
}
static void
base_idt_load(void)
{
struct pseudo_descriptor pdesc;
/* Create a pseudo-descriptor describing the GDT. */
pdesc.limit = sizeof(base_idt) - 1;
pdesc.linear_base = (l4_uint32_t)&base_idt;
set_idt(&pdesc);
}
static void
base_tss_load(void)
{
/* Make sure the TSS isn't marked busy. */
base_gdt[BASE_TSS / 8].access &= ~ACC_TSS_BUSY;
asm volatile ("" : : : "memory");
set_tr(BASE_TSS);
}
void
base_cpu_setup(void)
{
cpuid();
sse_enable();
base_idt_init();
base_gdt_init();
base_tss_init();
// force tables to memory before loading segment registers
asm volatile ("" : : : "memory");
base_gdt_load();
base_idt_load();
base_tss_load();
}
struct boot32_info_t boot32_info;
void
ptab_alloc(l4_uint32_t *out_ptab_pa)
{
static char pool[6 << 12] __attribute__((aligned(4096)));
static l4_uint32_t pdirs;
static int initialized;
if (! initialized)
{
initialized = 1;
boot32_info.ptab64_addr = (l4_uint32_t)pool;
boot32_info.ptab64_size = sizeof(pool);
memset(pool, 0, sizeof(pool));
pdirs = ((l4_uint32_t)pool + PAGE_SIZE - 1) & ~PAGE_MASK;
}
if (pdirs > (l4_uint32_t)pool + sizeof(pool))
panic("Cannot allocate page table -- increase ptab_alloc::pool");
*out_ptab_pa = pdirs;
pdirs += PAGE_SIZE;
}
void
base_paging_init(l4_uint64_t phys_mem_max)
{
ptab_alloc(&base_pml4_pa);
// Establish one-to-one mappings for the physical memory
ptab_map_range(base_pml4_pa, 0, 0, phys_mem_max, PTAB_WRITE | PTAB_USER);
//dbf_tss.cr3 = base_pml4_pa;
// XXX Turn on paging and activate long mode
paging_enable(base_pml4_pa);
}
void trap_dump_panic(const struct trap_state *st) L4_NORETURN;
void trap_dump_panic(const struct trap_state *st)
{
int from_user = st->cs & 3;
int i;
printf("EAX %08x EBX %08x ECX %08x EDX %08x\n",
st->eax, st->ebx, st->ecx, st->edx);
printf("ESI %08x EDI %08x EBP %08x ESP %08x\n",
st->esi, st->edi, st->ebp,
from_user ? st->esp : (l4_uint32_t)&st->esp);
printf("EIP %08x EFLAGS %08x\n", st->eip, st->eflags);
printf("CS %04x SS %04x DS %04x ES %04x FS %04x GS %04x\n",
st->cs & 0xffff, from_user ? st->ss & 0xffff : get_ss(),
st->ds & 0xffff, st->es & 0xffff,
st->fs & 0xffff, st->gs & 0xffff);
printf("trapno %d, error %08x, from %s mode\n",
st->trapno, st->err, from_user ? "user" : "kernel");
if (st->trapno == 0x0d)
{
if (st->err & 1)
printf("(external event");
else
printf("(internal event");
if (st->err & 2)
printf(" regarding IDT gate descriptor no. 0x%02x)\n", st->err >> 3);
else
printf(" regarding %s entry no. 0x%02x)\n",
st->err & 4 ? "LDT" : "GDT", st->err >> 3);
}
else if (st->trapno == 0x0e)
printf("page fault linear address %08x\n", st->cr2);
if (!from_user)
for (i = 0; i < 32; i++)
printf("%08x%c", (&st->esp)[i], ((i & 7) == 7) ? '\n' : ' ');
panic("Unexpected trap while booting Fiasco!");
}
static void
handle_dbf(void)
{
/*
printf("\n"
"EAX %08x EBX %08x ECX %08x EDX %08x\n"
"ESI %08x EDI %08x EBP %08x ESP %08x\n"
"EIP %08x EFLAGS %08x\n"
"CS %04x SS %04x DS %04x ES %04x FS %04x GS %04x\n\n",
base_tss.eax, base_tss.ebx, base_tss.ecx, base_tss.edx,
base_tss.esi, base_tss.edi, base_tss.ebp, base_tss.esp,
base_tss.eip, base_tss.eflags,
base_tss.cs & 0xffff, base_tss.ss & 0xffff, base_tss.ds & 0xffff,
base_tss.es & 0xffff, base_tss.fs & 0xffff, base_tss.gs & 0xffff);
*/
panic("Unexpected DOUBLE FAULT while booting Fiasco!");
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#ifndef BOOT_CPU_H
#define BOOT_CPU_H
#include "types.h"
void base_paging_init (l4_uint64_t);
void base_cpu_setup (void);
extern struct boot32_info_t boot32_info;
#endif

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2009 Technische Universität Dresden.
* Author(s): Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#define GATE_INITTAB_BEGIN(name) \
.text 1 ;\
.globl name ;\
name: ;\
.text
#define GATE_ENTRY(n,entry,type) \
.text 1 ;\
.long entry ;\
.word n ;\
.word type ;\
.text
#define GATE_INITTAB_END \
.text 1 ;\
.long 0 ;\
.text
#define EXCEPTION(n,name) \
GATE_ENTRY(n,name,0x0e) ;\
name: ;\
pushl $(0) ;\
pushl $(n) ;\
jmp alltraps
#define EXCEP_USR(n,name) \
GATE_ENTRY(n,name,0x6e) ;\
name: ;\
pushl $(0) ;\
pushl $(n) ;\
jmp alltraps
#define EXCEP_ERR(n,name) \
GATE_ENTRY(n,name,0x0e) ;\
name: ;\
pushl $(n) ;\
jmp alltraps
GATE_INITTAB_BEGIN(boot_idt_inittab)
EXCEPTION(0x00,t_zero_div)
EXCEPTION(0x01,t_debug)
EXCEPTION(0x02,t_nmi)
EXCEP_USR(0x03,t_int3)
EXCEP_USR(0x04,t_into)
EXCEP_USR(0x05,t_bounds)
EXCEPTION(0x06,t_invop)
EXCEPTION(0x07,t_nofpu)
GATE_ENTRY(0x08,0x20,0x05)
EXCEPTION(0x09,a_fpu_over)
EXCEP_ERR(0x0a,a_inv_tss)
EXCEP_ERR(0x0b,t_segnp)
EXCEP_ERR(0x0c,t_stack_fault)
EXCEP_ERR(0x0d,t_gen_prot)
EXCEP_ERR(0x0e,t_page_fault)
EXCEPTION(0x0f,t_trap_0f)
EXCEPTION(0x10,t_fpu_err)
EXCEPTION(0x11,t_trap_11)
EXCEPTION(0x12,t_trap_12)
EXCEPTION(0x13,t_trap_13)
EXCEPTION(0x14,t_trap_14)
EXCEPTION(0x15,t_trap_15)
EXCEPTION(0x16,t_trap_16)
EXCEPTION(0x17,t_trap_17)
EXCEPTION(0x18,t_trap_18)
EXCEPTION(0x19,t_trap_19)
EXCEPTION(0x1a,t_trap_1a)
EXCEPTION(0x1b,t_trap_1b)
EXCEPTION(0x1c,t_trap_1c)
EXCEPTION(0x1d,t_trap_1d)
EXCEPTION(0x1e,t_trap_1e)
EXCEPTION(0x1f,t_trap_1f)
GATE_INITTAB_END
alltraps:
pusha
pushl %ds
pushl %es
pushl %fs
pushl %gs
movl %ss,%eax
movl %eax,%ds
movl %eax,%es
movl %esp,%eax
pushl %eax
call trap_dump_panic

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Alexander Warg <warg@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <stdio.h>
#include <l4/util/mb_info.h>
#include "boot_cpu.h"
#include "paging.h"
#include "load_elf.h"
#include "mm_alloc.h"
#include "support.h"
extern unsigned KERNEL_CS_64;
extern char _binary_bootstrap64_bin_start;
extern char _image_start;
extern char _image_end;
void *rsdp_start = NULL;
l4_uint32_t rsdp_size = 0;
static l4_uint64_t find_upper_mem(l4util_mb_info_t *mbi)
{
l4_uint64_t max = 0;
l4util_mb_addr_range_t *mmap;
l4util_mb_for_each_mmap_entry(mmap, mbi)
{
if (max < mmap->addr + mmap->size
&& mmap->type == MB_ARD_MEMORY)
max = mmap->addr + mmap->size;
}
return max;
}
static void
reserve_mbi(l4util_mb_info_t *mbi)
{
reservation_add((unsigned long)mbi, sizeof(l4util_mb_info_t));
reservation_add(mbi->cmdline, __builtin_strlen((char*)mbi->cmdline) + 1);
l4util_mb_mod_t *mods = (l4util_mb_mod_t*)mbi->mods_addr;
reservation_add((unsigned long)mods,
mbi->mods_count * sizeof(l4util_mb_mod_t));
for (l4util_mb_mod_t *mod = mods; mod < mods + mbi->mods_count; ++mod)
{
reservation_add(mod->cmdline, __builtin_strlen((char *)mod->cmdline) + 1);
reservation_add(mod->mod_start, mod->mod_end - mod->mod_start);
}
}
void bootstrap (l4util_mb_info_t *mbi, unsigned int flag, char *rm_pointer);
void
bootstrap (l4util_mb_info_t *mbi, unsigned int flag, char *rm_pointer)
{
struct
{
l4_uint32_t start;
l4_uint16_t cs;
} far_ptr;
l4_uint64_t mem_upper;
// setup stuff for base_paging_init()
base_cpu_setup();
mem_upper = find_upper_mem(mbi);
if (!mem_upper)
mem_upper = 1024 * (1024 + mbi->mem_upper);
printf("Highest physical memory address found: 0x%llx (%llu MiB)\n",
mem_upper - 1, mem_upper >> 20);
// our memory available for our initial identity mapped page table is
// enough to cover 4GB of physical memory that must contain anything that
// is required to boot, i.e. bootstrap, all modules, any required devices
// and the final location of sigma0 and moe
const unsigned long long Max_initial_mem = 4ull << 30;
// Make sure future allocations do not overwrite our image
reservation_add((unsigned long)&_image_start,
(unsigned long)(&_image_end - &_image_start));
reservation_add(0, 0x1000); // null page
reservation_add(0x1000, 0x1000); // fiasco trampoline page
// reserve memory for final locations of fiasco, sigma0 and moe
l4util_mb_mod_t *mods = (l4util_mb_mod_t*)mbi->mods_addr;
if (mbi->mods_count > 0)
reserve_elf((void *)mods[0].mod_start); // fiasco
if (mbi->mods_count > 1)
reserve_elf((void *)mods[1].mod_start); // sigma0
if (mbi->mods_count > 2)
reserve_elf((void *)mods[2].mod_start); // moe
reserve_mbi(mbi);
if (mm_alloc_init)
mm_alloc_init(mbi);
if (mem_upper > Max_initial_mem)
mem_upper = Max_initial_mem;
mem_upper = round_superpage(mem_upper);
boot32_info.rsdp_start = (l4_uint32_t)rsdp_start;
boot32_info.rsdp_size = rsdp_size;
boot32_info.mem_end = mem_upper - 1;
// now do base_paging_init(): sets up paging with one-to-one mapping
base_paging_init(mem_upper);
printf("Loading 64bit part...\n");
// switch from 32 Bit compatibility mode to 64 Bit mode
far_ptr.cs = KERNEL_CS_64;
far_ptr.start = load_elf(&_binary_bootstrap64_bin_start);
asm volatile("ljmp *(%4)"
:: "D"(mbi), "S"(flag), "d"(rm_pointer),
"c"(&boot32_info),
"r"(&far_ptr), "m"(far_ptr));
}

View File

@@ -0,0 +1,58 @@
#define LOADADDR 0x10000000
ENTRY(_start)
PHDRS
{
sixtyfour PT_LOAD FLAGS(6);
text PT_LOAD FLAGS(5);
data PT_LOAD FLAGS(6);
rodata PT_LOAD FLAGS(4);
}
SECTIONS
{
. = LOADADDR; /* Place away such that a big (64-bit) bootstrap-image fits before */
_image_start = .;
.text :
{
KEEP(*(.multiboot2))
*(.text .text.*)
*(.rodata .rodata.*)
} :text =0x9090
.note.gnu.build-id : { *(.note.gnu.build-id) }
.data ALIGN(0x1000):
{
*.o32 (.idt .idt.*)
*.a (.idt .idt.*)
*.o32 (.data .data.*)
*.a (.data .data.*)
*.o32 (.bss .bss.*)
*.a (.bss .bss.*)
*.o32 (COMMON)
*.a (COMMON)
} :data
.data.elf64 ALIGN(0x1000):
{
KEEP(bootstrap32.bin (.data))
} :rodata
_image_end = .;
/* LINKADDR is DEFAULT_RELOC_amd64 aka the 64bit bootstrap binary */
.sixtyfour LINKADDR :
{
. = . + (LOADADDR - LINKADDR);
} :sixtyfour
/DISCARD/ : {
*(.interp)
*(.comment)
*(.note)
*(.eh_frame)
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2009-2021, 2023 Kernkonzept GmbH.
* Authors: Alexander Warg <warg@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Marcus Haehnel <marcus.haehnel@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <l4/util/elf.h>
#include "load_elf.h"
#include "mm_alloc.h"
#include "support.h"
// Even relocate if the memory region the binary is linked to is free.
static int const always_relocate = 0;
/**
* Function to relocate a value based on an ELF relocation entry.
*
* \param rel A RELA relocation entry structure from the ELF .rela section
* \param offset The signed offset of by how much to relocate the target
*/
static void relocate_rela_entry(Elf64_Rela* rel, Elf64_Sxword offset)
{
Elf32_Addr reloc_addr = (Elf32_Addr)(rel->r_offset + offset);
switch (ELF64_R_TYPE(rel->r_info))
{
case R_X86_64_RELATIVE:
*(Elf64_Addr *)reloc_addr = rel->r_addend + offset;
break;
// Should not appear with --no-dynamic-linker and -Bsymbolic
case R_X86_64_GLOB_DAT:
default:
printf("Info: type=0x%llx @ %llx -- ", rel->r_info, rel->r_offset);
panic("not supported");
}
}
/**
* Check if the specified range fits into the address range 0..4GiB.
*
* \param start Start of the range.
* \param size Size of the range.
*
* \retval 1 if whole range is within 4GB and not overlapping a reservation.
* \retval 0 otherwise.
*/
static int usable_range(Elf64_Addr start, Elf64_Xword size)
{
return is_range_in_4g(start, size)
&& !overlaps_reservation((void *)(Elf32_Addr)start, size);
}
/**
* Perform some light consistency checks on an ELF binary.
*/
static void
sanity_elf(Elf64_Ehdr const *eh)
{
if ( eh->e_ident[EI_MAG0] != ELFMAG0
|| eh->e_ident[EI_MAG1] != ELFMAG1
|| eh->e_ident[EI_MAG2] != ELFMAG2
|| eh->e_ident[EI_MAG3] != ELFMAG3)
panic("Invalid ELF file: bad header magic");
if (eh->e_ident[EI_CLASS] != ELFCLASS64)
panic("Invalid ELF file: wrong class");
if (eh->e_machine != EM_X86_64)
panic("Invalid ELF file: wrong machine");
}
/**
* Reserve all loadable program sections of an ELF binary.
*
* \param elf Start of the ELF binary.
*/
void
reserve_elf(void const *elf)
{
char const *_elf = (char const *)elf;
Elf64_Ehdr const *eh = (Elf64_Ehdr const *)(_elf);
sanity_elf(eh);
Elf64_Phdr const *ph = (Elf64_Phdr const *)(_elf + eh->e_phoff);
for (unsigned i = 0; i < eh->e_phnum; ++i)
if (ph[i].p_type == PT_LOAD)
reservation_add(ph[i].p_paddr, ph[i].p_memsz);
}
/**
* Load an ELF binary into memory.
*/
l4_uint32_t
load_elf(void const *elf)
{
char const *_elf = (char const *)elf;
Elf64_Ehdr const *eh = (Elf64_Ehdr const *)(_elf);
sanity_elf(eh);
Elf64_Shdr const *sh = (Elf64_Shdr const *)(_elf + eh->e_shoff);
Elf64_Phdr const *ph = (Elf64_Phdr const *)(_elf + eh->e_phoff);
Elf64_Sxword reloc = 0; // per default we do not relocate
int need_reloc = 0;
// Find out where to allocate memory by going through all phdrs and finding
// total required memory size and maximum required alignment.
Elf64_Addr min_addr = ~0ULL;
Elf64_Addr max_addr = 0ULL; // the address *after* the last byte
Elf64_Word max_align = 0ULL;
for (unsigned i = 0; i < eh->e_phnum; ++i)
{
if (ph[i].p_type != PT_LOAD)
continue;
if (max_align < ph[i].p_align && ph[i].p_align > 1)
max_align = ph[i].p_align;
if (min_addr > ph[i].p_paddr)
min_addr = ph[i].p_paddr;
if (max_addr < ph[i].p_paddr + ph[i].p_memsz)
max_addr = ph[i].p_paddr + ph[i].p_memsz;
need_reloc |= !usable_range(ph[i].p_paddr, ph[i].p_memsz);
}
// Only relocate when memory is not free anyways
if (always_relocate || need_reloc)
{
if (!mm_alloc_alloc)
panic("Memory already used and relocation not enabled!");
// Round down to max alignment to ensure all sections are correctly aligned
min_addr &= ~( max_align - 1 );
void* alloc_base = mm_alloc_alloc(max_addr - min_addr);
if (alloc_base == NULL)
panic("Unable to allocate memory for relocation!");
reloc = (Elf32_Addr)alloc_base - min_addr;
}
for (unsigned i = 0; i < eh->e_phnum; ++i, ++ph)
{
if (ph->p_type != PT_LOAD)
continue;
void* target = (void*)(Elf32_Addr)(ph->p_paddr + reloc);
if (!is_range_in_4g((uintptr_t)_elf, ph->p_offset))
panic("Could not load PHDR. Location in ELF exceeds 32-bit limits!");
memcpy(target, _elf + ph->p_offset, ph->p_filesz);
if (ph->p_filesz < ph->p_memsz)
memset(target + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
}
if (reloc != 0)
{
for (unsigned j = 0; j < eh->e_shnum; ++j, ++sh)
{
switch (sh->sh_type)
{
case SHT_RELA:
{
// Process each entry in the table and relocate if in range
Elf64_Rela *rel = (Elf64_Rela *)(_elf + sh->sh_offset);
for (; (char *)rel < _elf + sh->sh_offset + sh->sh_size; rel++)
relocate_rela_entry(rel, reloc);
break;
}
case SHT_REL:
panic("Unsupported relocation type SHT_REL");
}
}
}
return eh->e_entry + reloc;
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2009 Technische Universität Dresden.
* Author(s): Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#ifndef LOAD_ELF_H__
#define LOAD_ELF_H__ 1
#include "types.h"
void reserve_elf(void const *elf);
l4_uint32_t load_elf(void const *elf);
#endif

View File

@@ -0,0 +1,301 @@
/*
* Copyright (C) 2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <l4/util/port_io.h>
static void direct_cons_putchar(unsigned char c);
static int direct_cons_try_getchar(void);
void reboot(void);
int __libc_backend_outs( const char *s, size_t len);
int __getchar(void);
static void porte9(unsigned char c)
{
l4util_out8(c, 0xe9);
if (c == 10)
l4util_out8(13, 0xe9);
}
int
__libc_backend_outs( const char *s, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
{
direct_cons_putchar(s[i]);
if (0)
porte9(s[i]);
}
return 1;
}
void __attribute__((noreturn))
reboot(void)
{
l4util_out8(0x80, 0x70);
l4util_iodelay();
l4util_in8(0x71);
l4util_iodelay();
while (l4util_in8(0x64) & 0x02)
;
l4util_out8(0x8F, 0x70);
l4util_iodelay();
l4util_out8(0x00, 0x71);
l4util_iodelay();
l4util_out8(0xFE, 0x64);
l4util_iodelay();
for (;;)
;
}
int
__getchar(void)
{
int c = 0;
do
{
if (c == -1)
c = direct_cons_try_getchar();
} while (c == -1);
return c;
}
void
_Exit(int fd)
{
(void)fd;
printf("\n\033[1mReturn reboots...\033[m\n");
__getchar();
printf("Rebooting.\n");
reboot();
}
static void
direct_cons_putchar(unsigned char c)
{
static int ofs = -1;
static int esc;
static int esc_val;
static int attr = 0x07;
unsigned char *vidbase = (unsigned char*)0xb8000;
if (ofs < 0)
{
/* Called for the first time - initialize. */
ofs = 80 * 2 * 24;
direct_cons_putchar('\n');
}
switch (esc)
{
case 1:
if (c == '[')
{
esc++;
goto done;
}
esc = 0;
break;
case 2:
if (c >= '0' && c <= '9')
{
esc_val = 10 * esc_val + c - '0';
goto done;
}
if (c == 'm')
{
attr = esc_val ? 0x0f : 0x07;
goto done;
}
esc = 0;
break;
}
switch (c)
{
case '\n':
memmove(vidbase, vidbase + 80 * 2, 80 * 2 * 24);
memset(vidbase + 80 * 2 * 24, 0, 80 * 2);
/* fall through... */
case '\r':
ofs = 0;
break;
case '\t':
ofs = (ofs + 8) & ~7;
break;
case '\033':
esc = 1;
esc_val = 0;
break;
default:
/* Wrap if we reach the end of a line. */
if (ofs >= 80)
direct_cons_putchar('\n');
/* Stuff the character into the video buffer. */
{
volatile unsigned char *p = vidbase + 80 * 2 * 24 + ofs * 2;
p[0] = c;
p[1] = attr;
ofs++;
}
break;
}
done:
return;
}
#define SHIFT -1
static const char keymap[128][2] = {
{0}, /* 0 */
{27, 27}, /* 1 - ESC */
{'1', '!'}, /* 2 */
{'2', '@'},
{'3', '#'},
{'4', '$'},
{'5', '%'},
{'6', '^'},
{'7', '&'},
{'8', '*'},
{'9', '('},
{'0', ')'},
{'-', '_'},
{'=', '+'},
{8, 8}, /* 14 - Backspace */
{'\t','\t'}, /* 15 */
{'q', 'Q'},
{'w', 'W'},
{'e', 'E'},
{'r', 'R'},
{'t', 'T'},
{'y', 'Y'},
{'u', 'U'},
{'i', 'I'},
{'o', 'O'},
{'p', 'P'},
{'[', '{'},
// {']','}'}, /* 27 */
{'+', '*'}, /* 27 */
{'\r','\r'}, /* 28 - Enter */
{0, 0}, /* 29 - Ctrl */
{'a', 'A'}, /* 30 */
{'s', 'S'},
{'d', 'D'},
{'f', 'F'},
{'g', 'G'},
{'h', 'H'},
{'j', 'J'},
{'k', 'K'},
{'l', 'L'},
{';', ':'},
{'\'','"'}, /* 40 */
{'`', '~'}, /* 41 */
{SHIFT, SHIFT}, /* 42 - Left Shift */
{'\\', '|'}, /* 43 */
{'z', 'Z'}, /* 44 */
{'x', 'X'},
{'c', 'C'},
{'v', 'V'},
{'b', 'B'},
{'n', 'N'},
{'m', 'M'},
{',', '<'},
{'.', '>'},
// {'/','?'}, /* 53 */
{'-', '_'}, /* 53 */
{SHIFT, SHIFT}, /* 54 - Right Shift */
{0, 0}, /* 55 - Print Screen */
{0, 0}, /* 56 - Alt */
{' ', ' '}, /* 57 - Space bar */
{0, 0}, /* 58 - Caps Lock */
{0, 0}, /* 59 - F1 */
{0, 0}, /* 60 - F2 */
{0, 0}, /* 61 - F3 */
{0, 0}, /* 62 - F4 */
{0, 0}, /* 63 - F5 */
{0, 0}, /* 64 - F6 */
{0, 0}, /* 65 - F7 */
{0, 0}, /* 66 - F8 */
{0, 0}, /* 67 - F9 */
{0, 0}, /* 68 - F10 */
{0, 0}, /* 69 - Num Lock */
{0, 0}, /* 70 - Scroll Lock */
{'7', '7'}, /* 71 - Numeric keypad 7 */
{'8', '8'}, /* 72 - Numeric keypad 8 */
{'9', '9'}, /* 73 - Numeric keypad 9 */
{'-', '-'}, /* 74 - Numeric keypad '-' */
{'4', '4'}, /* 75 - Numeric keypad 4 */
{'5', '5'}, /* 76 - Numeric keypad 5 */
{'6', '6'}, /* 77 - Numeric keypad 6 */
{'+', '+'}, /* 78 - Numeric keypad '+' */
{'1', '1'}, /* 79 - Numeric keypad 1 */
{'2', '2'}, /* 80 - Numeric keypad 2 */
{'3', '3'}, /* 81 - Numeric keypad 3 */
{'0', '0'}, /* 82 - Numeric keypad 0 */
{'.', '.'}, /* 83 - Numeric keypad '.' */
};
int
direct_cons_try_getchar(void)
{
static unsigned shift_state;
unsigned status, scan_code, ch;
retry:
__asm__ __volatile__ ("rep; nop");
/* Wait until a scan code is ready and read it. */
status = l4util_in8(0x64);
if ((status & 0x01) == 0)
{
return -1;
}
scan_code = l4util_in8(0x60);
/* Drop mouse events */
if ((status & 0x20) != 0)
{
return -1;
}
/* Handle key releases - only release of SHIFT is important. */
if (scan_code & 0x80)
{
scan_code &= 0x7f;
if (keymap[scan_code][0] == SHIFT)
shift_state = 0;
goto retry;
}
/* Translate the character through the keymap. */
ch = keymap[scan_code][shift_state];
if (ch == (unsigned)SHIFT)
{
shift_state = 1;
goto retry;
} else if (ch == 0)
goto retry;
return ch;
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2020 Kernkonzept GmbH.
* Authors: Marcus Hähnel <marcus.haehnel@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <string.h>
#include <stdio.h>
#include <l4/util/elf.h>
#include <l4/util/mb_info.h>
#include "mm_alloc.h"
#include "support.h"
#include "types.h"
typedef struct
{
l4util_mb_info_t *mbi;
l4util_mb_addr_range_t *range;
unsigned long used; //< Memory used from the current range
} mm_alloc_state;
static mm_alloc_state mm_alloc = { NULL, NULL, 0 };
void
mm_alloc_init(l4util_mb_info_t *mbi)
{
mm_alloc.mbi = mbi;
mm_alloc.range = NULL;
}
/**
* Check if the currently set range actually falls inside the memory map.
*
* \retval 0 The range does not belong to the map
* \retval 1 The range belongs to the map
*
* Note: This should be used together with next_ram_range. It is mainly to
* detect when the iterator has gone beyond the last element. In particular it
* does not check unaligned access not done by iterating over entries!
*/
static int
mm_alloc_range_in_map(void)
{
unsigned long addr = (unsigned long)mm_alloc.range;
l4util_mb_info_t *mbi = mm_alloc.mbi;
return addr >= mbi->mmap_addr && addr < mbi->mmap_addr + mbi->mmap_length;
}
/**
* Checks if selected range can accommodate size below 4GiB.
*
* Checks if the last address of an allocation of size bytes in the current
* range would still be within the 4GB that can be catered by the allocator.
*
* \param size size of allocation planned from the currently selected range
*
* \retval 0 the allocation will not be fully below 4GB
* \retval 1 the allocation will be completely below 4GB
*/
static int
range_in_4G_for_size(unsigned long size)
{
return mm_alloc.range->size - mm_alloc.used >= size
&& mm_alloc.range->addr + mm_alloc.used + size <= (1ull << 32);
}
/**
* Set the allocator to the next ram range in the MBI memory map.
*
* This advances the allocator to the next ram range in the memory map that
* can provide the amount of memory specified in the size parameter.
*
* If no range has been set yet (e.g. directly after initialization) then the
* first range that satisfies the size constraint is selected. If no more
* ranges can satisfy a request then the current range is set to NULL.
*
* If next_ram_range is called again after the last range has been reached
* iteration will start anew from the first range.
*
* Only ranges of type MB_ART_MEMORY are considered. Ranges that start beyond
* 4GB are also not considered.
*
* \param size The amount of memory that must be at least provided by the range
*/
static void
next_ram_range(unsigned long size)
{
if (mm_alloc.range == NULL)
mm_alloc.range = l4util_mb_first_mmap_entry(mm_alloc.mbi);
else
mm_alloc.range = l4util_mb_next_mmap_entry(mm_alloc.range);
mm_alloc.used = 0;
while (mm_alloc.range != NULL)
{
// If the range is suitable just use it
if (mm_alloc.range->type == MB_ART_MEMORY && range_in_4G_for_size(size))
return;
// Otherwise advance to the next
mm_alloc.range = l4util_mb_next_mmap_entry(mm_alloc.range);
if (!mm_alloc_range_in_map())
mm_alloc.range = NULL;
}
}
void*
mm_alloc_alloc(unsigned long size)
{
// Not enough memory in current range? Get next range with enough size.
if (mm_alloc.range == NULL || !range_in_4G_for_size(size))
next_ram_range(size);
// Check if what we found overlaps with a reserved region, and retry if yes
while (mm_alloc.range != NULL)
{
void *result = (void*)((unsigned long)mm_alloc.range->addr + mm_alloc.used);
unsigned long overlap = overlaps_reservation(result, size);
if (overlap == 0)
{
mm_alloc.used += size;
return result;
}
else
{
//Advance to the first non-overlapping byte
mm_alloc.used = overlap - mm_alloc.range->addr;
}
// If we now exceeded the free memory in the range use the next one
if (mm_alloc.range->size <= mm_alloc.used || !range_in_4G_for_size(size))
next_ram_range(size);
}
// Uninitialized or no more available regions
return NULL;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 Kernkonzept GmbH.
* Authors: Marcus Hähnel <marcus.haehnel@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/util/mb_info.h>
/**
* Function to initialize the global state of the memory allocator.
*
* \param mbi Pointer to the multiboot information structure provided by the
* bootloader
*/
void mm_alloc_init(l4util_mb_info_t *mbi) __attribute__((weak));
/**
* Allocate memory from the mm_alloc allocator
*
* Returns a pointer to a chunk of memory of the specified size. It is
* guaranteed that the returned memory does not overlap with
*
* * the bootstrap image itself
* * any modules passed through multiboot
* * the multiboot information, except information pertaining to sections
* of this bootstrap ELF (not the inner ELF!).
*
* \param size The size of the memory that is to be allocated
* \returns A pointer to the newly allocated memory
* \retval NULL if not enough memory was available or the allocator was not
* initialized.
*/
void *mm_alloc_alloc(unsigned long size) __attribute__((weak));

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2009-2021, 2023 Kernkonzept GmbH.
* Authors: Alexander Warg <warg@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <stdio.h>
#include <l4/sys/consts.h>
#include "support.h"
void L4_NORETURN
panic(char const *str)
{
printf("PANIC: %s\n", str);
while (1)
;
}
int
is_range_in_4g(unsigned long long start, unsigned long long size)
{
return size <= (1ULL << 32) && start <= (1ULL << 32) - size;
}
typedef struct
{
unsigned long start;
unsigned long size;
} Area;
typedef struct
{
unsigned num;
Area entries[Max_reservations];
} Reservations;
static Reservations reservations;
void
reservation_add(unsigned long start, unsigned long size)
{
unsigned long _start = l4_trunc_page(start);
unsigned long _size = l4_round_page(start - _start + size);
if (!is_range_in_4g(_start, _size))
panic("Cannot add reservation that exceeds 32-bit address space");
for (Area *r = reservations.entries;
r < reservations.entries + reservations.num; ++r)
{
// Inside range:
if (_start >= r->start && _start + _size <= r->start + r->size)
return;
// Directly after
if (r->start + r->size == _start)
{
r->size += _size;
return;
}
// Directly before
if (r->start == _start + _size)
{
r->start = _start;
return;
}
}
if (reservations.num < Max_reservations)
{
reservations.entries[reservations.num].start = _start;
reservations.entries[reservations.num].size = _size;
++reservations.num;
}
else
{
Area *e = reservations.entries + (Max_reservations - 1);
printf("WARNING: Extending last reservation entry (%u) from [%lx:%lx]",
Max_reservations - 1, e->start, e->start + e->size - 1);
if (e->start > _start)
e->start = _start;
if (e->start + e->size < _start + _size)
e->size = _start + _size - e->start;
printf(" to [%lx:%lx]\n", e->start, e->start + e->size - 1);
}
}
unsigned long
overlaps_reservation(void* start, unsigned long size)
{
for (Area *r = reservations.entries;
r < reservations.entries + reservations.num; ++r)
{
if (r->start < (unsigned long)start + size
&& r->start + r->size > (unsigned long)start)
return r->start + r->size;
}
return 0;
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2009-2021, 2023 Kernkonzept GmbH.
* Authors: Alexander Warg <warg@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Marcus Haehnel <marcus.haehnel@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/sys/compiler.h>
/**
* Output a string and go into endless loop
*
* \param str The string to print
*/
void L4_NORETURN panic(char const *str);
enum { Max_reservations = 16 };
/**
* Checks if a range of memory is within the 32-bit addressable space (4 GiB).
*
* \param start start address of the memory range to check.
* \param size size of the memory range to check.
*
* \retval 0 The tested range is (partly) outside the 32-bit addressable space.
* \retval 1 The tested range is within the 32-bit addressable space.
*/
int
is_range_in_4g(unsigned long long start, unsigned long long size);
/**
* Adds a range of memory to a reservation map.
*
* A static reservation map is kept by the program. This function adds memory
* ranges to that reservation map. The overlaps_reservation function can be used
* to check whether a memory range intersects with any range in the map.
*
* To reduce bookkeeping effort and fragmentation, ranges are extended when
* added to the whole pages occupied by any part of the range. This means that
* the start address will be rounded down to the nearest multiple of page size
* while the size will be rounded up to page size. This helps with adding
* possibly fragmented data such as MBI information.
*
* The map contains space for as many entries as specified in Max_reservations.
* When no more entries can be allocated, the last entry is alwyas expanded to
* contain any additionally added reservation and a warning is printed.
*
* \param start start address of the range to be reserved
* \param size size of the memory range to reserve.
*/
void
reservation_add(unsigned long start, unsigned long size);
/**
* Check if a range of memory intersects with any range in the reservation map.
*
* If the specified range intersects with any range of memory kept in the
* internal reservation map, the address of the end of the range (i.e. the first
* address no longer belonging to the reserved region) is returned.
*
* \note The function does not guarantee that the so returned address does not
* intersect with any other reservation. It is the job of the caller to
* call this function again if necessary.
*
* \param start Pointer to the start of the memory area to check.
* \param size Size of the memory area to check.
*
* \retval 0 The tested range did not intersect with any reservation.
* \returns The first address after the memory range the checked range
* intersected with.
*/
unsigned long
overlaps_reservation(void* start, unsigned long size);

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2022-2023 Kernkonzept GmbH.
* Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "cpu_info.h"
struct cpu_info_t cpu_info = { 0, 0 };
static inline void
cpuid(l4_uint32_t mode,
l4_uint32_t *eax, l4_uint32_t *ebx, l4_uint32_t *ecx, l4_uint32_t *edx)
{
l4_uint32_t a, b, c, d;
asm volatile ("cpuid" : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
: "a" (mode), "c" (0));
if (eax) *eax = a;
if (ebx) *ebx = b;
if (ecx) *ecx = c;
if (edx) *edx = d;
}
void
init_cpu_info(void)
{
l4_uint32_t max_val;
cpuid(0, &max_val, 0, 0, 0);
if (max_val >= 1)
cpuid(1, 0, 0, 0, &cpu_info.feature_flags);
l4_uint32_t max_ext_val;
cpuid(0x80000000, &max_ext_val, 0, 0, 0);
if (max_ext_val >= 0x80000001)
cpuid(0x80000001, 0, 0, 0, &cpu_info.feature_flags_ext);
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2022, 2024 Kernkonzept GmbH.
* Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/sys/compiler.h>
#include <l4/sys/consts.h>
enum
{
CPUF_PSE = 1 << 3,
CPUFEXT_PDPE1GB = 1 << 26,
};
struct cpu_info_t
{
l4_uint32_t feature_flags;
l4_uint32_t feature_flags_ext;
};
extern struct cpu_info_t cpu_info;
L4_BEGIN_DECLS
void init_cpu_info(void);
L4_END_DECLS

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/sys/compiler.h>
.section .init
.globl _start
_start:
#ifdef __PIC__
lea _stack(%rip),%esp
#else
lea _stack,%esp
#endif
#ifdef __PIC__
pushq $_exit@plt
jmp __main@plt
#else
pushq $_exit
jmp __main
#endif
/* MultiBoot header - see multiboot.h. */
.p2align(2)
#define MULTIBOOT_MEMORY_INFO 0x00000002
_mb_header:
.long 0x1BADB002 /* magic */
.long MULTIBOOT_MEMORY_INFO /* flags */
.long 0 - 0x1BADB002 - MULTIBOOT_MEMORY_INFO
.bss
.globl _stack
.space 8192
_stack:

View File

@@ -0,0 +1,40 @@
PKGDIR ?= ../../../..
L4DIR ?= $(PKGDIR)/../..
TARGET = libc32.a
SYSTEMS = amd64-plain
VARIANTS = nofpu
# Not needed. This is not for general consumption
NOTARGETSTOINSTALL = y
SRC_C = __assert_fail.c \
glue/stdout_write.c \
glue/printf.c \
glue/puts.c \
glue/vprintf.c \
src/string/strlen.c \
src/string/strnlen.c \
src/string/memchr.c \
src/string/memmove.c \
src/string/memset.c \
src/stdio/__towrite.c \
src/stdio/fputs.c \
src/stdio/fwrite.c \
src/stdio/vfprintf.c \
src/ctype/isdigit.c
SRC_S = src/string/i386/memcpy.S
include $(L4DIR)/mk/lib.mk
CFLAGS := $(filter-out $(CCXX_FLAGS) $(CARCHFLAGS), $(CFLAGS)) \
-mno-sse -fno-builtin -ffreestanding
ASFLAGS := $(call checkcc,-Wa$(BID_COMMA)--32)
CPPFLAGS := -DLIBCL4 \
-m32 \
-nostdinc \
-I$(SRC_DIR)/src/internal \
-I$(SRC_DIR)/src/include \
-I$(SRC_DIR)/include
OPTS := -Os

View File

@@ -0,0 +1,12 @@
#include "assert.h"
#include "stdio.h"
#include "stdlib.h"
void
__assert(const char *__assertion, const char *__file,
unsigned int __line, const char *__func)
{
printf("ASSERTION_FAILED (%s)\n"
" in file %s:%d(%s)\n", __assertion, __file, __line, __func);
_Exit (EXIT_FAILURE);
}

View File

@@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdarg.h>
#include "stdio_impl.h"
#include "libc_stdio.h"
int printf(const char *restrict fmt, ...)
{
int r;
va_list ap;
FILE f = (FILE)
{
.write = __libc_stdout_write,
.buf = NULL,
.buf_size = 0, /* vfprintf() will use local internal_buf */
.lock = -1,
.lbf = -1,
};
va_start(ap, fmt);
r = vfprintf(&f, fmt, ap);
va_end(ap);
return r;
}

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include "libc_backend.h"
int putchar (int c)
{
char _c = c;
int ret = __libc_backend_outs(&_c,1) ? c : 0;
return ret;
}

View File

@@ -0,0 +1,14 @@
#include "libc_stdio.h"
#include "libc_backend.h"
#include <string.h>
int puts(const char *s)
{
int ret = __libc_backend_outs(s, strlen(s));
if (ret >= 0)
{
char c = '\n';
ret = __libc_backend_outs(&c, 1);
}
return ret;
}

View File

@@ -0,0 +1,12 @@
#include "libc_stdio.h"
#include "libc_backend.h"
size_t __libc_stdout_write(FILE *f, const unsigned char *buf, size_t len)
{
__libc_backend_outs((const char *)f->wbase, f->wpos - f->wbase);
__libc_backend_outs((const char *)buf, len);
f->wend = f->buf + f->buf_size;
f->wpos = f->wbase = f->buf;
return len;
}

View File

@@ -0,0 +1,16 @@
#include <stdio.h>
#include "stdio_impl.h"
#include "libc_stdio.h"
int vprintf(const char *restrict fmt, va_list ap)
{
FILE f = (FILE)
{
.write = __libc_stdout_write,
.buf = NULL,
.buf_size = 0, /* vfprintf() will use local internal_buf */
.lock = -1,
.lbf = -1,
};
return vfprintf(&f, fmt, ap);
}

View File

@@ -0,0 +1,19 @@
#ifndef _ALLOCA_H
#define _ALLOCA_H
#ifdef __cplusplus
extern "C" {
#endif
#define __NEED_size_t
#include <bits/alltypes.h>
void *alloca(size_t);
#define alloca __builtin_alloca
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,25 @@
#pragma once
#include <features.h>
#ifdef __cplusplus
extern "C"
#endif
_Noreturn
void __assert(const char *__assertion, const char *__file,
unsigned int __line, const char *func)
__attribute__ ((__noreturn__));
#define ASSERT_EXPECT_FALSE(exp) __builtin_expect((exp), 0)
#undef assert
#ifdef NDEBUG
#define assert(expr) do {} while (0)
#define check(expr) (void)(expr)
#else
# define assert(expr) \
((void)((ASSERT_EXPECT_FALSE(!(expr))) \
? (__assert(#expr, __FILE__, __LINE__, __func__), 0) \
: 0))
# define check(expr) assert(expr)
#endif

View File

@@ -0,0 +1,427 @@
#define _Addr long
#define _Int64 long long
#define _Reg long
#define __BYTE_ORDER 1234
#if __SIZEOF_LONG__ == 8
#define __LONG_MAX 0x7fffffffffffffffL
#else
#define __LONG_MAX 0x7fffffffL
#endif
#ifndef __cplusplus
#ifdef __WCHAR_TYPE__
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
typedef __WCHAR_TYPE__ wchar_t;
#define __DEFINED_wchar_t
#endif
#else
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
typedef long wchar_t;
#define __DEFINED_wchar_t
#endif
#endif
#endif
#if 0
#if defined(__FLT_EVAL_METHOD__) && __FLT_EVAL_METHOD__ == 2
#if defined(__NEED_float_t) && !defined(__DEFINED_float_t)
typedef long double float_t;
#define __DEFINED_float_t
#endif
#if defined(__NEED_double_t) && !defined(__DEFINED_double_t)
typedef long double double_t;
#define __DEFINED_double_t
#endif
#else
#if defined(__NEED_float_t) && !defined(__DEFINED_float_t)
typedef float float_t;
#define __DEFINED_float_t
#endif
#if defined(__NEED_double_t) && !defined(__DEFINED_double_t)
typedef double double_t;
#define __DEFINED_double_t
#endif
#endif
#if defined(__NEED_max_align_t) && !defined(__DEFINED_max_align_t)
typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
#endif // no float
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
#if 0
typedef unsigned _Addr size_t;
#else
typedef __SIZE_TYPE__ size_t;
#endif
#define __DEFINED_size_t
#endif
#if defined(__NEED_uintptr_t) && !defined(__DEFINED_uintptr_t)
typedef unsigned _Addr uintptr_t;
#define __DEFINED_uintptr_t
#endif
#if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t)
typedef _Addr ptrdiff_t;
#define __DEFINED_ptrdiff_t
#endif
#if defined(__NEED_ssize_t) && !defined(__DEFINED_ssize_t)
typedef _Addr ssize_t;
#define __DEFINED_ssize_t
#endif
#if defined(__NEED_intptr_t) && !defined(__DEFINED_intptr_t)
typedef _Addr intptr_t;
#define __DEFINED_intptr_t
#endif
#if defined(__NEED_regoff_t) && !defined(__DEFINED_regoff_t)
typedef _Addr regoff_t;
#define __DEFINED_regoff_t
#endif
#if defined(__NEED_register_t) && !defined(__DEFINED_register_t)
typedef _Reg register_t;
#define __DEFINED_register_t
#endif
#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
typedef _Int64 time_t;
#define __DEFINED_time_t
#endif
#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
typedef _Int64 suseconds_t;
#define __DEFINED_suseconds_t
#endif
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
#define __DEFINED_int8_t
#endif
#if defined(__NEED_int16_t) && !defined(__DEFINED_int16_t)
typedef signed short int16_t;
#define __DEFINED_int16_t
#endif
#if defined(__NEED_int32_t) && !defined(__DEFINED_int32_t)
typedef signed int int32_t;
#define __DEFINED_int32_t
#endif
#if defined(__NEED_int64_t) && !defined(__DEFINED_int64_t)
typedef signed _Int64 int64_t;
#define __DEFINED_int64_t
#endif
#if defined(__NEED_intmax_t) && !defined(__DEFINED_intmax_t)
typedef signed _Int64 intmax_t;
#define __DEFINED_intmax_t
#endif
#if defined(__NEED_uint8_t) && !defined(__DEFINED_uint8_t)
typedef unsigned char uint8_t;
#define __DEFINED_uint8_t
#endif
#if defined(__NEED_uint16_t) && !defined(__DEFINED_uint16_t)
typedef unsigned short uint16_t;
#define __DEFINED_uint16_t
#endif
#if defined(__NEED_uint32_t) && !defined(__DEFINED_uint32_t)
typedef unsigned int uint32_t;
#define __DEFINED_uint32_t
#endif
#if defined(__NEED_uint64_t) && !defined(__DEFINED_uint64_t)
typedef unsigned _Int64 uint64_t;
#define __DEFINED_uint64_t
#endif
#if defined(__NEED_u_int64_t) && !defined(__DEFINED_u_int64_t)
typedef unsigned _Int64 u_int64_t;
#define __DEFINED_u_int64_t
#endif
#if defined(__NEED_uintmax_t) && !defined(__DEFINED_uintmax_t)
typedef unsigned _Int64 uintmax_t;
#define __DEFINED_uintmax_t
#endif
#if defined(__NEED_mode_t) && !defined(__DEFINED_mode_t)
typedef unsigned mode_t;
#define __DEFINED_mode_t
#endif
#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t)
typedef unsigned _Reg nlink_t;
#define __DEFINED_nlink_t
#endif
#if defined(__NEED_off_t) && !defined(__DEFINED_off_t)
typedef _Int64 off_t;
#define __DEFINED_off_t
#endif
#if defined(__NEED_ino_t) && !defined(__DEFINED_ino_t)
typedef unsigned _Int64 ino_t;
#define __DEFINED_ino_t
#endif
#if defined(__NEED_dev_t) && !defined(__DEFINED_dev_t)
typedef unsigned _Int64 dev_t;
#define __DEFINED_dev_t
#endif
#if defined(__NEED_blksize_t) && !defined(__DEFINED_blksize_t)
typedef long blksize_t;
#define __DEFINED_blksize_t
#endif
#if defined(__NEED_blkcnt_t) && !defined(__DEFINED_blkcnt_t)
typedef _Int64 blkcnt_t;
#define __DEFINED_blkcnt_t
#endif
#if defined(__NEED_fsblkcnt_t) && !defined(__DEFINED_fsblkcnt_t)
typedef unsigned _Int64 fsblkcnt_t;
#define __DEFINED_fsblkcnt_t
#endif
#if defined(__NEED_fsfilcnt_t) && !defined(__DEFINED_fsfilcnt_t)
typedef unsigned _Int64 fsfilcnt_t;
#define __DEFINED_fsfilcnt_t
#endif
#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t)
typedef unsigned wint_t;
#define __DEFINED_wint_t
#endif
#if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t)
typedef unsigned long wctype_t;
#define __DEFINED_wctype_t
#endif
#if defined(__NEED_timer_t) && !defined(__DEFINED_timer_t)
typedef void * timer_t;
#define __DEFINED_timer_t
#endif
#if defined(__NEED_clockid_t) && !defined(__DEFINED_clockid_t)
typedef int clockid_t;
#define __DEFINED_clockid_t
#endif
#if defined(__NEED_clock_t) && !defined(__DEFINED_clock_t)
typedef long clock_t;
#define __DEFINED_clock_t
#endif
#if defined(__NEED_struct_timeval) && !defined(__DEFINED_struct_timeval)
struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#define __DEFINED_struct_timeval
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
#if defined(__NEED_pid_t) && !defined(__DEFINED_pid_t)
typedef int pid_t;
#define __DEFINED_pid_t
#endif
#if defined(__NEED_id_t) && !defined(__DEFINED_id_t)
typedef unsigned id_t;
#define __DEFINED_id_t
#endif
#if defined(__NEED_uid_t) && !defined(__DEFINED_uid_t)
typedef unsigned uid_t;
#define __DEFINED_uid_t
#endif
#if defined(__NEED_gid_t) && !defined(__DEFINED_gid_t)
typedef unsigned gid_t;
#define __DEFINED_gid_t
#endif
#if defined(__NEED_key_t) && !defined(__DEFINED_key_t)
typedef int key_t;
#define __DEFINED_key_t
#endif
#if defined(__NEED_useconds_t) && !defined(__DEFINED_useconds_t)
typedef unsigned useconds_t;
#define __DEFINED_useconds_t
#endif
#ifdef __cplusplus
#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t)
typedef unsigned long pthread_t;
#define __DEFINED_pthread_t
#endif
#else
#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t)
typedef struct __pthread * pthread_t;
#define __DEFINED_pthread_t
#endif
#endif
#if defined(__NEED_pthread_once_t) && !defined(__DEFINED_pthread_once_t)
typedef int pthread_once_t;
#define __DEFINED_pthread_once_t
#endif
#if defined(__NEED_pthread_key_t) && !defined(__DEFINED_pthread_key_t)
typedef unsigned pthread_key_t;
#define __DEFINED_pthread_key_t
#endif
#if defined(__NEED_pthread_spinlock_t) && !defined(__DEFINED_pthread_spinlock_t)
typedef int pthread_spinlock_t;
#define __DEFINED_pthread_spinlock_t
#endif
#if defined(__NEED_pthread_mutexattr_t) && !defined(__DEFINED_pthread_mutexattr_t)
typedef struct { unsigned __attr; } pthread_mutexattr_t;
#define __DEFINED_pthread_mutexattr_t
#endif
#if defined(__NEED_pthread_condattr_t) && !defined(__DEFINED_pthread_condattr_t)
typedef struct { unsigned __attr; } pthread_condattr_t;
#define __DEFINED_pthread_condattr_t
#endif
#if defined(__NEED_pthread_barrierattr_t) && !defined(__DEFINED_pthread_barrierattr_t)
typedef struct { unsigned __attr; } pthread_barrierattr_t;
#define __DEFINED_pthread_barrierattr_t
#endif
#if defined(__NEED_pthread_rwlockattr_t) && !defined(__DEFINED_pthread_rwlockattr_t)
typedef struct { unsigned __attr[2]; } pthread_rwlockattr_t;
#define __DEFINED_pthread_rwlockattr_t
#endif
#if defined(__NEED_struct__IO_FILE) && !defined(__DEFINED_struct__IO_FILE)
struct _IO_FILE { char __x; };
#define __DEFINED_struct__IO_FILE
#endif
#if defined(__NEED_FILE) && !defined(__DEFINED_FILE)
typedef struct _IO_FILE FILE;
#define __DEFINED_FILE
#endif
#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
typedef __builtin_va_list va_list;
#define __DEFINED_va_list
#endif
#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
typedef __builtin_va_list __isoc_va_list;
#define __DEFINED___isoc_va_list
#endif
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
#endif
#if defined(__NEED_sigset_t) && !defined(__DEFINED_sigset_t)
typedef struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t;
#define __DEFINED_sigset_t
#endif
#if defined(__NEED_struct_iovec) && !defined(__DEFINED_struct_iovec)
struct iovec { void *iov_base; size_t iov_len; };
#define __DEFINED_struct_iovec
#endif
#if defined(__NEED_struct_winsize) && !defined(__DEFINED_struct_winsize)
struct winsize { unsigned short ws_row, ws_col, ws_xpixel, ws_ypixel; };
#define __DEFINED_struct_winsize
#endif
#if defined(__NEED_socklen_t) && !defined(__DEFINED_socklen_t)
typedef unsigned socklen_t;
#define __DEFINED_socklen_t
#endif
#if defined(__NEED_sa_family_t) && !defined(__DEFINED_sa_family_t)
typedef unsigned short sa_family_t;
#define __DEFINED_sa_family_t
#endif
#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
#define __DEFINED_pthread_attr_t
#endif
#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
#define __DEFINED_pthread_mutex_t
#endif
#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
#define __DEFINED_mtx_t
#endif
#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
#define __DEFINED_pthread_cond_t
#endif
#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
#define __DEFINED_cnd_t
#endif
#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
#define __DEFINED_pthread_rwlock_t
#endif
#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
#define __DEFINED_pthread_barrier_t
#endif
#undef _Addr
#undef _Int64
#undef _Reg

View File

@@ -0,0 +1,134 @@
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define EIO 5
#define ENXIO 6
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define ENOTBLK 15
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define ETXTBSY 26
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
#define EDOM 33
#define ERANGE 34
#define EDEADLK 35
#define ENAMETOOLONG 36
#define ENOLCK 37
#define ENOSYS 38
#define ENOTEMPTY 39
#define ELOOP 40
#define EWOULDBLOCK EAGAIN
#define ENOMSG 42
#define EIDRM 43
#define ECHRNG 44
#define EL2NSYNC 45
#define EL3HLT 46
#define EL3RST 47
#define ELNRNG 48
#define EUNATCH 49
#define ENOCSI 50
#define EL2HLT 51
#define EBADE 52
#define EBADR 53
#define EXFULL 54
#define ENOANO 55
#define EBADRQC 56
#define EBADSLT 57
#define EDEADLOCK EDEADLK
#define EBFONT 59
#define ENOSTR 60
#define ENODATA 61
#define ETIME 62
#define ENOSR 63
#define ENONET 64
#define ENOPKG 65
#define EREMOTE 66
#define ENOLINK 67
#define EADV 68
#define ESRMNT 69
#define ECOMM 70
#define EPROTO 71
#define EMULTIHOP 72
#define EDOTDOT 73
#define EBADMSG 74
#define EOVERFLOW 75
#define ENOTUNIQ 76
#define EBADFD 77
#define EREMCHG 78
#define ELIBACC 79
#define ELIBBAD 80
#define ELIBSCN 81
#define ELIBMAX 82
#define ELIBEXEC 83
#define EILSEQ 84
#define ERESTART 85
#define ESTRPIPE 86
#define EUSERS 87
#define ENOTSOCK 88
#define EDESTADDRREQ 89
#define EMSGSIZE 90
#define EPROTOTYPE 91
#define ENOPROTOOPT 92
#define EPROTONOSUPPORT 93
#define ESOCKTNOSUPPORT 94
#define EOPNOTSUPP 95
#define ENOTSUP EOPNOTSUPP
#define EPFNOSUPPORT 96
#define EAFNOSUPPORT 97
#define EADDRINUSE 98
#define EADDRNOTAVAIL 99
#define ENETDOWN 100
#define ENETUNREACH 101
#define ENETRESET 102
#define ECONNABORTED 103
#define ECONNRESET 104
#define ENOBUFS 105
#define EISCONN 106
#define ENOTCONN 107
#define ESHUTDOWN 108
#define ETOOMANYREFS 109
#define ETIMEDOUT 110
#define ECONNREFUSED 111
#define EHOSTDOWN 112
#define EHOSTUNREACH 113
#define EALREADY 114
#define EINPROGRESS 115
#define ESTALE 116
#define EUCLEAN 117
#define ENOTNAM 118
#define ENAVAIL 119
#define EISNAM 120
#define EREMOTEIO 121
#define EDQUOT 122
#define ENOMEDIUM 123
#define EMEDIUMTYPE 124
#define ECANCELED 125
#define ENOKEY 126
#define EKEYEXPIRED 127
#define EKEYREVOKED 128
#define EKEYREJECTED 129
#define EOWNERDEAD 130
#define ENOTRECOVERABLE 131
#define ERFKILL 132
#define EHWPOISON 133

View File

@@ -0,0 +1 @@
#define PAGESIZE 4096

View File

@@ -0,0 +1,29 @@
typedef int32_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef uint32_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
#define INT_FAST16_MIN INT32_MIN
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST16_MAX INT32_MAX
#define INT_FAST32_MAX INT32_MAX
#define UINT_FAST16_MAX UINT32_MAX
#define UINT_FAST32_MAX UINT32_MAX
#if __LONG_MAX == 0x7fffffffL
#define INTPTR_MIN INT32_MIN
#define INTPTR_MAX INT32_MAX
#define UINTPTR_MAX UINT32_MAX
#define PTRDIFF_MIN INT32_MIN
#define PTRDIFF_MAX INT32_MAX
#define SIZE_MAX UINT32_MAX
#else
#define INTPTR_MIN INT64_MIN
#define INTPTR_MAX INT64_MAX
#define UINTPTR_MAX UINT64_MAX
#define PTRDIFF_MIN INT64_MIN
#define PTRDIFF_MAX INT64_MAX
#define SIZE_MAX UINT64_MAX
#endif

View File

@@ -0,0 +1,44 @@
#ifndef _CTYPE_H
#define _CTYPE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <features.h>
int isalnum(int);
int isalpha(int);
int isblank(int);
int iscntrl(int);
int isdigit(int);
int isgraph(int);
int islower(int);
int isprint(int);
int ispunct(int);
int isspace(int);
int isupper(int);
int isxdigit(int);
int tolower(int);
int toupper(int);
#ifndef __cplusplus
static __inline int __isspace(int _c)
{
return _c == ' ' || (unsigned)_c-'\t' < 5;
}
#define isalpha(a) (0 ? isalpha(a) : (((unsigned)(a)|32)-'a') < 26)
#define isdigit(a) (0 ? isdigit(a) : ((unsigned)(a)-'0') < 10)
#define islower(a) (0 ? islower(a) : ((unsigned)(a)-'a') < 26)
#define isupper(a) (0 ? isupper(a) : ((unsigned)(a)-'A') < 26)
#define isprint(a) (0 ? isprint(a) : ((unsigned)(a)-0x20) < 0x5f)
#define isgraph(a) (0 ? isgraph(a) : ((unsigned)(a)-0x21) < 0x5e)
#define isspace(a) __isspace(a)
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,31 @@
#ifndef _ERRNO_H
#define _ERRNO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <features.h>
#include <bits/errno.h>
#ifndef LIBCL4
#ifdef __GNUC__
__attribute__((const))
#endif
int *__errno_location(void);
#define errno (*__errno_location())
#ifdef _GNU_SOURCE
extern char *program_invocation_short_name, *program_invocation_name;
#endif
#endif /* LIBCL4 */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,42 @@
#ifndef _FEATURES_H
#define _FEATURES_H
#if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE 1
#endif
#if defined(_DEFAULT_SOURCE) && !defined(_BSD_SOURCE)
#define _BSD_SOURCE 1
#endif
#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) \
&& !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) \
&& !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__)
#define _BSD_SOURCE 1
#define _XOPEN_SOURCE 700
#endif
#if !defined(__cplusplus)
#if __STDC_VERSION__ >= 199901L
#define __restrict restrict
#elif !defined(__GNUC__)
#define __restrict
#endif
#endif // c++
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) || defined(__cplusplus)
#define __inline inline
#elif !defined(__GNUC__)
#define __inline
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#elif defined(__GNUC__)
#define _Noreturn __attribute__((__noreturn__))
#else
#define _Noreturn
#endif
#define __REDIR(x,y) __typeof__(x) x __asm__(#y)
#endif

View File

@@ -0,0 +1,231 @@
#ifndef _INTTYPES_H
#define _INTTYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#include <features.h>
#include <stdint.h>
#define __NEED_wchar_t
#include <bits/alltypes.h>
typedef struct { intmax_t quot, rem; } imaxdiv_t;
intmax_t imaxabs(intmax_t);
imaxdiv_t imaxdiv(intmax_t, intmax_t);
intmax_t strtoimax(const char *__restrict, char **__restrict, int);
uintmax_t strtoumax(const char *__restrict, char **__restrict, int);
#ifndef LIBCL4
intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int);
uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int);
#endif /* LIBCL4 */
#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"
#define SCNd8 "hhd"
#define SCNd16 "hd"
#define SCNd32 "d"
#define SCNd64 __PRI64 "d"
#define SCNdLEAST8 "hhd"
#define SCNdLEAST16 "hd"
#define SCNdLEAST32 "d"
#define SCNdLEAST64 __PRI64 "d"
#define SCNdFAST8 "hhd"
#define SCNdFAST16 "d"
#define SCNdFAST32 "d"
#define SCNdFAST64 __PRI64 "d"
#define SCNi8 "hhi"
#define SCNi16 "hi"
#define SCNi32 "i"
#define SCNi64 __PRI64 "i"
#define SCNiLEAST8 "hhi"
#define SCNiLEAST16 "hi"
#define SCNiLEAST32 "i"
#define SCNiLEAST64 __PRI64 "i"
#define SCNiFAST8 "hhi"
#define SCNiFAST16 "i"
#define SCNiFAST32 "i"
#define SCNiFAST64 __PRI64 "i"
#define SCNu8 "hhu"
#define SCNu16 "hu"
#define SCNu32 "u"
#define SCNu64 __PRI64 "u"
#define SCNuLEAST8 "hhu"
#define SCNuLEAST16 "hu"
#define SCNuLEAST32 "u"
#define SCNuLEAST64 __PRI64 "u"
#define SCNuFAST8 "hhu"
#define SCNuFAST16 "u"
#define SCNuFAST32 "u"
#define SCNuFAST64 __PRI64 "u"
#define SCNo8 "hho"
#define SCNo16 "ho"
#define SCNo32 "o"
#define SCNo64 __PRI64 "o"
#define SCNoLEAST8 "hho"
#define SCNoLEAST16 "ho"
#define SCNoLEAST32 "o"
#define SCNoLEAST64 __PRI64 "o"
#define SCNoFAST8 "hho"
#define SCNoFAST16 "o"
#define SCNoFAST32 "o"
#define SCNoFAST64 __PRI64 "o"
#define SCNx8 "hhx"
#define SCNx16 "hx"
#define SCNx32 "x"
#define SCNx64 __PRI64 "x"
#define SCNxLEAST8 "hhx"
#define SCNxLEAST16 "hx"
#define SCNxLEAST32 "x"
#define SCNxLEAST64 __PRI64 "x"
#define SCNxFAST8 "hhx"
#define SCNxFAST16 "x"
#define SCNxFAST32 "x"
#define SCNxFAST64 __PRI64 "x"
#define SCNdMAX __PRI64 "d"
#define SCNiMAX __PRI64 "i"
#define SCNoMAX __PRI64 "o"
#define SCNuMAX __PRI64 "u"
#define SCNxMAX __PRI64 "x"
#define SCNdPTR __PRIPTR "d"
#define SCNiPTR __PRIPTR "i"
#define SCNoPTR __PRIPTR "o"
#define SCNuPTR __PRIPTR "u"
#define SCNxPTR __PRIPTR "x"
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,18 @@
/* This file defines the backend interface */
/* of the kernel c-library. */
#pragma once
#include <stddef.h>
/**
* The text output backend.
*
* This function must be provided to the c-library for
* text output. It must simply send len characters of s
* to an output device.
*
* @param s the string to send (not zero terminated).
* @param len the number of characters.
* @return 1 on success, 0 else.
*/
int __libc_backend_outs(const char *s, size_t len);

View File

@@ -0,0 +1,168 @@
#ifndef _LIMITS_H
#define _LIMITS_H
#include <features.h>
#include <bits/alltypes.h> /* __LONG_MAX */
/* Support signed or unsigned plain-char */
#if '\xff' > 0
#define CHAR_MIN 0
#define CHAR_MAX 255
#else
#define CHAR_MIN (-128)
#define CHAR_MAX 127
#endif
#define CHAR_BIT 8
#define SCHAR_MIN (-128)
#define SCHAR_MAX 127
#define UCHAR_MAX 255
#define SHRT_MIN (-1-0x7fff)
#define SHRT_MAX 0x7fff
#define USHRT_MAX 0xffff
#define INT_MIN (-1-0x7fffffff)
#define INT_MAX 0x7fffffff
#define UINT_MAX 0xffffffffU
#define LONG_MIN (-LONG_MAX-1)
#define LONG_MAX __LONG_MAX
#define ULONG_MAX (2UL*LONG_MAX+1)
#define LLONG_MIN (-LLONG_MAX-1)
#define LLONG_MAX 0x7fffffffffffffffLL
#define ULLONG_MAX (2ULL*LLONG_MAX+1)
#define MB_LEN_MAX 4
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#include <bits/limits.h>
#define PIPE_BUF 4096
#define FILESIZEBITS 64
#ifndef NAME_MAX
#define NAME_MAX 255
#endif
#define PATH_MAX 4096
#define NGROUPS_MAX 32
#define ARG_MAX 131072
#define IOV_MAX 1024
#define SYMLOOP_MAX 40
#define WORD_BIT 32
#define SSIZE_MAX LONG_MAX
#define TZNAME_MAX 6
#define TTY_NAME_MAX 32
#define HOST_NAME_MAX 255
#if LONG_MAX == 0x7fffffffL
#define LONG_BIT 32
#else
#define LONG_BIT 64
#endif
/* Implementation choices... */
#define PTHREAD_KEYS_MAX 128
#define PTHREAD_STACK_MIN 2048
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
#define SEM_VALUE_MAX 0x7fffffff
#define SEM_NSEMS_MAX 256
#define DELAYTIMER_MAX 0x7fffffff
#define MQ_PRIO_MAX 32768
#define LOGIN_NAME_MAX 256
/* Arbitrary numbers... */
#define BC_BASE_MAX 99
#define BC_DIM_MAX 2048
#define BC_SCALE_MAX 99
#define BC_STRING_MAX 1000
#define CHARCLASS_NAME_MAX 14
#define COLL_WEIGHTS_MAX 2
#define EXPR_NEST_MAX 32
#define LINE_MAX 4096
#define RE_DUP_MAX 255
#define NL_ARGMAX 9
#define NL_MSGMAX 32767
#define NL_SETMAX 255
#define NL_TEXTMAX 2048
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE)
#ifndef LIBCL4
#ifdef PAGESIZE
#define PAGE_SIZE PAGESIZE
#endif
#endif /* LIBCL4 */
#define NZERO 20
#define NL_LANGMAX 32
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) \
|| (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE+0 < 700)
#define NL_NMAX 16
#endif
/* POSIX/SUS requirements follow. These numbers come directly
* from SUS and have nothing to do with the host system. */
#define _POSIX_AIO_LISTIO_MAX 2
#define _POSIX_AIO_MAX 1
#define _POSIX_ARG_MAX 4096
#define _POSIX_CHILD_MAX 25
#define _POSIX_CLOCKRES_MIN 20000000
#define _POSIX_DELAYTIMER_MAX 32
#define _POSIX_HOST_NAME_MAX 255
#define _POSIX_LINK_MAX 8
#define _POSIX_LOGIN_NAME_MAX 9
#define _POSIX_MAX_CANON 255
#define _POSIX_MAX_INPUT 255
#define _POSIX_MQ_OPEN_MAX 8
#define _POSIX_MQ_PRIO_MAX 32
#define _POSIX_NAME_MAX 14
#define _POSIX_NGROUPS_MAX 8
#define _POSIX_OPEN_MAX 20
#define _POSIX_PATH_MAX 256
#define _POSIX_PIPE_BUF 512
#define _POSIX_RE_DUP_MAX 255
#define _POSIX_RTSIG_MAX 8
#define _POSIX_SEM_NSEMS_MAX 256
#define _POSIX_SEM_VALUE_MAX 32767
#define _POSIX_SIGQUEUE_MAX 32
#define _POSIX_SSIZE_MAX 32767
#define _POSIX_STREAM_MAX 8
#define _POSIX_SS_REPL_MAX 4
#define _POSIX_SYMLINK_MAX 255
#define _POSIX_SYMLOOP_MAX 8
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
#define _POSIX_THREAD_KEYS_MAX 128
#define _POSIX_THREAD_THREADS_MAX 64
#define _POSIX_TIMER_MAX 32
#define _POSIX_TRACE_EVENT_NAME_MAX 30
#define _POSIX_TRACE_NAME_MAX 8
#define _POSIX_TRACE_SYS_MAX 8
#define _POSIX_TRACE_USER_EVENT_MAX 32
#define _POSIX_TTY_NAME_MAX 9
#define _POSIX_TZNAME_MAX 6
#define _POSIX2_BC_BASE_MAX 99
#define _POSIX2_BC_DIM_MAX 2048
#define _POSIX2_BC_SCALE_MAX 99
#define _POSIX2_BC_STRING_MAX 1000
#define _POSIX2_CHARCLASS_NAME_MAX 14
#define _POSIX2_COLL_WEIGHTS_MAX 2
#define _POSIX2_EXPR_NEST_MAX 32
#define _POSIX2_LINE_MAX 2048
#define _POSIX2_RE_DUP_MAX 255
#define _XOPEN_IOV_MAX 16
#define _XOPEN_NAME_MAX 255
#define _XOPEN_PATH_MAX 1024
#endif

View File

@@ -0,0 +1,21 @@
#ifndef _STDARG_H
#define _STDARG_H
#ifdef __cplusplus
extern "C" {
#endif
#define __NEED_va_list
#include <bits/alltypes.h>
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
#define va_copy(d,s) __builtin_va_copy(d,s)
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,29 @@
#ifndef _STDDEF_H
#define _STDDEF_H
#include <features.h>
#if defined(__cplusplus) && __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)
#endif
#define __NEED_ptrdiff_t
#define __NEED_size_t
#define __NEED_wchar_t
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || __cplusplus >= 201103L
#define __NEED_max_align_t
#endif
#include <bits/alltypes.h>
#if __GNUC__ > 3
#define offsetof(type, member) __builtin_offsetof(type, member)
#else
#define offsetof(type, member) ((size_t)( (char *)&(((type *)0)->member) - (char *)0 ))
#endif
#endif

View File

@@ -0,0 +1,117 @@
#ifndef _STDINT_H
#define _STDINT_H
#define __NEED_int8_t
#define __NEED_int16_t
#define __NEED_int32_t
#define __NEED_int64_t
#define __NEED_uint8_t
#define __NEED_uint16_t
#define __NEED_uint32_t
#define __NEED_uint64_t
#define __NEED_intptr_t
#define __NEED_uintptr_t
#define __NEED_intmax_t
#define __NEED_uintmax_t
#include <bits/alltypes.h>
typedef int8_t int_fast8_t;
typedef int64_t int_fast64_t;
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_fast8_t;
typedef uint64_t uint_fast64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
#define INT8_MIN (-1-0x7f)
#define INT16_MIN (-1-0x7fff)
#define INT32_MIN (-1-0x7fffffff)
#define INT64_MIN (-1-0x7fffffffffffffff)
#define INT8_MAX (0x7f)
#define INT16_MAX (0x7fff)
#define INT32_MAX (0x7fffffff)
#define INT64_MAX (0x7fffffffffffffff)
#define UINT8_MAX (0xff)
#define UINT16_MAX (0xffff)
#define UINT32_MAX (0xffffffffu)
#define UINT64_MAX (0xffffffffffffffffu)
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST64_MIN INT64_MIN
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST64_MIN INT64_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST64_MAX INT64_MAX
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST64_MAX UINT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
#define WINT_MIN 0U
#define WINT_MAX UINT32_MAX
#if L'\0'-1 > 0
#define WCHAR_MAX (0xffffffffu+L'\0')
#define WCHAR_MIN (0+L'\0')
#else
#define WCHAR_MAX (0x7fffffff+L'\0')
#define WCHAR_MIN (-1-0x7fffffff+L'\0')
#endif
#define SIG_ATOMIC_MIN INT32_MIN
#define SIG_ATOMIC_MAX INT32_MAX
#include <bits/stdint.h>
#define INT8_C(c) c
#define INT16_C(c) c
#define INT32_C(c) c
#define UINT8_C(c) c
#define UINT16_C(c) c
#define UINT32_C(c) c ## U
#if UINTPTR_MAX == UINT64_MAX
#define INT64_C(c) c ## L
#define UINT64_C(c) c ## UL
#define INTMAX_C(c) c ## L
#define UINTMAX_C(c) c ## UL
#else
#define INT64_C(c) c ## LL
#define UINT64_C(c) c ## ULL
#define INTMAX_C(c) c ## LL
#define UINTMAX_C(c) c ## ULL
#endif
#endif

View File

@@ -0,0 +1,237 @@
#ifndef _STDIO_H
#define _STDIO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <features.h>
#define __NEED_FILE
#define __NEED___isoc_va_list
#define __NEED_size_t
#ifndef LIBCL4
#if __STDC_VERSION__ < 201112L
#define __NEED_struct__IO_FILE
#endif
#endif /* LIBCL4 */
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
#define __NEED_ssize_t
#define __NEED_off_t
#define __NEED_va_list
#endif
#include <bits/alltypes.h>
#if defined(__cplusplus) && __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)
#endif
#undef EOF
#define EOF (-1)
#undef SEEK_SET
#undef SEEK_CUR
#undef SEEK_END
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define _IOFBF 0
#define _IOLBF 1
#define _IONBF 2
#define BUFSIZ 1024
#define FILENAME_MAX 4096
#define FOPEN_MAX 1000
#define TMP_MAX 10000
#define L_tmpnam 20
typedef union _G_fpos64_t {
char __opaque[16];
long long __lldata;
double __align;
} fpos_t;
#ifndef LIBCL4
extern FILE *const stdin;
extern FILE *const stdout;
extern FILE *const stderr;
#define stdin (stdin)
#define stdout (stdout)
#define stderr (stderr)
#endif /* LIBCL4 */
FILE *fopen(const char *__restrict, const char *__restrict);
FILE *freopen(const char *__restrict, const char *__restrict, FILE *__restrict);
int fclose(FILE *);
int remove(const char *);
int rename(const char *, const char *);
int feof(FILE *);
int ferror(FILE *);
int fflush(FILE *);
void clearerr(FILE *);
int fseek(FILE *, long, int);
long ftell(FILE *);
void rewind(FILE *);
int fgetpos(FILE *__restrict, fpos_t *__restrict);
int fsetpos(FILE *, const fpos_t *);
size_t fread(void *__restrict, size_t, size_t, FILE *__restrict);
size_t fwrite(const void *__restrict, size_t, size_t, FILE *__restrict);
int fgetc(FILE *);
int getc(FILE *);
int getchar(void);
int ungetc(int, FILE *);
int fputc(int, FILE *);
int putc(int, FILE *);
int putchar(int);
char *fgets(char *__restrict, int, FILE *__restrict);
#ifndef LIBCL4
#if __STDC_VERSION__ < 201112L
char *gets(char *);
#endif
#endif /* LIBCL4 */
int fputs(const char *__restrict, FILE *__restrict);
int puts(const char *);
int printf(const char *__restrict, ...);
int fprintf(FILE *__restrict, const char *__restrict, ...);
int sprintf(char *__restrict, const char *__restrict, ...);
int snprintf(char *__restrict, size_t, const char *__restrict, ...);
int vprintf(const char *__restrict, __isoc_va_list);
int vfprintf(FILE *__restrict, const char *__restrict, __isoc_va_list);
int vsprintf(char *__restrict, const char *__restrict, __isoc_va_list);
int vsnprintf(char *__restrict, size_t, const char *__restrict, __isoc_va_list);
int scanf(const char *__restrict, ...);
int fscanf(FILE *__restrict, const char *__restrict, ...);
int sscanf(const char *__restrict, const char *__restrict, ...);
int vscanf(const char *__restrict, __isoc_va_list);
int vfscanf(FILE *__restrict, const char *__restrict, __isoc_va_list);
int vsscanf(const char *__restrict, const char *__restrict, __isoc_va_list);
void perror(const char *);
int setvbuf(FILE *__restrict, char *__restrict, int, size_t);
void setbuf(FILE *__restrict, char *__restrict);
char *tmpnam(char *);
FILE *tmpfile(void);
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
FILE *fmemopen(void *__restrict, size_t, const char *__restrict);
FILE *open_memstream(char **, size_t *);
FILE *fdopen(int, const char *);
FILE *popen(const char *, const char *);
int pclose(FILE *);
int fileno(FILE *);
int fseeko(FILE *, off_t, int);
off_t ftello(FILE *);
int dprintf(int, const char *__restrict, ...);
int vdprintf(int, const char *__restrict, __isoc_va_list);
void flockfile(FILE *);
int ftrylockfile(FILE *);
void funlockfile(FILE *);
int getc_unlocked(FILE *);
int getchar_unlocked(void);
int putc_unlocked(int, FILE *);
int putchar_unlocked(int);
ssize_t getdelim(char **__restrict, size_t *__restrict, int, FILE *__restrict);
ssize_t getline(char **__restrict, size_t *__restrict, FILE *__restrict);
int renameat(int, const char *, int, const char *);
char *ctermid(char *);
#define L_ctermid 20
#endif
#if defined(_GNU_SOURCE)
#define RENAME_NOREPLACE (1 << 0)
#define RENAME_EXCHANGE (1 << 1)
#define RENAME_WHITEOUT (1 << 2)
int renameat2(int, const char *, int, const char *, unsigned);
#endif
#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
#define P_tmpdir "/tmp"
char *tempnam(const char *, const char *);
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define L_cuserid 20
char *cuserid(char *);
void setlinebuf(FILE *);
void setbuffer(FILE *, char *, size_t);
int fgetc_unlocked(FILE *);
int fputc_unlocked(int, FILE *);
int fflush_unlocked(FILE *);
size_t fread_unlocked(void *, size_t, size_t, FILE *);
size_t fwrite_unlocked(const void *, size_t, size_t, FILE *);
void clearerr_unlocked(FILE *);
int feof_unlocked(FILE *);
int ferror_unlocked(FILE *);
int fileno_unlocked(FILE *);
int getw(FILE *);
int putw(int, FILE *);
char *fgetln(FILE *, size_t *);
int asprintf(char **, const char *, ...);
int vasprintf(char **, const char *, __isoc_va_list);
#endif
#ifdef _GNU_SOURCE
char *fgets_unlocked(char *, int, FILE *);
int fputs_unlocked(const char *, FILE *);
typedef ssize_t (cookie_read_function_t)(void *, char *, size_t);
typedef ssize_t (cookie_write_function_t)(void *, const char *, size_t);
typedef int (cookie_seek_function_t)(void *, off_t *, int);
typedef int (cookie_close_function_t)(void *);
typedef struct _IO_cookie_io_functions_t {
cookie_read_function_t *read;
cookie_write_function_t *write;
cookie_seek_function_t *seek;
cookie_close_function_t *close;
} cookie_io_functions_t;
FILE *fopencookie(void *, const char *, cookie_io_functions_t);
#endif
#if defined(_LARGEFILE64_SOURCE)
#define tmpfile64 tmpfile
#define fopen64 fopen
#define freopen64 freopen
#define fseeko64 fseeko
#define ftello64 ftello
#define fgetpos64 fgetpos
#define fsetpos64 fsetpos
#define fpos64_t fpos_t
#define off64_t off_t
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,177 @@
#ifndef _STDLIB_H
#define _STDLIB_H
#ifdef __cplusplus
extern "C" {
#endif
#include <features.h>
#if defined(__cplusplus) && __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)
#endif
#define __NEED_size_t
#define __NEED_wchar_t
#include <bits/alltypes.h>
int atoi (const char *);
long atol (const char *);
long long atoll (const char *);
double atof (const char *);
float strtof (const char *__restrict, char **__restrict);
double strtod (const char *__restrict, char **__restrict);
long double strtold (const char *__restrict, char **__restrict);
long strtol (const char *__restrict, char **__restrict, int);
unsigned long strtoul (const char *__restrict, char **__restrict, int);
long long strtoll (const char *__restrict, char **__restrict, int);
unsigned long long strtoull (const char *__restrict, char **__restrict, int);
int rand (void);
void srand (unsigned);
void *malloc (size_t);
void *calloc (size_t, size_t);
void *realloc (void *, size_t);
void free (void *);
void *aligned_alloc(size_t, size_t);
_Noreturn void abort (void);
int atexit (void (*) (void));
_Noreturn void exit (int);
_Noreturn void _Exit (int);
int at_quick_exit (void (*) (void));
_Noreturn void quick_exit (int);
char *getenv (const char *);
int system (const char *);
void *bsearch (const void *, const void *, size_t, size_t, int (*)(const void *, const void *));
void qsort (void *, size_t, size_t, int (*)(const void *, const void *));
int abs (int);
long labs (long);
long long llabs (long long);
typedef struct { int quot, rem; } div_t;
typedef struct { long quot, rem; } ldiv_t;
typedef struct { long long quot, rem; } lldiv_t;
div_t div (int, int);
ldiv_t ldiv (long, long);
lldiv_t lldiv (long long, long long);
#ifndef LIBCL4
int mblen (const char *, size_t);
int mbtowc (wchar_t *__restrict, const char *__restrict, size_t);
int wctomb (char *, wchar_t);
size_t mbstowcs (wchar_t *__restrict, const char *__restrict, size_t);
size_t wcstombs (char *__restrict, const wchar_t *__restrict, size_t);
#endif /* LIBCL4 */
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
size_t __ctype_get_mb_cur_max(void);
#define MB_CUR_MAX (__ctype_get_mb_cur_max())
#define RAND_MAX (0x7fffffff)
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
#define WNOHANG 1
#define WUNTRACED 2
#define WEXITSTATUS(s) (((s) & 0xff00) >> 8)
#define WTERMSIG(s) ((s) & 0x7f)
#define WSTOPSIG(s) WEXITSTATUS(s)
#define WIFEXITED(s) (!WTERMSIG(s))
#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00)
#define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
int posix_memalign (void **, size_t, size_t);
int setenv (const char *, const char *, int);
int unsetenv (const char *);
int mkstemp (char *);
int mkostemp (char *, int);
char *mkdtemp (char *);
int getsubopt (char **, char *const *, char **);
int rand_r (unsigned *);
#endif
#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
char *realpath (const char *__restrict, char *__restrict);
long int random (void);
void srandom (unsigned int);
char *initstate (unsigned int, char *, size_t);
char *setstate (char *);
int putenv (char *);
int posix_openpt (int);
int grantpt (int);
int unlockpt (int);
char *ptsname (int);
char *l64a (long);
long a64l (const char *);
void setkey (const char *);
double drand48 (void);
double erand48 (unsigned short [3]);
long int lrand48 (void);
long int nrand48 (unsigned short [3]);
long mrand48 (void);
long jrand48 (unsigned short [3]);
void srand48 (long);
unsigned short *seed48 (unsigned short [3]);
void lcong48 (unsigned short [7]);
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#include <alloca.h>
char *mktemp (char *);
int mkstemps (char *, int);
int mkostemps (char *, int, int);
void *valloc (size_t);
void *memalign(size_t, size_t);
int getloadavg(double *, int);
int clearenv(void);
#define WCOREDUMP(s) ((s) & 0x80)
#define WIFCONTINUED(s) ((s) == 0xffff)
void *reallocarray (void *, size_t, size_t);
void qsort_r (void *, size_t, size_t, int (*)(const void *, const void *, void *), void *);
#endif
#ifdef _GNU_SOURCE
int ptsname_r(int, char *, size_t);
char *ecvt(double, int, int *, int *);
char *fcvt(double, int, int *, int *);
char *gcvt(double, int, char *);
char *secure_getenv(const char *);
#endif
#if defined(_LARGEFILE64_SOURCE)
#define mkstemp64 mkstemp
#define mkostemp64 mkostemp
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define mkstemps64 mkstemps
#define mkostemps64 mkostemps
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,97 @@
#ifndef _STRING_H
#define _STRING_H
#ifdef __cplusplus
extern "C" {
#endif
#include <features.h>
#if defined(__cplusplus) && __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__cplusplus)
#define NULL 0L
#else
#define NULL ((void*)0)
#endif
#define __NEED_size_t
#include <bits/alltypes.h>
void *memcpy (void *__restrict, const void *__restrict, size_t);
void *memmove (void *, const void *, size_t);
void *memset (void *, int, size_t);
int memcmp (const void *, const void *, size_t);
void *memchr (const void *, int, size_t);
char *strcpy (char *__restrict, const char *__restrict);
char *strncpy (char *__restrict, const char *__restrict, size_t);
char *strcat (char *__restrict, const char *__restrict);
char *strncat (char *__restrict, const char *__restrict, size_t);
int strcmp (const char *, const char *);
int strncmp (const char *, const char *, size_t);
int strcoll (const char *, const char *);
size_t strxfrm (char *__restrict, const char *__restrict, size_t);
char *strchr (const char *, int);
char *strrchr (const char *, int);
size_t strcspn (const char *, const char *);
size_t strspn (const char *, const char *);
char *strpbrk (const char *, const char *);
char *strstr (const char *, const char *);
char *strtok (char *__restrict, const char *__restrict);
size_t strlen (const char *);
char *strerror (int);
#ifndef LIBCL4
#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
#include <strings.h>
#endif
#endif
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
char *strtok_r (char *__restrict, const char *__restrict, char **__restrict);
int strerror_r (int, char *, size_t);
char *stpcpy(char *__restrict, const char *__restrict);
char *stpncpy(char *__restrict, const char *__restrict, size_t);
size_t strnlen (const char *, size_t);
char *strdup (const char *);
char *strndup (const char *, size_t);
char *strsignal(int);
void *memmem(const void *, size_t, const void *, size_t);
#endif
#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
void *memccpy (void *__restrict, const void *__restrict, int, size_t);
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
char *strsep(char **, const char *);
size_t strlcat (char *, const char *, size_t);
size_t strlcpy (char *, const char *, size_t);
void explicit_bzero (void *, size_t);
#endif
#ifdef _GNU_SOURCE
#define strdupa(x) strcpy(alloca(strlen(x)+1),x)
int strverscmp (const char *, const char *);
char *strchrnul(const char *, int);
char *strcasestr(const char *, const char *);
void *memrchr(const void *, int, size_t);
void *mempcpy(void *, const void *, size_t);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,7 @@
#pragma once
#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)

View File

@@ -0,0 +1 @@
/* */

View File

@@ -0,0 +1,7 @@
#include <ctype.h>
#undef isdigit
int isdigit(int c)
{
return (unsigned)c-'0' < 10;
}

View File

@@ -0,0 +1,13 @@
#ifndef FEATURES_H
#define FEATURES_H
#include "../../include/features.h"
#ifndef LIBCL4
#define weak __attribute__((__weak__))
#endif /* LIBCL4 */
#define hidden __attribute__((__visibility__("hidden")))
#define weak_alias(old, new) \
extern __typeof(old) new __attribute__((__weak__, __alias__(#old)))
#endif

View File

@@ -0,0 +1,5 @@
#pragma once
#include "stdio_impl.h"
size_t __libc_stdout_write(FILE *f, const unsigned char *buf, size_t len);

View File

@@ -0,0 +1,24 @@
#ifndef STDIO_H
#define STDIO_H
#define __DEFINED_struct__IO_FILE
#include "../../include/stdio.h"
#ifndef LIBCL4
#undef stdin
#undef stdout
#undef stderr
extern hidden FILE __stdin_FILE;
extern hidden FILE __stdout_FILE;
extern hidden FILE __stderr_FILE;
#define stdin (&__stdin_FILE)
#define stdout (&__stdout_FILE)
#define stderr (&__stderr_FILE)
#endif /* LIBCL4 */
#endif

View File

@@ -0,0 +1,124 @@
#ifndef _STDIO_IMPL_H
#define _STDIO_IMPL_H
#include <stdio.h>
#include "syscall.h"
#ifdef LIBCL4
#include "libc_backend.h"
#endif /* LIBCL4 */
#define UNGET 8
#define FFINALLOCK(f) ((f)->lock>=0 ? __lockfile((f)) : 0)
#ifndef LIBCL4
#define FLOCK(f) int __need_unlock = ((f)->lock>=0 ? __lockfile((f)) : 0)
#define FUNLOCK(f) do { if (__need_unlock) __unlockfile((f)); } while (0)
#else /* LIBCL4 */
#define FLOCK(f) do { } while (0)
#define FUNLOCK(f) do { } while (0)
#endif /* LIBCL4 */
#ifndef LIBCL4
#define F_PERM 1
#define F_NORD 4
#define F_NOWR 8
#define F_EOF 16
#define F_ERR 32
#define F_SVB 64
#define F_APP 128
#endif
/* LIBCL4: save some stack. Maybe remove even more. */
struct _IO_FILE {
#ifndef LIBCL4
unsigned flags;
#endif
unsigned char *rpos;
#ifndef LIBCL4
int (*close)(FILE *);
#endif
unsigned char *wend, *wpos;
#ifndef LIBCL4
unsigned char *mustbezero_1;
#endif
unsigned char *wbase;
size_t (*read)(FILE *, unsigned char *, size_t);
size_t (*write)(FILE *, const unsigned char *, size_t);
#ifndef LIBCL4
off_t (*seek)(FILE *, off_t, int);
#endif
unsigned char *buf;
size_t buf_size;
#ifndef LIBCL4
FILE *prev, *next;
int fd;
int pipe_pid;
long lockcount;
int mode;
#endif
volatile int lock;
int lbf;
void *cookie;
#ifndef LIBCL4
off_t off;
char *getln_buf;
void *mustbezero_2;
unsigned char *shend;
off_t shlim, shcnt;
FILE *prev_locked, *next_locked;
#endif
};
extern hidden FILE *volatile __stdin_used;
extern hidden FILE *volatile __stdout_used;
extern hidden FILE *volatile __stderr_used;
hidden int __lockfile(FILE *);
hidden void __unlockfile(FILE *);
hidden size_t __stdio_read(FILE *, unsigned char *, size_t);
hidden size_t __stdio_write(FILE *, const unsigned char *, size_t);
hidden size_t __stdout_write(FILE *, const unsigned char *, size_t);
hidden off_t __stdio_seek(FILE *, off_t, int);
hidden int __stdio_close(FILE *);
hidden int __towrite(FILE *);
hidden void __stdio_exit(void);
hidden void __stdio_exit_needed(void);
hidden int __fseeko(FILE *, off_t, int);
hidden int __fseeko_unlocked(FILE *, off_t, int);
hidden off_t __ftello(FILE *);
hidden off_t __ftello_unlocked(FILE *);
hidden size_t __fwritex(const unsigned char *, size_t, FILE *);
hidden int __putc_unlocked(int, FILE *);
hidden FILE *__fdopen(int, const char *);
hidden int __fmodeflags(const char *);
hidden FILE *__ofl_add(FILE *f);
hidden FILE **__ofl_lock(void);
hidden void __ofl_unlock(void);
struct __pthread;
hidden void __register_locked_file(FILE *, struct __pthread *);
hidden void __unlist_locked_file(FILE *);
hidden void __do_orphaned_stdio_locks(void);
#define MAYBE_WAITERS 0x40000000
hidden void __getopt_msg(const char *, const char *, const char *, size_t);
#ifndef LIBCL4
#define feof(f) ((f)->flags & F_EOF)
#define ferror(f) ((f)->flags & F_ERR)
#else
#define ferror(f) 0
#endif
/* Caller-allocated FILE * operations */
hidden FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t);
hidden int __fclose_ca(FILE *);
#endif

View File

@@ -0,0 +1,27 @@
#include "stdio_impl.h"
int __towrite(FILE *f)
{
#ifndef LIBCL4
f->mode |= f->mode-1;
if (f->flags & F_NOWR) {
f->flags |= F_ERR;
return EOF;
}
#endif
/* Clear read buffer (easier than summoning nasal demons) */
f->rpos = 0;
/* Activate write through the buffer. */
f->wpos = f->wbase = f->buf;
f->wend = f->buf + f->buf_size;
return 0;
}
#ifndef LIBCL4
hidden void __towrite_needs_stdio_exit()
{
__stdio_exit_needed();
}
#endif /* LIBCL4 */

View File

@@ -0,0 +1,10 @@
#include "stdio_impl.h"
#include <string.h>
int fputs(const char *restrict s, FILE *restrict f)
{
size_t l = strlen(s);
return (fwrite(s, 1, l, f)==l) - 1;
}
weak_alias(fputs, fputs_unlocked);

View File

@@ -0,0 +1,40 @@
#include "stdio_impl.h"
#include <string.h>
size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f)
{
size_t i=0;
if (!f->wend && __towrite(f)) return 0;
if (l > (size_t)(f->wend - f->wpos)) return f->write(f, s, l);
if (f->lbf >= 0) {
/* Match /^(.*\n|)/ */
for (i=l; i && s[i-1] != '\n'; i--);
if (i) {
size_t n = f->write(f, s, i);
if (n < i) return n;
s += i;
l -= i;
}
}
memcpy(f->wpos, s, l);
f->wpos += l;
return l+i;
}
size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f)
{
size_t k, l = size*nmemb;
if (!size) nmemb = 0;
FLOCK(f);
k = __fwritex(src, l, f);
FUNLOCK(f);
return k==l ? nmemb : k/size;
}
#ifndef LIBCL4
weak_alias(fwrite, fwrite_unlocked);
#endif /* LIBCL4 */

View File

@@ -0,0 +1,734 @@
#include "stdio_impl.h"
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#ifndef LIBCL4
#include <wchar.h>
#endif /* LIBCL4 */
#include <inttypes.h>
#ifndef LIBCL4
#include <math.h>
#include <float.h>
#endif /* LIBCL4 */
/* 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)
/* 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,
LONG, ULONG,
SHORT, USHORT, CHAR, UCHAR,
LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
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') = INT, S('C') = UINT,
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') = UINT, 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)
{
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);
break; case LONG: arg->i = va_arg(*ap, long);
break; case ULONG: arg->i = va_arg(*ap, unsigned long);
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);
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 *);
#ifndef LIBCL4
break; case DBL: arg->f = va_arg(*ap, double);
break; case LDBL: arg->f = va_arg(*ap, long double);
#endif /* LIBCL4 */
}
}
static void out(FILE *f, const char *s, size_t l)
{
if (!ferror(f)) __fwritex((void *)s, l, f);
}
static void pad(FILE *f, char c, size_t w, size_t 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] = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
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>=10; y/=10) *--s = '0' + y%10;
if (y) *--s = '0' + y;
return s;
}
#ifndef LIBCL4
/* 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, long double y, int w, int p, int fl, int t, int ps)
{
int bufsize = (ps==BIGLPRE)
? (LDBL_MANT_DIG+28)/29 + 1 + // mantissa expansion
(LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9 // exponent expansion
: (DBL_MANT_DIG+28)/29 + 1 +
(DBL_MAX_EXP+DBL_MANT_DIG+28+8)/9;
uint32_t big[bufsize];
uint32_t *a, *d, *r, *z;
int e2=0, e, i, j, l;
char buf[9+LDBL_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 = frexpl(y, &e2) * 2;
if (y) e2--;
if ((t|32)=='a') {
if (t&32) prefix += 9;
pl += 2;
if (p>=0 && p<(LDBL_MANT_DIG-1+3)/4) {
double round = scalbn(1, LDBL_MANT_DIG-1-(p*4));
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 > INT_MAX-2-(ebuf-estr)-pl)
return -1;
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) - LDBL_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+LDBL_MANT_DIG/3U+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*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
j += 9*LDBL_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) {
long double round = 2/LDBL_EPSILON;
long double small;
if ((*d/i & 1) || (i==1000000000 && d>a && (d[-1]&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));
}
}
if (p > INT_MAX-1-(p || (fl&ALT_FORM)))
return -1;
l = 1 + p + (p || (fl&ALT_FORM));
if ((t|32)=='f') {
if (e > INT_MAX-l) return -1;
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;
if (ebuf-estr > INT_MAX-l) return -1;
l += ebuf-estr;
}
if (l > INT_MAX-pl) return -1;
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);
}
#endif /* LIBCL4 */
static int getint(char **s) {
int i;
for (i=0; isdigit(**s); (*s)++) {
if ((unsigned)i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1;
else i = 10*i + (**s-'0');
}
return i;
}
static 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, xp;
union arg arg;
int argpos;
unsigned st, ps;
int cnt=0, l=0;
size_t i;
char buf[sizeof(uintmax_t)*3];
const char *prefix;
int t, pl;
wchar_t wc[2];
#ifndef LIBCL4
wchar_t *ws;
char mb[4];
#endif
for (;;) {
/* This error is only specified for snprintf, but since it's
* unspecified for other forms, do the same. Stop immediately
* on overflow; otherwise %n could produce wrong results. */
if (l > INT_MAX - cnt) goto overflow;
/* Update output count, end loop when fmt is exhausted */
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);
if (z-a > INT_MAX-cnt) goto overflow;
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;
if (!f) nl_type[s[1]-'0'] = INT, w = 0;
else w = nl_arg[s[1]-'0'].i;
s+=3;
} else if (!l10n) {
w = f ? va_arg(*ap, int) : 0;
s++;
} else goto inval;
if (w<0) fl|=LEFT_ADJ, w=-w;
} else if ((w=getint(&s))<0) goto overflow;
/* Read precision */
if (*s=='.' && s[1]=='*') {
if (isdigit(s[2]) && s[3]=='$') {
if (!f) nl_type[s[2]-'0'] = INT, p = 0;
else p = nl_arg[s[2]-'0'].i;
s+=4;
} else if (!l10n) {
p = f ? va_arg(*ap, int) : 0;
s+=2;
} else goto inval;
xp = (p>=0);
} else if (*s=='.') {
s++;
p = getint(&s);
xp = 1;
} else {
p = -1;
xp = 0;
}
/* Format specifier state machine */
st=0;
do {
if (OOB(*s)) goto inval;
ps=st;
st=states[st]S(*s++);
} while (st-1<STOP);
if (!st) goto inval;
/* Check validity of argument type (nl/normal) */
if (st==NOARG) {
if (argpos>=0) goto inval;
} else {
if (argpos>=0) {
if (!f) nl_type[argpos]=st;
else arg=nl_arg[argpos];
} else if (f) pop_arg(&arg, st, ap);
else return 0;
}
if (!f) continue;
/* Do not process any new directives once in error state. */
if (ferror(f)) return -1;
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, (int)(2*sizeof(void*)));
t = 'x';
fl |= ALT_FORM;
// fallthrough
case 'x': case 'X':
a = fmt_x(arg.i, z, t&32);
if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2;
goto ifmt_tail;
case 'o':
a = fmt_o(arg.i, z);
if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1;
goto ifmt_tail;
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;
// fallthrough
case 'u':
a = fmt_u(arg.i, z);
ifmt_tail:
if (xp && p<0) goto overflow;
if (xp) fl &= ~ZERO_PAD;
if (!arg.i && !p) {
a=z;
break;
}
p = MAX(p, z-a + !arg.i);
break;
narrow_c:
case 'c':
*(a=z-(p=1))=arg.i;
fl &= ~ZERO_PAD;
break;
#ifndef LIBCL4
case 'm':
if (1) a = strerror(errno); else
#endif /* LIBCL4 */
case 's':
a = arg.p ? arg.p : "(null)";
z = a + strnlen(a, p<0 ? INT_MAX : p);
if (p<0 && *z) goto overflow;
p = z-a;
fl &= ~ZERO_PAD;
break;
case 'C':
if (!arg.i) goto narrow_c;
wc[0] = arg.i;
wc[1] = 0;
arg.p = wc;
p = -1;
#ifndef LIBCL4
case 'S':
ws = arg.p;
for (i=l=0; i<p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=p-i; i+=l);
if (l<0) return -1;
if (i > INT_MAX) goto overflow;
p = i;
pad(f, ' ', w, p, fl);
ws = arg.p;
for (i=0; i<0U+p && *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l)
out(f, mb, l);
pad(f, ' ', w, p, fl^LEFT_ADJ);
l = w>p ? w : p;
continue;
case 'e': case 'f': case 'g': case 'a':
case 'E': case 'F': case 'G': case 'A':
if (xp && p<0) goto overflow;
l = fmt_fp(f, arg.f, w, p, fl, t, ps);
if (l<0) goto overflow;
continue;
#endif /* LIBCL4 */
}
if (p < z-a) p = z-a;
if (p > INT_MAX-pl) goto overflow;
if (w < pl+p) w = pl+p;
if (w > INT_MAX-cnt) goto overflow;
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) goto inval;
return 1;
inval:
#ifndef LIBCL4
errno = EINVAL;
#endif
return -1;
overflow:
#ifndef LIBCL4
errno = EOVERFLOW;
#endif
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];
unsigned char internal_buf[80], *saved_buf = 0;
#ifndef LIBCL4
int olderr;
#endif
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;
}
FLOCK(f);
#ifndef LIBCL4
olderr = f->flags & F_ERR;
f->flags &= ~F_ERR;
#endif
if (!f->buf_size) {
saved_buf = f->buf;
f->buf = internal_buf;
f->buf_size = sizeof internal_buf;
f->wpos = f->wbase = f->wend = 0;
}
if (!f->wend && __towrite(f)) ret = -1;
else ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
#ifdef LIBCL4
/* allow to pass f with buf_size = 0 and buf = NULL */
if (f->buf == internal_buf) {
#else
if (saved_buf) {
#endif
f->write(f, 0, 0);
if (!f->wpos) ret = -1;
f->buf = saved_buf;
f->buf_size = 0;
f->wpos = f->wbase = f->wend = 0;
}
if (ferror(f)) ret = -1;
#ifndef LIBCL4
f->flags |= olderr;
#endif
FUNLOCK(f);
va_end(ap2);
return ret;
}

View File

@@ -0,0 +1,32 @@
.global memcpy
.global __memcpy_fwd
.hidden __memcpy_fwd
.type memcpy,@function
memcpy:
__memcpy_fwd:
push %esi
push %edi
mov 12(%esp),%edi
mov 16(%esp),%esi
mov 20(%esp),%ecx
mov %edi,%eax
cmp $4,%ecx
jc 1f
test $3,%edi
jz 1f
2: movsb
dec %ecx
test $3,%edi
jnz 2b
1: mov %ecx,%edx
shr $2,%ecx
rep
movsl
and $3,%edx
jz 1f
2: movsb
dec %edx
jnz 2b
1: pop %edi
pop %esi
ret

View File

@@ -0,0 +1,22 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <strutil.h>
void *memchr(const void *src, int c, size_t n)
{
const unsigned char *s = src;
c = (unsigned char)c;
#ifdef __GNUC__
for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--);
if (n && *s != c) {
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
size_t k = ONES * c;
for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS);
s = (const void *)w;
}
#endif
for (; n && *s != c; s++, n--);
return n ? (void *)s : 0;
}

View File

@@ -0,0 +1,42 @@
#include <string.h>
#include <stdint.h>
#ifdef __GNUC__
typedef __attribute__((__may_alias__)) size_t WT;
#define WS (sizeof(WT))
#endif
void *memmove(void *dest, const void *src, size_t n)
{
char *d = dest;
const char *s = src;
if (d==s) return d;
if ((uintptr_t)s-(uintptr_t)d-n <= -2*n) return memcpy(d, s, n);
if (d<s) {
#ifdef __GNUC__
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;
}
#endif
for (; n; n--) *d++ = *s++;
} else {
#ifdef __GNUC__
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);
}
#endif
while (n) n--, d[n] = s[n];
}
return dest;
}

View File

@@ -0,0 +1,90 @@
#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] = c;
s[n-1] = c;
if (n <= 2) return dest;
s[1] = c;
s[2] = c;
s[n-2] = c;
s[n-3] = c;
if (n <= 6) return dest;
s[3] = c;
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;
}

View File

@@ -0,0 +1,18 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <strutil.h>
size_t strlen(const char *s)
{
const char *a = s;
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
for (; (uintptr_t)s % SS; s++) if (!*s) return s-a;
for (w = (const void *)s; !HASZERO(*w); w++);
s = (const void *)w;
#endif
for (; *s; s++);
return s-a;
}

View File

@@ -0,0 +1,7 @@
#include <string.h>
size_t strnlen(const char *s, size_t n)
{
const char *p = memchr(s, 0, n);
return p ? (size_t)(p - s) : n;
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2022-2023 Kernkonzept GmbH.
* Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "paging.h"
#include "cpu_info.h"
#include <assert.h>
enum
{
PTAB_LEVEL_PML4E = 3,
PTAB_LEVEL_PDPE = 2,
PTAB_LEVEL_PDE = 1,
PTAB_LEVEL_PTE = 0,
PTAB_SHIFT_PER_LEVEL = 9,
PTAB_ENTRY_NUM = 512,
PTAB_ENTRY_MASK = PTAB_ENTRY_NUM - 1,
};
static inline l4_uint32_t ptab_shift(l4_uint32_t level)
{ return 12 + (level * PTAB_SHIFT_PER_LEVEL); }
static inline l4_uint64_t ptab_size(l4_uint32_t level)
{ return ((l4_uint64_t)1) << ptab_shift(level); }
static inline l4_uint64_t ptab_mask(l4_uint32_t level)
{ return ptab_size(level) - 1; }
static inline l4_uint64_t* find_ptabe(l4_addr_t ptab_pa, l4_uint32_t level,
l4_uint64_t la)
{
unsigned entry_idx = (la >> ptab_shift(level)) & PTAB_ENTRY_MASK;
return &((l4_uint64_t *)ptab_pa)[entry_idx];
}
static inline int is_ptab_aligned(l4_uint32_t level, l4_uint64_t addr)
{ return (addr & ptab_mask(level)) == 0; }
static inline int allow_leaf(l4_uint32_t level)
{
switch (level)
{
case PTAB_LEVEL_PTE: return 1;
case PTAB_LEVEL_PDE: return cpu_info.feature_flags & CPUF_PSE;
case PTAB_LEVEL_PDPE: return cpu_info.feature_flags_ext & CPUFEXT_PDPE1GB;
default /* PTAB_LEVEL_PML4E*/ : return 0;
}
}
static inline l4_uint32_t leaf_bit(l4_uint32_t level)
{
if (level == PTAB_LEVEL_PDE || level == PTAB_LEVEL_PDPE)
return PTAB_PS;
return 0;
}
static inline int is_leaf(l4_uint32_t level, l4_uint64_t ptabe)
{ return level == PTAB_LEVEL_PTE || (ptabe & leaf_bit(level)); }
static inline void
ptab_map_level(l4_uint32_t level, l4_uint32_t ptab_pa, l4_uint64_t *la,
l4_uint64_t *pa, l4_uint64_t *size, l4_uint32_t mapping_bits)
{
do
{
l4_uint64_t *ptabe = find_ptabe(ptab_pa, level, *la);
l4_uint64_t ptab_page_size = ptab_size(level);
// Map ptab entry as leaf page if possible.
if (allow_leaf(level))
{
// If no mapping exists for the ptab entry, plus the alignment and
// remaining size allow it, map the ptab entry as a leaf page.
if (!(*ptabe & PTAB_VALID)
&& is_ptab_aligned(level, *la) && is_ptab_aligned(level, *pa)
&& (*size >= ptab_page_size))
{
*ptabe = *pa | PTAB_VALID | mapping_bits | leaf_bit(level);
}
// If the ptab entry either was already mapped as a leaf page or we
// just mapped it in the previous step, adjust the addresses and
// the remaining size according to the leaf page size.
if ((*ptabe & PTAB_VALID) && is_leaf(level, *ptabe))
{
*la += ptab_page_size;
*pa += ptab_page_size;
// Be careful to avoid an underflow of size, in case we
// encountered an existing leaf page.
*size -= ptab_page_size <= *size ? ptab_page_size : *size;
// We are done with this ptab entry.
continue;
}
}
// If the ptab entry is not mapped as a leaf page (either not allowed at
// this level, already mapped as a next level ptab or alignment/size
// requirements didn't allow for it), descend into next level ptab.
assert(level > PTAB_LEVEL_PTE);
// Map ptab entry as next level ptab.
if (!(*ptabe & PTAB_VALID))
{
l4_uint32_t next_ptab_pa;
// Allocate new page for next level ptab.
ptab_alloc(&next_ptab_pa);
// Set the ptab entry to point to it.
*ptabe = (next_ptab_pa & PTAB_PFN) | PTAB_VALID | mapping_bits;
}
// Continue mapping in next level ptab.
ptab_map_level(level - 1, *ptabe & PTAB_PFN, la, pa, size, mapping_bits);
// Stop mapping at this level if either all requested memory is mapped or
// we reached the end of this ptab.
} while ((*size > 0) && !is_ptab_aligned(level + 1, *la));
}
void
ptab_map_range(l4_uint32_t pml4_pa, l4_uint64_t la, l4_uint64_t pa,
l4_uint64_t size, l4_uint32_t mapping_bits)
{
assert(size);
assert(la+size-1 > la); // avoid wrap around
// Ensure that linear and physical addresses are page size aligned, and
// adjust range size accordingly.
size = round_page(la - trunc_page(la) + size);
la = trunc_page(la);
pa = trunc_page(pa);
ptab_map_level(PTAB_LEVEL_PML4E, pml4_pa, &la, &pa, &size, mapping_bits);
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2022, 2024 Kernkonzept GmbH.
* Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/sys/compiler.h>
#include <l4/sys/consts.h>
enum
{
PAGE_SIZE = (1 << 12),
PAGE_MASK = (PAGE_SIZE - 1),
// Physical Address Extension is enabled, thus superpages have a size of 2MB.
SUPERPAGE_SIZE = (1 << 21),
SUPERPAGE_MASK = (SUPERPAGE_SIZE - 1),
PTAB_VALID = 0x0000000000000001LL,
PTAB_WRITE = 0x0000000000000002LL,
PTAB_USER = 0x0000000000000004LL,
PTAB_PFN = 0x000ffffffffff000LL,
PTAB_PS = 0x0000000000000080LL,
};
static inline l4_uint64_t trunc_page(l4_uint64_t x)
{ return x & ~PAGE_MASK; }
static inline l4_uint64_t round_page(l4_uint64_t x)
{ return trunc_page(x + PAGE_MASK); }
static inline l4_uint64_t round_superpage(l4_uint64_t x)
{ return (x + SUPERPAGE_MASK) & ~SUPERPAGE_MASK; }
L4_BEGIN_DECLS
/**
* Allocate and zero-initialize a page table.
*
* \param[out] out_ptab_pa Physical address of the allocated page table.
*
* \note ptab_map_range() uses this function to allocate intermediate page
* tables. Thus, users of ptab_map_range() must provide an implementation
* of this function. ptab_map_range() expects that the physical memory
* from which the page tables are allocated, is identity mapped in the
* linear address space.
*/
void ptab_alloc(l4_uint32_t *out_ptab_pa);
/**
* Maps a physical memory range into the linear address space spanned/organized
* in a 4-level page table hierarchy.
*
* Existing mappings are left intact, i.e. this function only maps the parts of
* the given range that are not yet mapped. The underlying assumption is that we
* never try to map a a linear address to different physical addresses or with
* different mappings bits than it was initially mapped with.
* This is useful because as we are only interested in identity mappings, we can
* treat mapping physical memory as an idempotent operation, allowing us to map
* physical memory on demand, without checking if it is already mapped.
*
* \param[in] pml4_pa The root level page table.
* \param[in] la Linear base address.
* \param[in] pa Physical base address.
* \param[in] size The size of the range to be mapped.
* \param[in] mapping_bits The bits the mapping should be done with.
*/
void ptab_map_range(l4_uint32_t pml4_pa, l4_uint64_t la, l4_uint64_t pa,
l4_uint64_t size, l4_uint32_t mapping_bits);
L4_END_DECLS

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2022, 2024 Kernkonzept GmbH.
* Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/sys/types.h>
#include "panic.h"
#include "paging.h"
#include "support.h"
extern "C" void
ptab_alloc(l4_uint32_t *out_ptab_pa)
{
// try to find a free region for the page table
l4_addr_t ptab = mem_manager->find_free_ram_rev(PAGE_SIZE, 0, ~0U);
if (!ptab)
panic("fatal: could not allocate memory for page table\n");
// mark the region as reserved
mem_manager->regions->add(
Region::start_size(ptab, PAGE_SIZE, ".ptab", Region::Boot, L4_FPAGE_RW));
memset((void *)ptab, 0, PAGE_SIZE);
*out_ptab_pa = ptab;
}

View File

@@ -0,0 +1,130 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Alexander Warg <warg@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "ldscript.inc"
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
"elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
PHDRS {
common PT_LOAD;
mods PT_LOAD;
}
SECTIONS
{
/* Required by elf_machine_load_address() and assumed to be at address 0. */
PROVIDE_HIDDEN(__ehdr_start = 0);
/* Read-only sections, merged into text segment. The start address of
* the text segment is : */
. = LINKADDR;
_img_base = .;
.text :
{
_stext = .;
*(.text.init)
*(.init)
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
KEEP (*(.fini))
LONG(0xc3) /* terminate .fini */
. = ALIGN(0x40);
*(.rodata .rodata.* .gnu.linkonce.r.* .rodata1)
} : common
_etext = .;
PROVIDE (etext = .);
.note.gnu.build-id : { *(.note.gnu.build-id) }
/* ensure that data starts at a new L4 page */
. = ALIGN(4096);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
*(.anno)
CTORS
PLATFORMS
} : common
/* exception frames for C++ */
.eh_frame :
{
KEEP (*(.eh_frame))
LONG(0) /* terminate .eh_frame */
} : common
. = ALIGN(4);
_edata = .;
PROVIDE (edata = .);
_bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
} : common
_bss_end = .;
/* Must be before _end so that they are retained even if modules are moved
* around. In contrast, the .rel.dyn section is not needed after the
* relocations have been processed. */
.dynamic : { *(.dynamic) }
.got : { *(.got.plt) *(.got) }
_end = . ;
PROVIDE (end = .);
/* Moved here to ensure that these sections are located _after_ the text
* section. In the other case we would get program sections with a virtual
* address of 0 */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.rel.dyn :
{
*(.rel.init)
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
*(.rel.fini)
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
*(.rel.ctors)
*(.rel.dtors)
*(.rel.got)
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
}
.rel.plt : { *(.rel.plt) }
/* Needs to be last so that l4image does not mess up PHDR offsets other
* sections. */
.data.m :
{
_module_data_start = .;
*(.module_data)
} : mods
_end_of_initial_bootstrap = .;
/* drop the following sections since we do not need them for DROPS */
/DISCARD/ : {
*(.interp)
*(.comment)
*(.note)
*(.stab)
*(.fini)
*(.ARM.exidx*)
}
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
Frank Mehnert <fm3@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
/* -*- c -*- */
#ifdef CRT0_PLATFORM_EARLY_INIT
#include CRT0_PLATFORM_EARLY_INIT
#else
.macro crt0_platform_early_init
.endm
#endif
#define MIMIC_A_VMLINUZ
.section .text.init,"ax"
.type _start,#function
.globl _start
#ifdef CONFIG_BOOTSTRAP_THUMB_ENTRY
.thumb
_start:
adr r4, 1f
bx r4
1:
.arm
#else
_start:
#endif
/* Some bootloaders like it this way, for others it won't harm */
/* Only works on non-PIE builds because it leaves behind relocations in text
* segment. */
#if defined(MIMIC_A_VMLINUZ) && !defined(CONFIG_BID_PIE)
nop
nop
nop
nop
nop
nop
nop
nop
b .L32bitstart
.word 0x016f2818
.word _start
.word _end_of_initial_bootstrap // patched by l4image
.word 0x04030201
.word 0x45454545
.word 0
.word 0 // Potential PE/COFF offset
#endif
.L32bitstart:
// IRQs, FIQs off
mrs r4, cpsr
orr r4, #0xc0
msr cpsr_c, r4
crt0_platform_early_init
/*
* It might be the case that we're not run at the position where we
* have been linked to. If this is the case we copy ourselves to the
* position we're linked to. If L4Re is built with PIE support we
* can run from anywhere and there is no need to copy ourselves around.
*/
#ifndef CONFIG_BID_PIE
adr r4, run /* Running version */
ldr r5, .LCrun /* supposed to be version */
cmp r4, r5 /* If equal ... */
beq run /* ... go to run */
/* Disable caches as we're moving code around */
mcr p15, 0, r6, c7, c5, 0 /* ICIALLU */
mrc p15, 0, r6, c1, c0
bic r6, #0x0004
bic r6, #0x1000
mcr p15, 0, r6, c1, c0
/* Figure how to move */
ldr r7, crt_end_bin_lsb
add r7, r7, #3 /* Round up to word size for ldr and str... */
bic r7, r7, #3 /* ...below */
subs r8, r5, r4 /* r8 is the distance between the blocks */
bpl move_behind
/* Copy before, copy forwards */
/* First, copy our copy loop to the very beginning to avoid code
* overwrites */
mov r9, r5 /* r9: run address */
ldr r10, .LCstart_bin
ldr r6, 3f
str r6, [r10], #4
ldr r6, 32f
str r6, [r10], #4
ldr r6, 33f
str r6, [r10], #4
ldr r6, 34f
str r6, [r10], #4
ldr r6, 35f
str r6, [r10], #4
ldr pc, .LCstart_bin
3: ldr r6, [r4], #4
32: str r6, [r5], #4
33: cmp r5, r7
34: blt 3b
35: mov pc, r9
/* Copy behind, copy backwards */
move_behind:
sub r8, r7, r8 /* r8 points to the end of source image */
3: ldr r6, [r8, #-4]! /* Take bytes */
str r6, [r7, #-4]! /* Put bytes */
cmp r5, r7
blt 3b
ldr pc, .LCrun
.LCrun: .word run
.LCstart_bin: .word _start
crt_end_bin: .word 0
crt_end_bin_lsb: .word _end_of_initial_bootstrap; // patched by l4image
run:
#endif
b platform_cpu_bootup
.type platform_cpu_bootup, #function
.weak platform_cpu_bootup
platform_cpu_bootup:
/* Can be overridden by platform for special MP boot */
.global do_bootstrap
.type do_bootstrap, #function
do_bootstrap:
#ifdef __ARM_FP
.fpu vfp
/* Prevent triggering 'undefined instruction' exceptions by enabling
* the FPU. Newer gcc versions implicitly generate FP instructions. */
mrc p15, 0, r8, c1, c0, 2 /* read CPACR */
orr r8, #(0xf << 20) /* cp10 + cp11 (FPU) */
mcr p15, 0, r8, c1, c0, 2 /* try to enable */
mrc p15, 0, r8, c1, c0, 2 /* read CPACR */
and r8, #(0xf << 20)
cmp r8, #(0xf << 20) /* verify enabled */
bne no_fpu
vmrs r8, fpexc
orr r8, r8, #(0x1 << 30) /* enable FP unit */
vmsr fpexc, r8
no_fpu:
#endif
adr r8, do_bootstrap
ldr sp, .LCstack
add sp, sp, r8
#ifdef CONFIG_BID_PIE
/* Save r0..r3. They are passed to __main and will be clobbered by
* reloc_static_pie. */
mov v1, a1
mov v2, a2
mov v3, a3
mov v4, a4
adr a1, .L__ehdr_start_off
ldr a2, .L__ehdr_start_off
add a1, a1, a2
bl reloc_static_pie
mov a1, v1
mov a2, v2
mov a3, v3
mov a4, v4
#endif
bl __main
1: b 1b
.LCstack: .word (crt0_stack_high - do_bootstrap)
#ifdef CONFIG_BID_PIE
.L__ehdr_start_off:
.word __ehdr_start - .L__ehdr_start_off
#endif
.section ".bss"
.global crt0_stack_low
.align 3
crt0_stack_low:
.space 8192
.global crt0_stack_high
crt0_stack_high:

View File

@@ -0,0 +1,40 @@
#include <l4/sys/compiler.h>
#include "support.h"
#include "platform.h"
#include "startup.h"
extern "C" int __aeabi_unwind_cpp_pr0(void);
extern "C" int __aeabi_unwind_cpp_pr1(void);
enum { _URC_FAILURE = 9 };
int __aeabi_unwind_cpp_pr0(void) { return _URC_FAILURE; }
int __aeabi_unwind_cpp_pr1(void) { return _URC_FAILURE; }
struct boot_args boot_args;
extern "C" void __main(unsigned long r0, unsigned long r1,
unsigned long r2, unsigned long r3);
void __main(unsigned long r0, unsigned long r1,
unsigned long r2, unsigned long r3)
{
unsigned long r;
asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r" (r) : : "memory");
r &= ~1UL;
asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (r) : "memory");
clear_bss();
boot_args.r[0] = r0;
boot_args.r[1] = r1;
boot_args.r[2] = r2;
boot_args.r[3] = r3;
ctor_init();
Platform_base::iterate_platforms();
init_modules_infos();
startup(mod_header->mbi_cmdline());
l4_infinite_loop();
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2014-2024 Kernkonzept GmbH.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "panic.h"
#include "platform-arm.h"
#include <assert.h>
#include <stdio.h>
static inline l4_umword_t
running_in_hyp_mode()
{
l4_umword_t cpsr;
asm volatile("mrs %0, cpsr" : "=r"(cpsr));
return (cpsr & 0x1f) == 0x1a;
}
void
Platform_arm::setup_kernel_config(l4_kernel_info_t *kip)
{
setup_kernel_config_arm_common(kip);
l4_kip_platform_info_arch *ia = &kip->platform_info.arch;
asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (ia->cpuinfo.MIDR));
asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (ia->cpuinfo.CTR));
asm("mrc p15, 0, %0, c0, c0, 2" : "=r" (ia->cpuinfo.TCMTR));
#ifdef CONFIG_MMU
asm("mrc p15, 0, %0, c0, c0, 3" : "=r" (ia->cpuinfo.TLBTR));
#endif
asm("mrc p15, 0, %0, c0, c0, 5" : "=r" (ia->cpuinfo.MPIDR));
asm("mrc p15, 0, %0, c0, c0, 6" : "=r" (ia->cpuinfo.REVIDR));
if (((ia->cpuinfo.MIDR >> 16) & 0xf) >= 7)
{
asm("mrc p15, 0, %0, c0, c1, 0" : "=r" (ia->cpuinfo.ID_PFR[0]));
asm("mrc p15, 0, %0, c0, c1, 1" : "=r" (ia->cpuinfo.ID_PFR[1]));
asm("mrc p15, 0, %0, c0, c1, 2" : "=r" (ia->cpuinfo.ID_DFR0));
asm("mrc p15, 0, %0, c0, c1, 3" : "=r" (ia->cpuinfo.ID_AFR0));
asm("mrc p15, 0, %0, c0, c1, 4" : "=r" (ia->cpuinfo.ID_MMFR[0]));
asm("mrc p15, 0, %0, c0, c1, 5" : "=r" (ia->cpuinfo.ID_MMFR[1]));
asm("mrc p15, 0, %0, c0, c1, 6" : "=r" (ia->cpuinfo.ID_MMFR[2]));
asm("mrc p15, 0, %0, c0, c1, 7" : "=r" (ia->cpuinfo.ID_MMFR[3]));
asm("mrc p15, 0, %0, c0, c2, 0" : "=r" (ia->cpuinfo.ID_ISAR[0]));
asm("mrc p15, 0, %0, c0, c2, 1" : "=r" (ia->cpuinfo.ID_ISAR[1]));
asm("mrc p15, 0, %0, c0, c2, 2" : "=r" (ia->cpuinfo.ID_ISAR[2]));
asm("mrc p15, 0, %0, c0, c2, 3" : "=r" (ia->cpuinfo.ID_ISAR[3]));
asm("mrc p15, 0, %0, c0, c2, 4" : "=r" (ia->cpuinfo.ID_ISAR[4]));
asm("mrc p15, 0, %0, c0, c2, 5" : "=r" (ia->cpuinfo.ID_ISAR[5]));
}
assert(kernel_type != EL_Support::Unknown);
if (kernel_type == EL_Support::EL2 && !running_in_hyp_mode())
{
printf(" Detected HYP kernel, switching to HYP mode\n");
if ( ((ia->cpuinfo.MIDR >> 16) & 0xf) != 0xf // ARMv7
|| (((ia->cpuinfo.ID_PFR[1] >> 12) & 0xf) == 0)) // No Virt Ext
panic("\nCPU does not support Virtualization Extensions\n");
if (!arm_switch_to_hyp())
panic("\nNo switching functionality available on this platform.\n");
if (!running_in_hyp_mode())
panic("\nFailed to switch to HYP as required by Fiasco.OC.\n");
}
if (kernel_type == EL_Support::EL1 && running_in_hyp_mode())
{
printf(" Non-HYP kernel detected but running in HYP mode, switching back.\n");
asm volatile("mov r3, lr \n"
"mcr p15, 0, sp, c13, c0, 2 \n"
"mrs r0, cpsr \n"
"bic r0, #0x1f \n"
"orr r0, #0x13 \n"
"orr r0, #0x100 \n"
"adr r1, 1f \n"
".inst 0xe16ff000 \n" // msr spsr_cfsx, r0
".inst 0xe12ef301 \n" // msr elr_hyp, r1
".inst 0xe160006e \n" // eret
"nop \n"
"1: mrc p15, 0, sp, c13, c0, 2 \n"
"mov lr, r3 \n"
: : : "r0", "r1" , "r3", "lr", "memory");
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/sys/compiler.h>
#include "platform.h"
void
reboot_arch(void) __attribute__((noreturn));
void
reboot_arch(void)
{
Platform_base::platform->reboot();
l4_infinite_loop();
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2024 Kernkonzept GmbH.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Jan Klötzke <jan.kloetzke@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "ARCH-arm/spin_addr_boot.h"
.section .text.init,"ax"
.global cpu_bootup_code_start
cpu_bootup_code_start:
.global platform_cpu_bootup
.type platform_cpu_bootup, #function
platform_cpu_bootup:
mrc p15, 0, r4, c0, c0, 5 /* CPU ID */
tst r4, #0xff /* Test Aff0 field */
tsteq r4, #(0xff << 8) /* Test Aff1 field */
tsteq r4, #(0xff << 16) /* Test Aff2 field */
beq do_bootstrap /* CPU0 continues with bootstrap */
/* CPU1+ wait for bootup */
spin_addr_boot_wait
.global cpu_bootup_code_end
cpu_bootup_code_end:

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2024 Kernkonzept GmbH.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Jan Klötzke <jan.kloetzke@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
.macro spin_addr_boot_wait
adr r0, mp_launch_spin_addr
1: ldr r1, [r0]
cmp r1, #0
bxne r1
.inst 0xe320f002 // wfe
b 1b
.global mp_launch_spin_addr
mp_launch_spin_addr:
.space 4
.endm

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2023-2024 Kernkonzept GmbH.
* Author(s): Jan Klötzke <jan.kloetzke@kernkonzept.com>
* Adam Lackorzynski <adam@l4re.org>
*
* Taken from corresponding gnu-efi linkerscript
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "ldscript.inc"
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SECTIONS
{
/*
* The text section must start at address 0 because it holds the PE/COFF
* header that must be at the start of the file. In the same vein we also
* define _start here because there is no real entry point as far as the ELF
* image is concerned.
*/
. = 0;
_img_base = .;
ImageBase = .;
/* .hash and/or .gnu.hash MUST come first! */
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
. = ALIGN(4096);
.eh_frame : { *(.eh_frame) }
.gcc_except_table : { *(.gcc_except_table*) }
. = ALIGN(4096);
.text : {
_stext = .;
_text = .;
*(.text.head)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.srodata)
*(.rodata*)
. = ALIGN(16);
}
_etext = .;
_text_size = _etext - _text;
. = ALIGN(65536);
.reloc :
{
KEEP (*(.reloc))
}
. = ALIGN(4096);
.dynamic : { *(.dynamic) }
. = ALIGN(4096);
.data :
{
_data = .;
*(.sdata)
*(.data)
*(.data1)
*(.data.*)
*(.got.plt)
*(.got)
CTORS
PLATFORMS
/*
* Note that these aren't the using the GNU "CONSTRUCTOR" output section
* command, so they don't start with a size. Because of p2align and the
* end/END definitions, and the fact that they're mergeable, they can also
* have NULLs which aren't guaranteed to be at the end.
*/
/* Leave gnu-efi supplied ctors/dtors except __init_array_start which we
* also have.
. = ALIGN(16);
__init_array_start = .;
*(SORT(.init_array.*))
*(.init_array)
__init_array_end = .;
*/
. = ALIGN(16);
__CTOR_LIST__ = .;
*(SORT(.ctors.*))
*(.ctors)
__CTOR_END__ = .;
. = ALIGN(16);
__DTOR_LIST__ = .;
*(SORT(.dtors.*))
*(.dtors)
__DTOR_END__ = .;
. = ALIGN(16);
__fini_array_start = .;
*(SORT(.fini_array.*))
*(.fini_array)
__fini_array_end = .;
/* the EFI loader doesn't seem to like a .bss section, so we stick
it all into .data: */
. = ALIGN(16);
_bss = .;
*(.sbss)
*(.scommon)
*(.dynbss)
*(.bss*)
*(.bss.*)
*(COMMON)
*(.rel.local)
. = ALIGN(16);
_bss_end = .;
}
_end = .;
. = ALIGN(4096);
.rela :
{
*(.rela.text*)
*(.rela.data*)
*(.rela.got)
*(.rela.dyn)
*(.rela.stab)
*(.rela.init_array*)
*(.rela.fini_array*)
*(.rela.ctors*)
*(.rela.dtors*)
*(.rela.platformdata)
*(.rela.l4redeviceuart)
}
. = ALIGN(4096);
.rela.plt : { *(.rela.plt) }
. = ALIGN(4096);
.rodata : { *(.rodata*) }
. = ALIGN(512);
_edata = .;
_data_size = _edata - _data;
. = ALIGN(4096);
.dynsym : { *(.dynsym) }
. = ALIGN(4096);
.dynstr : { *(.dynstr) }
. = ALIGN(4096);
.note.gnu.build-id : { *(.note.gnu.build-id) }
.ignored.reloc :
{
*(.rela.reloc)
*(.note.GNU-stack)
}
/* Needs to be last so that l4image does not mess up PHDR offsets of other
* sections. */
.data.m :
{
_module_data_start = .;
*(.module_data)
}
.comment 0 : { *(.comment) }
}

View File

@@ -0,0 +1,130 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Alexander Warg <warg@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "ldscript.inc"
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64",
"elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(_start)
PHDRS {
common PT_LOAD;
mods PT_LOAD;
}
SECTIONS
{
/* Required by elf_machine_load_address() and assumed to be at address 0. */
PROVIDE_HIDDEN(__ehdr_start = 0);
/* Read-only sections, merged into text segment. The start address of
* the text segment is : */
. = LINKADDR;
_img_base = .;
.text :
{
_stext = .;
*(.text.init)
*(.init)
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
KEEP (*(.fini))
LONG(0xc3) /* terminate .fini */
. = ALIGN(0x40);
*(.rodata .rodata.* .gnu.linkonce.r.* .rodata1)
} : common
_etext = .;
PROVIDE (etext = .);
.note.gnu.build-id : { *(.note.gnu.build-id) }
/* ensure that data starts at a new L4 page */
. = ALIGN(4096);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
*(.anno)
CTORS
PLATFORMS
} : common
/* exception frames for C++ */
.eh_frame :
{
KEEP (*(.eh_frame))
LONG(0) /* terminate .eh_frame */
} : common
. = ALIGN(4);
_edata = .;
PROVIDE (edata = .);
_bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
} : common
_bss_end = .;
/* Must be before _end so that they are retained even if modules are moved
* around. In contrast, the .rel.dyn section is not needed after the
* relocations have been processed. */
.dynamic : { *(.dynamic) }
.got : { *(.got.plt) *(.got) }
_end = . ;
PROVIDE (end = .);
/* Moved here to ensure that these sections are located _after_ the text
* section. In the other case we would get program sections with a virtual
* address of 0 */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
}
.rela.plt : { *(.rela.plt) }
/* Needs to be last so that l4image does not mess up PHDR offsets other
* sections. */
.data.m :
{
_module_data_start = .;
*(.module_data)
} : mods
_end_of_initial_bootstrap = .;
/* drop the following sections since we do not need them for DROPS */
/DISCARD/ : {
*(.interp)
*(.comment)
*(.note)
*(.stab)
*(.fini)
*(.ARM.exidx*)
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2014-2021 Kernkonzept GmbH.
* Author(s): Jan Klötzke <jan.kloetzke@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
.macro set_sctlr sctlr_reg, tmp
mrs \tmp, \sctlr_reg
bic \tmp, \tmp, #0x0001 // disable MMU
bic \tmp, \tmp, #0x0004 // disable data cache
bic \tmp, \tmp, #0x1000 // disable instruction cache
msr \sctlr_reg, \tmp
.endm
.text
.global armv8_disable_mmu
.type armv8_disable_mmu, %function
armv8_disable_mmu:
/*
* First clean the entire data or unified cache to the point of coherency.
* Taken literally from the ARMv8 Architecture Reference Manual.
*/
MRS X0, CLIDR_EL1
AND W3, W0, #0x07000000 // get 2 x level of coherency
LSR W3, W3, #23
CBZ W3, 5f
MOV W10, #0 // W10 = 2 x cache level
MOV W8, #1 // W8 = constant 0b1
1: ADD W2, W10, W10, LSR #1 // calculate 3 x cache level
LSR W1, W0, W2 // extract 3-bit cache type for this level
AND W1, W1, #0x7
CMP W1, #2
B.LT 4f // no data or unified cache at this level
MSR CSSELR_EL1, X10 // select this cache level
ISB // sync change of CSSELR
MRS X1, CCSIDR_EL1 // read CCSIDR
AND W2, W1, #7 // W2 = log2(linelen)-4
ADD W2, W2, #4 // W2 = log2(linelen)
UBFX W4, W1, #3, #10 // W4 = max way number, right aligned
CLZ W5, W4 // W5 = 32-log2(ways), bit position of way in DC operand
LSL W9, W4, W5 // W9 = max way number, aligned to position in DC operand
LSL W16, W8, W5 // W16 = amount to decrement way number per iteration
2: UBFX W7, W1, #13, #15 // W7 = max set number, right aligned
LSL W7, W7, W2 // W7 = max set number, aligned to position in DC operand
LSL W17, W8, W2 // W17 = amount to decrement set number per iteration
3: ORR W11, W10, W9 // W11 = combine way number and cache number ...
ORR W11, W11, W7 // ... and set number for DC operand
DC CSW, X11 // do data cache clean by set and way
SUBS W7, W7, W17 // decrement set number
B.GE 3b
SUBS X9, X9, X16 // decrement way number
B.GE 2b
4: ADD W10, W10, #2 // increment 2 x cache level
CMP W3, W10
DSB SY // ensure completion of the clean on all processors
B.GT 1b
5:
/*
* Invalidate entire instruction cache.
*/
ic iallu
dsb sy
isb
/*
* Disable all caches.
*/
mrs x2, CurrentEL
ubfx x2, x2, #2, #2
cmp x2, #3
b.eq .Lsctlr_el3
cmp x2, #2
b.eq .Lsctlr_el2
set_sctlr SCTLR_EL1, x2
b .Lsctlr_done
.Lsctlr_el2:
set_sctlr SCTLR_EL2, x2
b .Lsctlr_done
.Lsctlr_el3:
set_sctlr SCTLR_EL3, x2
.Lsctlr_done:
isb
ret
.size armv8_disable_mmu, .-armv8_disable_mmu

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
Frank Mehnert <fm3@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
/* -*- c -*- */
.macro set_sctlr sctlr_reg, tmp
mrs \tmp, \sctlr_reg
bic \tmp, \tmp, #0x0004
bic \tmp, \tmp, #0x1000
msr \sctlr_reg, \tmp
.endm
#define MIMIC_A_VMLINUZ
.section .text.init,"ax"
.type _start,#function
.globl _start
_start:
/* Some bootloaders like it this way, for others it won't harm */
#ifdef MIMIC_A_VMLINUZ
nop
b 10f
.8byte 0x80000 /* text_offset */
.8byte 0 /* image_size */
.8byte 0 /* flags */
.8byte 0, 0, 0 /* reserved */
.ascii "ARM\x64" /* magic */
.4byte 0 /* reserved */
10:
#endif
#ifndef CONFIG_BID_PIE
/*
* It might be the case that we're not run at the position where we
* have been linked to. If this is the case we copy ourselves to the
* position we're linked to. If L4Re is built with PIE support we
* can run from anywhere and there is no need to copy ourselves around.
*/
adr x4, run /* Running version */
ldr x5, .LCrun /* supposed to be version */
cmp x4, x5 /* If equal ... */
b.eq run /* ... go to run */
/* Disable caches as we're moving code around */
ic iallu
mrs x12, CurrentEL
ubfx x12, x12, #2, #2
cmp x12, #3
b.eq .Lsctlr_el3
cmp x12, #2
b.eq .Lsctlr_el2
set_sctlr SCTLR_EL1, x12
b .Lsctlr_done
.Lsctlr_el2:
set_sctlr SCTLR_EL2, x12
b .Lsctlr_done
.Lsctlr_el3:
set_sctlr SCTLR_EL3, x12
.Lsctlr_done:
/* Figure how to move */
ldr x7, crt_end_bin
add x7, x7, #7 /* Round up to word size for ldr and str... */
bic x7, x7, #7 /* ...below */
subs x8, x5, x4 /* x8 is the distance between the blocks */
b.pl move_behind
/* Copy before, copy forwards */
/* First, copy our copy loop to the very beginning to avoid code
* overwrites */
mov x9, x5 /* x9: run address */
ldr x12, .LCstart_bin
ldr x13, 3f
str x13, [x12], #8
ldr x13, 33f
str x13, [x12], #8
ldr x13, 35f
str x13, [x12], #8
ldr x10, .LCstart_bin
br x10
3: ldr x6, [x4], #8
str x6, [x5], #8
33: cmp x5, x7
b.lt 3b
35: br x9
nop
/* Copy behind, copy backwards */
move_behind:
sub x8, x7, x8 /* x8 points to the end of source image */
3: ldr x6, [x8, #-8]! /* Take bytes */
str x6, [x7, #-8]! /* Put bytes */
cmp x5, x7
b.lt 3b
ldr x10, .LCrun
br x10
.align 3
.LCrun: .8byte run
.LCstart_bin: .8byte _start
crt_end_bin: .8byte _end_of_initial_bootstrap // patched by l4image
run:
#endif
b platform_cpu_bootup
.type platform_cpu_bootup, #function
.weak platform_cpu_bootup
platform_cpu_bootup:
/* Can be overridden by platform for special MP boot */
.global do_bootstrap
.type do_bootstrap, #function
do_bootstrap:
adrp x9, crt0_stack_high
add x9, x9, :lo12:crt0_stack_high
mov sp, x9
mrs x8, cpacr_el1
orr x8, x8, #0x300000 // fpen
msr cpacr_el1, x8
#ifdef CONFIG_BID_PIE
/* Save x0..x3. They are passed to __main and will be clobbered by
* reloc_static_pie. */
mov x19, x0
mov x20, x1
mov x21, x2
mov x22, x3
/* "Calculate" load address... */
adrp x0, __ehdr_start
/* Do relocations */
bl reloc_static_pie
mov x0, x19
mov x1, x20
mov x2, x21
mov x3, x22
#endif
bl __main
1: b 1b
.section ".bss"
.global crt0_stack_low
.align 4
crt0_stack_low:
.space 8192
.global crt0_stack_high
crt0_stack_high:

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2014-2021, 2023-2024 Kernkonzept GmbH.
* Author(s): Jan Klötzke <jan.kloetzke@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "efi-support.h"
#include "platform.h"
#include "startup.h"
#include "support.h"
extern "C" EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
ctor_init();
efi.init(image, systab);
// Do the usual platform iteration as done by head.cc.
Platform_base::iterate_platforms();
init_modules_infos();
startup(mod_header->mbi_cmdline());
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,31 @@
#include <l4/sys/compiler.h>
#include "support.h"
#include "platform.h"
#include "startup.h"
struct boot_args boot_args;
extern "C" void __main(unsigned long r0, unsigned long r1,
unsigned long r2, unsigned long r3);
void __main(unsigned long r0, unsigned long r1,
unsigned long r2, unsigned long r3)
{
// Ensure all is masked, irrespective of what our bootloader selected.
asm("msr daif, %0" : : "r" (0x3c0UL));
clear_bss();
boot_args.r[0] = r0;
boot_args.r[1] = r1;
boot_args.r[2] = r2;
boot_args.r[3] = r3;
ctor_init();
Platform_base::iterate_platforms();
init_modules_infos();
startup(mod_header->mbi_cmdline());
l4_infinite_loop();
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2018-2023 Kernkonzept GmbH.
* Author(s): Adam Lackorzynski <adam@l4re.org>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "panic.h"
#include "platform-arm.h"
#include <assert.h>
#include <stdio.h>
static inline unsigned current_el()
{
l4_umword_t current_el;
asm ("mrs %0, CurrentEL" : "=r" (current_el));
return (current_el >> 2) & 3;
}
void Platform_arm::setup_kernel_config(l4_kernel_info_t *kip)
{
setup_kernel_config_arm_common(kip);
l4_kip_platform_info_arch *ia = &kip->platform_info.arch;
asm("mrs %0, MIDR_EL1" : "=r" (ia->cpuinfo.MIDR));
asm("mrs %0, MPIDR_EL1" : "=r" (ia->cpuinfo.MPIDR));
asm("mrs %0, REVIDR_EL1" : "=r" (ia->cpuinfo.REVIDR));
asm("mrs %0, ID_PFR0_EL1" : "=r" (ia->cpuinfo.ID_PFR[0]));
asm("mrs %0, ID_PFR1_EL1" : "=r" (ia->cpuinfo.ID_PFR[1]));
// Armv8.x... needs check
//asm("mrs %0, ID_PFR2_EL1" : "=r" (ia->cpuinfo.ID_PFR[2]));
asm("mrs %0, ID_DFR0_EL1" : "=r" (ia->cpuinfo.ID_DFR0));
asm("mrs %0, ID_AFR0_EL1" : "=r" (ia->cpuinfo.ID_AFR0));
asm("mrs %0, ID_MMFR0_EL1" : "=r" (ia->cpuinfo.ID_MMFR[0]));
asm("mrs %0, ID_MMFR1_EL1" : "=r" (ia->cpuinfo.ID_MMFR[1]));
asm("mrs %0, ID_MMFR2_EL1" : "=r" (ia->cpuinfo.ID_MMFR[2]));
asm("mrs %0, ID_MMFR3_EL1" : "=r" (ia->cpuinfo.ID_MMFR[3]));
asm("mrs %0, ID_ISAR0_EL1" : "=r" (ia->cpuinfo.ID_ISAR[0]));
asm("mrs %0, ID_ISAR1_EL1" : "=r" (ia->cpuinfo.ID_ISAR[1]));
asm("mrs %0, ID_ISAR2_EL1" : "=r" (ia->cpuinfo.ID_ISAR[2]));
asm("mrs %0, ID_ISAR3_EL1" : "=r" (ia->cpuinfo.ID_ISAR[3]));
asm("mrs %0, ID_ISAR4_EL1" : "=r" (ia->cpuinfo.ID_ISAR[4]));
asm("mrs %0, ID_ISAR5_EL1" : "=r" (ia->cpuinfo.ID_ISAR[5]));
asm("mrs %0, ID_ISAR6_EL1" : "=r" (ia->cpuinfo.ID_ISAR[6]));
//asm("mrs %0, S3_0_C0_C0_3" : "=r" (ia->cpuinfo.ID_MVFR[0]));
//asm("mrs %0, S3_0_C0_C1_3" : "=r" (ia->cpuinfo.ID_MVFR[1]));
//asm("mrs %0, S3_0_C0_C2_3" : "=r" (ia->cpuinfo.ID_MVFR[2]));
asm("mrs %0, ID_AA64DFR0_EL1" : "=r" (ia->cpuinfo.ID_AA64DFR[0]));
asm("mrs %0, ID_AA64DFR1_EL1" : "=r" (ia->cpuinfo.ID_AA64DFR[1]));
asm("mrs %0, ID_AA64ISAR0_EL1" : "=r" (ia->cpuinfo.ID_AA64ISAR[0]));
asm("mrs %0, ID_AA64ISAR1_EL1" : "=r" (ia->cpuinfo.ID_AA64ISAR[1]));
asm("mrs %0, ID_AA64ISAR2_EL1" : "=r" (ia->cpuinfo.ID_AA64ISAR[2]));
asm("mrs %0, ID_AA64MMFR0_EL1" : "=r" (ia->cpuinfo.ID_AA64MMFR[0]));
asm("mrs %0, ID_AA64MMFR1_EL1" : "=r" (ia->cpuinfo.ID_AA64MMFR[1]));
// Armv8.2
//asm("mrs %0, ID_AA64MMFR2_EL1" : "=r" (ia->cpuinfo.ID_AA64MMFR[2]));
asm("mrs %0, ID_AA64PFR0_EL1" : "=r" (ia->cpuinfo.ID_AA64PFR[0]));
asm("mrs %0, ID_AA64PFR1_EL1" : "=r" (ia->cpuinfo.ID_AA64PFR[1]));
assert(kernel_type != EL_Support::Unknown);
if (kernel_type == EL_Support::EL2 && current_el() < 2)
panic("L4Re is configured for EL2 mode (virtualization / hypervisor) but got started in EL1 by the boot-loader. Please change your boot-loader to start L4Re in EL2 mode.");
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2024 Kernkonzept GmbH.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Jan Klötzke <jan.kloetzke@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "ARCH-arm64/spin_addr_boot.h"
.section .text.init,"ax"
.global cpu_bootup_code_start
cpu_bootup_code_start:
.global platform_cpu_bootup
.type platform_cpu_bootup, #function
platform_cpu_bootup:
mrs x9, MPIDR_EL1 /* CPU ID */
and x9, x9, #~(0xff << 24) /* Just keep Aff[0-3] fields */
cmp x9, #0 /* CPU0 continues with bootstrap */
beq do_bootstrap
/* CPU1+ wait for bootup */
spin_addr_boot_wait
.global cpu_bootup_code_end
cpu_bootup_code_end:

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2024 Kernkonzept GmbH.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* Jan Klötzke <jan.kloetzke@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
.macro spin_addr_boot_wait
1: ldr x9, mp_launch_spin_addr
cmp x9, #0
beq 2f /* Not yet */
blr x9
2: wfe
b 1b
.align 3
.global mp_launch_spin_addr
mp_launch_spin_addr:
.space 8
.endm

View File

@@ -0,0 +1,117 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License 2. See the file "COPYING-GPL-2" in the main directory of this
* archive for more details.
*
* Copyright (C) 2014 Imagination Technologies Ltd.
* Author: Sanjay Lal <sanjayl@kymasys.com>
* Author: Yann Le Du <ledu@kymasys.com>
*/
#include "ldscript.inc"
#if CPU_ABI == 64
OUTPUT_FORMAT("elf64-tradlittlemips", "elf64-tradbigmips",
"elf64-tradlittlemips")
#else
OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips",
"elf32-tradlittlemips")
#endif
/* OUTPUT_ARCH(mips) */
ENTRY(_start)
PHDRS {
common PT_LOAD;
mods PT_LOAD;
}
SECTIONS
{
/* Read-only sections, merged into text segment. The start address of
* the text segment is : */
. = LINKADDR;
_img_base = .;
.text :
{
_stext = .;
*(.text.init)
*(.init)
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
. = ALIGN(0x40);
*(.rodata .rodata.* .gnu.linkonce.r.* .rodata1)
*(.mips16.fn.*) *(.mips16.call.*)
} : common
_etext = .;
PROVIDE (etext = .);
.note.gnu.build-id : { *(.note.gnu.build-id) }
/* ensure that data starts at a new L4 page */
. = ALIGN(4096);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
*(.anno)
CTORS
PLATFORMS
_gp = ALIGN(16) + 0x7ff0;
*(.got)
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
*(.sdata .sdata.* .gnu.linkonce.s.*)
} : common
. = ALIGN(4);
_edata = .;
PROVIDE (edata = .);
_bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
} : common
_bss_end = .;
_end = . ;
PROVIDE (end = .);
/* Moved here to ensure that these sections are located _after_ the text
* section. In the other case we would get program sections with a virtual
* address of 0 */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.rel.dyn : { *(.rel.dyn) }
/* Needs to be last so that l4image does not mess up PHDR offsets other
* sections. */
. = ALIGN(4096);
.data.m :
{
. = ALIGN(4096);
_module_data_start = .;
*(EXCLUDE_FILE (*mod00.bin *mod01.bin *mod02.bin) .module_data)
*(.module_data)
} : mods
_end_of_initial_bootstrap = .;
/* drop the following sections since we do not need them for DROPS */
/DISCARD/ : {
*(.interp)
*(.MIPS.abiflags)
*(.eh_frame) *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*)
*(.fini)
*(.comment)
*(.note)
*(.stab)
*(.fini)
*(.reginfo)
}
}

View File

@@ -0,0 +1,184 @@
#include <l4/sys/types.h>
#include <stdio.h>
static void print_cache2(unsigned level, unsigned v)
{
if (!((v >> 4) & 0xf))
{
printf(" MIPS: no L%d-Cache implemented\n", level);
return;
}
printf(" MIPS: L%d-Cache: %d-way %d-set, %d byte per line (u=%x)\n",
level,
(v & 0xf) + 1, 64U << ((v >> 8U) & 0xf), 2U << ((v >> 4) & 0xf),
(v >> 12) & 0xf);
}
static l4_umword_t mips_guest_ctl0()
{
l4_umword_t v;
asm volatile ("mfc0 %0, $12, 6" : "=r"(v));
return v;
}
static void mips_guest_ctl0(l4_umword_t v)
{
asm volatile ("mtc0 %0, $12, 6" : : "r"(v));
}
static l4_umword_t mips_test_guest_ctl0(l4_umword_t bits)
{
l4_umword_t x = mips_guest_ctl0();
mips_guest_ctl0(x | bits);
l4_umword_t r = mips_guest_ctl0() & bits;
mips_guest_ctl0(x);
return r;
}
static l4_umword_t mips_test_guest_ctl1()
{
l4_umword_t v, r;
asm volatile ("mfc0 %0, $10, 4" : "=r"(v));
asm volatile ("mtc0 %0, $10, 4" : : "r"(~0UL));
asm volatile ("mfc0 %0, $10, 4" : "=r"(r));
asm volatile ("mtc0 %0, $10, 4" : : "r"(v));
return r;
}
static void print_vz_info()
{
l4_umword_t v = mips_guest_ctl0();
if (v & (1UL << 18))
printf(" MIPS: VZ: Pending Interrupt Passthrough\n");
if (mips_test_guest_ctl0(1UL << 24)) // CG
printf(" MIPS: VZ: Cache Instruction Guest-mode\n");
char const *const ats[] = {
"AT=0 <reserved>", "Guest MMU under Root control",
"AT=2 <reserved>", "Guest MMU under Guest control"
};
printf(" MIPS: VZ: %s\n", ats[(v >> 26) & 3]);
if (v & (1UL << 9)) // RAD
printf(" MIPS: VZ: RAD (Root ASID Dealias)\n");
if (mips_test_guest_ctl0(1UL << 8)) // DRG
printf(" MIPS: VZ: Direct Root to Guest\n");
if (v & (1UL << 22)) // G1
{
printf(" MIPS: VZ: GuestID support\n");
l4_umword_t g1 = mips_test_guest_ctl1();
printf(" MIPS: VZ: GuestCtl1: %lx\n", g1);
printf(" MIPS: VZ: EID=0x%lx\n", (g1 >> 24) & 0xff);
printf(" MIPS: VZ: GuestIDs=%lu\n", (g1 & 0xff) + 1);
printf(" MIPS: VZ: GuestRIDs=%lu\n", ((g1 >> 16) & 0xff) + 1);
}
if (v & (1UL << 7)) // G2
printf(" MIPS: VZ: GuestCtl2 supported\n");
if (v & (1UL << 19)) // G2
{
l4_umword_t t;
asm volatile ("mfc0 %0, $11, 4" : "=r"(t));
printf(" MIPS: VZ: GuestCtl0Ext supported: val=%lx\n", t);
char const *const nccs[] = {
"Guest CCA independent of root CCA",
"Guest CCA modified by root CCA",
"2 <reserved>", "3 <reserved>"
};
printf(" MIPS: VZ: Nested Cache Coherency: %s\n", nccs[(t >> 6) & 3]);
}
}
void print_cpu_info();
void print_cpu_info()
{
l4_umword_t v;
asm volatile ("mfc0 %0, $15" : "=r"(v));
printf(" MIPS: processor ID: %08lx\n", v);
asm volatile ("mfc0 %0, $16" : "=r"(v));
char const *const ars[] = { "r1", "r2+", "r6", "AR<4>", "AR<5>", "AR<6>", "AR<7>" };
char const *const ats[] = { "MIPS32", "MIPS64 (32bit compat)", "MIPS64", "AT<3>" };
printf(" MIPS: Config: %08lx %s %s %s %sMMU-Type=%lx IMPL=%lx K0=%lx KU=%lx K23=%lx\n",
v,
ats[(v >> 13) & 3], ars[(v >> 10) & 7],
(v & (1UL << 15)) ? "BE" : "LE",
(v & 8) ? "VI " : "", (v >> 7) & 7,
(v >> 16) & 0x1ff,
(v & 0x7), (v >> 25) & 7, (v >> 28) & 7);
if (!(v & (1UL << 31)))
return;
asm volatile ("mfc0 %0, $16, 1" : "=r"(v));
printf(" MIPS: Config1: %08lx %s%s%s%s%s%s%s\n", v,
(v & 1) ? "FPU " : "", (v & 2) ? "EJTAG " : "",
(v & 4) ? "MIPS16e " : "", (v & 8) ? "WATCH " : "",
(v & 0x10) ? "PERF " : "", (v & 0x20) ? "MDMX " : "",
(v & 0x40) ? "COP2 " : "");
printf(" MIPS: D-cache: %lu-way %d-set %d byte per line\n",
((v >> 7) & 7) + 1, 32 * (1U << (((v >> 13) + 1) & 7)),
1U << (((v >> 10) & 7) + 1));
printf(" MIPS: I-cache: %lu-way %d-set %d byte per line\n",
((v >> 16) & 7) + 1, 32 * (1U << (((v >> 22) + 1) & 7)),
1U << (((v >> 19) & 7) + 1));
printf(" MIPS: TLB: %lu entries\n", ((v >> 25) & 0x3f) + 1);
if (!(v & (1UL << 31)))
return;
asm volatile ("mfc0 %0, $16, 2" : "=r"(v));
printf(" MIPS: Config2: %08lx\n", v);
print_cache2(2, v);
print_cache2(3, v >> 16);
if (!(v & (1UL << 31)))
return;
asm volatile ("mfc0 %0, $16, 3" : "=r"(v));
printf(" MIPS: Config3: %08lx\n", v);
char const *const features3[] = {
"TraceLogic", "SmartMIPS", "MT (Multi Threading)",
"CDMM (Common Device Memory Map)", "SP (1KiB Page)",
"VInt", "VEIC", "LPA", "ITL (MIPS IFlowtrace)",
"CTXTC (ContextConfig)", "DSPP (MIPS DSP)", "DSP2P (MIPS DSP r2)",
"RXI", "ULRI", "microMIPS", "boot microMIPS", "exc microMIPS",
"MCU"
};
char const *const features3_2[] = {
"VZ", "PW (HW Page Walk)", "SC (Segment Control)", "BadInstr",
"BadInstrP", "MASP (SIMD)", "CMGCR (Coherency Manager MM)",
"BPG (Big Pages)",
};
printf(" MIPS:");
for (unsigned i = 0; i < 18; ++i)
if (v & (1UL << i))
printf(" %s", features3[i]);
for (unsigned i = 23; i < 31; ++i)
if (v & (1UL << i))
printf(" %s", features3_2[i - 23]);
printf("\n");
if (v & (1UL << 23))
print_vz_info();
if (!(v & (1UL << 31)))
return;
asm volatile ("mfc0 %0, $16, 4" : "=r"(v));
printf(" MIPS: Config4: %08lx\n", v);
if (!(v & (1UL << 31)))
return;
asm volatile ("mfc0 %0, $16, 5" : "=r"(v));
printf(" MIPS: Config5: %08lx\n", v);
if (!(v & (1UL << 31)))
return;
}

View File

@@ -0,0 +1,134 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License 2. See the file "COPYING-GPL-2" in the main directory of this
* archive for more details.
*
* Copyright (C) 2013 Imagination Technologies Ltd.
* Author: Prajna Dasgupta <prajna@kymasys.com>
* Author: Yann Le Du <ledu@kymasys.com>
*/
/* -*- c -*- */
#include <sys/asm.h>
/* This routine makes changes to the instruction stream effective to the hardware.
* It should be called after the instruction stream is written.
* On return, the new instructions are effective.
* Inputs:
* a0 = Start address of new instruction stream
* a1 = Size, in bytes, of new instruction stream
*/
#define HW_SYNCI_Step $1
.text
.globl syncICache;
.ent syncICache, 0;
syncICache: ;
.set push
.set noreorder
beq $a1, $0, 20f
nop
# figure out the synci step size the hard way, as rdhwr
# might not work in kernel mode ?
# so read the data and isns cache line size, take the smaller
# one and use this as step size
mfc0 $v1, $16, 1
ext $v0, $v1, 10, 3 # D-cache line size
beq $v0, $zero, 20f # if this is zero (no D-cache) we skip all
ext $v1, $v1, 19, 3 # I-cache line size
beq $v1, $zero, 1f # if zero (no I-cache) we use the DL
nop
sltu $t0, $v0, $v1 # if DL < IL use DL else IL
beq $t0, $zero, 1f
nop
move $v0, $v1
1:
li $v1, 2 # size is 2 << min(DL, IL)
sllv $v0, $v1, $v0
addu $a1, $a0, $a1 # a1 is end = start + size
# run the loop
10:
synci 0($a0)
addu $a0, $a0, $v0
sltu $v1, $a0, $a1
bne $v1, $0, 10b
nop
sync
20:
jr.hb $ra
nop
.set pop
.end syncICache
.section .text.init, "ax"
.type _start, @function
.globl _start
_start:
.set push
.set noreorder
/* initialize GP */
SETUP_GPX($0)
SETUP_GPX64($25, $0)
#if defined(PLATFORM_TYPE_baikal_t) || defined(PLATFORM_TYPE_ci40)
// Fix invalid setting of CCA by boot loader
mfc0 $8, $16, 0
li $9, 5
ins $8, $9, 0, 3
mtc0 $8, $16, 0
#endif
/* for bootstrap, map the first 0x20000000 of memory 1:1 in USEG address space */
li $8, 0x00000000
mtc0 $8, $0, 0 // mtc0 t0, c0_index
li $8, 0x1ffff800 // li t0, 0x1ffff800
mtc0 $8, $5, 0 // mtc0 t0, c0_pagemask (256MB)
li $8, 0x0000001F // even page @0MB, cached, dirty, valid, global
mtc0 $8, $2, 0 // mtc0 t0, c0_entrylo0
li $8, 0x0080001F // odd page @256MB, cached, dirty, valid, global
mtc0 $8, $3, 0 // mtc0 t0, c0_entrylo1
li $8, 0x00000000
mtc0 $8, $10, 0 // mtc0 t0, c0_entryhi (1:1 mapping)
ehb
tlbwi
ehb
mfc0 $8, $12, 0 // mfc0 t0, c0_status
li $9, -5 // ~(1 << 2) -> ST_ERL
and $8, $8, $9 // clear ERL
li $9, 0x20000000 // set ST0_CU1 to enable FPU
or $8, $8, $9
mtc0 $8, $12, 0 // mtc0 t0, c0_status
ehb
mfc0 $8, $15, 1 // Get CPU ID
andi $8, $8, 0x3ff
beqz $8, 7f
nop
6: wait
b 6b
nop
7:
PTR_LA $29, crt0_stack_high
PTR_SUBU $29, (NARGSAVE * SZREG)
PTR_LA $25, __main // jump to USEG address space
jr $25
nop
1:
b 1b
nop
.set pop
.section ".bss", "aw"
.align 12
.global crt0_stack_low
crt0_stack_low:
.space 4096
.global crt0_stack_high
crt0_stack_high:

View File

@@ -0,0 +1,17 @@
#include <l4/sys/compiler.h>
#include "platform.h"
#include "support.h"
#include "startup.h"
extern "C" void __main();
void __main()
{
clear_bss();
ctor_init();
Platform_base::iterate_platforms();
init_modules_infos();
startup(mod_header->mbi_cmdline());
l4_infinite_loop();
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <l4/sys/l4int.h>
namespace Mips {
constexpr l4_addr_t sign_ext(l4_uint32_t base)
{ return (l4_addr_t) ((l4_mword_t) ((l4_int32_t) base)); }
enum : l4_addr_t {
KSEG0 = sign_ext(0x80000000),
KSEG1 = sign_ext(0xa0000000)
};
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Copyright (C) 2014 Imagination Technologies Ltd.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* Yann Le Du <ledu@kymasys.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/sys/compiler.h>
#include "platform.h"
#include "support.h"
void
reboot_arch(void) __attribute__((noreturn));
void
reboot_arch(void)
{
Platform_base::platform->reboot();
l4_infinite_loop();
}

View File

@@ -0,0 +1,97 @@
#include "ldscript.inc"
OUTPUT_FORMAT("elf32-powerpc", "elf32-big",
"elf32-little")
ENTRY(_start)
PHDRS {
text PT_LOAD;
data PT_LOAD;
mods PT_LOAD;
}
SECTIONS
{
/* Read-only sections, merged into text segment. The start address of
* the text segment is : */
. = LINKADDR;
_img_base = .;
.text :
{
. = ALIGN(4);
_stext = .;
*(.text.init)
*(.init)
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
KEEP (*(.fini))
LONG(0xc3) /* terminate .fini */
. = ALIGN(0x40);
*(.rodata .rodata.* .gnu.linkonce.r.* .rodata1)
} : text
_etext = .;
PROVIDE (etext = .);
.note.gnu.build-id : { *(.note.gnu.build-id) }
/* ensure that data starts at a new L4 page */
. = ALIGN(4096);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
*(.anno)
CTORS
PLATFORMS
} : data
/* exception frames for C++ */
.eh_frame :
{
KEEP (*(.eh_frame))
LONG(0) /* terminate .eh_frame */
} : data
. = ALIGN(4);
_edata = .;
PROVIDE (edata = .);
_bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
} : data
_bss_end = .;
_end = . ;
PROVIDE (end = .);
/* Moved here to ensure that these sections are located _after_ the text
* section. In the other case we would get program sections with a virtual
* address of 0 */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.rel.dyn : { *(.rel.dyn) }
/* Needs to be last so that l4image does not mess up PHDR offsets other
* sections. */
. = ALIGN(4096);
.data.m :
{
_module_data_start = .;
*(.module_data)
} : mods
/* drop the following sections since we do not need them for DROPS */
/DISCARD/ : {
*(.interp)
*(.comment)
*(.note)
*(.stab)
*(.stabstr*)
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
/* -*- c -*- */
.section .text.init, "ax"
.type _start, @function
.globl _start
_start:
lis %r1, crt0_stack_high@ha /* load stack pointer */
addi %r1, %r1, crt0_stack_high@l
b __main
1:
b 1b
.section ".bss", "aw"
.global crt0_stack_low
crt0_stack_low:
.space 4096
.global crt0_stack_high
crt0_stack_high:

View File

@@ -0,0 +1,20 @@
#include "platform.h"
#include "support.h"
#include "startup.h"
#include <l4/drivers/of.h>
#include <l4/sys/compiler.h>
extern "C" void __main(unsigned long p1, unsigned long p2, unsigned long p3);
void __main(unsigned long, unsigned long, unsigned long p3)
{
clear_bss();
ctor_init();
L4_drivers::Of::set_prom(p3); //p3 is OF prom pointer
Platform_base::iterate_platforms();
printf("PPC platform initialized\n");
init_modules_infos();
startup(mod_header->mbi_cmdline());
l4_infinite_loop();
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "init_kip.h"
#include <l4/drivers/of_if.h>
void
init_kip_v2_arch(l4_kernel_info_t* l4i)
{
L4_drivers::Of_if of_if;
//l4i->total_ram = of_if.detect_ramsize();
printf("TBD: set total RAM via mem-descs!\n");
l4i->frequency_cpu = (l4_uint32_t)of_if.detect_cpu_freq() / 1000; //kHz
of_if.vesa_set_mode(0x117);
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2008-2009 Technische Universität Dresden.
* Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/sys/compiler.h>
void
reboot_arch(void) __attribute__((noreturn));
void
reboot_arch(void)
{
l4_infinite_loop();
}

View File

@@ -0,0 +1,143 @@
#include "ldscript.inc"
#if __riscv_xlen == 32
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
"elf32-littleriscv")
#else
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv",
"elf64-littleriscv")
#endif
OUTPUT_ARCH(riscv)
ENTRY(_start)
PHDRS {
common PT_LOAD;
mods PT_LOAD;
}
SECTIONS
{
/* Required by elf_machine_load_address() and assumed to be at address 0. */
PROVIDE_HIDDEN(__ehdr_start = 0);
/* Read-only sections, merged into text segment. The start address of
* the text segment is : */
. = LINKADDR;
_img_base = .;
.text :
{
_stext = .;
*(.text.init)
*(.init)
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
KEEP (*(.fini))
LONG(0xc3) /* terminate .fini */
. = ALIGN(0x40);
*(.rodata .rodata.* .gnu.linkonce.r.* .rodata1)
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
} : common
_etext = .;
PROVIDE (etext = .);
.note.gnu.build-id : { *(.note.gnu.build-id) }
/* ensure that data starts at a new L4 page */
. = ALIGN(4096);
.data :
{
__DATA_BEGIN__ = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.anno)
CTORS
PLATFORMS
} : common
.sdata :
{
__SDATA_BEGIN__ = .;
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
} : common
/* exception frames for C++ */
.eh_frame :
{
KEEP (*(.eh_frame))
LONG(0) /* terminate .eh_frame */
} : common
. = ALIGN(4);
_edata = .;
PROVIDE (edata = .);
_bss_start = .;
.sbss :
{
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
} : common
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
} : common
_bss_end = .;
__global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800,
MAX(__DATA_BEGIN__ + 0x800, _bss_end - 0x800));
/* Must be before _end so that they are retained even if modules are moved
* around. In contrast, the .rel.dyn section is not needed after the
* relocations have been processed. */
.dynamic : { *(.dynamic) }
.got : { *(.got.plt) *(.got) }
_end = . ;
PROVIDE (end = .);
/* Moved here to ensure that these sections are located _after_ the text
* section. In the other case we would get program sections with a virtual
* address of 0 */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
}
.rela.plt : { *(.rela.plt) }
/* Needs to be last so that l4image does not mess up PHDR offsets other
* sections. */
. = ALIGN(4096);
.data.m :
{
. = ALIGN(4096);
_module_data_start = .;
*(.module_data)
} : mods
/* drop the following sections since we do not need them for DROPS */
/DISCARD/ : {
*(.interp)
*(.comment)
*(.note)
*(.stab)
*(.fini)
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2021, 2024 Kernkonzept GmbH.
* Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <sys/asm.h>
.section ".text.init", "ax"
.type _start, @function
.globl _start
_start:
.option push
.option norelax
la gp, __global_pointer$
.option pop
// Arguments provided by firmware (OpenSBI)
// a0: Hart ID
// a1: Flattened Device Tree
// Store hartid in tp register
mv tp, a0
la t1, _mp_hart_lottery
li t0, 1
amoadd.w t1, t0, (t1)
// First hart continues with bootstrap
bnez t1, _wait_for_bootstrap
la sp, crt0_stack_high
#ifdef CONFIG_BID_PIE
// save arguments
mv s0, a0
mv s1, a1
/* "Calculate" load address... */
la a0, __ehdr_start
/* Do relocations */
call reloc_static_pie
mv a0, s0
mv a1, s1
#endif
tail __main
_wait_for_bootstrap:
// Other harts wait for bootstrap to finish
REG_L t0, (mp_launch_boot_kernel)
beqz t0, _wait_for_bootstrap
// Continue with next stage
jr t0
.section ".bss", "aw"
.global crt0_stack_low
.balign 16
crt0_stack_low:
.space 8192
.global crt0_stack_high
crt0_stack_high:
.section ".data", "aw"
.global mp_launch_boot_kernel
.balign 8
mp_launch_boot_kernel:
.zero 8
_mp_hart_lottery:
.zero 4

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2021 Kernkonzept GmbH.
* Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "platform.h"
#include "support.h"
#include "startup.h"
struct boot_args boot_args;
extern "C" void __main(unsigned long hartid, unsigned long fdt);
void __main(unsigned long hartid, unsigned long fdt)
{
clear_bss();
boot_args.r[0] = hartid;
boot_args.r[1] = fdt;
ctor_init();
Platform_base::iterate_platforms();
printf("Boot hart ID: %lu\n", hartid);
init_modules_infos();
startup(mod_header->mbi_cmdline());
l4_infinite_loop();
}

Some files were not shown because too many files have changed in this diff Show More