OSDev.org https://forum.osdev.org/ |
|
BIOS calls for VESA functionalities https://forum.osdev.org/viewtopic.php?f=1&t=33486 |
Page 1 of 2 |
Author: | iman [ Wed Feb 06, 2019 10:56 am ] |
Post subject: | BIOS calls for VESA functionalities |
Hi. I am new in this Forum. On my way to develop my OS and using VESA for it, I got an issue. It is now in protected mode and I want to call VESA functionalities. I used the source code provided by Napalm at Rohitab (http://www.rohitab.com/discuss/user/3860-napalm/). Some functionalities work perfectly, but one of them not. I have a struct called VBE_INFO which holds the vbe info such as vendor, version, etc. Then I supplied reg.ax with 0xF400, regs.es with SEGMENT(&vbe_info) which passes the segment of the pointer and reg.di with OFFSET(&vbe_info) which passes the offset of the 32-bit pointer. After calling int32 function with 0x10 and ® as the arguments, I checked the return value in ax and indeed it is 0x00F4. But the vbe_info did not updated by the BIOS. For instance, vbe_info.version is 0. It made me thought perhaps there is a bug in the int32 calling function. Is there anybody who can help me with that? Maybe others had the same problem before. Thanks. |
Author: | MichaelPetch [ Wed Feb 06, 2019 11:10 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
It would probably help to see your actual code.Do you have your OS on Gitlab or Github (or similar service)? Sounds like the memory address of your vbe_info (Segment and Offset) structure that you told Int 10h/04f00h to fill in. Was this a typo? Quote: Then I supplied reg.ax with 0xF400, Did you mean 0x4F00?
|
Author: | bzt [ Wed Feb 06, 2019 2:34 pm ] |
Post subject: | Re: BIOS calls for VESA functionalities |
Hi, and welcome! You should also initialize the buffer with a magic value. Here's how I do it: Code: xor ax, ax mov es, ax mov ax, 4f00h mov di, 0A000h mov dword [di], 'VBE2' int 10h cmp ax, 004fh je @f mov si, novbe jmp die @@: Cheers, bzt |
Author: | BenLunt [ Wed Feb 06, 2019 3:07 pm ] |
Post subject: | Re: BIOS calls for VESA functionalities |
iman wrote: It is now in protected mode and I want to call VESA functionalities. Does this mean you are executing an INT 10h instruction while in protected mode? iman wrote: Then I supplied reg.ax with 0xF400, As MichaelPetch asked, is this a typo? It should be 0x4F00. Also as bzt mentioned, you need to give it a signature to tell the BIOS your buffer is big enough to hold the version 2.0 data. I think your biggest issue is trying to execute an INT 10h instruction while in protected mode. All of this should be done before you move to protected mode. Ben - http://www.fysnet.net/osdesign_book_series.htm |
Author: | iman [ Thu Feb 07, 2019 3:12 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
BenLunt wrote: iman wrote: It is now in protected mode and I want to call VESA functionalities. Does this mean you are executing an INT 10h instruction while in protected mode? iman wrote: Then I supplied reg.ax with 0xF400, As MichaelPetch asked, is this a typo? It should be 0x4F00. Also as bzt mentioned, you need to give it a signature to tell the BIOS your buffer is big enough to hold the version 2.0 data. I think your biggest issue is trying to execute an INT 10h instruction while in protected mode. All of this should be done before you move to protected mode. Ben - http://www.fysnet.net/osdesign_book_series.htm Sorry it was a typo. I put the value 0x004F in ax and not 0x00F4. I also put the 'VBE2' signature and reserved 512 bytes for the buffer. To trigger INT 10H in protected mode, I used the same function that Napalm distributed long time ago and as I said for some other calls, it works perfectly. For example, I can supply ax and bx with the needed value and call INT 10H to change the mode for me and it does the job. But for this task that I play with reg.es, although it gives me the success return value, it does not fill up the VBE_INFO buffer. |
Author: | iman [ Thu Feb 07, 2019 3:17 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
MichaelPetch wrote: It would probably help to see your actual code.Do you have your OS on Gitlab or Github (or similar service)? Sounds like the memory address of your vbe_info (Segment and Offset) structure that you told Int 10h/04f00h to fill in. Was this a typo? Quote: Then I supplied reg.ax with 0xF400, Did you mean 0x4F00?Dear Michael. It was a typo during my message writing. I put the value 0x004F in reg.ax and not 0x00F4. I will put it public on my Github and send the link here. But, I used exactly the same function that Napalm distributed and my little OS is supposed not to do anything but draw in SVGA. Therefore, I have a kernel file and a loader file which reserve some stack, provides magic numbers for GRUB, and call the kernel. In the kernel file on the other hand, I would like to call INT 10H with the use of int32 function. |
Author: | iman [ Thu Feb 07, 2019 3:19 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
BenLunt wrote: iman wrote: It is now in protected mode and I want to call VESA functionalities. Does this mean you are executing an INT 10h instruction while in protected mode? iman wrote: Then I supplied reg.ax with 0xF400, As MichaelPetch asked, is this a typo? It should be 0x4F00. Also as bzt mentioned, you need to give it a signature to tell the BIOS your buffer is big enough to hold the version 2.0 data. I think your biggest issue is trying to execute an INT 10h instruction while in protected mode. All of this should be done before you move to protected mode. Ben - http://www.fysnet.net/osdesign_book_series.htm BenLunt wrote: Does this mean you are executing an INT 10h instruction while in protected mode? Yes. This is where I tried to switch back to the real-mode and trigger INT 10H. |
Author: | iman [ Thu Feb 07, 2019 3:37 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
Here is the link to the Github: https://github.com/ImAbdollahzadeh/OS |
Author: | MichaelPetch [ Thu Feb 07, 2019 8:46 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
It is unclear how your OS in github even compiles or works as expected since you define function int32 to take 2 parameters and you only call it with one. Are you sure your github actually is a workable example.Would also help if your project contained something that had the commands used to compile/linker your files, your linker script etc. |
Author: | iman [ Thu Feb 07, 2019 9:00 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
MichaelPetch wrote: It is unclear how your OS in github even compiles or works as expected since you define function int32 to take 2 parameters and you only call it with one. Are you sure your github actually is a workable example.Would also help if your project contained something that had the commands used to compile/linker your files, your linker script etc. Re-updated. You can find the working code of mine. Besides all the commands have been given in their orders as well. Cheers. |
Author: | MichaelPetch [ Thu Feb 07, 2019 9:59 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
Can you look back at my question and answer the one about function int32 defined as taking 2 parameters but you only pass 1 when you call it from kernel.c? |
Author: | iman [ Thu Feb 07, 2019 10:01 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
MichaelPetch wrote: Can you look back at my question and answer the one about function int32 defined as taking 2 parameters but you only pass 1 when you call it from kernel.c? It gets two arguments. It was a mistake. In my Github page, I updated everything. Now the status of the code is exactly what I use on both linux and windows machines that I have. |
Author: | bzt [ Thu Feb 07, 2019 11:55 am ] |
Post subject: | Re: BIOS calls for VESA functionalities |
Hi, I took a look at your code. There are so many things you should fix first before you try VESA. 1. first of all, you should NEVER use a hosted C compiler for a kernel. Use a cross-compiler, or at least specify "-ffreestanding -nostdlib -nostdinc". ANSI C defines two modes, freestanding and hosted for a reason. 2. why do you copy and relocate a lot on every single int32 call? Why don't you place the regs struct somewhere in memory where both the prot mode and real mode codes can access it directly? 3. your stack is very likely corrupted. Maybe I'm mistaken, but where do you push the segment registers on the stack which you pop at line 71? 4. I'm not sure that pusha struct - regs struct are the same, mostly because of the wild stack handling. It would be much faster to use a couple of mov's instead btw, but if you insist on popa / pusha, then you should set the stack at 7C00 and map that area with the regs struct from your linker script. That way you could directly update the real mode stack (which loads the registers from there with a popa) from your C code simply using the regs struct. 5. maybe it would be useful to take a look how Minix does int86(). It also uses a register structure, and it does not relocate anything (although it relies on a real mode monitor, which is implemented in its boot loader). Cheers, bzt |
Author: | MichaelPetch [ Thu Feb 07, 2019 5:20 pm ] |
Post subject: | Re: BIOS calls for VESA functionalities |
Your VBE structure will have to be below 0x100000 to properly work since BIOS interrupts will have difficulty writing above the 1MiB mark. As it is your VBE structure is on the stack where ESP > 0x100000. Pick a memory location in lower memory (like 0x600) that is above the BIOS Data area and the interrupt vector table. This address can be used for both protected mode and realmode. Your OFF and SEG macros assume realmode FAR pointers. Adjust them so they compute to a normalized segment:offset for physical address < 0x100000. The macros could look like: Code: #define SEG(FP) ((uint16_t)(((unsigned long)FP)>>4)) Your VBE function could look like: #define OFF(FP) ((uint16_t)(((unsigned long)FP)&0xF)) Code: int VBE( VBE_INFO* vbe ) Your main could look like { regs16_t regs; regs.ax = 0x4F00; regs.es = SEG(vbe); regs.di = OFF(vbe); int32( 0x10, ®s ); if ( regs.ax == 0x004F ) return 1; return 0; } Code: int main( void ) { VBE_INFO *vbe = (VBE_INFO *)0x600; int res; vbe->signature[0] = 'V'; vbe->signature[1] = 'B'; vbe->signature[2] = 'E'; vbe->signature[3] = '2'; res = VBE( vbe ); if (res == 1) { if(vbe->version == 0x0000) // this is what I get always printk('N'); else if(vbe->version != 0x0000) printk('Y'); } else printk('0'); } Function int32 assumes that the interrupts were already on prior to being called and turns them on when finished. If you don't have a protected mode IDT set up (or you haven't disabled all the IRQs on the PICs) the code will fault in protected mode when int32 is finished. I've amended the code to only re-enable interrupts if they were already enabled when first called: Code: [bits 32]
global int32, _int32 struc regs16_t .di resw 1 .si resw 1 .bp resw 1 .sp resw 1 .bx resw 1 .dx resw 1 .cx resw 1 .ax resw 1 .gs resw 1 .fs resw 1 .es resw 1 .ds resw 1 .ef resw 1 endstruc %define INT32_BASE 0x7C00 ; base BIOS address %define REBASE(x) (((x) - reloc) + INT32_BASE) %define GDTENTRY(x) ((x) << 3) %define CODE32 GDTENTRY(1) ; 0x08 %define DATA32 GDTENTRY(2) ; 0x10 %define CODE16 GDTENTRY(3) ; 0x18 %define DATA16 GDTENTRY(4) ; 0x20 %define STACK16 (INT32_BASE - regs16_t_size) section .text int32: use32 _int32: pushf pop dword [eflags] ; Save the current CPU flags (including IF state) cli ; disable interrupts pusha ; save register state to 32bit stack mov esi, reloc ; set source to code below mov edi, INT32_BASE ; set destination to new base address mov ecx, (int32_end - reloc) ; set copy size to our codes size: LOOK AT THE COMMENT TAGGED WITH %*% cld ; clear direction flag (so we copy forward) rep movsb ; do the actual copy (relocate code to low 16bit space) jmp INT32_BASE ; jump to new code location reloc: use32 ; %*% From here on gets copy startting from INT32_BASE mov [REBASE(stack32_ptr)], esp ; save 32bit stack pointer sidt [REBASE(idt32_ptr)] ; save 32bit idt pointer sgdt [REBASE(gdt32_ptr)] ; save 32bit gdt pointer lgdt [REBASE(gdt16_ptr)] ; load 16bit gdt pointer lea esi, [esp+0x24] ; set position of intnum on 32bit stack lodsd ; read intnum into eax mov [REBASE(ib)], al ; set intrrupt immediate byte from our arguments mov esi, [esi] ; read regs pointer in esi as source mov edi, STACK16 ; set destination to 16bit stack mov ecx, regs16_t_size ; set copy size to our struct size mov esp, edi ; save destination to as 16bit stack offset rep movsb ; do the actual copy (32bit stack to 16bit stack) jmp word CODE16:REBASE(p_mode16) ; switch to 16bit selector (16bit protected mode) p_mode16: use16 mov ax, DATA16 ; get our 16bit data selector mov ds, ax ; set ds to 16bit selector mov es, ax ; set es to 16bit selector mov fs, ax ; set fs to 16bit selector mov gs, ax ; set gs to 16bit selector mov ss, ax ; set ss to 16bit selector mov eax, cr0 ; get cr0 so we can modify it and al, ~0x01 ; mask off PE bit to turn off protected mode mov cr0, eax ; set cr0 to result jmp word 0x0000:REBASE(r_mode16) ; finally set cs:ip to enter real-mode r_mode16: use16 xor ax, ax ; set ax to zero mov ds, ax ; set ds so we can access idt16 mov ss, ax ; set ss so they the stack is valid lidt [REBASE(idt16_ptr)] ; load 16bit idt popa ; load general purpose registers from 16bit stack pop gs ; load gs from 16bit stack pop fs ; load fs from 16bit stack pop es ; load es from 16bit stack pop ds ; load ds from 16bit stack sti ; enable interrupts db 0xCD ; opcode of INT instruction with immediate byte ib: db 0x00 cli ; disable interrupts xor sp, sp ; zero sp so we can reuse it mov ss, sp ; set ss so the stack is valid mov sp, INT32_BASE ; set correct stack position so we can copy back pushf ; save eflags to 16bit stack push ds ; save ds to 16bit stack push es ; save es to 16bit stack push fs ; save fs to 16bit stack push gs ; save gs to 16bit stack pusha ; save general purpose registers to 16bit stack mov eax, cr0 ; get cr0 so we can modify it inc eax ; set PE bit to turn on protected mode mov cr0, eax ; set cr0 to result jmp dword CODE32:REBASE(p_mode32) ; switch to 32bit selector (32bit protected mode) p_mode32: use32 mov ax, DATA32 ; get our 32bit data selector mov ds, ax ; reset ds selector mov es, ax ; reset es selector mov fs, ax ; reset fs selector mov gs, ax ; reset gs selector mov ss, ax ; reset ss selector lgdt [REBASE(gdt32_ptr)] ; restore 32bit gdt pointer lidt [REBASE(idt32_ptr)] ; restore 32bit idt pointer mov esp, [REBASE(stack32_ptr)] ; restore 32bit stack pointer mov esi, STACK16 ; set copy source to 16bit stack lea edi, [esp+0x28] ; set position of regs pointer on 32bit stack mov edi, [edi] ; use regs pointer in edi as copy destination mov ecx, regs16_t_size ; set copy size to our struct size cld ; clear direction flag (so we copy forward) rep movsb ; do the actual copy (16bit stack to 32bit stack) popa ; restore registers test dword [eflags], 1<<9 ; If original interrupt state was on, issue STI jz int_off ; otherwise keep interrupts off sti int_off: ret ; return to caller stack32_ptr: ; address in 32bit stack after we dd 0x00000000 ; save all general purpose registers idt32_ptr: ; IDT table pointer for 32bit access dw 0x0000 ; table limit (size) dd 0x00000000 ; table base address gdt32_ptr: ; GDT table pointer for 32bit access dw 0x0000 ; table limit (size) dd 0x00000000 ; table base address idt16_ptr: ; IDT table pointer for 16bit access dw 0x03FF ; table limit (size) dd 0x00000000 ; table base address gdt16_base: ; GDT descriptor table .null: ; 0x00 - null segment descriptor dd 0x00000000 ; must be left zero'd dd 0x00000000 ; must be left zero'd .code32: ; 0x01 - 32bit code segment descriptor 0xFFFFFFFF dw 0xFFFF ; limit 0:15 dw 0x0000 ; base 0:15 db 0x00 ; base 16:23 db 0x9A ; present, iopl/0, code, execute/read db 0xCF ; 4Kbyte granularity, 32bit selector; limit 16:19 db 0x00 ; base 24:31 .data32: ; 0x02 - 32bit data segment descriptor 0xFFFFFFFF dw 0xFFFF ; limit 0:15 dw 0x0000 ; base 0:15 db 0x00 ; base 16:23 db 0x92 ; present, iopl/0, data, read/write db 0xCF ; 4Kbyte granularity, 32bit selector; limit 16:19 db 0x00 ; base 24:31 .code16: ; 0x03 - 16bit code segment descriptor 0x000FFFFF dw 0xFFFF ; limit 0:15 dw 0x0000 ; base 0:15 db 0x00 ; base 16:23 db 0x9A ; present, iopl/0, code, execute/read db 0x0F ; 1Byte granularity, 16bit selector; limit 16:19 db 0x00 ; base 24:31 .data16: ; 0x04 - 16bit data segment descriptor 0x000FFFFF dw 0xFFFF ; limit 0:15 dw 0x0000 ; base 0:15 db 0x00 ; base 16:23 db 0x92 ; present, iopl/0, data, read/write db 0x0F ; 1Byte granularity, 16bit selector; limit 16:19 db 0x00 ; base 24:31 gdt16_ptr: ; GDT table pointer for 16bit access dw gdt16_ptr - gdt16_base - 1 ; table limit (size) dd gdt16_base ; table base address eflags: dd 0 ; Storage for EFLAGS (including IF) int32_end: ; end marker (so we can copy the code) |
Author: | MichaelPetch [ Thu Feb 07, 2019 7:27 pm ] |
Post subject: | Re: BIOS calls for VESA functionalities |
bzt wrote: 3. your stack is very likely corrupted. Maybe I'm mistaken, but where do you push the segment registers on the stack which you pop at line 71? .They aren't pushed, but they are copied in from the memory address passed as a regs16_t * to the 16-bit real mode stack with these lines:Code: mov esi, [esi] ; read regs pointer in esi as source mov edi, STACK16 ; set destination to 16bit stack mov ecx, regs16_t_size ; set copy size to our struct size mov esp, edi ; save destination to as 16bit stack offset rep movsb ; do the actual copy (32bit stack to 16bit stack) |
Page 1 of 2 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |