1 /** @file
2 
3 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
4 
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions
7 of the BSD License which accompanies this distribution.  The
8 full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "LegacyBiosInterface.h"
17 #include <IndustryStandard/Pci.h>
18 
19 // Give floppy 3 states
20 // FLOPPY_PRESENT_WITH_MEDIA  = Floppy controller present and media is inserted
21 // FLOPPY_NOT_PRESENT = No floppy controller present
22 // FLOPPY_PRESENT_NO_MEDIA = Floppy controller present but no media inserted
23 //
24 #define FLOPPY_NOT_PRESENT           0
25 #define FLOPPY_PRESENT_WITH_MEDIA    1
26 #define FLOPPY_PRESENT_NO_MEDIA      2
27 
28 BBS_TABLE           *mBbsTable;
29 BOOLEAN             mBbsTableDoneFlag   = FALSE;
30 BOOLEAN             IsHaveMediaInFloppy = TRUE;
31 
32 /**
33   Checks the state of the floppy and if media is inserted.
34 
35   This routine checks the state of the floppy and if media is inserted.
36   There are 3 cases:
37   No floppy present         - Set BBS entry to ignore
38   Floppy present & no media - Set BBS entry to lowest priority. We cannot
39   set it to ignore since 16-bit CSM will
40   indicate no floppy and thus drive A: is
41   unusable. CSM-16 will not try floppy since
42   lowest priority and thus not incur boot
43   time penality.
44   Floppy present & media    - Set BBS entry to some priority.
45 
46   @return  State of floppy media
47 
48 **/
49 UINT8
HasMediaInFloppy(VOID)50 HasMediaInFloppy (
51   VOID
52   )
53 {
54   EFI_STATUS                            Status;
55   UINTN                                 HandleCount;
56   EFI_HANDLE                            *HandleBuffer;
57   UINTN                                 Index;
58   EFI_ISA_IO_PROTOCOL                   *IsaIo;
59   EFI_BLOCK_IO_PROTOCOL                 *BlkIo;
60 
61   HandleBuffer  = NULL;
62   HandleCount   = 0;
63 
64   gBS->LocateHandleBuffer (
65         ByProtocol,
66         &gEfiIsaIoProtocolGuid,
67         NULL,
68         &HandleCount,
69         &HandleBuffer
70         );
71 
72   //
73   // If don't find any ISA/IO protocol assume no floppy. Need for floppy
74   // free system
75   //
76   if (HandleCount == 0) {
77     return FLOPPY_NOT_PRESENT;
78   }
79 
80   ASSERT (HandleBuffer != NULL);
81 
82   for (Index = 0; Index < HandleCount; Index++) {
83     Status = gBS->HandleProtocol (
84                     HandleBuffer[Index],
85                     &gEfiIsaIoProtocolGuid,
86                     (VOID **) &IsaIo
87                     );
88     if (EFI_ERROR (Status)) {
89       continue;
90     }
91 
92     if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) {
93       continue;
94     }
95     //
96     // Update blockio in case the floppy is inserted in during BdsTimeout
97     //
98     Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
99 
100     if (EFI_ERROR (Status)) {
101       continue;
102     }
103 
104     Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
105 
106     if (EFI_ERROR (Status)) {
107       continue;
108     }
109 
110     Status = gBS->HandleProtocol (
111                     HandleBuffer[Index],
112                     &gEfiBlockIoProtocolGuid,
113                     (VOID **) &BlkIo
114                     );
115     if (EFI_ERROR (Status)) {
116       continue;
117     }
118 
119     if (BlkIo->Media->MediaPresent) {
120       FreePool (HandleBuffer);
121       return FLOPPY_PRESENT_WITH_MEDIA;
122     } else {
123       FreePool (HandleBuffer);
124       return FLOPPY_PRESENT_NO_MEDIA;
125     }
126   }
127 
128   FreePool (HandleBuffer);
129 
130   return FLOPPY_NOT_PRESENT;
131 
132 }
133 
134 
135 /**
136   Complete build of BBS TABLE.
137 
138   @param  Private                 Legacy BIOS Instance data
139   @param  BbsTable                BBS Table passed to 16-bit code
140 
141   @retval EFI_SUCCESS             Removable media not present
142 
143 **/
144 EFI_STATUS
LegacyBiosBuildBbs(IN LEGACY_BIOS_INSTANCE * Private,IN BBS_TABLE * BbsTable)145 LegacyBiosBuildBbs (
146   IN  LEGACY_BIOS_INSTANCE      *Private,
147   IN  BBS_TABLE                 *BbsTable
148   )
149 {
150   UINTN     BbsIndex;
151   HDD_INFO  *HddInfo;
152   UINTN     HddIndex;
153   UINTN     Index;
154 
155   //
156   // First entry is floppy.
157   // Next 2*MAX_IDE_CONTROLLER entries are for onboard IDE.
158   // Next n entries are filled in after each ROM is dispatched.
159   //   Entry filled in if follow BBS spec. See LegacyPci.c
160   // Next entries are for non-BBS compliant ROMS. They are filled in by
161   //   16-bit code during Legacy16UpdateBbs invocation. Final BootPriority
162   //   occurs after that invocation.
163   //
164   // Floppy
165   // Set default state.
166   //
167   IsHaveMediaInFloppy = HasMediaInFloppy ();
168   if (IsHaveMediaInFloppy == FLOPPY_PRESENT_WITH_MEDIA) {
169     BbsTable[0].BootPriority = BBS_UNPRIORITIZED_ENTRY;
170   } else {
171     if (IsHaveMediaInFloppy == FLOPPY_PRESENT_NO_MEDIA) {
172       BbsTable[0].BootPriority = BBS_LOWEST_PRIORITY;
173     } else {
174       BbsTable[0].BootPriority = BBS_IGNORE_ENTRY;
175     }
176   }
177 
178   BbsTable[0].Bus                       = 0xff;
179   BbsTable[0].Device                    = 0xff;
180   BbsTable[0].Function                  = 0xff;
181   BbsTable[0].DeviceType                = BBS_FLOPPY;
182   BbsTable[0].Class                     = 01;
183   BbsTable[0].SubClass                  = 02;
184   BbsTable[0].StatusFlags.OldPosition   = 0;
185   BbsTable[0].StatusFlags.Reserved1     = 0;
186   BbsTable[0].StatusFlags.Enabled       = 0;
187   BbsTable[0].StatusFlags.Failed        = 0;
188   BbsTable[0].StatusFlags.MediaPresent  = 0;
189   BbsTable[0].StatusFlags.Reserved2     = 0;
190 
191   //
192   // Onboard HDD - Note Each HDD controller controls 2 drives
193   //               Master & Slave
194   //
195   HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
196   //
197   // Get IDE Drive Info
198   //
199   LegacyBiosBuildIdeData (Private, &HddInfo, 0);
200 
201   for (HddIndex = 0; HddIndex < MAX_IDE_CONTROLLER; HddIndex++) {
202 
203     BbsIndex = HddIndex * 2 + 1;
204     for (Index = 0; Index < 2; ++Index) {
205 
206       BbsTable[BbsIndex + Index].Bus                      = HddInfo[HddIndex].Bus;
207       BbsTable[BbsIndex + Index].Device                   = HddInfo[HddIndex].Device;
208       BbsTable[BbsIndex + Index].Function                 = HddInfo[HddIndex].Function;
209       BbsTable[BbsIndex + Index].Class                    = 01;
210       BbsTable[BbsIndex + Index].SubClass                 = 01;
211       BbsTable[BbsIndex + Index].StatusFlags.OldPosition  = 0;
212       BbsTable[BbsIndex + Index].StatusFlags.Reserved1    = 0;
213       BbsTable[BbsIndex + Index].StatusFlags.Enabled      = 0;
214       BbsTable[BbsIndex + Index].StatusFlags.Failed       = 0;
215       BbsTable[BbsIndex + Index].StatusFlags.MediaPresent = 0;
216       BbsTable[BbsIndex + Index].StatusFlags.Reserved2    = 0;
217 
218       //
219       // If no controller found or no device found set to ignore
220       // else set to unprioritized and set device type
221       //
222       if (HddInfo[HddIndex].CommandBaseAddress == 0) {
223         BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
224       } else {
225         if (Index == 0) {
226           if ((HddInfo[HddIndex].Status & (HDD_MASTER_IDE | HDD_MASTER_ATAPI_CDROM | HDD_MASTER_ATAPI_ZIPDISK)) != 0) {
227             BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
228             if ((HddInfo[HddIndex].Status & HDD_MASTER_IDE) != 0) {
229               BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
230             } else if ((HddInfo[HddIndex].Status & HDD_MASTER_ATAPI_CDROM) != 0) {
231               BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;
232             } else {
233               //
234               // for ZIPDISK
235               //
236               BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
237             }
238           } else {
239             BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
240           }
241         } else {
242           if ((HddInfo[HddIndex].Status & (HDD_SLAVE_IDE | HDD_SLAVE_ATAPI_CDROM | HDD_SLAVE_ATAPI_ZIPDISK)) != 0) {
243             BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
244             if ((HddInfo[HddIndex].Status & HDD_SLAVE_IDE) != 0) {
245               BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
246             } else if ((HddInfo[HddIndex].Status & HDD_SLAVE_ATAPI_CDROM) != 0) {
247               BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;
248             } else {
249               //
250               // for ZIPDISK
251               //
252               BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
253             }
254           } else {
255             BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
256           }
257         }
258       }
259     }
260   }
261 
262   return EFI_SUCCESS;
263 
264 }
265 
266 
267 /**
268   Get all BBS info
269 
270   @param  This                    Protocol instance pointer.
271   @param  HddCount                Number of HDD_INFO structures
272   @param  HddInfo                 Onboard IDE controller information
273   @param  BbsCount                Number of BBS_TABLE structures
274   @param  BbsTable                List BBS entries
275 
276   @retval EFI_SUCCESS             Tables returned
277   @retval EFI_NOT_FOUND           resource not found
278   @retval EFI_DEVICE_ERROR        can not get BBS table
279 
280 **/
281 EFI_STATUS
282 EFIAPI
LegacyBiosGetBbsInfo(IN EFI_LEGACY_BIOS_PROTOCOL * This,OUT UINT16 * HddCount,OUT HDD_INFO ** HddInfo,OUT UINT16 * BbsCount,OUT BBS_TABLE ** BbsTable)283 LegacyBiosGetBbsInfo (
284   IN EFI_LEGACY_BIOS_PROTOCOL         *This,
285   OUT UINT16                          *HddCount,
286   OUT HDD_INFO                        **HddInfo,
287   OUT UINT16                          *BbsCount,
288   OUT BBS_TABLE                       **BbsTable
289   )
290 {
291   LEGACY_BIOS_INSTANCE              *Private;
292   EFI_IA32_REGISTER_SET             Regs;
293   EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
294 //  HDD_INFO                          *LocalHddInfo;
295 //  IN BBS_TABLE                      *LocalBbsTable;
296   UINTN                             NumHandles;
297   EFI_HANDLE                        *HandleBuffer;
298   UINTN                             Index;
299   UINTN                             TempData;
300   UINT32                            Granularity;
301 
302   HandleBuffer            = NULL;
303 
304   Private                 = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
305   EfiToLegacy16BootTable  = &Private->IntThunk->EfiToLegacy16BootTable;
306 //  LocalHddInfo            = EfiToLegacy16BootTable->HddInfo;
307 //  LocalBbsTable           = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
308 
309   if (!mBbsTableDoneFlag) {
310     mBbsTable = Private->BbsTablePtr;
311 
312     //
313     // Always enable disk controllers so 16-bit CSM code has valid information for all
314     // drives.
315     //
316     //
317     // Get PciRootBridgeIO protocol
318     //
319     gBS->LocateHandleBuffer (
320           ByProtocol,
321           &gEfiPciRootBridgeIoProtocolGuid,
322           NULL,
323           &NumHandles,
324           &HandleBuffer
325           );
326 
327     if (NumHandles == 0) {
328       return EFI_NOT_FOUND;
329     }
330 
331     mBbsTableDoneFlag = TRUE;
332     for (Index = 0; Index < NumHandles; Index++) {
333       //
334       // Connect PciRootBridgeIO protocol handle with FALSE parameter to let
335       // PCI bus driver enumerate all subsequent handles
336       //
337       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
338 
339     }
340 
341     LegacyBiosBuildBbs (Private, mBbsTable);
342 
343     Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);
344 
345     //
346     // Call into Legacy16 code to add to BBS table for non BBS compliant OPROMs.
347     //
348     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
349     Regs.X.AX = Legacy16UpdateBbs;
350 
351     //
352     // Pass in handoff data
353     //
354     TempData  = (UINTN) EfiToLegacy16BootTable;
355     Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINT32) TempData);
356     Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINT32) TempData);
357 
358     Private->LegacyBios.FarCall86 (
359       This,
360       Private->Legacy16CallSegment,
361       Private->Legacy16CallOffset,
362       &Regs,
363       NULL,
364       0
365       );
366 
367     Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
368     Private->LegacyRegion->Lock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);
369 
370     if (Regs.X.AX != 0) {
371       return EFI_DEVICE_ERROR;
372     }
373   }
374 
375   if (HandleBuffer != NULL) {
376     FreePool (HandleBuffer);
377   }
378 
379   *HddCount = MAX_IDE_CONTROLLER;
380   *HddInfo  = EfiToLegacy16BootTable->HddInfo;
381   *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
382   *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
383   return EFI_SUCCESS;
384 }
385