Meaty Skeleton: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
Remove -fbuiltin from the Makefiles
Modernize Meaty Skeleton to my 2016 taste. See talk page section 2016-09-02 Changes for the full summary of changes.
Line 208: Line 208:


Check for differences between the git revision used in this article and what you cloned (empty output is no difference):
Check for differences between the git revision used in this article and what you cloned (empty output is no difference):

<source lang="bash">
<source lang="bash">
git diff 3941087c7674ed9b3a3a936670b72e35c6749629..master
git diff 084d1624bedaa9f9e395f055c6bd99299bd97f58..master
</source>
</source>


Line 216: Line 215:


=== kernel ===
=== kernel ===

==== kernel/include/kernel/vga.h ====

<source lang="c">
#ifndef _KERNEL_VGA_H
#define _KERNEL_VGA_H

#include <stdint.h>

enum vga_color
{
COLOR_BLACK = 0,
COLOR_BLUE = 1,
COLOR_GREEN = 2,
COLOR_CYAN = 3,
COLOR_RED = 4,
COLOR_MAGENTA = 5,
COLOR_BROWN = 6,
COLOR_LIGHT_GREY = 7,
COLOR_DARK_GREY = 8,
COLOR_LIGHT_BLUE = 9,
COLOR_LIGHT_GREEN = 10,
COLOR_LIGHT_CYAN = 11,
COLOR_LIGHT_RED = 12,
COLOR_LIGHT_MAGENTA = 13,
COLOR_LIGHT_BROWN = 14,
COLOR_WHITE = 15,
};

static inline uint8_t make_color(enum vga_color fg, enum vga_color bg)
{
return fg | bg << 4;
}

static inline uint16_t make_vgaentry(char c, uint8_t color)
{
uint16_t c16 = c;
uint16_t color16 = color;
return c16 | color16 << 8;
}

static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;

static uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000;

#endif
</source>


==== kernel/include/kernel/tty.h ====
==== kernel/include/kernel/tty.h ====
Line 284: Line 235:


<source lang="make">
<source lang="make">
HOST?=$(shell ../default-host.sh)
DEFAULT_HOST!=../default-host.sh
HOST?=DEFAULT_HOST
HOSTARCH:=$(shell ../target-triplet-to-arch.sh $(HOST))
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)


CFLAGS?=-O2 -g
CFLAGS?=-O2 -g
Line 299: Line 251:


CFLAGS:=$(CFLAGS) -ffreestanding -Wall -Wextra
CFLAGS:=$(CFLAGS) -ffreestanding -Wall -Wextra
CPPFLAGS:=$(CPPFLAGS) -D__is_myos_kernel -Iinclude
CPPFLAGS:=$(CPPFLAGS) -D__is_kernel -Iinclude
LDFLAGS:=$(LDFLAGS)
LDFLAGS:=$(LDFLAGS)
LIBS:=$(LIBS) -nostdlib -lk -lgcc
LIBS:=$(LIBS) -nostdlib -lk -lgcc


ARCHDIR:=arch/$(HOSTARCH)
ARCHDIR=arch/$(HOSTARCH)


include $(ARCHDIR)/make.config
include $(ARCHDIR)/make.config
Line 312: Line 264:
LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)
LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)


KERNEL_OBJS=\
OBJS:=\
$(KERNEL_ARCH_OBJS) \
$(KERNEL_ARCH_OBJS) \
kernel/kernel.o \
kernel/kernel.o \


OBJS=\
CRTI_OBJ:=$(ARCHDIR)/crti.o
$(ARCHDIR)/crti.o \
CRTBEGIN_OBJ:=$(shell $(CC) $(CFLAGS) $(LDFLAGS) -print-file-name=crtbegin.o)
$(ARCHDIR)/crtbegin.o \
CRTEND_OBJ:=$(shell $(CC) $(CFLAGS) $(LDFLAGS) -print-file-name=crtend.o)
$(KERNEL_OBJS) \
CRTN_OBJ:=$(ARCHDIR)/crtn.o
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \


LINK_LIST=\
ALL_OUR_OBJS:=\
$(CRTI_OBJ) \
$(LDFLAGS) \
$(OBJS) \
$(ARCHDIR)/crti.o \
$(CRTN_OBJ) \
$(ARCHDIR)/crtbegin.o \
$(KERNEL_OBJS) \
$(LIBS) \
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \


