<feed xmlns='http://www.w3.org/2005/Atom'>
<title>tashaboot, branch main</title>
<subtitle>tashaboot multi-stage bootloader framework</subtitle>
<id>https://p10-linux-brads.osuosl.org/tashaboot/atom?h=main</id>
<link rel='self' href='https://p10-linux-brads.osuosl.org/tashaboot/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://p10-linux-brads.osuosl.org/tashaboot/'/>
<updated>2026-10-03T22:12:35Z</updated>
<entry>
<title>tashaboot: VMSAv8-64 identity map at EL1 and EL2</title>
<updated>2026-10-03T22:12:35Z</updated>
<author>
<name>Bradley Morgan</name>
<email>brads@mainlining.org</email>
</author>
<published>2026-10-03T22:12:35Z</published>
<link rel='alternate' type='text/html' href='https://p10-linux-brads.osuosl.org/tashaboot/commit/?id=6b3fcc0def1e173c76943682dcf3cba6edcd3b55'/>
<id>urn:sha1:6b3fcc0def1e173c76943682dcf3cba6edcd3b55</id>
<content type='text'>
The bootloader now builds its own stage 1 translation tables instead
of only tearing firmware state down. one L0 table, one L1 under it,
device nGnRE block for the low 1GB, normal writeback 2MB blocks for
RAM. the descriptors, attribute encodings, MAIR and TCR settings come
straight from the manual, level 0/1/2 and level 3 formats at D5-2444
and D5-2447, stage 1 attribute fields at D5-2451, MAIR region
attributes at D5-2476, the PA size from ID_AA64MMFR0_EL1.PARange per
D5-2399.

The tables are EL aware, TTBR0/TCR/MAIR at whichever regime the entry
left us in, EL2 or EL1, and the self test translates through AT
S1E2R or AT S1E1R per the exception level and checks PAR_EL1 for the
identity result:

  mmu: mmio 0x09000000 (uart) ok, pa 9000000
  mmu: mmio 0x00000000 ok, pa 0
  mmu: ram  0x40200000 (load) ok, pa 40200000
  mmu: ram  0x41000000 ok, pa 41000000
  mmu: self 0x40080000 ok, pa 40080000
  mmu: identity map on

The map is torn down again before the payload, the kernel wants the
architecture state at entry, not ours.

Two bugs the self test caught on the way. T0SZ was 25 for a 39-bit
VA, but with the 4KB granule a 39-bit VA starts the walk at level 1,
and the L0 indexed structure was misread one level over, every
descriptor landed in the wrong slot and all fetches past the first
2MB faulted level 1. T0SZ is 16 now, the walk starts at level 0 and
the three level structure matches. The second, the mmio table was
orphaned, the l0 entry was written twice and the second write won,
so the device block was never reachable and AT on the uart address
faulted. the mmio block now lives at l1[0] in the same L1 table as
RAM.

The stack also moved to its own region above the bss in the linker
script. the tables are bss objects, a stack growing down from the
bss end shares their address space and a deep call chain writes into
the top table.

Signed-off-by: Bradley Morgan &lt;brads@mainlining.org&gt;
</content>
</entry>
<entry>
<title>tashaboot: arm64 bootloader</title>
<updated>2026-10-03T21:37:00Z</updated>
<author>
<name>Bradley Morgan</name>
<email>brads@mainlining.org</email>
</author>
<published>2026-10-03T20:02:29Z</published>
<link rel='alternate' type='text/html' href='https://p10-linux-brads.osuosl.org/tashaboot/commit/?id=9dbdb15abf8ffb9dbdd972d6bbbcea9a3591e2a3'/>
<id>urn:sha1:9dbdb15abf8ffb9dbdd972d6bbbcea9a3591e2a3</id>
<content type='text'>
A small arm64 bootloader. No board code, no device tree porting, the
architecture manual is the whole story: exception vectors in the
fixed 16 slot layout (Table D1-7), ESR_ELx decoded by exception class
(D1-2172), EL entry and eret chains per the programmers model
(D1-2146), cache maintenance by set/way over the CLIDR_EL1 levels,
semihosting for console and file io per DUI 0203, and the A64 boot
protocol from Documentation/arch/arm64/booting.rst.

The loader boots a stock mainline Image end to end on the qemu virt
machine. Boot receipt with 7.3-rc3 (42MB Image):

  tashaboot 0.1
  loaded 43450368 bytes at 40200000, entry 40200000
  jumping
  [    0.000000] Booting Linux on physical CPU 0x0000000000 [0x411fd070]
  [    0.000000] Linux version 7.3.0-rc3
  [    0.000000] Machine model: linux,dummy-virt
  [    0.000000] earlycon: pl11 MMIO32:0x0000000009000000
  ...
  ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs ]---

The panic is the expected end state, no root filesystem is handed
over yet.

The boot chain, state per stage, start to payload:

+-----------+-----+--------------+----------------------------------+
| stage     | EL  | state        | work                             |
+-----------+-----+--------------+----------------------------------+
| firmware  | any | MMU maybe on | x0 = dtb, jump in               |
+-----------+-----+--------------+----------------------------------+
| tashaboot | 3-2 |              | SCR_EL3.NS = 1, eret to EL2     |
+-----------+-----+--------------+----------------------------------+
|           | 2   | virt scrub   | HCR/CNTHCTL/CPTR/HSTR, CNTFRQ,  |
|           |     |              | VBAR_EL2, MMU off, tlbi alle2   |
+-----------+-----+--------------+----------------------------------+
|           | 2   |              | load Image over semihosting,    |
|           |     |              | validate header, place per      |
|           |     |              | booting.rst                     |
+-----------+-----+--------------+----------------------------------+
|           | 2   | caches clean | flush dcache, inval icache,     |
|           |     |              | args ride x20/x21, regs last    |
+-----------+-----+--------------+----------------------------------+
| payload   | 2   | fresh start  | x0 = dtb, x1-x3 = 0, DAIF       |
|           |     |              | masked, br to image entry       |
+-----------+-----+--------------+----------------------------------+

Two handoff bugs the kernel caught, both AAPCS clobbers in the final
jump. Cache maintenance was called after the register setup, x0-x18
are caller saved, so tb_flush_dcache_all() wiped the dtb pointer and
the kernel spun in setup_machine_fdt() with an invalid device tree
blob. The flush helpers also clobbered x1 (u-boot's void call
convention left mov x1, x0 in cache.S) which handed the kernel a wild
x0. The arguments ride in x20/x21 across the cache calls now, callee
saved, and the register setup is the last thing before the branch.

What is missing on purpose: no SMP bringup (secondary cores park),
no PSCI, no initrd or root filesystem handoff, single serial
console. Those come next.

Signed-off-by: Bradley Morgan &lt;brads@mainlining.org&gt;
</content>
</entry>
</feed>
