Page 1 of 2

call ?

Posted: Sat Mar 27, 2010 11:49 am
by Sam111
When I boot and my program
it display's 'This is sector 2!' on the screen but it some how doesn't call the c function sound?
It just seems to skip it and go directly to the endless loop jmp condition at the end?

Code: Select all

global main
BITS 16 

jmp main
hello	db	'This is sector 2!',13d,10d,'$' ;Put any data here!


main:
mov ax , 0
mov ds , ax 
mov es , ax

mov ax , 0x6000 
mov ss , ax
mov ax , 0x4000
mov sp , ax


mov ax , 600h       ; clear screen scroll up function
mov bh , 7h         ; white on black background
mov ch , 0h         ;upper line (top)
mov cl , 0h         ;left col (far left)
mov dh , 18h        ;bottom 
mov dl , 4Fh        ;far right
int 10h             ;do the clearing 

; display the string This is sector 2 on the screen

mov ah , 13h
mov al , 01h 
mov bh , 0h
mov bl , 0Fh
mov dh , 5h
mov dl , 3h
mov cx , hello
mov bp , cx
mov cx , 16d
int 10h

extern _sound
call _sound [color=#FF0000] ; this is what is not working ????[/color]
endsss:
jmp endsss
the c function is

Code: Select all

.....
void sound()
{

puts( "Welcome to the kernel sound !" ) ;
int i = 1 ;
while( i == 1 )
{
beep() ;
}

}
....
do you have to push something on the stack before calling a c function ?

I don't think the computer is triple faulting I don't see it reseting or anything
When I get rid of the sound function call and put some other int 13 display code their it displays that perfectly as well.... so it must be the c funtion call that is screwed up.

The only thing I can think of is bits 16 to probably c functions bits 32 duno?

And I placed the ss amd sp at 0x6000 and 0x4000

Any help would be great since I don't know how to debug this one.

this is what I compile and linked it as so their is nostdinc , fno-builtin ,....etc

Code: Select all

C:\KERNEL~1>gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -c sound.c -I..\djgpp\include

C:\KERNEL~1>ld -T link.ld load2.o sound.o -o kernel.bin
link.ld is

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(main)
phys = 0x00008000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
	load2.o (.text);
    sound.o (.text);
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
The only thing didn't fully understand what to set
is sp , ss to (stack stuff maybe the bss is not correctly put where the sp , ss is is that it)

bits 16 or 32 if I use 32 then then my boot program doesn't jump to the above file correctly and the code is not executed.

Or maybe align is not correctly set ?
Those are the 3 things I don't fully get yet.

Thanks for any help

Re: call ?

Posted: Sat Mar 27, 2010 12:51 pm
by Gigasoft
This won't work. The C function is a 32 bit one, so you have to go into protected mode and have a 32 bit code segment. The puts function must also be defined.

Re: call ?

Posted: Sat Mar 27, 2010 1:25 pm
by Sam111
Yes , I have all the puts functions ,..etc defined .

I was just wondering if their is away from a 16bit asm boot loading code call a 32bit c function without going into Pmode , setting up GDT , doing a far jump ,...etc

Their should be a reason why you cann't call 32 bit code from 16 bit what is failing in the execution???
And could you clear this up by compile the c function to 16 bit code... (is it even possible to compile 32 bit code to 16 bit with gcc and have it run correctly)

Is the best way to clear this up only to bite the bullet and go into Pmode before calling the c function... or is their other ways of doing it.

I really thought you could call 32 bit functions from 16 bit code without having to be in Pmode?

Could I just turn on the cr0 bit for Pmode and not use the GDT / ldtr ...
Because I really don't care about having the protection of GDT just want to have the ability to jump to my c function later I was thing of setting up the GDT , LDT , IDT , within my c code...

just curious if it is possible to not be in Pmode and call a 32bit c function???

Thanks for any help I don't really see any restrictions on why you cann't do this
care to elaborate.... why?

Plus I tried to switch bits 16 to 32 in the load2.asm could ( i.e the one that calls the sound function posted above)

But when I do that my bootloading code when it puts the load2.asm into memory and jumps to it.
The execution of my load2 program doesn't work at all when it is bit 32 instead of bits 16 wondering why?
I did look at it with a hex editor and the aligment is 2**3 instead of 2**2
As well as their are a few 00 00 bits in between some of the instructions use to be 16bit code I know I can visually see the problem but I don't understand if it is possible to fix this with out having it bits 16..... but then I have the bits 32 call statement ....

AHHHHHHHHHHHH just frustrating


Like if I compiled

Code: Select all

; LoaderAttempt2.asm 
bits 32 
extern sound
global start 
 
start: 
  call sound 
And jumped to the exact start line with my bootloading program (which loads the LoaderAttempt2.asm file into memory 0000:8000h and jmps to it....
I don't see why it wouldn't call the sound function ???

Re: call ?

Posted: Sat Mar 27, 2010 1:39 pm
by Gigasoft
If you call 32 bit code in 16 bit mode, the instructions won't be interpreted correctly since their meaning is different. And GCC can't compile 16 bit code.

The only way to load CS with a 32 bit code segment descriptor is to be in protected mode, and the GDT is necessary to load any segment register in protected mode. The IDT is not necessary if interrupts are off, and LDTs are never necessary, they only exist for your convenience. A TSS is not necessary while running code at CPL 0.

All that's needed is a basic GDT, consisting of these entries:
dd 0ffffh,0cf9a00h,0ffffh,0cf9200h
The LGDT operand should contain:
dw 23
dd GDT-8

If you're returning to real mode later, the GDT must also have two additional entries:
dd 0ffffh,9a00h,0ffffh,9200h

Re: call ?

Posted: Sat Mar 27, 2010 1:50 pm
by StephanvanSchaik
I use this to enable the PC speaker and set it to a specific frequency (I forgot what I set it to):

Code: Select all

    in al, 0x61
    or al, 00000011b
    out 0x61, al
    mov al, 0xB6
    out 0x42, al
    mov al, 0x3A
    out 0x42, al
    mov al, 0x02
    out 0x42, al
and this to disable the PC speaker:

Code: Select all

    in al, 0x61
    and al, 11111100b
    out 0x61, al
I think that would be a better solution instead of trying to get some C function to work. Also, this article about the PC speaker might be a good read.


Regards,
Stephan J.R. van Schaik.

Re: call ?

Posted: Sat Mar 27, 2010 2:02 pm
by Sam111
Few last questions

1)
Must you also turn on the cr0 bit as well or can you just setup the GDT and point the gdtr to the begining of it? ( or must you be completely be in Pmode another words)
Or to put it another way is it just that I need to setup the GDT and point the gdtr to it or do I need to do everything else and fully be in Pmode like turn on the cr0 bit , do a far jump ???


2) I thought cs was 16bits
don't get your statement
The only way to load CS with a 32 bit code segment descriptor is to be in protected mode
32bit is more then 16bits it won't even fit in cs ????

