Writing an OS Kernel from Scratch – Part 12: stdin/stdout/stderr in VFS — Making User Programs “Talk”!

# Writing an OS Kernel from Scratch – Part 12: stdin/stdout/stderr in VFS — Making User Programs “Talk”!

“Your OS can run user programs, but how do they interact with the outside world? Today, we wrap the serial port and VGA display as standard files, making printf actually work!”

In previous posts, we implemented the ext2 file system and IDE driver. User programs can be loaded from disk and executed. But have you noticed: user programs still can’t output anything! They call `write(1, “Hello”, 5)`, but the kernel doesn’t know what “1” represents.

A real operating system must provide stdin, stdout, and stderr for every process, and make them work just like ordinary files — this is the essence of the Unix “everything is a file” philosophy.

Today, we’ll implement these three special files in VFS, so your user programs can communicate with the world!


## 1. The Essence of Standard Streams: Special “Files”

In Unix:

– stdin = file descriptor 0
– stdout = file descriptor 1
– stderr = file descriptor 2

They are not disk files, but abstract interfaces provided by the kernel. Behind them can be:
– Serial Port
– VGA Text Buffer
– Network sockets
– Pipes
– Pseudo-terminals (PTY)

Key idea: Disguise hardware output as “files” through the VFS file_operations abstraction!


## 2. Device File Design in VFS

We need a mechanism to map file paths (e.g., /dev/tty) to device drivers.

Approach: Device inode + device number

Predefined devices:

| Path | Major | Minor | Description |
|——|——-|——-|————-|
| /dev/tty | 1 | 0 | Console (stdout/stderr) |
| /dev/console | 1 | 1 | System console |
| /dev/null | 1 | 3 | Bit bucket device |

Standard streams don’t correspond to specific paths; they are file descriptors pre-opened when a process is created.


## 3. Implementing the Console Device

The console device redirects output to Serial Port + VGA.

1. Console file operations
2. Create console inode


## 4. Process Initialization: Pre-opening Standard Streams

When each new process is created (fork/exec), the kernel automatically opens three file descriptors:

Key: When forking, the child process copies the parent’s fd_table, so the child inherits the standard streams!


## 5. System Call Integration: write(fd, buf, count)

Now, sys_write can handle any file descriptor. When a user calls `write(1, “Hello”, 5)`, the kernel calls console_write!


## 6. Test: printf in User Programs

user.c:

Running result (QEMU serial output): Standard streams work correctly!


## 7. Extension: Implementing /dev Directory and Device Files

Although standard streams are pre-opened, we also want users to access devices via paths by creating device nodes in the ext2 root directory with VFS path resolution supporting device inodes.

Last modified: 2025年12月30日

Author

Comments

Write a Reply or Comment

Your email address will not be published.