<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/</id>
    <title>Oxide Computer Company Blog</title>
    <updated>2026-04-07T21:17:11.659Z</updated>
    <generator>Remix using Feed for Node.js</generator>
    <author>
        <name>Oxide Computer Company</name>
        <email>info@oxide.computer</email>
        <uri>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app</uri>
    </author>
    <link rel="alternate" href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/"/>
    <link rel="self" href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/feed"/>
    <subtitle>Servers as they should be</subtitle>
    <logo>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/favicon-large.png</logo>
    <icon>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/favicon-large.png</icon>
    <rights>Copyright © 2026 Oxide Computer Company</rights>
    <entry>
        <title type="html"><![CDATA[Engineering a culture]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/engineering-culture</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/engineering-culture"/>
        <updated>2024-03-31T18:00:00.000Z</updated>
        <summary type="html"><![CDATA[A revelation, a bug, and a fix -- how it all reflects the culture at Oxide]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div class="paragraph"><p>We ran into an interesting issue recently.  On the one hand, it was routine:
we had a bug&#8201;&#8212;&#8201;a regression&#8201;&#8212;&#8201;and the team quickly jumped on it, getting
it root caused and fixed.  But on the other, this particular issue
was something of an Oxide object lesson, representative not just of the
technologies but also of the
culture we have built here.  I wasn&#8217;t the only person who thought so,
and two of my colleagues wrote terrific blog entries with their perspectives:</p></div><div class="ulist"><ul class=""><li><p>Matt Keeter with <a href="https://www.mattkeeter.com/blog/2024-03-25-packing/">It&#8217;s Free Real Estate</a></p></li><li><p>Cliff Biffle with <a href="https://cliffle.com/blog/who-killed-the-network-switch/">Who killed the network switch?  A Hubris Bug Story</a></p></li></ul></div><div class="paragraph"><p>The initial work as described by Matt represents a creative solution to
a thorny problem; if it&#8217;s clear in hindsight, it certainly wasn&#8217;t at the time!
(In Matt&#8217;s evocative words: "One morning, I had a revelation.") I first learned of
Matt&#8217;s work when he demonstrated it during our weekly
<a href="https://www.youtube.com/watch?v=7RR6hFE_jDU#t=6">Demo Friday</a>,
an hour-long unstructured session to demo our work for one another.  Demo
Friday is such an essential part of Oxide&#8217;s culture that it feels like we have
always done it, but in fact it took us nearly two years into the company&#8217;s
life to get there: over the spring and summer of 2021, our colleague Sean
Klein had instituted regular demos for the area that he works on (the
<a href="https://github.com/oxidecomputer/omicron">Oxide control plane</a>),
and others around the company&#8201;&#8212;&#8201;seeing the energy that came from it&#8201;&#8212;&#8201;asked
if they, too, could start regular demos for their domain.  But instead of
doing it group by group, we instituted it company-wide starting in the fall of
2021: an unstructured hour once a week in which anyone can demo
anything.</p></div><div class="paragraph"><p>In the years since, we have had demos of all scopes and sizes.  Importantly,
no demo is too small&#8201;&#8212;&#8201;and we have often found that a demo that feels small
to someone in the thick of work will feel extraordinary to someone outside of
it.  ("I have a small demo building on the work of a lot of other people" has
been heard so frequently that it has become something of an inside joke.) Demo
Friday is important because it gets to one of our most important drivers as
technologists:  <strong>the esteem of our peers</strong>.  The thrill that you get from showing
work to your colleagues is unparalleled&#8201;&#8212;&#8201;and their wonderment in return is
uniquely inspiring.  (Speaking personally, Matt&#8217;s demo addressed a problem
that I had personally had many times over in working on Hubris&#8201;&#8212;&#8201;and I was one
of the many <a href="https://en.wikipedia.org/wiki/W00t">w00ts in the chat</a>, excited to see his
creative solution!)</p></div><div class="paragraph"><p>Having the demos be company-wide has also been a huge win
for not just our shared empathy and teamwork but also our curiosity and
versatility:  it&#8217;s really inspiring to have (say) one colleague show how they
used
<a href="https://www.protoexpress.com/blog/back-drilling-pcb-design-and-manufacturing/">PCB
backdrilling</a> for signal integrity, and the next show an integration they
built using
<a href="https://github.com/oxidecomputer/dropshot">Dropshot</a>
between our CRM and spinning up a demonstration environment for a customer.
And this is more than just idle intellectual curiosity:  our stack is deep&#8201;&#8212;&#8201;spanning
both hardware and software&#8201;&#8212;&#8201;and the demos make for a fun and engaging way to learn
about aspects of the system that we don&#8217;t normally work on.</p></div><div class="paragraph"><p>Returning to Matt and Cliff, if
<a href="https://www.mattkeeter.com/blog/2024-03-25-packing/">Matt&#8217;s work</a>
implicitly hits on aspects of our culture,
<a href="https://cliffle.com/blog/who-killed-the-network-switch/">Cliff&#8217;s story of debugging</a> addresses that culture
explicitly, noting that the experience demonstrated:</p></div><div class="quoteblock"><blockquote><div class="paragraph">
<p><strong>Tight nonhierarchical integration of the team.</strong> This isn’t a Hubris feature, but it’s hard to separate Hubris from the team that built it. Oxide’s engineering team has essentially no internal silos. Our culture rewards openness, curiosity, and communication, and discourages defensiveness, empire-building, and gatekeeping. We’ve worked hard to create and defend this culture, and I think it shows in the way we organized horizontally, across the borders of what other organizations would call teams, to solve this mystery.</p>
</div></blockquote></div><div class="paragraph"><p>In
<a href="https://news.ycombinator.com/item?id=39813365">the discussion on Hacker News of Cliff&#8217;s piece</a>,
this cultural observeration stood out, with
<a href="https://news.ycombinator.com/item?id=39837073">a commenter asking</a>:</p></div><div class="quoteblock"><blockquote><div class="paragraph">
<p>I&#8217;d love to hear more about the motivations for crafting such a culture as
well as some particular implementation details. I&#8217;m curious if there are
drawbacks to fostering "openness, curiosity, and communication" within an
organization?</p>
</div></blockquote></div><div class="paragraph"><p>The culture at Oxide is in fact very deliberate:  when starting a company,
one is building many things at once (the team, the product, the organization,
the brand)&#8201;&#8212;&#8201;and the culture will both inform and be reinforced by all of
these.
Setting that first cultural cornerstone was very important to us&#8201;&#8212;&#8201;starting with
<a href="https://oxide.computer/principles">our mission, principles,
and values</a>.
Critically, by using our mission, principles, and values as the foundation for
<a href="https://rfd.shared.oxide.computer/rfd/0003">our hiring process</a>,
we have deliberately created a culture that reinforces itself.</p></div><div class="paragraph"><p>Some of the implementation details:</p></div><div class="ulist"><ul class=""><li><p>We have <a href="https://oxide.computer/blog/compensation-as-a-reflection-of-values">uniform compensation</a> (even if it might not scale indefinitely)</p></li><li><p>We are <a href="https://rfd.shared.oxide.computer/">writing intensive</a> (but we still believe in spoken collaboration)</p></li><li><p>We have no formalized performance review process (but we believe in feedback)</p></li><li><p>We record every meeting (but not every conversation)</p></li><li><p>We have a remote work force (but we also have an office)</p></li><li><p>We are non-hierarchical (but we all ultimately report to our CEO)</p></li><li><p>We don&#8217;t use engineering metrics (but we all measure ourselves by our
customers and their success)</p></li></ul></div><div class="paragraph"><p>If it needs to be said, there is plenty of <strong>ambiguity</strong>: if you are using
absolutes to think of Oxide (outside of our principles of honesty, integrity
and decency!) you are probably missing some nuance of our culture.</p></div><div class="paragraph"><p>Finally, to the (seemingly loaded?) question of the "drawbacks" of fostering
"openness, curiosity, and communication" within an organization, the only
drawback is that it&#8217;s hard work: culture has to be deliberate without being
overly prescriptive, and that can be a tricky balance.  In this regard,
building a culture is very different than building (say) software:  it is not
engineered in a traditional sense, but is rather a gooey, squishy, organism
that will evolve over time.  But the reward of the effort is something that its
participants care intensely about: it will continue to be (in Cliff&#8217;s words) a
culture that we work hard to not just create but defend!</p></div></div>]]></content>
        <author>
            <name>Bryan Cantrill</name>
        </author>
        <contributor>
            <name>Bryan Cantrill</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Moore's Scofflaws]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/moores-scofflaws</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/moores-scofflaws"/>
        <updated>2024-02-20T18:00:00.000Z</updated>
        <summary type="html"><![CDATA[The tyranny of per-core licensing]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div class="paragraph"><p>Years ago, Jeff Bezos famously quipped that "your margin is my opportunity."
This was of course aimed not at Amazon&#8217;s customers, but rather its
competitors, and it was deadly serious: customers of AWS in those bygone years
will fondly remember that every re:Invent brought with it another round of
price cuts.  This era did not merely reflect Bezos&#8217;s relentless execution, but
also a disposition towards who should reap the reward of advances in
underlying technology: Amazon believed (if implicitly) that improvements at
the foundations of computing (e.g., in transistor density, core count, DRAM
density, storage density, etc.) should reflect themselves in lower prices for
consumers rather than higher margins for suppliers.</p></div><div class="paragraph"><p>Price cuts are no longer a re:Invent staple, having been replaced by a regular
Amazon tradition of a different flavor:  cutting depreciation (and therefore
increasing earnings) by
<a href="https://www.theregister.com/2024/02/02/amazon_q4_2023/">extending the effective
life of their servers</a>.  (These announcements are understandably much more
subdued, as "my depreciation is my margin opportunity" doesn&#8217;t have quite the
same ring to it.)</p></div><div class="paragraph"><p>As compute needs have grown and price cuts have become an increasingly distant
memory, some have questioned their sky-high cloud bills, wondering if they
should in fact be owning their compute instead of renting it.  When we started
Oxide, we knew from operating our own public cloud what those economics looked
like&#8201;&#8212;&#8201;and we knew that over time others of a particular scale would come to
the same realization that they would be better off not giving their margin
away by renting compute.  (Though it&#8217;s safe to say that we did not predict
that it would be <a href="https://www.youtube.com/watch?v=a30vFpSaoZg">DHH leading the
charge</a>!)</p></div><div class="paragraph"><p>Owning one&#8217;s own cloud sounds great, but there is a bit that&#8217;s unsaid: <strong>what
about the software?</strong>  Software is essential for elastic, automated
infrastructure:  hardware alone does not a cloud make!  Unfortunately, the
traditional server vendors do not help here: because of a PC-era divide in how
systems are delivered, customers are told to look elsewhere for any and all
system software.  This divide is problematic on several levels.  First, it
impedes the hardware/software co-design that we (and, famously,
<a href="https://www.youtube.com/watch?v=XAfTXYa36f4">others</a>!) believe is essential to
deliver the best possible product.  Second, it leads to
<a href="https://twitter.com/_sysengineer/status/1487149172637712386">infamous finger
pointing</a> when the whole thing doesn&#8217;t work.  But there is also a thorny
economic problem:  when your hardware and your software don&#8217;t come from the
same provider, <strong>to whom should go the spoils of better hardware?</strong></p></div><div class="paragraph"><p>To someone who has just decided to buy their hardware out of their frustration
with renting it, the answer feels obvious:  whoever owns the hardware should
naturally benefit from its advances!  Unfortunately, the enterprise software
vendor delivering your infrastructure often has other ideas&#8201;&#8212;&#8201;and because
their software is neither rented nor bought, but rather comes from the
hinterlands of software licensing, they have broad latitude as to how it is
priced and used.  In particular, this allows them to charge based on the
hardware that you run it on&#8201;&#8212;&#8201;to have <strong>per-core software licensing.</strong></p></div><div class="paragraph"><p>This galling practice isn&#8217;t new (and is in fact as old as symmetric
multiprocessing systems), but it has taken on new dimensions in the era of
<a href="https://en.wikipedia.org/wiki/Chiplet">chiplets</a> and packaging innovation: the
advances that your next CPU has over your current one are very likely to be
expressed in core count.  Per-core licensing allows a third party&#8201;&#8212;&#8201;who
neither made the significant investment in developing the next generation of
microprocessor nor paid for the part themselves&#8201;&#8212;&#8201;to exact a tax on improved
infrastructure.  (And this tax can be
<a href="https://news.vmware.com/company/cpu-pricing-model-update-feb-2020">shockingly
brazen</a>!) Couple this with
<a href="https://arstechnica.com/information-technology/2023/12/broadcom-ends-vmware-perpetual-license-sales-testing-customers-and-partners/">the
elimination of perpetual licensing</a>, and software costs can potentially absorb
the entire gain from a next-generation CPU, leaving a disincentive to run
newer, more efficient infrastructure.  As an industry, we have come to accept
this practice, but we shouldn&#8217;t: in the go-go era of
<a href="https://en.wikipedia.org/wiki/Dennard_scaling">Dennard scaling</a> (when clock
rates rose at a blistering rate), software vendors never would have been
allowed to get away with charging by the gigahertz; we should not allow them to
feel so emboldened to charge by core count now!</p></div><div class="paragraph"><p>If it needs to be said, we have taken a different approach at Oxide:  when you
buy the <a href="/blog/the-cloud-computer">Oxide cloud computer</a>, <strong>all of the
software to run it is included</strong>.  This includes all of the software necessary
to run the rack as elastic infrastructure:
<a href="/product/compute">virtual compute</a>,
<a href="/product/storage">virtual storage</a>,
<a href="/product/networking">virtual networking</a>.
(And yes, it&#8217;s all open source&#8201;&#8212;&#8201;which unfortunately demands the immediate
clarification that it&#8217;s <a href="https://opensource.org/osd/"><em>actually</em> open source</a>
rather than <a href="https://bcantrill.dtrace.org/2018/12/16/a-eula-in-foss-clothing/">pretend open
source</a>.) When we add a new feature to our software, there is no licensing
enablement or other such nuisance&#8201;&#8212;&#8201;the feature just comes with the next
update.  And what happens when AMD releases a new CPU with twice the core
count?  The new sled running the new CPU runs along your existing rack&#8201;&#8212;&#8201;you&#8217;re not paying more than the cost of the new sled itself.  This gives the
dividends of Moore&#8217;s Law (or
<a href="https://www.youtube.com/watch?v=cuvp-e4ztC0">Wright&#8217;s Law</a>!) to whom they
rightfully belong:  the users of compute.</p></div></div>]]></content>
        <author>
            <name>Bryan Cantrill</name>
        </author>
        <contributor>
            <name>Bryan Cantrill</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[A Gap in the TrustZone Preset Settings for the LPC55S69]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/lpc55s69-tzpreset</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/lpc55s69-tzpreset"/>
        <updated>2023-11-20T18:00:00.000Z</updated>
        <summary type="html"><![CDATA[A weakness with TrustZone preset settings]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>We&#8217;re very excited to have <a href="https://oxide.computer/blog/the-cloud-computer">announced</a>
the general availability of our cloud computer. As part of this work, we
continue to build on top of the LPC55S69 from NXP as our Root of Trust. We&#8217;ve
discovered some gaps when using TrustZone preset settings on the LPC55S69 that
can allow for unexpected behavior including enabling debug settings and
exposure of the UDS (Unique Device Secret). These issues require a signed
image or access at manufacturing time.</p></div></div></div><div class="sect1"><h2 data-sectnum="">How to (safely, securely) configure a chip</h2><div class="sectionbody"><div class="paragraph"><p>The LPC55S69 uses the <a href="https://developer.arm.com/documentation/ddi0553/latest">Armv8-m</a>
architecture which includes TrustZone-M. We&#8217;ve <a href="https://oxide.computer/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69">previously</a>
discussed some aspects of the Armv8-m architecture and <a href="https://media.defcon.org/DEF%20CON%2029/DEF%20CON%2029%20video%20and%20slides/DEF%20CON%2029%20-%20Laura%20Abbott%20Rick%20Altherr%20-%20Breaking%20TrustZone-M%20-%20Privilege%20Escalation%20on%20LPC55S69.mp4">presented</a>
on it in more detail. Fundamentally, setting up TrustZone-M is simply a matter
of putting the right values in the right registers. The word "simply" is, of
course, doing a lot of heavy lifting here. TrustZone-M must also be set up
in conjunction with the Memory Protection Unit (MPU) and any other vendor
specific security settings. Once the ideal settings have been decided upon,
there&#8217;s still the matter of actually performing the register programming
sequence. NXP offers a feature called TrustZone preset data to make this
programming easier. Register data may optionally be appended to the end of
an image for the LPC55S69, and the ROM will set the registers before jumping
into the user image. Some of those registers may also be configured to
prevent futher modification. This means the user image does not need to be
concerned with the settings for those registers.</p></div><div class="paragraph"><p>The structure used to configure the registers looks like the <a href="https://github.com/nxp-mcuxpresso/spsdk/blob/09c711a8fd4c54f126a7dfe1b3ae8bb361c5473e/spsdk/data/tz_presets/lpc55s6x.yaml">following</a>:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code class="language-c" data-lang="c"><span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> _<span class="hljs-title">tzm_secure_config</span>
{</span>
  <span class="hljs-type">uint32_t</span> cm33_vtor_addr;  <span class="hljs-comment">/*! CM33 Secure vector table address */</span>
  <span class="hljs-type">uint32_t</span> cm33_vtor_ns_addr; <span class="hljs-comment">/*! CM33 Non-secure vector table address */</span>
  <span class="hljs-type">uint32_t</span> cm33_nvic_itns0; <span class="hljs-comment">/*! CM33 Interrupt target non-secure register 0 */</span>
  <span class="hljs-type">uint32_t</span> cm33_nvic_itns1; <span class="hljs-comment">/*! CM33 Interrupt target non-secure register 1 */</span>
  <span class="hljs-type">uint32_t</span> mcm33_vtor_addr; <span class="hljs-comment">/*! MCM33 Secure vector table address */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_ctrl; <span class="hljs-comment">/*! MPU Control Register.*/</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_mair0; <span class="hljs-comment">/*! MPU Memory Attribute Indirection Register 0 */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_mair1; <span class="hljs-comment">/*! MPU Memory Attribute Indirection Register 1 */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar0; <span class="hljs-comment">/*! MPU Region 0 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar0; <span class="hljs-comment">/*! MPU Region 0 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar1; <span class="hljs-comment">/*! MPU Region 1 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar1; <span class="hljs-comment">/*! MPU Region 1 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar2; <span class="hljs-comment">/*! MPU Region 2 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar2; <span class="hljs-comment">/*! MPU Region 2 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar3; <span class="hljs-comment">/*! MPU Region 3 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar3; <span class="hljs-comment">/*! MPU Region 3 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar4; <span class="hljs-comment">/*! MPU Region 4 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar4; <span class="hljs-comment">/*! MPU Region 4 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar5; <span class="hljs-comment">/*! MPU Region 5 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar5; <span class="hljs-comment">/*! MPU Region 5 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar6; <span class="hljs-comment">/*! MPU Region 6 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar6; <span class="hljs-comment">/*! MPU Region 6 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar7; <span class="hljs-comment">/*! MPU Region 7 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar7; <span class="hljs-comment">/*! MPU Region 7 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_ctrl_ns; <span class="hljs-comment">/*! Non-secure MPU Control Register.*/</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_mair0_ns; <span class="hljs-comment">/*! Non-secure MPU Memory Attribute Register 0 */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_mair1_ns; <span class="hljs-comment">/*! Non-secure MPU Memory Attribute Register 1 */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar0_ns; <span class="hljs-comment">/*! Non-secure MPU Region 0 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar0_ns; <span class="hljs-comment">/*! Non-secure MPU Region 0 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar1_ns; <span class="hljs-comment">/*! Non-secure MPU Region 1 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar1_ns; <span class="hljs-comment">/*! Non-secure MPU Region 1 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar2_ns; <span class="hljs-comment">/*! Non-secure MPU Region 2 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar2_ns; <span class="hljs-comment">/*! Non-secure MPU Region 2 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar3_ns; <span class="hljs-comment">/*! Non-secure MPU Region 3 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar3_ns; <span class="hljs-comment">/*! Non-secure MPU Region 3 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar4_ns; <span class="hljs-comment">/*! Non-secure MPU Region 4 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar4_ns; <span class="hljs-comment">/*! Non-secure MPU Region 4 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar5_ns; <span class="hljs-comment">/*! Non-secure MPU Region 5 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar5_ns; <span class="hljs-comment">/*! Non-secure MPU Region 5 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar6_ns; <span class="hljs-comment">/*! Non-secure MPU Region 6 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar6_ns; <span class="hljs-comment">/*! Non-secure MPU Region 6 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rbar7_ns; <span class="hljs-comment">/*! Non-secure MPU Region 7 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_mpu_rlar7_ns; <span class="hljs-comment">/*! Non-secure MPU Region 7 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_ctrl;
  <span class="hljs-type">uint32_t</span> cm33_sau_rbar0;<span class="hljs-comment">/*! SAU Region 0 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rlar0;<span class="hljs-comment">/*! SAU Region 0 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rbar1;<span class="hljs-comment">/*! SAU Region 1 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rlar1;<span class="hljs-comment">/*! SAU Region 1 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rbar2;<span class="hljs-comment">/*! SAU Region 2 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rlar2;<span class="hljs-comment">/*! SAU Region 2 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rbar3;<span class="hljs-comment">/*! SAU Region 3 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rlar3;<span class="hljs-comment">/*! SAU Region 3 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rbar4;<span class="hljs-comment">/*! SAU Region 4 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rlar4;<span class="hljs-comment">/*! SAU Region 4 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rbar5;<span class="hljs-comment">/*! SAU Region 5 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rlar5;<span class="hljs-comment">/*! SAU Region 5 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rbar6;<span class="hljs-comment">/*! SAU Region 6 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rlar6;<span class="hljs-comment">/*! SAU Region 6 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rbar7;<span class="hljs-comment">/*! SAU Region 7 Base Address Register */</span>
  <span class="hljs-type">uint32_t</span> cm33_sau_rlar7;<span class="hljs-comment">/*! SAU Region 7 Limit Address Register */</span>
  <span class="hljs-type">uint32_t</span> flash_rom_slave_rule;<span class="hljs-comment">/*! FLASH/ROM Slave Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> flash_mem_rule0;<span class="hljs-comment">/*! FLASH Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> flash_mem_rule1;<span class="hljs-comment">/*! FLASH Memory Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> flash_mem_rule2;<span class="hljs-comment">/*! FLASH Memory Rule Register 2 */</span>
  <span class="hljs-type">uint32_t</span> rom_mem_rule0;<span class="hljs-comment">/*! ROM Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> rom_mem_rule1;<span class="hljs-comment">/*! ROM Memory Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> rom_mem_rule2;<span class="hljs-comment">/*! ROM Memory Rule Register 2 */</span>
  <span class="hljs-type">uint32_t</span> rom_mem_rule3;<span class="hljs-comment">/*! ROM Memory Rule Register 3 */</span>
  <span class="hljs-type">uint32_t</span> ramx_slave_rule;
  <span class="hljs-type">uint32_t</span> ramx_mem_rule0;
  <span class="hljs-type">uint32_t</span> ram0_slave_rule;
  <span class="hljs-type">uint32_t</span> ram0_mem_rule0;<span class="hljs-comment">/*! RAM0 Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> ram0_mem_rule1;<span class="hljs-comment">/*! RAM0 Memory Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> ram1_slave_rule; <span class="hljs-comment">/*! RAM1 Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> ram1_mem_rule1;<span class="hljs-comment">/*! RAM1 Memory Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> ram2_mem_rule1;<span class="hljs-comment">/*! RAM2 Memory Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> ram3_mem_rule0;<span class="hljs-comment">/*! RAM3 Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> ram3_mem_rule1;<span class="hljs-comment">/*! RAM3 Memory Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> ram4_slave_rule;
  <span class="hljs-type">uint32_t</span> ram2_mem_rule0;
  <span class="hljs-type">uint32_t</span> ram3_slave_rule;
  <span class="hljs-type">uint32_t</span> ram1_mem_rule0;
  <span class="hljs-type">uint32_t</span> ram2_slave_rule;
  <span class="hljs-type">uint32_t</span> ram4_mem_rule0;<span class="hljs-comment">/*! RAM4 Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> apb_grp_slave_rule;<span class="hljs-comment">/*! APB Bridge Group Slave Rule Register */</span>
  <span class="hljs-type">uint32_t</span> apb_grp0_mem_rule0;<span class="hljs-comment">/*! APB Bridge Group 0 Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> apb_grp0_mem_rule1;<span class="hljs-comment">/*! APB Bridge Group 0 Memory Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> apb_grp0_mem_rule2;<span class="hljs-comment">/*! APB Bridge Group 0 Memory Rule Register 2 */</span>
  <span class="hljs-type">uint32_t</span> apb_grp0_mem_rule3;<span class="hljs-comment">/*! APB Bridge Group 0 Memory Rule Register 3 */</span>
  <span class="hljs-type">uint32_t</span> apb_grp1_mem_rule0;<span class="hljs-comment">/*! APB Bridge Group 1 Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> apb_grp1_mem_rule1;<span class="hljs-comment">/*! APB Bridge Group 1 Memory Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> apb_grp1_mem_rule2;<span class="hljs-comment">/*! APB Bridge Group 1 Memory Rule Register 2 */</span>
  <span class="hljs-type">uint32_t</span> apb_grp1_mem_rule3;<span class="hljs-comment">/*! APB Bridge Group 1 Memory Rule Register 3 */</span>
  <span class="hljs-type">uint32_t</span> ahb_periph0_slave_rule0;<span class="hljs-comment">/*! AHB Peripherals 0 Slave Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> ahb_periph0_slave_rule1;<span class="hljs-comment">/*! AHB Peripherals 0 Slave Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> ahb_periph1_slave_rule0;<span class="hljs-comment">/*! AHB Peripherals 1 Slave Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> ahb_periph1_slave_rule1;<span class="hljs-comment">/*! AHB Peripherals 1 Slave Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> ahb_periph2_slave_rule0;<span class="hljs-comment">/*! AHB Peripherals 2 Slave Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> ahb_periph2_slave_rule1;<span class="hljs-comment">/*! AHB Peripherals 2 Slave Rule Register 1 */</span>
  <span class="hljs-type">uint32_t</span> ahb_periph2_mem_rule0;<span class="hljs-comment">/*! AHB Peripherals 2 Memory Rule Register 0*/</span>
  <span class="hljs-type">uint32_t</span> usb_hs_slave_rule0; <span class="hljs-comment">/*! HS USB Slave Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> usb_hs__mem_rule0; <span class="hljs-comment">/*! HS USB Memory Rule Register 0 */</span>
  <span class="hljs-type">uint32_t</span> sec_gp_reg0;<span class="hljs-comment">/*! Secure GPIO Register 0 */</span>
  <span class="hljs-type">uint32_t</span> sec_gp_reg1;<span class="hljs-comment">/*! Secure GPIO Register 1 */</span>
  <span class="hljs-type">uint32_t</span> sec_gp_reg2;<span class="hljs-comment">/*! Secure GPIO Register 2 */</span>
  <span class="hljs-type">uint32_t</span> sec_gp_reg3;<span class="hljs-comment">/*! Secure GPIO Register 3 */</span>
  <span class="hljs-type">uint32_t</span> sec_int_reg0;<span class="hljs-comment">/*! Secure Interrupt Mask for CPU1 Register 0 */</span>
  <span class="hljs-type">uint32_t</span> sec_int_reg1;<span class="hljs-comment">/*! Secure Interrupt Mask for CPU1 Register 1 */</span>
  <span class="hljs-type">uint32_t</span> sec_gp_reg_lock;<span class="hljs-comment">/*! Secure GPIO Lock Register */</span>
  <span class="hljs-type">uint32_t</span> master_sec_reg;<span class="hljs-comment">/*! Master Secure Level Register */</span>
  <span class="hljs-type">uint32_t</span> master_sec_anti_pol_reg;
  <span class="hljs-type">uint32_t</span> cm33_lock_reg; <span class="hljs-comment">/*! CM33 Lock Control Register */</span>
  <span class="hljs-type">uint32_t</span> mcm33_lock_reg; <span class="hljs-comment">/*! MCM33 Lock Control Register */</span>
  <span class="hljs-type">uint32_t</span> misc_ctrl_dp_reg;<span class="hljs-comment">/*! Secure Control Duplicate Register */</span>
  <span class="hljs-type">uint32_t</span> misc_ctrl_reg;
  <span class="hljs-type">uint32_t</span> misc_tzm_settings;
} <span class="hljs-type">tzm_secure_config_t</span>;</code></pre></div></div><div class="paragraph"><p>An implementation detail of the ROM is that the settings for these registers
are (mostly) applied in the order shown in the structure. This means that the
very first register that gets changed is <code>VTOR</code> which switches the vector
table from the one in the ROM to the user provided one. <strong>Any faults that
occur after <code>VTOR</code> is changed will be handled by user code, not ROM
code.</strong> This turns out to have some "interesting" side effects.</p></div></div></div><div class="sect1"><h2 data-sectnum="">(Un)locking debug access</h2><div class="sectionbody"><div class="paragraph"><p>The LPC55S69 offers debug access via <a href="https://developer.arm.com/documentation/ihi0031/g/?lang=en">standard ARM interfaces (SWD)</a>.
Debug access can be configured to be always available, always disabled, or
only available to authenticated users. These settings are designed to be
applied at manufacturing time via the <a href="https://github.com/nxp-mcuxpresso/spsdk/blob/09c711a8fd4c54f126a7dfe1b3ae8bb361c5473e/spsdk/data/pfr/cmpa/lpc55s6x_1b.xml">CMPA</a> region.
Debugging is disabled by default while executing in the ROM and only enabled
(if allowed) as the very last step before jumping to user code. The debug
settings are also locked out, preventing further modification from user code
except in specific authenticated circumstances. Because debug access is highly
sensitive, it makes sense to minimize the amount of time the ROM spends with
it enabled.</p></div><div class="paragraph"><p>If the debug settings are applied last, this means that the TrustZone preset
settings must be applied before them. Combine this information with the
implementation detail of how the preset setting are applied, <strong>if the code
faults after <code>VTOR</code> is changed but before we apply the debug settings, it
will be possible to run in user controlled code with debug registers open
for modification</strong>.</p></div><div class="paragraph"><p>How easy is it to actually trigger this? Very easy. Other registers in the
preset structure include settings for the MPU. Setting the enable bit in
<code>MPU_CTRL</code> without any other regions set is enough to trigger
the fault. NXP actually says in their manual that you need to make sure
the entire ROM region is configured as secure privileged and executable
otherwise "boot process will fail". "fail" in this case is vectoring off
into the appropriate fault handler of the user code.</p></div><div class="paragraph"><p>This makes the following sequence possible:</p></div><div class="ulist"><ul class=""><li><p>Have debug disabled in the CMPA</p></li><li><p>Sign an image with TrustZone preset settings with a valid <code>VTOR</code> and MPU
settings that exclude the ROM region</p></li><li><p>Have the <code>MemManage</code> fault handler follow the standard sequence to enable
debugging</p></li><li><p>The image will trigger the fault handler and have debugging enabled despite
the settings in the CMPA</p></li></ul></div><div class="paragraph"><p>This does require access to the secure boot signing key, but it&#8217;s a departure
from the presentation of the CMPA settings as being independent of any
possible settings in an image.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Extracting the UDS</h2><div class="sectionbody"><div class="paragraph"><p>One additional step in the setting of the debug registers is a final lockout
of some PUF registers. The PUF (Physically Unclonable Function) is designed to
tie secrets to a specific chip. When a secret is PUF encoded, it can only
be decoded by that specific chip. The LPC55S69 uses the PUF to encode the
Unique Device Secret (UDS) for use as the basis of a <a href="https://trustedcomputinggroup.org/work-groups/dice-architectures/">DICE</a> identity.
To ensure the identity is tied to the specific chip and cannot be cloned,
access to the PUF index for the UDS is locked out after it is used.</p></div><div class="paragraph"><p>The UDS is always locked out for secure boot images, but the ROM relies on
the code path for debug settings to lock out for non-secure images.
TrustZone preset settings can be used with non-secure CRC images which means
that the previously described issue can be used to extract the UDS since the
final lockout will never occur.</p></div><div class="paragraph"><p>Requiring an unsigned image significantly limits the impact to
cases such as the following:</p></div><div class="ulist"><ul class=""><li><p>Attacker at manufacturing time runs ISP command to generate the UDS on an
unprogrammed LPC55S69</p></li><li><p>Attacker runs an unsigned image with a buggy TrustZone preset to extract the
UDS</p></li><li><p>Attacker continues on with the rest of the manufacturing sequence, making
sure not to re-generate the extracted UDS</p></li></ul></div><div class="paragraph"><p>This may be mitigated with sufficient tooling at manufacturing time but the
issue still remains.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Is this a security issue?</h2><div class="sectionbody"><div class="paragraph"><p>There was disagreement between Oxide and NXP about whether this qualified
as a true security vulnerability (Oxide&#8217;s opinion) vs. a gap in design and
documentation (NXP&#8217;s opinion). The areas of disagreement were related to what
exactly it was possible to do with these issues and what was
required to make them happen. Unlocking the debug ports requires access to the
secure boot signing keys and arguably if you can sign something with a bad
TrustZone preset you don&#8217;t need to bother with debug port access; once your
secure boot integrity has been compromised all bets are off. Oxide believes
this undersells the potential for mitigation and why this should be considered
a security issue: there could be circumstances where having debug port access
would make extracting assets significantly easier.</p></div><div class="paragraph"><p>Transparency is an Oxide value and that is what we strive for in bug reporting.
Our goal is to make sure that issues are acknowledged and information about
the bug is made widely available. NXP agreed to acknowledge this issue as
a non-security errata and there will not be a CVE filed at this time. Given
the narrow scope and lack of agreement between Oxide and NXP, filing a CVE
would provide <a href="https://daniel.haxx.se/blog/2023/08/26/cve-2020-19909-is-everything-that-is-wrong-with-cves/">little benefit</a>.
If new information were to come to light from Oxide, NXP, or other
researchers who are interested in our findings, we would re-evaluate this
decision.</p></div><div class="paragraph"><p>We are pleased that NXP is choosing to protect its customers by informing them
of this gap. A bigger takeaway from this issue is to understand the limitations
of secure/verified boot. A proper secure boot implementation will ensure that
the only code that runs on a device is code that has been signed with an
appropriate private key. Secure boot provides no assertions about the
implementation of that code. <strong>The strength of secure boot is bounded by the
code you choose to sign</strong>. In the absence of a fix for this errata, we will
not be using the TrustZone preset data. If other customers choose to continue
using TrustZone preset data they will need to be diligent about validating
their inputs to avoid introducing gaps in the security model. Oxide has a
commitment to open firmware to ensure our customers can have confidence in
what code we will be signing to run on their machines.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Timeline</h2><div class="sectionbody"><div class="sect2"><h3 data-sectnum="..">2023-08-16</h3><div class="sectionbody"><div class="paragraph"><p>Oxide discovers issue while reviewing image settings</p></div></div></div><div class="sect2"><h3 data-sectnum="..">2023-08-21</h3><div class="sectionbody"><div class="paragraph"><p>Oxide discloses issue to NXP PSIRT with a disclosure deadline of 2023-11-20</p></div></div></div><div class="sect2"><h3 data-sectnum="..">2023-08-21</h3><div class="sectionbody"><div class="paragraph"><p>Oxide PSIRT acknowledges receipt</p></div></div></div><div class="sect2"><h3 data-sectnum="..">2023-10-11</h3><div class="sectionbody"><div class="paragraph"><p>NXP requests meeting to discuss the report with Oxide</p></div></div></div><div class="sect2"><h3 data-sectnum="..">2023-10-19</h3><div class="sectionbody"><div class="paragraph"><p>Oxide and NXP meet to discuss the reported issues</p></div></div></div><div class="sect2"><h3 data-sectnum="..">2023-10-23</h3><div class="sectionbody"><div class="paragraph"><p>Oxide suggests documentation clarifications</p></div></div></div><div class="sect2"><h3 data-sectnum="..">2023-10-27</h3><div class="sectionbody"><div class="paragraph"><p>NXP agress to issue an errata</p></div></div></div><div class="sect2"><h3 data-sectnum="..">2023-11-20</h3><div class="sectionbody"><div class="paragraph"><p>Oxide publishes this blog post as a disclosure</p></div></div></div></div></div></div>]]></content>
        <author>
            <name>Laura Abbott</name>
        </author>
        <contributor>
            <name>Laura Abbott</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Cloud Computer]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/the-cloud-computer</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/the-cloud-computer"/>
        <updated>2023-10-26T09:00:00.000Z</updated>
        <summary type="html"><![CDATA[The world's first commercial cloud computer.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>Today we are announcing the general availability of the world&#8217;s first
commercial cloud computer — along with
<a href="https://oxide.computer/blog/oxide-unveils-the-worlds-first-commercial-cloud-computer">our $44M Series A financing</a>.</p></div><div class="paragraph"><p>From the outset at Oxide, and as I outlined in
<a href="https://www.youtube.com/watch?v=vvZA9n3e5pc">my 2020 Stanford talk</a>,
we have had three core beliefs as a company:</p></div><div class="olist arabic"><ol class="arabic"><li class=""><p>Cloud computing is the future of all computing infrastructure.</p></li><li class=""><p>The computer that runs the cloud should be able to be <strong>purchased</strong> and not
merely rented.</p></li><li class=""><p>Building a cloud computer necessitates a rack-level approach — and the
co-design of both hardware and software.</p></li></ol></div><div class="paragraph"><p>Of these beliefs, the first is not at all controversial: the agility,
flexibility, and scalability of cloud computing have been indisputably
essential for many of the services that we depend on in the modern economy.</p></div><div class="paragraph"><p>The degree that the second belief is controversial, however, depends on who you
are:  for those that are already running on premises due to security,
regulatory, economic, or latency reasons, it is self-evident that computers
should be able to be purchased and not merely rented.  But to others, this has
been more of a revelation — and since we started Oxide, we have found more and
more people realize that the rental-only model for the cloud is not
sustainable.  Friends love to tag us on links to
<a href="https://a16z.com/the-cost-of-cloud-a-trillion-dollar-paradox/">VC thinkpieces</a>,
<a href="https://world.hey.com/dhh/why-we-re-leaving-the-cloud-654b47e0">CTO rants</a>, or
<a href="https://www.idc.com/getdoc.jsp?containerId=IDC_P20184">analyst reports on
industry trends</a> — and we love people thinking of us, of course (even when
being tagged for the dozenth time!) — but the only surprise is how surprising
it continues to be for some folks.</p></div><div class="paragraph"><p>The third belief — that the development of a cloud computer necessitates
rack-scale design of both hardware <em>and</em> software — may seem iconoclastic to
those who think only in terms of software, but it is in fact not controversial
among technologists: as computing pioneer Alan Kay famously observed, "people
who are really serious about software should make their own hardware." This is
especially true in cloud computing, where the large public cloud companies
have long ago come to the conclusion that they needed to be designing their
own holistic systems.  But if this isn&#8217;t controversial, why hasn&#8217;t there been
a cloud computer before Oxide&#8217;s?  First, because <strong>it&#8217;s big</strong>:  to meaningfully
build a cloud computer, one must break out of the shackles of the 1U or 2U
server, and really think about the rack as the unit of design.  Second,
it hasn&#8217;t been done because <strong>it&#8217;s hard</strong>:  co-designing hardware and
software that spans compute, networking, and storage requires building an
extraordinary team across disparate disciplines, coupling deep expertise with
a strong sense of versatility, teamwork, and empathy.  And the team isn&#8217;t
enough by itself: it also needs courage, resilience, and (especially) time.</p></div><div class="paragraph"><p>So the biggest question when we set out was not "is the market there?" or "is
this the right way to do it?", but rather <strong>could we pull this off?</strong></p></div></div></div><div class="sect1"><h2 data-sectnum="">Pulling it off</h2><div class="sectionbody"><div class="paragraph"><p>We have indeed
<a href="https://oxide.computer/product/specifications">pulled it off</a> — and it&#8217;s been a
wild ride!  While we have talked about the trek quite a bit on our podcast,
<a href="https://oxide.computer/podcasts/oxide-and-friends">Oxide and Friends</a> (and
specifically, <a href="https://oxide.computer/podcasts/oxide-and-friends/1411249">Steve
and I recently answered questions about the rack</a>), our general availability
is a good opportunity to reflect on some of the first impressions that the
Oxide cloud computer has made upon those who have seen it.</p></div><div class="sect2"><h3 data-sectnum="..">"Where are all the boxes?"</h3><div class="sectionbody"><div class="paragraph"><p>The traditional rack-and-stack approach starts with a sea of boxes arriving
with servers, racks, cabling, etc.  This amounts to a literal
<a href="https://en.wikipedia.org/wiki/Kit_car">kit car</a> approach — and it starts with
tedious, dusty, de-boxing.  But the Oxide rack ships with everything installed
and comes in just <strong>one</strong> box — a crate that is
<a href="https://oxide.computer/podcasts/oxide-and-friends/1417751">its own feat of
engineering</a>.  All of this serves to dramatically reduce the latency from
equipment arrival to power on and first provision — from weeks and months to
days or even hours.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">"Is it on?"</h3><div class="sectionbody"><div class="paragraph"><p>We knew at the outset that rack-level design would afford us the ability to
change the geometry of compute sleds — that we would get higher density in the
rack by trading horizontal real estate for vertical.  We knew, too, that we
were choosing to use 80mm fans for their ability to move more air much more
efficiently — so much so that we leveraged
<a href="https://oxide.computer/blog/navigating-todays-supply-chain-challenges">our
approach to the supply chain</a> to partner with Sanyo Denki (our fan provider) to
lower the minimum speed of the fans from 5K RPM to the 2K RPM that we needed.
But adding it up, the Oxide rack has a surprising aesthetic attribute:  <strong>it is
whisper quiet.</strong>  To those accustomed to screaming servers, this is so
unexpected that when we were
<a href="https://oxide.computer/podcasts/oxide-and-friends/1200412">getting FCC
compliance</a>, the engineer running the test sheepishly asked us if we were sure
the rack was on — when it was dissipating 15 kW!  That the rack is quiet wasn&#8217;t
really deliberate (and we are frankly much more interested in the often hidden
power draw that blaring fan noise represents), but it does viscerally embody
much of the Oxide differentiation with respect to both rack-level design and
approach to the supply chain.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">"Where are the cables?"</h3><div class="sectionbody"><div class="paragraph"><p>Anyone accustomed to a datacenter will note the missing mass of cold-aisle
cabling that one typically sees at the front of a rack.  But moving to the back
of the rack reveals only a <a href="https://en.wikipedia.org/wiki/Busbar">DC busbar</a> and
a tight, cabled backplane.  This represents one of the bigger bets we made:
<a href="https://oxide.computer/podcasts/oxide-and-friends/1281318">we blindmated
networking</a>.  This was mechanically tricky, but the payoff is huge: capacity
can be added to the Oxide cloud computer simply by snapping in a new compute
sled — nothing to be cabled whatsoever!  This is a domain in which we have
leapfrogged the hyperscalers, who (for their own legacy reasons) don&#8217;t do it
this way.  This can be jarring to veteran technologists.  As one exclaimed upon
seeing the rack last week, "I am both surprised and delighted!" (Or rather:
a very profane variant of that sentiment.)</p></div></div></div><div class="sect2"><h3 data-sectnum="..">"You did your own switch too?!"</h3><div class="sectionbody"><div class="paragraph"><p>When we first started the company, one of our biggest technical quandaries was
what to do about the switch.  At some level, both paths seemed untenable:  we
knew from our own experience that integrating with third-party switches would
lead to exactly the kind of integration pain for customers that we sought to
alleviate — but it also seemed outrageously ambitious to do our own switch in
addition to everything else we were doing.  But as we have many times over the
course of Oxide, we opted for the steeper path in the name of saving our
customers grief, choosing to
<a href="https://oxide.computer/podcasts/oxide-and-friends/838572">build our own
switch</a>.  If it has to be said,
<a href="https://oxide.computer/podcasts/oxide-and-friends/1008496">getting it working
isn&#8217;t easy</a>!  And of course, building the switch is insufficient: we also
needed to <a href="https://oxide.computer/podcasts/oxide-and-friends/1231631">build our
own networking software</a> — to say nothing of the
<a href="https://oxide.computer/podcasts/oxide-and-friends/1333581">management network</a>
required to be able to manage compute sleds when they&#8217;re powered off.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">"Wait, <em>that&#8217;s</em> part of it?!"</h3><div class="sectionbody"><div class="paragraph"><p>It&#8217;s one thing to say that all of the software that one needs to operate the
cloud computer is built in — but it&#8217;s another to actually see what that
software includes.  And for many, it&#8217;s seeing the
<a href="https://github.com/oxidecomputer/console">Oxide web console</a> (or its
<a href="https://oxide-console-preview.vercel.app/">live demo</a>!) that really drives the
message home:  yes, <strong>all</strong> of the software is included.  And because the
<a href="https://oxide.computer/podcasts/oxide-and-friends/1426644">console
implementation</a> is built on the <a href="https://docs.oxide.computer/">public API</a>,
everything that one can do in the console for the Oxide rack is also available
via CLI and API — a concrete manifestation of our
<a href="https://www.youtube.com/watch?v=EmSjZbSzA3A">code-as-contract</a> approach.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">"And there&#8217;s no separate licensing?"</h3><div class="sectionbody"><div class="paragraph"><p>One common source of pain for users of on-prem infrastructure has been license
management: financial pain due to over-paying and under-utilizing, and
operational pain in the navigation of different license terms, different
expiration dates, unpredictable dependencies, and
<a href="https://www.theregister.com/2022/05/31/vmware_broadcom_acquisition_customer_reaction/">uncertain
vendor futures</a>.  From the beginning we knew that we wanted to deliver a
delightful, integrated experience:  we believe that cloud computers should come
complete with all system software built-in, and with no additional licensing to
manage or to pay for.  Bug fixes and new features are always only an update
away and do not require a multi-departmental discussion to determine value and
budget.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">"It&#8217;s all open source?"</h3><div class="sectionbody"><div class="paragraph"><p>While the software is an essential part of the Oxide cloud computer, what we
sell is in fact the computer.  As <a href="https://www.youtube.com/watch?v=um5bC20NTQ0">a
champion of open source</a>, this allows Oxide a particularly straightforward open
source strategy:  <a href="https://github.com/oxidecomputer/">our software is all open</a>.
So you don&#8217;t need to worry about hinky open core models or relicensing
surprises.  And from a user perspective, you are assured levels of transparency
that you don&#8217;t get in the public cloud — let alone the proprietary on-prem
world.</p></div></div></div></div></div><div class="sect1"><h2 data-sectnum="">Getting your own first impression</h2><div class="sectionbody"><div class="paragraph"><p>We&#8217;re really excited to have the first commercial cloud computer — and for
it to be generally available!  If you yourself are interested, we look
forward to it making its first impression on you —
<a href="https://oxide.computer/sales">reach out to us</a>!</p></div></div></div></div>]]></content>
        <author>
            <name>Bryan Cantrill</name>
        </author>
        <contributor>
            <name>Bryan Cantrill</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building Big Systems with Remote Hardware Teams]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/building-big-systems-with-remote-hardware-teams</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/building-big-systems-with-remote-hardware-teams"/>
        <updated>2023-03-08T15:30:00.000Z</updated>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>The product we&#8217;re building, a rack-scale computer, is specifically designed to
