Triple fault in home grown kernel - c

I am trying to write a kernel, mostly for entertainment purposes, and I am running into a problem were I believe it is triple faulting. Everything worked before I attempted to enable paging. The code that is breaking is this:
void switch_page_directory(page_directory_t *dir){
current_directory = dir;
asm volatile("mov %0, %%cr3":: "r"(&dir->tablesPhysical));
u32int cr0;
asm volatile("mov %%cr0, %0": "=r"(cr0));
cr0 |= 0x80000000;//enable paging
asm volatile("mov %0, %%cr0":: "r"(cr0)); //this line breaks
}//switch page directory
I have been following a variety of tutorials / documents for this but the one I am using to paging is thus http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html . I am not sure what other code will be useful in figuring this out but if there is more I should provide I will be more than happy to do so.
Edit=====
I believe the CS,DS and SS are selecting correct entries here's the code used to set them
global gdt_flush
extern gp
gdt_flush:
lgdt [gp] ; Load the GDT with our 'gp' which is a special pointer
mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:flush2 ; 0x08 is the offset to our code segment: Far jump!
flush2:
ret ; Returns back to the C code!
and here's the gdt struct itself
struct gdt_entry{
unsigned short limit_low;
unsigned short base_low;
unsigned char base_middle;
unsigned char access;
unsigned char granularity;
unsigned char base_high;
} __attribute__((packed));
struct gdt_ptr{
unsigned short limit;
unsigned int base;
} __attribute__((packed));
struct gdt_entry gdt[5];
struct gdt_ptr gp;
The IDT is very similar to this.

GDT: you don't say what the contents of the GDT entries are, but the stuff you've shown looks fairly similar to the earlier part of the tutorial you linked to and if you've set up the entries in the same way, then all should be well (i.e. flat segment mapping with a ring 0 code segment for CS, ring 0 data segment for everything else, both with a base of 0 and a limit of 4GB).
IDT: probably doesn't matter anyway if interrupts are disabled and you're not (yet) expecting to cause page faults.
Page tables: incorrect page tables do seem like the most likely suspect. Make sure that your identity mapping covers all of the code, data and stack memory that you're using (at least).
The source code linked to at the bottom of http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html definitely builds something that does work correctly with both QEMU and Bochs, so hopefully you can compare what you're doing with what that's doing, and work out what is wrong.
QEMU is good in general, but I would recommend Bochs for developing really low-level stuff - it includes (or can be configured to include) a very handy internal debugger. e.g. set reset_on_triple_fault=0 on the cpu: line of the config file, set a breakpoint in the switch_page_directory() code, run to the breakpoint, then single step instructions and see what happens...

You can link qemu to a gdb debugger session via the remote debugger tools in gdb. This can be done by issuing the following commands:
qemu -s [optional arguments]
Then inside your gdb session, open your kernel executable, and after setting a break-point in your switch_page_directory() function, type in the following command at the gdb prompt:
target remote localhost:1234
You can then single-step through your kernel at the breakpoint, and see where your triple-fault is taking place.
Another step to consider is to actually install some default exception handlers in your IDT ... the reason you are triple-faulting is because an exception is being thrown by the CPU, but there is no proper exception handler available to handle it. Thus with some default handlers installed, especially the double-fault handler, you can effectively stop the kernel without going into a triple-fault that automatically resets the PC.
Finally, make sure you have re-programmed the PIC before going into protected mode ... otherwise the default hardware interrupts it's programmed to trigger from the BIOS in real-mode will now trigger the exception interrupts in protected mode.

I was also facing the same problem with paging tutorial.But after some searching i found the solution it was happening because as soon as paging is enabled, all address become virtual and to solve it we must map the virtual addresses to the same physical addresses so they refer to the same thing and this is called identity mapping.
you can follow this link for further help in implementing Identity Maping.
and one more thing you have memset the newly allocated space to zero because it may contain garbage values and memset was not done in tutorial it will work on bochs because it set the space to zero for you but other emulator(qemu) and real hardware are so kind.

Related

Can i use interrupts in inline assembly