3) curious why 32 bit code cann't be executed in real mode I thought the cpu is 32 bit processor so it is processing 32bits 4 bytes per instruction so I would think that 16 bit instructions would have to be converted first to 32 bit instructions etc ,....for it to run the code because the process or would be executing 2 instructions per instruction cycle....
I guess I don't understand how the processor can run 16 bit code on a 32 bit processor with out padding it to make every instruction 32bits long in the 16bit code....their must be some backwards compatible thing....
I guess I don't see how 16bit code is run any differently then the 32 bit code on a 32bit cpu.

I understand how to do Pmode ,....etc but I just don't get why real mode cann't call c functions directly without having to go into Pmode in theory you should beable to call 32 bit functions with 16 bit code

Thanks
the confusion is starting to go away alittle now.

Re: call ?

Posted: Sat Mar 27, 2010 2:23 pm
by Gigasoft
A 32 bit code segment descriptor means a descriptor for a code segment with a default operand size of 32. Each segment descriptor is 8 bytes in length. JMP FAR takes a 16 bit selector whose upper 13 bits are an index to a code segment descriptor. JMP FAR and other instructions that load segment registers use the selector to locate the segment descriptor and load it. When moving from a segment register to a general register or memory, only the selector is copied. To use the GDT, CR0 bit 0 must be 1, otherwise each segment selector will be interpreted as a base address shifted right by 4.

I explained the difference between 16 bit and 32 bit code in another thread, which I will quote:
No, the bits directive specifies the current default operand and address size. It's not the instruction length. Instructions have variable length.

Instructions are never padded. If a 66h byte precedes an instruction, the operand size changes from 16 bit to 32 bit or from 32 bit to 16 bit. Similarly, the 67h byte changes the address size. For example, if the default size is 16 bits, 89 C8 means mov ax,cx and 66 89 C8 means mov eax,ecx. Similarly, B8 34 12 means mov ax,1234h while 66 B8 34 12 00 00 means mov eax,1234h. In 32 bit mode, 66 B8 34 12 means mov ax,1234h and B8 34 12 00 00 means mov eax,1234h.

In real mode, or when the code segment has a cleared D bit, the default size is 16 bit, and when the D bit is set, the default size is 32 bit, so the corresponding bits directive should be used. For a 64 bit code segment, the default size is still 32 bit, but the meaning of opcodes 40-4fh has changed and some instructions are invalid.

Re: call ?

Posted: Sat Mar 27, 2010 2:28 pm
by StephanvanSchaik
Some additional information:
Sam111 wrote:1)
Must you also turn on the cr0 bit as well or can you just setup the GDT and point the gdtr to the begining of it? ( or must you be completely be in Pmode another words)
Or to put it another way is it just that I need to setup the GDT and point the gdtr to it or do I need to do everything else and fully be in Pmode like turn on the cr0 bit , do a far jump ???
The cr0-register is a register not a bit. The bits in that register can be set and unset to enable features like paging and protected mode. The thing you're probably looking for is protected mode. If your sound function is targeted at 32-bit unreal mode, then you should enter unreal mode, but if it is targeted at 32-bit protected mode, then you should enter protected mode. I however doubt that it is either, as I have a feeling you just compiled code that is supposed to run in user mode, but I might be wrong.
Sam111 wrote:3) curious why 32 bit code cann't be executed in real mode I thought the cpu is 32 bit processor so it is processing 32bits 4 bytes per instruction so I would think that 16 bit instructions would have to be converted first to 32 bit instructions etc ,....for it to run the code because the process or would be executing 2 instructions per instruction cycle....
The x86(-64) architecture has several operation modes such as 16-bit, 32-bit and 64-bit with various "side-modes" (e.g. protected mode, long mode, real mode, etc.) as well. The processor initially executes 16-bit real mode instructions and will therefore interpret them as 16-bit and not as 32-bit, unless they're prefixed with the address or register size operands (0x66 and 0x67). To let the processor execute 32-bit it should be in a 32-bit mode. Also, the x86(-64) does not fetch and execute four bytes per instruction unlike the ARM, PPC, SPARC, etc. as the x86(-64) architecture is a CISC-architecture and not a RISC-architecture. That means that the instructions have a variable size which should be one byte up to fifteen bytes on the x86(-64) architecture).
Sam111 wrote:I guess I don't understand how the processor can run 16 bit code on a 32 bit processor with out padding it to make every instruction 32bits long in the 16bit code....their must be some backwards compatible thing....
I guess I don't see how 16bit code is run any differently then the 32 bit code on a 32bit cpu.
You're confusing CISC with RISC, whether it is running in 16-bit or 32-bit doesn't say anything about the instruction size. Even on RISC architectures it doesn't tell anything about the instruction size (e.g. a PPC64 processor operating in 64-bit mode still uses four bytes per instruction instead of eight). Neither do they actually tell anything about the register size as the registers might be 32-bit in 16-bit real mode on the x86(-64) architecture, hence the address and register size operands. What they do refer to is the mode of execution or operation, that means that most instructions, if not all, instructions are able to access 16-bit registers and such in 16-bit real mode by default.


Regards,
Stephan J.R. van Schaik.

Re: call ?

Posted: Sat Mar 27, 2010 2:40 pm
by ~
There seems to be an error, and corrected the line to access port 43h:
StephanVanSchaik wrote:

Code: Select all

    in al, 0x61
    or al, 00000011b
    out 0x61, al
    mov al, 0xB6
    out 0x43, al
    mov al, 0x3A
    out 0x42, al
    mov al, 0x02
    out 0x42, al
There seems to be a typo. You must send the 0xB6 value to port 43h. If you send it to port 42h (the "speaker frequency divider" port), or in general if you send an odd number of bytes to that port, it will be left waiting for another byte to complete a 2-byte value.

As an additional note, it's curious that I have never seemed to have any difficulties by omitting the command to port 43h, I have just sent 2 byte values, one by one to port 42h to set the frequency, and, as soon as I send the second byte, if the speaker is on, the change in frequency can be heard.

I have done the normal enabling in port 61h, then omitted the write to port 43h even in a 386 (if I remember correctly), and set the frequency in port 42h and the frequency is changed correctly.

What is the purpose of writing to port 43h then, other than indicating the "speaker frequency timer" that we are about to reprogram it, if it doesn't actually seem to be necessary (I have omitted it with no ill effects so far), or should it be set only for safety?

-------------------------------
As for the other questions of Sam111...

