Appendix A: Hardware manuals for Project 3

This project programs three pieces of hardware you have not programmed before: the receive half of the UART, a second interrupt controller, and the GPU. They are documented in four places, and—this is the interesting part—one of them is not a document at all.

Here is what to read for what:

What you are doingWhere to look
Quest 1: making the UART interrupt on a keystrokeBCM2835 §13, and the PL011 TRM (below) for the parts §13 gets wrong or omits
Quest 1: routing that interrupt to your coreBCM2835 §7, plus the errata page
Quest 1: noticing a peripheral IRQ has arrivedthe ARM-local peripherals document (“QA7”), which you already used in Project 2
Quests 3 and 4: asking the GPU for a framebuffer, and flipping itthe Raspberry Pi firmware wiki
Anything involving mrs/msr, wfi, or DAIFProject 2’s Appendix A, which already covers all of it

Project 3 adds almost no new ARM64 assembly—it is the first project you will write almost entirely in C—so there is no new ARM64 appendix this time. Project 2’s is still the one you want, in particular its table of CNT* timer registers and its section on reaching system registers from C.


1. BCM2835 ARM Peripherals

The BCM2835 ARM Peripherals manual is the same document you used in Project 1, and the same caveats apply: it is written for the BCM2835 rather than the Pi 3’s BCM2837, and its peripheral addresses are bus addresses starting 0x7E00'0000 which you translate to 0x3F00'0000 for the CPU’s view.

Two sections matter this time.

§13, “PL011 UART” (p. 175ff) — you know the first half of this section already. What is new is the interrupt machinery near the end of it:

  • UARTIMSC, the interrupt mask set/clear register: one bit per interrupt source, and setting a bit unmasks (enables) it. Until you write this, the UART raises nothing at all.
  • UARTMIS, the masked interrupt status register: read-only, and tells you which interrupts are both asserted and unmasked, i.e. why you were interrupted.
  • UARTICR, the interrupt clear register: write a 1 to acknowledge. Forget this and you get an interrupt storm.
  • UARTIFLS, the interrupt FIFO level select register, which decides how full the receive FIFO must get before it raises an interrupt.

The bit you want in the first three is the receive interrupt, RXI. Note that the same bit position means “receive interrupt” in all three registers, which is the usual convention for this sort of register trio.

§7, “Interrupts” — this is new. It describes the interrupt controller that sits between the SoC’s peripherals (UART, GPIO, system timer, SD card, …) and the ARM cores. You need the pending and enable registers for interrupt bank 2, and which bit in that bank belongs to the UART. The register list is in §7.5, on p. 112.

Read the errata before you read §7. The interrupt chapter is the least reliable part of this manual, and the table of peripheral IRQ numbers in §7.5 is incomplete: several entries, the UART’s among them, are simply missing. You are not misreading it and you have not lost your place.

The community-maintained BCM2835 datasheet errata fills the gaps; the notes on p. 113 are the ones that give the UART’s IRQ number. Check this page whenever the manual and reality disagree—which, in this chapter, is often.

That a widely-used chip’s real documentation lives partly on a wiki maintained by volunteers is not a quirk of the Raspberry Pi. It is ordinary in this line of work, and it is a good reason to write the section and page number you took each value from into a comment beside it.

2. The ARM PL011 Technical Reference Manual

The PL011 is an ARM design that Broadcom licensed and dropped into their chip, so there are two manuals describing the same device—and for the interrupt side, ARM’s is much the better one.

The PrimeCell UART (PL011) Technical Reference Manual gives each register a full bit-field table with reset values, which §13 of the Broadcom manual mostly does not. Two things you will want from it:

  • The reset value of UARTIFLS. The receive FIFO trigger level does not default to “one byte”, and on real hardware that is the difference between a keyboard that works and one that does nothing. (QEMU is more forgiving, which is exactly what makes this worth looking up rather than discovering.)
  • The receive timeout interrupt, RTI. This is the mechanism by which a partially-filled FIFO gets delivered at all—in other words, the mechanism by which a human typing at human speed produces interrupts. It is barely mentioned in the Broadcom manual.

Be specific about which device you are asking about, whether you are searching this manual or asking an AI: the Raspberry Pi has two UARTs, and the other one (the “mini UART”, part of the AUX block, documented in the Broadcom manual’s “Auxiliaries” chapter) has a completely different register layout. Everything here is about the PL011.

3. The ARM local peripherals (“QA7”)

The BCM2836/BCM2837 ARM-local peripherals document — usually called “QA7” after its original filename — is the one you met in Project 2 for the per-core timer. Its registers are based at 0x4000'0000.

You need exactly one new fact from it this project: in the “Core 0 interrupt source” register you already read on every interrupt, there is a bit meaning “a peripheral IRQ is pending”. That bit is how a UART interrupt announces itself to your existing dispatch code, and it is the hinge between the two interrupt controllers:

   PL011 UART  --(IMSC)-->  BCM2835 interrupt controller  --(ENABLE_IRQS_2)-->
        ARM local controller  --(bit in "Core 0 interrupt source")-->  your core

Your handle_interrupt therefore asks two questions rather than one: what kind of interrupt was this? (QA7), and then, if the answer is “a peripheral”, which peripheral? (BCM2835 §7).

4. The GPU mailbox: a wiki page, not a datasheet

For the framebuffer there is no datasheet at all, and this is worth dwelling on rather than working around.

The display hardware belongs to the VideoCore GPU. The GPU runs its own closed firmware, and that firmware—not any documented register—decides where the framebuffer lives. The only way to get one is to send the firmware a message and ask. The message format is defined by the firmware, and the firmware’s authors documented it on their project wiki:

  • Mailbox property interface — the buffer layout, the request/response protocol, and the full list of property tags. This is the page the tag numbers in kernel/drivers/mbox.h come from.
  • Mailboxes — the transport underneath it: the registers, the channel numbers, and the message encoding.

The registers themselves are in the BCM2835 manual — it has a short section on the mailboxes — but it tells you only that they exist. It says nothing about what you may put in them, which is the part you actually need.

Why does this matter beyond getting a framebuffer? Because it is increasingly how hardware works. A modern GPU, network card, NVMe drive or server management controller is a computer in its own right, running firmware you did not write and cannot read, and “programming” it means composing requests in a format someone documented informally and hoping the reply means what you think it means. Memory-mapped registers with a bit-field table in a PDF, which is what Projects 1 and 2 trained you on, are the older and simpler world.

The practical consequence is that your error handling has to be different in kind. There is no bit you can read to find out why the GPU refused; there is a status word that says “no”. When something goes wrong, print the whole request and response buffer and compare it word by word against the wiki page.


A habit worth forming

Every magic number in kernel code should be traceable to a source. The reference code you have been given does this:

// PL011 UART (p. 175ff, §13; note errata)
#define UART_BASE (PERIPHERALS_BASE + 0x201000)

Do the same in the constants you add this project, and include which document—by the end of Quest 3 you will be drawing from four of them, and “p. 112” is ambiguous across four manuals. Future-you, trying to work out whether a value is wrong or merely surprising, will be grateful.