'sti' cause crash.. need some help

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

Assuming everything is OK, it could be that the compiler used renders wrong addresses and writes to any location other than the intended one.

First, I wasn't able to read the contents of the floppy once I removed it and put it in again. Maybe there's something wrong with the floppy MBR.

Other thing that I did was to remove the code from kernel that executes LGDT and kept interrupts enabled. I loaded it alternatively without GRUB by jumping directly into 8:101030

It gave me a message like:

Code: Select all

Whoops! System Halted!

Division By Zero

At least it responded to interrupts and printed a message. If i had loaded the GDT it had directly restarted without messages.




I also have attached an image of the original sample disk. The only thing I did was to copy your original KERNEL.EXE and add a boot entry that says "MSVC Kernel". Everything else from that image is unchanged.

But it will give you a message like:

Code: Select all

Whoops! System Halted!

General Protection Fault


That's why I assume that the compiler used rendered wrong code for building the GDT and probably other parts, because by not loading it, at least it gives a "Division By Zero" message which tells us that it indeed responded to interrupts.
Attachments
test_img.zip
(48.44 KiB) Downloaded 34 times
Gnippel
Posts: 14
Joined: Tue Mar 06, 2007 6:49 pm

Post by Gnippel »

@~: wow! thanks for all the testing! that's really helpfull! :)

so, it turns out to be the PshPack thing ?
then what is the alternative of '__attribute__((packed))' for msvc?
anybody knows?

thanks!
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

last hint:

Code: Select all

void isrs_install()
{
    idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E);
    idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E);
    idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E);
/*...*/
    idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E);
    idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
    idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
}
and the PIC generates interrupt 32 (!)

for the rest, a session using bochs debugger reveals nothing wrong with the compiler, gdt structures or whatever. My guess is that vs automatically enforces packed structures.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Gnippel
Posts: 14
Joined: Tue Mar 06, 2007 6:49 pm

Post by Gnippel »

Combuster wrote:last hint:

Code: Select all

void isrs_install()
{
    idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E);
    idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E);
    idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E);
/*...*/
    idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E);
    idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
    idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
}
and the PIC generates interrupt 32 (!)

for the rest, a session using bochs debugger reveals nothing wrong with the compiler, gdt structures or whatever. My guess is that vs automatically enforces packed structures.
yes, i know..
that is in irq_install();

void irq_install()
{
irq_remap();

idt_set_gate(32, (unsigned)irq0, 0x08, 0x8E);
idt_set_gate(33, (unsigned)irq1, 0x08, 0x8E);
/* ..... */
idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E);
idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E);
}


and in kernel.c:
void main(unsigned long magic, unsigned long addr)
{
gdt_install();
idt_install();
isrs_install();
irq_install();
init_video();
timer_install();
keyboard_install();

__asm sti;

for( ; ; );
}

i don't see anything wrong there...
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Try this

Code: Select all

__asm__ __volatile__ ( "sti" );
Gnippel
Posts: 14
Joined: Tue Mar 06, 2007 6:49 pm

Post by Gnippel »

pcmattman wrote:Try this

Code: Select all

__asm__ __volatile__ ( "sti" );
i'm using visual studio.. so that can't be done like that there..
__asm sti or:
__asm {
sti
}
is the right to do in msvc.. :wink:
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

When I run it in bochs it crashes on iret, with an invalid CS. It looks to me like you forgot to pop something off of the stack that you pushed up there. However, I didn't have time to look at the sources, so I can't be sure.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

If you have a disassembler/hex editor like HIEW or W32Dasm, you will be able to see that the Visual C binary has opcode bytes that probably shouldn't exist, such as 0xCC for INT 3 instructions (lots of them), whereas the original KERNEL.BIN file doesn't even have not one of them.

The best thing would be to have functional 16/32 assembly knowledge to distinguish what is being compiled and what is additional (and bad) for our program. Maybe it's possible to produce a rawer code with MSVC, maybe looking to disable every debugging functionality, etc.

Maybe taking out those INT 3 codes would help. If not, it would be ideal to examine the contents of both the IDT(R) and GDT(R) as well as the rest of registers just before the point where it crashes, which we'll have to find by intensive testing in the worst case.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

Well, I think I found the VERY problem of this VERY kernel version.

