Moved site to hugo

This commit is contained in:
Drew Galbraith 2023-12-06 16:38:11 -08:00
parent 1339d09535
commit cd8be31924
49 changed files with 243 additions and 615 deletions

5
archetypes/default.md Normal file
View File

@ -0,0 +1,5 @@
+++
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
date = {{ .Date }}
draft = true
+++

22
assets/css/main.css Normal file
View File

@ -0,0 +1,22 @@
body {
color: #222;
font-family: sans-serif;
line-height: 1.5;
margin: 1rem;
max-width: 768px;
}
header {
border-bottom: 1px solid #222;
margin-bottom: 1rem;
}
footer {
border-top: 1px solid #222;
margin-top: 1rem;
}
a {
color: #00e;
text-decoration: none;
}

View File

@ -16,7 +16,7 @@ img {
max-height: 500px;
}
.center-img {
.center-img img {
display: block;
margin-left: auto;
margin-right: auto;

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
$-- Run with the following command:
$-- pandoc -s --template=blog/pandoc.html -o public/blog/sudoku.html blog/2023-04-10-sudoku.md
<html>
<head>
<meta charset="utf-8" />
<title>$title$</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<div class="container">
<h1 class="page-title">$title$</h1>
<div class="date">Published $date$</div>
$body$
</div>
</body>
</html>

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 136 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,6 +1,7 @@
---
title: "Writing a Sudoku Solver: Displaying the Grid"
date: 2023-04-10
draft: true
---
I previously dabbled with writing a [sudoku solver](https://gitlab.com/dgalbraith33/sudoku-solver)
@ -40,7 +41,8 @@ puzzle with nothing in it.
}
```
![A box with nothing in it.](images/sudoku-1.png){.center-img}
{{< figure src="images/sudoku-1.png" alt="A box with nothing in it."
class="center-img" >}}
I'm not joking when I say I'm going to have to do baby steps here.
@ -67,33 +69,37 @@ want a narrower one for the cells.
}
```
![](images/sudoku-2.png){.center-img}
{{< figure src="images/sudoku-2.png" alt="Boxes stacked vertically."
class="center-img" >}}
Reload that and... right div's auto linebreak after them.
I think we can "float: left" these bad boys and...
![](images/sudoku-3.png){.center-img}
{{< figure src="images/sudoku-3.png" alt="Boxes stacked vertically in pairs."
class="center-img" >}}
Right, now I'm pretty sure the boxes are 210 + 4 pixels wide because the border isn't included.
While I'm tempted to just math my way out of this I recall that you can specify the border-box
sizing to avoid this.
Right, now I'm pretty sure the boxes are 210 + 4 pixels wide because the border
isn't included. While I'm tempted to just math my way out of this I recall that
you can specify the border-box sizing to avoid this.
Now this works! Now the astute of you may have noticed that there were 10 not 9 boxes in the
screenshot with the 2 columns. That became even more obvious in the full grid.
![Off by one errors...](images/sudoku-4.png){.center-img}
{{< figure src="images/sudoku-4.png" alt="A 3x3 grid of boxes with one extra below it."
class="center-img" >}}
Ok now we can just recreate all of this with the cells and should be good to go right?
Nope! The internal size of the boxes are now only 206x206 because of the border-box attribute. But
I now realize I can just get rid of the puzzle sizing all together and go back to regular sizing on
the boxes. This happens to work because 4 214px boxes won't fit in the 800px wide container. (Again
just use flexbox).
Nope! The internal size of the boxes are now only 206x206 because of the
border-box attribute. But I now realize I can just get rid of the puzzle sizing
all together and go back to regular sizing on the boxes. This happens to work
because 4 214px boxes won't fit in the 800px wide container. (Again just use
flexbox).
Finally this works!
![We have a grid!](images/sudoku-5.png){.center-img}
{{< figure src="images/sudoku-5.png" alt="A 3x3 grid of boxes." class="center-img" >}}
## Displaying a puzzle
@ -114,7 +120,7 @@ StackOverflow answer convinced me.
}
```
![](images/sudoku-6.png){.center-img}
{{< figure src="images/sudoku-6.png" alt="A box with 9 cells in it." class="center-img" >}}
### Taking the puzzle from the URL
@ -153,7 +159,7 @@ window.onload = (event) => {
And hooray it works super well!
![This isn't quite right.](images/sudoku-7.png){.center-img}
{{< figure src="images/sudoku-7.png" alt="A full sudoku puzzle!" class="center-img" >}}
Oh wait... I didn't think about the fact that the elements in the HTMLCollection from the
document.getElementsByClassName call wouldn't be in the row order of the puzzle (all of the cells
@ -176,7 +182,7 @@ for (i = 0; i < 81; i++) {
It works!
![We have a puzzle!](images/sudoku-8.png){.center-img}
{{< figure src="images/sudoku-8.png" alt="A full sudoku puzzle for real this time!" class="center-img" >}}
Still some goofiness like the border on the outside being thinner than the interiors but I'm pretty
happy with this for now.
@ -202,7 +208,8 @@ string and let the browser break them up into multiple lines for us.
This comes out quite nicely:
![](images/sudoku-9.png){.center-img}
{{< figure src="images/sudoku-9.png" alt="The top boxes of a sudoku puzzle with pencil marks"
class="center-img" >}}
### Reading the pencil marks from the url
@ -238,4 +245,5 @@ Using the string above we can use the following javascript code to parse and ins
Which also comes out nicely:
![](images/sudoku-10.png){.center-img}
{{< figure src="images/sudoku-10.png" alt="The top boxes of a sudoku puzzle with pencil marks"
class="center-img" >}}

0
content/blog/_index.md Normal file
View File

View File

@ -1,17 +1,21 @@
---
title: "AcadiaOS 0.1.0"
date: 2023-12-06
---
+++
title = 'Acadia 0.1.0'
date = 2023-12-06
draft = true
tags = ['osdev']
+++
For the last six months or so I've been periodically working on developing a
hobby operating system. A couple weeks ago I decided that I should finally aim
to cut a "release." This very-early release doesn't include a bunch of user
functionality. Namely you can navigate a filesystem in a primitive manner and
functionality but does have a fair amount of kernel features.
Namely you can navigate a filesystem in a primitive manner and
execute binaries. The following image shows just about everything the OS can do.
(The black window is the OS running in QEMU and the larger gray window is debug
output sent to COM1).
![AcadiaOS in action](images/acadiaos-0.1.0.png)
![AcadiaOS in action](/images/blog/acadiaos-0.1.0.png)
While there isn't much to do as a user, there are a lot of building blocks there
that I spent the last 6 months learning about and working on.

4
content/sudoku/index.md Normal file
View File

@ -0,0 +1,4 @@
+++
title = 'Sudoku'
layout = 'sudoku'
+++

3
hugo.toml Normal file
View File

@ -0,0 +1,3 @@
baseURL = 'https://example.org/'
languageCode = 'en-us'
title = 'Tiramisu'

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}" dir="{{ or site.Language.LanguageDirection `ltr` }}">
<head>
{{ partial "head.html" . }}
</head>
<body>
<div class="container">
<header>
{{ partial "header.html" . }}
</header>
<main>
{{ block "main" . }}{{ end }}
</main>
<footer>
{{ partial "footer.html" . }}
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,7 @@
{{ define "main" }}
{{ .Content }}
{{ range site.RegularPages }}
<h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
{{ .Summary }}
{{ end }}
{{ end }}

View File

@ -0,0 +1,8 @@
{{ define "main" }}
<h1>{{ .Title }}</h1>
{{ .Content }}
{{ range .Pages }}
<h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
{{ .Summary }}
{{ end }}
{{ end }}

View File

@ -0,0 +1,10 @@
{{ define "main" }}
<h1>{{ .Title }}</h1>
{{ $dateMachine := .Date | time.Format "2006-01-02T15:04:05-07:00" }}
{{ $dateHuman := .Date | time.Format ":date_long" }}
<time datetime="{{ $dateMachine }}" class="date">{{ $dateHuman }}</time>
{{ .Content }}
{{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
{{ end }}

View File

@ -1,15 +1,4 @@
<!DOCTYPE html>
<html>
<head>
<title>Sudoku</title>
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="css/sudoku.css">
<script src="scripts/sudoku.js"></script>
</head>
<body>
<div class="container">
<h1>Sudoku</h1>
{{ define "main" }}
<div class="puzzle">
<div class="box">
<div id="1" class="cell">
@ -192,6 +181,4 @@
</div>
</div>
</div>
</div>
</body>
</html>
{{ end }}

View File

@ -0,0 +1 @@
<p>Copyright {{ now.Year }}. All rights reserved.</p>

View File

@ -0,0 +1,5 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>{{ if .IsHome }}{{ site.Title }}{{ else }}{{ printf "%s | %s" .Title site.Title }}{{ end }}</title>
{{ partialCached "head/css.html" . }}
{{ partialCached "head/js.html" . }}

View File

@ -0,0 +1,19 @@
{{- with resources.Get "css/styles.css" }}
{{- if eq hugo.Environment "development" }}
<link rel="stylesheet" href="{{ .RelPermalink }}">
{{- else }}
{{- with . | minify | fingerprint }}
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
{{- end }}
{{- end }}
{{- end }}
{{- range .Resources.Match "css/*.css" }}
{{- if eq hugo.Environment "development" }}
<link rel="stylesheet" href="{{ .RelPermalink }}">
{{- else }}
{{- with . | minify | fingerprint }}
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,25 @@
{{- with resources.Get "js/main.js" }}
{{- if eq hugo.Environment "development" }}
{{- with . | js.Build }}
<script src="{{ .RelPermalink }}"></script>
{{- end }}
{{- else }}
{{- $opts := dict "minify" true }}
{{- with . | js.Build $opts | fingerprint }}
<script src="{{ .RelPermalink }}" integrity="{{- .Data.Integrity }}" crossorigin="anonymous"></script>
{{- end }}
{{- end }}
{{- end }}
{{- range .Resources.Match "js/*.js" }}
{{- if eq hugo.Environment "development" }}
{{- with . | js.Build }}
<script src="{{ .RelPermalink }}"></script>
{{- end }}
{{- else }}
{{- $opts := dict "minify" true }}
{{- with . | js.Build $opts | fingerprint }}
<script src="{{ .RelPermalink }}" integrity="{{- .Data.Integrity }}" crossorigin="anonymous"></script>
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,2 @@
<h1>{{ site.Title }}</h1>
{{ partial "menu.html" (dict "menuID" "main" "page" .) }}

View File

@ -0,0 +1,51 @@
{{- /*
Renders a menu for the given menu ID.
@context {page} page The current page.
@context {string} menuID The menu ID.
@example: {{ partial "menu.html" (dict "menuID" "main" "page" .) }}
*/}}
{{- $page := .page }}
{{- $menuID := .menuID }}
{{- with index site.Menus $menuID }}
<nav>
<ul>
{{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
</ul>
</nav>
{{- end }}
{{- define "partials/inline/menu/walk.html" }}
{{- $page := .page }}
{{- range .menuEntries }}
{{- $attrs := dict "href" .URL }}
{{- if $page.IsMenuCurrent .Menu . }}
{{- $attrs = merge $attrs (dict "class" "active" "aria-current" "page") }}
{{- else if $page.HasMenuCurrent .Menu .}}
{{- $attrs = merge $attrs (dict "class" "ancestor" "aria-current" "true") }}
{{- end }}
{{- $name := .Name }}
{{- with .Identifier }}
{{- with T . }}
{{- $name = . }}
{{- end }}
{{- end }}
<li>
<a
{{- range $k, $v := $attrs }}
{{- with $v }}
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
{{- end }}
{{- end -}}
>{{ $name }}</a>
{{- with .Children }}
<ul>
{{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
</ul>
{{- end }}
</li>
{{- end }}
{{- end }}

View File

@ -0,0 +1,23 @@
{{- /*
For a given taxonomy, renders a list of terms assigned to the page.
@context {page} page The current page.
@context {string} taxonomy The taxonony.
@example: {{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
*/}}
{{- $page := .page }}
{{- $taxonomy := .taxonomy }}
{{- with $page.GetTerms $taxonomy }}
{{- $label := (index . 0).Parent.LinkTitle }}
<div>
<div>{{ $label }}:</div>
<ul>
{{- range . }}
<li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
{{- end }}
</ul>
</div>
{{- end }}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,235 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Writing a Sudoku Solver: Displaying the Grid</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<div class="container">
<h1 class="page-title">Writing a Sudoku Solver: Displaying the
Grid</h1>
<div class="date">Published 2023-04-10</div>
<p>I previously dabbled with writing a <a
href="https://gitlab.com/dgalbraith33/sudoku-solver">sudoku
solver</a> but got carried away early on by making crazy speed
improvements rather than actually improving the solving ability.
What I did enjoy about the project is making logical deductions
rather than the guess and backcheck method commonly employed.</p>
<p>I want to take another crack at doing this except this time focus
on the question “Given the current state what are any of the next
possible deductions” without focusing on speed. Eventually Id also
like to take a crack at solving other types of sudokus (Chess
Sudoku, Killer Sudoku, etc).</p>
<p>One of the issues I had last time as I was debugging was
displaying the current board state in a clean way so I could see
what had gone wrong. So this time around Im planning on writing a
quick HTML/javascript board state display to be able to visualize
the board. For now I dont intend it to be interactive, however Ill
likely add that in the future.</p>
<h2 id="creating-a-sudoku-grid">Creating a sudoku grid</h2>
<p>Im no front end dev so this may take some time. I literally just
want to create an outline for the puzzle with nothing in it.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode html"><code class="sourceCode html"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;div</span> <span class="er">class</span><span class="ot">=</span><span class="st">&quot;container&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">&lt;h1&gt;</span>Sudoku<span class="kw">&lt;/h1&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">&lt;div</span> <span class="er">class</span><span class="ot">=</span><span class="st">&quot;puzzle&quot;</span><span class="kw">&gt;</span>nothing<span class="kw">&lt;/div&gt;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;/div&gt;</span></span></code></pre></div>
<div class="sourceCode" id="cb2"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">.container</span> {</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">max-width</span>: <span class="dv">800</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">margin</span>: <span class="bu">auto</span><span class="op">;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="fu">.puzzle</span> {</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">border</span>: <span class="dv">1</span><span class="dt">px</span> <span class="dv">solid</span> <span class="cn">black</span><span class="op">;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<figure>
<img src="images/sudoku-1.png" class="center-img"
alt="A box with nothing in it." />
<figcaption aria-hidden="true">A box with nothing in
it.</figcaption>
</figure>
<p>Im not joking when I say Im going to have to do baby steps
here.</p>
<p>Next Ill try to actually make a square grid. The best way to do
this is probably with flexbox or something but Im just gonna hard
code some widths and heights.</p>
<p>Ok lets make this thing a width divisible by 9 so we can divide
it into equal portions. I chose 630 quite honestly because it was
the first number below 800px that popped into my head divisible by
9.</p>
<p>Lets focus on the 9 main boxes in the grid now before worrying
about the cells. Ill make each box 210 pixels tall and wide. And
slap a big ole border on there. Lets make it 2px because we will
want a narrower one for the cells.</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">.puzzle</span> {</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">width</span>: <span class="dv">630</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">height</span>: <span class="dv">630</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="fu">.box</span> {</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">border</span>: <span class="dv">2</span><span class="dt">px</span> <span class="dv">solid</span> <span class="cn">black</span><span class="op">;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">width</span>: <span class="dv">210</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">height</span>: <span class="dv">210</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><img src="images/sudoku-2.png" class="center-img" /></p>
<p>Reload that and… right divs auto linebreak after them.</p>
<p>I think we can “float: left” these bad boys and…</p>
<p><img src="images/sudoku-3.png" class="center-img" /></p>
<p>Right, now Im pretty sure the boxes are 210 + 4 pixels wide
because the border isnt included. While Im tempted to just math my
way out of this I recall that you can specify the border-box sizing
to avoid this.</p>
<p>Now this works! Now the astute of you may have noticed that there
were 10 not 9 boxes in the screenshot with the 2 columns. That
became even more obvious in the full grid.</p>
<figure>
<img src="images/sudoku-4.png" class="center-img"
alt="Off by one errors…" />
<figcaption aria-hidden="true">Off by one errors…</figcaption>
</figure>
<p>Ok now we can just recreate all of this with the cells and should
be good to go right?</p>
<p>Nope! The internal size of the boxes are now only 206x206 because
of the border-box attribute. But I now realize I can just get rid of
the puzzle sizing all together and go back to regular sizing on the
boxes. This happens to work because 4 214px boxes wont fit in the
800px wide container. (Again just use flexbox).</p>
<p>Finally this works!</p>
<figure>
<img src="images/sudoku-5.png" class="center-img"
alt="We have a grid!" />
<figcaption aria-hidden="true">We have a grid!</figcaption>
</figure>
<h2 id="displaying-a-puzzle">Displaying a puzzle</h2>
<p>Next up is to actually get some numbers in this bad boy. Now this
is where I relent and use flexboxes because <a
href="https://stackoverflow.com/questions/2939914/how-do-i-vertically-align-text-in-a-div/13515693">this</a>
StackOverflow answer convinced me.</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">.cell</span> {</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">...</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">font-size</span>: <span class="dv">40</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">font-weight</span>: <span class="dv">bold</span><span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">display</span>: <span class="dv">flex</span><span class="op">;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">align-items</span>: <span class="dv">center</span><span class="op">;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">justify-content</span>: <span class="dv">center</span><span class="op">;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p><img src="images/sudoku-6.png" class="center-img" /></p>
<h3 id="taking-the-puzzle-from-the-url">Taking the puzzle from the
URL</h3>
<p>Now to make it so I can get the page to display any puzzle I want
easily from the solver, Ill allow specifying it as a parameter in
the URL. For now in a row-major string of 81 characters using a
period to denote blank spaces.</p>
<p>Ill can just get all of the cells by class name and iterate over
them in the same order as the puzzle string and it will display
relatively easily.</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode js"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="bu">window</span><span class="op">.</span><span class="at">onload</span> <span class="op">=</span> (<span class="bu">event</span>) <span class="kw">=&gt;</span> {</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">var</span> params <span class="op">=</span> <span class="kw">new</span> <span class="fu">URLSearchParams</span>(<span class="bu">window</span><span class="op">.</span><span class="at">location</span><span class="op">.</span><span class="at">search</span>)<span class="op">;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">var</span> puzzle <span class="op">=</span> params<span class="op">.</span><span class="fu">get</span>(<span class="st">&quot;p&quot;</span>)<span class="op">;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (puzzle <span class="op">===</span> <span class="kw">null</span>) {</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (puzzle<span class="op">.</span><span class="at">length</span> <span class="op">!=</span> <span class="dv">81</span>) {</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&quot;Failure: puzzle url len is &quot;</span> <span class="op">+</span> puzzle<span class="op">.</span><span class="at">length</span>)<span class="op">;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">var</span> cells <span class="op">=</span> <span class="bu">document</span><span class="op">.</span><span class="fu">getElementsByClassName</span>(<span class="st">&quot;cell&quot;</span>)<span class="op">;</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (cells<span class="op">.</span><span class="at">length</span> <span class="op">!=</span> <span class="dv">81</span>) {</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&quot;Failure: wrong number of cells: &quot;</span> <span class="op">+</span> cells<span class="op">.</span><span class="at">length</span>)<span class="op">;</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> (i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> <span class="dv">81</span><span class="op">;</span> i<span class="op">++</span>) {</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (puzzle[i] <span class="op">!=</span> <span class="st">&#39;.&#39;</span>) {</span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a> cells[i]<span class="op">.</span><span class="at">innerText</span> <span class="op">=</span> puzzle[i]</span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>And hooray it works super well!</p>
<figure>
<img src="images/sudoku-7.png" class="center-img"
alt="This isnt quite right." />
<figcaption aria-hidden="true">This isnt quite right.</figcaption>
</figure>
<p>Oh wait… I didnt think about the fact that the elements in the
HTMLCollection from the document.getElementsByClassName call
wouldnt be in the row order of the puzzle (all of the cells in box
1 come first).</p>
<p>You can see the effect of this as there are 2 9s in column 2 of
the puzzle. Oops.</p>
<p>Im going to just do the old fashioned brute force way and give
each cell an id from 1-81 and insert those manually. Im sure there
is a better way but hey this works.</p>
<p>Then with a quick update to the code.</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode js"><code class="sourceCode javascript"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> (i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> <span class="dv">81</span><span class="op">;</span> i<span class="op">++</span>) {</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (puzzle[i] <span class="op">!=</span> <span class="st">&#39;.&#39;</span>) {</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="bu">document</span><span class="op">.</span><span class="fu">getElementById</span>(i<span class="op">+</span><span class="dv">1</span>)<span class="op">.</span><span class="at">innerText</span> <span class="op">=</span> puzzle[i]</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>It works!</p>
<figure>
<img src="images/sudoku-8.png" class="center-img"
alt="We have a puzzle!" />
<figcaption aria-hidden="true">We have a puzzle!</figcaption>
</figure>
<p>Still some goofiness like the border on the outside being thinner
than the interiors but Im pretty happy with this for now.</p>
<h2 id="showing-pencil-marks">Showing pencil marks</h2>
<p>Now to really visualize the solvers state, well also need to
see which pencil marks it has. These could be styled nicely but for
now I just went with a span inside the cell div with the following
style.</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="fu">.cell</span> <span class="op">&gt;</span> span {</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">font-size</span>: <span class="dv">10</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">font-weight</span>: <span class="dv">normal</span><span class="op">;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">text-align</span>: <span class="dv">center</span><span class="op">;</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">letter-spacing</span>: <span class="dv">6</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">word-wrap</span>: anywhere<span class="op">;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>The letter-spacing and wordwrap attributes let us just jam all of
the pencil marks in as a single string and let the browser break
them up into multiple lines for us.</p>
<p>This comes out quite nicely:</p>
<p><img src="images/sudoku-9.png" class="center-img" /></p>
<h3 id="reading-the-pencil-marks-from-the-url">Reading the pencil
marks from the url</h3>
<p>For this url trick we will add the pencil marks using a comma
separated array like so:</p>
<p>123,,,,456,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,</p>
<p>Using the string above we can use the following javascript code
to parse and insert them:</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode js"><code class="sourceCode javascript"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a> <span class="kw">var</span> marks_param <span class="op">=</span> params<span class="op">.</span><span class="fu">get</span>(<span class="st">&quot;m&quot;</span>)<span class="op">;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (marks_param <span class="op">===</span> <span class="kw">null</span>) {</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">var</span> marks <span class="op">=</span> marks_param<span class="op">.</span><span class="fu">split</span>(<span class="st">&quot;,&quot;</span>)<span class="op">;</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (marks<span class="op">.</span><span class="at">length</span> <span class="op">!=</span> <span class="dv">81</span>) {</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&quot;Failure: marks url len is &quot;</span> <span class="op">+</span> marks<span class="op">.</span><span class="at">length</span>)<span class="op">;</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> (i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> <span class="dv">81</span><span class="op">;</span> i<span class="op">++</span>) {</span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (marks[i]<span class="op">.</span><span class="at">length</span> <span class="op">&gt;</span> <span class="dv">0</span>) {</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">var</span> cell <span class="op">=</span> <span class="bu">document</span><span class="op">.</span><span class="fu">getElementById</span>(i<span class="op">+</span><span class="dv">1</span>)<span class="op">;</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (cell<span class="op">.</span><span class="at">innerHTML</span><span class="op">.</span><span class="fu">trim</span>()<span class="op">.</span><span class="at">length</span> <span class="op">&gt;</span> <span class="dv">0</span>) {</span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&quot;Pencil marks in cell with number: &quot;</span> <span class="op">+</span> (i<span class="op">+</span><span class="dv">1</span>))<span class="op">;</span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a> } <span class="cf">else</span> {</span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a> cell<span class="op">.</span><span class="at">innerHTML</span> <span class="op">=</span> <span class="st">&quot;&lt;span&gt;&quot;</span> <span class="op">+</span> marks[i] <span class="op">+</span> <span class="st">&quot;&lt;/span&gt;&quot;</span><span class="op">;</span></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a> }</span></code></pre></div>
<p>Which also comes out nicely:</p>
<p><img src="images/sudoku-10.png" class="center-img" /></p>
</div>
</body>
</html>

View File

@ -1,323 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>AcadiaOS 0.1.0</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<div class="container">
<h1 class="page-title">AcadiaOS 0.1.0</h1>
<div class="date">Published 2023-12-06</div>
<p>For the last six months or so Ive been periodically working on
developing a hobby operating system. A couple weeks ago I decided
that I should finally aim to cut a “release.” This very-early
release doesnt include a bunch of user functionality. Namely you
can navigate a filesystem in a primitive manner and execute
binaries. The following image shows just about everything the OS can
do. (The black window is the OS running in QEMU and the larger gray
window is debug output sent to COM1).</p>
<figure>
<img src="images/acadiaos-0.1.0.png" alt="AcadiaOS in action" />
<figcaption aria-hidden="true">AcadiaOS in action</figcaption>
</figure>
<p>While there isnt much to do as a user, there are a lot of
building blocks there that I spent the last 6 months learning about
and working on.</p>
<h2 id="what-i-knew-going-into-this">What I knew going into
this</h2>
<p>Frankly, not a lot.</p>
<p>I took an OS class in college, but while it covered OS
fundamentals the projects were based on writing modules for the
Linux kernel rather than working on our own barebones kernel and OS.
So while I vaguely knew of how things like process scheduling,
interrupts, and memory management worked, I had no experience
getting down to the brass tacks of how to actually implement these
things.</p>
<p>I had over the previous couple years spent some time writing a
small kernel to start learning some of these things. However, since
I used it as a testing ground for learning with no real design goals
or long term plan, it was kind of a mess. I had gotten to user space
with some primitive syscalls but it was memory issues and page
faults galore. So I decided to “reboot” things earlier this
year.</p>
<h2 id="design-goals">Design Goals</h2>
<p>I decided I wanted to write a microkernel based OS because I
figured the more of my messy code I can move to user space the
better. And also because thats what OS nerds do. Im not too
concerned about the performance cost of extra syscalls because by
god this thing isnt gonna be too performant anyways.</p>
<p>Additionally, I wanted to try to make the system
capability-based. Trying a new permission model was appealing to me
because Ive always felt the unix style one was a bit clunky. After
spending some time reading about seL4 and digging into the Zircon
interface I had a (very) rough idea of how these systems worked. I
have no illusions that my OS will every be “secure” but I find the
model interesting.</p>
<h2 id="references-and-resources">References and Resources</h2>
<p>Over the course of this project I used a lot of resources, not
least of which the OSDev.org <a
href="https://wiki.osdev.org">wiki</a> and <a
href="https://forum.osdev.org">forums</a>. The resources provided
there were invaluable, but the biggest lesson I learned since my
first time around writing a kernel was to rely on specs more than
others code samples and tutorials.</p>
<p>For the low-level stuff I spent a lot of time digging through
Intel and AMDs monstrous programming manuals. It was helpful to use
the wiki to learn for instance that using the “iret” instruction is
a good way to jump to user-space for the first time, but from there
using the programming manuals to understand exactly how that
instruction works rather than just copying code from somewhere. I
had a similar experience with initializing the GDT in 64 bit
software. There are a lot of random claims out there on exactly how
you have to set it up, so it was much more efficient to just go dig
through the AMD64 spec however dry it may be.</p>
<p>As I worked my way up the stack, I used the SATA and AHCI specs
as well. They pose the additional complication of splitting things
up across multiple specs so you have to go back and forth a lot in
non-obvious ways. Hey at least they dont try to charge you
thousands of dollars to get the spec like PCI.</p>
<p>I also found that when you needed examples of how to do something
specific it can be far better to look at an existing operating
systems approach to help contextualize a specification. Andreas
Klings SerenityOS was invaluable for this for some low level x86
things. I also referenced the Zircon microkernel to figure out how
to use C++ templates to downcast capability pointers to their
specific objects types without relying on RTTI (run time type
information).</p>
<h2 id="kernel-implementation-details">Kernel Implementation
Details</h2>
<p>Ok enough about high level information, ambitions, and goals.
Lets discuss a little bit more about what the actual system can do
at this point. I named the kernel Zion because it is another place I
love and it is also kind of fun to think of the operating system as
everything from (A)cadia down to (Z)ion.</p>
<p>This section will frequently reference the source code which is
available on my self-hosted <a
href="https://gitea.tiramisu.one">gitea</a> or mirrored to <a
href="https://github.com/dgalbraith33/acadia">GitHub</a>.</p>
<h3 id="low-level-x86-64-stuff">Low-level x86-64 stuff</h3>
<p>Because I found setting up paging, the higher half kernel, and
getting to long mode to be a pain the first time around, I decided
to use the <a
href="https://github.com/limine-bootloader/limine">limine
bootloader</a> to start the kernel this time around instead of GRUB
so I could focus on slightly higher level things. I have ambitions
to make the kernel more bootloader-agnostic in the future but for
now it is tightly coupled to the limine protocol.</p>
<p>On top of the things mentioned above, we use the limine protocol
to:</p>
<ul>
<li>Get a map of physical memory.</li>
<li>Set up a higher-half direct map of memory.</li>
<li>Find the RDSP.</li>
<li>Get a VGA framebuffer from UEFI.</li>
<li>Load the 3 init programs that are needed to bootstrap the
VFS.</li>
</ul>
<p>Following boot we immediately initialize the global descriptor
table (GDT) and interrupt descriptor table (IDT). The
<strong>GDT</strong> is mostly irrelevant for x86-64, however it was
interesting trying to get it to work with the sysret function which
expects two copies of the user-space segment descriptors to allow
returing to 32bit code from a 64 bit OS. Right now the system
doesnt support 32 bit code (and likely never will) so we just
duplicate the 64 bit code segment.</p>
<p>The <strong>IDT</strong> is fairly straightforward and barebones
for now. I slowly add more debugging information to faults as I run
into them and it is useful. One of the biggest improvements was
setting up a seperate kernel stack for Page Faults and General
Protection Faults. That way if I broke memory related to the current
stack frame I get useful debugging information rather than an
immediate triple fault. I also recently added some very sloppy stack
unwind code so I can more easily find the context that the fault
occurred in.</p>
<p>Finally we also initialize the <strong>APIC</strong> in a
rudimentary fashion. The timer is used to trigger scheduling events
and we map PCI and PS/2 Keyboard interrupts to appropriate vectors
in the IDT.</p>
<h3 id="memory-management">Memory management</h3>
<p>Memory management seems to be one of those areas where every time
I make progress on something I discover about 4 more things Ill
have to do down the line. Im somewhat happy with the progress Ive
made so far but I still have a lot to read up on and learn -
especially relating to caching policies for mapped pages.</p>
<p>For <strong>physical memory management</strong> I maintain the
available memory regions in two separate linked lists. One list
contains single pages for when those are requested, the other
contains the large memory regions which are populated during
initialization. This design allows us to easily reuse freed pages
(using the list of small pages) while still efficiently finding
large blocks for things like memory mapped IO (using the list of
large pages).</p>
<p>The one catch is that to build these linked lists we need an
available heap. And to have an available heap we need to be able to
allocate a physical memory region for it (and its necessary paging
structures). To accommodate this, we initialize a temporary physical
memory manager that just takes a hardcoded number of pages from the
first memory region and doles them out in sequence. Right now I
hardcode the number of necessary pages to exactly the number it
needs. This means if I change something that causes more pages to be
allocated earlier than they need to be it is obvious because things
break.</p>
<p>For <strong>virtual memory management</strong> I keep the higher
half (kernel) mappings identical in each address space. Most of the
kernel mappings are already availble from the bootloader but some
are added for heaps and additional stacks. For user memory we
maintain a tree of the mapped in objects to ensure that none
intersect. Right now the tree is innefficient because it doesnt
self balance and most objects are inserted in ascending order
(i.e. it is essentially a linked list).</p>
<p>For user space memory structures we wait until the memory is
accessed and generates a page fault to actually map it in. In order
to map it in we check each paging structure in the higher-half
direct map (rather than using a recursive page structure) to ensure
it exists, allocating a page table if necessary. All physical pages
used for paging structures are freed when the process exits.</p>
<p>For <strong>kernel heap management</strong> I wrote a <a
href="https://en.wikipedia.org/wiki/Slab_allocation">slab-allocator</a>
for relatively small allocations (up to 128 bytes currently). I plan
on raising the limit for that as well as adding a buddy allocator
for larger allocations in the future but for now there is no need -
all of the allocations are 128 bytes or less! Larger allocations for
now are done using a linear allocator.</p>
<h3 id="scheduling">Scheduling</h3>
<p>Right now the scheduling process is very straight forward. Each
runnable thread is kept in an intrusive linked list and scheduled
for a single time slice in a round robin fashion.</p>
<p>Thread can block on other threads, semaphores, or mutexes. When
this happens they are flagged as blocked and moved to an intrusive
linked list on that object which is responsible for scheduling those
threads once the relevant state changes.</p>
<p>The context switching code simply dumps all of the registers onto
the stack and then writes the stack pointer into the thread
structure. It also writes the SSE registers to an allocated space on
the thread structure. I believe this code could be made more
efficient by only pushing callee-saved registers and using the x86
feature that allows you to lazily save the SSE registers only once
they are used. However for now I prefer this code be more reliable
than efficient (because it scares me and is a PITA to debug).</p>
<p>Finally, there are definitely critical sections in the kernel
code that are not mutex protected currently. It is on the TODO list
to do a good audit of this in preparation for SMP (AcadiaOS 0.2
anyone?).</p>
<h3 id="interface">Interface</h3>
<p>Most system calls the kernel provides either (a) create and
return a capability or (b) operate on an existing capability.
Capabilities can be duplicated and/or transmitted to other processes
using IPC.</p>
<p>For syscalls that operate on an existing capability, the kernel
checks that the capability exists, that it is of the correct type,
and that the caller has the correct permissions on it. Only then
does it act on the request.</p>
<p>The kernel provides APIs to:</p>
<ul>
<li>Manage processes and threads.</li>
<li>Synchronizes threads using mutexes and semaphores.</li>
<li>Allocate memory and map it into an address space.</li>
<li>Communicate with other processes using Endpoints, Ports, and
Channels.</li>
<li>Register IRQ handlers.</li>
<li>Manage Capabilites.</li>
<li>Print debug information to the VM output.</li>
</ul>
<h3 id="ipc">IPC</h3>
<p>Interprocess communication can be done using Endpoints, Ports, or
Channels. <strong>Endpoints</strong> are like servers that can be
called and provide a response. For each call a “ReplyPort”
capability is generated that the caller can wait for a response on
and the server can send its response to. <strong>Ports</strong> are
simply one-way streams of messages that dont expect a response.
Example uses are for process initialization information or for IRQ
handlers. <strong>Channels</strong> are for bidirectional message
passing that I havent found a use for and will probably replace in
the future with a byte-stream interface.</p>
<p>Message that are passed on these interfaces consist of two parts:
a byte array, and an array of capabilities. Each capability passed
is removed from the existing process and passed along to whichever
process receives the request.</p>
<p>Im fairly happy with these interfaces so far and was able to
build a user-space IDL (Yunq) on top of them to facilitate message
and capability passing. However, Im concerned about their ability
to handle certain concerns. For instance, since endpoints arent
“owned” by a specific process, it is impossible to tell if you are
“shouting into the void” at a process that has crashed or isnt
listening to the specific endpoint anymore.</p>
<h2 id="user-space-programs">User Space Programs</h2>
<p>There are a few user-space programs that are run on the
system:</p>
<ul>
<li><strong>Yellowstone</strong>: The init process that starts all
others and maintains a registry of endpoints. (Because Yellowstone
was first).</li>
<li><strong>Denali</strong>: A basic AHCI driver to read from disk.
(D for disk).</li>
<li><strong>VictoriaFallS</strong>: A VFS server with a super simple
read-only ext2 implementation. (I couldnt resist because it has VFS
in it).</li>
<li><strong>Teton</strong>: A terminal application with a
lightweight shell in it (should eventually be split). (T for
terminal).</li>
<li><strong>Voyageurs</strong>: PS/2 Keyboard driver with the intent
of becoming the USB driver. (Idk bytes traveling over USB are making
a voyage I guess).</li>
</ul>
<p>These programs are all bare-bones versions of what they could be
in the future. I hope to describe them in further detail in the
future, but for now the initialization process works like this.</p>
<ol type="1">
<li>Yellowstone, Denali, and VictoriaFallS binaries are loaded into
memory as modules by the bootloader.</li>
<li>The kernel loads and starts the Yellowstone process, passing it
memory capabilities to the Denali and VictoriaFallS binaries.</li>
<li>Yellowstone starts Denali and waits for it to register
itself.</li>
<li>Yellowstone reads the GPT and then starts VictoriaFallS on the
correct partition and waits for it to register itself.</li>
<li>Yellowstone then reads the /init.txt file from the disk and
starts each process specified (one per line) in succession.</li>
</ol>
<h2 id="yunq-idl">Yunq IDL</h2>
<p>As I began writing system services, I found a huge speed bump was
creating client and server classes for the service. I started by
just passing structs as a byte array and hardcoding whether or not
the process expected to receive a capability with the call. This
approach worked but was painful and led to me dreading each new
service I added to the system (not how it should be for a
microkernel architecture!). Additionally I did things like avoiding
repeated fields or strings fields that werent possible to pass in a
single struct.</p>
<p>It was clear I needed some sort of IDL to handle this, but for
months I waffled on it as I tried to figure out how to incorporate
an existing one into the system. That didnt work for two reasons.
First, we need a way to pass capabilities with the messages. These
kind of need to be sidechanneled because the kernel cant just treat
them as another string of bytes (they have to be moved into the
other processes capability space). Second, existing serialization
libraries tend to have dependencies, so porting them would require
porting those dependencies first. Granted, some of them just require
super basic things like say a libc implementation - but we dont
even have that yet. All that to say I ended up writing my own.</p>
<p>I was pleasantly surprised with how straightforward it ended up
being. I think it took me about 3 coding sessions to get the basic
parsing and codegen going for the language. It still doesnt have
all of the features I planned for it (like nested messages), but it
works super well for setting up new services quickly and easily.
Currently the implementation is in python because I wanted to get
something working quickly, but Ill probably reimplement it in a
compiled language in the future with a focus on better error
information.</p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>Overall, Im very pleased with how this project has turned out. I
feel like Ive definitely accomplished my goal to learn more about
how operating systems are actually implemented. It has been cool to
be able to pull back the curtain and see some of the simple
primitives that underlay the complex features of an operating
system.</p>
<p>I aim to continue forward with this project - without throwing
out the code again as I did earlier this year. Im happy with the
base and look to iterate on it, hopefully building something more
useful in the future but definitely learning more along the way.</p>
</div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 268 KiB

After

Width:  |  Height:  |  Size: 268 KiB