I want to use interrupts in inline asm but it is not letting me I think my app is this
__asm__("movb %ah,9;"
"movb %al,0x41;"
"movb %bh,0x0;"
"movw %cx,0x1; "
"movb %bl,0x0F ;"
"int $10; ");
I am getting nothing after running this just a blank space what should I do?
Can i use interrupts in inline assembly?
Yes, as long as the interrupt exists and you inform the compiler of how to deal with it correctly (e.g. "clobber list" to tell the compiler which registers changed, etc). See the GCC manual and https://stackoverflow.com/tags/inline-assembly/info
And as long as you use the correct number, likely you wanted int $0x10 instead of int $10. And you'll want to mov immediates into registers, not mov registers to absolute memory addresses.
If that doesn't work, I'd be tempted to suspect that you're trying to use BIOS "video services" to print a character on the screen; but you're not in real mode (and doing it in 32-bit code or 64-bit code); and the BIOS might not exist at all (e.g. a UEFI system); and an OS may have taken over control of the hardware (and broken all the assumptions that BIOS expects, like disabling obsolete "legacy junk emuation" in certain devices, reconfiguring memory, and timers and interrupt controllers; so that even if BIOS exists and you're in real mode you still can't use it safely).

Load/store register results in different value than memory viewer

I'm working on a program that runs under Xilinx's QEMU builds. This question is tagged zynq, but I'm actually targeting a Zynq MP in QEMU, specifically the Cortex-R5.
My background is in microcontrollers and Cortex-M, so this is a big jump and there are a lot of features (MPU, AXI, extra caches) that I'm not accustomed to. I'm writing a driver that is accessing peripheral registers in one of the hard peripherals (in the low power domain). I've written a function, reginsert to simplify accessing bits in these registers.
void reginsert(uint32_t base, uint32_t offset,
uint32_t mask, uint32_t data)
{
uint32_t volatile * reg = (uint32_t volatile *)(base + offset);
uint32_t regdata;
/* This section actually happens in a critical section for atomicity,
* but I've trimmed that out for brevity */
regdata = *reg;
*reg = (regdata & ~mask) | data;
/* End of critical section */
}
Not a very exciting function at all. To me, it's also straightforward.
I call the function like so:
/* Magic number provided by Xilinx, I don't actually plan to keep it as such a
* magical number, but for now while trying things to debug. */
reginsert(XPAR_PSU_UART_0_BASEADDR, XUARTPS_CR_OFFSET, 0x3C, 0);
Additional information:
#define XPART_PSU_UART_0_BASEADDR 0xFF000000
#define XUARTPS_CR_OFFSET 0x00000000
In stepping through the code, I find that this function correctly calculates the address for the register as 0xFF000000, and I can see this within the Xilinx SDK debugger (gdb based) when viewing the value for reg. I can also see, stepping through the assembly that the register r3 is loaded with the proper address.
When execution reaches:
regdata = *reg;
The disassembly has:
ldr r3, [r3]
And I get 0x00000000 in r3. If I use the memory view, I can see that 0xFF000000 has a value of 0x00000114. If I look in the variable view, I can see that *reg has the same value (0x00000114). If I step to the line where the local copy is masked and then written back, I end up at the instruction:
str r2, [r3] ; r3 has been reloaded with the register address,
; and r2 contains the read-modify-write data.
Stepping past this, I see that the value of 0x00000000 (though not the correct value) should have been written, but the value does not actually change (via memory or variable view). In either of these views, I can manually change the value and it writes correctly.
I don't know how thoroughly the bus architecture of the Zynq MP is being emulated in this build of QEMU, but the silicon has separate memory ports for debug access and processor access, and does not access memory through the CPU, so there is a possibility for things to be mapped differently. However, the Xilinx demo code does appropriately perform the same actions.
So, a summary of what I've tried:
Verify disassembly should load/store from register location.
Step through instructions to verify CPU registers have the correct value to access peripheral register.
Accessed memory and variable directly via debugger.
Verify with Xilinx code that QEMU emulates peripheral.
Checked MPU settings (the region is set to non-shared and no restrictions on access)
I don't know what else I should try, and I'm basically stumped. It appears that QEMU, at least through the gdb interface, properly simulates the peripheral register, so I would think it would be fairly straightforward for the CPU to read/write. I appreciate any help, pointers, tips, etc. There's a lot going on that is new to me, including using QEMU as a development platform.

