# System Programming: OS Design and Implementation

## Start the MIT 6.1810 Fall2025 Course

So… here’s an update on my learning path.

**2023 – 2024:** *Building a Modern Computer from First Principles* (aka **Nand2Tetris**). I studied the fundamentals of computer architecture; from logic gates and the CPU to the operating system and compiler.

**Mid 2025:** *Introduction to Networking Basics.*

**Late 2025 – :**

I want to learn more about OS internals, especially the Linux kernel and similar topics. So, some days ago, I started the **MIT 6.1810** course on *Design and Implementation of Operating Systems*.

The course is based on **xv6**, a simple Unix-like teaching operating system. The goal is to study OS concepts by extending xv6.

**What’s good about this course:**

* It’s well structured and has a clear schedule. (This year’s session started in September 2025 and is expected to end in December 2025.)
    
* It combines theory with practical labs, so you don’t just read; you build as well.
    

I’ll spend some nights and weekends working on it, enjoy the process, and share updates about my progress here.

I’m currently working on the Week 1 assignment (*Lab: Utilities*), where we’re implementing Unix-like utilities using the xv6 API.

By the way, MIT offers really well-structured courses on various topics in Computer Science.

**MIT 61.810** Fall 2025 (Operating System Engineering) link:\[[https://pdos.csail.mit.edu/6.1810/2025/overview.html](https://pdos.csail.mit.edu/6.1810/2025/overview.html)\]

## Update \[07 November 2025\]

### Lectures

I just finished week 1 of the course. This week, I read [Chapter 1: Operating System Interface](https://pdos.csail.mit.edu/6.1810/2025/xv6/book-riscv-rev5.pdf) of the book on **xv6.** This chapter introduces:

* The **xv6** system calls, such as **open**, which "opens" a file by returning a file descriptor, and **fork**, which creates a process.
    
* How processes behave, including how to create a child process and execute a command.
    
* Importantly, what a **file descriptor** is (an entry in a table for each process that lists files opened by the process), which allows a process to read or write.
    
* A method for processes to communicate (Inter-Process Communication): **Pipes**, which use file descriptors.
    

I also read the chapters on Pointers (Arrays, Characters, Structs) from **The C Programming Language (Second Edition) by *Kernighan and Ritchie (K&R)*** to refresh key concepts about manipulating pointers.

Then there are the assignments or labs.

### Lab Assignments: Unix utilities

The labs focused on writing Unix-like utilities. Here are a few, along with brief descriptions::

* **sixfive (not so easy):** For each input file, **sixfive** must print all the numbers in the file that are multiples of 5 or 6. Number are a sequence of decimal digits separated by characters in the string " -\\r\\t\\n./,"*.*
    
* **memdump (not so easy):** Implement the function memdump(char *fmt, char* data). **memdump()**'s purpose is to print the contents of the memory pointed to by data in the format described by the fmt argument.
    
* **find (not easy):** Write a simple version of the UNIX find program for xv6: find all the files in a directory tree with a specific name.
    
* **pingpong (easy and from Fall 2020):** Write a program that uses UNIX system calls to **ping-pong** a byte between two processes over a pair of pipes, one for each direction
    

These labs were not too difficult and had clear instructions, but I often felt stuck and unsure of what to do. However, after reading **chapter 1** of the **xv6** book multiple times and reviewing the source code of some existing utilities, I completed them. Here are a few things to remember (and I'm not ready to forget them)::

1. When creating a **child** with the **fork** system call, don't forget to use **wait** in the **parent**. This ensures that the parent waits for the child to finish executing. This way, both the **parent** and **child** code will run properly.
    

* ```c
    if (fork() == 0) // Child
    {
        write(1, "hello ", 6);
    	exit(0);
    }
    else // Parent
    {
    	wait(0); // Don't forget to wait here so child can execute
    	write(1, "world\n", 6);
    }
    ```
    
    Forgetting this, make me stuck on the pingpong **task.**
    

2. When we define an array of **int** and another of **char**, like `int tab_1[5]` and `char tab_2[5]`, we know that **tab\_1** and **tab\_2** are pointers to the first element (\[0\]) of the array. Also, `tab_1[1]` is equivalent to `*(tab_1 + 1)`, and the same applies to `tab_2[1]`, which is equivalent to `*(tab_2 + 1)`..
    
    * But if we assume that the memory address of **tab\_1** is **4000** and the address of **tab\_2** is **5000**, what will be the address of `tab_1[1]` and `tab_2[2]`? The address of `tab_1[1]` will be **4000 + 4 bytes = 4004**, not **4001**, since `sizeof(int) = 4 bytes` on most modern 32-bit/64-bit computers..
        
        Why? Because **tab\_1** is a series of contiguous memory addresses that store integers, each with a size of 4 bytes (`sizeof(int)`). To move from one address or index to the next in the array, you need to step by 4 bytes. So, you move 4 bytes at a time. `tab_1[0]` occupies the memory blocks from **4000 to 4003**, and `tab_1[1]` starts at **4004**.
        
        The same rule applies to **tab\_2**, but here `sizeof(char)` **\= 1**, so the address of `tab_2[1]` will be **5000 + 1 byte = 5001**.
        
        The rule is simple: **New Address = Start Address + (N \* sizeof(Type))**
        
    * But here's another question: when we use `*(tab_1 + 1)` or `tab_1[1]`, how does the compiler know to add **N \* sizeof(Type)** to the initial address? Well, this is done at compile time when the compiler generates the assembly code. It uses a table called the Symbol Table, which holds information about variables, functions, and other elements in our code. This allows it to check the data type and perform the appropriate calculations..
        

From **Gemini**

> When the compiler reads your source code, it builds an internal data structure called the **Symbol Table**. This table tracks every identifier (variable, function, type, etc.) in your program and records all its key attributes, including its data type.
> 
> **For a pointer variable declared as** `int *p`**; the Symbol Table records that** `p` **is a pointer to an** `int`**.**

**Done for now, see you next time!**

It's good to write the utility and get back into C to remember these concepts before diving into OS.

I'm starting Week 2 of the course.

By the way, here's my GitHub repo for the lab course: [https://github.com/TawalMc/MIT-6.1810Fall2025-xv6](https://github.com/TawalMc/MIT-6.1810Fall2025-xv6)
