Jérémy Compostella has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/77231?usp=email )
Change subject: vendorcode/intel: Add uGOP support ......................................................................
vendorcode/intel: Add uGOP support
This patch introduces code to load and execute uGOP (microGOP). uGOP is a pre-memory Pre-EFI Initialization Module (PEIM) capable of bringing graphics in VGA legacy mode. This a version of the Intel Graphics PEIM driver usually included in FSP silicon and generally referred as the GOP (Graphics Output Protocol) driver. Compared to GOP, uGOP is designed to run in pre-memory environment and therefor can be use to provide on screen information in pre-memory coreboot stages.
uGOP dependency to the PEI environment is limited to: 1. InstallPpi() to install uGOP interfaces 2. LocatePpi() to find optinal protocols 3. AllocatePool() to perform some dynamic memory allocation 4. CreateHob() and GetHobList() to handle global variables 5. ReportStatusCode() to report debug information
These services are implemented in a very simple fashion in pei.c.
pei.c also installs the PEI services pointer in the architecture size word immediately preceding the Interrupt Descriptor Table (IDT) to comply with Platform Initialization (PI) specification 5.4 PEI Services Table Retrieval.
This patch introduces the `CONFIG_UGOP_EARLY_GRAPHICS' boolean configuration flag to enable this feature along with the following additional settings: - CONFIG_UGOP_FILE: uGOP PEIM binary path and filename - CONFIG_UGOP_CBFS: The filename of the uGOP PEIM binary in CBFS. - CONFIG_UGOP_ALIGNMENT: uGOP binary alignment in CBFS - CONFIG_UGOP_LIMIT_TO_REGIONS: To restrict uGOP to certain regions. This options can be used to restrict the regions in which the uGOP PEIM binary is included. For instance, it can be used to exclude uGOP support in WP_RO region. - CONFIG_UGOP_REGIONS: This options specifies in which region(s) the uGOP PEIM binary should be included. Example: FW_MAIN_A,FW_MAIN_B
BUG=b:279173035 TEST=If CONFIG_UGOP_EARLY_GRAPHICS is set to y, ugop.c and pei.c are compiled and the ugop.efi is included in CBFS.
Change-Id: I66ae5f1948474330bfa41c42cda7cc0738f7b9cd Signed-off-by: Jeremy Compostella jeremy.compostella@intel.com --- A Documentation/soc/intel/ugop/code-flow.svg A Documentation/soc/intel/ugop/ugop.md M src/vendorcode/intel/Kconfig M src/vendorcode/intel/Makefile.inc A src/vendorcode/intel/ugop/Kconfig A src/vendorcode/intel/ugop/Makefile.inc A src/vendorcode/intel/ugop/pei.c A src/vendorcode/intel/ugop/pei.h A src/vendorcode/intel/ugop/ugop.c A src/vendorcode/intel/ugop/ugop.h 10 files changed, 749 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/31/77231/1
diff --git a/Documentation/soc/intel/ugop/code-flow.svg b/Documentation/soc/intel/ugop/code-flow.svg new file mode 100644 index 0000000..448e508 --- /dev/null +++ b/Documentation/soc/intel/ugop/code-flow.svg @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="1616px" preserveAspectRatio="none" style="width:1222px;height:1616px;background:#FFFFFF;" version="1.1" viewBox="0 0 1222 1616" width="1222px" zoomAndPan="magnify"><defs/><g><rect fill="#00C7FD" height="1392.1339" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="163" y="62.6879"/><rect fill="#00C7FD" height="54.1879" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="168" y="1196.5702"/><rect fill="#00C7FD" height="983.3186" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="488" y="101.3758"/><rect fill="#00C7FD" height="25" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="493" y="361.8153"/><rect fill="#00C7FD" height="25" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="493" y="448.5032"/><rect fill="#00C7FD" height="25" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="493" y="789.9428"/><rect fill="#00C7FD" height="141.3758" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="488" y="1304.446"/><rect fill="#00C7FD" height="159.0637" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="148.0637"/><rect fill="#00C7FD" height="54.1879" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="743" y="202.7516"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="579.879"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="640.5669"/><rect fill="#00C7FD" height="17" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="718.2549"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="921.3186"/><rect fill="#00C7FD" height="17" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="1414.8218"/><rect fill="#005500" height="138.3758" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1078" y="530.1911"/><rect fill="#005500" height="77.6879" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1078" y="871.6307"/><rect fill="#005500" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1078" y="1351.1339"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1167" y="996.0065"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1167" y="1056.6944"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1167" y="1131.3823"/><line style="stroke:#00C7FD;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="168" x2="168" y1="52.6879" y2="1463.8218"/><line style="stroke:#00C7FD;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="493" x2="493" y1="52.6879" y2="1463.8218"/><line style="stroke:#00C7FD;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="742.5" x2="742.5" y1="52.6879" y2="1463.8218"/><line style="stroke:#005500;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="1083" x2="1083" y1="52.6879" y2="1463.8218"/><line style="stroke:#00C7FD;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="1172" x2="1172" y1="52.6879" y2="1463.8218"/><rect fill="#2872C5" height="46.6879" rx="2.5" ry="2.5" style="stroke:#2872C5;stroke-width:0.5;" width="198" x="69" y="5"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="184" x="76" y="37.6559">soc/romstage.c</text><rect fill="#2872C5" height="46.6879" rx="2.5" ry="2.5" style="stroke:#2872C5;stroke-width:0.5;" width="198" x="69" y="1462.8218"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="184" x="76" y="1495.4777">soc/romstage.c</text><rect fill="#2872C5" height="46.6879" rx="2.5" ry="2.5" style="stroke:#2872C5;stroke-width:0.5;" width="246" x="370" y="5"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="232" x="377" y="37.6559">vendorcode/ugop.c</text><rect fill="#2872C5" height="46.6879" rx="2.5" ry="2.5" style="stroke:#2872C5;stroke-width:0.5;" width="246" x="370" y="1462.8218"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="232" x="377" y="1495.4777">vendorcode/ugop.c</text><rect fill="#2872C5" height="46.6879" rx="2.5" ry="2.5" style="stroke:#2872C5;stroke-width:0.5;" width="221" x="632.5" y="5"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="207" x="639.5" y="37.6559">vendorcode/pei.c</text><rect fill="#2872C5" height="46.6879" rx="2.5" ry="2.5" style="stroke:#2872C5;stroke-width:0.5;" width="221" x="632.5" y="1462.8218"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="207" x="639.5" y="1495.4777">vendorcode/pei.c</text><rect fill="#005500" height="46.6879" rx="2.5" ry="2.5" style="stroke:#005500;stroke-width:0.5;" width="82" x="1042" y="5"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="68" x="1049" y="37.6559">µGOP</text><rect fill="#005500" height="46.6879" rx="2.5" ry="2.5" style="stroke:#005500;stroke-width:0.5;" width="82" x="1042" y="1462.8218"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="68" x="1049" y="1495.4777">µGOP</text><rect fill="#2872C5" height="46.6879" rx="2.5" ry="2.5" style="stroke:#2872C5;stroke-width:0.5;" width="76" x="1134" y="5"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="62" x="1141" y="37.6559">vga.c</text><rect fill="#2872C5" height="46.6879" rx="2.5" ry="2.5" style="stroke:#2872C5;stroke-width:0.5;" width="76" x="1134" y="1462.8218"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="62" x="1141" y="1495.4777">vga.c</text><rect fill="#00C7FD" height="1392.1339" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="163" y="62.6879"/><rect fill="#00C7FD" height="54.1879" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="168" y="1196.5702"/><rect fill="#00C7FD" height="983.3186" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="488" y="101.3758"/><rect fill="#00C7FD" height="25" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="493" y="361.8153"/><rect fill="#00C7FD" height="25" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="493" y="448.5032"/><rect fill="#00C7FD" height="25" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="493" y="789.9428"/><rect fill="#00C7FD" height="141.3758" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="488" y="1304.446"/><rect fill="#00C7FD" height="159.0637" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="148.0637"/><rect fill="#00C7FD" height="54.1879" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="743" y="202.7516"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="579.879"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="640.5669"/><rect fill="#00C7FD" height="17" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="718.2549"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="921.3186"/><rect fill="#00C7FD" height="17" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="738" y="1414.8218"/><rect fill="#005500" height="138.3758" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1078" y="530.1911"/><rect fill="#005500" height="77.6879" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1078" y="871.6307"/><rect fill="#005500" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1078" y="1351.1339"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1167" y="996.0065"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1167" y="1056.6944"/><rect fill="#00C7FD" height="14" style="stroke:#00C7FD;stroke-width:1.0;" width="10" x="1167" y="1131.3823"/><polygon fill="#000000" points="476,97.3758,486,101.3758,476,105.3758,480,101.3758" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="173" x2="482" y1="101.3758" y2="101.3758"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="291" x="180" y="92.3438">ugop_early_graphics_init()</text><polygon fill="#000000" points="726,144.0637,736,148.0637,726,152.0637,730,148.0637" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="732" y1="148.0637" y2="148.0637"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="96" x="625" y="139.0317">pei_init()</text><line style="stroke:#000000;stroke-width:1.0;" x1="748" x2="795" y1="189.7516" y2="189.7516"/><line style="stroke:#000000;stroke-width:1.0;" x1="795" x2="795" y1="189.7516" y2="202.7516"/><line style="stroke:#000000;stroke-width:1.0;" x1="754" x2="795" y1="202.7516" y2="202.7516"/><polygon fill="#000000" points="764,198.7516,754,202.7516,764,206.7516,760,202.7516" style="stroke:#000000;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="232" x="760" y="180.7196">set_pei_services_idt()</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="753" x2="795" y1="255.9395" y2="255.9395"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="795" x2="795" y1="255.9395" y2="268.9395"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="748" x2="795" y1="268.9395" y2="268.9395"/><polygon fill="#000000" points="758,264.9395,748,268.9395,758,272.9395,754,268.9395" style="stroke:#000000;stroke-width:1.0;"/><path d="M803,220.7516 L803,295.7516 L1175,295.7516 L1175,230.7516 L1165,220.7516 L803,220.7516 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1165,220.7516 L1165,230.7516 L1175,230.7516 L1165,220.7516 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="322" x="809" y="251.4075">Install a temporary IDT table</text><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="351" x="809" y="284.0954">including a PEI services pointer.</text><polygon fill="#000000" points="509,303.1274,499,307.1274,509,311.1274,505,307.1274" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="742" y1="307.1274" y2="307.1274"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="545" y1="348.8153" y2="348.8153"/><line style="stroke:#000000;stroke-width:1.0;" x1="545" x2="545" y1="348.8153" y2="361.8153"/><line style="stroke:#000000;stroke-width:1.0;" x1="504" x2="545" y1="361.8153" y2="361.8153"/><polygon fill="#000000" points="514,357.8153,504,361.8153,514,365.8153,510,361.8153" style="stroke:#000000;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="130" x="510" y="339.7834">load_ugop()</text><path d="M65,323.6274 L65,365.6274 L483,365.6274 L483,333.6274 L473,323.6274 L65,323.6274 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M473,323.6274 L473,333.6274 L483,333.6274 L473,323.6274 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="397" x="71" y="354.2834">Load the ugop.efi binary from CBFS</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="545" y1="385.8153" y2="385.8153"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="545" x2="545" y1="385.8153" y2="398.8153"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="498" x2="545" y1="398.8153" y2="398.8153"/><polygon fill="#000000" points="508,394.8153,498,398.8153,508,402.8153,504,398.8153" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="545" y1="435.5032" y2="435.5032"/><line style="stroke:#000000;stroke-width:1.0;" x1="545" x2="545" y1="435.5032" y2="448.5032"/><line style="stroke:#000000;stroke-width:1.0;" x1="504" x2="545" y1="448.5032" y2="448.5032"/><polygon fill="#000000" points="514,444.5032,504,448.5032,514,452.5032,510,448.5032" style="stroke:#000000;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="96" x="510" y="426.4713">igd_init()</text><path d="M110,410.3153 L110,452.3153 L483,452.3153 L483,420.3153 L473,410.3153 L110,410.3153 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M473,410.3153 L473,420.3153 L483,420.3153 L473,410.3153 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="352" x="116" y="440.9713">Perform minimal IGD PCI Setup</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="545" y1="472.5032" y2="472.5032"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="545" x2="545" y1="472.5032" y2="485.5032"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="498" x2="545" y1="485.5032" y2="485.5032"/><polygon fill="#000000" points="508,481.5032,498,485.5032,508,489.5032,504,485.5032" style="stroke:#000000;stroke-width:1.0;"/><polygon fill="#000000" points="1066,526.1911,1076,530.1911,1066,534.1911,1070,530.1911" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="1072" y1="530.1911" y2="530.1911"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="250" x="811" y="521.1592">entry(, pei_services **)</text><path d="M157,493.5032 L157,535.5032 L483,535.5032 L483,503.5032 L473,493.5032 L157,493.5032 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M473,493.5032 L473,503.5032 L483,503.5032 L473,493.5032 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="305" x="163" y="524.1592">Call µGOP PEIM entry point</text><polygon fill="#000000" points="759,575.879,749,579.879,759,583.879,755,579.879" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="753" x2="1077" y1="579.879" y2="579.879"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="139" x="765" y="570.8471">create_hob()</text><polygon fill="#000000" points="1066,589.879,1076,593.879,1066,597.879,1070,593.879" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="743" x2="1072" y1="593.879" y2="593.879"/><polygon fill="#000000" points="759,636.5669,749,640.5669,759,644.5669,755,640.5669" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="753" x2="1077" y1="640.5669" y2="640.5669"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="128" x="765" y="631.535">install_ppi()</text><polygon fill="#000000" points="1066,650.5669,1076,654.5669,1066,658.5669,1070,654.5669" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="743" x2="1072" y1="654.5669" y2="654.5669"/><polygon fill="#000000" points="509,664.5669,499,668.5669,509,672.5669,505,668.5669" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="1082" y1="668.5669" y2="668.5669"/><polygon fill="#000000" points="726,714.2549,736,718.2549,726,722.2549,730,718.2549" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="732" y1="718.2549" y2="718.2549"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="128" x="593" y="709.2229">locate_ppi()</text><path d="M114,681.5669 L114,723.5669 L483,723.5669 L483,691.5669 L473,681.5669 L114,681.5669 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M473,681.5669 L473,691.5669 L483,691.5669 L473,681.5669 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="348" x="120" y="712.2229">Find µGOP installed PPI pointer</text><polygon fill="#000000" points="509,731.2549,499,735.2549,509,739.2549,505,735.2549" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="742" y1="735.2549" y2="735.2549"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="545" y1="776.9428" y2="776.9428"/><line style="stroke:#000000;stroke-width:1.0;" x1="545" x2="545" y1="776.9428" y2="789.9428"/><line style="stroke:#000000;stroke-width:1.0;" x1="504" x2="545" y1="789.9428" y2="789.9428"/><polygon fill="#000000" points="514,785.9428,504,789.9428,514,793.9428,510,789.9428" style="stroke:#000000;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="226" x="510" y="767.9108">Load VBT from CBFS</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="545" y1="813.9428" y2="813.9428"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="545" x2="545" y1="813.9428" y2="826.9428"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="498" x2="545" y1="826.9428" y2="826.9428"/><polygon fill="#000000" points="508,822.9428,498,826.9428,508,830.9428,504,826.9428" style="stroke:#000000;stroke-width:1.0;"/><polygon fill="#000000" points="1066,867.6307,1076,871.6307,1066,875.6307,1070,871.6307" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="1072" y1="871.6307" y2="871.6307"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="88" x="973" y="862.5987">init(vbt)</text><path d="M5,834.9428 L5,876.9428 L483,876.9428 L483,844.9428 L473,834.9428 L5,834.9428 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M473,834.9428 L473,844.9428 L483,844.9428 L473,834.9428 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="457" x="11" y="865.5987">Perform graphic and display initialization</text><polygon fill="#000000" points="759,917.3186,749,921.3186,759,925.3186,755,921.3186" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="753" x2="1077" y1="921.3186" y2="921.3186"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="311" x="765" y="912.2866">get_hob_list(), locate_ppi()...</text><polygon fill="#000000" points="1066,931.3186,1076,935.3186,1066,939.3186,1070,935.3186" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="743" x2="1072" y1="935.3186" y2="935.3186"/><polygon fill="#000000" points="509,945.3186,499,949.3186,509,953.3186,505,949.3186" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="1082" y1="949.3186" y2="949.3186"/><polygon fill="#000000" points="1155,992.0065,1165,996.0065,1155,1000.0065,1159,996.0065" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="1161" y1="996.0065" y2="996.0065"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="132" x="1018" y="986.9745">vga_io_init()</text><polygon fill="#000000" points="509,1006.0065,499,1010.0065,509,1014.0065,505,1010.0065" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="1171" y1="1010.0065" y2="1010.0065"/><polygon fill="#000000" points="1155,1052.6944,1165,1056.6944,1155,1060.6944,1159,1056.6944" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="1161" y1="1056.6944" y2="1056.6944"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="221" x="929" y="1047.6624">vga_textmode_init()</text><polygon fill="#000000" points="509,1066.6944,499,1070.6944,509,1074.6944,505,1070.6944" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="1171" y1="1070.6944" y2="1070.6944"/><polygon fill="#000000" points="184,1080.6944,174,1084.6944,184,1088.6944,180,1084.6944" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="492" y1="1084.6944" y2="1084.6944"/><polygon fill="#000000" points="1155,1127.3823,1165,1131.3823,1155,1135.3823,1159,1131.3823" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="173" x2="1161" y1="1131.3823" y2="1131.3823"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="483" x="667" y="1122.3503">vga_write_text("Sign-of-Life text message")</text><polygon fill="#000000" points="184,1141.3823,174,1145.3823,184,1149.3823,180,1145.3823" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="1171" y1="1145.3823" y2="1145.3823"/><line style="stroke:#000000;stroke-width:1.0;" x1="173" x2="220" y1="1183.5702" y2="1183.5702"/><line style="stroke:#000000;stroke-width:1.0;" x1="220" x2="220" y1="1183.5702" y2="1196.5702"/><line style="stroke:#000000;stroke-width:1.0;" x1="179" x2="220" y1="1196.5702" y2="1196.5702"/><polygon fill="#000000" points="189,1192.5702,179,1196.5702,189,1200.5702,185,1196.5702" style="stroke:#000000;stroke-width:1.0;"/><path d="M228,1158.3823 L228,1233.3823 L592,1233.3823 L592,1168.3823 L582,1158.3823 L228,1158.3823 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M582,1158.3823 L582,1168.3823 L592,1168.3823 L582,1158.3823 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="264" x="234" y="1189.0382">Perform long operation</text><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="343" x="234" y="1221.7261">(CSME update, MRC training...)</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="220" y1="1249.7581" y2="1249.7581"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="220" x2="220" y1="1249.7581" y2="1262.7581"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="173" x2="220" y1="1262.7581" y2="1262.7581"/><polygon fill="#000000" points="183,1258.7581,173,1262.7581,183,1266.7581,179,1262.7581" style="stroke:#000000;stroke-width:1.0;"/><polygon fill="#000000" points="476,1300.446,486,1304.446,476,1308.446,480,1304.446" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="173" x2="482" y1="1304.446" y2="1304.446"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="296" x="175" y="1295.414">ugop_early_graphics_exit()</text><polygon fill="#000000" points="1066,1347.1339,1076,1351.1339,1066,1355.1339,1070,1351.1339" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="1072" y1="1351.1339" y2="1351.1339"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="56" x="1005" y="1342.1019">exit()</text><polygon fill="#000000" points="509,1361.1339,499,1365.1339,509,1369.1339,505,1365.1339" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="1082" y1="1365.1339" y2="1365.1339"/><polygon fill="#000000" points="726,1410.8218,736,1414.8218,726,1418.8218,730,1414.8218" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;" x1="498" x2="732" y1="1414.8218" y2="1414.8218"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="101" x="620" y="1405.7898">pei_exit()</text><path d="M753,1378.1339 L753,1420.1339 L1044,1420.1339 L1044,1388.1339 L1034,1378.1339 L753,1378.1339 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M1034,1378.1339 L1034,1388.1339 L1044,1388.1339 L1034,1378.1339 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="24" lengthAdjust="spacing" textLength="270" x="759" y="1408.7898">Uninstall temporary IDT</text><polygon fill="#000000" points="509,1427.8218,499,1431.8218,509,1435.8218,505,1431.8218" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="503" x2="742" y1="1431.8218" y2="1431.8218"/><polygon fill="#000000" points="184,1441.8218,174,1445.8218,184,1449.8218,180,1445.8218" style="stroke:#000000;stroke-width:1.0;"/><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="492" y1="1445.8218" y2="1445.8218"/><rect fill="#FFFFFF" height="81.3758" rx="7.5" ry="7.5" style="stroke:#FFFFFF;stroke-width:1.0;" width="205" x="1001" y="1519.5097"/><rect fill="#2872C5" height="32.6879" style="stroke:none;stroke-width:1.0;" width="193" x="1007" y="1527.5097"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="172" x="1021" y="1553.1656">coreboot code</text><rect fill="#005500" height="32.6879" style="stroke:none;stroke-width:1.0;" width="193" x="1007" y="1560.1976"/><text fill="#FFFFFF" font-family="sans-serif" font-size="24" font-weight="bold" lengthAdjust="spacing" textLength="131" x="1021" y="1585.8535">µGOP code</text><line style="stroke:#FFFFFF;stroke-width:1.0;" x1="1007" x2="1200" y1="1527.5097" y2="1527.5097"/><line style="stroke:#FFFFFF;stroke-width:1.0;" x1="1007" x2="1200" y1="1560.1976" y2="1560.1976"/><line style="stroke:#FFFFFF;stroke-width:1.0;" x1="1007" x2="1200" y1="1592.8855" y2="1592.8855"/><line style="stroke:#FFFFFF;stroke-width:1.0;" x1="1007" x2="1007" y1="1527.5097" y2="1592.8855"/><line style="stroke:#FFFFFF;stroke-width:1.0;" x1="1200" x2="1200" y1="1527.5097" y2="1592.8855"/><!--MD5=[c73244932b3f4ee4c66f065050495b49] +@startuml +!include ../code-flow.iuml +@enduml + +@startuml +skinparam shadowing false +skinparam defaultFontSize 24 + +skinparam activity { + ArrowColor Black + BackgroundColor White + BackgroundColor<< Begin >> White + BorderColor #2872c5 +} + +skinparam legend { + BackgroundColor White + BackgroundColor<< Begin >> White + BorderColor White + FontColor White + FontSize 24 + FontStyle Bold +} + +skinparam class { + BorderColor black + ArrowColor #2872c5 + BackgroundColor White + FontColor #2872c5 +} + +skinparam sequence { + ArrowColor Black + BackgroundColor White + BackgroundColor<< Begin >> White + BorderColor #2872c5 + + ActorBorderColor #2872c5 + ActorBackgroundColor None + LifeLineBorderColor #00c7fd + LifeLineBackgroundColor #00c7fd + + ParticipantBorderColor #2872c5 + ParticipantBackgroundColor #2872c5 + ParticipantFontColor White + ParticipantFontStyle Bold +} +<style> + sequenceDiagram { + .uGOP { + LineColor #005500 + BackgroundColor #005500 + } + } +} +</style> +legend right + |<#2872c5> coreboot code | + |<#005500> µGOP code | +endlegend +autoactivate on +skinparam SequenceMessageAlign reverseDirection +activate "soc/romstage.c" +"soc/romstage.c" -> "vendorcode/ugop.c": ugop_early_graphics_init() +"vendorcode/ugop.c" -> "vendorcode/pei.c": pei_init() +"vendorcode/pei.c" -> "vendorcode/pei.c": set_pei_services_idt() +return +note right + Install a temporary IDT table + including a PEI services pointer. +end note +return +"vendorcode/ugop.c" -> "vendorcode/ugop.c": load_ugop() +note left + Load the ugop.efi binary from CBFS +end note +return +"vendorcode/ugop.c" -> "vendorcode/ugop.c": igd_init() +note left + Perform minimal IGD PCI Setup +end note +return +participant "µGOP" <<uGOP>> +"vendorcode/ugop.c" -> "µGOP" #005500: entry(, pei_services **) +note left + Call µGOP PEIM entry point +end note +"µGOP" -> "vendorcode/pei.c": create_hob() +return +"µGOP" -> "vendorcode/pei.c": install_ppi() +return +return +"vendorcode/ugop.c" -> "vendorcode/pei.c": locate_ppi() +note left + Find µGOP installed PPI pointer +end note +return +"vendorcode/ugop.c" -> "vendorcode/ugop.c": Load VBT from CBFS +return +"vendorcode/ugop.c" -> "µGOP" #005500: init(vbt) +note left + Perform graphic and display initialization +end note +"µGOP" -> "vendorcode/pei.c": get_hob_list(), locate_ppi()... +return +return +"vendorcode/ugop.c" -> "vga.c": vga_io_init() +return +"vendorcode/ugop.c" -> "vga.c": vga_textmode_init() +return +return +"soc/romstage.c" -> "vga.c": vga_write_text("Sign-of-Life text message") +return +"soc/romstage.c" -> "soc/romstage.c" +note right + Perform long operation + (CSME update, MRC training...) +end note +return +"soc/romstage.c" -> "vendorcode/ugop.c": ugop_early_graphics_exit() +"vendorcode/ugop.c" -> "µGOP" #005500: exit() +return +"vendorcode/ugop.c" -> "vendorcode/pei.c": pei_exit() +note right + Uninstall temporary IDT +end note +return +return +@enduml + +PlantUML version 1.2022.5(Sat Apr 30 03:55:52 MST 2022) +(LGPL source distribution) +Java Runtime: OpenJDK Runtime Environment +JVM: OpenJDK 64-Bit Server VM +Default Encoding: UTF-8 +Language: en +Country: US +--></g></svg> \ No newline at end of file diff --git a/Documentation/soc/intel/ugop/ugop.md b/Documentation/soc/intel/ugop/ugop.md new file mode 100644 index 0000000..1c3c03d --- /dev/null +++ b/Documentation/soc/intel/ugop/ugop.md @@ -0,0 +1,78 @@ +uGOP is a Pre-EFI Initialization Module indented to be used for pre-memory +stages Sign-of-Life use-cases. This driver performs minimal graphics +initialization allowing legacy VGA operations. + + +# Specification + +The uGOP PEIM provides the following PEIM-to-PEIM protocol under the +`31a4622d-0e21-40a2-80db-c44208fce1b5` GUID. + + #define PEI_PREMEM_GRAPHICS_PPI_GUID \ + { \ + 0x31a4622d, 0x0e21, 0x40a2, 0x80, 0xdb, 0xc4, 0x42, 0x08, 0xfc, 0xe1, 0xb5 \ + }; + +The protocol is composed of three fields. + + struct { + UINT32 Version; + PREMEM_PEI_GRAPHICS_INIT PreMemGraphicsPpiInit; + PREMEM_PEI_GRAPHICS_EXIT PreMemGraphicsPpiExit; + } PEI_MICRO_GRAPHICS_PPI; + +1. The current `Version` is `0x00010000`. Where the upper 16 bits represent the + major (1) and the lower 16 bits represent the minor number. +2. `PreMemGraphicsPpiInit()` + + typedef + EFI_STATUS + (EFIAPI *PREMEM_PEI_GRAPHICS_INIT) ( + IN VOID *Vbt + ); + + The `PreMemGraphicsPpiInit()` should be supplied with a pointer to the Video + BIOS Table. +3. `PreMemGraphicsPpiExit()` does not take any parameters. This function must + be called to disable VGA graphics configuration once not necessary + anymore. Not performing this operation may lead to undesirable behaviour + when other graphics stack starts (GOP in FSP-S or Operating System driver). + + +# coreboot support for uGOP + +uGOP depends on a limited set of PEI services which are implemented in coreboot. + +1. `InstallPpi()` to install the PEIM Graphics PPI +2. `LocatePpi()` to access PEIM-to-PEIM Interface (PPI) Dependencies +3. `AllocatePool()` to dynamically allocate memory to handle internal data + structure such as display information … +4. `GetHobList()` and `CreateHob()` to access Hand Off Blocks (HOB) holding + runtime data +5. `ReportStatusCode()` to report debug information which coreboot prints using + `printk`. + + +## PEI services pointer + +uGOP expects to find the PEI services pointer in the architecture size word +immediately preceding the Interrupt Descriptor Table (IDT) (cf. [Platform +Initialization (PI) +Specification](https://uefi.org/sites/default/files/resources/PI_Spec_1_6.pdf) +**5.4 PEI Services Table Retrieval**). Since coreboot x86 exception module +already sets up the IDT and as we do not want to disrupt this configuration a +copy of the IDT is created. However, this copy include an extra architecture +size word preceding the table to store the PEI services pointer. + + +## Portable Executable Relocation + +As we need to execute the uGOP binary in place, we need to perform a relocation +operation of the Portable Executable binary. Since memory space is limited in +the pre-memory stages, this relocation is performed statically during the +firmware stitching operation. + + +# Code flow + +![img](./code-flow.svg) diff --git a/src/vendorcode/intel/Kconfig b/src/vendorcode/intel/Kconfig index 8af7eb8..4552a07 100644 --- a/src/vendorcode/intel/Kconfig +++ b/src/vendorcode/intel/Kconfig @@ -1,5 +1,7 @@ ## SPDX-License-Identifier: GPL-2.0-only
+source "src/vendorcode/intel/ugop/Kconfig" + config UDK_BASE def_bool n
diff --git a/src/vendorcode/intel/Makefile.inc b/src/vendorcode/intel/Makefile.inc index c4e21e3..4fa4e6e 100644 --- a/src/vendorcode/intel/Makefile.inc +++ b/src/vendorcode/intel/Makefile.inc @@ -1,4 +1,5 @@ ## SPDX-License-Identifier: GPL-2.0-only +subdirs-y += ugop
ifeq ($(CONFIG_UEFI_2_4_BINDING),y) # ProccessorBind.h provided in Ia32 directory. Types are derived from ia32. diff --git a/src/vendorcode/intel/ugop/Kconfig b/src/vendorcode/intel/ugop/Kconfig new file mode 100644 index 0000000..62843dc --- /dev/null +++ b/src/vendorcode/intel/ugop/Kconfig @@ -0,0 +1,49 @@ +## SPDX-License-Identifier: GPL-2.0-only + +config UGOP_EARLY_GRAPHICS + bool "Enable uGOP early graphics support" + default n + help + uGOP (micro Graphics Output Protocol driver) is a Pre-EFI + Initialization Module driver capable of performing legacy + VGA initialization in pre-memory stages. When this setting + is set, the uGOP binary is added to CBFS and some PEIM + wrapping code are included. + +if UGOP_EARLY_GRAPHICS +config UGOP_FILE + string "uGOP PEIM binary path and filename" + help + The path and filename of uGOP PEIM binary. + +config UGOP_CBFS + string + default "ugop.efi" + help + The filename of the uGOP PEIM binary in CBFS. + +config UGOP_ALIGNMENT + int + default 32 + help + uGOP binary alignment in CBFS + +config UGOP_LIMIT_TO_REGIONS + bool "Restrict uGOP to certain regions" + help + This options can be used to restrict the regions in which + the uGOP PEIM binary is included. For instance, it can be + used to exclude uGOP support in WP_RO region. + +config UGOP_REGIONS + string + depends on UGOP_LIMIT_TO_REGIONS + help + This options specifies in which region(s) the uGOP PEIM + binary should be included. + + Example: FW_MAIN_A,FW_MAIN_B + +config VBT_CBFS_COMPRESSION + default n if !UGOP_LIMIT_TO_REGIONS +endif # UGOP_EARLY_GRAPHICS diff --git a/src/vendorcode/intel/ugop/Makefile.inc b/src/vendorcode/intel/ugop/Makefile.inc new file mode 100644 index 0000000..e4b2466 --- /dev/null +++ b/src/vendorcode/intel/ugop/Makefile.inc @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only + +CPPFLAGS_common += -I$(src)/vendorcode/intel/ugop + +romstage-$(CONFIG_UGOP_EARLY_GRAPHICS) += pei.c +romstage-$(CONFIG_UGOP_EARLY_GRAPHICS) += ugop.c + +ifeq ($(CONFIG_UGOP_EARLY_GRAPHICS),y) +UGOP_CBFS = $(call strip_quotes,$(CONFIG_UGOP_CBFS)) +cbfs-files-y += $(UGOP_CBFS) +ifeq ($(CONFIG_UGOP_LIMIT_TO_REGIONS),y) +regions-for-file-$(UGOP_CBFS) = $(call strip_quotes,$(CONFIG_UGOP_REGIONS)) +$(foreach region, $(subst $(comma),$(spc),$(regions-for-file-$(UGOP_CBFS))), \ + $(eval vbt.bin-$(region)-compression := none)) +endif # CONFIG_UGOP_LIMIT_TO_REGIONS +$(UGOP_CBFS)-file := $(call strip_quotes,$(CONFIG_UGOP_FILE)) +$(UGOP_CBFS)-type := efi +$(UGOP_CBFS)-options := --xip +$(UGOP_CBFS)-align := $(CONFIG_UGOP_ALIGNMENT) +endif # CONFIG_UGOP_EARLY_GRAPHICS diff --git a/src/vendorcode/intel/ugop/pei.c b/src/vendorcode/intel/ugop/pei.c new file mode 100644 index 0000000..789ee90 --- /dev/null +++ b/src/vendorcode/intel/ugop/pei.c @@ -0,0 +1,291 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * This file provides a minimal Pre-EFI Initialization implementation designed + * to accommodate the limited need of the uGOP driver. + * + * The implementation is kept as minimalist as possible as it intends to be used + * in pre-memory stages. + */ + +#include <console/console.h> +#include <fsp/fsp_debug_event.h> +#include <Guid/StatusCodeDataTypeDebug.h> +#include <stdint.h> +#include <string.h> + +#include "pei.h" + +#define PEI_PPI_SIZE 4 +#define PEI_ALLOC_POOL_SIZE 6144 +#define PEI_HOB_SIZE 512 + +static const EFI_PEI_PPI_DESCRIPTOR ppi_end_of_list = { + .Flags = EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST +}; +static EFI_PEI_PPI_DESCRIPTOR ppis[PEI_PPI_SIZE]; +static size_t ppi_current; + +static EFIAPI EFI_STATUS install_ppi(const EFI_PEI_SERVICES **PeiServices, + const EFI_PEI_PPI_DESCRIPTOR *PpiList) +{ + for (;; PpiList++) { + if (ppi_current + 1 == ARRAY_SIZE(ppis)) + return EFI_OUT_OF_RESOURCES; + + memcpy(&ppis[ppi_current], PpiList, sizeof(*PpiList)); + ppi_current++; + + if (PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) + break; + } + + return EFI_SUCCESS; +} + +static EFIAPI EFI_STATUS locate_ppi(const EFI_PEI_SERVICES **PeiServices, + const EFI_GUID *Guid, + UINTN Instance, + EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor, + void **Ppi) +{ + size_t i, instance; + + for (i = 0, instance = 0; i < ppi_current; i++) { + if (memcmp(Guid, ppis[i].Guid, sizeof(*Guid))) + continue; + if (instance < Instance) { + instance++; + continue; + } + if (PpiDescriptor) + *PpiDescriptor = &ppis[i]; + *Ppi = ppis[i].Ppi; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +static EFIAPI EFI_STATUS allocate_pool(const EFI_PEI_SERVICES **PeiServices, + UINTN Size, + VOID **Buffer) +{ + static __aligned(8) char pool[PEI_ALLOC_POOL_SIZE]; + static size_t current; + + if (current + Size >= sizeof(pool)) { + printk(BIOS_ERR, "PEI: Out of memory\n"); + return EFI_OUT_OF_RESOURCES; + } + + *Buffer = &pool[current]; + current = ALIGN_UP(current + Size, 8); + + return EFI_SUCCESS; +} + +static EFIAPI VOID copy_mem(VOID *Destination, + VOID *Source, + UINTN length) +{ + memcpy(Destination, Source, length); +} + +static EFIAPI VOID set_mem(VOID *Buffer, + UINTN Size, + UINT8 Value) +{ + memset(Buffer, Value, Size); +} + +static const EFI_HOB_GENERIC_HEADER hob_end_of_list = { + .HobType = EFI_HOB_TYPE_END_OF_HOB_LIST +}; +static char hobs[PEI_HOB_SIZE]; + +static EFIAPI EFI_STATUS get_hob_list(const EFI_PEI_SERVICES **PeiServices, + VOID **HobList) +{ + *HobList = hobs; + return EFI_SUCCESS; +} + +static EFIAPI EFI_STATUS create_hob(const EFI_PEI_SERVICES **PeiServices, + UINT16 Type, + UINT16 Length, + void **Hob) +{ + static size_t current; + EFI_HOB_GENERIC_HEADER *hob; + size_t size = ALIGN_UP(Length, 8); + + if (current + size + sizeof(hob_end_of_list) > sizeof(hobs)) + return EFI_OUT_OF_RESOURCES; + + hob = (EFI_HOB_GENERIC_HEADER *)&hobs[current]; + hob->HobType = Type; + hob->HobLength = Length; + + current += size; + *Hob = hob; + + memcpy(&hobs[current], &hob_end_of_list, sizeof(hob_end_of_list)); + + return EFI_SUCCESS; +} + +/* This is the C-mapping of the data structure described in + EDK2 Guid/StatusCodeDataTypeDebug.h header file. */ +typedef struct { + uint32_t error_level; + uint8_t format_args[96]; + char format_string[0]; +} efi_status_code_data_debug; + +static EFIAPI EFI_STATUS report_status_code(const EFI_PEI_SERVICES **PeiServices, + EFI_STATUS_CODE_TYPE Type, + EFI_STATUS_CODE_VALUE Value, + UINT32 Instance, + const EFI_GUID *CallerId, + const EFI_STATUS_CODE_DATA *Data) +{ + const EFI_GUID status_code_guid = EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID; + efi_status_code_data_debug *debug_info; + + if (memcmp(&Data->Type, &status_code_guid, sizeof(status_code_guid))) + return EFI_SUCCESS; + + debug_info = (efi_status_code_data_debug *)(Data + 1); + printk(get_log_level(), "%s", debug_info->format_string); + + return EFI_SUCCESS; +} + +/* Since in the EFIAPI calling convention the caller clean the stack we can use + a unique function to handle all the unsupported PEI services. */ +static EFIAPI EFI_STATUS unsupported(void) +{ + printk(BIOS_ERR, "pei: Unsupported PEI service called\n"); + return EFI_UNSUPPORTED; +} + +const EFI_PEI_SERVICES PEI_SERVICES = { + .Hdr = { + .Signature = PEI_SERVICES_SIGNATURE, + .Revision = PEI_SERVICES_REVISION + }, + + .InstallPpi = install_ppi, + .LocatePpi = locate_ppi, + + .GetHobList = get_hob_list, + .CreateHob = create_hob, + + .AllocatePool = allocate_pool, + .CopyMem = copy_mem, + .SetMem = set_mem, + + .ReportStatusCode = report_status_code, + + /* + * Unsupported PEI services. + * + * The following services are not used by the current version of + * uGOP. We make them point to a default routine to detect missing + * service implementation with later version. + */ + .ReInstallPpi = (EFI_PEI_REINSTALL_PPI)unsupported, + .NotifyPpi = (EFI_PEI_NOTIFY_PPI)unsupported, + .GetBootMode = (EFI_PEI_GET_BOOT_MODE)unsupported, + .SetBootMode = (EFI_PEI_SET_BOOT_MODE)unsupported, + .FfsFindNextVolume = (EFI_PEI_FFS_FIND_NEXT_VOLUME2)unsupported, + .FfsFindNextFile = (EFI_PEI_FFS_FIND_NEXT_FILE2)unsupported, + .FfsFindSectionData = (EFI_PEI_FFS_FIND_SECTION_DATA2)unsupported, + .InstallPeiMemory = (EFI_PEI_INSTALL_PEI_MEMORY)unsupported, + .AllocatePages = (EFI_PEI_ALLOCATE_PAGES)unsupported, + .ResetSystem = (EFI_PEI_RESET_SYSTEM)unsupported, + .FfsFindFileByName = (EFI_PEI_FFS_FIND_BY_NAME)unsupported, + .FfsGetFileInfo = (EFI_PEI_FFS_GET_FILE_INFO)unsupported, + .FfsGetVolumeInfo = (EFI_PEI_FFS_GET_VOLUME_INFO)unsupported, + .RegisterForShadow = (EFI_PEI_REGISTER_FOR_SHADOW)unsupported, + .FindSectionData3 = (EFI_PEI_FFS_FIND_SECTION_DATA3)unsupported, + .FfsGetFileInfo2 = (EFI_PEI_FFS_GET_FILE_INFO2)unsupported, + .ResetSystem2 = (EFI_PEI_RESET2_SYSTEM)unsupported, + .FreePages = (EFI_PEI_FREE_PAGES)unsupported +}; + +static struct lidtarg { + uint16_t limit; +#if ENV_X86_32 + uint32_t base; +#else + uint64_t base; +#endif +} __packed lidtarg_backup; + +static struct idt_storage { + uintptr_t pei_services; + char idt[0]; +} *idt_storage; + +/* + * According to PI specification, on X86, and x64, the PEI services pointer is + * stored in the 4-bytes, respectively the 8-bytes, immediately preceding the + * Interrupt Descriptor Table. + */ +static EFI_STATUS set_pei_services_idt(const EFI_PEI_SERVICES **pei_services) +{ + EFI_STATUS ret; + struct lidtarg lidtarg; + + if (!idt_storage) { + asm volatile ("sidt %0" : "=m"(lidtarg_backup)); + ret = allocate_pool(pei_services, + sizeof(uintptr_t) + lidtarg_backup.limit + 1, + (void **)&idt_storage); + if (EFI_ERROR(ret)) { + printk(BIOS_ERR, "PEI: Fail to allocate IDT storage\n"); + return ret; + } + + idt_storage->pei_services = (uintptr_t)pei_services; + memcpy(idt_storage->idt, (void *)lidtarg_backup.base, + lidtarg_backup.limit + 1); + } + + lidtarg.limit = lidtarg_backup.limit; + lidtarg.base = (uintptr_t)&idt_storage[1]; + + asm volatile ("lidt %0" :: "m"(lidtarg)); + + return 0; +} + +EFI_PEI_SERVICES *pei_init(void) +{ + static EFI_PEI_SERVICES *pei_services; + EFI_STATUS ret; + + if (memcmp(ppis, &ppi_end_of_list, sizeof(ppi_end_of_list))) + memcpy(ppis, &ppi_end_of_list, sizeof(ppi_end_of_list)); + if (memcmp(hobs, &hob_end_of_list, sizeof(hob_end_of_list))) + memcpy(hobs, &hob_end_of_list, sizeof(hob_end_of_list)); + + pei_services = (EFI_PEI_SERVICES *)&PEI_SERVICES; + + ret = set_pei_services_idt((const EFI_PEI_SERVICES **)&pei_services); + if (EFI_ERROR(ret)) + return NULL; + + return pei_services; +} + +void pei_exit(void) +{ + if (!lidtarg_backup.limit || !lidtarg_backup.base) + return; + + asm volatile ("lidt %0" :: "m"(lidtarg_backup)); + lidtarg_backup.limit = lidtarg_backup.base = 0; +} diff --git a/src/vendorcode/intel/ugop/pei.h b/src/vendorcode/intel/ugop/pei.h new file mode 100644 index 0000000..eb9807c --- /dev/null +++ b/src/vendorcode/intel/ugop/pei.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _PEI_H_ +#define _PEI_H_ + +#include <fsp/soc_binding.h> +#include <Pi/PiPeiCis.h> + +EFI_PEI_SERVICES *pei_init(void); +void pei_exit(void); + +#endif diff --git a/src/vendorcode/intel/ugop/ugop.c b/src/vendorcode/intel/ugop/ugop.c new file mode 100644 index 0000000..e234187 --- /dev/null +++ b/src/vendorcode/intel/ugop/ugop.c @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * This file provides wrapper functions to use the uGOP Pre-EFI Initialization + * Module (PEIM). + * + * uGOP (aka. Pre-Memory Graphics PEIM driver) is short for Micro Graphics + * Output Protocol driver. This PEIM driver is designed to run in pre-memory + * context and can be use to perform legacy VGA graphics initialization. + */ + +#include <arch/io.h> +#include <cbfs.h> +#include <commonlib/endian.h> +#include <console/console.h> +#include <device/pci.h> +#include <fsp/soc_binding.h> +#include <intelblocks/igd_init.h> +#include <pc80/vga.h> +#include <soc/pci_devs.h> + +#include "pei.h" +#include "ugop.h" + +static const EFI_GUID PEI_PREMEM_GRAPHICS_PPI_GUID = { + 0x31a4622d, 0x0e21, 0x40a2, { + 0x80, 0xdb, 0xc4, 0x42, 0x08, 0xfc, 0xe1, 0xb5 + } +}; + +static const char *VBT_CBFS = "vbt.bin"; + +#define PEI_PREMEM_GRAPHICS_PPI_VERSION 0x00010000 + +typedef struct { + uint32_t version; + EFI_STATUS EFIAPI (*init)(void *vbt); + EFI_STATUS EFIAPI (*close)(void); +} PEI_GRAPHICS_PPI; + +static PEI_GRAPHICS_PPI *gop_ppi; +static EFI_PEI_SERVICES *pei_services; + +static EFI_PEIM_ENTRY_POINT2 load_ugop(void) +{ + EFI_IMAGE_DOS_HEADER *doshdr; + EFI_IMAGE_NT_HEADERS32 *peih; + EFI_IMAGE_OPTIONAL_HEADER32 *ophdr; + size_t size; + + doshdr = (EFI_IMAGE_DOS_HEADER *)cbfs_map(CONFIG_UGOP_CBFS, &size); + if (!doshdr) + return NULL; + + if (read_le16(&doshdr->e_magic) != EFI_IMAGE_DOS_SIGNATURE) { + printk(BIOS_ERR, "ugop: Invalid DOS Header/magic\n"); + return NULL; + } + + peih = (EFI_IMAGE_NT_HEADERS32 *)((uintptr_t)doshdr + doshdr->e_lfanew); + if (read_le32(&peih->Signature) != EFI_IMAGE_NT_SIGNATURE) { + printk(BIOS_ERR, "ugop: Invalid PE32 header\n"); + return NULL; + } + + ophdr = &peih->OptionalHeader; + if (read_le16(&ophdr->Magic) != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + printk(BIOS_ERR, "ugop: No support for non-PE32 images\n"); + return NULL; + } + + return (EFI_PEIM_ENTRY_POINT2)(((uintptr_t)doshdr) + ophdr->AddressOfEntryPoint); +} + +static bool initialized; +bool ugop_early_graphics_init(void) +{ + EFI_STATUS ret; + EFI_PEIM_ENTRY_POINT2 entry; + size_t vbt_size; + void *vbt; + + pei_services = pei_init(); + if (!pei_services) { + printk(BIOS_ERR, "ugop: PEI services initialization failed\n"); + return false; + } + + entry = load_ugop(); + if (!entry) { + printk(BIOS_ERR, "ugop: Failed to load %s\n", CONFIG_UGOP_CBFS); + return false; + } + + igd_init(); + ret = entry((EFI_PEI_FILE_HANDLE)entry, + (const EFI_PEI_SERVICES **)&pei_services); + if (EFI_ERROR(ret)) { + printk(BIOS_ERR, "ugop: entry point failed, ret=0x%x\n", ret); + return false; + } + + ret = pei_services->LocatePpi((const EFI_PEI_SERVICES **)&pei_services, + &PEI_PREMEM_GRAPHICS_PPI_GUID, 0, NULL, + (void **)&gop_ppi); + if (EFI_ERROR(ret)) { + printk(BIOS_ERR, "ugop: Could not find the uGOP PPI\n"); + return false; + } + + if (gop_ppi->version != PEI_PREMEM_GRAPHICS_PPI_VERSION) { + printk(BIOS_ERR, "ugop: version 0x%x not supported\n", + gop_ppi->version); + return false; + } + + vbt = cbfs_map(VBT_CBFS, &vbt_size); + if (!vbt) { + printk(BIOS_ERR, "ugop: Could not find VBT (%s)\n", VBT_CBFS); + return false; + } + + ret = gop_ppi->init(vbt); + if (EFI_ERROR(ret)) { + printk(BIOS_ERR, "ugop: graphics initialization failed, ret=0x%x\n", + ret); + return false; + } + + vga_io_init(); + vga_textmode_init(); + + initialized = true; + return true; +} + +void ugop_early_graphics_exit(void) +{ + if (gop_ppi && initialized) + gop_ppi->close(); + if (pei_services) + pei_exit(); + + pei_services = NULL; + gop_ppi = NULL; +} diff --git a/src/vendorcode/intel/ugop/ugop.h b/src/vendorcode/intel/ugop/ugop.h new file mode 100644 index 0000000..09f8df0 --- /dev/null +++ b/src/vendorcode/intel/ugop/ugop.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _UGOP_H_ +#define _UGOP_H_ + +#include <stdbool.h> + +bool ugop_early_graphics_init(void); +void ugop_early_graphics_exit(void); + +#endif