Can't seem to add %ES to the clobberlist (inline assembly, GCC)

I'm going through Micheal Abrash's Graphics Programming Black Book (which by the way, I am really enjoying, I strongly recommend it), so the example code I'm working with is quite old. Nonetheless, I don't see what the problem is:
__asm__(
//Some setup code here
"movl %%esi, %%edi;"
"movw %%ds, %%es;"
//A whole bunch more assembly code in between
"divloop:"
"lodsw;"
"divl %%ebx;"
"stosw;"
"loop divloop;"
//And a little more code here
: "=r" (ret)
: "0" (ret) /*Have to do this for some reason*/, "b" (div), "c" (l), "S" (p)
: "%edi", "%es"
);
The l variable is an unsigned int, the p variable is a char*. l
is a byte count for the length of the string pointed at by p. div
is the divisor and is an unsigned int. ret is the return value (an
unsigned int) of the function and is set inside to assembly block to
be the remainder of the division.
The error message I am getting is "error: unknown register name '%es' in 'asm'" (This is the only error message). My best guess is that it goes by another name in GAS syntax. I know I'm working with old code, but as far as I know, on my fairly new intel i3 there is still an ES register that gets used by stos*
Secondly, there's a question that's been bugging me. I've basically had no choice but to just assume that DS was already set to the right memory location for use with lods*. Since I am reading from, modifying, and writing to the same memory location (using stos* and lods*) I'm setting ES equal to DS. However, it's really scaring me that my DS could be anything and I don't know what else to set it to. What's more is that ESI and EDI are already 32 bit registers and should be enough on their own to access memory.
In my experience, two strange problems at once are usually related and caused by a more fundamental problem (and usually a PEBKAC). However, I'm stumped at this point. Does anyone know what's going on?
Thanks a bunch
P.S. I'm trying to recreate the code from Chapter 9 (Hints My Readers Gave Me, Listing 9.5, page 182) that divides a large number stored in contiguous memory by EBX. There is no other reason for doing this than my own personal growth and amusement.
If you're running in a flat 32-bit protected mode environment (like a Linux or Windows user-mode process), there's no need to set es.
The segment registers are set for you by the OS, and es and ds both allow you to access a flat 32-bit address space.
GCC won't generate code to save/restore segment registers, so it's not surprising that it won't allow you to add them to the clobber list.

call stack unwinding in ARM cortex m3

I would like to create a debugging tool which will help me debug better my application.
I'm working bare-bones (without an OS). using IAR embedded workbench on Atmel's SAM3.
I have a Watchdog timer, which calls a specific IRQ in case of timeout (This will be replaced with a software reset on release).
In the IRQ handler, I want to print out (UART) the stack trace, of where exactly the Watchdog timeout occurred.
I looked in the web, and I didn't find any implementation of that functionality.
Anyone has an idea on how to approach this kind of thing ?
EDIT: OK, I managed to grab the return address from the stack, so I know exactly where the WDT timeout occurred.
Unwinding the whole stack is not simple as it first appears, because each function pushes different amount of local variables into the stack.
The code I end up with is this (for others, who may find it usefull)
void WDT_IrqHandler( void )
{
uint32_t * WDT_Address;
Wdt *pWdt = WDT ;
volatile uint32_t dummy ;
WDT_Address = (uint32_t *) __get_MSP() + 16 ;
LogFatal ("Watchdog Timer timeout,The Return Address is %#X", *WDT_Address);
/* Clear status bit to acknowledge interrupt */
dummy = pWdt->WDT_SR ;
}
ARM defines a pair of sections, .ARM.exidx and .ARM.extbl, that contain enough information to unwind the stack without debug symbols. These sections exist for exception handling but you can use them to perform a backtrace as well. Add -funwind-tables to force GCC to include these sections.
To do this with ARM, you will need to tell your compiler to generate stack frames. For instance with gcc, check the option -mapcs-frame. It may not be the one you need, but this will be a start.
If you do not have this, it will be nearly impossible to "unroll" the stack, because you will need for each function the exact stack usage depending on parameters and local variables.
If you are looking for some exemple code, you can check dump_stack() in Linux kernel sources, and find back the related piece of code executed for ARM.
It should be pretty straight forward to follow execution. Not programmatically in your isr...
We know from the ARM ARM that on a Cortex-M3 it pushes xPSR,
ReturnAddress, LR (R14), R12, R3, R2, R1, and R0 on the stack. mangles the lr so it can detect a return from interrupt then calls the entry point listed in the vector table. if you implement your isr in asm to control the stack, you can have a simple loop that disables the interrupt source (turns off the wdt, whatever, this is going to take some time) then goes into a loop to dump a portion of the stack.
From that dump you will see the lr/return address, the function/instruction that was interrupted, from a disassembly of your program you can then see what the compiler has placed on the stack for each function, subtract that off at each stage and go as far back as you like or as far back as you have printed the stack contents.
You could also make a copy of the stack in ram and dissect it later rather than doing such things in an isr (the copy still takes too much time but is less intrusive than waiting on the uart).
If all you are after is the address of the instruction that was interrupted, that is the most trivial task, just read that from the stack, it will be at a known place, and print it out.
Did I hear my name? :)
You will probably need a tiny bit of inline assembly. Just figure out the format of the stack frames, and which register holds the ordinary1 stack pointer, and transfer the relevant values into C variables from which you can format strings for output to the UART.
It shouldn't be too tricky, but of course (being rather low-level) you need to pay attention to the details.
1As in "non-exception"; not sure if the ARM has different stacks for ordinary code and exceptions, actually.
Your watchdog timer can fire at any point, even when the stack does not contain enough information to unwind (e.g. stack space has been allocated for register spill, but the registers not copied yet).
For properly optimized code, you need debug info, period. All you can do from a watchdog timer is a register and stack dump in a format that is machine readable enough to allow conversion into a core dump for gdb.

