Initial commit

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2021-01-13 03:22:11 +09:00
commit 8af9f1eb95
27 changed files with 1859 additions and 0 deletions

7
.clang-format Normal file
View file

@ -0,0 +1,7 @@
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: Never
BreakBeforeBraces: Linux
AllowShortIfStatementsOnASingleLine: Never
AllowShortFunctionsOnASingleLine: false
IndentCaseLabels: true

14
.editorconfig Normal file
View file

@ -0,0 +1,14 @@
root = true
# Defaults
[*]
indent_style = space
indent_size = 4
tab_width = 4
charset = utf-8
insert_final_newline = true
max_line_length = 100
[Makefile*]
indent_style = tab
indent_size = 8

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
!build/.keep
build/

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "artwork"]
path = artwork
url = https://github.com/AsahiLinux/artwork.git

20
LICENSE Normal file
View file

@ -0,0 +1,20 @@
Copyright (c) 2021 The Asahi Linux controbutors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

66
Makefile Normal file
View file

@ -0,0 +1,66 @@
ARCH := aarch64-linux-gnu-
CFLAGS := -O2 -Wall -Wundef -Werror=strict-prototypes -fno-common -fno-PIE \
-Werror=implicit-function-declaration -Werror=implicit-int \
-ffreestanding -mabi=lp64 -fpic
LDFLAGS := -T m1n1.ld -EL -maarch64elf --no-undefined -X -shared -Bsymbolic \
-z notext --no-apply-dynamic-relocs --orphan-handling=warn --strip-debug \
-z nocopyreloc \
OBJECTS := bootlogo_128.o bootlogo_256.o fb.o main.o start.o startup.o \
string.o uart.o utils.o utils_asm.o vsprintf.o
BUILD_OBJS := $(patsubst %,build/%,$(OBJECTS))
NAME := m1n1
TARGET := m1n1.macho
DEPDIR := build/.deps
CC := $(ARCH)gcc
AS := $(ARCH)gcc
LD := $(ARCH)ld
OBJCOPY := $(ARCH)objcopy
.PHONY: all clean format
all: build/$(TARGET)
clean:
rm -rf build/*
format:
clang-format -i src/*.c src/*.h
build/%.o: src/%.S
@echo " AS $@"
@mkdir -p $(DEPDIR)
@$(AS) -c $(CFLAGS) -Wp,-MMD,$(DEPDIR)/$(*F).d,-MQ,"$@",-MP -o $@ $<
build/%.o: src/%.c
@echo " CC $@"
@mkdir -p $(DEPDIR)
@$(CC) -c $(CFLAGS) -Wp,-MMD,$(DEPDIR)/$(*F).d,-MQ,"$@",-MP -o $@ $<
build/$(NAME).elf: $(BUILD_OBJS) m1n1.ld
@echo " LD $@"
@$(LD) $(LDFLAGS) -o $@ $(BUILD_OBJS)
build/$(NAME).macho: build/$(NAME).elf
@echo " MACHO $@"
@$(OBJCOPY) -O binary $< $@
build/build_tag.h:
@echo " TAG $@"
@echo "#define BUILD_TAG \"$$(git describe --always --dirty)\"" > $@
build/%.bin: data/%.png
@echo " IMG $@"
@convert $< -background black -flatten -depth 8 rgba:$@
build/%.o: build/%.bin
@echo " BIN $@"
@$(OBJCOPY) -I binary -O elf64-littleaarch64 $< $@
build/main.o: build/build_tag.h src/main.c
-include $(DEPDIR)/*

16
README.md Normal file
View file

@ -0,0 +1,16 @@
# m1n1: an experimentation playground for Apple Silicon
(And perhaps some day a Linux bootloader)
## License
Copyright (c) 2021 The Asahi Linux contributors
m1n1 is licensed under the MIT license, as included in the [LICENSE](LICENSE) file.
Please see the Git history for authorship information.
Portions of m1n1 are based on mini:
Copyright (c) 2008-2010 Hector Martin "marcan" <marcan@marcan.st>
Copyright (c) 2008-2010 Sven Peter <sven@svenpeter.dev>
Copyright (c) 2008-2010 Andre Heider <a.heider@gmail.com>

1
artwork Submodule

@ -0,0 +1 @@
Subproject commit 35626c31f5c5a8a884aaff93f864795026495742

1
data/bootlogo_128.png Symbolic link
View file

@ -0,0 +1 @@
../artwork/logos/png_128/AsahiLinux_logomark.png

1
data/bootlogo_256.png Symbolic link
View file

@ -0,0 +1 @@
../artwork/logos/png_256/AsahiLinux_logomark.png

185
m1n1.ld Normal file
View file

@ -0,0 +1,185 @@
ENTRY(_start)
/* Fake virtual load address for the mach-o */
_va_base = 0xFFFFFE0007004000;
/* We are actually relocatable */
_base = 0;
_stack_size = 0x20000;
. = _base;
PHDRS
{
hdr PT_LOAD;
text PT_LOAD;
rodata PT_LOAD;
data PT_LOAD;
}
SECTIONS {
.header : {
_mach_header = .;
/* mach-o header */
LONG(0xfeedfacf); /* magic */
LONG(0x100000c); /* cputype */
LONG(0x02); /* cputype */
LONG(0x0c); /* filetype */
LONG(5); /* ncmds */
LONG(_cmd_end - _cmd_start); /* sizeofcmds */
LONG(4); /* flags */
LONG(0); /* reserved */
_cmd_start = .;
/* unix_thread (entrypoint) */
LONG(0x5); /* type = UNIX_THREAD */
LONG(0x120); /* cmdsize */
LONG(6); /* ARM_THREAD64 */
LONG(0x44); /* length */
. += 32 * 8; /* useless registers */
QUAD(_start + _va_off) /* pc */
. += 8; /* useless registers */
ASSERT(. - _cmd_start == 0x120, "Bad unix_thread structure");
/* segment: mach-o structures */
LONG(0x19); /* type = SEGMENT_64 */
LONG(0x48); /* cmdsize */
LONG(0x5244485f); /* segname = "_HDR" */
. += 12;
QUAD(ADDR(.header) + _va_off); /* vmaddr */
QUAD(SIZEOF(.header)); /* vmsize */
QUAD(ADDR(.header) - _base); /* fileoff */
QUAD(SIZEOF(.header)); /* filesize */
LONG(PROT_READ); /* maxprot */
LONG(PROT_READ); /* initprot */
LONG(0); /* nsects */
LONG(0); /* flags */
/* segment: text */
LONG(0x19); /* type = SEGMENT_64 */
LONG(0x48); /* cmdsize */
LONG(0x54584554); /* segname = "TEXT" */
. += 12;
QUAD(ADDR(.init) + _va_off); /* vmaddr */
QUAD(_text_size); /* vmsize */
QUAD(ADDR(.init) - _base); /* fileoff */
QUAD(_text_size); /* filesize */
LONG(PROT_READ | PROT_EXECUTE); /* maxprot */
LONG(PROT_READ | PROT_EXECUTE); /* initprot */
LONG(0); /* nsects */
LONG(0); /* flags */
/* segment: rodata */
LONG(0x19); /* type = SEGMENT_64 */
LONG(0x48); /* cmdsize */
LONG(0x41444F52); /* segname = "RODA" */
. += 12;
QUAD(ADDR(.rodata) + _va_off); /* vmaddr */
QUAD(_rodata_end - ADDR(.rodata)); /* vmsize */
QUAD(ADDR(.rodata) - _base); /* fileoff */
QUAD(_rodata_end - ADDR(.rodata)); /* filesize */
LONG(PROT_READ); /* maxprot */
LONG(PROT_READ); /* initprot */
LONG(0); /* nsects */
LONG(0); /* flags */
/* segment: data */
LONG(0x19); /* type = SEGMENT_64 */
LONG(0x48); /* cmdsize */
LONG(0x41544144); /* segmname = "DATA" */
. += 12;
QUAD(ADDR(.data) + _va_off); /* vmaddr */
QUAD(_data_size); /* vmsize */
QUAD(ADDR(.data) - _base); /* fileoff */
QUAD(SIZEOF(.data)); /* filesize */
LONG(PROT_READ | PROT_WRITE); /* maxprot */
LONG(PROT_READ | PROT_WRITE); /* initprot */
LONG(0); /* nsects */
LONG(0); /* flags */
_cmd_end = .;
. = ALIGN(0x8000);
_hdr_end = .;
} :hdr
_text_start = .;
.init : ALIGN(0x8000) {
*(.init)
*(.init.*)
} :text
.text : ALIGN(0x8000) {
*(.text)
*(.text.*)
. = ALIGN(8);
*(.got.plt)
. = ALIGN(0x8000);
} :text
_text_size = . - _text_start;
.rodata : ALIGN(0x8000) {
*(.rodata)
*(.rodata.*)
. = ALIGN(8);
} :rodata
.rela.dyn : {
_rela_start = .;
*(.rela)
*(.rela.*)
_rela_end = .;
. = ALIGN(0x8000);
} :rodata
_rodata_end = .;
_data_start = .;
.data : ALIGN(0x8000) {
*(.data)
*(.data.*)
. = ALIGN(8);
_got_start = .;
*(.got)
_got_end = .;
. = ALIGN(0x8000);
} :data
.bss : ALIGN(0x8000) {
*(.bss)
*(.bss.*)
*(.dynbss)
*(COMMON)
. = ALIGN(0x8000);
PROVIDE(_stack_top = .);
. += _stack_size;
PROVIDE(_stack_bot = .);
. = ALIGN(0x8000);
} :data
_data_size = . - _data_start;
_end = .;
/DISCARD/ : {
*(.discard)
*(.discard.*)
*(.interp .dynamic)
*(.dynsym .dynstr .hash .gnu.hash)
*(.eh_frame)
*(.gnu.version*)
*(.note*)
*(.comment*)
}
.empty (NOLOAD) : {
*(.plt) *(.plt.*) *(.iplt) *(.igot)
*(.data.rel.ro)
}
ASSERT(SIZEOF(.empty) == 0, "Unexpected sections detected!")
.got.plt (NOLOAD) : {
*(.got.plt)
}
ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT PLT detected!")
}
PROT_READ = 0x01;
PROT_WRITE = 0x02;
PROT_EXECUTE = 0x04;
_va_off = _va_base - _base;

