Computer Laboratory

Raspberry Pi

Troubleshooting

There is little more satisfying than when an Operating Sytsem you've written works perfectly, however this is, unfortunately, rarely the case. I lost count long ago how many Operating Systems I've written that didn't work in making this couse. This page contains advice for what to do when things just aren't working. It is broken down into compile errors that happen before you can even make the Operating System, load errors that prevent your Operating System doing anything, and runtime errors, where your Operating System doens't do the correct thing. I've also added specific help on each of the tutorial Operating Systems, such as things that can commonly go wrong. If you have a problem that isn't explained here, and think others my be able to benefit from your experience, send an email to me at awc32@cam.ac.uk, and I will add it here.

1 Compiler Errors

Compiler errors are errors that occur when the make command runs on your Operating System. I've also included some common warnings too.

1.1 Error: bad instruction

source/file.s:8: Error: bad instruction `sdd r0,r1'

This error occurs when you use a command that doesn't exist. First of all, check that you haven't mistyped the command. If you're using condition codes as well as other options such as an str command with a b suffix to only store a byte, and a eq suffix to only store if the last condition was equal, the correct order is in fact streqb not strbeq.

1.2 Error: immediate expression requires a # prefix

source/file.s:32: Error: immediate expression requires a # prefix -- `add r0,1'

This means that you're trying to use a constant number, such as adding the number one, but forgot to put a # (e.g. add r3,4 should be add r3,#4. You must do so wherever you use a constant on a command that normally uses registers. This is true even for calculated constants such as #3*4.

1.3 Error: ARM register expected

source/file.s:24: Error: ARM register expected -- `add 0,r1'

This means that you typed something that was not a register, when a register was expected. Double check your spelling, especially if you're using .req. If you are, make sure you haven't used .unreq between the .req and this command.

1.4 Error: unknown pseudo-op

source/file.s: Error: unknown pseudo-op: `.suction'

This error occurs when you use a pseudo operation that doesn't exit. Check your spelling.

1.5 Error: invalid constant (number) after fixup

source/file.s:24: Error: invalid constant (c21) after fixup

This error occurs when you use a constant which does not meet the requirements of the function. The most common example of this is the mov instruction, which only allows numbers which can be represented as an 8 bit number, shifted left by an even number. For example c2116 = 1100001000012 and so cannot be represented in a mov, but c2016 = 1100001000002 = 110000102 << 4, and so is valid in a mov. Much the same rules apply to most constants in functions. Remember, to load in any constant, use ldr r0,=value.

1.6 warning : end of file not at end of a line; newline inserted

source/file.s: warning : end of file not at end of a line; newline inserted

This means the last line in your file is not empty. You can ignore this, but to fix it just add a new line at the end.

1.7 undefined reference

.text(+0x18): undefined reference to `label'

This means you've used a label which the linker can't find. This is probably due to a misspelling. Remember that labels are case sensitive and that labels in different files require .globl commands before they're accessible in other files.

1.8 `section' referenced in section `section' of build/file.o: defined in discarded section `section' of build/file.o

`.trxt' referenced in section `.init' of build/main.o: defined in discarded section `.trxt' of build/main.o

This means that you've used a .section command, but you've specified a section other than .init, .text or .data. Only these sections are copied into the kernel.img file, any others are discarded, hence the error is saying that some of your code was discarded. Check your spelling on .section commands.

2 Load Errors

Load errors are errors that occur that prevent your Operating System from giving any output. This can be the hardest to diagnose and fix. Unfortunately, by their nature, they give off no indication of what is wrong.

The first thing you should check is that the tutorial answer does work. This confirms that you're installing things correctly, that your Raspberry Pi is not physically damaged and that your SD card works. If the answer doesn't work, make sure Linux still does. If it doesn't you may have a problem with your SD card or Raspberry Pi physically. Reimage the SD card or get a new one. If Linux does work but the tutorial does not, you may not be installing the Operating System correctly. Double check you're replacing kernel.img in the FAT partition of the SD card. Try altering the config.txt's settings, especially putting kernel_old=1.

If the answer does work but your attempt does not, then we know it is something in your code. On the later tutorials, try altering the start of your code to turn on the OK LED, just so you know if it boots at all. If not, double check that you have some code in the .init section which branches into your .text section. Try enabling the OK LED from the .init section.

Ultimately what we need is some output. If you can get the LED to turn on from your early code, then this is just a runtime error. If placing that code in the .init section still doesn't enable output, it may be worth going back to the template and copying in your code bit by bit until it stops working. Sometimes you never do find the error; In the past I've ended up copying the entire code back into the template and suddenly it worked.

3 Runtime Errors

Behind load errors, runtime errors are the hardest to diagnose and fix. These occur when your Operating System just doesn't do what you want.

The most important thing is to get information out of the system. The OK LED is very useful for this. If the Operating System seems to stop, or get stuck, try turning on the LED just before and just after various commands. If it turns on when just before an instruction, but won't on the instruction afterwards, then we know this is the problem. Please remember that turning on the LED will generally alter r0 to r3, so use push {r0,r1,r2,r3} and pop {r0,r1,r2,r3} to preserve these registers. If you're in looping code, try flashing the LED in the loop to see how many loops actually happen.

If you're in the later tutorials make sure to use the screen for information. Write out text about the current status, values, etc, in order to learn what is going on. Once you've got some idea, have a look at the following common problems to see if you can spot what has happened.

Remember, think outside the box. Perhaps a function you wrote ages ago had a bug you never noticed.

3.1 Alignment

One of the most subtle runtime errors is the ARM alignment constraint. Any str or ldr instruction will not function correctly unless the computed address is a multiple of the size of the data being read. For example, if you're using ldr r0,[r1,#2], then the value of r1,#2 must be a mutliple of 4. If not unpredictable results occur. You should always be able to guarantee this is this case. If you're referring to a label, make sure you have a .align 2 command BEFORE the label. This will ensure that the label's address is a multiple of 22 = 4. You can use .align 3 to align to a multiple of 23 = 8, etc.

3.2 Hanging

A processor 'hangs' (stops) if it encounters a bad instruciton or a bad address. If your code gets stuck on a branch, load or store command, this is likely to be the problem. You can use a condition around turning on the OK LED to check this.

3.3 Infinite Loops

Similarly to haninging, a processor can easily get stuck in loops. If the processor reaches one of your loops, but never leaves, this could well be the problem. Double check the conditions for leaving the loop will be satisfied.

4 General Advice

To help you, every time you compile a kernel, two extra files are compiled. kernel.list contains a direct listing of all the assembly code, and kernel.map contains a map of all your labels. You can use these files to mentally simulate the processor and check it will do the correct thing. The processor starts at address 0 with all registers in an undefined state. Try mentally checking that the processor will do what you want. For things like alignment issues, you can double check everything is as it should be with kernel.map.

5 Tutorial Specific Advice

No one has submitted any tutorial specific problems yet.