/** Starts the device with this driver. @param This The driver binding instance. @param Controller Handle of device to bind driver to. @param RemainingDevicePath Optional parameter use to pick a specific child device to start. @retval EFI_SUCCESS The controller is controlled by the driver. @retval Other This controller cannot be started. **/ EFI_STATUS EFIAPI BiosBlockIoDriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; // EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; EFI_PCI_IO_PROTOCOL *PciIo; UINT8 DiskStart = 0x80; UINT8 DiskEnd = 0xFF; BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate; EFI_DEVICE_PATH_PROTOCOL *PciDevPath; UINTN Index; // UINTN Flags; UINTN TmpAddress; BOOLEAN DeviceEnable; // // Initialize variables // PciIo = NULL; PciDevPath = NULL; DeviceEnable = FALSE; // // See if the Legacy BIOS Protocol is available // /* Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); if (EFI_ERROR (Status)) { goto Error; } */ if (mLegacy8259 == NULL) { Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &mLegacy8259); if (EFI_ERROR (Status)) { goto Error; } InitializeBiosIntCaller(&mThunkContext); InitializeInterruptRedirection(mLegacy8259); } // // Open the IO Abstraction(s) needed // Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &PciIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { goto Error; } Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, (VOID **) &PciDevPath, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { goto Error; } // // Enable the device and make sure VGA cycles are being forwarded to this VGA device // Status = PciIo->Attributes ( PciIo, EfiPciIoAttributeOperationEnable, EFI_PCI_DEVICE_ENABLE, NULL ); if (EFI_ERROR (Status)) { goto Error; } DeviceEnable = TRUE; // // Check to see if there is a legacy option ROM image associated with this PCI device // //Slice - something for replacement? /* Status = LegacyBios->CheckPciRom ( LegacyBios, Controller, NULL, NULL, &Flags ); if (EFI_ERROR (Status)) { goto Error; } // // Post the legacy option ROM if it is available. // Status = LegacyBios->InstallPciRom ( LegacyBios, Controller, NULL, &Flags, &DiskStart, &DiskEnd, NULL, NULL ); if (EFI_ERROR (Status)) { goto Error; } */ // // All instances share a buffer under 1MB to put real mode thunk code in // If it has not been allocated, then we allocate it. // if (mBufferUnder1Mb == 0) { // // Should only be here if there are no active instances // // ASSERT (mActiveInstances == 0); if (mActiveInstances) { Status = EFI_OUT_OF_RESOURCES; goto Error; } // // Acquire the lock // EfiAcquireLock (&mGlobalDataLock); // // Allocate below 1MB // mBufferUnder1Mb = 0x00000000000FFFFF; Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, BLOCK_IO_BUFFER_PAGE_SIZE, &mBufferUnder1Mb); // // Release the lock // EfiReleaseLock (&mGlobalDataLock); // // Check memory allocation success // if (EFI_ERROR (Status)) { // // In checked builds we want to assert if the allocate failed. // // ASSERT_EFI_ERROR (Status); Status = EFI_OUT_OF_RESOURCES; mBufferUnder1Mb = 0; goto Error; } TmpAddress = (UINTN) mBufferUnder1Mb; // // Adjusting the value to be on proper boundary // mEdd11Buffer = (VOID *) ALIGN_VARIABLE (TmpAddress); TmpAddress = (UINTN) mEdd11Buffer + MAX_EDD11_XFER; // // Adjusting the value to be on proper boundary // mLegacyDriverUnder1Mb = (BIOS_LEGACY_DRIVE *) ALIGN_VARIABLE (TmpAddress); TmpAddress = (UINTN) mLegacyDriverUnder1Mb + sizeof (BIOS_LEGACY_DRIVE); // // Adjusting the value to be on proper boundary // mEddBufferUnder1Mb = (EDD_DEVICE_ADDRESS_PACKET *) ALIGN_VARIABLE (TmpAddress); } // // Allocate the private device structure for each disk // for (Index = DiskStart; Index <= DiskEnd; Index++) { Status = gBS->AllocatePool ( EfiBootServicesData, sizeof (BIOS_BLOCK_IO_DEV), (VOID **) &BiosBlockIoPrivate ); if (EFI_ERROR (Status)) { goto Error; } // // Zero the private device structure // ZeroMem (BiosBlockIoPrivate, sizeof (BIOS_BLOCK_IO_DEV)); // // Initialize the private device structure // BiosBlockIoPrivate->Signature = BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE; BiosBlockIoPrivate->ControllerHandle = Controller; // BiosBlockIoPrivate->LegacyBios = LegacyBios; BiosBlockIoPrivate->Legacy8259 = mLegacy8259; BiosBlockIoPrivate->ThunkContext = &mThunkContext; BiosBlockIoPrivate->PciIo = PciIo; BiosBlockIoPrivate->Bios.Floppy = FALSE; BiosBlockIoPrivate->Bios.Number = (UINT8) Index; BiosBlockIoPrivate->Bios.Letter = (UINT8) (Index - 0x80 + 'C'); BiosBlockIoPrivate->BlockMedia.RemovableMedia = FALSE; if (BiosInitBlockIo (BiosBlockIoPrivate)) { SetBiosInitBlockIoDevicePath (PciDevPath, &BiosBlockIoPrivate->Bios, &BiosBlockIoPrivate->DevicePath); // // Install the Block Io Protocol onto a new child handle // Status = gBS->InstallMultipleProtocolInterfaces ( &BiosBlockIoPrivate->Handle, &gEfiBlockIoProtocolGuid, &BiosBlockIoPrivate->BlockIo, &gEfiDevicePathProtocolGuid, BiosBlockIoPrivate->DevicePath, NULL ); if (EFI_ERROR (Status)) { gBS->FreePool (BiosBlockIoPrivate); } // // Open For Child Device // Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, (VOID **) &BiosBlockIoPrivate->PciIo, This->DriverBindingHandle, BiosBlockIoPrivate->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } else { gBS->FreePool (BiosBlockIoPrivate); } } mBiosDrivesEnumerated = TRUE; Error: if (EFI_ERROR (Status)) { if (PciIo != NULL) { if (DeviceEnable) { PciIo->Attributes ( PciIo, EfiPciIoAttributeOperationDisable, EFI_PCI_DEVICE_ENABLE, NULL ); } gBS->CloseProtocol ( Controller, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, Controller ); if (PciDevPath != NULL) { gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller ); } if (mBufferUnder1Mb != 0 && mActiveInstances == 0) { gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE); // // Clear the buffer back to 0 // EfiAcquireLock (&mGlobalDataLock); mBufferUnder1Mb = 0; EfiReleaseLock (&mGlobalDataLock); } } } else { // // Successfully installed, so increment the number of active instances // EfiAcquireLock (&mGlobalDataLock); mActiveInstances++; EfiReleaseLock (&mGlobalDataLock); } return Status; }
/** Internal function to allocate pool of a particular type. Caller must have the memory lock held @param PoolType Type of pool to allocate @param Size The amount of pool to allocate @param NeedGuard Flag to indicate Guard page is needed or not @return The allocate pool, or NULL **/ VOID * CoreAllocatePoolI ( IN EFI_MEMORY_TYPE PoolType, IN UINTN Size, IN BOOLEAN NeedGuard ) { POOL *Pool; POOL_FREE *Free; POOL_HEAD *Head; POOL_TAIL *Tail; CHAR8 *NewPage; VOID *Buffer; UINTN Index; UINTN FSize; UINTN Offset, MaxOffset; UINTN NoPages; UINTN Granularity; BOOLEAN HasPoolTail; ASSERT_LOCKED (&mPoolMemoryLock); if (PoolType == EfiACPIReclaimMemory || PoolType == EfiACPIMemoryNVS || PoolType == EfiRuntimeServicesCode || PoolType == EfiRuntimeServicesData) { Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY; } else { Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY; } // // Adjust the size by the pool header & tail overhead // HasPoolTail = !(NeedGuard && ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0)); // // Adjusting the Size to be of proper alignment so that // we don't get an unaligned access fault later when // pool_Tail is being initialized // Size = ALIGN_VARIABLE (Size); Size += POOL_OVERHEAD; Index = SIZE_TO_LIST(Size); Pool = LookupPoolHead (PoolType); if (Pool== NULL) { return NULL; } Head = NULL; // // If allocation is over max size, just allocate pages for the request // (slow) // if (Index >= SIZE_TO_LIST (Granularity) || NeedGuard) { if (!HasPoolTail) { Size -= sizeof (POOL_TAIL); } NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1; NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1); Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard); if (NeedGuard) { Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size); } goto Done; } // // If there's no free pool in the proper list size, go get some more pages // if (IsListEmpty (&Pool->FreeList[Index])) { Offset = LIST_TO_SIZE (Index); MaxOffset = Granularity; // // Check the bins holding larger blocks, and carve one up if needed // while (++Index < SIZE_TO_LIST (Granularity)) { if (!IsListEmpty (&Pool->FreeList[Index])) { Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE); RemoveEntryList (&Free->Link); NewPage = (VOID *) Free; MaxOffset = LIST_TO_SIZE (Index); goto Carve; } } // // Get another page // NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity, NeedGuard); if (NewPage == NULL) { goto Done; } // // Serve the allocation request from the head of the allocated block // Carve: Head = (POOL_HEAD *) NewPage; // // Carve up remaining space into free pool blocks // Index--; while (Offset < MaxOffset) { ASSERT (Index < MAX_POOL_LIST); FSize = LIST_TO_SIZE(Index); while (Offset + FSize <= MaxOffset) { Free = (POOL_FREE *) &NewPage[Offset]; Free->Signature = POOL_FREE_SIGNATURE; Free->Index = (UINT32)Index; InsertHeadList (&Pool->FreeList[Index], &Free->Link); Offset += FSize; } Index -= 1; } ASSERT (Offset == MaxOffset); goto Done; } // // Remove entry from free pool list // Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE); RemoveEntryList (&Free->Link); Head = (POOL_HEAD *) Free; Done: Buffer = NULL; if (Head != NULL) { // // Account the allocation // Pool->Used += Size; // // If we have a pool buffer, fill in the header & tail info // Head->Signature = POOL_HEAD_SIGNATURE; Head->Size = Size; Head->Type = (EFI_MEMORY_TYPE) PoolType; Buffer = Head->Data; if (HasPoolTail) { Tail = HEAD_TO_TAIL (Head); Tail->Signature = POOL_TAIL_SIGNATURE; Tail->Size = Size; Size -= POOL_OVERHEAD; } else { Size -= SIZE_OF_POOL_HEAD; } DEBUG_CLEAR_MEMORY (Buffer, Size); DEBUG (( DEBUG_POOL, "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType, Buffer, (UINT64)Size, (UINT64) Pool->Used )); } else { DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size)); } return Buffer; }
/** Internal function to allocate pool of a particular type. Caller must have the memory lock held @param PoolType Type of pool to allocate @param Size The amount of pool to allocate @return The allocate pool, or NULL **/ VOID * CoreAllocatePoolI ( IN EFI_MEMORY_TYPE PoolType, IN UINTN Size ) { POOL *Pool; POOL_FREE *Free; POOL_HEAD *Head; POOL_TAIL *Tail; CHAR8 *NewPage; VOID *Buffer; UINTN Index; UINTN FSize; UINTN Offset; UINTN NoPages; ASSERT_LOCKED (&gMemoryLock); // // Adjust the size by the pool header & tail overhead // // // Adjusting the Size to be of proper alignment so that // we don't get an unaligned access fault later when // pool_Tail is being initialized // Size = ALIGN_VARIABLE (Size); Size += POOL_OVERHEAD; Index = SIZE_TO_LIST(Size); Pool = LookupPoolHead (PoolType); if (Pool== NULL) { return NULL; } Head = NULL; // // If allocation is over max size, just allocate pages for the request // (slow) // if (Index >= MAX_POOL_LIST) { NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1; NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1); Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION); goto Done; } // // If there's no free pool in the proper list size, go get some more pages // if (IsListEmpty (&Pool->FreeList[Index])) { // // Get another page // NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION); if (NewPage == NULL) { goto Done; } // // Carve up new page into free pool blocks // Offset = 0; while (Offset < DEFAULT_PAGE_ALLOCATION) { ASSERT (Index < MAX_POOL_LIST); FSize = LIST_TO_SIZE(Index); while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) { Free = (POOL_FREE *) &NewPage[Offset]; Free->Signature = POOL_FREE_SIGNATURE; Free->Index = (UINT32)Index; InsertHeadList (&Pool->FreeList[Index], &Free->Link); Offset += FSize; } Index -= 1; } ASSERT (Offset == DEFAULT_PAGE_ALLOCATION); Index = SIZE_TO_LIST(Size); } // // Remove entry from free pool list // Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE); RemoveEntryList (&Free->Link); Head = (POOL_HEAD *) Free; Done: Buffer = NULL; if (Head != NULL) { // // If we have a pool buffer, fill in the header & tail info // Head->Signature = POOL_HEAD_SIGNATURE; Head->Size = Size; Head->Type = (EFI_MEMORY_TYPE) PoolType; Tail = HEAD_TO_TAIL (Head); Tail->Signature = POOL_TAIL_SIGNATURE; Tail->Size = Size; Buffer = Head->Data; DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD); DEBUG (( DEBUG_POOL, "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType, Buffer, (UINT64)(Size - POOL_OVERHEAD), (UINT64) Pool->Used )); // // Account the allocation // Pool->Used += Size; } else { DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size)); } return Buffer; }