62
src/fb.c Normal file
View file

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: MIT */
#include "fb.h"
#include "utils.h"
#include "xnuboot.h"
u32 *fb;
int fb_s, fb_w, fb_h;
static u32 *logo;
static int logo_w, logo_h;
extern char _binary_build_bootlogo_128_bin_start[0];
extern char _binary_build_bootlogo_256_bin_start[0];
void fb_init(void)
{
fb = (void *)cur_boot_args.video.base;
fb_s = cur_boot_args.video.stride / 4;
fb_w = cur_boot_args.video.width;
fb_h = cur_boot_args.video.height;
printf("fb init: %dx%d [s=%d] @%p\n", fb_w, fb_h, fb_s, fb);
if (fb_w > 2048) { // random guess
logo = (void *)_binary_build_bootlogo_256_bin_start;
logo_w = logo_h = 256;
} else {
logo = (void *)_binary_build_bootlogo_128_bin_start;
logo_w = logo_h = 128;
}
}
static inline uint32_t rgbx_to_rgb30(u32 c)
{
u8 r = c;
u8 g = c >> 8;
u8 b = c >> 16;
return (b << 2) | (g << 12) | (r << 22);
}
void fb_blit(int x, int y, int w, int h, void *data, int stride)
{
uint32_t *p = data;
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
fb[x + j + (y + i) * fb_s] = rgbx_to_rgb30(p[j + i * stride]);
}
void fb_fill(int x, int y, int w, int h, u32 color)
{
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
fb[x + j + (y + i) * fb_s] = rgbx_to_rgb30(color);
}
void fb_display_logo(void)
{
printf("fb: display logo\n");
fb_blit((fb_w - logo_w) / 2, (fb_h - logo_h) / 2, logo_w, logo_h, logo,
logo_w);
}

17
src/fb.h Normal file
View file

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: MIT */
#ifndef FB_H
#define FB_H
#include "types.h"
extern u32 *fb;
extern int fb_s, fb_w, fb_h;
void fb_init(void);
void fb_blit(int x, int y, int w, int h, void *data, int stride);
void fb_fill(int x, int y, int w, int h, u32 color);
void fb_display_logo(void);
#endif

