Skip to content

Commit

Permalink
up
Browse files Browse the repository at this point in the history
  • Loading branch information
fxlin committed Feb 8, 2021
1 parent e511f4d commit 78610a1
Show file tree
Hide file tree
Showing 14 changed files with 666 additions and 115 deletions.
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# A tiny, modern kernel for Raspberry Pi 3

https://fxlin.github.io/p1-kernel/
**Get the code**: https://github.com/fxlin/p1-kernel

A tiny kernel *incrementally built* for OS education.

Expand Down
14 changes: 11 additions & 3 deletions docs/cheatsheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@
* x9-x28: caller-saved registers. In general okay to use in your code
* x29 (FP): frame pointer, pointing to the base of the current stack frame
* x30 (LR): link register

* SP Stack pointer

* PC Program counter


Our [GDB customization](gdb.md) color-codes the registers.

White highlight (x0-x7): parameter/results; red background (x19-x29): callee saved.

(Green reg values: the values have changed since the last instruction)

![](images/gdb-dash-aarch64-reg.png)





## Special purpose registers

Expand Down
106 changes: 76 additions & 30 deletions docs/gdb.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
# Using GDB to debug kernel

**Note (WSL users)**: It seems GDB server does not play well with WSL… see below.
**NOTE**:

# Installation
1. Read the whole document before you attempt GDB.
2. *WSL users who want to develop on local machines instead of the server*: gdbserver may not play well with WSL. See "troubleshooting" below. You are fine if you develop on the server.

# GDB Installation

We've done this on the server already. Do this if developing on local machines (Linux or WSL).

Linux or WSL:
```
sudo apt install gdb-multiarch gcc-aarch64-linux-gnu build-essential
```
Note: the gdb for aarch64 is not called aarch64-XXXX-gdb.
Note: the gdb for aarch64 is NOT called aarch64-XXXX-gdb.

## Basic Usage
# The workflow

From one terminal
## Launch QEMU + the kernel and wait for the debugger

```
qemu-system-aarch64 -M raspi3 -kernel ./kernel8.img -serial null -serial stdio -s -S
# will wait for gdb to connect at local tcp 1234
qemu-system-aarch64 -M raspi3 -kernel ./kernel8.img -serial null -serial stdio -s -S
# OR, will wait for gdb to connect at local tcp 5678
qemu-system-aarch64 -M raspi3 -kernel ./kernel8.img -serial null -serial stdio -gdb tcp::5678 -S
```

From another terminal (the elf is needed if we need debugging info)
Explanation: -S not starting the guest until you tell it to from gdb. -s listening for an incoming connection from gdb on TCP port 1234

**WARNING** If multiple students run the first command on the server machine, they all attempt to listen on tcp port 1234. Only one will succeed. If you see such a failure, use the second form to specify a different TCP port number.

## Launch GDB

From another terminal

