Subrata Banik has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/33737
Change subject: device/oprom: Add vbe return status support as per VBE spec 3.0 ......................................................................
device/oprom: Add vbe return status support as per VBE spec 3.0
Existing coreboot oprom implementation relies on user selected vesa mode through CONFIG_FRAMEBUFFER_VESA_MODE Kconfig option and expects that all oprom might support user selected vesa mode.
Take an example: Enabling AMD external radeon PCIE graphics card on ICLRVP with default vesa mode 0x118. Unable to get valid X and Y resolution after executing vbe_get_mode_info() with 0x4118, return data buffer shows 0x0 resolution. It causes further hang while trying to draw bmpblk image at depthcharge.
This patch checks for output register AX in all vbe functions(0x3 and 0x4f00/1/2) and list all supported vesa mode by oprom using Function 0x4F00 (return vbe controller information). This information might be useful for user to select correct vesa mode for oprom.
TEST=Enabling external pcie based graphics card on ICLRVP
Case 1: with unsupported vesa mode 0x118 Now coreboot will show below msg to user to know there is a potential issue with choosen vesa mode and better user know the failure rather going to depthcharge and debug further.
Calling Option ROM... ... Option ROM returned. VBE: Getting information about VESA mode 4118 VBE: Function call invalid with unsupported video mode 0x118! User to select mode from below list - Supported Video Mode list for OpRom are: 0x110 0x111 0x113 0x114 0x116 0x117 0x119 0x11a 0x165 0x166 0x121 0x122 0x123 0x124 0x145 0x146 0x175 0x176 0x1d2 0x1d4
Error: In vbe_get_mode_info function
Case 2: with supported vesa mode 0x116
Calling Option ROM... ... Option ROM returned. VBE: Getting information about VESA mode 4116 VBE: resolution: 1024x768@16 VBE: framebuffer: a0000000 VBE: Setting VESA mode 4116 VGA Option ROM was run
Change-Id: Iacd2ce468e038a14424f029df3a0adec3e5fa15c Signed-off-by: Subrata Banik subrata.banik@intel.com --- M src/device/oprom/realmode/x86.c M src/device/oprom/realmode/x86_asm.S M src/include/vbe.h 3 files changed, 107 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/37/33737/1
diff --git a/src/device/oprom/realmode/x86.c b/src/device/oprom/realmode/x86.c index a7631a1..d1c7731 100644 --- a/src/device/oprom/realmode/x86.c +++ b/src/device/oprom/realmode/x86.c @@ -221,6 +221,90 @@ return mode_info_valid; }
+static int vbe_check_for_failure(void); + +static vbe_info_t vbe_get_ctrl_info(void) +{ + char *buffer = PTR_TO_REAL_MODE(__realmode_buffer); + vbe_info_t info; + u16 buffer_seg = (((unsigned long)buffer) >> 4) & 0xff00; + u16 buffer_adr = ((unsigned long)buffer) & 0xffff; + realmode_interrupt(0x10, VESA_GET_INFO, 0x0000, 0x0000, 0x0000, + buffer_seg, buffer_adr); + if (vbe_check_for_failure()) + die("\nError: In %s function\n", __func__); + memcpy(&info, buffer, sizeof(vbe_info_t)); + + return info; +} + +static void vbe_opron_list_supported_mode(uint16_t *video_mode_ptr) +{ + uint16_t mode; + printk(BIOS_DEBUG,"Supported Video Mode list for OpRom are:\n"); + do + { + mode = *video_mode_ptr++; + if (mode != 0xffff) + printk(BIOS_DEBUG,"%x\n", mode); + } while (mode != 0xffff); +} + +static void vbe_oprom_supported_mode_list(void) +{ + vbe_info_t info = vbe_get_ctrl_info(); + uint32_t video_mode_ptr = info.video_mode_list[1] << 16 | + info.video_mode_list[0]; + vbe_opron_list_supported_mode((uint16_t *)video_mode_ptr); +} + +/* + * EAX register is used to indicate the completion status upon return from + * VBE function in real mode. + * In x86_asm.S, store EAX into REALMODE_BASE before jumping into protected + * 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: Functio call invalid in current video mode + * + *Return 0 on success else -1 for failure + */ +static int vbe_check_for_failure(void) +{ + uint32_t vbe_return_status; + int status; + vbe_return_status = *((unsigned int*)REALMODE_BASE); + + switch ((vbe_return_status & 0xff00) >> 8) { + 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: Function call invalid with" + " unsupported video mode %x!\n", + CONFIG_FRAMEBUFFER_VESA_MODE); + printk(BIOS_DEBUG, "User to select mode from below list - \n"); + vbe_oprom_supported_mode_list(); + 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", @@ -230,20 +314,25 @@ u16 buffer_adr = ((unsigned long)buffer) & 0xffff; realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, mi->video_mode, 0x0000, buffer_seg, buffer_adr); + if (vbe_check_for_failure()) + die("\nError: In %s function\n", __func__); memcpy(mi->mode_info_block, buffer, sizeof(mi->mode_info_block)); mode_info_valid = 1; + return 0; }
static u8 vbe_set_mode(vbe_mode_info_t * mi) { printk(BIOS_DEBUG, "VBE: Setting VESA mode %04x\n", mi->video_mode); - // request linear framebuffer mode + /* request linear framebuffer mode */ mi->video_mode |= (1 << 14); - // request clearing of framebuffer + /* request clearing of framebuffer */ mi->video_mode &= ~(1 << 15); realmode_interrupt(0x10, VESA_SET_MODE, mi->video_mode, 0x0000, 0x0000, 0x0000, 0x0000); + if (vbe_check_for_failure()) + die("\nError: In %s function\n", __func__); return 0; }
@@ -253,6 +342,7 @@ void vbe_set_graphics(void) { mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE; + vbe_get_mode_info(&mode_info); unsigned char *framebuffer = (unsigned char *)mode_info.vesa.phys_base_ptr; @@ -288,6 +378,8 @@ delay(2); realmode_interrupt(0x10, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000); + if (vbe_check_for_failure()) + die("\nError: In %s function\n", __func__); }
int fill_lb_framebuffer(struct lb_framebuffer *framebuffer) diff --git a/src/device/oprom/realmode/x86_asm.S b/src/device/oprom/realmode/x86_asm.S index 87348cd..ed3f897 100644 --- a/src/device/oprom/realmode/x86_asm.S +++ b/src/device/oprom/realmode/x86_asm.S @@ -291,6 +291,13 @@ __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_BASE + /* Ok, the job is done, now go back to protected mode coreboot */ movl %cr0, %eax orl $PE, %eax diff --git a/src/include/vbe.h b/src/include/vbe.h index 2c40d05..fea55f5 100644 --- a/src/include/vbe.h +++ b/src/include/vbe.h @@ -14,6 +14,10 @@ #define VBE_H
#include <boot/coreboot_tables.h> + +/* Lets hope we never have more than 256 video modes. */ +#define MAX_VBE_FRAMEBUFFER_MODE 256 + // these structs are for input from and output to OF typedef struct { u8 display_type; // 0 = NONE, 1 = analog, 2 = digital @@ -41,10 +45,9 @@ u16 version; u8 *oem_string_ptr; u32 capabilities; - u16 video_mode_list[256]; // lets hope we never have more than - // 256 video modes... + u16 video_mode_list[MAX_VBE_FRAMEBUFFER_MODE]; u16 total_memory; -} vbe_info_t; +} __packed vbe_info_t;
typedef struct { u16 mode_attributes; // 00