25
src/main.c Normal file
View file

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: MIT */
#include "fb.h"
#include "utils.h"
#include "xnuboot.h"
#include "../build/build_tag.h"
void m1n1_main(void)
{
printf("\n\nm1n1 v%s\n", BUILD_TAG);
printf("Copyright (C) 2021 The Asahi Linux Contributors\n");
printf("Licensed under the MIT license\n");
fb_init();
fb_display_logo();
u64 dtaddr = ((u64)cur_boot_args.devtree) - cur_boot_args.virt_base +
cur_boot_args.phys_base;
hexdump((void *)dtaddr, cur_boot_args.devtree_size);
while (1)
;
}

61
src/start.S Normal file
View file

@ -0,0 +1,61 @@
/* SPDX-License-Identifier: MIT */
#define UART_BASE 0x235200000
#define UTRSTAT 0x010
#define UTXH 0x020
.extern _start_c
.extern _stack_bot
.section .init, "ax"
.globl _start
.type _start, @function
_start:
mov x9, x0
mov w0, 'm'
bl debug_putc
mov w0, '1'
bl debug_putc
adrp x1, _stack_bot
mov sp, x1
mov w0, 'n'
bl debug_putc
adrp x0, _base
mov x10, x0
adrp x1, _rela_start
add x1, x1, :lo12:_rela_start
adrp x2, _rela_end
add x2, x2, :lo12:_rela_end
bl apply_rela
mov w0, '1'
bl debug_putc
mov w0, '\r'
bl debug_putc
mov w0, '\n'
bl debug_putc
mov x0, x9
mov x1, x10
bl _start_c
b .
.globl debug_putc
.type debug_putc, @function
debug_putc:
ldr x1, =UART_BASE
1:
ldr w2, [x1, UTRSTAT]
tst w2, #2
beq 1b
str w0, [x1, UTXH]
ret
.pool

77
src/startup.c Normal file
View file

@ -0,0 +1,77 @@
/* SPDX-License-Identifier: MIT */
#include "string.h"
#include "types.h"
#include "uart.h"
#include "utils.h"
#include "xnuboot.h"
struct boot_args cur_boot_args;
struct rela_entry {
uint64_t off, type, addend;
};
void debug_putc(char c);
void m1n1_main(void);
#define R_AARCH64_RELATIVE 1027
void apply_rela(uint64_t base, struct rela_entry *rela_start,
struct rela_entry *rela_end)
{
struct rela_entry *e = rela_start;
while (e < rela_end) {
switch (e->type) {
case R_AARCH64_RELATIVE:
*(u64 *)(base + e->off) = base + e->addend;
break;
default:
debug_putc('R');
debug_putc('!');
while (1)
;
}
e++;
}
}
void dump_boot_args(struct boot_args *ba)
{
printf(" revision: %d\n", ba->revision);
printf(" version: %d\n", ba->version);
printf(" virt_base: 0x%lx\n", ba->virt_base);
printf(" phys_base: 0x%lx\n", ba->phys_base);
printf(" mem_size: 0x%lx\n", ba->mem_size);
printf(" top_of_kdata: 0x%lx\n", ba->top_of_kernel_data);
printf(" video:\n");
printf(" base: 0x%lx\n", ba->video.base);
printf(" display: 0x%lx\n", ba->video.display);
printf(" stride: 0x%lx\n", ba->video.stride);
printf(" width: %d\n", ba->video.width);
printf(" height: %d\n", ba->video.height);
printf(" depth: 0x%lx\n", ba->video.depth);
printf(" machine_type: %d\n", ba->machine_type);
printf(" devtree: %p\n", ba->devtree);
printf(" devtree_size: 0x%x\n", ba->devtree_size);
printf(" cmdline: %s\n", ba->cmdline);
printf(" boot_flags: 0x%x\n", ba->boot_flags);
printf(" mem_size_act: 0x%lx\n", ba->mem_size_actual);
}
void _start_c(void *boot_args, void *base)
{
uart_putc('s');
uart_init();
uart_putc('c');
uart_puts(": Initializing\n");
printf("boot_args at %p\n", boot_args);
memcpy(&cur_boot_args, boot_args, sizeof(cur_boot_args));
dump_boot_args(&cur_boot_args);
m1n1_main();
}

86
src/string.c Normal file
View file

@ -0,0 +1,86 @@
/* SPDX-License-Identifier: MIT */
#include <string.h>
// Routines based on The Public Domain C Library
void *memcpy(void *s1, const void *s2, size_t n)
{
char *dest = (char *)s1;
const char *src = (const char *)s2;
while (n--) {
*dest++ = *src++;
}
return s1;
}
int memcmp(const void *s1, const void *s2, size_t n)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;
while (n--) {
if (*p1 != *p2) {
return *p1 - *p2;
}
++p1;
++p2;
}
return 0;
}
void *memset(void *s, int c, size_t n)
{
unsigned char *p = (unsigned char *)s;
while (n--) {
*p++ = (unsigned char)c;
}
return s;
}
char *strcpy(char *s1, const char *s2)
{
char *rc = s1;
while ((*s1++ = *s2++)) {
/* EMPTY */
}
return rc;
}
char *strncpy(char *s1, const char *s2, size_t n)
{
char *rc = s1;
while (n && (*s1++ = *s2++)) {
/* Cannot do "n--" in the conditional as size_t is unsigned and we have
to check it again for >0 in the next loop below, so we must not risk
underflow.
*/
--n;
}
/* Checking against 1 as we missed the last --n in the loop above. */
while (n-- > 1) {
*s1++ = '\0';
}
return rc;
}
int strcmp(const char *s1, const char *s2)
{
while ((*s1) && (*s1 == *s2)) {
++s1;
++s2;
}
return (*(unsigned char *)s1 - *(unsigned char *)s2);
}

