Meaty Skeleton: Difference between revisions
[unchecked revision] | [unchecked revision] |
Content deleted Content added
New section: Forum Posts |
No edit summary |
||
(13 intermediate revisions by 9 users not shown) | |||
Line 1:
{{FirstPerson}}
{{You}}
{{BeginnersWarning}}
{{Rating|1
{{Kernel designs}}
operating system in the [[Stan Dard]] style suitable for further modification or
as inspiration for your initial operating system version. The [[Bare Bones]]
tutorial only gives you the absolutely minimal code to demonstrate how to
correctly cross-compile a kernel, however this is unsuitable as an example
operating system. Additionally, this tutorial implements neccesary ABI features
needed to satisfy the ABI and compiler contracts to prevent possible mysterious
errors.
This tutorial also serves as the initial template tutorial on how to
Line 50 ⟶ 53:
== Building a Cross-Compiler ==
You ''must'' use a [[GCC Cross-Compiler]] in this tutorial as in the
Line 98 ⟶ 101:
<tt>sysroot/boot</tt> directory.
We already use system roots
The <tt>-elf</tt> targets have no user-space and are incapable of having one. We configured the compiler with system root support, so it will look in <tt>${SYSROOT}/usr/lib</tt> as expected. We prevented the compiler from searching for a standard library using the --without-headers option when building <tt>i686-elf-gcc</tt>, so it will ''not'' look in <tt>${SYSROOT}/usr/include</tt>. (Once you add a user-space and a libc, you will configure your custom cross-gcc with <tt>--with-sysroot</tt> and it will look in <tt>${SYSROOT}/usr/include</tt>. As a temporary work-around until you get that far, we fix it by passing <tt>-isystem=/usr/include</tt>).
Line 111 ⟶ 114:
provide the compiler a copy of your headers before you actually compile your
system. You will [[Hosted_GCC_Cross-Compiler#Sysroot_Headers|need to provide the
standard library headers]] when you
future that is capable of an user-space.
Note how your cross-compiler comes with a number of fully freestanding headers
Line 127 ⟶ 130:
are used, while a default is used if the user has no opinion. The makefiles also
make sure that particular options are always in CFLAGS. This is done by having
two phases in the makefiles: one that
mandatory options the project makefile requires:
<
# Default CFLAGS:
CFLAGS?=-O2 -g
Line 136 ⟶ 139:
# Add mandatory options to CFLAGS:
CFLAGS:=$(CFLAGS) -Wall -Wextra
</syntaxhighlight>
== Architecture Directories ==
Line 220 ⟶ 223:
--->
You can easily download the source code using [[Git]] from the [https://gitlab.com/sortie/meaty-skeleton Meaty Skeleton Git repository]. This is preferable to doing a manual error-prone copy, as you may make a mistake or whitespace
<
git clone https://gitlab.com/sortie/meaty-skeleton.git
</syntaxhighlight>
Check for differences between the git revision used in this article and what you cloned (empty output means there is no difference):
<
git diff 084d1624bedaa9f9e395f055c6bd99299bd97f58..master
</syntaxhighlight>
Operating systems development is about being an expert. Take the time to read the code carefully through and understand it. Please seek further information and help if you don't understand aspects of it. This code is minimal and almost everything is done deliberately, often to pre-emptively solve future problems.
Line 237 ⟶ 240:
==== kernel/include/kernel/tty.h ====
<
#ifndef _KERNEL_TTY_H
#define _KERNEL_TTY_H
Line 249 ⟶ 252:
#endif
</syntaxhighlight>
==== kernel/Makefile ====
<
DEFAULT_HOST!=../default-host.sh
HOST?=DEFAULT_HOST
Line 337 ⟶ 340:
-include $(OBJS:.o=.d)
</syntaxhighlight>
==== kernel/kernel/kernel.c ====
<
#include <stdio.h>
Line 350 ⟶ 353:
printf("Hello, kernel World!\n");
}
</syntaxhighlight>
==== kernel/arch/i386/tty.c ====
<
#include <stdbool.h>
#include <stddef.h>
Line 393 ⟶ 396:
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = vga_entry(c, color);
}
void terminal_scroll(int line) {
int loop;
char c;
for(loop = line * (VGA_WIDTH * 2) + 0xB8000; loop < VGA_WIDTH * 2; loop++) {
c = *loop;
*(loop - (VGA_WIDTH * 2)) = c;
}
}
void terminal_delete_last_line() {
int x, *ptr;
for(x = 0; x < VGA_WIDTH * 2; x++) {
ptr = 0xB8000 + (VGA_WIDTH * 2) * (VGA_HEIGHT - 1) + x;
*ptr = 0;
}
}
void terminal_putchar(char c) {
int line;
unsigned char uc = c;
terminal_putentryat(uc, terminal_color, terminal_column, terminal_row);
if (++terminal_column == VGA_WIDTH) {
terminal_column = 0;
if (++terminal_row == VGA_HEIGHT)
{
for(line = 1; line <= VGA_HEIGHT - 1; line++)
{
terminal_scroll(line);
}
terminal_delete_last_line();
terminal_row = VGA_HEIGHT - 1;
}
}
}
Line 413 ⟶ 444:
terminal_write(data, strlen(data));
}
</syntaxhighlight>
==== kernel/arch/i386/crtn.S ====
Line 431 ⟶ 462:
==== kernel/arch/i386/vga.h ====
<
#ifndef ARCH_I386_VGA_H
#define ARCH_I386_VGA_H
Line 465 ⟶ 496:
#endif
</syntaxhighlight>
==== kernel/arch/i386/make.config ====
<
KERNEL_ARCH_CFLAGS=
KERNEL_ARCH_CPPFLAGS=
Line 478 ⟶ 509:
$(ARCHDIR)/boot.o \
$(ARCHDIR)/tty.o \
</syntaxhighlight>
==== kernel/arch/i386/crti.S ====
Line 604 ⟶ 635:
==== libc/include/string.h ====
<
#ifndef _STRING_H
#define _STRING_H 1
Line 627 ⟶ 658:
#endif
</syntaxhighlight>
==== libc/include/stdio.h ====
<
#ifndef _STDIO_H
#define _STDIO_H 1
Line 652 ⟶ 683:
#endif
</syntaxhighlight>
==== libc/include/sys/cdefs.h ====
<
#ifndef _SYS_CDEFS_H
#define _SYS_CDEFS_H 1
Line 663 ⟶ 694:
#endif
</syntaxhighlight>
==== libc/include/stdlib.h ====
<
#ifndef _STDLIB_H
#define _STDLIB_H 1
Line 685 ⟶ 716:
#endif
</syntaxhighlight>
==== libc/Makefile ====
<
DEFAULT_HOST!=../default-host.sh
HOST?=DEFAULT_HOST
Line 783 ⟶ 814:
-include $(OBJS:.o=.d)
-include $(LIBK_OBJS:.o=.d)
</syntaxhighlight>
==== libc/stdlib/abort.c ====
<
#include <stdio.h>
#include <stdlib.h>
Line 796 ⟶ 827:
// TODO: Add proper kernel panic.
printf("kernel: panic: abort()\n");
asm volatile("hlt");
#else
// TODO: Abnormally terminate the process as if by SIGABRT.
Line 803 ⟶ 835:
__builtin_unreachable();
}
</syntaxhighlight>
==== libc/string/memmove.c ====
<
#include <string.h>
Line 822 ⟶ 854:
return dstptr;
}
</syntaxhighlight>
==== libc/string/strlen.c ====
<
#include <string.h>
Line 835 ⟶ 867:
return len;
}
</syntaxhighlight>
==== libc/string/memcmp.c ====
<
#include <string.h>
Line 853 ⟶ 885:
return 0;
}
</syntaxhighlight>
==== libc/string/memset.c ====
<
#include <string.h>
Line 866 ⟶ 898:
return bufptr;
}
</syntaxhighlight>
==== libc/string/memcpy.c ====
<
#include <string.h>
Line 880 ⟶ 912:
return dstptr;
}
</syntaxhighlight>
==== libc/stdio/puts.c ====
<
#include <stdio.h>
Line 890 ⟶ 922:
return printf("%s\n", string);
}
</syntaxhighlight>
==== libc/stdio/putchar.c ====
<
#include <stdio.h>
Line 910 ⟶ 942:
return ic;
}
</syntaxhighlight>
==== libc/stdio/printf.c ====
<
#include <limits.h>
#include <stdbool.h>
Line 995 ⟶ 1,027:
return written;
}
</syntaxhighlight>
==== libc/arch/i386/make.config ====
<
ARCH_CFLAGS=
ARCH_CPPFLAGS=
Line 1,008 ⟶ 1,040:
ARCH_HOSTEDOBJS=\
</syntaxhighlight>
==== libc/.gitignore ====
Line 1,024 ⟶ 1,056:
==== build.sh ====
<
#!/bin/sh
set -e
Line 1,032 ⟶ 1,064:
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install)
done
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x build.sh
</syntaxhighlight>
==== clean.sh ====
<
#!/bin/sh
set -e
Line 1,053 ⟶ 1,085:
rm -rf isodir
rm -rf myos.iso
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x clean.sh
</syntaxhighlight>
==== config.sh ====
<
SYSTEM_HEADER_PROJECTS="libc kernel"
PROJECTS="libc kernel"
Line 1,091 ⟶ 1,123:
export CC="$CC -isystem=$INCLUDEDIR"
fi
</syntaxhighlight>
==== default-host.sh ====
<
#!/bin/sh
echo i686-elf
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x default-host.sh
</syntaxhighlight>
==== headers.sh ====
<
#!/bin/sh
set -e
Line 1,117 ⟶ 1,149:
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install-headers)
done
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x headers.sh
</syntaxhighlight>
==== iso.sh ====
<
#!/bin/sh
set -e
Line 1,142 ⟶ 1,174:
EOF
grub-mkrescue -o myos.iso isodir
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x iso.sh
</syntaxhighlight>
==== qemu.sh ====
<
#!/bin/sh
set -e
Line 1,157 ⟶ 1,189:
qemu-system-$(./target-triplet-to-arch.sh $HOST) -cdrom myos.iso
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x qemu.sh
</syntaxhighlight>
==== target-triplet-to-arch.sh ====
<
#!/bin/sh
if echo "$1" | grep -Eq 'i[[:digit:]]86-'; then
Line 1,173 ⟶ 1,205:
echo "$1" | grep -Eo '^[[:alnum:]_]*'
fi
</syntaxhighlight>
You should make this executable script executable by running:
<
chmod +x target-triplet-to-arch.sh
</syntaxhighlight>
==== .gitignore ====
Line 1,197 ⟶ 1,229:
the source tree by invoking:
<
./clean.sh
</syntaxhighlight>
You can install all the system headers into the system root without relying on
Line 1,205 ⟶ 1,237:
[[Hosted GCC Cross-Compiler]], by invoking:
<
./headers.sh
</syntaxhighlight>
You can build a bootable cdrom image of the operating system by invoking:
<
./iso.sh
</syntaxhighlight>
It's probably a good idea to create a quick ''build-and-then-launch'' short-cut
like used in this example to run the system in your favorite emulator quickly:
<
./qemu.sh
</syntaxhighlight>
== Troubleshooting ==
If you receive odd errors during the build, you may have made a mistake during manual copying, perhaps missed a file,
== Moving Forward ==
Line 1,265 ⟶ 1,297:
* [[topic:36584|A link error found & fixed]]
[[Category:
[[Category:C]]
|