Think of your processor as being 2-in-1 if you have a 32-bit capable processor. If you have a 64-bit capable processor, think of it as being a 3-in-1 processor.

You need to specify which of them you want to use. If the 16-bit mode processor is enabled (by default on BIOS boot), you cannot fully use the capabilities of the 32-bit one. For that, you must activate the 32-bit mode processor, and the same goes for 64-bit.

And of course, for a machine like a Pentium or AMD64 (with only one core), you can use that single-core CPU as a 16, 32 or 64-bit CPU at the same time, not interchangeably.

Re: call ?

Posted: Sat Mar 27, 2010 2:55 pm
by StephanvanSchaik
~ wrote:There seems to be an error, and corrected the line to access port 43h:
StephanVanSchaik wrote:

Code: Select all

    in al, 0x61
    or al, 00000011b
    out 0x61, al
    mov al, 0xB6
    out 0x43, al
    mov al, 0x3A
    out 0x42, al
    mov al, 0x02
    out 0x42, al
There seems to be a typo. You must send the 0xB6 value to port 43h. If you send it to port 42h (the "speaker frequency divider" port), or in general if you send an odd number of bytes to that port, it will be left waiting for another byte to complete a 2-byte value.

As an additional note, it's curious that I have never seemed to have any difficulties by omitting the command to port 43h, I have just sent 2 byte values, one by one to port 42h to set the frequency, and, as soon as I send the second byte, if the speaker is on, the change in frequency can be heard.

I have done the normal enabling in port 61h, then omitted the write to port 43h even in a 386 (if I remember correctly), and set the frequency in port 42h and the frequency is changed correctly.

What is the purpose of writing to port 43h then, other than indicating the "speaker frequency timer" that we are about to reprogram it, if it doesn't actually seem to be necessary (I have omitted it with no ill effects so far), or should it be set only for safety?
Thanks, I fixed that now. As for your additional note, I actually have no idea. It might be required for older PIT-chips.


Regards,
Stephan J.R. van Schaik.

Re: call ?

Posted: Sat Mar 27, 2010 3:14 pm
by ~
I have just made a test in a machine, and this is what I saw that happened:

I wrote port 61h to enable the speaker:

Code: Select all

in al,61h
or al,00000011b
out 61h,al
Then it had a certain frequency.

Next, I wrote port 42h with only 1 value to test:

Code: Select all

mov al,42h
out 42h,al
Of course, the frequency didn't change because it was waiting another byte to complete the 16-bit value.
--------------------------

Instead, I wrote to port 43h to indicate reprogramming of the "speaker frequency timer":

Code: Select all

mov al,0xB6
out 43h,al
The effect was that the speaker went silent, but it was NOT disabled in port 61h.

Then I had to write 2 bytes again to port 42h to change the frequency.

It means that the speaker was "reset" , and discarded the incomplete, 1-byte value I sent in the beginning to port 42h.

Code: Select all