15
src/string.h Normal file
View file

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: MIT */
#ifndef STRING_H
#define STRING_H
#include <stddef.h>
void *memcpy(void *s1, const void *s2, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
void *memset(void *s, int c, size_t n);
char *strcpy(char *s1, const char *s2);
char *strncpy(char *s1, const char *s2, size_t n);
int strcmp(const char *s1, const char *s2);
#endif

49
src/types.h Normal file
View file

@ -0,0 +1,49 @@
/* SPDX-License-Identifier: MIT */
#ifndef TYPES_H
#define TYPES_H
#include <stddef.h>
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef u64 uintptr_t;
typedef s64 ptrdiff_t;
#define NULL ((void *)0)
#define ALIGNED(x) __attribute__((aligned(x)))
#define STACK_ALIGN(type, name, cnt, alignment) \
u8 _al__##name[( \
(sizeof(type) * (cnt)) + (alignment) + \
(((sizeof(type) * (cnt)) % (alignment)) > 0 \
? ((alignment) - ((sizeof(type) * (cnt)) % (alignment))) \
: 0))]; \
type *name = \
(type *)(((u32)(_al__##name)) + \
((alignment) - (((u32)(_al__##name)) & ((alignment)-1))))
#define INT_MAX ((int)0x7fffffff)
#define UINT_MAX ((unsigned int)0xffffffff)
#define LONG_MAX ((long)0x7fffffffffffffffl)
#define ULONG_MAX ((unsigned long)0xfffffffffffffffful)
#define LLONG_MAX LONG_MAX
#define ULLONG_MAX ULLONG_MAX
#define HAVE_PTRDIFF_T 1
#define HAVE_UINTPTR_T 1
#define UPTRDIFF_T uintptr_t
#endif

63
src/uart.c Normal file
View file

@ -0,0 +1,63 @@
/* SPDX-License-Identifier: MIT */
#include <stdarg.h>
#include "types.h"
#include "uart.h"
#include "utils.h"
#include "vsprintf.h"
#define UART_BASE 0x235200000L
#define ULCON 0x000
#define UCON 0x004
#define UFCON 0x008
#define UTRSTAT 0x010
#define UTXH 0x020
#define URXH 0x024
#define UBRDIV 0x028
#define UFRACVAL 0x02c
void *pxx = uart_init;
void uart_init(void)
{
/* keep UART config from iBoot */
}
void uart_putbyte(u8 c)
{
while (!(read32(UART_BASE + UTRSTAT) & 0x02))
;
write32(UART_BASE + UTXH, c);
}
void uart_putc(u8 c)
{
if (c == '\n')
uart_putbyte('\r');
uart_putbyte(c);
}
void uart_puts(const char *s)
{
while (*s)
uart_putc(*(s++));
uart_putc('\n');
}
void uart_write(const void *buf, size_t count)
{
const u8 *p = buf;
while (count--)
uart_putbyte(*p++);
}
u8 uart_getc(void)
{
return 0;
}

15
src/uart.h Normal file
View file

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: MIT */
#ifndef UART_H
#define UART_H
void uart_init(void);
void uart_putc(u8 c);
u8 uart_getc(void);
void uart_write(const void *buf, size_t count);
void uart_puts(const char *s);
#endif

80
src/utils.c Normal file
View file

@ -0,0 +1,80 @@
/* SPDX-License-Identifier: MIT */
#include "utils.h"
#include "types.h"
#include "uart.h"
#include "vsprintf.h"
#include <stdarg.h>
static char ascii(char s)
{
if (s < 0x20)
return '.';
if (s > 0x7E)
return '.';
return s;
}
void hexdump(const void *d, int len)
{
u8 *data;
int i, off;
data = (u8 *)d;
for (off = 0; off < len; off += 16) {
printf("%08x ", off);
for (i = 0; i < 16; i++) {
if ((i + off) >= len)
printf(" ");
else
printf("%02x ", data[off + i]);
}
printf(" ");
for (i = 0; i < 16; i++) {
if ((i + off) >= len)
printf(" ");
else
printf("%c", ascii(data[off + i]));
}
printf("\n");
}
}
void regdump(u64 addr, int len)
{
u64 i, off;
for (off = 0; off < len; off += 32) {
printf("%016x ", addr + off);
for (i = 0; i < 32; i += 4) {
printf("%08x ", read32(addr + off + i));
}
printf("\n");
}
}
int sprintf(char *buffer, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = vsprintf(buffer, fmt, args);
va_end(args);
return i;
}
int debug_printf(const char *fmt, ...)
{
va_list args;
char buffer[512];
int i;
va_start(args, fmt);
i = vsprintf(buffer, fmt, args);
va_end(args);
uart_write(buffer, i);
return i;
}

167
src/utils.h Normal file
View file

@ -0,0 +1,167 @@
/* SPDX-License-Identifier: MIT */
#ifndef UTILS_H
#define UTILS_H
#include "types.h"
#define printf debug_printf
static inline u32 read32(u64 addr)
{
u32 data;
__asm__ volatile("ldr\t%w0, [%1]" : "=r"(data) : "r"(addr));
return data;
}
static inline void write32(u64 addr, u32 data)
{
__asm__ volatile("str\t%w0, [%1]" : : "r"(data), "r"(addr));
}
static inline u32 set32(u64 addr, u32 set)
{
u32 data;
__asm__ volatile("ldr\t%w0, [%1]\n"
"\torr\t%w0, %w0, %w2\n"
"\tstr\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(set));
return data;
}
static inline u32 clear32(u64 addr, u32 clear)
{
u32 data;
__asm__ volatile("ldr\t%w0, [%1]\n"
"\tbic\t%w0, %w0, %w2\n"
"\tstr\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(clear));
return data;
}
static inline u32 mask32(u64 addr, u32 clear, u32 set)
{
u32 data;
__asm__ volatile("ldr\t%w0, [%1]\n"
"\tbic\t%w0, %w0, %w3\n"
"\torr\t%w0, %w0, %w2\n"
"\tstr\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(set), "r"(clear));
return data;
}
static inline u16 read16(u64 addr)
{
u32 data;
__asm__ volatile("ldrh\t%w0, [%1]" : "=r"(data) : "r"(addr));
return data;
}
static inline void write16(u64 addr, u16 data)
{
__asm__ volatile("strh\t%w0, [%1]" : : "r"(data), "r"(addr));
}
static inline u16 set16(u64 addr, u16 set)
{
u16 data;
__asm__ volatile("ldrh\t%w0, [%1]\n"
"\torr\t%w0, %w0, %w2\n"
"\tstrh\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(set)
);
return data;
}
static inline u16 clear16(u64 addr, u16 clear)
{
u16 data;
__asm__ volatile("ldrh\t%w0, [%1]\n"
"\tbic\t%w0, %w0, %w2\n"
"\tstrh\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(clear));
return data;
}
static inline u16 mask16(u64 addr, u16 clear, u16 set)
{
u16 data;
__asm__ volatile("ldrh\t%w0, [%1]\n"
"\tbic\t%w0, %3\n"
"\torr\t%w0, %w0, %w2\n"
"\tstrh\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(set), "r"(clear));
return data;
}
static inline u8 read8(u64 addr)
{
u32 data;
__asm__ volatile("ldrb\t%w0, [%1]" : "=r"(data) : "r"(addr));
return data;
}
static inline void write8(u64 addr, u8 data)
{
__asm__ volatile("strb\t%w0, [%1]" : : "r"(data), "r"(addr));
}
static inline u8 set8(u64 addr, u8 set)
{
u8 data;
__asm__ volatile("ldrb\t%w0, [%1]\n"
"\torr\t%w0, %w0, %w2\n"
"\tstrb\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(set));
return data;
}
static inline u8 clear8(u64 addr, u8 clear)
{
u8 data;
__asm__ volatile("ldrb\t%w0, [%1]\n"
"\tbic\t%w0, %w0, %w2\n"
"\tstrb\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(clear));
return data;
}
static inline u8 mask8(u64 addr, u8 clear, u8 set)
{
u8 data;
__asm__ volatile("ldrb\t%w0, [%1]\n"
"\tbic\t%w0, %w0, %w3\n"
"\torr\t%w0, %w0, %w2\n"
"\tstrb\t%w0, [%1]"
: "=&r"(data)
: "r"(addr), "r"(set), "r"(clear));
return data;
}
/*
* These functions are guaranteed to copy by reading from src and writing to dst
* in <n>-bit units If size is not aligned, the remaining bytes are not copied
*/
void memset32(void *dst, u32 value, u32 size);
void memcpy32(void *dst, void *src, u32 size);
void memset16(void *dst, u16 value, u32 size);
void memcpy16(void *dst, void *src, u32 size);
void memset8(void *dst, u8 value, u32 size);
void memcpy8(void *dst, void *src, u32 size);
void hexdump(const void *d, int len);
void regdump(u64 addr, int len);
int sprintf(char *str, const char *fmt, ...);
int debug_printf(const char *fmt, ...);
void udelay(u32 d);
#endif

72
src/utils_asm.S Normal file
View file

@ -0,0 +1,72 @@
/* SPDX-License-Identifier: MIT */
.text
.globl memcpy32
.type memcpy32, @function
memcpy32:
ands x2, x2, #~3
beq 2f
1: ldr x3, [x1], #4
str w3, [x0], #4
subs x2, x2, #4
bne 1b
2:
ret
.globl memset32
.type memset32, @function
memset32:
ands x2, x2, #~3
beq 2f
1: str w1, [x0], #4
subs x2, x2, #4
bne 1b
2:
ret
.globl memcpy16
.type memcpy16, @function
memcpy16:
ands x2, x2, #~1
beq 2f
1: ldrh w3, [x1], #2
strh w3, [x0], #2
subs x2, x2, #2
bne 1b
2:
ret
.globl memset16
.type memset16, @function
memset16:
ands x2, x2, #~1
beq 2f
1: strh w1, [x0], #2
subs x2, x2, #2
bne 1b
2:
ret
.globl memcpy8
.type memcpy8, @function
memcpy8:
cmp x2, #0
beq 2f
1: ldrb w3, [x1], #1
strb w3, [x0], #1
subs x2, x2, #1
bne 1b
2:
ret
.globl memset8
.type memset8, @function
memset8:
cmp x2, #0
beq 2f
1: strb w1, [x0], #1
subs x2, x2, #1
bne 1b
2:
ret

708
src/vsprintf.c Normal file
View file

@ -0,0 +1,708 @@
/*
* Copyright (c) 1995 Patrick Powell.
*
* This code is based on code written by Patrick Powell <papowell@astart.com>.
* It may be used for any purpose as long as this notice remains intact on all
* source code distributions.
*/
/*
* Copyright (c) 2008 Holger Weiss.
*
* This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
* My changes to the code may freely be used, modified and/or redistributed for
* any purpose. It would be nice if additions and fixes to this file (including
* trivial code cleanups) would be sent back in order to let me include them in
* the version available at <http://www.jhweiss.de/software/snprintf.html>.
* However, this is not a requirement for using or redistributing (possibly
* modified) versions of this file, nor is leaving this notice intact mandatory.
*/
/*
* History
*
* 2009-03-05 Hector Martin "marcan" <marcan@marcansoft.com>
*
* Hacked up and removed a lot of stuff including floating-point support,
* a bunch of ifs and defines, locales, and tests
*
* 2008-01-20 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.1:
*
* Fixed the detection of infinite floating point values on IRIX (and
* possibly other systems) and applied another few minor cleanups.
*
* 2008-01-06 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.0:
*
* Added a lot of new features, fixed many bugs, and incorporated various
* improvements done by Andrew Tridgell <tridge@samba.org>, Russ Allbery
* <rra@stanford.edu>, Hrvoje Niksic <hniksic@xemacs.org>, Damien Miller
* <djm@mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH
* projects. The additions include: support the "e", "E", "g", "G", and
* "F" conversion specifiers (and use conversion style "f" or "F" for the
* still unsupported "a" and "A" specifiers); support the "hh", "ll", "j",
* "t", and "z" length modifiers; support the "#" flag and the (non-C99)
* "'" flag; use localeconv(3) (if available) to get both the current
* locale's decimal point character and the separator between groups of
* digits; fix the handling of various corner cases of field width and
* precision specifications; fix various floating point conversion bugs;
* handle infinite and NaN floating point values; don't attempt to write to
* the output buffer (which may be NULL) if a size of zero was specified;
* check for integer overflow of the field width, precision, and return
* values and during the floating point conversion; use the OUTCHAR() macro
* instead of a function for better performance; provide asprintf(3) and
* vasprintf(3) functions; add new test cases. The replacement functions
* have been renamed to use an "rpl_" prefix, the function calls in the
* main project (and in this file) must be redefined accordingly for each
* replacement function which is needed (by using Autoconf or other means).
* Various other minor improvements have been applied and the coding style
* was cleaned up for consistency.
*
* 2007-07-23 Holger Weiss <holger@jhweiss.de> for Mutt 1.5.13:
*
* C99 compliant snprintf(3) and vsnprintf(3) functions return the number
* of characters that would have been written to a sufficiently sized
* buffer (excluding the '\0'). The original code simply returned the
* length of the resulting output string, so that's been fixed.
*
* 1998-03-05 Michael Elkins <me@mutt.org> for Mutt 0.90.8:
*
* The original code assumed that both snprintf(3) and vsnprintf(3) were
* missing. Some systems only have snprintf(3) but not vsnprintf(3), so
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
*
* 1998-01-27 Thomas Roessler <roessler@does-not-exist.org> for Mutt 0.89i:
*
* The PGP code was using unsigned hexadecimal formats. Unfortunately,
* unsigned formats simply didn't work.
*
* 1997-10-22 Brandon Long <blong@fiction.net> for Mutt 0.87.1:
*
* Ok, added some minimal floating point support, which means this probably
* requires libm on most operating systems. Don't yet support the exponent
* (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just
* wasn't being exercised in ways which showed it, so that's been fixed.
* Also, formatted the code to Mutt conventions, and removed dead code left
* over from the original. Also, there is now a builtin-test, run with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf
*
* 2996-09-15 Brandon Long <blong@fiction.net> for Mutt 0.43:
*
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything from the
* normal C string format, at least as far as I can tell from the Solaris
* 2.5 printf(3S) man page.
*/
#include "types.h"
#include <stdarg.h>
#define VA_START(ap, last) va_start(ap, last)
#define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */
#define ULLONG unsigned long long
#define UINTMAX_T unsigned long
#define LLONG long
#define INTMAX_T long
/* Support for uintptr_t. */
#ifndef UINTPTR_T
#if HAVE_UINTPTR_T || defined(uintptr_t)
#define UINTPTR_T uintptr_t
#else
#define UINTPTR_T unsigned long int
#endif /* HAVE_UINTPTR_T || defined(uintptr_t) */
#endif /* !defined(UINTPTR_T) */
/* Support for ptrdiff_t. */
#ifndef PTRDIFF_T
#if HAVE_PTRDIFF_T || defined(ptrdiff_t)
#define PTRDIFF_T ptrdiff_t
#else
#define PTRDIFF_T long int
#endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */
#endif /* !defined(PTRDIFF_T) */
/*
* We need an unsigned integer type corresponding to ptrdiff_t (cf. C99:
* 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an
* unsigned type if necessary. This should work just fine in practice.
*/
#ifndef UPTRDIFF_T
#define UPTRDIFF_T PTRDIFF_T
#endif /* !defined(UPTRDIFF_T) */
/*
* We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7).
* However, we'll simply use size_t and convert it to a signed type if
* necessary. This should work just fine in practice.
*/
#ifndef SSIZE_T
#define SSIZE_T size_t
#endif /* !defined(SSIZE_T) */
/*
* Buffer size to hold the octal string representation of UINT128_MAX without
* nul-termination ("3777777777777777777777777777777777777777777").
*/
#ifdef MAX_CONVERT_LENGTH
#undef MAX_CONVERT_LENGTH
#endif /* defined(MAX_CONVERT_LENGTH) */
#define MAX_CONVERT_LENGTH 43
/* Format read states. */
#define PRINT_S_DEFAULT 0
#define PRINT_S_FLAGS 1
#define PRINT_S_WIDTH 2
#define PRINT_S_DOT 3
#define PRINT_S_PRECISION 4
#define PRINT_S_MOD 5
#define PRINT_S_CONV 6
/* Format flags. */
#define PRINT_F_MINUS (1 << 0)
#define PRINT_F_PLUS (1 << 1)
#define PRINT_F_SPACE (1 << 2)
#define PRINT_F_NUM (1 << 3)
#define PRINT_F_ZERO (1 << 4)
#define PRINT_F_QUOTE (1 << 5)
#define PRINT_F_UP (1 << 6)
#define PRINT_F_UNSIGNED (1 << 7)
#define PRINT_F_TYPE_G (1 << 8)
#define PRINT_F_TYPE_E (1 << 9)
/* Conversion flags. */
#define PRINT_C_CHAR 1
#define PRINT_C_SHORT 2
#define PRINT_C_LONG 3
#define PRINT_C_LLONG 4
//#define PRINT_C_LDOUBLE 5
#define PRINT_C_SIZE 6
#define PRINT_C_PTRDIFF 7
#define PRINT_C_INTMAX 8
#ifndef MAX
#define MAX(x, y) ((x >= y) ? x : y)
#endif /* !defined(MAX) */
#ifndef CHARTOINT
#define CHARTOINT(ch) (ch - '0')
#endif /* !defined(CHARTOINT) */
#ifndef ISDIGIT
#define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9')
#endif /* !defined(ISDIGIT) */
#define OUTCHAR(str, len, size, ch) \
do { \
if (len + 1 < size) \
str[len] = ch; \
(len)++; \
} while (/* CONSTCOND */ 0)
static void fmtstr(char *, size_t *, size_t, const char *, int, int, int);
static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int);
static void printsep(char *, size_t *, size_t);
static int getnumsep(int);
static int convert(UINTMAX_T, char *, size_t, int, int);
int vsnprintf(char *str, size_t size, const char *format, va_list args)
{
INTMAX_T value;
unsigned char cvalue;
const char *strvalue;
INTMAX_T *intmaxptr;
PTRDIFF_T *ptrdiffptr;
SSIZE_T *sizeptr;
LLONG *llongptr;
long int *longptr;
int *intptr;
short int *shortptr;
signed char *charptr;
size_t len = 0;
int overflow = 0;
int base = 0;
int cflags = 0;
int flags = 0;
int width = 0;
int precision = -1;
int state = PRINT_S_DEFAULT;
char ch = *format++;
/*
* C99 says: "If `n' is zero, nothing is written, and `s' may be a null
* pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer
* even if a size larger than zero was specified. At least NetBSD's
* snprintf(3) does the same, as well as other versions of this file.
* (Though some of these versions will write to a non-NULL buffer even
* if a size of zero was specified, which violates the standard.)
*/
if (str == NULL && size != 0)
size = 0;
while (ch != '\0')
switch (state) {
case PRINT_S_DEFAULT:
if (ch == '%')
state = PRINT_S_FLAGS;
else
OUTCHAR(str, len, size, ch);
ch = *format++;
break;
case PRINT_S_FLAGS:
switch (ch) {
case '-':
flags |= PRINT_F_MINUS;
ch = *format++;
break;
case '+':
flags |= PRINT_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= PRINT_F_SPACE;
ch = *format++;
break;
case '#':
flags |= PRINT_F_NUM;
ch = *format++;
break;
case '0':
flags |= PRINT_F_ZERO;
ch = *format++;
break;
case '\'': /* SUSv2 flag (not in C99). */
flags |= PRINT_F_QUOTE;
ch = *format++;
break;
default:
state = PRINT_S_WIDTH;
break;
}
break;
case PRINT_S_WIDTH:
if (ISDIGIT(ch)) {
ch = CHARTOINT(ch);
if (width > (INT_MAX - ch) / 10) {
overflow = 1;
goto out;
}
width = 10 * width + ch;
ch = *format++;
} else if (ch == '*') {
/*
* C99 says: "A negative field width argument is
* taken as a `-' flag followed by a positive
* field width." (7.19.6.1, 5)
*/
if ((width = va_arg(args, int)) < 0) {
flags |= PRINT_F_MINUS;
width = -width;
}
ch = *format++;
state = PRINT_S_DOT;
} else
state = PRINT_S_DOT;
break;
case PRINT_S_DOT:
if (ch == '.') {
state = PRINT_S_PRECISION;
ch = *format++;
} else
state = PRINT_S_MOD;
break;
case PRINT_S_PRECISION:
if (precision == -1)
precision = 0;
if (ISDIGIT(ch)) {
ch = CHARTOINT(ch);
if (precision > (INT_MAX - ch) / 10) {
overflow = 1;
goto out;
}
precision = 10 * precision + ch;
ch = *format++;
} else if (ch == '*') {
/*
* C99 says: "A negative precision argument is
* taken as if the precision were omitted."
* (7.19.6.1, 5)
*/
if ((precision = va_arg(args, int)) < 0)
precision = -1;
ch = *format++;
state = PRINT_S_MOD;
} else
state = PRINT_S_MOD;
break;
case PRINT_S_MOD:
switch (ch) {
case 'h':
ch = *format++;
if (ch == 'h') { /* It's a char. */
ch = *format++;
cflags = PRINT_C_CHAR;
} else
cflags = PRINT_C_SHORT;
break;
case 'l':
ch = *format++;
if (ch == 'l') { /* It's a long long. */
ch = *format++;
cflags = PRINT_C_LLONG;
} else
cflags = PRINT_C_LONG;
break;
case 'j':
cflags = PRINT_C_INTMAX;
ch = *format++;
break;
case 't':
cflags = PRINT_C_PTRDIFF;
ch = *format++;
break;
case 'z':
cflags = PRINT_C_SIZE;
ch = *format++;
break;
}
state = PRINT_S_CONV;
break;
case PRINT_S_CONV:
switch (ch) {
case 'd':
/* FALLTHROUGH */
case 'i':
switch (cflags) {
case PRINT_C_CHAR:
value = (signed char)va_arg(args, int);
break;
case PRINT_C_SHORT:
value = (short int)va_arg(args, int);
break;
case PRINT_C_LONG:
value = va_arg(args, long int);
break;
case PRINT_C_LLONG:
value = va_arg(args, LLONG);
break;
case PRINT_C_SIZE:
value = va_arg(args, SSIZE_T);
break;
case PRINT_C_INTMAX:
value = va_arg(args, INTMAX_T);
break;
case PRINT_C_PTRDIFF:
value = va_arg(args, PTRDIFF_T);
break;
default:
value = va_arg(args, int);
break;
}
fmtint(str, &len, size, value, 10, width, precision,
flags);
break;
case 'X':
flags |= PRINT_F_UP;
/* FALLTHROUGH */
case 'x':
base = 16;
/* FALLTHROUGH */
case 'o':
if (base == 0)
base = 8;
/* FALLTHROUGH */
case 'u':
if (base == 0)
base = 10;
flags |= PRINT_F_UNSIGNED;
switch (cflags) {
case PRINT_C_CHAR:
value =
(unsigned char)va_arg(args, unsigned int);
break;
case PRINT_C_SHORT:
value = (unsigned short int)va_arg(
args, unsigned int);
break;
case PRINT_C_LONG:
value = va_arg(args, unsigned long int);
break;
case PRINT_C_LLONG:
value = va_arg(args, ULLONG);
break;
case PRINT_C_SIZE:
value = va_arg(args, size_t);
break;
case PRINT_C_INTMAX:
value = va_arg(args, UINTMAX_T);
break;
case PRINT_C_PTRDIFF:
value = va_arg(args, UPTRDIFF_T);
break;
default:
value = va_arg(args, unsigned int);
break;
}
fmtint(str, &len, size, value, base, width, precision,
flags);
break;
case 'c':
cvalue = va_arg(args, int);
OUTCHAR(str, len, size, cvalue);
break;
case 's':
strvalue = va_arg(args, char *);
fmtstr(str, &len, size, strvalue, width, precision,
flags);
break;
case 'p':
/*
* C99 says: "The value of the pointer is
* converted to a sequence of printing
* characters, in an implementation-defined
* manner." (C99: 7.19.6.1, 8)
*/
if ((strvalue = va_arg(args, void *)) == NULL)
/*
* We use the glibc format. BSD prints
* "0x0", SysV "0".
*/
fmtstr(str, &len, size, "(nil)", width, -1, flags);
else {
/*
* We use the BSD/glibc format. SysV
* omits the "0x" prefix (which we emit
* using the PRINT_F_NUM flag).
*/
flags |= PRINT_F_NUM;
flags |= PRINT_F_UNSIGNED;
fmtint(str, &len, size, (UINTPTR_T)strvalue, 16,
width, precision, flags);
}
break;
case 'n':
switch (cflags) {
case PRINT_C_CHAR:
charptr = va_arg(args, signed char *);
*charptr = len;
break;
case PRINT_C_SHORT:
shortptr = va_arg(args, short int *);
*shortptr = len;
break;
case PRINT_C_LONG:
longptr = va_arg(args, long int *);
*longptr = len;
break;
case PRINT_C_LLONG:
llongptr = va_arg(args, LLONG *);
*llongptr = len;
break;
case PRINT_C_SIZE:
/*
* C99 says that with the "z" length
* modifier, "a following `n' conversion
* specifier applies to a pointer to a
* signed integer type corresponding to
* size_t argument." (7.19.6.1, 7)
*/
sizeptr = va_arg(args, SSIZE_T *);
*sizeptr = len;
break;
case PRINT_C_INTMAX:
intmaxptr = va_arg(args, INTMAX_T *);
*intmaxptr = len;
break;
case PRINT_C_PTRDIFF:
ptrdiffptr = va_arg(args, PTRDIFF_T *);
*ptrdiffptr = len;
break;
default:
intptr = va_arg(args, int *);
*intptr = len;
break;
}
break;
case '%': /* Print a "%" character verbatim. */
OUTCHAR(str, len, size, ch);
break;
default: /* Skip other characters. */
break;
}
ch = *format++;
state = PRINT_S_DEFAULT;
base = cflags = flags = width = 0;
precision = -1;
break;
}
out:
if (len < size)
str[len] = '\0';
else if (size > 0)
str[size - 1] = '\0';
if (overflow || len >= INT_MAX) {
return -1;
}
return (int)len;
}
static void fmtstr(char *str, size_t *len, size_t size, const char *value,
int width, int precision, int flags)
{
int padlen, strln; /* Amount to pad. */
int noprecision = (precision == -1);
if (value == NULL) /* We're forgiving. */
value = "(null)";
/* If a precision was specified, don't read the string past it. */
for (strln = 0; value[strln] != '\0' && (noprecision || strln < precision);
strln++)
continue;
if ((padlen = width - strln) < 0)
padlen = 0;
if (flags & PRINT_F_MINUS) /* Left justify. */
padlen = -padlen;
while (padlen > 0) { /* Leading spaces. */
OUTCHAR(str, *len, size, ' ');
padlen--;
}
while (*value != '\0' && (noprecision || precision-- > 0)) {
OUTCHAR(str, *len, size, *value);
value++;
}
while (padlen < 0) { /* Trailing spaces. */
OUTCHAR(str, *len, size, ' ');
padlen++;
}
}
static void fmtint(char *str, size_t *len, size_t size, INTMAX_T value,
int base, int width, int precision, int flags)
{
UINTMAX_T uvalue;
char iconvert[MAX_CONVERT_LENGTH];
char sign = 0;
char hexprefix = 0;
int spadlen = 0; /* Amount to space pad. */
int zpadlen = 0; /* Amount to zero pad. */
int pos;
int separators = (flags & PRINT_F_QUOTE);
int noprecision = (precision == -1);
if (flags & PRINT_F_UNSIGNED)
uvalue = value;
else {
uvalue = (value >= 0) ? value : -value;
if (value < 0)
sign = '-';
else if (flags & PRINT_F_PLUS) /* Do a sign. */
sign = '+';
else if (flags & PRINT_F_SPACE)
sign = ' ';
}
pos = convert(uvalue, iconvert, sizeof(iconvert), base, flags & PRINT_F_UP);
if (flags & PRINT_F_NUM && uvalue != 0) {
/*
* C99 says: "The result is converted to an `alternative form'.
* For `o' conversion, it increases the precision, if and only
* if necessary, to force the first digit of the result to be a
* zero (if the value and precision are both 0, a single 0 is
* printed). For `x' (or `X') conversion, a nonzero result has
* `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
*/
switch (base) {
case 8:
if (precision <= pos)
precision = pos + 1;
break;
case 16:
hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
break;
}
}
if (separators) /* Get the number of group separators we'll print. */
separators = getnumsep(pos);
zpadlen = precision - pos - separators;
spadlen = width /* Minimum field width. */
- separators /* Number of separators. */
- MAX(precision, pos) /* Number of integer digits. */
- ((sign != 0) ? 1 : 0) /* Will we print a sign? */
- ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */
if (zpadlen < 0)
zpadlen = 0;
if (spadlen < 0)
spadlen = 0;
/*
* C99 says: "If the `0' and `-' flags both appear, the `0' flag is
* ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a
* precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
*/
if (flags & PRINT_F_MINUS) /* Left justify. */
spadlen = -spadlen;
else if (flags & PRINT_F_ZERO && noprecision) {
zpadlen += spadlen;
spadlen = 0;
}
while (spadlen > 0) { /* Leading spaces. */
OUTCHAR(str, *len, size, ' ');
spadlen--;
}
if (sign != 0) /* Sign. */
OUTCHAR(str, *len, size, sign);
if (hexprefix != 0) { /* A "0x" or "0X" prefix. */
OUTCHAR(str, *len, size, '0');
OUTCHAR(str, *len, size, hexprefix);
}
while (zpadlen > 0) { /* Leading zeros. */
OUTCHAR(str, *len, size, '0');
zpadlen--;
}
while (pos > 0) { /* The actual digits. */
pos--;
OUTCHAR(str, *len, size, iconvert[pos]);
if (separators > 0 && pos > 0 && pos % 3 == 0)
printsep(str, len, size);
}
while (spadlen < 0) { /* Trailing spaces. */
OUTCHAR(str, *len, size, ' ');
spadlen++;
}
}
static void printsep(char *str, size_t *len, size_t size)
{
OUTCHAR(str, *len, size, ',');
}
static int getnumsep(int digits)
{
int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
return separators;
}
static int convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
{
const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
size_t pos = 0;
/* We return an unterminated buffer with the digits in reverse order. */
do {
buf[pos++] = digits[value % base];
value /= base;
} while (value != 0 && pos < size);
return (int)pos;
}
int vsprintf(char *buf, const char *fmt, va_list args)
{
return vsnprintf(buf, INT_MAX, fmt, args);
}

11
src/vsprintf.h Normal file
View file

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: MIT */
#ifndef VSPRINTF_H
#define VSPRINTF_H
#include <stdarg.h>
int vsprintf(char *buf, const char *fmt, va_list args);
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
#endif

35
src/xnuboot.h Normal file
View file

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: MIT */
#ifndef XNUBOOT_H
#define XNUBOOT_H
#define CMDLINE_LENGTH 608
struct boot_video {
u64 base;
u64 display;
u64 stride;
u64 width;
u64 height;
u64 depth;
};
struct boot_args {
u16 revision;
u16 version;
u64 virt_base;
u64 phys_base;
u64 mem_size;
u64 top_of_kernel_data;
struct boot_video video;
u32 machine_type;
void *devtree;
u32 devtree_size;
char cmdline[CMDLINE_LENGTH];
u64 boot_flags;
u64 mem_size_actual;
};
extern struct boot_args cur_boot_args;
#endif