.PHONY: all clean install install-headers install-kernel
OBJ_LINK_LIST:=\
.SUFFIXES: .o .c .S
$(CRTI_OBJ) \
$(CRTBEGIN_OBJ) \
$(OBJS) \
$(CRTEND_OBJ) \
$(CRTN_OBJ) \


all: myos.kernel
all: myos.kernel


myos.kernel: $(OBJS) $(ARCHDIR)/linker.ld
.PHONY: all clean install install-headers install-kernel
$(CC) -T $(ARCHDIR)/linker.ld -o $@ $(CFLAGS) $(LINK_LIST)
grub-file --is-x86-multiboot myos.kernel


myos.kernel: $(OBJ_LINK_LIST) $(ARCHDIR)/linker.ld
$(ARCHDIR)/crtbegin.o $(ARCHDIR)/crtend.o:
OBJ=`$(CC) $(CFLAGS) $(LDFLAGS) -print-file-name=$(@F)` && cp "$$OBJ" $@
$(CC) -T $(ARCHDIR)/linker.ld -o $@ $(CFLAGS) $(OBJ_LINK_LIST) $(LDFLAGS) $(LIBS)


%.o: %.c
.c.o:
$(CC) -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)
$(CC) -MD -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)


%.o: %.S
.S.o:
$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
$(CC) -MD -c $< -o $@ $(CFLAGS) $(CPPFLAGS)


