Page 1 of 1

Question about BIOS calls

Posted: Fri Sep 27, 2013 8:02 pm
by Bender
Alright So I am confused with BIOS calls, Firstly is it possible to call a BIOS function from protected mode WITHOUT switching to real mode? Also do I have to mess with segment registers if my OS is to be booted up in unreal mode? And does UEFI support some legacy mode for BIOS. Such that I would be able to use all the interrupts through a UEFI machine?
And is there a BIOS call that returns the processor properties like "Intel(R) i386"
I have seen many OSes have this feature of telling the CPU properties like RAM,Processor, Model Number, but couldn't find how to do the same with my OS.
Help would be appreciated
Sid123

Re: Question about BIOS calls

Posted: Sat Sep 28, 2013 3:46 am
by dozniak
You could've actually taken few minutes of time and read already existing topics on this forum addressing this very issue. There's couple dozens of those. All with the same question how to handle BIOS from protected mode.

Add: You're actually breaking forum rules by not doing that.

Re: Question about BIOS calls

Posted: Sat Sep 28, 2013 12:18 pm
by ScropTheOSAdventurer
Firstly is it possible to call a BIOS function from protected mode WITHOUT switching to real mode?
No, because the functions depend on being in real mode to work.
Also do I have to mess with segment registers if my OS is to be booted up in unreal mode?
You do have to mess with segment registers to get in unreal mode (at least that is what it looks like from the wiki entry).
And does UEFI support some legacy mode for BIOS. Such that I would be able to use all the interrupts through a UEFI machine?
You can use the BIOS as usual with UEFI enabled http://stackoverflow.com/questions/1510 ... interrupts.
And is there a BIOS call that returns the processor properties like "Intel(R) i386"
I have seen many OSes have this feature of telling the CPU properties like RAM,Processor, Model Number, but couldn't find how to do the same with my OS.
There isn't a BIOS call, but there is an instruction for this exact purpose: cpuid. You put some value into EAX, stating what you want, and then you use this instruction. For more information on what you put into EAX and other info on cpuid, see http://wiki.osdev.org/CPUID.


And finally, next time, PLEASE look up this stuff yourself before you go to the forum.

Re: Question about BIOS calls

Posted: Sat Sep 28, 2013 2:11 pm
by ~
sid123 wrote:Alright So I am confused with BIOS calls, Firstly is it possible to call a BIOS function from protected mode WITHOUT switching to real mode?
It is possible, but you would need an emulator or V86. There's work and learning to be done in any of those options. If you still need to use the BIOS, then it is better to understand some more of it to later replace that functionality (except for Super VGA modes, for which you will probably need to emulate the BIOS to set those modes).
sid123 wrote:Also do I have to mess with segment registers if my OS is to be booted up in unreal mode?
Yes, but only once, and it isn't difficult. It just requires a very TINY and very well-known assembly snippet. What it does is just increase the limit of the data segments for DS, ES, FS and GS, from 65536 bytes (the normal 0xFFFF segment limit) to 4 Gigabytes (0xFFFFFFFF). There's a hidden part in the segment selectors that can be set in Protected Mode and that stays in Real Mode, and that is basically the trick. And also enabling the A20 line to have access to odd Megabytes.

There are 3 ways to enable the A20 line (fast A20, int 15, and with the keyboad controller). Here you can read more:

http://wiki.osdev.org/A20_Line

I don't know if there are recent machines with that gate already enabled by default, but by this time, it would have seemed the best choice and if I were to make a PC, I would have that gate enabled by default. Here you have the code to set Unreal Mode and enabling the A20 line with the keyboard controller. It may have some errors but it should be easy to fix if that's the case, and you get the idea of how easy it is:

Code: Select all