mov al,42h
out 42h,al
mov al,05h
out 42h,al
So it looks like it would be useful in case the speaker gets stuck with an incomplete value somehow. By sending the 0xB6 byte to port 43h, a full programming cycle is assured, although it seems to not be necessary most of the time (all my machines don't require it).

And sending that command to port 43h always causes the speaker to go silent in every case, even if it's the first time you program the speaker from bootup, and you note it provided the steps are timed in seconds between them and the speaker has been enabled in port 61h.

Re: call ?

Posted: Sat Mar 27, 2010 3:31 pm
by Gigasoft
You only need to write to 43h to reset a counter (and the counting mode). BIOSes may or may not initialize counter 2 to 16 bit square wave mode, so you should always initialize it in the beginning of the program if you are using it. When doing a frequency sweep in particular, you should not reset the counter. However, you can always issue a counter latch or read back command without disturbing the counters. Resetting a counter stops it until the initial count is programmed.

The programming manual can be found here:
http://www.intel-assembler.it/PORTALE/4 ... 54_PIT.pdf

Re: call ?

Posted: Sat Mar 27, 2010 3:34 pm
by Sam111
Ok , I am trying to understand all of this
these are my questions from your questions
A 32 bit code segment descriptor means a descriptor for a code segment with a default operand size of 32. Each segment descriptor is 8 bytes in length. JMP FAR takes a 16 bit selector whose upper 13 bits are an index to a code segment descriptor. JMP FAR and other instructions that load segment registers use the selector to locate the segment descriptor and load it. When moving from a segment register to a general register or memory, only the selector is copied. To use the GDT, CR0 bit 0 must be 1, otherwise each segment selector will be interpreted as a base address shifted right by 4.
I am sorry but I don't fully understand what the far jmp is doing.
I get that the GDT segment descriptors are 8bytes long or 64bits and 32bits of it are used for the limit and base address stuff.

Code: Select all

JMP FAR takes a 16 bit selector whose upper 13 bits are an index to a code segment descriptor.
How did you know that? why the upper 13bits in the cs register are an index into a code segment descriptor? Is all x86 computers made like this? And by code segment descriptor you mean apart of an entry in the GDT table (limit and base)


Question 2
Could I call a 32 bit program if I manual put a 66 or 67 prefix on it.
Instead of going into protected mode?

Question 3
If I didn't want to go into protected mode can I just go into unreal mode without going first into protected mode?
What would happen if I set the cr0 bit to protected mode but I never setup the GDT stuff or did a far jump just curious?
Where is the default gdtr , ldtr ,...etc pointing before setting them up curious?
I am thinking the ldtr is pointing to the IVT at 0x00000000 ... though I am not 100% sure.


Question 4
Being on a 32bit arch x86 machine is their any other modes other then real mode , unreal mode , and protected mode? ( I know when we go to 64bits they have one more called long mode)
Another words is their any different mode or corosponding bits for modes that I haven't commented on?

Question 5
Is their any other difference in unreal mode from real mode apart from the fact you can access all 4GB of memory in unreal as opposed to real?
Can you still use the IVT of real mode in unreal mode ,...etc ?

Thanks

Wait I just thought about it still don't get the 13bits thing in question 1 and how this was built into the hardware but
2^13 = 8192 would this be the exact max number of entries that a GDT can have... ?
That would make since!

Re: call ?

Posted: Sat Mar 27, 2010 4:07 pm
by ~
The higher 13 bits are used because the lower 3 bits encode addresses from 0 to 7, and that's because each GDT selector is 8 bytes long, and by using the higher 13 bits as index the location of the GDT selector is aligned to 8 bytes (in steps of 8).

To create Unreal Mode you need to briefly enter a minimum protected mode environment (GDT only, set PE bit in CR0, enable Gate A20, interrupts disabled with CLI instruction, nothing more).

If you enable the PE bit in the CR0 register but you don't load a GDT, or don't do a far jump, it surely will cause the machine to reset because of what is called a Triple Fault in the protected mode world.

If you want to use instructions that are native to 32-bit mode, you must do so for each of them (the assembler helps you a little in this by generating the prefixes and proper instructions). Only general purpose instructions and a few system instructions can be used in 16-bit mode.

If you want to run 32-bit code natively, you must enter protected mode, load GDT, an optional IDT and do a far jump.

--------------------
In Real/Unreal Mode, you are still in 16-bit mode, and you can use BIOS, etc., plus now you can use 4GB of data.

Re: call ?

Posted: Sat Mar 27, 2010 4:36 pm
by Owen
Sam111 wrote: Question 2
Could I call a 32 bit program if I manual put a 66 or 67 prefix on it.
Instead of going into protected mode?
Maybe, but unlikely. It depends entirely on the program. A program as generated by a compiler probably has some assumptions that do not hold in real mode.
Question 3
If I didn't want to go into protected mode can I just go into unreal mode without going first into protected mode?
What would happen if I set the cr0 bit to protected mode but I never setup the GDT stuff or did a far jump just curious?
Where is the default gdtr , ldtr ,...etc pointing before setting them up curious?
I am thinking the ldtr is pointing to the IVT at 0x00000000 ... though I am not 100% sure.
The GDTR is udnefined. the IDTR points at the IVT (IIRC You can use the LIDT instruction in real mode to relocate the IVT)

If you never set the GDT, you would be in a rather fragile protected mode (One which with the slightest provocation - accidental segment register load, for example) would crash

Entering Unreal mode involves
  • Turning protected mode on (Setting the PE bit in CR0)
  • Loading a GDT
  • Loading an appropriate segment register (Usually FS or GS) with a 32-bit data segment
  • Turning protected mode off (Clearing the PE bit in CR0)
Question 4
Being on a 32bit arch x86 machine is their any other modes other then real mode , unreal mode , and protected mode? ( I know when we go to 64bits they have one more called long mode)
Another words is their any different mode or corosponding bits for modes that I haven't commented on?
Protected mode has 16-bit, 32-bit and Virtual 8086 submodes, but there are just real and protected mode (unreal mode being a funny form of real mode)
[/quote]