```
gdb-multiarch build/kernel8.elf
Expand All @@ -45,14 +59,14 @@ Single step

show reg information at each step. This example shows
```
display/10i $sp
(gdb) display/10i $sp
```

![gdb-si-display](images/gdb-si-display.gif)

## Dump memory

dump memory. can specify a symbol or a raw addr
You can specify a symbol or a raw addr

... as instructions

Expand Down Expand Up @@ -94,53 +108,89 @@ b *0xffff0000

## Function/source lookup

type of a given symbol
Look up type of a given symbol
```
ptype mem_map
```

find out function name at a given addr
Find out function name at a given addr
```
info line *0x10000000
```

list source at a given addr
List source at a given addr
```
list *0x10000000
list *fn
```

# Enhancement
# The GDB "dashboard" enhancement

I recommend GEF (https://github.com/hugsy/gef) and GDB-dashboard (https://github.com/cyrus-and/gdb-dashboard). Based on my quick test:
The basic GDB UI is too primitive to beginners. We provide you an enhancement called GDB-dashboard. The upstream source is [here](https://github.com/fxlin/gdb-dashboard-aarch64). I adapted it for aarch64. Screenshot:

* Both enhanced GDB significantly.

* GEF understands aarch64 semantics (e.g. CPU flags) very well. It can even tell why a branch was taken/not taken. However, GEF does not parse aarch64 callstack properly (at least I cannot get it work).
![Screenshot](https://raw.githubusercontent.com/fxlin/gdb-dashboard-aarch64/master/gdb-dash-aarch64.png)

* GDB-dashboard nicely parses the callstack. It, however, does not display aarch64 registers properly.

GEF screenshot (note the CPU flags it recognized)

![image-20210127220750060](lesson03/images/gef.png)
## Installation

I slightly adapted GDB-dashboard for aarch64: https://github.com/fxlin/gdb-dashboard-aarch64
Grab from my repository:

```
wget -P ~ https://raw.githubusercontent.com/fxlin/gdb-dashboard-aarch64/master/.gdbinit
```

Results:
There's only one file: `.gdbinit`. It's the initial script that GDB will load upon start. The above line download it to your home directory.

![Screenshot](https://raw.githubusercontent.com/fxlin/gdb-dashboard-aarch64/master/gdb-dash-aarch64.png)
## Usage

*All GDB commands still apply*, e.g. "si" is single step per instruction; "b" is to set a breakpoint; "c" for continuing execution. See below for more.

The major features here are multiple views: for registers, stack, assembly, and source.

### Customize

Open ~/.gdbinit. Go to near line 2500 where you can see initialization commands for GDB, e.g.

```
file build/kernel8.elf
target remote :1234
```

GDB execute these commands whenever it starts, so you do not have to type them every time.

The best documentation of gdb-dashboard seems from typing`help dashboard` in the GDB console. Examples:
In the above example, GDB loads the ELF file kernel8.elf (only for parsing symbols and debugging info); it connects to a remote target at local port 1234.

Lines below customize gdb-dashboard behaviors, e.g.

```
dashboard source -style height 15
dashboard assembly -style height 8
```

These lines set the height of the "source" panel and the "assembly" panel.

The best documentation of gdb-dashboard seems from typing `help dashboard` in the GDB console. e.g. In GDB, type:

```
>>> help dashboard expressions
```

All GDB commands still apply.
# Other enhancement (FYI)

GEF (https://github.com/hugsy/gef) is also viable. Both GEF and GDB-dashboard:

* Both enhanced GDB significantly.

* GEF understands aarch64 semantics (e.g. CPU flags) very well. It can even tell why a branch was taken/not taken. However, GEF does not parse aarch64 callstack properly (at least I cannot get it work).

* GDB-dashboard nicely parses the callstack. It, however, does not display aarch64 registers properly.

GEF screenshot (note the CPU flags it recognized)

![image-20210127220750060](lesson03/images/gef.png)



## Troubleshooting

Expand All @@ -162,7 +212,3 @@ Good article

https://interrupt.memfault.com/blog/advanced-gdb#source-files


```
```
64 changes: 44 additions & 20 deletions docs/lesson00/rpi-os.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,47 @@ baremetal; kernel; kernel binary; kernel image

This is where you develop kernel code.

We have configured departmental server(s) for you to use. See [here](../ssh-proxy.md). You can develop on your local machine and test on the servers.
### If you build kernel for Rpi3 ...

Alternatively, you may do everything on your local machine, here are suggestions:
Note:

- Linux. Recommended: Ubuntu 20.04 LTS.
- Windows: WSL or WSL2. See [instructions](https://docs.microsoft.com/en-us/windows/wsl/install-win10#:~:text=To%20check%20your%20version%20and,command%20in%20Windows%20Command%20Prompt). My Windows machine runs WSL2 with Ubuntu18.04.
- OS X: (likely HomeBrew is needed. Not tested)
* Recommended configurations are <u>underscored</u>.

* How to connect to CS server(s): see [here](../ssh-proxy.md).

* VSCode: optional. It's available on Win/OSX/Linux. It can be used for any configuration below.

| Your local machine runs: | Develop remotely on CS servers | Develop locally |
| ------------------------ | ------------------------------------------------------------ | --------------------------------- |
| Windows | WSL for SSH shell; then download (scp) kernel binary to local | <u>WSL for toolchain</u> |
| Linux | SSH shell; then download (scp) kernel binary to local | <u>Native toolchain + console</u> |
| Mac | <u>Terminal for SSH shell</u> | HomeBrew (untested) |

### If you build kernel for QEMU ...

Note:

* Recommended configurations are <u>underscored</u>.

* How to connect to CS server(s): see [here](../ssh-proxy.md).

* VSCode: optional. It's available on Win/OSX/Linux. It can be used for any configuration below.

| Your local machine runs: | If develop remotely on CS servers | If develop on your local machine |
| ------------------------ | --------------------------------- | --------------------------------------------- |
| Windows | <u>WSL for SSH shell</u> | WSL for toolchain. gdbserver could be tricky. |
| Linux | <u>SSH shell</u> | <u>Native toolchain + console</u> |
| Mac | <u>Terminal for SSH shell</u> | HomeBrew (untested) |

### Toolchain

These are compiler, linker, etc. for us to generate the kernel code. Use the one provided by Ubuntu
These are compiler, linker, etc. for us to generate the kernel code. Use the one provided by Ubuntu.

```
# this is necessary only when you develop kernel code on your local machine
# the server already has the toolchain installed
$ sudo apt install gcc-aarch64-linux-gnu
$ sudo apt install gdb-multiarch
$ aarch64-linux-gnu-gcc --version
aarch64-linux-gnu-gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Expand Down Expand Up @@ -137,23 +164,19 @@ Viola! You just built your first baremetal program for Rpi3!