be a centralized, integrated product because that&#8217;s what our customers need.
This requirement and the design choices we&#8217;ve made to meet this need
create some daily efficiency challenges for our team. As a remote-first company,
we&#8217;re designing this product with team members (including the hardware team)
across most North American time zones and even multiple continents, so a large
portion of our team is not going into the office/lab every day for hands-on
access to "production" hardware. At first blush, the design of our product and
the design of our team appear to conflict at some level: we value remote work,
but we can&#8217;t ship entire racks to the homes of our teammates for both practical
and economic reasons.</p></div><div class="paragraph"><p>Our racks are rather inconvenient for a home installation: over 2.3 m (7.7')
tall, very heavy, and have 3-phase power inputs that aren&#8217;t usable in a typical
residential setting. Aside from the logistical challenges of a home
installation, there&#8217;s also the actual cost: these are expensive, and
outfitting each remote team member with a full, or even partially populated,
rack is economically infeasible. Further, a racked target is not terribly useful
for development, as accessing them for debugging is challenging: we
have no externally accessible debugging interfaces or other things that can be
repurposed as such because our customers don&#8217;t want that stuff! We can (and do!)
travel some to get hands-on with a full system, but it became clear early on in
the development cycle that we needed more convenient ways of being productive
remotely.</p></div><div class="paragraph"><p>Remote productivity on this design is a multi-faceted problem and the solution
includes robust remote access to fully-built and partially built systems back
at HQ, but that alone does not address all the needs.</p></div><div class="paragraph"><p>This post will deal more with the philosophy we have developed around our
non-product board designs as we&#8217;ve learned what works for us on our journey
through remote development. Some of these tools have become pivotal in
increasing our remote efficiency, especially early in the design cycle when the
"real" systems weren&#8217;t very functional and remote accessibility was limited.
For more board-by-board specifics, check out a great
<a href="https://oxide.computer/podcasts/oxide-and-friends/1173990">Oxide and Friends
episode</a> where we talked through the genesis of many of
these designs. With many of our team members who designed these
boards on-hand, it was a great discussion and a lot of fun talking about the
role prototypes have played in facilitating our actual product design.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Not a distraction from "real" product design</h2><div class="sectionbody"><div class="paragraph"><p>We fully believe that these small designs, most of which end up taking around a
week of engineering time to design, have <strong>radically</strong> accelerated or augmented
our "real" product designs. I detail a couple of specific examples of how this
prototype hardware helped us, from enabling software work before any "real"
hardware existed, to prototyping circuits like our multiplexed QSPI flash
design. Specifically for the QSPI design, the initial circuit just did not work
like we expected and using these boards we were able to quickly (and
inexpensively!) iterate on the design, directly informing the work on our "real"
designs, and in this case, likely saving a spin of our production hardware that
wouldn&#8217;t have worked. We were even able to connect our SPI mux to extant
development hardware from AMD and validate our assumptions before building a
server sled. The Oxide and Friends episode mentioned above covers some of these
and other stories in more detail.</p></div><div class="paragraph"><p>Our team fully embraces toolmaking up and down the stack: it informs many of our
design choices and directions. Bryan recently gave a
<a href="https://www.p99conf.io/session/sharpening-the-axe-the-primacy-of-toolmaking/">talk</a>
on the concept, and this is yet another application of it. Just like software
teams build tools to help build software, we&#8217;re building hardware tools to help
build hardware and software.</p></div><div class="paragraph"><p>To emphasize how pervasive this culture is in our company,
<a href="https://discord.com/channels/1042492311080288306/1064708202962354258/1064736636077867078">Dan</a>
made a great point during the Oxide and Friends chat:</p></div><div class="quoteblock"><blockquote>Anyone in the company is empowered to do this.</blockquote></div><div class="paragraph"><p>We don&#8217;t need approval or sign-off, we just go do what&#8217;s right for Oxide, and I
think this quote from
<a href="https://www.linkedin.com/feed/update/urn:li:activity:7022200431799934976?updateEntityUrn=urn%3Ali%3Afs_feedUpdate%3A%28V2%2Curn%3Ali%3Aactivity%3A7022200431799934976%29">Aaron</a>
really sums up our team&#8217;s viewpoint:</p></div><div class="quoteblock"><blockquote>Investments in tools pay off long-term and often faster than you&#8217;d think!</blockquote></div><div class="paragraph"><p>We&#8217;ve seen time and time again the effort put into these small boards has paid
back big dividends in team productivity, development ease, and bug chasing.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Why we needed custom hardware vs off-the-shelf development boards</h2><div class="sectionbody"><div class="paragraph"><p>There are multiple aspects to our need for custom hardware. First, the custom
designs supplement our use of off-the-shelf (OTS) hardware. We use <strong>many</strong>
off-the-shelf development boards and even provide
<a href="https://github.com/oxidecomputer/hubris#flash">support</a> for a number of these
boards in <a href="https://github.com/oxidecomputer/hubris">Hubris</a>. These are great for
many use-cases, but less great when we are trying to model specific circuits or
subsystems of our product designs. Second, we have numerous examples of custom
boards that were built simply because we could find no useful OTS alternative:
boards like the Dimmlet (I<sup>2</sup>C access to DDR4 SPD EEPROMs) and the K.2 (U.2 &#8594;
PCIEx4 CEM breakout) fall into this category.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/small-boards/dimmlet.webp?w=700 700w, https://oxide-computer.imgix.net//img/blog/small-boards/dimmlet.webp?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/small-boards/dimmlet.webp?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/small-boards/dimmlet.webp" alt="Narrow PMOD-interface board for interfacing with the SPD EEPROMs on the two installed DDR4 DIMMs"/></div><div class="title">Figure 1. Narrow PMOD-interface board for interfacing with the SPD EEPROMs on the two installed DDR4 DIMMs</div></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/small-boards/k2r2.webp?w=700 700w, https://oxide-computer.imgix.net//img/blog/small-boards/k2r2.webp?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/small-boards/k2r2.webp?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/small-boards/k2r2.webp" alt="PCIe U.2 connector to PCIe x4 CEM connector extender board"/></div><div class="title">Figure 2. PCIe U.2 connector to PCIe x4 CEM connector extender board</div></div></div></div><div class="sect1"><h2 data-sectnum="">Thriftiness in practice</h2><div class="sectionbody"><div class="paragraph"><p>While this strategy of developing prototypes touches on many Oxide values (as
discussed below), Thriftiness deserves special attention. Making inexpensive
hardware has never been easier! Quick-turn PCB houses, both offshore and
onshore, have achieved incredibly low cost while maintaining high quality. We
had 50 K.2r2 PCBs with impedance control and a framed stencil fabricated for
&lt;$400USD. For something so simple (BOM count &lt;10 parts) we built these in-house
using an open-source pick and place machine (Lumen PNP from
<a href="https://opulo.io/">Opulo</a>), and a modified toaster oven with a
<a href="https://www.whizoo.com/controleo3">Controleo3</a> controller. We&#8217;ve also done
hot-plate reflow and hand assembly. And while we will outsource assembly when it
makes sense due to complexity or volume, for these simple, low volume designs,
we see real benefits in self-building: we can build as few or as many as we
want, do immediate bring-up and feed any rework directly into the next batch,
and there&#8217;s no overhead in working with a supplier to get kitted parts there,
quotes, questions etc. A good example of this was on the Dimmlet: I messed up
the I<sup>2</sup>C level translator circuit by missing the chip&#8217;s requirements about
which side was connected to the higher voltage. Since I was hand-assembling
these, I built one, debugged it, and figured out the rework required to make it
function. Since this rework included flipping the translator and cutting some
traces, catching this issue on the first unit made reworking the remaining ones
<strong>before</strong> going through assembly much easier.</p></div><div class="paragraph"><p>All of that to say, the cost of building small boards is really low. A single
prototype run that saves a "real" board re-spin pays for itself immediately.
Enabling software development before "real" hardware lands pays for itself
immediately. Even when things don&#8217;t work out, the cost of failure is low; we
lost a few hundred dollars and some engineering time, but learned something in
the process.</p></div><div class="paragraph"><p>Because of this low cost, we can use a "looser" design process, with fewer
tollgates and a less formal review/approval process. This lowers the
engineering overhead required to execute these designs. We can have more
informal reviews, a light-weight (if any) specification and allow design
iteration to happen naturally. Looking at the designs, we have multiple examples
of design refinement like the K.2r2 which improved on the electrical and
mechanical aspects of the original K.2, and a refinement to the sled&#8217;s bench
power connector boards resulting in a more compact and ergonomic design that
improves mating with sleds in their production sheet metal.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Experience and the evolution of our strategy</h2><div class="sectionbody"><div class="paragraph"><p>Early in our company&#8217;s history, the team built out a development platform,
named the Gemini Bring-up board, representing the core of the embedded
design for our product-- our Gemini complex (Service Processor + Root of Trust<br>
Management Network plane). The resulting platform was a very nice development
tool, with hilarious silkscreen and some awesome ideas that have continued
informing current and future designs, but we rapidly outgrew this first design.
While the major choices held, such as which microcontrollers are present, the
still-nebulous design of the actual product, and subsequent design iteration,
left the periphery of the bring-up board bearing little resemblance to the
final Gemini complex design. The changes came from a variety of unforeseen
sources: the global chip shortage forced BOM changes and a better understanding
of the constraints/needs of our product necessitated architecture changes,
resulting in further drift between this platform and what we intended to
implement in the product.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/small-boards/gemini.webp?w=700 700w, https://oxide-computer.imgix.net//img/blog/small-boards/gemini.webp?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/small-boards/gemini.webp?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/small-boards/gemini.webp" alt="First custom Oxide hardware with SP"/></div><div class="title">Figure 3. First custom Oxide hardware with SP and RoT</div></div><div class="paragraph"><p>A re-imagining of what would be most useful gave way to the Gimletlet, a major
work-horse for in-house development, designed (and initially hot-plate reflowed) by
Cliff. The Gimletlet is essentially a development board using the STM32H7 part
that we&#8217;re using as our Service Processor (SP) in our product. It provides power
and basic board functionality including a couple of LEDs, and a dedicated
connector for a network breakout card, and breaks out most of the remaining I/O
to PMOD-compatible headers. This choice has been key to enabling a very modular
approach to prototyping, recognizing that less is more when it comes to
platforms. The Gimletlet design means that we can build purpose-built interface
cards without needing to worry about network connectivity or processor support,
simplifying the design of the interface cards and able to share a core board
support package.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/small-boards/gimletlet.webp?w=700 700w, https://oxide-computer.imgix.net//img/blog/small-boards/gimletlet.webp?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/small-boards/gimletlet.webp?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/small-boards/gimletlet.webp" alt="Custom STM32H7 board with I/O breakout to many PMOD interfaces"/></div><div class="title">Figure 4. Custom STM32H7 board with I/O breakout to many PMOD interfaces</div></div><div class="paragraph"><p>Our team has learned that modularity is key to making these small proto-boards
successful. It does mean workspaces can get a little messy with a bunch of
boards connected together, but we&#8217;ve found this to be a good balance, allowing
our team members to cobble together a small, purpose-built system that meets
their specific needs, and allows us to easily share these common, low-cost
setups to our distributed team. The modularity also means that storing them is
relatively easy as they can be broken down and stashed in small boxes.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/small-boards/gimletlet-and-periphs.webp?w=700 700w, https://oxide-computer.imgix.net//img/blog/small-boards/gimletlet-and-periphs.webp?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/small-boards/gimletlet-and-periphs.webp?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/small-boards/gimletlet-and-periphs.webp" alt="Gimletlet with Igntionlet"/></div><div class="title">Figure 5. Gimletlet with Igntionlet, SPI MUx, Dimmlet, RoTCarrierCarrier, and RoTCarrier connected</div></div></div></div><div class="sect1"><h2 data-sectnum="">Our values tie-ins</h2><div class="sectionbody"><div class="paragraph"><p>There are some obvious <a href="/principles#values">values</a> tie-ins like teamwork and
thriftiness as already mentioned, but as I started writing this section I
realized we hit more of our values than I had even realized. Rather than attempt
to enumerate each one, I wanted to hit on some maybe less-obvious ones:</p></div><div class="ulist"><ul class=""><li><p>Humor: The silkscreens on our boards contain jokes, word-play and other
silliness because we enjoy making our co-workers laugh and want our work to be
fun too. The funny silkscreen is often snuck in post-review, and thus
a surprise to co-workers as they open the finished hardware.
Engineering demands creativity — I&#8217;ve worked at places where silliness baked
into a board would be frowned upon, but at Oxide it is supported and even
encouraged! This enables team members to bake a little bit of their personality
into these designs, while allowing the rest of the team to have fun as it&#8217;s
discovered.</p></li></ul></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/small-boards/gemini-rot-zoom.webp?w=700 700w, https://oxide-computer.imgix.net//img/blog/small-boards/gemini-rot-zoom.webp?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/small-boards/gemini-rot-zoom.webp?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/small-boards/gemini-rot-zoom.webp" alt="Gemini Bring up board with silkscreen riffing on Root of Trust vs Route of Trust vs Newt of Trust as well as pointing out the untrustworthiness of vendor boot ROMs"/></div><div class="title">Figure 6. Preview of Gemini Bring up board</div></div><div class="ulist"><ul class=""><li><p>Rigor/Urgency: We often find Rigor and Urgency in tension with each other,
but in this case, they are complementary. The time from concept to ordering of
a PCB on some of these designs is measured in hours or days, not weeks. Being
able to move quickly from a paper concept to a physical manifestation of that
concept in real hardware has been instrumental in grounding our assumptions and
informing our designs. We&#8217;re able to quickly iterate in areas where we have
questions, driving resolution without holding up the rest of the design. This
work directly contributes to better architecture and circuit design decisions
in our "real" designs.</p></li><li><p>Transparency/Responsibility/Teamwork: We believe in openness, including our
own designs, so we&#8217;re opening up the various proto-board design repositories
for reference and hope that something there is useful in your own hardware
endeavors. These designs are things that we wished existed and so created them,
some of these may be a bit specific for our use-cases, but there are some
generally useful things there too. These are mostly KiCAD designs and support
for them is "as-is" since we&#8217;re focused on getting our product out the door,
but feel free to reach out in the repo with questions and we&#8217;ll attempt to
answer on a best-effort basis.</p></li></ul></div></div></div><div class="sect1"><h2 data-sectnum="">Our open source hardware repos</h2><div class="sectionbody"><div class="ulist"><ul class=""><li><p><a href="https://github.com/oxidecomputer/gemini-bringup">gemini-bringup</a></p></li><li><p><a href="https://github.com/oxidecomputer/hw-lpc55-carrier">RoT-Carrier and Carrier-Carrier</a></p></li></ul></div><div class="sect2"><h3 data-sectnum="..">Gimletlets + peripherals</h3><div class="sectionbody"><div class="ulist"><ul class=""><li><p><a href="https://github.com/oxidecomputer/hw-gimletlet">Gimletlets (v1 + 2)</a></p></li><li><p><a href="https://github.com/oxidecomputer/hw-ignitionlet">Ignitionlet</a></p></li><li><p><a href="https://github.com/oxidecomputer/hw-spimux">SPI-mux</a></p></li><li><p><a href="https://github.com/oxidecomputer/hw-dimmlet">Dimmlet</a></p></li><li><p><a href="https://github.com/oxidecomputer/hw-gimletlet-nic">GimletletNIC</a></p></li></ul></div></div></div><div class="sect2"><h3 data-sectnum="..">Other designs</h3><div class="sectionbody"><div class="ulist"><ul class=""><li><p><a href="https://github.com/oxidecomputer/hw-k2">k.2</a></p></li><li><p><a href="https://github.com/oxidecomputer/hw-samtec-dbg">debug header breakout</a></p></li><li><p><a href="https://github.com/oxidecomputer/hw-ignition-adapter">iceprog-compatible adafruit breakout</a></p></li></ul></div></div></div></div></div></div>]]></content>
        <author>
            <name>Nathanael Huffman</name>
        </author>
        <contributor>
            <name>Nathanael Huffman</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[A Tool for Discussion]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/a-tool-for-discussion</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/a-tool-for-discussion"/>
        <updated>2023-02-02T17:00:00.000Z</updated>
        <summary type="html"><![CDATA[Showcasing a hub for knowledge sharing and collaboration that drives our decision-making process.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>At Oxide, RFDs (Requests for Discussion) play a crucial role in driving our architectural and design decisions. They document the processes, APIs, and tools that we use. The workflow for the RFD process is based upon those of the Golang proposal process, Joyent RFD process, Rust RFC (Request for Comments) process, and Kubernetes proposal process. To learn more about RFDs and their process, you can read <a href="https://oxide.computer/blog/rfd-1-requests-for-discussion">this post</a>.</p></div><div class="quoteblock"><blockquote><div class="paragraph">
<p>Similar to RFCs, our philosophy of RFDs is to allow both timely
discussion of rough ideas, while still becoming a permanent repository
for more established ones.</p>
</div></blockquote></div><div class="paragraph"><p>Oxide RFDs are essentially a collection of AsciiDoc documents, collected in a GitHub repo. They can be quickly iterated on in a branch, discussed actively as part of a pull request to be merged, or commented upon after having been published.</p></div><div class="paragraph"><p>Whilst a repo is a useful storage and collaboration tool, there are a number of drawbacks: it doesn&#8217;t provide the best reading experience, is limited in terms of AsciiDoc support, and is challenging to share externally. To address these issues we developed an internal RFD site. This post serves as showcase for that site and gives a brief look at some of its features.</p></div></div></div><div class="sect1"><h2 data-sectnum="">RFD directory</h2><div class="sectionbody"><div class="paragraph"><p>Users land directly on the directory. By default it is sorted by last updated to give the user an idea of the RFDs that are actively being worked on.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-directory.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-directory.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-directory.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/rfd-site/rfd-site-directory.png" alt="RFD site homepage"/></div></div><div class="sect2"><h3 data-sectnum="..">Full-text search</h3><div class="sectionbody"><div class="paragraph"><p>Full-text search is powered by a self-hosted <a href="https://www.meilisearch.com/">Meilisearch</a> instance. The search index is automatically updated whenever an RFD is edited. Users can access the search function through the navigation menu or by using the hotkey <code>CMD+K</code> and can quickly navigate through the search results using their keyboard whilst previewing the associated RFD.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-search.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-search.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-search.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/rfd-site/rfd-site-search.png" alt="Search dialog showing results and a preview of the matched RFD"/></div></div></div></div><div class="sect2"><h3 data-sectnum="..">Inline PR discussion</h3><div class="sectionbody"><div class="paragraph"><p>The discussion surrounding an RFD is crucial to understanding its context, but until recently users would have to open the associated pull request in a separate tab to view its comments. To improve this experience, we&#8217;ve implemented a feature that uses the GitHub API to fetch the pull request discussion and display the comments that are still actively attached to a line alongside the part of the document they relate to.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-inline-comments-2.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-inline-comments-2.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-inline-comments-2.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/rfd-site/rfd-inline-comments-2.png" alt="Pop-over menu with comments that relate to the part of the document they are next to"/></div><div class="title">Figure 1. Inline comments</div></div><div class="paragraph"><p>We achieve this by using the <code>getLineNumber</code> function in <code>asciidoctor.js</code>, which allows us to map the raw line number of the comment (from the GitHub API) to the nearest block in the rendered document. While this method may not pinpoint the exact line, it is usually accurate enough.</p></div><div class="paragraph"><p>To avoid slowing down page load times, we use the Remix <a href="https://remix.run/docs/en/v1/guides/streaming">deferred response</a> feature to stream in the comments asynchronously, holding only for the critical RFD content to finish loading.</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code class="language-ts" data-lang="ts">  <span class="hljs-keyword">const</span> rfd = <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetchRfd</span>(num, user)
  <span class="hljs-keyword">if</span> (!rfd) <span class="hljs-keyword">throw</span> <span class="hljs-title function_">resp404</span>()

  <span class="hljs-comment">// this must not be awaited, it is being deferred</span>
  <span class="hljs-keyword">const</span> discussionPromise = <span class="hljs-title function_">fetchDiscussion</span>(rfd.<span class="hljs-property">discussion_link</span>, user)

  <span class="hljs-keyword">return</span> <span class="hljs-title function_">defer</span>({ rfd, discussionPromise })</code></pre></div></div><div class="paragraph"><p>Users can access the full discussion of an RFD at any time by opening a dialog regardless of their current location on the page. This dialog also provides the ability to jump directly to the line that is being commented on.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-discussion.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-discussion.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-site-discussion.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/rfd-site/rfd-site-discussion.png" alt="Dialog with a GitHub PR style timeline showing comments and snippets of the raw document"/></div><div class="title">Figure 2. Full discussion</div></div></div></div><div class="sect2"><h3 data-sectnum="..">Inter-RFD linking</h3><div class="sectionbody"><div class="paragraph"><p>When an RFD document references another RFD within its content, the user can hover over the reference to see a preview of the title, authors, status, and the date of the last update. This makes it easy for users to understand the context and relationship between different RFDs, and quickly access the related documents.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-inter-link.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-inter-link.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-inter-link.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/rfd-site/rfd-inter-link.png" alt="Pop-over that previews the linked RFD"/></div></div></div></div><div class="sect2"><h3 data-sectnum="..">Jump-to menu</h3><div class="sectionbody"><div class="paragraph"><p>For users who know the title or number of the RFD they want to view, a menu can be opened by pressing <code>CMD+/</code> from any page on the site. This menu allows users to quickly filter and select the desired RFD using their keyboard.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-jump-to.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-jump-to.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/rfd-site/rfd-jump-to.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/rfd-site/rfd-jump-to.png" alt="Navigation modal that shows a list of RFDs being filtered by an input"/></div></div></div></div></div></div><div class="sect1"><h2 data-sectnum="">Upcoming</h2><div class="sectionbody"><div class="paragraph"><p>The internal tooling around RFDs is always improving, and as it does, we hope that the way we collaborate will also improve. There is still work to be done in terms of discoverability of documentation, such as adding more tools to filter and tag RFDs, and creating collections of documents. This will make it easier for new employees to get up to speed, and make it easier to manage the challenges that come with a growing team and an increasing amount of documentation. Having a better understanding of the whole stack is valuable, as it allows us to better understand the impact of our work on other parts of the product.</p></div><div class="paragraph"><p>Additionally, we need to consider how we can make this process more accessible to everyone. Writing an RFD currently requires cloning a Git repo, running a script, committing, pushing, and making a PR. We are thinking about how to do this all through the web app with an embedded text editor. Oxide is and will continue to be an engineering-led organization, but RFDs are not just for engineers. Making it easier for everyone to create and collaborate on these documents will result in richer conversations.</p></div></div></div></div>]]></content>
        <author>
            <name>Ben Leonard</name>
        </author>
        <contributor>
            <name>Ben Leonard</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Navigating Today’s Supply Chain Challenges]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/navigating-todays-supply-chain-challenges</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/navigating-todays-supply-chain-challenges"/>
        <updated>2022-09-08T17:00:00.000Z</updated>
        <summary type="html"><![CDATA[The tale of a small tech startup navigating procurement in the most constrained market in recent history.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>We’ve all experienced it. From toilet paper, exercise equipment, toys, cars, and everything in between, the supply chain during COVID has been blamed for many consumer goods shortages, and rightfully so. During lockdown, how many of us stalked our local warehouse clubs for that elusive delivery of toilet paper, scared of the implications if none was found? Or maybe you tried negotiating the price on eBay for a set of weights that was 3-4x the usual cost? Those shortages seen by the average consumer also heavily plagued electronics manufacturers and their customers as well.</p></div><div class="paragraph"><p>Now imagine being a start-up during COVID. A start-up in the electronics industry. A start-up in competition for those highly demanded, severely constrained electronic components. A start-up with no name recognition, no history, and no relationships with manufacturers and / or distributors. Seemingly simple items like capacitors and resistors saw 20+ week lead times, with other parts advertising lead times of 52, 98, and even 104+ weeks. That’s what the supply chain looked like for Oxide in 2021, and in many component categories, still looks like today.</p></div><div class="paragraph"><p>Our Operations Team has been hard at work since late 2020 trying to secure supply for a product that, throughout 2021 and into 2022, has continued to undergo design changes. The procurement function became a delicate balancing act taking into account lead time, cost, industry outlooks, and working closely with our engineering team regarding upcoming design changes. How much faith could we put in the demand for a given part today, when we knew an updated Bill of Materials (BOM) would be published in a few weeks? For parts with lead times that would extend past our first customer ship date, how much supply should we purchase 12-18 months ahead of schedule, knowing our design was not finalized? Working with borrowed money (literally, from our investors), we needed to quickly put in place a robust procurement system to balance the issues we faced. We needed an actionable plan that solved supply issues on many fronts. So, we did what the average consumer did during COVID; we stalked the stores (in our case, online distributors) day and night, weekdays and weekends waiting for restocks. We negotiated with suppliers, investigating whether there was additional inventory available but being held back. In some cases, being a start-up and only needing small quantities was helpful. We were able to get sample quantities of parts that would last us through our engineering build cycle. However, being a small start-up also meant we were up against the big guys. Getting recognition of our existence, let alone inventory allocated to us, was often a stressful, tedious process. What have we found that helped our team the most? Strategic supplier relationships.</p></div><div class="paragraph"><p>There is not enough that can be said for setting up strong, trusting relationships with your suppliers. All of us on the Operations Team at Oxide have extensive backgrounds at some of the world’s top manufacturing and supply chain companies. We’ve seen and heard it all. We know the lengths many procurement professionals will go to in order to secure supply during allocations. They may inflate demand knowing their allocation quantity is based on their demand, or they may communicate required dates that are several weeks or months ahead of when the supply is actually needed. However, those responsible for the supply allocations usually realize this. When the truth comes to light, that company’s future demand is often taken with a grain of salt. It becomes difficult to trust that company again. That’s where the Oxide Ops Team differentiate ourselves. Oxide’s principles and values truly drive our everyday work. We’re firmly committed to our principles of Integrity, Honesty, and Decency, and integrate them into all of our business practices. We strive to balance our sometimes conflicting values in order to strengthen our vendor relationships. Here are a few of the Oxide values and how we showcase them in our supply chain relationships.</p></div><div class="ulist"><ul class=""><li><p><strong>Candor</strong> — We’re upfront about our needs, including quantities and dates. As these items change, we do our best to proactively communicate those changes to our suppliers. We know there will be times we need our suppliers to jump through hoops for us, to expedite, to get supply not otherwise allocated to us. However, we also understand these should be one-off instances and not the norm. We want our supplier reps to succeed just as much as we strive for success at Oxide. Being candid helps ensure we are all set up for success.</p></li><li><p><strong>Rigor</strong> — We demand a lot from ourselves, but we also demand a lot from our suppliers. If a date slips or the component quality isn’t as expected, we request our supplier proactively communicate, root cause, and implement corrective action as needed. We have a small team and we rely on our suppliers to have the same sense of rigor as we do at Oxide.</p></li><li><p><strong>Teamwork</strong> — We look at the relationships with our suppliers as extended team members. We want to instill in them a sense of pride for the Oxide product, just as much as we support them and their company. Successes and failures are shared amongst everyone involved. We will not be successful at Oxide without our extended team.</p></li><li><p><strong>Thriftiness</strong> – We’re a start-up with maniacally focused founders, a very involved board of directors, and limited capital. We’re building a massive product while being very cognizant of costs. Given our small size and start-up status, we rely on our relationships with our suppliers, coupled with massive amounts of internet searching and price comparing, to try and get the best costs we can. We know we’re paying more for items than the big guys, but we’re trying to close that gap as much as we can. Getting our suppliers on board with our vision, and getting them excited about the Oxide rack, is instrumental in price negotiations. We’re also sure that one day we’ll be one of those big guys. :)</p></li></ul></div><div class="paragraph"><p>Aligning ourselves with suppliers we can trust and partners invested in the success of Oxide has allowed us to successfully navigate the current supply chain conditions. Treating others with respect and kindness cannot be underestimated. Building strong relationships on an unfaltering basis of Integrity, Honesty and Decency is key. Adhering to our principles and balancing our values will continue to drive our successes.</p></div></div></div><div class="sect1"><h2 data-sectnum="">When Allocation Hits the Fan</h2><div class="sectionbody"><div class="paragraph"><p>Allocation. A term no supply chain professional wants to hear. Even more so when you’re a start-up in a critical test phase of your new product which has yet to launch. Founders, investors, manufacturing partners and others, all anxious for an update. That timing device, tiny in size, but mighty in nature, gating your entire build process. Your product can’t run without it. There are no suitable alternates and there is no supply via your normal channels. There is, however, a large supply showing in the broker market. Over 100K. <em>Wow, score!</em> You may have just solved your high-profile supply constraint. Now the only thing left to decide is which of these companies will get your business.</p></div><div class="paragraph"><p>Before you get too excited though, you need to pause, step back, and analyze the situation. Could there really be over 100K of this highly constrained part on the broker market? That $0.38 part is showing for between $1.10 and $7.08 on the broker market. How could there be that much variation? Is the higher priced part <em>“real”</em> while the lower priced part possibly counterfeit or stolen? What would happen if you were to receive a counterfeit part? The brokers typically all provide some sort of generic <em>“guarantee”</em> on their website. How bad could it be? You could order the part, have it tested, realize it’s not real and get your money back, right? Sounds easy, though it rarely is. From reading reviews of brokers, speaking with people who have had bad experiences, and my own search for broker parts, many of the broker websites are not legitimate. Embrace your inner pessimist and begin your search being wary of everyone. While there are certain countries which automatically throw up red flags, there are also plenty of US based companies I wouldn’t consider doing business with. It’s ok to be pessimistic now and then. You need to protect your company, your product, and your reputation. What sorts of issues could you face with parts purchased from a broker? You could end up with parts that have old date codes, have not been stored correctly in humidity controlled / ESD bags, damaged, or downright counterfeit. Things to look for when evaluating an online broker:</p></div><div class="olist arabic"><ol class="arabic"><li class=""><p><strong>Misspellings &amp; Poor Grammar.</strong> Sure, we all make mistakes from time to time. I had to make sure <em>“misspellings”</em> was spelled correctly! However, a professional website should not have misspellings, blatant grammar issues or obviously poor translation.</p></li><li class=""><p><strong>Authorized Distributor Claims.</strong> Make sure to go to the actual manufacturer’s website and look up their authorized distributors. If a broker claims they are authorized and aren’t listed, do not order anything, ever.</p></li><li class=""><p><strong>100% Guaranteed Claims – Authenticity, Quality, etc.</strong> Read the superfine print. Understand what is being guaranteed. A phrase such as “guaranteed to function like original part” should make you pause given use of the word <em>“like”</em>. Most sites seem to offer some feel-good blurb on how they’ve had the parts tested in-house or by a third-party tester and results are available. What are the qualifications of the tester? What were they testing? Some websites will even tell you they support you having the part tested. If your tests show the part is not original, you can return the part with your test data. However, reading deeper into their return policy, often found in a different section of their website, will reveal that you cannot return any part that has been opened and / or is not the full quantity ordered. Return windows may also be abnormally short, not affording you enough time to test the parts. Unfortunately for you, in order to perform a physical and electrical verification, you must open the packaging and use several for testing purposes. You have now invalidated your ability to return the part.</p></li><li class=""><p><strong>Payment Terms</strong> – Be extremely cognizant of payment terms, types of payment accepted, and the entity you are paying. Research the payee and bank information. There are certain payment methods that are more secure and better for this type of transaction than others.</p></li><li class=""><p><strong>Do Your Research</strong> – Spend some time reading online reviews. Take note of who / where any good reviews are coming from. Pay closer attention to the negative reviews. While it’s true more people are likely to leave a negative review than a positive review, if you see consistency in the negative reviews, it’s probably best to move along. Common negative reviews of brokers include no communication after payment sent, payment sent and part not actually in stock, payment sent and part not received, and parts do not work as expected (old date code, damaged, counterfeit). A quick search can open your eyes to a lot of questionable activities!</p></li></ol></div><div class="paragraph"><p>After checking out many of the websites showing stock on the part you desperately need, you’re back to square one. You’ve realized you can’t possibly trust one of these unheard-of websites to provide an instrumental component in your product. You’ve spoken with the manufacturer and distributors and nothing is available, not even samples. What next? Give up? Tell your founders and investors the timeline is in jeopardy and all forward progress must come to a halt? None of those sound like great alternatives.</p></div><div class="paragraph"><p>I’m blessed in that I have a history in the broker market from a previous job in the computer industry. I’ve been exposed to all sorts of people and stories, some that make you just shake your head in disbelief. I already have the handful of people I feel comfortable and enjoy working with. These are a few areas I look at when deciding to work with any broker.</p></div><div class="olist arabic"><ol class="arabic"><li class=""><p><strong>Certifications (ISO, OSHA, R2, eStewards, etc)</strong> – While these certifications are typically for manufacturers and / or refurbishers, it gives me a sense of comfort in knowing that a company has achieved any of these certifications. Can a certification be <em>“bought”</em>? Sure, though no one involved would admit it. Don’t make this your only deciding factor but do take it into account. Physical site visits can help clarify any outstanding questions.</p></li><li class=""><p><strong>Length of Time in Business</strong> – The good ones survive the times. Some not-so-great ones survive as well. Some new ones have yet to make a name for themselves but may be great options and provide amazing customer service. Or, they may cut corners to try and increase the bottom line. Do your research and talk to respected members of the secondary market community.</p></li><li class=""><p><strong>Reputation</strong> – Not everyone will agree on a binary assignment of <em>“good”</em> or <em>“bad”</em> for a company. Again, speak with people in the industry about the company, its leadership, and its employees. Do your research on how the company started, how they’ve grown and changed over time, employee turnover, focus for the future, etc.</p></li><li class=""><p><strong>Component Testing</strong> – As we’ve seen, many companies say they do component testing to verify legitimacy of a part. Ask questions, ask to see sample reports, inquire where they do their testing (in-house, 3rd party), etc. You may even consider asking if you can be present during the testing. You can learn a lot from how that question is answered, even if you don’t plan on actually being present.</p></li><li class=""><p><strong>Warranty</strong> – Do they offer the same level of warranty as the manufacturer? What is covered by the warranty? How are warranty claims made?</p></li><li class=""><p><strong>Trust</strong> – Trust the people you’re going to be working with and choose people you’re going to enjoy working with. There are a lot of good brokers out there, so you do have options. Find one you sync with, and the relationship will be off to a positive start.</p></li></ol></div><div class="paragraph"><p>In the end, choosing a broker to work with is both a tactical and personal choice. We don’t often get to choose who we work with, but when presented with an opportunity to do so, make sure you choose wisely. The quality and security of your product depend on it, and oftentimes, so does your sanity.</p></div></div></div></div>]]></content>
        <author>
            <name>Kate Hicks</name>
        </author>
        <author>
            <name>Kirstin Neira</name>
        </author>
        <contributor>
            <name>Kate Hicks</name>
        </contributor>
        <contributor>
            <name>Kirstin Neira</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Benefits as a Reflection of Values]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/benefits-as-a-reflection-of-values</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/benefits-as-a-reflection-of-values"/>
        <updated>2022-04-20T18:00:00.000Z</updated>
        <summary type="html"><![CDATA[Our values drive us to provide the best benefits we can find, and then some.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div class="paragraph"><p>“We offer the best health insurance we could find” is what we promise in <a href="https://oxide.computer/careers">our job postings</a>. On paper, this is accurate: the health insurance Oxide offers is the best plan we can find that is offered to small businesses.</p></div><div class="paragraph"><p>What we left unsaid until now is that the best health insurance offered to small businesses is, in fact, not very good at all if you don’t neatly fit into a narrow demographic; the bitter irony is that the US healthcare system isn’t designed for those of us who rely on it the most. And life-saving treatments that aren’t needed by able-bodied cisgender people are, more often than not, deemed “not medically necessary” in off-the-shelf insurance policies simply because there is no law to require their coverage. In our society’s bizarre and accidental system, we rely on employers to provide benefits everyone should have, including healthcare, retirement plans, and dependent care.</p></div><div class="paragraph"><p>When I came out as trans and started seeking medical care, I worked at a large employer that directly paid for the medical costs of its employees and dictated how their insurance networks process claims. I had the benefits I needed because other trans people fought for them and the company could unilaterally choose to provide them. Startups don’t have this luxury and are at the whims of insurance companies to keep the cost of hiring and retaining employees manageable. Meanwhile, insurers put profit over care, and won’t budge on off-the-shelf benefits plans unless Congress forces the issue – yet as I write this, lawmakers across the country are either ignoring us or actively stripping away our right to get the healthcare we need, so we’re not holding our breath.</p></div><div class="paragraph"><p>With this in mind, I was initially uneasy about applying to Oxide because we didn’t make our benefits clear to prospective applicants. But I still applied — not out of blind faith, but because I felt a company built on <a href="https://oxide.computer/principles">these values</a> would put its people first and work to provide what I needed. Shortly after I started, despite insurance companies not budging even an inch, our CEO Steve announced a reimbursement arrangement that would cover $10,000 of out-of-pocket healthcare expenses for gender-related healthcare per year. This isn’t perfect, but it’s a damn good start.</p></div><div class="paragraph"><p>Future applicants shouldn’t need to put this much faith in us upholding our values in order to be comfortable about applying, though. Here’s a much clearer summary of our benefits:</p></div><div class="ulist"><ul class=""><li><p>We offer the best medical, dental, and vision insurance plans we can find as a small employer; premiums are 100% paid by Oxide for both employees and dependents.</p></li><li><p>We offer an optional FSA plan for out-of-pocket healthcare and dependent care expenses.</p></li><li><p>We reimburse (through an HRA) up to $17,000 annually: $10,000 annually for gender affirmation or infertility expenses, $5,000 annually for hearing and laser eye surgery expenses, and $2,000 annually for dental and miscellaneous healthcare expenses. The HRAs cover out-of-pocket expenses regardless of whether insurance covers them partially or not at all.</p></li></ul></div><div class="paragraph"><p>The bottom line: Where our insurers fall short, we will work to meet our employees where they need us to be.</p></div><div class="paragraph"><p>As with <a href="https://oxide.computer/blog/compensation-as-a-reflection-of-values">our compensation model</a>, the benefits we provide embody <a href="https://oxide.computer/principles">our mission, principles, and values</a>: We can’t focus on our mission if we’re distracted by healthcare expenses. Our principles of integrity, honesty, and decency compel us to care for our teammates and their families. And our approach to benefits intersects with several of our values:</p></div><div class="ulist"><ul class=""><li><p>It is driven by our empathy. Even if we don’t have the context for someone else’s needs, we don’t need it: none of us ever want to have to worry about healthcare expenses for ourselves, our partners, or our families, and we wouldn’t wish it on each other. We understand that this approach is necessary and important, even if some of us don’t directly benefit.</p></li><li><p>It is a step toward building a more diverse team. In this regard, we are not meeting the same standard to which we hold ourselves with our other values. We strive to change that by embracing the needs of our current team as well as those of prospective future teammates. Benefits are a critical part of what employers bring to the table for candidates, and we don’t want to inhibit people from applying to Oxide because of the perception that small companies can only provide meager coverage that doesn’t work for them. While <a href="https://oxide.computer/blog/compensation-as-a-reflection-of-values">our compensation model</a> ensures we have no pay gap, our approach ensures that people relying more on these vital benefits are still getting paid the same as their peers. Every member of the team has different needs, and we will do our best to address as many of them as we can.</p></li><li><p>It is a reflection of our resilience. We will do everything within our power to take care of our employees. We will continue to fight our insurers to provide for basic healthcare needs, and when they fall short, we will find other ways to provide for those needs (such as offering HRAs) while we continue to fight. We will never stop advocating for our employees.</p></li><li><p>It is a fundamental responsibility to our teammates. We don’t treat healthcare benefits as a “perk”: it is a basic need for all of us. And while it is tiring to continue to fight against an uncaring and unwavering healthcare system only to make incremental progress, we know that we must do so to keep our mission in sight.</p></li></ul></div><div class="paragraph"><p>Finally, in the spirit of transparency: we’ve made <a href="https://drive.google.com/drive/folders/1WJs_tIFlpTOiJK4dI5KnuX_aamoVMXrY">our benefits information public</a> starting today. These are close to the same documents employees see when signing up for benefits (with some information only relevant for employees removed). We’re working to provide additional information for specific situations that we’re aware of — and we know that our benefits are not complete; there are innumerable needs none of us have experienced or thought of.</p></div><div class="paragraph"><p>We share our benefits information for two important reasons: first, we want applicants to be able to learn everything we know about our benefits so that they feel confident in applying even in the face of a healthcare need that is not commonly covered; second, we want to give employees at other similarly-situated companies tools (such as suggesting HRAs) to help fight for the healthcare coverage they need. We have a responsibility to take care of our employees, but we also have a responsibility to make our industry a better place to work for everyone.</p></div></div>]]></content>
        <author>
            <name>iliana etaoin</name>
        </author>
        <contributor>
            <name>iliana etaoin</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Another vulnerability in the LPC55S69 ROM]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/another-vulnerability-in-the-lpc55s69-rom</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/another-vulnerability-in-the-lpc55s69-rom"/>
        <updated>2022-03-23T18:00:00.000Z</updated>
        <summary type="html"><![CDATA[The discovery of an undocumented hardware block in the LPC55S69.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>Here at Oxide, we continue to work on building servers as they should be. Last year, we discovered an undocumented hardware block in the LPC55S69 (our chosen part for our product’s Root of Trust implementation) that could be used to violate security boundaries. This issue highlighted the importance of transparency as an Oxide value which is why we are bringing another recently discovered vulnerability to light today. While continuing to develop our product, we discovered a buffer overflow in the ROM of the LPC55S69. This issue exists in the In-System Programming (ISP) code for the signed update mechanism which lives in ROM. This vulnerability allows an attacker to gain non-persistent code execution with a carefully crafted update regardless of whether the update is signed. This can be used to circumvent restrictions when the chip is fully locked down and also extract the device’s DICE Unique Device Secret (UDS). Because this issue exists in ROM there is no known workaround other than disabling all hardware and software paths to enter ISP mode. CVE-2022-22819 has been assigned for this vulnerability. Finding two separate issues in the same chip only strengthens Oxide’s assertion that keeping code proprietary does not improve product security and hardware manufacturers such as NXP should make their ROM source available for customer review.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Updates are hard</h2><div class="sectionbody"><div class="paragraph"><p>Before discussing the exploit, it’s worth thinking about the higher level problem: how do you update your software on a microcontroller once it leaves the factory? This turns out to be a tricky problem where a bug can result in a non-functional device. To make this problem easier, chip makers like NXP will provide some method to put the chip in a mode that allows for safe modification of flash independent of installed firmware. NXP offers this via its In System Programming (ISP) mode.</p></div><div class="paragraph"><p>ISP mode allows a host (typically a general purpose computer) to read and write various parts of the chip including flash by sending commands to the target over a variety of protocols. The LPC55S69 supports receiving ISP commands over UART, SPI, I2C, and, on variants that include the necessary peripheral, CAN. The LPC55S69 can be configured to require code be signed with a specific key. In this configuration, most commands are restricted and changes to the flash can only come via the <code>receive-sb-file</code> command.</p></div></div></div><div class="sect1"><h2 data-sectnum="">The update format</h2><div class="sectionbody"><div class="paragraph"><p>The <code>receive-sb-file</code> ISP command uses the SB2 format. This format includes a header followed by a series of commands which can modify the flash or start code execution. Confidentiality and integrity of an update are provided by encrypting the commands with a key programmed at manufacturing time, inserting a secure digest of the commands in the update header, and finally signing the header. The C representation of the first part of the header looks like the following:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code class="language-C" data-lang="C"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sb2_header_t</span> {</span>
	<span class="hljs-type">uint32_t</span> nonce[<span class="hljs-number">4</span>];

	<span class="hljs-type">uint32_t</span> reserved;
	<span class="hljs-type">uint8_t</span> m_signature[<span class="hljs-number">4</span>];
	<span class="hljs-type">uint8_t</span> m_majorVersion;
	<span class="hljs-type">uint8_t</span> m_minorVersion;

	<span class="hljs-type">uint16_t</span> m_flags;
	<span class="hljs-type">uint32_t</span> m_imageBlocks;
	<span class="hljs-type">uint32_t</span> m_firstBootTagBlock;
	<span class="hljs-type">section_id_t</span> m_firstBootableSectionID;

	<span class="hljs-type">uint32_t</span> m_offsetToCertificateBlockInBytes;

	<span class="hljs-type">uint16_t</span> m_headerBlocks;

	<span class="hljs-type">uint16_t</span> m_keyBlobBlock;
	<span class="hljs-type">uint16_t</span> m_keyBlobBlockCount;
	<span class="hljs-type">uint16_t</span> m_maxSectionMacCount;
	<span class="hljs-type">uint8_t</span> m_signature2[<span class="hljs-number">4</span>];

	<span class="hljs-type">uint64_t</span> m_timestamp;
	<span class="hljs-type">version_t</span> m_productVersion;
	<span class="hljs-type">version_t</span> m_componentVersion;
	<span class="hljs-type">uint32_t</span> m_buildNumber;
	<span class="hljs-type">uint8_t</span> m_padding1[<span class="hljs-number">4</span>];
};</code></pre></div></div></div></div><div class="sect1"><h2 data-sectnum="">The bug</h2><div class="sectionbody"><div class="paragraph"><p>The SB2 update is parsed sequentially in 16-byte blocks. The header identifies some parts of the update by block number (e.g. block 0 is at byte offset 0, block 1 at byte offset 16 etc). The bug comes from improper bounds checking on the block numbers. The SB2 parser in ROM copies the header to a global buffer before checking the signature. Instead of stopping when the size of the header has been copied (a total of 8 blocks or 128 bytes), the parsing code copies up to <code>m_keyBlobBlock</code> number of blocks. In a correctly formatted header, <code>m_keyBlobBlock</code> will refer to the block number right after the header, but the code does not check the bounds on this. If <code>m_keyBlobBlock</code> is set to a much larger number the code will continue copying bytes beyond the end of the global buffer, a classic buffer overflow.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Impact</h2><div class="sectionbody"><div class="paragraph"><p>The full extent of this bug depends on system configuration with code execution possible in many circumstances. A simple version of this can allow for enabling SWD access (normally disabled during ISP mode) via jumping to existing code in ROM. A more sophisticated attack has been demonstrated as a proof-of-concept to provide arbitrary code execution. While code execution via this vulnerability does not directly provide persistence, attack code executes with the privileges of ISP mode and can thus modify flash contents. If this system is configured for secure boot and sealed via the Customer Manufacturing Programming Area (CMPA), modifications of code stored in flash will be detected on subsequent boots. Additionally, ISP mode executes while the DICE UDS (Unique Device Secret) is still accessible allowing for off-device derivation of keys based on the secret.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Mitigation</h2><div class="sectionbody"><div class="paragraph"><p>Because this is an issue in the ROM, the best mitigation without replacing the chip is to prevent access to the vulnerable SB2 parser. Disabling ISP mode and not using flash recovery mode will avoid exposure, although this does mean the chip user must come up with alternate designs for those use cases.</p></div><div class="paragraph"><p>The NXP ROM also provides an API for applying an SB2 update directly from user code. Using this API in any form will still provide a potential path to expose the bug. Checking the signature on an update using another ROM API before calling the update API would provide verification than an update is from a trusted source. This is not the same thing as verifying that the update data is correct or not malicious. Signature verification does provide a potential mechanism for some degree of confidence if using the SB2 update mechanism cannot be avoided.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Conclusion</h2><div class="sectionbody"><div class="paragraph"><p>As exciting as it was to find this issue, it was also surprising given NXP’s previous statement that the ROM had been reviewed for vulnerabilities. While no review is guaranteed to find every issue, this issue once again highlights that a single report is no substitute for transparency. Oxide continues to assert that open firmware is necessary for building a more secure system. Transparency in what we are building and how we are building it will allow our customers to make a fully informed choice about what they are buying and how their system will work. We, once again, invite everyone to join us in making open firmware the industry baseline.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Timeline</h2><div class="sectionbody"><div class="dlist"><dl><dt class="hdlist1">2021-12-22</dt><dd><p>Oxide discovers vulnerability while attempting to understand SB2 update process</p></dd><dt class="hdlist1">2021-12-23</dt><dd><p>Oxide discloses vulnerability to NXP</p></dd><dt class="hdlist1">2022-01-03</dt><dd><p>NXP PSIRT acknowledges the report</p></dd><dt class="hdlist1">2022-01-04</dt><dd><p>NXP PSIRT acknowledges the vulnerability</p></dd><dt class="hdlist1">2022-02-28</dt><dd><p>NXP Discloses issues in a NXP Security Bulletin (NDA required) and confirms that a new ROM revision, and thus new part revisions, are required to correct the vulnerability in affected product lines.</p></dd><dt class="hdlist1">2022-03-23</dt><dd><p>Oxide discloses as CVE-2022-22819</p></dd></dl></div></div></div></div>]]></content>
        <author>
            <name>Laura Abbott</name>
        </author>
        <contributor>
            <name>Laura Abbott</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Hubris and Humility]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/hubris-and-humility</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/hubris-and-humility"/>
        <updated>2021-11-30T18:00:00.000Z</updated>
        <summary type="html"><![CDATA[The release of a small open-source operating system for deeply-embedded computer systems.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div class="paragraph"><p>When <a href="https://oxide.computer/blog/oxide-computer-company-initial-boot-sequence">we started Oxide</a>, we knew we were going to take a fresh look at the entire system. We knew, for example, that we wanted to have a true hardware root of trust and that we wanted to revisit the traditional BMC. We knew, too, that we would have our own system software on each of these embedded systems, and assumed that we would use an existing open source operating system as a foundation. However, as we waded deeper into these embedded systems and especially their constraints of security and robustness we found that what we wanted out of the existing operating systems wasn’t necessarily what they offered (or even wanted to offer).</p></div><div class="paragraph"><p>As time went on in early 2020 and we found ourselves increasingly forcing existing systems out of the comfort of their design centers, we wondered: was our assumption of using an existing system wrong? Should we in fact be exploring our own de novo operating system? In particular, our colleague <a href="http://cliffle.com/">Cliff Biffle</a>, who had a ton of experience with both Rust and embedded systems, had a vision for what such a system might look like (namely, the system that he had always wanted for himself!). Cliff dove into a sketch of his ideas, giving the nascent system a name that felt perfectly apt: Hubris.</p></div><div class="paragraph"><p>After just a few weeks, Cliff’s ideas were taking concrete shape, and it was clear that there was a lot to like: the emerging Hubris was an all-Rust system that was not distracting itself by accommodating other runtimes; it was microkernel-based, allowing for safety and isolation; it employed a strictly synchronous task model, allowing for it be easily developed and comprehended; and it was small and light, allowing it to fit into some of the tight spots we envisioned for it. But for me, it was the way Cliff thought about the building of the system that really set Hubris apart: instead of having an operating system that knows how to dynamically create tasks at run-time (itself a hallmark of multiprogrammed, general purpose systems), Cliff had designed Hubris to fully specify the tasks for a particular application at build time, with the build system then combining the kernel with the selected tasks to yield a single (attestable!) image.</p></div><div class="paragraph"><p>This is the best of both worlds: it is at once dynamic and general purpose with respect to what the system can run, but also entirely static in terms of the binary payload of a particular application — and broadly static in terms of its execution. Dynamic resource exhaustion is the root of many problems in embedded systems; having the system know a priori all of the tasks that it will ever see liberates it from not just a major source of dynamic allocation, but also from the concomitant failure modes. For example, in Hubris, tasks can always be safely restarted, because we know that the resources associated with a task are available if that task itself has faulted! And this eliminates failure modes in which dynamic task creation in response to load induces resource exhaustion; as Cliff has quipped, it is hard to have a fork bomb when the system lacks fork itself!</p></div><div class="paragraph"><p>Precedence for the Hubris approach can be found in other systems like library operating systems, but there is an essential difference: Hubris is a memory-protected system, with tasks, the kernel, and drivers all in disjoint protection domains. (And yes, even in memory safe languages like Rust, memory protection is essential!) In this regard, Hubris represents what we like about Rust, too: a creative solution that cuts through a false dichotomy to yield a system that is at once nimble and rigorous.</p></div><div class="paragraph"><p>It was clear that Cliff was on the right track with Hubris, and the rest of us jumped in with gusto. For my own part, with debugging and debuggability deep in my marrow, I set to work writing the debugger that I felt that we would need — and that Hubris deserved. Following Cliff’s lead, I dubbed it Humility, and it’s been exciting for me to see the debugger and the operating system work together to yield a higher-quality system.</p></div><div class="paragraph"><p>We have known for quite some time that we would open source Hubris: not only is open source core to our own commercial thesis at Oxide, we also believe that the open source revolution — and its many advantages for customers — are long overdue in the lowest layers of the software stack. So we were waiting for the right occasion, and the <a href="https://osfc.io/">Open Source Firmware Conference</a> afforded us an excellent one: if you are a listener of our <a href="https://oxide.computer/podcasts">On the Metal</a> podcast, you heard us talk about OSFC a bunch, and it felt entirely fitting that we would kickoff our own open source firmware contribution there. And while the conference starts today, the good news is that you haven’t missed anything! Or at least, not yet: the conference is virtual, so if you want to hear Cliff talk about Hubris in his own words — and it’s before 12:10 Pacific today — it’s not too late to <a href="https://tickets.osfc.io/">buy a ticket</a>! (The recording will naturally be released after the conference.)</p></div><div class="paragraph"><p>And of course, if you just want to play with the system itself, Hubris and Humility are both now open source! Start by checking out the <a href="https://github.com/oxidecomputer/hubris">Hubris repo</a>, the <a href="https://hubris.oxide.computer/reference/">Hubris docs</a>, and the <a href="https://github.com/oxidecomputer/humility">Humility repo</a>. (And if you are looking for a hardware vehicle for your exploration, take a look at the ST Nucleo-H753ZI evaluation board — a pretty capable computer for less than thirty bucks!) We believe Rust to be a part of the <a href="https://www.youtube.com/watch?v=XbBzSSvT_P0">coming firmware revolution</a>, and it’s exciting for us to have a system out there that embodies that belief!</p></div></div>]]></content>
        <author>
            <name>Bryan Cantrill</name>
        </author>
        <contributor>
            <name>Bryan Cantrill</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Exploiting Undocumented Hardware Blocks in the LPC55S69]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69"/>
        <updated>2021-04-30T23:00:00.000Z</updated>
        <summary type="html"><![CDATA[A write up of the LPC55S69 ROM Patch.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>At Oxide Computer, we are designing a new computer system from the ground up. Along the way we carefully review all hardware selected to ensure it meets not only functional needs but our security needs as well. This work includes reverse engineering where necessary to get a full understanding of the hardware. During the process of reverse engineering the NXP LPC55S69 ROM we discovered an undocumented hardware block intended to allow NXP to fix bugs discovered in the ROM by applying patches from on-device flash as part of the boot process. That’s important because this ROM contains the first instructions that are run on boot and stores a set of APIs that are called from user applications. Unfortunately, this undocumented block is left open and accessible by non-secure, unprivileged user code thus allowing attackers to make runtime modifications to purportedly trusted APIs, allowing them to potentially hijack future execution and subvert multiple security boundaries. This issue has been assigned CVE-2021-31532.</p></div><div class="paragraph"><p>This vulnerability was found by pure chance. We believe that this issue would have been discovered much earlier if the source code for the ROM itself were publicly available. For us, finding and disclosing this issue has highlighted the importance of being able to audit the components in our system. Transparency is one of our <a href="https://oxide.computer/about/">values</a> at Oxide because we believe that open systems are more likely to be secure ones.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Details</h2><div class="sectionbody"><div class="paragraph"><p>The purpose of a secure boot process rooted in a hardware root of trust is to provide some level of assurance that the firmware and software booted on a server is unmodified and was produced by a trusted supplier. Using a root of trust in this way allows users to detect certain types of persistent attacks such as those that target <a href="https://arstechnica.com/information-technology/2020/12/dangerous-uefi-malware-is-rare-a-botnet-called-trickbot-may-change-that/">firmware</a>. Hardware platforms developed by cloud vendors contain a hardware root of trust, such as <a href="https://cloud.google.com/blog/products/gcp/titan-in-depth-security-in-plaintext">Google’s Titan</a>, Microsoft’s Cerberus, and <a href="https://aws.amazon.com/ec2/nitro/">AWS’s Nitro</a>. For Oxide’s rack, we evaluated the <a href="https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc5500-cortex-m33/high-efficiency-arm-cortex-m33-based-microcontroller-family:LPC55S6x">NXP LPC55S69</a> as a candidate for our hardware root of trust.</p></div><div class="paragraph"><p>Part of evaluating a hardware device for use as a root of trust is reviewing how trust and integrity of code and data is maintained during the boot process. A common technique for establishing trust is to put the first instruction in an on-die ROM. If this is an actual <a href="https://www.arrow.com/en/research-and-events/articles/what-is-rom-types-of-rom-explained">mask ROM</a> the code is permanently encoded in the hardware and cannot be changed. This is great for our chain of trust as we can have confidence that the first code executed will be what we expect and we can use that as the basis for validating other parts of the system. A downside to this approach is that any bugs discovered in the ROM cannot be fixed in existing devices. Allowing modification of read-only code has been associated with <a href="https://media.defcon.org/DEF%20CON%2026/DEF%20CON%2026%20presentations/DEFCON-26-Yuwei-Zheng-Shaokun-Cao-Bypass-the-SecureBoot-and-etc-on-NXP-SOCs-Updated.pdf">exploits</a> in other generations of chips.</p></div><div class="paragraph"><p>An appealing feature of the LPC55 is the addition of <a href="https://developer.arm.com/ip-products/security-ip/trustzone">TrustZone-M</a>. TrustZone-M provides hardware-enforced isolation allowing sensitive firmware and data to be protected from attacks against the rest of the system. Unlike TrustZone-A which uses thread context and memory mappings to distinguish between secure and non-secure worlds, TrustZone-M relies on designating parts of the physical address space as either secure or non-secure. Because of this, any hardware block that supports remapping of memory regions or that is shared between secure and non-secure worlds can potentially break that isolation. ARM recognized this risk and explicitly prohibited including their own <a href="https://developer.arm.com/documentation/ddi0439/b/Debug/About-the-Flash-Patch-and-Breakpoint-Unit&#8212;&#8203;FPB-/FPB-programmers-model">Flash Patch and Breakpoint (FPB) unit</a>, a hardware block commonly included in Cortex-M devices to improve debugging, in devices with TrustZone-M.</p></div><div class="paragraph"><p>While doing our due diligence in reviewing the part, we discovered a custom undocumented hardware block by NXP that is similar to the ARM FPB but for patching ROM. While this ROM patcher is useful for fixing bugs discovered in the ROM after chip fabrication, it potentially weakens trusted boot assertions, as there is no longer a 100% guarantee that the same code is running each time the system boots. Thankfully, experimentation revealed that ROM patches are cleared upon device reset thus preventing any viable attacks against secure boot.</p></div><div class="paragraph"><p>NXP also has a set of runtime APIs in ROM for accessing the on-board flash, authenticating firmware images, and entering in-system programming mode. These ROM APIs are expected to be called from secure mode and some, such as skboot_authenticate, require privileged mode as well. Since the ROM patcher is accessible from non-secure/unprivileged mode, an attacker can leverage these ROM APIs to gain privilege escalation by modifying the ROM API as follows:</p></div><div class="olist arabic"><ol class="arabic"><li class=""><p>Pick a target ROM API (say flash_program) likely to be used by a secure mode application</p></li><li class=""><p>Use the ROM patcher to change the first instruction to branch to an attacker controlled address</p></li><li class=""><p>The next call into the ROM will execute the selected address</p></li></ol></div><div class="paragraph"><p>This issue can be mitigated through use of the <a href="https://developer.arm.com/documentation/100699/0100/">memory protection unit (MPU)</a> or <a href="https://developer.arm.com/documentation/100235/0004/the-cortex-m33-peripherals/security-attribution-and-memory-protection/security-attribution-unit">security attribution unit (SAU)</a> which restricts access to specified address ranges. Not all code bases will choose to enable the MPU, however. Developers may consider this unnecessary overhead given the expected small footprint of a microcontroller. This issue shows why that’s a dangerous assumption. Even close examination of the official documentation would not have given any indication of a reason to use the MPU. Multiple layers of security can mitigate or lessen the effects of a security issue.</p></div></div></div><div class="sect1"><h2 data-sectnum="">How did we find this</h2><div class="sectionbody"><div class="paragraph"><p>Part of building a secure product means knowing exactly what code is running and what that code is doing. While having first instruction code in ROM is good for measured boot (we can know what code is running), the ROM itself is completely undocumented by NXP except for API entry points. This means we had no idea exactly what code was running or if that code was correct. Running undocumented code isn’t a value-add no matter how optimized or clever that code might be. We took some time to reverse engineer the ROM to get a better idea of how exactly the secure boot functionality worked and verify exactly what it was doing.</p></div><div class="paragraph"><p>Reverse engineering is a very specialized field but it turns out you can get a decent idea of what code is doing with <a href="https://ghidra-sre.org/">Ghidra</a> and a knowledge of ARM assembly. It also helps that the ROM code was not intentionally obfuscated so Ghidra did a decent job of turning it back into C. Using the breadcrumbs available to us in NXP’s documentation we discovered an undocumented piece of hardware related to a “ROM patch” stored in on-chip persistent storage and we dug in to understand how it works.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Details about the hardware block</h2><div class="sectionbody"><div class="paragraph"><p>NXP’s homegrown ROM patcher is a hardware block implemented as an APB peripheral at non-secure base address 0x4003e000 and secure base address 0x5003e000. It provides a mechanism for replacing up to 16 32-bit words in the ROM with either an explicit 32-bit value or a svc instruction. The svc instruction is typically used by unprivileged code to request privileged code to perform an operation on its behalf. As this provides a convenient mechanism for performing an indirect call, it is used to trampoline to a patch stored in SRAM when the patch is longer than a few words.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/nxp-patch-layout.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/nxp-patch-layout.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/nxp-patch-layout.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/nxp-patch-layout.png" alt="NXP patch layout"/></div><div class="title">Figure 1. NXP patch layout</div></div></div></div><div class="sect1"><h2 data-sectnum="">Persistent ROM patches stored in flash</h2><div class="sectionbody"><div class="paragraph"><p>NXP divides the flash up into two main parts: regular flash and protected flash. Regular flash is available to the device developer for all uses. The protected flash region holds data for device settings. NXP documents the user configurable parts of the protected flash region in <a href="https://www.nxp.com/docs/en/application-note/AN12283.pdf">detail</a>. The documentation notes the existence of an NXP area which cannot be reprogrammed but gives limited information about what data exists in that area.</p></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/lpc55-flash-layout.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/lpc55-flash-layout.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/lpc55-flash-layout.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/lpc55-flash-layout.png" alt="LPC55 flash layout"/></div><div class="title">Figure 2. LPC55 flash layout</div></div><div class="paragraph"><p>The limited documentation for the NXP area in protected flash refers to a ROM patch area. This contains a data structure for setting the ROM patcher at boot up. We’ve decoded the structure but some of the information may be incomplete. Each entry in the NXP ROM patch area is described by a structure. This is the rough structure we’ve reverse engineered:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code class="language-C" data-lang="C"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">rom_patch_entry</span> {</span>
	u8 word_count;
	u8 relative_address;
	u8 command;
	u8 magic_marker; <span class="hljs-comment">// Always ‘U’</span>
	u32 offset_to_be_patched
	u8 instructions[];
}</code></pre></div></div><div class="paragraph"><p>There’s three different commands defined by NXP to program the ROM patcher: a group of single word changes, an svc change, and a patch to SRAM. For the single word, the addresses to be changed are written to the entry in the array at offset 0x100 along with their corresponding entries in the reverse array at 0xf0. The relative_address field seems to determine if the addresses are relative or absolute. All the patches on our system have only been a single address so the full use of relative_address may be slightly different. For an svc change, the address is written to the 0x100 array, and the instructions are copied to an offset in the SRAM region. The patch to SRAM doesn’t actually use the flash patcher but it adjusts values in the global state stored in the SRAM.</p></div><div class="sect2"><h3 data-sectnum="..">Using the ROM patcher</h3><div class="sectionbody"><div class="paragraph"><p>Let’s show a detailed example of using the ROM patcher to change a single 32-bit word. In general, assuming the ROM patcher block starts at address 0x5003e000 and using patch slot “n” to modify a target ROM address “A” to have value “V”, we would do the following:</p></div><div class="olist arabic"><ol class="arabic"><li class=""><p>Set bit 29 at 0x5003e0f4 to turn off all patches</p></li><li class=""><p>Write our target address A to the address register at 0x5003e100 + 4*n</p></li><li class=""><p>Write our replacement value V to the value register at 0x5003e0f0 - 4*n</p></li><li class=""><p>Set bit n to the enable register at 0x5003e0fc</p></li><li class=""><p>Clear bit 29 and set bit n in 0x5003d0f4 to use the replacement value</p></li></ol></div><div class="paragraph"><p>To make this concrete, let’s modify ROM address 0x13001000 from its initial value of 0 to a new value 0xffffffff. We’ll use the first patch slot (bit 0 in 0xf4).</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>// Initial value at the address in ROM that we’re going to patch
pyocd> read32 0x13001000
13001000: 00000000 |….|

// Step 1: Turn off all patches
pyocd> write32 0x5003e0f4 0x20000000

// Step 2: Write the target address (0x13001000)
pyocd> write32 0x5003e100 0x13001000

// Step 3: Write the value we’re going to patch it with (0xffffffff)
pyocd> write32 0x5003e0f0 0xffffffff

// Step 4: Enable patch 0
pyocd> write32 0x5003e0fc 0x1

// Step 5: Turn on the ROM patch and set bit 0 to use replacement
pyocd> write32 0x5003e0f4 0x1

// Our replaced value
pyocd> read32 0x13001000

13001000: ffffffff |….|</code></pre></div></div><div class="imageblock   "><div class="content"><img srcSet="https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/nxp-rom-patcher.png?w=700 700w, https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/nxp-rom-patcher.png?w=1400 1400w, https://oxide-computer.imgix.net//img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/nxp-rom-patcher.png?w=2100 2100w" sizes="(min-width: 600px) 700px, 1400px, 2100px" src="/img/blog/exploiting-undocumented-hardware-blocks-in-the-lpc55s69/nxp-rom-patcher.png" alt="NXP ROM patcher"/></div><div class="title">Figure 3. NXP ROM patcher</div></div><div class="paragraph"><p>We can use these same steps to modify the flash APIs. NXP provides a function to verify that bytes have been written correctly to flash:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code class="language-C" data-lang="C"><span class="hljs-type">status_t</span> <span class="hljs-title function_">FLASH_VerifyProgram</span><span class="hljs-params">(<span class="hljs-type">flash_config_t</span> *config, <span class="hljs-type">uint32_t</span> start,
	<span class="hljs-type">uint32_t</span> lengthInBytes,
	<span class="hljs-type">const</span> <span class="hljs-type">uint32_t</span> *expectedData,
	<span class="hljs-type">uint32_t</span> *failedAddress,
	<span class="hljs-type">uint32_t</span> *failedData)</span>;</code></pre></div></div><div class="paragraph"><p>The function itself lives at 0x130073f8 (This is after indirection via the official function call table)</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>pyocd> disas 0x130073f8 32
0x130073f8: 2de9f847 push.w {r3, r4, r5, r6, r7, r8, sb, sl, lr}
0x130073fc: 45f61817 movw r7, #0x5918
0x13007400: 8046 mov r8, r0
0x13007402: c1f20047 movt r7, #0x1400
0x13007406: 3868 ldr r0, [r7]
0x13007408: 5fea030a movs.w sl, r3
0x1300740c: 85b0 sub sp, #0x14
0x1300740e: 0490 str r0, [sp, #0x10]
0x13007410: 0c46 mov r4, r1
0x13007412: 08bf it eq
0x13007414: 0420 moveq r0, #4
0x13007416: 1546 mov r5, r2</code></pre></div></div><div class="paragraph"><p>We can modify this function to always return success. ARM THUMB2 uses r0 as the return register. 0 is the value for success so we need to generate a mov r0, #0instruction followed by a bx lr instruction to return. This ends up being 0x2000 for the mov r0, #0 and 0x4770 for bx lr. The first instruction at 0x130073f8 is conveniently 4 bytes so it’s easy to replace with a single ROM patch slot.</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>// Turn off the patcher
pyocd> write32 0x5003e0f4 0x20000000

// Write the target address
pyocd> write32 0x5003e100 0x130073f8

// Write the target value
pyocd> write32 0x5003e0f0 0x47702000

// Enable patch 0
pyocd> write32 0x5003e0fc 0x1

// Turn on the patcher and use replacement for patch 0
pyocd> write32 0x5003e0f4 0x1

// The first two instructions have been replaced
pyocd> disas 0x130073f8 32
0x130073f8: 0020 movs r0, #0
0x130073fa: 7047 bx lr
0x130073fc: 45f61817 movw r7, #0x5918
0x13007400: 8046 mov r8, r0
0x13007402: c1f20047 movt r7, #0x1400
0x13007406: 3868 ldr r0, [r7]
0x13007408: 5fea030a movs.w sl, r3
0x1300740c: 85b0 sub sp, #0x14
0x1300740e: 0490 str r0, [sp, #0x10]
0x13007410: 0c46 mov r4, r1
0x13007412: 08bf it eq
0x13007414: 0420 moveq r0, #4
0x13007416: 1546 mov r5, r2</code></pre></div></div><div class="paragraph"><p>So long as this patch is active, any call to FLASH_VerifyProgram will return success regardless of its contents.</p></div><div class="paragraph"><p>NXP also provides a function to verify the authenticity of an image:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>skboot_status_t skboot_authenticate(const uint8_t *imageStartAddr,
	secure_bool_t *isSignVerified)</code></pre></div></div><div class="paragraph"><p>In addition to returning a status code, the value stored in the second argument also contains a separate return value that must be checked. It does make the ROM patching code longer but not significantly so. The assembly we need is:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>// Two instructions to load kSECURE_TRACKER_VERIFIED = 0x55aacc33U
movw r0, 0xcc33
movt r0, 0x55aa

// store kSECURE_TRACKER_VERIFIED to r1 aka isSignVerified
str r0, [r1]

// Two instructions to load kStatus_SKBOOT_Success = 0x5ac3c35a
movw r0, 0xc35a
movt r0, 0x5ac3

// return
bx lr</code></pre></div></div><div class="paragraph"><p>If you look at a sample disassembly, there’s a mixture of 16 and 32 bit instructions:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>45c: f64c 4033 movw r0, #52275 ; 0xcc33
460: f2c5 50aa movt r0, #21930 ; 0x55aa
464: 6008 str r0, [r1, #0]
466: f24c 305a movw r0, #50010 ; 0xc35a
46a: f6c5 20c3 movt r0, #23235 ; 0x5ac3
46e: 4770 bx lr</code></pre></div></div><div class="paragraph"><p>Everything must be written in 32-bit words so the 16 bit instructions either get combined with bytes from another instruction or padded with nop. The start of the function is halfway on a word boundary (0x1300a34e) which needs to be padded:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>pyocd> disas 0x1300a34c 32
0x1300a34c: 70bd pop {r4, r5, r6, pc}
0x1300a34e: 38b5 push {r3, r4, r5, lr}
0x1300a350: 0446 mov r4, r0
0x1300a352: 0d46 mov r5, r1
0x1300a354: fbf7e0f9 bl #0x13005718
0x1300a358: 0020 movs r0, #0
0x1300a35a: 00f048f9 bl #0x1300a5ee
0x1300a35e: 00b1 cbz r0, #0x1300a362
0x1300a360: 09e0 b #0x1300a376
0x1300a362: 0de0 b #0x1300a380
0x1300a364: 38b5 push {r3, r4, r5, lr}
0x1300a366: 0446 mov r4, r0
0x1300a368: 0d46 mov r5, r1
0x1300a36a: 0020 movs r0, #0

// Turn off the ROM patch
pyocd> write32 0x5003e0f4 0x20000000
pyocd>

// Write address and value 0
pyocd> write32 0x5003e100 0x1300a34c
pyocd> write32 0x5003e0f0 0xf64cbf00
pyocd>

// Write address and value 1
pyocd> write32 0x5003e104 0x1300a350
pyocd> write32 0x5003e0ec 0xf2c54033
pyocd>

// Write address and value 2
pyocd> write32 0x5003e108 0x1300a354
pyocd> write32 0x5003e0e8 0x600850aa
pyocd>

// Write address and value 3
pyocd> write32 0x5003e10c 0x1300a358
pyocd> write32 0x5003e0e4 0x305af24c
pyocd>

// Write address and value 4
pyocd> write32 0x5003e110 0x1300a35c
pyocd> write32 0x5003e0e0 0x20c3f6c5
pyocd>

// Write address and value 5
pyocd> write32 0x5003e114 0x1300a360
pyocd> write32 0x5003e0dc 0xbf004770

// Enable patches 0-5
pyocd> write32 0x5003e0f4 0x3f
pyocd>

// Turn on the ROM patcher and set patches 0-5 to single-word replacement mode.
pyocd> write32 0x5003e0f4 0x3f

// The next 7 instructions are the modifications
pyocd> disas 0x1300a34c 32
0x1300a34c: 00bf nop
0x1300a34e: 4cf63340 movw r0, #0xcc33
0x1300a352: c5f2aa50 movt r0, #0x55aa
0x1300a356: 0860 str r0, [r1]
0x1300a358: 4cf25a30 movw r0, #0xc35a
0x1300a35c: c5f6c320 movt r0, #0x5ac3
0x1300a360: 7047 bx lr
0x1300a362: 00bf nop
0x1300a364: 38b5 push {r3, r4, r5, lr}
0x1300a366: 0446 mov r4, r0
0x1300a368: 0d46 mov r5, r1
0x1300a36a: 0020 movs r0, #0</code></pre></div></div><div class="paragraph"><p>The authentication method now returns success for any address passed in.</p></div><div class="paragraph"><p>The careful observer will note that the FLASH_VerifyProgram and skboot_authenticate patches use the same address slots and thus cannot be applied at the same time. We’re limited to eight 32-bit word changes or a total of 32 bytes which limits the number of locations that can be changed. The assembly demonstrated here is not optimized and could certainly be improved. Another approach is to apply one patch, wait for the function to be called and then switch to a different patch.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">Applying Mitigations</h3><div class="sectionbody"><div class="paragraph"><p>A full mitigation would provide a lock-out option so that once the ROM patcher is enabled no further changes are available until the next reset. Based on discussions with NXP, this is not a feature that is available on the current hardware.</p></div><div class="paragraph"><p>The LPC55 offers a standard <a href="https://developer.arm.com/documentation/100699/0100/">memory protection unit (MPU)</a>. The MPU works on an allowed list of memory regions. If the MPU is configured without the ROM patcher in the allowed set, any access will trigger a fault. This makes it possible to prevent applications from using the ROM patcher at all.</p></div><div class="paragraph"><p>The LPC55 also has a secure AHB bus matrix to provide another layer of protection. This is custom hardware to block access on both secure and privilege axes. Like the ROM patcher itself, the ability to block access to the ROM patcher is not documented even though it exists. The base address of the ROM patcher (0x5003e000) comes right after the last entry in the APB table (The PLU at 0x5003d000). The order of the bits in the secure AHB registers correspond to the order of blocks in the memory map, which means the bits corresponding to the ROM patcher come right after the PLU. SEC_CTRL_APB_BRIDGE1_MEM_CTRL3 is the register of interest and the bits to set for the ROM patch are 24 and 25.</p></div><div class="paragraph"><p>NXP offers a <a href="https://www.nxp.com/docs/en/application-note/AN12278.pdf">family of products</a> based on the LPC55 line. The LPC55S2x is notable for not including TrustZone-M. While at first glance, this may seem to imply it is immune to privilege escalation via ROM patches, LPC55S2x is still an ARMv8-M device with privileged/non-privileged modes which are just as vulnerable. The non-secure MPU is the only method of blocking non-privileged access to the ROM patcher on all LPC55 variants.</p></div></div></div></div></div><div class="sect1"><h2 data-sectnum="">Conclusion</h2><div class="sectionbody"><div class="paragraph"><p>Nobody expects code to be perfect. Code for the mask ROM in particular may have to be completed well before other code given manufacturing requirements. Several of the ROM patches on the LPC55 were related to power settings which may not be finalized until very late in the product cycle. Features to fix bugs must not introduce vulnerabilities however! The LPC55S69 is marketed as a security product which makes the availability of the ROM patcher even riskier. The biggest takeaway from all of this is that transparency is important for security. A risk cannot be mitigated unless it is known. Had we not begun to ask deep questions about the ROM’s behavior, we would have been exposed to this vulnerability until it was eventually discovered and reported. Attempts to provide security through obscurity, such as preventing read access to ROMs or leaving hardware undocumented, have been repeatedly shown to be ineffective (<a href="https://blog.zapb.de/stm32f1-exceptional-failure/" class="bare">https://blog.zapb.de/stm32f1-exceptional-failure/</a>, <a href="http://dmitry.gr/index.php?r=05.Projects&amp;proj=23" class="bare">http://dmitry.gr/index.php?r=05.Projects&amp;proj=23</a>. PSoC4) and merely prolong the exposure. Had NXP documented the ROM patch hardware block and provided ROM source code for auditing, the user community could have found this issue much earlier and without extensive reverse engineering effort.</p></div><div class="paragraph"><p>NXP, however, does not agree; this is their position on the matter (which they have authorized us to share publicly):</p></div><div class="quoteblock"><blockquote><div class="paragraph">
<p>Even though we are not believers of security-by-obscurity, keeping the interest of our wide customer base the product specific ROM code is not opened to external parties, except to NXP approved Common Criteria certified security test labs for vulnerability reviews.</p>
</div></blockquote></div><div class="paragraph"><p>At Oxide, we believe fervently in open firmware, at all layers of the stack. In this regard, we intend to be the model for what we wish to see in the world: by the time our Oxide racks are commercially available next year, you can expect that all of the software and firmware that we have written will be open source, available for view – and scrutiny! – by all. Moreover, we know that the arc of system software bends towards open source: we look forward to the day that NXP – and others in the industry who cling to their proprietary software as a means of security – join us with truly open firmware.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Timeline</h2><div class="sectionbody"><div class="dlist"><dl><dt class="hdlist1">2020-12-16</dt><dd><p>Oxide sends disclosure to NXP including an embargo of 90 days</p></dd><dt class="hdlist1">2020-12-16</dt><dd><p>NXP PSIRT Acknowledges disclosure</p></dd><dt class="hdlist1">2021-01-11</dt><dd><p>Oxide requests confirmation that vulnerability was able to be reproduced</p></dd><dt class="hdlist1">2021-01-12</dt><dd><p>NXP confirms vulnerability and is working on mitigation</p></dd><dt class="hdlist1">2021-02-03</dt><dd><p>Oxide requests an update on disclosure timeline</p></dd><dt class="hdlist1">2021-02-08</dt><dd><p>NXP requests clarification of vulnerability scope</p></dd><dt class="hdlist1">2021-02-24</dt><dd><p>Oxide provides responses and a more complete PoC</p></dd><dt class="hdlist1">2021-03-05</dt><dd><p>NXP requests 45 day embargo extension to April 30th, 2021</p></dd><dt class="hdlist1">2021-04-30</dt><dd><p>Oxide publicly discloses this vulnerability as CVE-2021-31532</p></dd></dl></div></div></div></div>]]></content>
        <author>
            <name>Laura Abbott</name>
        </author>
        <contributor>
            <name>Laura Abbott</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Compensation as a Reflection of Values]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/compensation-as-a-reflection-of-values</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/compensation-as-a-reflection-of-values"/>
        <updated>2021-03-03T18:00:00.000Z</updated>
        <summary type="html"><![CDATA[Our thoughts on compensation, and how they reflect Oxide's values.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div class="paragraph"><p>Compensation: the word alone is enough to trigger a fight-or-flight reaction in
many. But we in technology have the good fortune of being in a well-compensated
domain, so why does this issue induce such anxiety when our basic needs are
clearly covered? If it needs to be said, it&#8217;s because compensation isn&#8217;t merely
about the currency we redeem in exchange for our labors, but rather it is a
proxy for how we are valued in a larger organization. This, in turn, brings us
to our largest possible questions for ourselves, around things like meaning and
self-worth.</p></div><div class="paragraph"><p>So when we started Oxide – as in any new endeavor – compensation was an issue we
had to deal with directly. First, there was the thorny issue of how we founders
would compensate ourselves. Then, of course, came the team we wished to hire:
hybrid local and remote, largely experienced to start (on account of
<a href="https://www.youtube.com/watch?v=vvZA9n3e5pc">Oxide&#8217;s outrageously ambitious
mission</a>), and coming from a diverse set of backgrounds and experiences. How
would we pay people in different geographies? How could we responsibly recruit
experienced folks, many of whom have families and other financial obligations
that can&#8217;t be addressed with stock options? How could we avoid bringing people&#8217;s
compensation history – often a reflection of race, gender, class, and other
factors rather than capability – with them?</p></div><div class="paragraph"><p>We decided to do something outlandishly simple: take the salary that Steve,
Jess, and I were going to pay ourselves, and pay that to everyone. The three of
us live in the San Francisco Bay Area, and Steve and I each have three kids; we
knew that the dollar figure that would allow us to live without financial
distress – which we put at $175,000 a year – would be at least universally
adequate for the team we wanted to build. And we mean everyone literally: as of
this writing we have 23 employees, and that&#8217;s what we all make.</p></div><div class="paragraph"><p>Now, because compensation is the hottest of all hot buttons, it can be fairly
expected that many people will have a reaction to this. Assuming you&#8217;ve made it
to this sentence it means you are not already lighting us up in your local
comments section (thank you!), and I want to promise in return that we know some
likely objections, and we&#8217;ll address those. But before we do, we want to talk
about the benefits of transparent uniform compensation, because they are, in a
word, profound.</p></div><div class="paragraph"><p>Broadly, our compensation model embodies our
<a href="https://oxide.computer/principles/">mission, principles, and values</a>. First and
foremost, we believe that our compensation model reflects our principles of
honesty, integrity, and decency. To flip it around: sadly, we have seen extant
comp structures in the industry become breeding grounds for dishonesty, deceit,
and indecency. Beyond our principles, our comp model is a tangible expression of
several of our values in particular:</p></div><div class="ulist"><ul class=""><li><p>It has set the tone with respect to teamwork. In my experience, the need to
"quantify" one&#8217;s performance in exchange for justifying changes to individual
compensation are at the root of much of what&#8217;s wrong in the tech industry.
Instead of incentivizing people to achieve together as a team, they are
incentivized to advance themselves – usually with sophisticated-sounding jargon
like OKRs or MBOs, or perhaps reasonable-sounding (but ultimately misguided)
mantras like "measure everything." Even at their very best, these individual
incentives represent a drag on a team, as their infrequent calibration can
prevent a team from a necessary change in its direction. And at worst, they
leave individuals perversely incentivized and operating in direct opposition to
the team&#8217;s best interest. When comp is taken out of the picture, everyone can
just focus on what we need to focus on: getting this outlandish thing built, and
loving and serving the customers who are taking a chance on it.</p></li><li><p>It is an
expression of our empathy. Our approach to compensation reflects our belief in
treating other people the way that we ourselves want to be treated. There are
several different dimensions for this, but one is particularly visceral: because
we have not talked about this publicly, candidates who have applied to Oxide
have done so assuming that we have a traditional comp model, and have braced
themselves for the combat of a salary negotiation. But we have spoken about it
relatively upfront with candidates (before they talk to the team, for example),
and (as the one who has often had this discussion) the relief is often palpable.
As one recent candidate phrased it to me: "if I had known about this earlier, I
wouldn&#8217;t have wasted time stressing out about it!"</p></li><li><p>It is (obviously?)
proof-positive of our transparency. Transparency is essential for building
trust, itself one of the most important elements of doing something bold
together. One of the interesting pieces of advice we got early on from someone
who has had outsized, repeated success: modulo private personnel meetings, make
sure that every meeting is open to everyone. For those accustomed to more opaque
environments, our level of transparency can be refreshing: for example, new
Oxide employees have been pleasantly surprised that we always go through our
board decks with everyone – but we can&#8217;t imagine doing it any other way.
Transparent compensation takes this to an unusual (but not unprecedented)
extreme, and we have found it to underscore how seriously we take transparency
in general.</p></li><li><p>It has allowed whole new levels of candor. When everyone can talk
about their salary, other things become easier to discuss directly. This candor
is in all directions; without comp to worry about, we can all be candid with
respect to our own struggles – which in turn allows us to address them directly.
And we can be candid too when giving public positive feedback; we don&#8217;t need to
be afraid that by calling attention to someone&#8217;s progress, someone else will
feel shorted.</p></li></ul></div><div class="paragraph"><p>These are (some of!) the overwhelming positives; what about those objections?</p></div><div class="ulist"><ul class=""><li><p>Some will say that this salary is too low. While cash compensation gets
exaggerated all of the time, it&#8217;s unquestionable that salaries in our privileged
domain have gotten much higher than our $175,000 (and indeed, many at Oxide have
taken a cut in pay to work here). But it&#8217;s also true that $175,000 per year puts
us each in the top 5% of US individual earners – and it certainly puts a roof
over our families' heads and food in their bellies. Put more viscerally: this is
enough to not fret when your kids toss the organic raspberries into the shopping
cart – or when they devour them before you&#8217;ve managed to get the grocery bags
out of the car! And speaking of those families: nothing is more
anxiety-producing than having a healthcare issue compounded by financial
distress due to inadequate insurance; Oxide not only offers the best healthcare
plans we could find, but we also pay 100% of monthly premiums – a significant
benefit for those with dependents.</p></li><li><p>Some will say that we should be paying
people differently based on different geographical locations. I know there are
thoughtful people who pay folks differently based on their zip code, but
(respectfully), we disagree with this approach. Companies spin this by
explaining they are merely paying people based on their cost of living, but this
is absurd: do we increase someone&#8217;s salary when their spouse loses their job or
when their kid goes to college? Do we slash it when they inherit money from
their deceased parent or move in with someone? The answer to all of these is no,
of course not: we pay people based on their work, not their costs. The truth is
that companies pay people less in other geographies for a simple reason: because
they can. We at Oxide just don&#8217;t agree with this; we pay people the same
regardless of where they pick up their mail.</p></li><li><p>Some will say that this doesn&#8217;t
scale. This is, at some level, surely correct: it&#8217;s hard to envision a
multi-thousand employee Oxide where everyone makes the same salary – but it has
also been (rightly) said that startups should do things that don&#8217;t scale. And
while it seems true that the uniformity won&#8217;t necessarily scale, we believe that
the values behind it very much will!</p></li><li><p>Some will say that this makes us unlikely
to hire folks just starting out in their career. There is truth to this too, but
the nature of our problem at Oxide (namely, technically very broad and very
deep), the size of our team (very small), and the stage of our company (still
pretty early!) already means that engineers at the earliest stages of their
career are unlikely to be a fit for us right now. That said, we don&#8217;t think this
is impossible; and if we felt that we had someone much earlier in their career
who was a fit – that is, if we saw them contributing to the company as much as
anyone else – why wouldn&#8217;t we reflect that by paying them the same as everyone
else?</p></li><li><p>Some will say that this narrows the kind of roles that we can hire for.
In particular, different roles can have very different comp models (sales often
has a significant commission component in exchange for a lower base, for
example). There is truth to this too – but for the moment we&#8217;re going to put
this in the "but-this-can&#8217;t-scale" bucket.</p></li><li><p>Some will say that this doesn&#8217;t
offer a career ladder. Uniform compensation causes us to ask some deeper
questions: namely, what is a career ladder, anyway? To me, the true objective
for all of us should be to always be taking on new challenges – to be unafraid
to learn and develop. I have found traditional ladders to not serve these ends
particularly well, because they focus us on competition rather than
collaboration. By eliminating the rung of compensation, we can put the focus on
career development where it belongs: on supporting one another in our
self-improvement, and working together to do things that are beyond any one of
us.</p></li><li><p>Some will say that we should be talking about equity, not cash
compensation. While it&#8217;s true that startup equity is important, it&#8217;s also true
that startup equity doesn&#8217;t pay the orthodontist&#8217;s bill or get the basement
repainted. We believe that every employee should have equity to give them a
stake in the company&#8217;s future (and that an outsized return for investors should
also be an outsized return for employees), but we also believe that the presence
of equity can&#8217;t be used as an excuse for unsustainably low cash compensation. As
for how equity is determined, it really deserves its own in-depth treatment, but
in short, equity compensates for risk – and in a startup, risk reduces over
time: the first employee takes much more risk than the hundredth.</p></li></ul></div><div class="paragraph"><p>Of these objections, several are of the ilk that this cannot endure at arbitrary
scale. This may be true – our compensation may well not be uniform in perpetuity
– but we believe wholeheartedly that our values will endure. So if and when the
uniformity of our compensation needs to change, we fully expect that it will
remain transparent – and that we as a team will discuss it candidly and
empathetically. In this regard, we take inspiration from companies that have
pioneered transparent compensation. It is very interesting to, for example, look
at how <a href="https://buffer.com/resources/salary-formula-changes-2019/">Buffer&#8217;s
compensation has changed over the years</a>. Their approach is different from ours
in the specifics, but they are a kindred spirit with respect to underlying
values – and their success with transparent compensation gives us confidence
that, whatever changes must come with time, we will be able to accommodate them
without sacrificing what is important to us!</p></div><div class="paragraph"><p>Finally, a modest correction. The $175,000 isn&#8217;t quite true – or at least not
anymore. I had forgotten that when we did our initial planning, we had budgeted
modest comp increases after the first year, so it turns out, we all got a raise
to $180,250 in December! I didn&#8217;t know it was coming (and nor did anyone else);
Steve just announced it in the All Hands: no three-hundred-and-sixty degree
reviews, no stack ranking, no OKRs, no skip-levels, no numerical grades – just a
few more organic raspberries in everyone&#8217;s shopping basket. Never has a change
in compensation felt so universally positive!</p></div><div class="paragraph"><p><strong>UPDATES</strong>: Since originally writing this blog entry in 2021, we have
increased our salary a few times, and it now stands at $201,227. We have
also added some sales positions that have variable compensation, consisting
of a lower base salary and a commission component.</p></div></div>]]></content>
        <author>
            <name>Bryan Cantrill</name>
        </author>
        <contributor>
            <name>Bryan Cantrill</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[RFD 1 Requests for Discussion]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/rfd-1-requests-for-discussion</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/rfd-1-requests-for-discussion"/>
        <updated>2020-07-24T18:00:00.000Z</updated>
        <summary type="html"><![CDATA[A look inside our internal Requests for Discussion process.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>One of the first things we did in setting up the company was create a repo named “rfd.” This repo houses our requests for discussion. Bryan teased this to the internet…</p></div><div class="paragraph"><p>…and folks asked for our process, so we are going to share it!</p></div><div class="paragraph"><p>The best way to describe RFDs is with “RFD 1 Requests for Discussion.” Below is that RFD.</p></div><div class="paragraph"><p>Writing down ideas is important: it allows them to be rigorously formulated (even while nascent), candidly discussed and transparently shared. We capture the written expression of an idea in a Request for Discussion (RFD), a document in the original spirit of the IETF <a href="https://en.wikipedia.org/wiki/Request_for_Comments">Request for Comments</a>, as expressed by <a href="https://tools.ietf.org/html/rfc3">RFC 3</a>:</p></div><div class="quoteblock"><blockquote><div class="paragraph">
<p>The content of a note may be any thought, suggestion, etc. related to the software or other aspect of the network. Notes are encouraged to be timely rather than polished. Philosophical positions without examples or other specifics, specific suggestions or implementation techniques without introductory or background explication, and explicit questions without any attempted answers are all acceptable. The minimum length for a note is one sentence.</p>
</div>
<div class="paragraph">
<p>These standards (or lack of them) are stated explicitly for two reasons. First, there is a tendency to view a written statement as ipso facto authoritative, and we hope to promote the exchange and discussion of considerably less than authoritative ideas. Second, there is a natural hesitancy to publish something unpolished, and we hope to ease this inhibition.</p>
</div></blockquote></div><div class="paragraph"><p>Similar to RFCs, our philosophy of RFDs is to allow both timely discussion of rough ideas, while still becoming a permanent repository for more established ones. Depending on their state, RFDs may be quickly iterated on in a branch, discussed actively as part of a pull request to be merged, or commented upon after having been published. The workflow for the RFD process for is based upon those of the Golang proposal process, Joyent RFD process, Rust RFC process, and Kubernetes proposal process.</p></div></div></div><div class="sect1"><h2 data-sectnum="">When to use an RFD</h2><div class="sectionbody"><div class="paragraph"><p>The following are examples of when an RFD is appropriate, these are intended to be broad:</p></div><div class="ulist"><ul class=""><li><p>Add or change a company process</p></li><li><p>An architectural or design decision for hardware or software</p></li><li><p>Change to an API or command-line tool used by customers</p></li><li><p>Change to an internal API or tool</p></li><li><p>Change to an internal process</p></li><li><p>A design for testing</p></li></ul></div><div class="paragraph"><p>RFDs not only apply to technical ideas but overall company ideas and processes as well. If you have an idea to improve the way something is being done as a company, you have the power to make your voice heard by adding to discussion.</p></div></div></div><div class="sect1"><h2 data-sectnum="">RFD Metadata and State</h2><div class="sectionbody"><div class="paragraph"><p>At the start of every RFD document, we’d like to include a brief amount of metadata. The metadata format is based on the <a href="https://github.com/trentm/python-markdown2/wiki/metadata">python-markdown2</a> metadata format. It’d look like:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>—
authors: Andy Smith <andy@example.computer>, Neal Jones <neal@example.computer>
state: prediscussion
—</code></pre></div></div><div class="paragraph"><p>We keep track of three pieces of metadata:</p></div><div class="olist arabic"><ol class="arabic"><li class=""><p><code>authors</code>: the authors (and therefore owners) of an RFD. They should be listed with their name and e-mail address.</p></li><li class=""><p><code>state</code>: must be one of the states discussed below.</p></li><li class=""><p><code>discussion</code>: for RFDs that are in or beyond the discussion state, this should be a link to the PR to integrate the RFD; see below for details.</p></li></ol></div><div class="paragraph"><p>An RFD can be in one of the following six states:</p></div><div class="olist arabic"><ol class="arabic"><li class=""><p><code>prediscussion</code></p></li><li class=""><p><code>ideation</code></p></li><li class=""><p><code>discussion</code></p></li><li class=""><p><code>published</code></p></li><li class=""><p><code>committed</code></p></li><li class=""><p><code>abandoned</code></p></li></ol></div><div class="paragraph"><p>A document in the prediscussion state indicates that the work is not yet ready for discussion, but that the RFD is effectively a placeholder. The prediscussion state signifies that work iterations are being done quickly on the RFD in its branch in order to advance the RFD to the discussion state.</p></div><div class="paragraph"><p>A document in the ideation state contains only a description of the topic that the RFD will cover, providing an indication of the scope of the eventual RFD. Unlike the prediscussion state, there is no expectation that it is undergoing active revision. Such a document can be viewed as a scratchpad for related ideas. Any member of the team is encouraged to start active development of such an RFD (moving it to the prediscussion state) with or without the participation of the original author. It is critical that RFDs in the ideation state are clear and narrowly defined.</p></div><div class="paragraph"><p>Documents under active discussion should be in the discussion state. At this point a discussion is being had for the RFD in a Pull Request.</p></div><div class="paragraph"><p>Once (or if) discussion has converged and the Pull Request is ready to be merged, it should be updated to the published state before merge. Note that just because something is in the published state does not mean that it cannot be updated and corrected. See the <a href="#_making_changes_to_an_rfd">Making changes to an RFD</a> section for more information.</p></div><div class="paragraph"><p>The prediscussion state should be viewed as essentially a collaborative extension of an engineer’s notebook, and the discussion state should be used when an idea is being actively discussed. These states shouldn’t be used for ideas that have been committed to, organizationally or otherwise; by the time an idea represents the consensus or direction, it should be in the published state.</p></div><div class="paragraph"><p>Once an idea has been entirely implemented, it should be in the committed state. Comments on ideas in the committed state should generally be raised as issues — but if the comment represents a call for a significant divergence from or extension to committed functionality, a new RFD may be called for; as in all things, use your best judgment.</p></div><div class="paragraph"><p>Finally, if an idea is found to be non-viable (that is, deliberately never implemented) or if an RFD should be otherwise indicated that it should be ignored, it can be moved into the abandoned state.</p></div><div class="paragraph"><p>We will go over this in more detail. Let’s walk through the life of a RFD.</p></div></div></div><div class="sect1"><h2 data-sectnum="">RFD life-cycle</h2><div class="sectionbody"><div class="paragraph"><p>There is a prototype script in this repository, scripts/new.sh, that will automate the process.</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>$ scripts/new.sh 0042 “My title here”</code></pre></div></div><div class="paragraph"><p>If you wish to create a new RFD by hand, or understand the process in greater detail, read on.</p></div><div class="admonitionblock note"><div class="admonition-icon"><svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" class="rotate-180"><path fill-rule="evenodd" clip-rule="evenodd" d="M6 12A6 6 0 1 0 6 0a6 6 0 0 0 0 12Zm.083-9c.368 0 .667.299.667.667v2.666A.667.667 0 0 1 6.083 7h-.166a.667.667 0 0 1-.667-.667V3.667c0-.368.299-.667.667-.667h.166Zm0 5c.368 0 .667.299.667.667v.166a.667.667 0 0 1-.667.667h-.166a.667.667 0 0 1-.667-.667v-.166c0-.368.299-.667.667-.667h.166Z" fill="currentColor"></path></svg></div><div class="admonition-content content"><div>Note</div><div>Never at anytime through the process do you push directly to the master branch. Once your pull request (PR) with your RFD in your branch is merged into master, then the RFD will appear in the master branch.</div></div></div></div></div><div class="sect1"><h2 data-sectnum="">Reserve a RFD number</h2><div class="sectionbody"><div class="paragraph"><p>You will first need to reserve the number you wish to use for your RFC. This number should be the next available RFD number from looking at the current git branch -r output.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Create a branch for your RFD</h2><div class="sectionbody"><div class="paragraph"><p>Now you will need to create a new git branch, named after the RFD number you wish to reserve. This number should have leading zeros if less than 4 digits. Before creating the branch, verify that it does not already exist:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>$ git branch -rl *0042</code></pre></div></div><div class="paragraph"><p>If you see a branch there (but not a corresponding sub-directory in rfd in master), it is possible that the RFD is currently being created; stop and check with co-workers before proceeding! Once you have verified that the branch doesn’t exist, create it locally and switch to it:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>$ git checkout -b 0042</code></pre></div></div></div></div><div class="sect1"><h2 data-sectnum="">Create a placeholder RFD</h2><div class="sectionbody"><div class="paragraph"><p>Now create a placeholder RFD. You can do so with the following commands:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>$ mkdir -p rfd/0042
$ cp prototypes/prototype.md rfd/0042/README.md</code></pre></div></div></div></div><div class="sect1"><h2 data-sectnum="">Or if you prefer asciidoc</h2><div class="sectionbody"><div class="listingblock"><div class="content"><pre class="highlight"><code>$ cp prototypes/prototype.adoc rfd/0042/README.adoc</code></pre></div></div><div class="paragraph"><p>Fill in the RFD number and title placeholders in the new doc and add your name as an author. The status of the RFD at this point should be prediscussion.</p></div><div class="paragraph"><p>If your preference is to use asciidoc, that is acceptable as well, however the examples in this flow will assume markdown.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Push your RFD branch remotely</h2><div class="sectionbody"><div class="paragraph"><p>Push your changes to your RFD branch in the RFD repo.</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>$ git add rfd/0042/README.md
$ git commit -m ‘0042: Adding placeholder for RFD <Title>’
$ git push origin 0042</code></pre></div></div><div class="paragraph"><p>After your branch is pushed, the table in the README on the master branch will update automatically with the new RFD. If you ever change the name of the RFD in the future, the table will update as well. Whenever information about the state of the RFD changes, this updates the table as well. The single source of truth for information about the RFD comes from the RFD in the branch until it is merged.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Iterate on your RFD in your branch</h2><div class="sectionbody"><div class="paragraph"><p>Now, you can work on writing your RFD in your branch.</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>$ git checkout 0042</code></pre></div></div><div class="paragraph"><p>Now you can gather your thoughts and get your RFD to a state where you would like to get feedback and discuss with others. It’s recommended to push your branch remotely to make sure the changes you make stay in sync with the remote in case your local gets damaged.</p></div><div class="paragraph"><p>It is up to you as to whether you would like to squash all your commits down to one before opening up for feedback, or if you would like to keep the commit history for the sake of history.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Discuss your RFD</h2><div class="sectionbody"><div class="paragraph"><p>When you are ready to get feedback on your RFD, make sure all your local changes are pushed to the remote branch. At this point you are likely at the stage where you will want to change the status of the RFD from prediscussion to discussionfor a fully formed RFD or to ideation for one where only the topic is specified. Do this in your branch.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Push your RFD branch remotely</h2><div class="sectionbody"><div class="paragraph"><p>Along with your RFD content, update the RFD’s state to discussion in your branch, then:</p></div><div class="listingblock"><div class="content"><pre class="highlight"><code>$ git commit -am ‘0042: Add RFD for <Title>’
$ git push origin 0042</code></pre></div></div></div></div><div class="sect1"><h2 data-sectnum="">Open a Pull Request</h2><div class="sectionbody"><div class="paragraph"><p>Open a pull request on GitHub to merge your branch, in this case 0042 into the master branch.</p></div><div class="paragraph"><p>If you move your RFD into discussion but fail to open a pull request, a friendly bot will do it for you. If you open a pull request but fail to update the state of the RFD to discussion, the bot will automatically correct the state by moving it into discussion. The bot will also cleanup the title of the pull request to be RFD {num} {title}. The bot will automatically add the link to the pull request to the discussion: metadata.</p></div><div class="paragraph"><p>After the pull request is opened, anyone subscribed to the repo will get a notification that you have opened a pull request and can read your RFD and give any feedback.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Discuss the RFD on the pull request</h2><div class="sectionbody"><div class="paragraph"><p>The comments you choose to accept from the discussion are up to you as the owner of the RFD, but you should remain empathetic in the way you engage in the discussion.</p></div><div class="paragraph"><p>For those giving feedback on the pull request, be sure that all feedback is constructive. Put yourself in the other person’s shoes and if the comment you are about to make is not something you would want someone commenting on an RFD of yours, then do not make the comment.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Merge the Pull Request</h2><div class="sectionbody"><div class="paragraph"><p>After there has been time for folks to leave comments, the RFD can be merged into master and changed from the discussion state to the published state. The timing is left to your discretion: you decide when to open the pull request, and you decide when to merge it. As a guideline, 3-5 business days to comment on your RFD before merging seems reasonable — but circumstances (e.g., time zones, availability of particular expertise, length of RFD) may dictate a different timeline, and you should use your best judgment. In general, RFDs shouldn’t be merged if no one else has read or commented on it; if no one is reading your RFD, it’s time to explicitly ask someone to give it a read!</p></div><div class="paragraph"><p>Discussion can continue on published RFDs! The discussion: link in the metadata should be retained, allowing discussion to continue on the original pull request. If an issue merits more attention or a larger discussion of its own, an issue may be opened, with the synopsis directing the discussion.</p></div><div class="paragraph"><p>Any discussion on an RFD in the can still be made on the original pull request to keep the sprawl to a minimum. Or if you feel your comment post-merge requires a larger discussion, an issue may be opened on it — but be sure to reflect the focus of the discussion in the issue synopsis (e.g., “RFD 42: add consideration of RISC-V”), and be sure to link back to the original PR in the issue description so that one may find one from the other.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Making changes to an RFD</h2><div class="sectionbody"><div class="paragraph"><p>After your RFD has been merged, there is always opportunity to make changes. The easiest way to make a change to an RFD is to make a pull request with the change you would like to make. If you are not the original author of the RFD name your branch after the RFD # (e.g. 0001) and be sure to @ the original authors on your pull request to make sure they see and approve of the changes.</p></div><div class="paragraph"><p>Changes to an RFD will go through the same discussion and merge process as described above.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Committing to an RFD</h2><div class="sectionbody"><div class="paragraph"><p>Once an RFD has become implemented — that is, once it is not an idea of some future state but rather an explanation of how a system works — its state should be moved to be committed. This state is essentially no different from published, but represents ideas that have been more fully developed. While discussion on committed RFDs is permitted (and changes allowed), they would be expected to be infrequent.</p></div></div></div><div class="sect1"><h2 data-sectnum="">Changing the RFD process</h2><div class="sectionbody"><div class="paragraph"><p>The best part about the RFD process is that it itself is expressed in this RFD; if you want to change the process itself, you can apply the RFD process to its own RFD: chime in on the discussion link or open an issue as dictated by its current state!</p></div></div></div><div class="sect1"><h2 data-sectnum="">Tooling</h2><div class="sectionbody"><div class="sect2"><h3 data-sectnum="..">API</h3><div class="sectionbody"><div class="paragraph"><p>Because RFDs are so core to everything we do, we automatically update a CSV file of all the RFDs along with their state, links, and other information in the repo for easy parsing. We then have functions in rust that allow us to easily get this information and automate or program tooling with RFD data.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">Short URLs</h3><div class="sectionbody"><div class="paragraph"><p>As you can imagine, keeping track of RFDs and their links is unweidly at scale. To help, we have short URLs. You can link to any RFD on GitHub with {num}.rfd.oxide.computer. So for example, 12.rfd.oxide.computer. The path also works: rfd.oxide.computer/12 if that is preferred.</p></div><div class="paragraph"><p>Any discussion for an RFD can be linked with {num}.rfd.oxide.computer/discussion.</p></div><div class="paragraph"><p>These short URLs get automatically updated when a new RFD is opened.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">Chat bot</h3><div class="sectionbody"><div class="paragraph"><p>In chat you can use !rfd {any text} | {rfd number} to return information about that RFD. For example, !rfd 1 returns the links to RFD 1, its discussion (if it is in discussion), and information about its state. Remembering the number for an RFD is often hard so any strings you pass to the bot will be fuzzy matched across RFD titles. !rfd user api will return the RFD that title matches the text. In this example, it is RFD 4.</p></div></div></div><div class="sect2"><h3 data-sectnum="..">Shared RFD Rendered Site</h3><div class="sectionbody"><div class="paragraph"><p>As a way to share certain RFDs with other parties like potential customers, partners, and friends of the company, we have created a website that renders the RFD markdown or asciidoc into HTML in a nice format. This is a nice way to get feedback without adding everyone to the repo (as well as nicely formatting the content).</p></div><div class="paragraph"><p>And that’s a wrap! Hopefully, this is helpful if you ever think about doing the same type of process internally!</p></div></div></div></div></div></div>]]></content>
        <author>
            <name>Jessie Frazelle</name>
        </author>
        <contributor>
            <name>Jessie Frazelle</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[RIP Khaled Bichara, 1971-2020]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/rip-khaled-bichara</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/rip-khaled-bichara"/>
        <updated>2020-02-03T17:00:00.000Z</updated>
        <summary type="html"><![CDATA[We were deeply saddened to learn that Khaled Bichara, one of Oxide's angel investors, died in a car accident in Cairo on Friday night. Our heart goes out to his family, and to all those who he touched over his career.]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div class="paragraph"><p>We were deeply saddened to learn that
<a href="https://en.wikipedia.org/wiki/Khaled_Bichara">Khaled Bichara</a>, one of Oxide&#8217;s
angel investors,
<a href="https://www.menabytes.com/khaled-bichara-dies-car-accident/">died in a car
accident in Cairo on Friday night</a>.</p></div><div class="paragraph"><p>Those of us who have known Khaled for years have known him to be a bold investor
who appreciated hard technical problems – and also a profoundly decent person,
who cared deeply for his family, his companies, and his country. Khaled&#8217;s
stories of kindling entrepreneurship in Egypt were inspiring to any who heard
them – and served as a reminder of the reponsibility that we all have to our
broader communities. Our most recent conversation with Khaled – just a few
short months ago – remains vivid: he was excited by our technical vision and
thrilled to be a part of Oxide. For our part, we were looking forward to a long
journey together, and to making good on his belief in us; we are gutted to have
lost him so abruptly. Our heart goes out to his family, and to all those who he
touched over his career; Silicon Valley may be a long way from Cairo, but his
impact and <a href="https://waya.media/the-legacy-of-khaled-bichara/">legacy</a> will be felt
here for years to come.</p></div></div>]]></content>
        <author>
            <name>Steve Tuck</name>
        </author>
        <author>
            <name>Bryan Cantrill</name>
        </author>
        <author>
            <name>Jessie Frazelle</name>
        </author>
        <contributor>
            <name>Steve Tuck</name>
        </contributor>
        <contributor>
            <name>Bryan Cantrill</name>
        </contributor>
        <contributor>
            <name>Jessie Frazelle</name>
        </contributor>
    </entry>
    <entry>
        <title type="html"><![CDATA[Oxide Computer Company: Initial boot sequence]]></title>
        <id>https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/introducing-the-oxide-computer-company</id>
        <link href="https://oxide-computer-5rmkwzczj-oxidecomputer.vercel.app/blog/introducing-the-oxide-computer-company"/>
        <updated>2019-12-01T21:09:00.000Z</updated>
        <summary type="html"><![CDATA[Introducing the Oxide Computer Company!]]></summary>
        <content type="html"><![CDATA[<div id="content" class="asciidoc-body w-full"><div class="paragraph"><p>We have started a computer company! If you haven&#8217;t yet, read Jess&#8217;s account of
us being <a href="https://blog.jessfraz.com/post/born-in-a-garage/">born in a garage</a> and
Bryan&#8217;s on <a href="http://dtrace.org/blogs/bmc/?p=1086">the soul of our new computer
company</a>. Also, see the perspectives of some of our founding engineers:
<a href="https://twitter.com/rmustacc">Robert Mustacchi</a> on
<a href="https://fingolfin.org/blog/20191202/oxide.html">joining Oxide</a>,
<a href="https://twitter.com/jmclulow">Joshua Clulow</a> on the need for
<a href="https://sysmgr.org/blog/2019/12/02/a-new-machine/">a new machine</a>, and
<a href="https://twitter.com/pfmooney">Patrick Mooney</a> on
<a href="https://www.pfmooney.com/post/2019-12-02-the-new-thing/">everything he sees
aligning at Oxide</a> (and in particular, on the importance of
<a href="https://oxide.computer/principles">Oxide&#8217;s principles</a>!).</p></div><div class="paragraph"><p>If it needs to be said, starting a computer company is an ambitious endeavor; we
are thrilled to have investment led by Eclipse Ventures and joined by an
incredible group of institutional and angel investors. Our investors see what we
see: the potential to integrate hardware and software together to bring
hyperscaler-class infrastructure to everyone.</p></div><div class="paragraph"><p>To use the machine as metaphor, Oxide is at the earliest stages of boot: the
power is on, and the first instructions have been executed – but we have a long
way to go before we&#8217;re fully operational! If you are interested in following our
progress
<a href="https://oxidecomputer.us20.list-manage.com/subscribe?u=e46acf89cdf1f5bddf3136473&amp;id=8a6d823488">sign
up for our mailing list</a>. If you are interested in potentially joining us, check
out <a href="https://oxide.computer/careers">our careers page</a>. And if nothing else, give
a listen to our podcast, <a href="https://onthemetal.fm">On the Metal</a>!</p></div></div>]]></content>
        <author>
            <name>Steve Tuck</name>
        </author>
        <author>
            <name>Bryan Cantrill</name>
        </author>
        <author>
            <name>Jessie Frazelle</name>
        </author>
        <contributor>
            <name>Steve Tuck</name>
        </contributor>
        <contributor>
            <name>Bryan Cantrill</name>
        </contributor>
        <contributor>
            <name>Jessie Frazelle</name>
        </contributor>
    </entry>
</feed>