org 0
bits 16


 ;INIT: enable protected mode (time 1 of 2) to load GDT
 ;INIT: enable protected mode (time 1 of 2) to load GDT
 ;INIT: enable protected mode (time 1 of 2) to load GDT

  start:  cli                             ;{0}
          lgdt    [cs:GDT]              ;Load GDT. This is how we would
                                          ;exactly access the GDT in
                                          ;real mode
            mov     ecx, CR0                ;Switch to protected mode
            inc     cx            ;set PE bit
            mov     CR0, ecx          ;{5} here we activate protected mode
 ;END:  enable protected mode (time 1 of 2) to load GDT
 ;END:  enable protected mode (time 1 of 2) to load GDT
 ;END:  enable protected mode (time 1 of 2) to load GDT



;;INIT: enable A20
;;INIT: enable A20
;;INIT: enable A20

  .5:     in      al, 0x64              ;Enable A20 {4A}. Port 0x64 is the
                                        ;KBC port at the motherboard.

          test    al, 2     ;See if bit 2 at this port is 1, which means
                            ;that he KBC is not ready.

          jnz     .5    ;Repeat until but 2 of port 0x64 is 0, which means
                        ;that the KBC is ready for commands.

        mov     al, 0xD1    ;This command is to write the status byte.
                            ;This is the so-called *WRITE OUTPUT PORT*.
          out     0x64, al    ;Here we send it and it gets executed.

.6:     in      al, 0x64    ;Read the byte at port 0x64.
        and     ax, byte 2   ;See if this bit is 0.
                             ;NOTE: this will leave AL to 0 at once, which
                             ;      will be used in the next
                             ;      INIT--END block.
          jnz     .6           ;Repeat until the KBC is ready
                               ;(bit 2 to 0)


        mov     al, 0xDF    ;Set the configuration bits to send.

            out     0x60, al   ;Send this parameter to the data port
                               ;of the KBC. At this point is where the
                               ;A20 line is enabled.
;;END:  enable A20
;;END:  enable A20
;;END:  enable A20






 ;;INIT: configuration of memory and register parameters
 ;;INIT: configuration of memory and register parameters
 ;;INIT: configuration of memory and register parameters

        mov     ax, _SELDat32            ;Selector for 4Gb data seg. What we do here
                                        ;is to take the address of the second selector
                                        ;of the GDT.
                                        ;We are using the 8-bit register AL to hold the
                                        ;16-bit data selector number because AH is
                                        ;already set to 0, and with this we save 1 byte
                                        ;or so of boot space.


        mov     ds, ax                  ;{2} Extend limit for ds. Typically
                                        ;would get the value 0010h. (16)
        mov     es, ax                  ;Extend limit for es. ES would also
                                        ;be set to 16.
        mov     fs, ax
        mov     gs, ax


        dec     cx                      ;Switch back to real mode. From the start, ECX
                                        ;contained the value of CR0 with PE
                                        ;bit set. Here we disable the PE bit again,
                                        ;and we put it into CR0 in the next
                                        ;instruction.
	mov	CR0, ecx		;{5}
        sti


  ;Here we are in Real Mode:
  ;Here we are in Real Mode:
  ;Here we are in Real Mode:

        xor     eax, eax                ;Segment. 32 bits set to 0x0000
        mov     ds, ax                  ;DS (Data Segment) set to 0x0000
        mov     es, ax                  ;ES (Data Segment) set to 0x0000
        mov     fs, ax                  ;FS (Data Segment) set to 0x0000
        mov     gs, ax                  ;GS (Data Segment) set to 0x0000



 ;;END:  configuration of memory and register parameters
 ;;END:  configuration of memory and register parameters
 ;;END:  configuration of memory and register parameters



 ;;END OF PROGRAM
 ;;END OF PROGRAM
 ;;END OF PROGRAM
 ;;END OF PROGRAM
 ;;END OF PROGRAM
 ;;END OF PROGRAM
 ;;END OF PROGRAM
 ;;END OF PROGRAM
 ;;;
   ret
   ret
   ret
   ret
   ret
   ret
   ret
   ret



 ;INIT: GDT
 ;INIT: GDT
 ;INIT: GDT
    GDT:
   _SELNull equ 0   ;WARNING: This selector, besides being the pointer to the GDT
        GDT_size:   ;         is the null selector.
        dw GDTsize
        GDT_actualptr:
        dd GDT
       dw 0x0000

   _SELCod32 equ 8
     dw 0FFFFh       ; bits 0-15 length
     dw 00000h       ; bits 0-15 base address
     db 0            ; bits 16-23 base address
     db 10011010b    ; bits P,DPL,DT and type
     db 11001111b    ; bits G,D and bits 16-19 length
     db 0            ; bits 24-31 base address

   _SELDat32 equ 16  ;this is the "plain data selector"
     dw 0FFFFh       ; bits 0-15 length
     dw 00000h       ; bits 0-15 base address
     db 0            ; bits 16-23 base address
     db 10010010b    ; bits P,DPL,DT and type
     db 11001111b    ; bits G,D and bits 16-19 length
     db 0            ; bits 24-31 base address
   GDT_end:

   GDTsize equ (GDT_end-GDT)-1
 ;END:  GDT
 ;END:  GDT
 ;END:  GDT

