SchOS/lib/glue.c
Nexoniarz a1c965da1e include: one folder per subsystem, and includes that name it
Sixty-five headers sat side by side in include/, so `#include "irq.h"`
said nothing about where irq.h was or what it belonged to, and errno.h,
stat.h and fcntl.h at the top shadowed the system's for any host tool
built with -I./include. They are in folders now -- arch/ core/ fs/
dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and
every include names the folder, as Linux's do: "core/proc.h".

Done mechanically and checked the hard way: the kernel built from this
tree disassembles identically to the one built from the tree before
it. The full image boots, and userland is the same set of programs.
Paths in docs and comments follow; docs/guides/layout.md has a table
of what is where, and tools/fix-includes.py rewrites old-style
includes from the folders in the tree, for code written before this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
2026-10-23 15:05:12 +02:00

111 lines
3.3 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
// SchOS — first-party userland runtime: _start entry and exit.
#include "core/types.h"
#include "uapi/user.h"
// The raw syscall. It takes the status in %rdi, and both callers below must
// pass one: this declaration used to be `void _xv6_exit(void)`, so the status
// was whatever the caller happened to leave in that register. Every program
// that ended with a bare exit() reported a random number, which is why
// `if socktest; then` could not work for any of them.
extern void _xv6_exit(int status);
// exit(void) in this library means exit(0). A program that wants to report
// something returns it from main -- lib/start.S passes that through now -- or
// calls exit_group(n).
void
exit(void)
{
_xv6_exit(0);
for (;;);
}
/* _start lives in lib/start.S — it must read incoming registers, which
* cannot be expressed portably in C. See that file. */
// The four the compiler is allowed to call without being asked.
//
// A freestanding build gets no libc, but it does not get a compiler that
// promises never to *call* one: the C standard lets an implementation emit
// calls to memcpy, memmove, memset and memcmp for things that look nothing
// like a function call. A struct assignment is the common one --
//
// *out = in; /* struct pciuser_info, 96 bytes */
//
// -- which gcc unrolled into stores and clang turned into `call memcpy`, so
// ldlsd linked for months and then did not, on a machine where nothing about
// it had changed except which compiler ran. The fix is not to avoid struct
// assignment; it is to provide the four functions, because the compiler is
// within its rights either way.
//
// Deliberately simple. These are not the hot path of anything here, and a
// clever one risks being turned back into a call to itself.
void *
memcpy(void *dst, const void *src, unsigned long n)
{
unsigned char *d = dst;
const unsigned char *s = src;
while (n--) *d++ = *s++;
return dst;
}
void *
memmove(void *dst, const void *src, unsigned long n)
{
unsigned char *d = dst;
const unsigned char *s = src;
if (d == s || n == 0)
return dst;
// Backwards when they overlap the wrong way, which is the whole reason
// this is not memcpy.
if (d < s) {
while (n--) *d++ = *s++;
} else {
d += n; s += n;
while (n--) *--d = *--s;
}
return dst;
}
void *
memset(void *dst, int c, unsigned long n)
{
unsigned char *d = dst;
while (n--) *d++ = (unsigned char)c;
return dst;
}
int
memcmp(const void *a, const void *b, unsigned long n)
{
const unsigned char *p = a, *q = b;
while (n--) {
if (*p != *q)
return *p - *q;
p++; q++;
}
return 0;
}
void
__stack_chk_fail(void)
{
// A smashed stack is not a successful run. 134 is what a shell reports for
// SIGABRT, which is the nearest true thing this can say.
_xv6_exit(134);
for (;;);
}
// exec() without an environment.
//
// The syscall is execve, three arguments, because that is what Linux numbers
// 59 and what musl calls. The two-argument spelling stays because most of
// cmd/ has no environment to pass and should not have to say so -- but it
// says so *here*, explicitly, rather than leaving %rdx to chance.
int
exec(char *path, char **argv)
{
return execve(path, argv, 0);
}