#### Compile QEMU from source

Need QEMU >v2.12. Newer version is likely fine. The following shows the default QEMU coming with Ubuntu 18.04 is too old. For instance:

```
$ qemu-system-aarch64 --version
QEMU emulator version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.26)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers
```
*This is required no matter you develop on local machines or on the server.*

Now, build QEMU from source. Clean any pre-installed qemu and install necessary tools:
Clean any pre-installed qemu and install necessary tools:

```
# this is necessary only when you develop kernel code on your own machine (not recommended)
# the server already has these software uninstalled/installed
sudo apt remove qemu-system-arm
sudo apt install gdb-multiarch build-essential pkg-config
sudo apt install libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev
```

Grab the source. Our QEMU is based on upstream v4.2 **with some aarch64 debugging support.**
Grab the QEMU source. Our QEMU is based on upstream v4.2 **with custom aarch64 debugging support.**

```
git clone https://github.com/fxlin/qemu-cs4414.git
Expand All @@ -170,13 +193,14 @@ If you encounter compilation errors (e.g. unmet dependencies), make sure you run
Now try QEMU & check its version. The supported machines should include Rpi3

```
$ qemu-system-aarch64 --version
QEMU emulator version 4.2.0 (v4.2.0-11797-g2890edc853-dirty)
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
$ qemu-system-aarch64 --version
QEMU emulator version 5.0.50 (v5.0.0-1247-gaf6f75d03f-dirty)
Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers
patched for cs4414/6456 aarch64 kernel hacking
$ qemu-system-aarch64 -M help|grep rasp
raspi2 Raspberry Pi 2
raspi3 Raspberry Pi 3
raspi2 Raspberry Pi 2B
raspi3 Raspberry Pi 3B
```

#### Test the compilation
Expand Down
10 changes: 7 additions & 3 deletions docs/lesson01/rpi-os.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

![](figures/helloworld.png)

![](figures/overview.png)

We will build: a minimal, baremetal program that can print "Hello world" via Rpi3's UART.

Students will experience:
Expand All @@ -16,6 +18,8 @@ Students will experience:

4. Basic knowledge on Rpi3 and its UART hardware

**Source code location: p1-kernel/src/lesson01**

## Roadmap

Create a Makefile project. Add minimum code to boot the platform. Initialize the UART hardware. Send characters to the UART registers.
Expand All @@ -28,9 +32,9 @@ Create a Makefile project. Add minimum code to boot the platform. Initialize the

## Project structure

1. **Makefile** We will use the [make](http://www.math.tau.ac.il/~danha/courses/software1/make-intro.html) utility to build the kernel. `make`'s behavior is configured by a Makefile, which contains instructions on how to compile and link the source code.
1. **src** This folder contains all of the source code.
1. **include** All of the header files are placed here.
1. `Makefile`: We will use the GNU Makefile to build the kernel.
1. `src`: This folder contains all of the source code.
1. `include`: All of the header files are placed here.

Note: Of all the subsequent experiments in p1, the source code has the same structure.

Expand Down
2 changes: 2 additions & 0 deletions docs/lesson02/rpi-os.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

## Objectives

**Source code location: p1-kernel/src/lesson02**

We are going to build:

A baremetal program that can switch among CPU exception levels and print out the current level.
Expand Down
Loading

0 comments on commit 78610a1

Please sign in to comment.