diff options
-rw-r--r-- | src/device/oprom/realmode/x86.c | 58 | ||||
-rw-r--r-- | src/device/oprom/realmode/x86.h | 8 | ||||
-rw-r--r-- | src/device/oprom/realmode/x86_asm.S | 23 |
3 files changed, 78 insertions, 11 deletions
diff --git a/src/device/oprom/realmode/x86.c b/src/device/oprom/realmode/x86.c index a7631a1a84..bf31babe6e 100644 --- a/src/device/oprom/realmode/x86.c +++ b/src/device/oprom/realmode/x86.c @@ -50,11 +50,11 @@ extern unsigned char __realmode_buffer; /* to have a common register file for interrupt handlers */ X86EMU_sysEnv _X86EMU_env; -void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, +unsigned int (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, u32 esi, u32 edi) asmlinkage; -void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, u32 edx, - u32 esi, u32 edi) asmlinkage; +unsigned int (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, + u32 edx, u32 esi, u32 edi) asmlinkage; static void setup_realmode_code(void) { @@ -221,6 +221,46 @@ static int vbe_mode_info_valid(void) return mode_info_valid; } +/* + * EAX register is used to indicate the completion status upon return from + * VBE function in real mode. + * + * If the VBE function completed successfully then 0x0 is returned in the AH + * register. Otherwise the AH register is set with the nature of the failure: + * + * AH == 0x00: Function call successful + * AH == 0x01: Function call failed + * AH == 0x02: Function is not supported in the current HW configuration + * AH == 0x03: Function call invalid in current video mode + * + * Return 0 on success else -1 for failure + */ +static int vbe_check_for_failure(int ah) +{ + int status; + + switch (ah) { + case 0x0: + status = 0; + break; + case 1: + printk(BIOS_DEBUG, "VBE: Function call failed!\n"); + status = -1; + break; + case 2: + printk(BIOS_DEBUG, "VBE: Function is not supported!\n"); + status = -1; + break; + case 3: + default: + printk(BIOS_DEBUG, "VBE: Unsupported video mode %x!\n", + CONFIG_FRAMEBUFFER_VESA_MODE); + status = -1; + break; + } + + return status; +} static u8 vbe_get_mode_info(vbe_mode_info_t * mi) { printk(BIOS_DEBUG, "VBE: Getting information about VESA mode %04x\n", @@ -228,8 +268,10 @@ static u8 vbe_get_mode_info(vbe_mode_info_t * mi) char *buffer = PTR_TO_REAL_MODE(__realmode_buffer); u16 buffer_seg = (((unsigned long)buffer) >> 4) & 0xff00; u16 buffer_adr = ((unsigned long)buffer) & 0xffff; - realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, + X86_EAX = realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, mi->video_mode, 0x0000, buffer_seg, buffer_adr); + if (vbe_check_for_failure(X86_AH)) + die("\nError: In %s function\n", __func__); memcpy(mi->mode_info_block, buffer, sizeof(mi->mode_info_block)); mode_info_valid = 1; return 0; @@ -242,8 +284,10 @@ static u8 vbe_set_mode(vbe_mode_info_t * mi) mi->video_mode |= (1 << 14); // request clearing of framebuffer mi->video_mode &= ~(1 << 15); - realmode_interrupt(0x10, VESA_SET_MODE, mi->video_mode, + X86_EAX = realmode_interrupt(0x10, VESA_SET_MODE, mi->video_mode, 0x0000, 0x0000, 0x0000, 0x0000); + if (vbe_check_for_failure(X86_AH)) + die("\nError: In %s function\n", __func__); return 0; } @@ -286,8 +330,10 @@ void vbe_set_graphics(void) void vbe_textmode_console(void) { delay(2); - realmode_interrupt(0x10, 0x0003, 0x0000, 0x0000, + X86_EAX = realmode_interrupt(0x10, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000); + if (vbe_check_for_failure(X86_AH)) + die("\nError: In %s function\n", __func__); } int fill_lb_framebuffer(struct lb_framebuffer *framebuffer) diff --git a/src/device/oprom/realmode/x86.h b/src/device/oprom/realmode/x86.h index b8cc02a51e..052c9c0dbf 100644 --- a/src/device/oprom/realmode/x86.h +++ b/src/device/oprom/realmode/x86.h @@ -33,11 +33,11 @@ extern unsigned int __idt_handler_size; extern unsigned char __realmode_code; extern unsigned int __realmode_code_size; -extern void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, - u32 esi, u32 edi) asmlinkage; +extern unsigned int (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, + u32 edx, u32 esi, u32 edi) asmlinkage; -extern void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, u32 edx, - u32 esi, u32 edi) asmlinkage; +extern unsigned int (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, + u32 edx, u32 esi, u32 edi) asmlinkage; #define FAKE_MEMORY_SIZE (1024*1024) // only 1MB #define INITIAL_EBDA_SEGMENT 0xF600 diff --git a/src/device/oprom/realmode/x86_asm.S b/src/device/oprom/realmode/x86_asm.S index 87348cdc22..ec82e53ec5 100644 --- a/src/device/oprom/realmode/x86_asm.S +++ b/src/device/oprom/realmode/x86_asm.S @@ -43,6 +43,10 @@ __idt_handler_size: .globl __realmode_code __realmode_code: +/* Realmode function return. */ +__realmode_ret = RELOCATED(.) + .long 0 + /* Realmode IDT pointer structure. */ __realmode_idt = RELOCATED(.) .word 1023 /* 16 bit limit */ @@ -167,6 +171,13 @@ __lcall_instr = RELOCATED(.) .word 0x0000, 0x0000 /* ************************************ */ + /* + * Here is end of real mode call and time to go back to protected mode. + * Before that its better to store current eax into some memory address + * so that context persist in protected mode too. + */ + mov %eax, __realmode_ret + /* If we got here, we are just about done. * Need to get back to protected mode. */ @@ -196,7 +207,8 @@ __lcall_instr = RELOCATED(.) popa /* and exit */ - // TODO return AX from OPROM call + /* return AX from OPROM call */ + mov __realmode_ret, %eax ret .globl __realmode_interrupt @@ -291,6 +303,13 @@ __realmode_interrupt: __intXX_instr = RELOCATED(.) .byte 0xcd, 0x00 /* This becomes intXX */ + /* + * Here is end of real mode call and time to go back to protected mode. + * Before that its better to store current eax into some memory address + * so that context persist in protected mode too. + */ + mov %eax, __realmode_ret + /* Ok, the job is done, now go back to protected mode coreboot */ movl %cr0, %eax orl $PE, %eax @@ -314,6 +333,8 @@ __intXX_instr = RELOCATED(.) movl __stack, %esp popf popa + /* return AX from OPROM call */ + mov __realmode_ret, %eax ret /* This is the 16-bit interrupt entry point called by the IDT stub code. |