clean:
clean:
rm -f myos.kernel $(OBJS) $(ALL_OUR_OBJS) *.o */*.o */*/*.o
rm -f myos.kernel
rm -f $(OBJS) *.o */*.o */*/*.o
rm -f $(OBJS:.o=.d) *.d */*.d */*/*.d


install: install-headers install-kernel
install: install-headers install-kernel
Line 353: Line 311:
install-headers:
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -RTv include $(DESTDIR)$(INCLUDEDIR)
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.


install-kernel: myos.kernel
install-kernel: myos.kernel
mkdir -p $(DESTDIR)$(BOOTDIR)
mkdir -p $(DESTDIR)$(BOOTDIR)
cp myos.kernel $(DESTDIR)$(BOOTDIR)
cp myos.kernel $(DESTDIR)$(BOOTDIR)

-include $(OBJS:.o=.d)
</source>
</source>


Line 363: Line 323:


<source lang="c">
<source lang="c">
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdio.h>


#include <kernel/tty.h>
#include <kernel/tty.h>


void kernel_early(void)
void kernel_main(void) {
{
terminal_initialize();
terminal_initialize();
}

void kernel_main(void)
{
printf("Hello, kernel World!\n");
printf("Hello, kernel World!\n");
}
}
Line 390: Line 342:


#include <kernel/tty.h>
#include <kernel/tty.h>
#include <kernel/vga.h>


#include "vga.h"
size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer;


static const size_t VGA_WIDTH = 80;
void terminal_initialize(void)
static const size_t VGA_HEIGHT = 25;
{
static uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000;

static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_color;
static uint16_t* terminal_buffer;

void terminal_initialize(void) {
terminal_row = 0;
terminal_row = 0;
terminal_column = 0;
terminal_column = 0;
terminal_color = make_color(COLOR_LIGHT_GREY, COLOR_BLACK);
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
terminal_buffer = VGA_MEMORY;
terminal_buffer = VGA_MEMORY;
for ( size_t y = 0; y < VGA_HEIGHT; y++ )
for (size_t y = 0; y < VGA_HEIGHT; y++) {
for (size_t x = 0; x < VGA_WIDTH; x++) {
{
for ( size_t x = 0; x < VGA_WIDTH; x++ )
{
const size_t index = y * VGA_WIDTH + x;
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = make_vgaentry(' ', terminal_color);
terminal_buffer[index] = vga_entry(' ', terminal_color);
}
}
}
}
}
}


void terminal_setcolor(uint8_t color)
void terminal_setcolor(uint8_t color) {
{
terminal_color = color;
terminal_color = color;
}
}


void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y) {
{
const size_t index = y * VGA_WIDTH + x;
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = make_vgaentry(c, color);
terminal_buffer[index] = vga_entry(c, color);
}
}


void terminal_putchar(char c)
void terminal_putchar(char c) {
unsigned char uc = c;
{
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
terminal_putentryat(uc, terminal_color, terminal_column, terminal_row);
if ( ++terminal_column == VGA_WIDTH )
if (++terminal_column == VGA_WIDTH) {
{
terminal_column = 0;
terminal_column = 0;
if ( ++terminal_row == VGA_HEIGHT )
if (++terminal_row == VGA_HEIGHT)
{
terminal_row = 0;
terminal_row = 0;
}
}
}
}
}


void terminal_write(const char* data, size_t size)
void terminal_write(const char* data, size_t size) {
for (size_t i = 0; i < size; i++)
{
for ( size_t i = 0; i < size; i++ )
terminal_putchar(data[i]);
terminal_putchar(data[i]);
}
}


void terminal_writestring(const char* data)
void terminal_writestring(const char* data) {
{
terminal_write(data, strlen(data));
terminal_write(data, strlen(data));
}
}
Line 462: Line 409:
ret
ret
</pre>
</pre>

==== kernel/arch/i386/vga.h ====

<source lang="c">
#ifndef ARCH_I386_VGA_H
#define ARCH_I386_VGA_H

#include <stdint.h>

enum vga_color {
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
};

static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
return fg | bg << 4;
}

static inline uint16_t vga_entry(unsigned char uc, uint8_t color) {
return (uint16_t) uc | (uint16_t) color << 8;
}

#endif
</source>


==== kernel/arch/i386/make.config ====
==== kernel/arch/i386/make.config ====


<source lang="make">
<source lang="make">
KERNEL_ARCH_CFLAGS:=
KERNEL_ARCH_CFLAGS=
KERNEL_ARCH_CPPFLAGS:=
KERNEL_ARCH_CPPFLAGS=
KERNEL_ARCH_LDFLAGS:=
KERNEL_ARCH_LDFLAGS=
KERNEL_ARCH_LIBS:=
KERNEL_ARCH_LIBS=


KERNEL_ARCH_OBJS:=\
KERNEL_ARCH_OBJS=\
$(ARCHDIR)/boot.o \
$(ARCHDIR)/boot.o \
$(ARCHDIR)/tty.o \
$(ARCHDIR)/tty.o \
Line 537: Line 522:
*(COMMON)
*(COMMON)
*(.bss)
*(.bss)
*(.bootstrap_stack)
}
}


Line 548: Line 532:


<pre>
<pre>
# Declare constants used for creating a multiboot header.
# Declare constants for the multiboot header.
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set MEMINFO, 1<<1 # provide memory map
.set MEMINFO, 1<<1 # provide memory map
Line 563: Line 547:


# Reserve a stack for the initial thread.
# Reserve a stack for the initial thread.
.section .bootstrap_stack, "aw", @nobits
.section .bss
.align 16
stack_bottom:
stack_bottom:
.skip 16384 # 16 KiB
.skip 16384 # 16 KiB
Line 574: Line 559:
_start:
_start:
movl $stack_top, %esp
movl $stack_top, %esp

# Initialize the core kernel before running the global constructors.
call kernel_early


# Call the global constructors.
# Call the global constructors.
Line 586: Line 568:
# Hang if kernel_main unexpectedly returns.
# Hang if kernel_main unexpectedly returns.
cli
cli
1: hlt
.Lhang:
jmp 1b
hlt
jmp .Lhang
.size _start, . - _start
.size _start, . - _start
</pre>
</pre>
Line 595: Line 576:


<pre>
<pre>
*.o
*.d
*.kernel
*.kernel
*.o
</pre>
</pre>


Line 635: Line 617:


#include <sys/cdefs.h>
#include <sys/cdefs.h>

#define EOF (-1)


#ifdef __cplusplus
#ifdef __cplusplus
Line 687: Line 671:


<source lang="make">
<source lang="make">
HOST?=$(shell ../default-host.sh)
DEFAULT_HOST!=../default-host.sh
HOST?=DEFAULT_HOST
HOSTARCH:=$(shell ../target-triplet-to-arch.sh $(HOST))
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)


CFLAGS?=-O2 -g
CFLAGS?=-O2 -g
Line 701: Line 686:
LIBDIR?=$(EXEC_PREFIX)/lib
LIBDIR?=$(EXEC_PREFIX)/lib


CFLAGS:=$(CFLAGS) -Wall -Wextra
CFLAGS:=$(CFLAGS) -ffreestanding -Wall -Wextra
CPPFLAGS:=$(CPPFLAGS) -D__is_myos_libc -Iinclude
CPPFLAGS:=$(CPPFLAGS) -D__is_libc -Iinclude
LIBK_CFLAGS:=$(CFLAGS) -ffreestanding
LIBK_CFLAGS:=$(CFLAGS)
LIBK_CPPFLAGS:=$(CPPFLAGS) -D__is_myos_kernel
LIBK_CPPFLAGS:=$(CPPFLAGS) -D__is_libk


ARCHDIR:=arch/$(HOSTARCH)
ARCHDIR=arch/$(HOSTARCH)


include $(ARCHDIR)/make.config
include $(ARCHDIR)/make.config
Line 715: Line 700:
LIBK_CPPFLAGS:=$(LIBK_CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)
LIBK_CPPFLAGS:=$(LIBK_CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)


FREEOBJS:=\
FREEOBJS=\
$(ARCH_FREEOBJS) \
$(ARCH_FREEOBJS) \
stdio/printf.o \
stdio/printf.o \
Line 727: Line 712:
string/strlen.o \
string/strlen.o \


HOSTEDOBJS:=\
HOSTEDOBJS=\
$(ARCH_HOSTEDOBJS) \
$(ARCH_HOSTEDOBJS) \


OBJS:=\
OBJS=\
$(FREEOBJS) \
$(FREEOBJS) \
$(HOSTEDOBJS) \
$(HOSTEDOBJS) \


LIBK_OBJS:=$(FREEOBJS:.o=.libk.o)
LIBK_OBJS=$(FREEOBJS:.o=.libk.o)


BINARIES=libc.a libg.a libk.a
#BINARIES=libc.a libk.a # Not ready for libc yet.
BINARIES=libk.a

all: $(BINARIES)


.PHONY: all clean install install-headers install-libs
.PHONY: all clean install install-headers install-libs
.SUFFIXES: .o .libk.o .c .S

all: $(BINARIES)


libc.a: $(OBJS)
libc.a: $(OBJS)
$(AR) rcs $@ $(OBJS)
$(AR) rcs $@ $(OBJS)

libg.a:
$(AR) rcs $@


libk.a: $(LIBK_OBJS)
libk.a: $(LIBK_OBJS)
$(AR) rcs $@ $(LIBK_OBJS)
$(AR) rcs $@ $(LIBK_OBJS)


%.o: %.c
.c.o:
$(CC) -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)
$(CC) -MD -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)


%.o: %.S
.c.S:
$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
$(CC) -MD -c $< -o $@ $(CFLAGS) $(CPPFLAGS)


%.libk.o: %.c
.c.libk.o:
$(CC) -c $< -o $@ -std=gnu11 $(LIBK_CFLAGS) $(LIBK_CPPFLAGS)
$(CC) -MD -c $< -o $@ -std=gnu11 $(LIBK_CFLAGS) $(LIBK_CPPFLAGS)


%.libk.o: %.S
.S.libk.o:
$(CC) -c $< -o $@ $(LIBK_CFLAGS) $(LIBK_CPPFLAGS)
$(CC) -MD -c $< -o $@ $(LIBK_CFLAGS) $(LIBK_CPPFLAGS)


clean:
clean:
rm -f $(BINARIES) $(OBJS) $(LIBK_OBJS) *.o */*.o */*/*.o
rm -f $(BINARIES) *.a
rm -f $(OBJS) $(LIBK_OBJS) *.o */*.o */*/*.o
rm -f $(OBJS:.o=.d) $(LIBK_OBJS:.o=.d) *.d */*.d */*/*.d


install: install-headers install-libs
install: install-headers install-libs
Line 770: Line 756:
install-headers:
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -RTv include $(DESTDIR)$(INCLUDEDIR)
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.


install-libs: $(BINARIES)
install-libs: $(BINARIES)
mkdir -p $(DESTDIR)$(LIBDIR)
mkdir -p $(DESTDIR)$(LIBDIR)
cp $(BINARIES) $(DESTDIR)$(LIBDIR)
cp $(BINARIES) $(DESTDIR)$(LIBDIR)

-include $(OBJS:.o=.d)
-include $(LIBK_OBJS:.o=.d)
</source>
</source>


Line 784: Line 773:


__attribute__((__noreturn__))
__attribute__((__noreturn__))
void abort(void)
void abort(void) {
#if defined(__is_libk)
{
// TODO: Add proper kernel panic.
// TODO: Add proper kernel panic.
printf("Kernel Panic: abort()\n");
printf("kernel: panic: abort()\n");
#else
while ( 1 ) { }
// TODO: Abnormally terminate the process as if by SIGABRT.
printf("abort()\n");
#endif
while (1) { }
__builtin_unreachable();
__builtin_unreachable();
}
}
Line 798: Line 791:
#include <string.h>
#include <string.h>


void* memmove(void* dstptr, const void* srcptr, size_t size)
void* memmove(void* dstptr, const void* srcptr, size_t size) {
{
unsigned char* dst = (unsigned char*) dstptr;
unsigned char* dst = (unsigned char*) dstptr;
const unsigned char* src = (const unsigned char*) srcptr;
const unsigned char* src = (const unsigned char*) srcptr;
if ( dst < src )
if (dst < src) {
for ( size_t i = 0; i < size; i++ )
for (size_t i = 0; i < size; i++)
dst[i] = src[i];
dst[i] = src[i];
else
} else {
for ( size_t i = size; i != 0; i-- )
for (size_t i = size; i != 0; i--)
dst[i-1] = src[i-1];
dst[i-1] = src[i-1];
}
return dstptr;
return dstptr;
}
}
Line 817: Line 810:
#include <string.h>
#include <string.h>


size_t strlen(const char* string)
size_t strlen(const char* str) {
size_t len = 0;
{
while (str[len])
size_t result = 0;
len++;
while ( string[result] )
return len;
result++;
return result;
}
}
</source>
</source>
Line 831: Line 823:
#include <string.h>
#include <string.h>


int memcmp(const void* aptr, const void* bptr, size_t size)
int memcmp(const void* aptr, const void* bptr, size_t size) {
{
const unsigned char* a = (const unsigned char*) aptr;
const unsigned char* a = (const unsigned char*) aptr;
const unsigned char* b = (const unsigned char*) bptr;
const unsigned char* b = (const unsigned char*) bptr;
for ( size_t i = 0; i < size; i++ )
for (size_t i = 0; i < size; i++) {
if ( a[i] < b[i] )
if (a[i] < b[i])
return -1;
return -1;
else if ( b[i] < a[i] )
else if (b[i] < a[i])
return 1;
return 1;
}
return 0;
return 0;
}
}
Line 849: Line 841:
#include <string.h>
#include <string.h>


void* memset(void* bufptr, int value, size_t size)
void* memset(void* bufptr, int value, size_t size) {
{
unsigned char* buf = (unsigned char*) bufptr;
unsigned char* buf = (unsigned char*) bufptr;
for ( size_t i = 0; i < size; i++ )
for (size_t i = 0; i < size; i++)
buf[i] = (unsigned char) value;
buf[i] = (unsigned char) value;
return bufptr;
return bufptr;
Line 863: Line 854:
#include <string.h>
#include <string.h>


void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size)
void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) {
{
unsigned char* dst = (unsigned char*) dstptr;
unsigned char* dst = (unsigned char*) dstptr;
const unsigned char* src = (const unsigned char*) srcptr;
const unsigned char* src = (const unsigned char*) srcptr;
for ( size_t i = 0; i < size; i++ )
for (size_t i = 0; i < size; i++)
dst[i] = src[i];
dst[i] = src[i];
return dstptr;
return dstptr;
Line 878: Line 868:
#include <stdio.h>
#include <stdio.h>


int puts(const char* string)
int puts(const char* string) {
{
return printf("%s\n", string);
return printf("%s\n", string);
}
}
Line 889: Line 878:
#include <stdio.h>
#include <stdio.h>


#if defined(__is_myos_kernel)
#if defined(__is_libk)
#include <kernel/tty.h>
#include <kernel/tty.h>
#endif
#endif


int putchar(int ic)
int putchar(int ic) {
#if defined(__is_libk)
{
#if defined(__is_myos_kernel)
char c = (char) ic;
char c = (char) ic;
terminal_write(&c, sizeof(c));
terminal_write(&c, sizeof(c));
#else
#else
// TODO: You need to implement a write system call.
// TODO: Implement stdio and the write system call.
#endif
#endif
return ic;
return ic;
Line 908: Line 896:


<source lang="c">
<source lang="c">
#include <limits.h>
#include <stdbool.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stdarg.h>
Line 913: Line 902:
#include <string.h>
#include <string.h>


static void print(const char* data, size_t data_length)
static bool print(const char* data, size_t length) {
const unsigned char* bytes = (const unsigned char*) data;
{
for ( size_t i = 0; i < data_length; i++ )
for (size_t i = 0; i < length; i++)
if (putchar(bytes[i]) == EOF)
putchar((int) ((const unsigned char*) data)[i]);
return false;
return true;
}
}


int printf(const char* restrict format, ...)
int printf(const char* restrict format, ...) {
{
va_list parameters;
va_list parameters;
va_start(parameters, format);
va_start(parameters, format);


int written = 0;
int written = 0;
size_t amount;
bool rejected_bad_specifier = false;


while ( *format != '\0' )
while (*format != '\0') {
size_t maxrem = INT_MAX - written;
{

if ( *format != '%' )
if (format[0] != '%' || format[1] == '%') {
{
if (format[0] == '%')
print_c:
amount = 1;
format++;
while ( format[amount] && format[amount] != '%' )
size_t amount = 1;
while (format[amount] && format[amount] != '%')
amount++;
amount++;
print(format, amount);
if (maxrem < amount) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, amount))
return -1;
format += amount;
format += amount;
written += amount;
written += amount;
Line 942: Line 936:
}
}


const char* format_begun_at = format;
const char* format_begun_at = format++;


if ( *(++format) == '%' )
if (*format == 'c') {
goto print_c;

if ( rejected_bad_specifier )
{
incomprehensible_conversion:
rejected_bad_specifier = true;
format = format_begun_at;
goto print_c;
}

if ( *format == 'c' )
{
format++;
format++;
char c = (char) va_arg(parameters, int /* char promotes to int */);
char c = (char) va_arg(parameters, int /* char promotes to int */);
if (!maxrem) {
print(&c, sizeof(c));
// TODO: Set errno to EOVERFLOW.
}
return -1;
else if ( *format == 's' )
{
}
if (!print(&c, sizeof(c)))
return -1;
written++;
} else if (*format == 's') {
format++;
format++;
const char* s = va_arg(parameters, const char*);
const char* str = va_arg(parameters, const char*);
print(s, strlen(s));
size_t len = strlen(str);
if (maxrem < len) {
}
// TODO: Set errno to EOVERFLOW.
else
return -1;
{
}
goto incomprehensible_conversion;
if (!print(str, len))
return -1;
written += len;
} else {
format = format_begun_at;
size_t len = strlen(format);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, len))
return -1;
written += len;
format += len;
}
}
}
}


