878ddf1f |
1 | /*++\r |
2 | \r |
3 | Copyright (c) 2006, Intel Corporation \r |
4 | All rights reserved. This program and the accompanying materials \r |
5 | are licensed and made available under the terms and conditions of the BSD License \r |
6 | which accompanies this distribution. The full text of the license may be found at \r |
7 | http://opensource.org/licenses/bsd-license.php \r |
8 | \r |
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r |
11 | \r |
12 | Module Name:\r |
13 | \r |
14 | Capsules.c\r |
15 | \r |
16 | Abstract:\r |
17 | \r |
18 | BDS routines to handle capsules.\r |
19 | \r |
20 | --*/\r |
21 | \r |
22 | \r |
23 | #include <Common/FlashMap.H>\r |
24 | \r |
25 | VOID\r |
26 | BdsLockFv (\r |
27 | IN EFI_CPU_IO_PROTOCOL *CpuIo,\r |
28 | IN EFI_FLASH_SUBAREA_ENTRY *FlashEntry\r |
29 | );\r |
30 | \r |
31 | VOID\r |
32 | BdsLockFv (\r |
33 | IN EFI_CPU_IO_PROTOCOL *CpuIo,\r |
34 | IN EFI_FLASH_SUBAREA_ENTRY *FlashEntry\r |
35 | )\r |
36 | {\r |
37 | EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r |
38 | EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r |
39 | UINT64 BaseAddress;\r |
40 | UINT8 Data;\r |
41 | UINT32 BlockLength;\r |
42 | UINTN Index;\r |
43 | \r |
44 | BaseAddress = FlashEntry->Base - 0x400000 + 2;\r |
45 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (FlashEntry->Base));\r |
46 | BlockMap = &(FvHeader->FvBlockMap[0]);\r |
47 | \r |
48 | while ((BlockMap->NumBlocks != 0) && (BlockMap->BlockLength != 0)) {\r |
49 | BlockLength = BlockMap->BlockLength;\r |
50 | for (Index = 0; Index < BlockMap->NumBlocks; Index++) {\r |
51 | CpuIo->Mem.Read (\r |
52 | CpuIo,\r |
53 | EfiCpuIoWidthUint8,\r |
54 | BaseAddress,\r |
55 | 1,\r |
56 | &Data\r |
57 | );\r |
58 | Data = (UINT8) (Data | 0x3);\r |
59 | CpuIo->Mem.Write (\r |
60 | CpuIo,\r |
61 | EfiCpuIoWidthUint8,\r |
62 | BaseAddress,\r |
63 | 1,\r |
64 | &Data\r |
65 | );\r |
66 | BaseAddress += BlockLength;\r |
67 | }\r |
68 | \r |
69 | BlockMap++;\r |
70 | }\r |
71 | }\r |
72 | \r |
73 | VOID\r |
74 | BdsLockNonUpdatableFlash (\r |
75 | VOID\r |
76 | )\r |
77 | {\r |
78 | EFI_FLASH_MAP_ENTRY_DATA *FlashMapEntryData;\r |
79 | EFI_PEI_HOB_POINTERS GuidHob;\r |
80 | EFI_STATUS Status;\r |
81 | EFI_CPU_IO_PROTOCOL *CpuIo;\r |
82 | \r |
83 | Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, &CpuIo);\r |
84 | ASSERT_EFI_ERROR (Status);\r |
85 | \r |
86 | GuidHob.Raw = GetHobList ();\r |
87 | while ((GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw)) != NULL) {\r |
88 | FlashMapEntryData = (EFI_FLASH_MAP_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid);\r |
89 | \r |
90 | //\r |
91 | // Get the variable store area\r |
92 | //\r |
93 | if ((FlashMapEntryData->AreaType == EFI_FLASH_AREA_RECOVERY_BIOS) ||\r |
94 | (FlashMapEntryData->AreaType == EFI_FLASH_AREA_MAIN_BIOS)\r |
95 | ) {\r |
96 | BdsLockFv (CpuIo, &(FlashMapEntryData->Entries[0]));\r |
97 | }\r |
98 | GuidHob.Raw = GET_NEXT_HOB (GuidHob);\r |
99 | }\r |
100 | \r |
101 | return ;\r |
102 | }\r |
103 | \r |
104 | EFI_STATUS\r |
105 | ProcessCapsules (\r |
106 | EFI_BOOT_MODE BootMode\r |
107 | )\r |
108 | /*++\r |
109 | \r |
110 | Routine Description:\r |
111 | \r |
112 | This routine is called to see if there are any capsules we need to process.\r |
113 | If the boot mode is not UPDATE, then we do nothing. Otherwise find the\r |
114 | capsule HOBS and produce firmware volumes for them via the DXE service.\r |
115 | Then call the dispatcher to dispatch drivers from them. Finally, check\r |
116 | the status of the updates.\r |
117 | \r |
118 | Arguments:\r |
119 | \r |
120 | BootMode - the current boot mode\r |
121 | \r |
122 | Returns:\r |
123 | \r |
124 | EFI_INVALID_PARAMETER - boot mode is not correct for an update\r |
125 | \r |
126 | Note:\r |
127 | \r |
128 | This function should be called by BDS in case we need to do some\r |
129 | sort of processing even if there is no capsule to process. We\r |
130 | need to do this if an earlier update went awry and we need to\r |
131 | clear the capsule variable so on the next reset PEI does not see it and \r |
132 | think there is a capsule available.\r |
133 | \r |
134 | --*/\r |
135 | {\r |
136 | EFI_STATUS Status;\r |
137 | EFI_HOB_CAPSULE_VOLUME *CvHob;\r |
138 | EFI_PHYSICAL_ADDRESS BaseAddress;\r |
139 | UINT64 Length;\r |
140 | EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r |
141 | EFI_HANDLE FvProtocolHandle;\r |
142 | \r |
143 | //\r |
144 | // We don't do anything else if the boot mode is not flash-update\r |
145 | //\r |
146 | if (BootMode != BOOT_ON_FLASH_UPDATE) {\r |
147 | return EFI_INVALID_PARAMETER;\r |
148 | }\r |
149 | //\r |
150 | // Only one capsule HOB allowed.\r |
151 | //\r |
152 | CvHob = GetFirstHob (EFI_HOB_TYPE_CV);\r |
153 | if (CvHob == NULL) {\r |
154 | //\r |
155 | // We didn't find a hob, so had no errors.\r |
156 | //\r |
157 | BdsLockNonUpdatableFlash ();\r |
158 | return EFI_SUCCESS;\r |
159 | }\r |
160 | \r |
161 | BaseAddress = CvHob->BaseAddress;\r |
162 | Length = CvHob->Length;\r |
163 | \r |
164 | Status = EFI_SUCCESS;\r |
165 | //\r |
166 | // Now walk the capsule and call the core to process each\r |
167 | // firmware volume in it.\r |
168 | //\r |
169 | while (Length != 0) {\r |
170 | //\r |
171 | // Point to the next firmware volume header, and then\r |
172 | // call the DXE service to process it.\r |
173 | //\r |
174 | FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r |
175 | if (FwVolHeader->FvLength > Length) {\r |
176 | //\r |
177 | // Notes: need to stuff this status somewhere so that the\r |
178 | // error can be detected at OS runtime\r |
179 | //\r |
180 | Status = EFI_VOLUME_CORRUPTED;\r |
181 | break;\r |
182 | }\r |
183 | \r |
184 | Status = gDS->ProcessFirmwareVolume (\r |
185 | (VOID *) (UINTN) BaseAddress,\r |
186 | (UINTN) FwVolHeader->FvLength,\r |
187 | &FvProtocolHandle\r |
188 | );\r |
189 | if (EFI_ERROR (Status)) {\r |
190 | break;\r |
191 | }\r |
192 | //\r |
193 | // Call the dispatcher to dispatch any drivers from the produced firmware volume\r |
194 | //\r |
195 | gDS->Dispatch ();\r |
196 | //\r |
197 | // On to the next FV in the capsule\r |
198 | //\r |
199 | Length -= FwVolHeader->FvLength;\r |
200 | BaseAddress = (EFI_PHYSICAL_ADDRESS) ((UINTN) BaseAddress + FwVolHeader->FvLength);\r |
201 | //\r |
202 | // Notes: when capsule spec is finalized, if the requirement is made to\r |
203 | // have each FV in a capsule aligned, then we will need to align the\r |
204 | // BaseAddress and Length here.\r |
205 | //\r |
206 | }\r |
207 | \r |
208 | \r |
209 | BdsLockNonUpdatableFlash ();\r |
210 | \r |
211 | return Status;\r |
212 | }\r |
213 | \r |