When writing an unix-like OS, what are the basic syscalls you need?
By basic I mean fork, execve, browsing contents of a directory, writing to a file, reading a file, chroot, some syscalls for IPC, shared memory, multi-threading.
Basic syscalls needed in a unix clone
Basic syscalls needed in a unix clone
All a good OS needs to do is to run Linux inside QEMU
-
- Member
- Posts: 501
- Joined: Wed Jun 17, 2015 9:40 am
- Libera.chat IRC: glauxosdever
- Location: Athens, Greece
Re: Basic syscalls needed in a unix clone
Hi,
For (old) Linux system call reference check here: http://syscalls.kernelgrok.com/. Check which of these calls are mandated by POSIX and start implementing them.
I think it would be better to keep compatibility with Linux (the most used Unix-like operating system) and implement whatever system calls Linux supports and with the same parameters (except you have something superior to show and implement). If you want something more basic, I think you should implement whatever a typical libc needs to function. Choose interrupt 0x80 for as the system call interrupt, the same as Linux uses. This way it will be easier to port third-party programs.
For the system calls you will obviously need a working kernel. So don't mess with them unless you have it and want to add user-space.
Regards,
glauxosdever
For (old) Linux system call reference check here: http://syscalls.kernelgrok.com/. Check which of these calls are mandated by POSIX and start implementing them.
I think it would be better to keep compatibility with Linux (the most used Unix-like operating system) and implement whatever system calls Linux supports and with the same parameters (except you have something superior to show and implement). If you want something more basic, I think you should implement whatever a typical libc needs to function. Choose interrupt 0x80 for as the system call interrupt, the same as Linux uses. This way it will be easier to port third-party programs.
For the system calls you will obviously need a working kernel. So don't mess with them unless you have it and want to add user-space.
Regards,
glauxosdever
Re: Basic syscalls needed in a unix clone
Why don't you just start writing programs and add whatever syscall you need next?
In the one unixy OS I have, I added syscalls in the following order: write, read, open, close, mmap, exit, fork, waitpid, mount, exec, opendir, readdir, closedir, chdir, getcwd, mkdir, stat, lseek, getfsstat, dup, pipe. And that's it so far.
Things such as chroot, shared memory or multithreading I wouldn't really consider basic. IPC can be achieved with pipe() and the usual file operations. I don't think any of these are items that I would implement next if I were to continue work on this OS.
In the one unixy OS I have, I added syscalls in the following order: write, read, open, close, mmap, exit, fork, waitpid, mount, exec, opendir, readdir, closedir, chdir, getcwd, mkdir, stat, lseek, getfsstat, dup, pipe. And that's it so far.
Things such as chroot, shared memory or multithreading I wouldn't really consider basic. IPC can be achieved with pipe() and the usual file operations. I don't think any of these are items that I would implement next if I were to continue work on this OS.
Trying to be binary compatible with Linux definitely isn't the easy way. Try being compatible at the libc level (i.e. implement the POSIX standard) so that you can easily compile existing programs from source. Many programs include a configure script that checks what your libc can do and they haven code to cope with a limited libc when compiled against it; but if compiled for Linux, they will use everything and you would have to support everything to make Linux binaries work.Choose interrupt 0x80 for as the system call interrupt, the same as Linux uses. This way it will be easier to port third-party programs.
Re: Basic syscalls needed in a unix clone
That applies to 32-bit Linux only.glauxosdever wrote:Choose interrupt 0x80 for as the system call interrupt, the same as Linux uses.
Re: Basic syscalls needed in a unix clone
Seems like a good idea, I'll try it.glauxosdever wrote:I think it would be better to keep compatibility with Linux
This is exactly what I have been looking for.Kevin wrote:In the one unixy OS I have, I added syscalls in the following order: write, read, open, close, mmap, exit, fork, waitpid, mount, exec, opendir, readdir, closedir, chdir, getcwd, mkdir, stat, lseek, getfsstat, dup, pipe. And that's it so far.
Yes, as far as I know 64-bit linux uses the SYSCALL instruction.iansjack wrote:That applies to 32-bit Linux only.
Huge thanks everyone, but I still have one question:
Do I need to implement any special syscall for making a user-mode process being able to multi-thread?
Or maybe they can just be implemented in the libc without the need of any special syscall as malloc() and free() can?
Somehow I couldn't find anything on the Wiki.
All a good OS needs to do is to run Linux inside QEMU
Re: Basic syscalls needed in a unix clone
Hi,
As someone with a very advanced custom Unix, beware some of the advise in this thread.
Linux is an old operating system and the i386 ABI is full of compatibility and old practices. Following old Linux practices may not be a good idea. There's also do need to pick 0x80 as the syscall interrupt as unlike glauxosdever suggests, no third party applications actually do raw syscalls. They just use the libc standard API. (A few times, I've seen bad software use sys/syscall.h to do raw syscalls, that is worrying. That software is broken anyway, don't try to support it.)
The Linux syscall ABI for i386 is also ancient by design. POSIX has a lot of modern facilities that are superior to the traditional ones. For instance, open is dominated by the new openat system call and gettimeofday with clock_gettime. All the traditional filesystem opening system calls have *at variants now. Those are crucial from a security and reliability perspective and fits in well with the Unix design. Don't implement the older facilities like open as a system call, but have open in the libc call openat. This is much simpler and cleaner. Newer Linux ABI archs do this, too.
See my system call list. It's pretty big and has a few non-standard extensions. But I basically need all of those system calls now. Notice how none of the traditional standard interfaces with more powerful replacements are there.
However, all that said, Linux ABI compatibility may be desirable. It's not desirable on its own merits as the ABI has issues, but if you want to make a real Unix operating system, you are going to need a libc. The best option is to write one yourself as you can improve the ABI as I do, but that is a lot of work. A perfectly viable alternative is to implement the Linux ABI and then use the musl libc, which is really great. That'll save you effort, sacrifice a little quality, but get something good that works with less effort. Don't do newlib for quality reasons.
What system calls do you need first? Well, I can't tell you, but your test programs for your OS will. If you want a ls, you are going to need a syscall to load a program (execve), you will need openat to open the directory, fstat to see if what you opened was actually a dir (or do O_DIRECTORY in your openat), a read-directory-entries system call (there's no standard one, readdir(3) is a libc abstraction), then a write system call to write to fd 1 (stdout), and a close system call to close the directory, and _exit to kill the process at the end. My point is that you think of something you want to runm and then find out what it needs. I do the same with third party software, I try to compile it and see what it errors on, then implement that.
You don't need any special system calls for being multi threaded, except obviously a system call to create threads and one for them to exit, and optionally a kernel assisted futex syscall for efficient sleeping. In my OS, to create threads, I just allocate with mmap a new stack and per-thread structure for it in user-space, use tfork to create a thread in this address space with the specified registers, and then that happens. The kernel needs to keep track of very little and doesn't care at all what the threads do in user-space. It's pretty beautiful.
malloc isn't a syscall. mmap is. (Don't implement brk/sbrk, do mmap!). mmap can be used to allocate memory by MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ|PROT_WRITE so it's process private and unbacked by a file. malloc and free is just a thread safe libc facility that maintain a general purpose allocation data structure in that mmap area.
As someone with a very advanced custom Unix, beware some of the advise in this thread.
Linux is an old operating system and the i386 ABI is full of compatibility and old practices. Following old Linux practices may not be a good idea. There's also do need to pick 0x80 as the syscall interrupt as unlike glauxosdever suggests, no third party applications actually do raw syscalls. They just use the libc standard API. (A few times, I've seen bad software use sys/syscall.h to do raw syscalls, that is worrying. That software is broken anyway, don't try to support it.)
The Linux syscall ABI for i386 is also ancient by design. POSIX has a lot of modern facilities that are superior to the traditional ones. For instance, open is dominated by the new openat system call and gettimeofday with clock_gettime. All the traditional filesystem opening system calls have *at variants now. Those are crucial from a security and reliability perspective and fits in well with the Unix design. Don't implement the older facilities like open as a system call, but have open in the libc call openat. This is much simpler and cleaner. Newer Linux ABI archs do this, too.
See my system call list. It's pretty big and has a few non-standard extensions. But I basically need all of those system calls now. Notice how none of the traditional standard interfaces with more powerful replacements are there.
However, all that said, Linux ABI compatibility may be desirable. It's not desirable on its own merits as the ABI has issues, but if you want to make a real Unix operating system, you are going to need a libc. The best option is to write one yourself as you can improve the ABI as I do, but that is a lot of work. A perfectly viable alternative is to implement the Linux ABI and then use the musl libc, which is really great. That'll save you effort, sacrifice a little quality, but get something good that works with less effort. Don't do newlib for quality reasons.
What system calls do you need first? Well, I can't tell you, but your test programs for your OS will. If you want a ls, you are going to need a syscall to load a program (execve), you will need openat to open the directory, fstat to see if what you opened was actually a dir (or do O_DIRECTORY in your openat), a read-directory-entries system call (there's no standard one, readdir(3) is a libc abstraction), then a write system call to write to fd 1 (stdout), and a close system call to close the directory, and _exit to kill the process at the end. My point is that you think of something you want to runm and then find out what it needs. I do the same with third party software, I try to compile it and see what it errors on, then implement that.
You don't need any special system calls for being multi threaded, except obviously a system call to create threads and one for them to exit, and optionally a kernel assisted futex syscall for efficient sleeping. In my OS, to create threads, I just allocate with mmap a new stack and per-thread structure for it in user-space, use tfork to create a thread in this address space with the specified registers, and then that happens. The kernel needs to keep track of very little and doesn't care at all what the threads do in user-space. It's pretty beautiful.
malloc isn't a syscall. mmap is. (Don't implement brk/sbrk, do mmap!). mmap can be used to allocate memory by MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ|PROT_WRITE so it's process private and unbacked by a file. malloc and free is just a thread safe libc facility that maintain a general purpose allocation data structure in that mmap area.
Re: Basic syscalls needed in a unix clone
Hi,
For example, for a unix-like OS on a micro-kernel (e.g. Minix) you probably only need 2 syscalls (send message, receive message). Note that "need" is very different to "want" (just because you only need 2 syscalls doesn't mean you wouldn't want or wouldn't have more than 2 syscalls).
For a unix-like OS on a monolithic kernel; the kernel might have syscalls that directly correspond to the functionality that the system library is supposed to provide so that the system library is "minimal glue"; or the kernel's syscalls might be something completely different (where the system library is much larger). Note that for Linux and FreeBSD it's about half-way between, with things like "printf()" and "malloc()" in the system library and things like "write()" and "mmap()" implemented as minimal glue in the library.
For a unix-like OS on an exo-kernel, it's similar to the "monolithic kernel" case except functionality is shifted from kernel into the system library, the kernel's syscalls are much lower level and the system library does a lot more.
Cheers,
Brendan
For a unix-like OS; there is a system library in user-space that provides the interface that processes use (which is dynamically linked into the process); and because the kernel and its syscalls are hidden behind the system library's abstraction the kernel can do anything it likes. Basically the syscalls you actually need depend on the kernel design, how much you're putting in the system library in user space, what mood you were in when you designed it, etc.StartOS wrote:When writing an unix-like OS, what are the basic syscalls you need?
For example, for a unix-like OS on a micro-kernel (e.g. Minix) you probably only need 2 syscalls (send message, receive message). Note that "need" is very different to "want" (just because you only need 2 syscalls doesn't mean you wouldn't want or wouldn't have more than 2 syscalls).
For a unix-like OS on a monolithic kernel; the kernel might have syscalls that directly correspond to the functionality that the system library is supposed to provide so that the system library is "minimal glue"; or the kernel's syscalls might be something completely different (where the system library is much larger). Note that for Linux and FreeBSD it's about half-way between, with things like "printf()" and "malloc()" in the system library and things like "write()" and "mmap()" implemented as minimal glue in the library.
For a unix-like OS on an exo-kernel, it's similar to the "monolithic kernel" case except functionality is shifted from kernel into the system library, the kernel's syscalls are much lower level and the system library does a lot more.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.