va_end(parameters);
va_end(parameters);

return written;
return written;
}
}
Line 982: Line 981:


<source lang="make">
<source lang="make">
ARCH_CFLAGS:=
ARCH_CFLAGS=
ARCH_CPPFLAGS:=
ARCH_CPPFLAGS=
KERNEL_ARCH_CFLAGS:=
KERNEL_ARCH_CFLAGS=
KERNEL_ARCH_CPPFLAGS:=
KERNEL_ARCH_CPPFLAGS=


ARCH_FREEOBJS:=\
ARCH_FREEOBJS=\


ARCH_HOSTEDOBJS:=\
ARCH_HOSTEDOBJS=\
</source>
</source>


Line 995: Line 994:


<pre>
<pre>
*.o
*.a
*.a
*.d
*.o
</pre>
</pre>


Line 1,011: Line 1,011:


for PROJECT in $PROJECTS; do
for PROJECT in $PROJECTS; do
DESTDIR="$PWD/sysroot" $MAKE -C $PROJECT install
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install)
done
done
</source>
</source>
Line 1,028: Line 1,028:


for PROJECT in $PROJECTS; do
for PROJECT in $PROJECTS; do
$MAKE -C $PROJECT clean
(cd $PROJECT && $MAKE clean)
done
done


rm -rfv sysroot
rm -rf sysroot
rm -rfv isodir
rm -rf isodir
rm -rfv myos.iso
rm -rf myos.iso
</source>
</source>


Line 1,064: Line 1,064:


# Configure the cross-compiler to use the desired system root.
# Configure the cross-compiler to use the desired system root.
export CC="$CC --sysroot=$PWD/sysroot"
export SYSROOT="$(pwd)/sysroot"
export CC="$CC --sysroot=$SYSROOT"


# Work around that the -elf gcc targets doesn't have a system include directory
# Work around that the -elf gcc targets doesn't have a system include directory
# because configure received --without-headers rather than --with-sysroot.
# because it was configured with --without-headers rather than --with-sysroot.
if echo "$HOST" | grep -Eq -- '-elf($|-)'; then
if echo "$HOST" | grep -Eq -- '-elf($|-)'; then
export CC="$CC -isystem=$INCLUDEDIR"
export CC="$CC -isystem=$INCLUDEDIR"
Line 1,092: Line 1,093:
. ./config.sh
. ./config.sh


mkdir -p sysroot
mkdir -p "$SYSROOT"


for PROJECT in $SYSTEM_HEADER_PROJECTS; do
for PROJECT in $SYSTEM_HEADER_PROJECTS; do
DESTDIR="$PWD/sysroot" $MAKE -C $PROJECT install-headers
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install-headers)
done
done
</source>
</source>