Hi,
Thpertic wrote:Ok then... But in the libc to work properly I have to add the exact stdlib, stdio and so on, right?
For the C standard library, there's a large difference between "hosted" and "freestanding".
Hosted is for normal user-space software, where you've got a massive amount of stuff that the software/library can rely on (file systems, time zone database, unicode/wchar handling, scheduler, etc). For this you need everything.
Freestanding is for when there is nothing the software/library can rely on (e.g. kernels that implement things like file systems, etc). It only includes float.h, iso646.h, limits.h, stdalign.h, stdarg.h, stdbool.h, stddef.h, stdint.h, and stdnoreturn.h.
Essentially; when the language was designed (about 46 years ago), the people that designed it knew that a lot of the C standard library (including stdlib, stdio, etc) doesn't make any sense for kernels.
Thpertic wrote:I'm thinking to not worry about the actual compatibility and the code duplication since I'm still a starter. Just use a sort of printf only in the kernel for now. Thanks for all the answers
For a kernel, the idea of "printing" doesn't really make sense once you get past "temporary hello world experiment". After boot (e.g. after user starts a GUI, etc) you don't want kernel or drivers ruining the screen with trash just because (e.g.) someone plugged in a USB device. Instead, you want some kind of logging system that appends data to file/s on disk, so that users/admin can do (e.g.) "cat /log/kern.log" whenever they feel like to see what happened. During boot (where you might want to display kernel initialisation stuff, even though it's all going to scroll off the top of the screen faster than anyone can read it and will look a lot uglier than a nice splash screen) you mostly want to add text to a log in memory (so that it can handed off to a "system logger" daemon and/or saved to disk later), and then have multiple different things in your boot code that can show the log to the user (e.g. one piece of code that shows the log using a local video card in text mode, another piece of code that can show the log using a local video card in graphics mode, another piece of code that sends the log to a serial port if it's a headless system without any video card, etc).
When you get tasks working you'll have to worry about race conditions and synchronisation. For example if one task is initialising the network and wants to add a multiple line message to the log and another task is initialising a file system and wants to add a different message to the log at the same time, then you don't want these messages to end up as jumbled mess (e.g. you don't want "
Network info:\nIP address is Bad blocks found at sectors: 123.45.67.89\n #84, #85, Netmask is #86, #87, 255.255.255.0\n #88\n" when one task is trying to say "
Network info:\nIP address is 123.45.67.89\nNetmask is 255.255.255.0" and another task is trying to say "
Bad blocks found at sectors: #84, #85, #86, #87, #88\n"). For this reason you end up needing to have "local string builders" that create the text as a single string, and then an "atomically append string to log" in the kernel.
Also note that good operating systems don't use plain text for logging either. For example, each message in the log might be an entry with a header; where the header might have a 32-bit entry size field, a 64-bit timestamp field, a 32-bit "where it came from" field, an 8-bit "type" field, and an 8-bit "severity" field; with the text after the header. This allows you to quickly index, filter and sort the messages (e.g. so that the user can look at "all message from e1000 driver only" or "all messages from anywhere sorted in order of severity" or "all messages with severity > informational sorted in order of where it came from", or "all messages from 8:00 am to 10:00 am yesterday morning when the server seemed incredibly slow" or ...).
Essentially; you might end up with function/s to build the text (that might use something like "ksprintf()" multiple times to build the whole piece of text but might use a set of significantly simpler and more efficient "add_string(), add_decimal_integer(), add_hex_integer()" functions instead); then have a function like "atomically_append_to_log(int source_ID, int severity, char *message);" that determines the length of the string, gets a time stamp, acquires a lock, allocates space at the old end of the log (using something like "address = log_end; log_end += sizeof(header)+length_of_text;"), copies all the "header + text" data into the allocated space, then releases the lock, then broadcasts some kind of "log was updated" notification to whatever is listening (so that it can be displayed and/or sent to a serial port and/or added to files on disk and/or whatever else).
Cheers,
Brendan