Page 1 of 1

Reference the address of a function in assembly with c

Posted: Mon Jan 19, 2009 8:21 pm
by CPLH
Hello,
After coming from an ASM only world, I've decided to program an OS in c.
Currently I'm trying to get IDTs to work. After looking at the wiki, I have concluded that at least the initial structure of interrupt handlers must be written in assembly. So, I tried connecting my C code that builds up the IDT with my simple interrupt handler in assembly. Unfortunately apparently something is wrong with how I reference the function.
The OS simply locks up... I found that it can lock up *before* I call STI or LIDT, which is really strange. I guess it is caused by the way that I reference my interrupt handler.
The following is the code of the interrupt handler:

Code: Select all

bits 32

global genericExceptionHandler

genericExceptionHandler:
	mov byte [0xb8000], 'H'
	cli
	hlt
	jmp $
As I said, simple. I still haven't seen the "H" appear btw. I have a very similar function up for hardware except it also sends the EOI. The jmp is just an unneeded precaution. ;)
Note btw that all hardware interrupts have been remapped and unmapped. This shouldn't matter though as lidt and sti aren't called yet.
Now for the IDT code:

Code: Select all

extern void genericExceptionHandler();

...

typedef unsigned char uint8;
typedef unsigned short uint16;

struct IDTDescr
{
   uint16 offset_1; /* offset bits 0..15 */
   uint16 selector; /* a code segment selector in GDT or LDT */
   uint8 zero;      /* unused, set to 0 */
   uint8 type_attr; /* type and attributes, see below */
   uint16 offset_2; /* offset bits 16..31 */
}__attribute__((packed));

...

	struct idtPointer idtInfo;
	struct IDTDescr *idtMem = (struct IDTDescr *) 0;

	int numExceptions = 0x20;
	int numHardware = 0x10;
	int i;

	idtInfo.idtLength = 8 * (numExceptions + numHardware) - 1;
	idtInfo.idtStart = 0;
	for(i = 0; i < numExceptions; i++)
	{
		idtMem->offset_1 = (int)&genericExceptionHandler & 0xFFFF;	/* See below and above */
		idtMem->offset_2 = (int)&genericExceptionHandler >> 16;
		idtMem->selector = 8;
		idtMem->zero = 0;
		idtMem->type_attr = 0x8F;
		idtMem++;
	}
..once again, the code for hardware interrupts is very similar.
Did anybody find any problems with my code? I particularly have found the code failing when setting offsets1 and 2. I don't know why. Am I referencing the functions correctly?
I am assembling the handler code and compiling the c code separately and then linking it all together. Is there anything wrong you can see that I have done?

Thank you,
Veniamin

Re: Reference the address of a function in assembly with c

Posted: Mon Jan 19, 2009 9:30 pm
by bewing
The pointer idtMem is never being initialized to point to your IDT entry in your IDT memory structure?
It is only initted to point to address 0, which is already the location of the realmode IDT, which should not be overwritten.
I'm a little confused about why it crashes immediately -- I'm suspecting an unhandled GPF, but I'm not sure -- and I'm not sure why GPF would be firing.

Re: Reference the address of a function in assembly with c

Posted: Mon Jan 19, 2009 9:54 pm
by CPLH
Usually in real mode, you have a IVT. IDT completely replaces IVT... I thought, why not simply replace it on the spot? Uses up less memory.. I've done it in assembly with no problems.
I am unsure as you are. I cannot really check exceptions yet as you can see, so I'm kind of stuck. I keep on thinking I incorrectly look at the address of the handlers. Is that the correct way to do it?

Thank you,
Veniamin

Re: Reference the address of a function in assembly with c

Posted: Mon Jan 19, 2009 9:57 pm
by Love4Boobies
IVT and real mode IDT are the same thing. And you don't care about it if your OS never returns to real mode.

Re: Reference the address of a function in assembly with c

Posted: Mon Jan 19, 2009 10:04 pm
by neon
Usually in real mode, you have a IVT. IDT completely replaces IVT... I thought, why not simply replace it on the spot?
Actually the IDT never replaces the IVT. You can always setup IDTR to point to the real mode IVT even after previously installing a different IDT. (That is, assuming you dont trash the IVT in physical memory.) This may be used in going back to real mode from protected mode, for example.
I have concluded that at least the initial structure of interrupt handlers must be written in assembly.
Why do you say it "must" be written in assembly? It can be written in C...

Also, if you are using bochs have it output a log file and see if there is anything that looks strange in it. If you are not sure, feel free to post it here so we can view it. If an exception fired, it would be in the log.

Re: Reference the address of a function in assembly with c

Posted: Mon Jan 19, 2009 10:49 pm
by bewing
CPLH wrote:I thought, why not simply replace it on the spot? Uses up less memory.. I've done it in assembly with no problems.
Changing the video mode in your OS (at least initially) will almost certainly require you to return to Real Mode for an instant. There may also be a constant that you need for your floppy driver, stored at the beginning of one of the real mode interrupt handlers. You may also need to get some disk info from real mode. Or PCI info. So, yes, it seems sad to waste 1K of ram, but it's best to leave it alone, I think.

It does work to overwrite it, just as long as you make it to pmode successfully -- which you aren't.
I am unsure as you are. I cannot really check exceptions yet as you can see, so I'm kind of stuck.
As neon said -- you will find more bugs more easily more often, if you use a debugger version of bochs.
I keep on thinking I incorrectly look at the address of the handlers. Is that the correct way to do it?
Oh, actually, you are right. genericExceptionHandler is already a function pointer. You do not want to have that extra & there, I'm pretty sure. Try getting rid of it.

Re: Reference the address of a function in assembly with c

Posted: Tue Jan 20, 2009 6:23 am
by CPLH
To clarify, I do not intend on returning to real mode for any purpose, including switching video modes. All needed real mode information is passed read and stored in a different location when I am in real mode. That is why *should* be able to safely overwrite the IVT. However, read below.

neon, based on what was written in the wiki (Interrupt Service Routines), it seemed to me that you cannot make the basic structure of interrupts in gcc. (I am using gcc..) Well, how would you do it then?

bewing, I tried removing the "&" and I didn't see anything different happen.

I am trying to debug using qemu. So far I've found that for some reason when "locking up" basically the CPU seems to try to execute nonexisting code until it runs out of memory to execute (I guess qemu's virtual memory is made up of zeros.)
My best guess is that an exception is called and thrown into an unknown area where there is no code. How this is handled before LIDT is called, I am uncertain.
Does anybody know how to check which exception is fired through GDB connected to QEMU? I'm still trying to figure it out..

Based on my explanation, it would seem that the IVT is handling the exceptions before LIDT is called. To check that, I will change the address to some other location.

Re: Reference the address of a function in assembly with c

Posted: Tue Jan 20, 2009 6:51 am
by CPLH
WOW.. I just figured out was wrong. Looks like I've been poking around in the dark, looking for problems in the wrong place:

Ready? :)

*My boot loader didn't load all of the sectors of the kernel* #-o

...Note that it seems that the program became larger than 512 bytes a bit faster when using C... :roll:

Re: Reference the address of a function in assembly with c

Posted: Fri Jan 23, 2009 12:20 am
by iammisc
CPLH wrote:...Note that it seems that the program became larger than 512 bytes a bit faster when using C... :roll:
Try using -Os if you're using gcc.