How to determine values saved on the stack?

I'm doing some experimenting and would like to be able to see what is saved on the stack during a system call (the saved state of the user land process). According to http://lxr.linux.no/#linux+v2.6.30.1/arch/x86/kernel/entry_32.S it shows that the various values of registers are saved at those particular offsets to the stack pointer. Here is the code I have been trying to use to examine what is saved on the stack (this is in a custom system call I have created):
asm("movl 0x1C(%esp), %ecx");
asm("movl %%ecx, %0" : "=r" (value));
where value is an unsigned long.
As of right now, this value is not what is expected (it is showing a 0 is saved for the user value of ds).
Am I correctly accessing the offset of the stack pointer?
Another possibility might be could I use a debugger such as GDB to examine the stack contents while in the kernel? I don't have much extensive use with debugging and am not sure of how to debug code inside the kernel. Any help is much appreciated.
No need for inline assembly. The saved state that entry_32.S pushes onto the stack for a syscall is laid out as a struct pt_regs, and you can get a pointer to it like this (you'll need to include <asm/ptrace.h> and/or <asm/processor.h> either directly or indirectly):
struct pt_regs *regs = task_pt_regs(current);
Inline assembly is trickier than it seems. Trying to shortly cover the concerns for GCC:
If it modifies processor registers, it's necessary to put these registers on the clobber list. It's important to note that the clobber list must contain ALL registers that you changed directly (read explicitly) or indirectly (read implicitly);
To reinforce (1), conditional and mathematical operations also change registers, more known as status flags (zero, carry, overflow, etc), so you have to inform it by adding "cc" to the clobber list;
Add "memory" if it modifies different (read random) memory positions;
Add the volatile keyword if it modifies memory that isn't mentioned on the input/output arguments;
Then, your code becomes:
asm("movl 0x1C(%%esp), %0;"
: "=r" (value)
: /* no inputs :) */
/* no modified registers */
);
The output argument isn't required to be on the clobber list because GCC already knows it will be changed.
Alternatively, since all you want is the value of ESP register, you can avoid all the pain doing this:
register int esp asm("esp");
esp += 0x1C;
It might not solve your problem, but it's the way to go. For reference, check this, this and this.
Keep in mind that x86_64 code will often pass values in registers (since it has so many) so nothing will be on the stack. Check the gcc intermediate output (-S IIRC) and look for push in the assembly.
I'm not familiar with debugging kernel code, but gdb is definitely nicer to examine the stack interactively.

Resources