A 16-bit iret (IRET instead of IRETD, returns 16-bit regs, not 32-bit) is causing a stack corruption. It looks like only half of the registers are being restored when returning from INTERRUPT. Try changing the opcode prefix for 16-bit registers operation, 0x66, by a simple NOP instruction 0x90 to solve it. It must be done because bytes cannot be easily removed from a readily linked executable without getting further instructions with wrong addresses.

Look at the byte at the physical, actual offset 0x0000169C inside the file HACK.EXE and KERNEL.EXE:


------------------------------------
| 169C: 66 CF IRET | 16-bit registers
------------------------------------

Modified by:


------------------------------------
| 169C: 90 CF IRETD | 32-bit registers
------------------------------------


I have attached a new disk image with a new entry called "Hacked MSVC Kernel". Note that I didn't recompile it with Visual C, the only thing I did was to change the byte 0x66 by a NOP 0x90.

It is sure that if you keep using MSVC and if there is really not a way of avoiding and making sure that it isn't putting prefixes for 16-bit instructions in 32-bit code, then you will have to be editing manually your machine code in the worst case, and is very likely that there will be many more hard to find instructions with problems like this or other not foreseen at the moment.

Maybe it would be better to use the original tools (mostly GCC/NASM, etc.) indicated by each tutorial for not overcomplicating things and not facing nearly impossible bugs.

I hope that the attached disk image works fine for you as well, but you must bear in mind that whenever you recompile this code or code like this you will keep facing this problem. My last bet is that MSVC is producing 16-bit code (isn't it MSVC6, or maybe its built-in assembler produces it for low level inline assembly like IRET?). Maybe there is some way to produce fully 32-bit code as in nasm by something like:

Code: Select all

a32 iret

Which in fact would only produce the opcode byte for 0xCF, automatically interpreted as a 32-bit interrupt return if in protected mode.



------------------------------------------

HINT: Try replacing all the occurrences of the mnemonic IRET with IRETD (note the D at the end denoting that it will pop DWORDs out of the stack on interrupt return); maybe that is the easy fix.
Attachments
hacked_img.zip
(48.88 KiB) Downloaded 28 times
Last edited by ~ on Thu Mar 08, 2007 4:09 am, edited 3 times in total.
Gnippel
Posts: 14
Joined: Tue Mar 06, 2007 6:49 pm

Post by Gnippel »

@~: wow! you where right!
it's 2 places in the sources where there are iret, now i've changed it to iretd and it works!
i never even thought about that being where the problem was..

thank you so much! :D
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

Gnippel wrote:@~: wow! thanks for all the testing! that's really helpfull! :)

so, it turns out to be the PshPack thing ?
then what is the alternative of '__attribute__((packed))' for msvc?
anybody knows?

thanks!
Guess it should be something like:

Code: Select all

#pragma pack(push, 1) //- packing is now 1 byte and store old
struct _packed_thingy {
    char x;
    short y;
    int z
} packed_thingy;
#pragma pack(pop) //- restore old packing alignment
sizeof(packed_thingy) should be 7 this is also how you can test your structures simply do a sizeof and see if they have the correct size.

otherwise use the compiler switch /Zp1

the iretd sollutions rings a bell i had the same problem with 64bit code. I used iretd but i should have used iretq.
regards
Author of COBOS
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

I have always wondered why it has been done like that by Intel/AMD, having 4 or so combinations for a simple IRET functionality that should be consistent with the current processor mode instead of having real mode IRET (0xCF), 16-bit protected mode (0x66 0xCF), 32-bit protected mode (0xCF) and 64-bit mode (0x48 0xCF) by means of a confusing prefix or no prefix at all...
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post by Candy »

os64dev wrote:

Code: Select all

#pragma pack(push, 1) //- packing is now 1 byte and store old
struct _packed_thingy {
    char x;
    short y;
    int z
} packed_thingy;
#pragma pack(pop) //- restore old packing alignment
sizeof(packed_thingy) should be 7 this is also how you can test your structures simply do a sizeof and see if they have the correct size.

otherwise use the compiler switch /Zp1
That's a tad compiler specific. You might want to inform people what compiler it's specifically for.
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

well as Gnippel said he was using msvc i thought i should give the answer for msvc :wink: i use gcc so that would be the attribute packed thingy but indeed i should have mentioned msvc to clarify.
Author of COBOS
Post Reply