summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/device/oprom/realmode/x86.c58
-rw-r--r--src/device/oprom/realmode/x86.h8
-rw-r--r--src/device/oprom/realmode/x86_asm.S23
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.