sid123 wrote:And does UEFI support some legacy mode for BIOS. Such that I would be able to use all the interrupts through a UEFI machine?
And is there a BIOS call that returns the processor properties like "Intel(R) i386"
I have seen many OSes have this feature of telling the CPU properties like RAM,Processor, Model Number, but couldn't find how to do the same with my OS.
Help would be appreciated
Sid123
I think UEFI is supposed to completely replace the BIOS calls and overall environment. If you are to create or run an OS that boots the legacy way (BIOS), then UEFI will be out of the question. If you are to create or run an OS that relies on UEFI to boot, then the BIOS is out of the question. The one excludes the other.

There are BIOS calls to get a RAM map, and some other data. Things in the CMOS and the BDA can be still useful too.

To get information on the CPU, you will need to use CPUID, and testing actual capabilities would be the best, but if you won't use them or don't know how to use them, you will probably won't understand all of that is involved or how to gather that information.

Re: Question about BIOS calls

Posted: Sat Sep 28, 2013 8:43 pm
by Bender
Thank You Very much! Just had a query about CPUID,
It uses EAX which is a 32-bit register, but I want to do this in Real Mode (16Bit)
According to the osdev wiki, all 32bit registers are accessible in RM.
But I was wondering whether I could assign the value of a 32bit register (EAX) to a 16bit register(SI) I am afraid that it will generate a index range out of bounds stuff. So it's something like this

Code: Select all

MOV EAX,0 ;----We want the vendor id
CPUID ;----Call the instruction
;---Now according to Wikipedia CPUID returns stuff in EBX,ECX,EDX
MOV SI,EBX
CALL PRINTF
MOV SI,ECX
CALL PRINTF
MOV SI,EDX
CALL PRINTF
Now this should return "GenuineIntel" on PC right? Or is there something wrong?

Re: Question about BIOS calls

Posted: Sun Sep 29, 2013 9:42 am
by azblue
sid123 wrote: But I was wondering whether I could assign the value of a 32bit register (EAX) to a 16bit register(SI) I am afraid that it will generate a index range out of bounds stuff. So it's something like this

Code: Select all

MOV EAX,0 ;----We want the vendor id
CPUID ;----Call the instruction
;---Now according to Wikipedia CPUID returns stuff in EBX,ECX,EDX
MOV ESI,EBX
CALL PRINTF
MOV ESI,ECX
CALL PRINTF
MOV ESI,EDX
CALL PRINTF
Now this should return "GenuineIntel" on PC right? Or is there something wrong?
Use the 32 bit registers.As long as you don't read or write to those memory locations, nothing can go wrong. And you can you can still read/write [si] and [di]