<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Operating Systems on jairrs</title><link>https://jairsantana.com/tags/operating-systems/</link><description>Recent content in Operating Systems on jairrs</description><generator>Hugo -- 0.156.0</generator><language>en-us</language><atom:link href="https://jairsantana.com/tags/operating-systems/index.xml" rel="self" type="application/rss+xml"/><item><title>Operating Systems: Memory, Networking, and Files</title><link>https://jairsantana.com/portfolio/operating-systems/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://jairsantana.com/portfolio/operating-systems/</guid><description>Copy-on-write memory, an Ethernet driver, concurrent allocation, and file-backed mappings in xv6.</description><content:encoded><![CDATA[<p>For MIT&rsquo;s 6.1810 Operating System Engineering course, I implemented a series of assignments in xv6, a small Unix-like operating system for RISC-V. The work covered virtual memory, networking, synchronization, and file systems. Working inside a kernel gave me a better understanding of what happens behind operations I normally just call from a program.</p>
<p>Here&rsquo;s a small overview of my favorite parts of OS.</p>
<h2 id="copy-on-write">Copy-On-Write</h2>
<p>I implemented copy-on-write for <code>fork</code>. Instead of immediately copying a process&rsquo;s memory, the parent and child initially share physical pages. Pages that were writable become read-only, and a write triggers a page fault that creates a private copy.</p>
<p>I added a page-table flag to distinguish these pages, reference counts to track their lifetime, and handling for writes made through the kernel&rsquo;s <code>copyout</code> function.</p>
<h2 id="nic-driver">NIC Driver</h2>
<p>I implemented transmit and receive handling for the emulated E1000 Ethernet device, along with UDP port binding and packet queues. A process waiting for a packet sleeps until the receive path wakes it up.</p>
<p>The driver uses rings of descriptors shared with the OS via MMIO. I replace received buffers before handing packets to the network stack, and reclaim transmitted buffers once the device is done with them.</p>
<details class="article-details">
    <summary>Code: waiting for a packet</summary>
    <div class="article-details-content">
        <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#ff7b72">char</span> <span style="color:#ff7b72;font-weight:bold">*</span>packet;
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">while</span>((packet <span style="color:#ff7b72;font-weight:bold">=</span> (<span style="color:#ff7b72">char</span> <span style="color:#ff7b72;font-weight:bold">*</span>) udp_port<span style="color:#ff7b72;font-weight:bold">-&gt;</span>packet_ring[udp_port<span style="color:#ff7b72;font-weight:bold">-&gt;</span>head]) <span style="color:#ff7b72;font-weight:bold">==</span> <span style="color:#a5d6ff">0</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#d2a8ff;font-weight:bold">sleep</span>(udp_port, <span style="color:#ff7b72;font-weight:bold">&amp;</span>netlock);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><code>sleep</code> releases the lock while the process waits, then reacquires it before returning. The loop checks the queue again after waking up.</p>

    </div>
</details>

<h2 id="letting-cpus-work-in-parallel">Letting CPUs Work in Parallel</h2>
<p>I split the physical memory allocator into per-CPU free lists, each with its own lock. When one list is empty, it can take a page from another CPU&rsquo;s list. I also implemented a reader-writer spinlock that allows multiple readers, with pending writers preventing new readers from entering.</p>
<h2 id="extending-the-file-system">Extending the File System</h2>
<p>I added doubly indirect blocks so files could grow beyond xv6&rsquo;s original limit, including the cleanup needed when truncating them. I also implemented symbolic links, following chains when opening a file and supporting <code>O_NOFOLLOW</code>.</p>
<h2 id="mapping-files-into-memory">Mapping Files into Memory</h2>
<p>I added file-backed <code>mmap</code> and <code>munmap</code>. Each process records its mapped regions, and page faults load file contents as those pages are accessed. Shared mappings write data back during unmapping, while private mappings keep changes out of the file. I also added handling for these regions across <code>fork</code>, exit, and <code>exec</code>.</p>
<p>Accessing a file through a pointer still involves allocating pages, checking permissions, and managing the underlying file&rsquo;s lifetime.</p>
]]></content:encoded></item></channel></rss>