1 /** @file 2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid 3 which is used to enable recovery function from USB Drivers. 4 5 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR> 6 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions 9 of the BSD License which accompanies this distribution. The 10 full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 #include "XhcPeim.h" 19 20 /** 21 Allocate a block of memory to be used by the buffer pool. 22 23 @param Pages How many pages to allocate. 24 25 @return Pointer to the allocated memory block or NULL if failed. 26 27 **/ 28 USBHC_MEM_BLOCK * 29 UsbHcAllocMemBlock ( 30 IN UINTN Pages 31 ) 32 { 33 USBHC_MEM_BLOCK *Block; 34 EFI_STATUS Status; 35 UINTN PageNumber; 36 EFI_PHYSICAL_ADDRESS TempPtr; 37 38 PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_BLOCK)); 39 Status = PeiServicesAllocatePages ( 40 EfiBootServicesData, 41 PageNumber, 42 &TempPtr 43 ); 44 45 if (EFI_ERROR (Status)) { 46 return NULL; 47 } 48 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber)); 49 50 // 51 // each bit in the bit array represents USBHC_MEM_UNIT 52 // bytes of memory in the memory block. 53 // 54 ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE); 55 56 Block = (USBHC_MEM_BLOCK *) (UINTN) TempPtr; 57 Block->BufLen = EFI_PAGES_TO_SIZE (Pages); 58 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8); 59 60 PageNumber = EFI_SIZE_TO_PAGES (Block->BitsLen); 61 Status = PeiServicesAllocatePages ( 62 EfiBootServicesData, 63 PageNumber, 64 &TempPtr 65 ); 66 67 if (EFI_ERROR (Status)) { 68 return NULL; 69 } 70 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber)); 71 72 Block->Bits = (UINT8 *) (UINTN) TempPtr; 73 74 Status = PeiServicesAllocatePages ( 75 EfiBootServicesData, 76 Pages, 77 &TempPtr 78 ); 79 if (EFI_ERROR (Status)) { 80 return NULL; 81 } 82 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (Pages)); 83 84 Block->BufHost = (UINT8 *) (UINTN) TempPtr;; 85 Block->Buf = (UINT8 *) (UINTN) TempPtr; 86 Block->Next = NULL; 87 88 return Block; 89 } 90 91 /** 92 Free the memory block from the memory pool. 93 94 @param Pool The memory pool to free the block from. 95 @param Block The memory block to free. 96 97 **/ 98 VOID 99 UsbHcFreeMemBlock ( 100 IN USBHC_MEM_POOL *Pool, 101 IN USBHC_MEM_BLOCK *Block 102 ) 103 { 104 ASSERT ((Pool != NULL) && (Block != NULL)); 105 // 106 // No free memory in PEI. 107 // 108 } 109 110 /** 111 Alloc some memory from the block. 112 113 @param Block The memory block to allocate memory from. 114 @param Units Number of memory units to allocate. 115 116 @return The pointer to the allocated memory. 117 If couldn't allocate the needed memory, the return value is NULL. 118 119 **/ 120 VOID * 121 UsbHcAllocMemFromBlock ( 122 IN USBHC_MEM_BLOCK *Block, 123 IN UINTN Units 124 ) 125 { 126 UINTN Byte; 127 UINT8 Bit; 128 UINTN StartByte; 129 UINT8 StartBit; 130 UINTN Available; 131 UINTN Count; 132 133 ASSERT ((Block != 0) && (Units != 0)); 134 135 StartByte = 0; 136 StartBit = 0; 137 Available = 0; 138 139 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) { 140 // 141 // If current bit is zero, the corresponding memory unit is 142 // available, otherwise we need to restart our searching. 143 // Available counts the consective number of zero bit. 144 // 145 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) { 146 Available++; 147 148 if (Available >= Units) { 149 break; 150 } 151 152 NEXT_BIT (Byte, Bit); 153 } else { 154 NEXT_BIT (Byte, Bit); 155 156 Available = 0; 157 StartByte = Byte; 158 StartBit = Bit; 159 } 160 } 161 162 if (Available < Units) { 163 return NULL; 164 } 165 166 // 167 // Mark the memory as allocated 168 // 169 Byte = StartByte; 170 Bit = StartBit; 171 172 for (Count = 0; Count < Units; Count++) { 173 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); 174 175 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit)); 176 NEXT_BIT (Byte, Bit); 177 } 178 179 return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT; 180 } 181 182 /** 183 Calculate the corresponding pci bus address according to the Mem parameter. 184 185 @param Pool The memory pool of the host controller. 186 @param Mem The pointer to host memory. 187 @param Size The size of the memory region. 188 189 @return The pci memory address 190 191 **/ 192 EFI_PHYSICAL_ADDRESS 193 UsbHcGetPciAddrForHostAddr ( 194 IN USBHC_MEM_POOL *Pool, 195 IN VOID *Mem, 196 IN UINTN Size 197 ) 198 { 199 USBHC_MEM_BLOCK *Head; 200 USBHC_MEM_BLOCK *Block; 201 UINTN AllocSize; 202 EFI_PHYSICAL_ADDRESS PhyAddr; 203 UINTN Offset; 204 205 Head = Pool->Head; 206 AllocSize = USBHC_MEM_ROUND (Size); 207 208 if (Mem == NULL) { 209 return 0; 210 } 211 212 for (Block = Head; Block != NULL; Block = Block->Next) { 213 // 214 // scan the memory block list for the memory block that 215 // completely contains the allocated memory. 216 // 217 if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) { 218 break; 219 } 220 } 221 222 ASSERT ((Block != NULL)); 223 // 224 // calculate the pci memory address for host memory address. 225 // 226 Offset = (UINT8 *) Mem - Block->BufHost; 227 PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->Buf + Offset); 228 return PhyAddr; 229 } 230 231 /** 232 Calculate the corresponding host address according to the pci address. 233 234 @param Pool The memory pool of the host controller. 235 @param Mem The pointer to pci memory. 236 @param Size The size of the memory region. 237 238 @return The host memory address 239 240 **/ 241 EFI_PHYSICAL_ADDRESS 242 UsbHcGetHostAddrForPciAddr ( 243 IN USBHC_MEM_POOL *Pool, 244 IN VOID *Mem, 245 IN UINTN Size 246 ) 247 { 248 USBHC_MEM_BLOCK *Head; 249 USBHC_MEM_BLOCK *Block; 250 UINTN AllocSize; 251 EFI_PHYSICAL_ADDRESS HostAddr; 252 UINTN Offset; 253 254 Head = Pool->Head; 255 AllocSize = USBHC_MEM_ROUND (Size); 256 257 if (Mem == NULL) { 258 return 0; 259 } 260 261 for (Block = Head; Block != NULL; Block = Block->Next) { 262 // 263 // scan the memory block list for the memory block that 264 // completely contains the allocated memory. 265 // 266 if ((Block->Buf <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->Buf + Block->BufLen))) { 267 break; 268 } 269 } 270 271 ASSERT ((Block != NULL)); 272 // 273 // calculate the host memory address for pci memory address. 274 // 275 Offset = (UINT8 *) Mem - Block->Buf; 276 HostAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->BufHost + Offset); 277 return HostAddr; 278 } 279 280 /** 281 Insert the memory block to the pool's list of the blocks. 282 283 @param Head The head of the memory pool's block list. 284 @param Block The memory block to insert. 285 286 **/ 287 VOID 288 UsbHcInsertMemBlockToPool ( 289 IN USBHC_MEM_BLOCK *Head, 290 IN USBHC_MEM_BLOCK *Block 291 ) 292 { 293 ASSERT ((Head != NULL) && (Block != NULL)); 294 Block->Next = Head->Next; 295 Head->Next = Block; 296 } 297 298 /** 299 Is the memory block empty? 300 301 @param Block The memory block to check. 302 303 @retval TRUE The memory block is empty. 304 @retval FALSE The memory block isn't empty. 305 306 **/ 307 BOOLEAN 308 UsbHcIsMemBlockEmpty ( 309 IN USBHC_MEM_BLOCK *Block 310 ) 311 { 312 UINTN Index; 313 314 for (Index = 0; Index < Block->BitsLen; Index++) { 315 if (Block->Bits[Index] != 0) { 316 return FALSE; 317 } 318 } 319 320 return TRUE; 321 } 322 323 /** 324 Unlink the memory block from the pool's list. 325 326 @param Head The block list head of the memory's pool. 327 @param BlockToUnlink The memory block to unlink. 328 329 **/ 330 VOID 331 UsbHcUnlinkMemBlock ( 332 IN USBHC_MEM_BLOCK *Head, 333 IN USBHC_MEM_BLOCK *BlockToUnlink 334 ) 335 { 336 USBHC_MEM_BLOCK *Block; 337 338 ASSERT ((Head != NULL) && (BlockToUnlink != NULL)); 339 340 for (Block = Head; Block != NULL; Block = Block->Next) { 341 if (Block->Next == BlockToUnlink) { 342 Block->Next = BlockToUnlink->Next; 343 BlockToUnlink->Next = NULL; 344 break; 345 } 346 } 347 } 348 349 /** 350 Initialize the memory management pool for the host controller. 351 352 @return Pointer to the allocated memory pool or NULL if failed. 353 354 **/ 355 USBHC_MEM_POOL * 356 UsbHcInitMemPool ( 357 VOID 358 ) 359 { 360 USBHC_MEM_POOL *Pool; 361 UINTN PageNumber; 362 EFI_STATUS Status; 363 EFI_PHYSICAL_ADDRESS TempPtr; 364 365 PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_POOL)); 366 Status = PeiServicesAllocatePages ( 367 EfiBootServicesData, 368 PageNumber, 369 &TempPtr 370 ); 371 if (EFI_ERROR (Status)) { 372 return NULL; 373 } 374 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber)); 375 376 Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr); 377 Pool->Head = UsbHcAllocMemBlock (USBHC_MEM_DEFAULT_PAGES); 378 379 if (Pool->Head == NULL) { 380 // 381 // No free memory in PEI. 382 // 383 Pool = NULL; 384 } 385 386 return Pool; 387 } 388 389 /** 390 Release the memory management pool. 391 392 @param Pool The USB memory pool to free. 393 394 **/ 395 VOID 396 UsbHcFreeMemPool ( 397 IN USBHC_MEM_POOL *Pool 398 ) 399 { 400 USBHC_MEM_BLOCK *Block; 401 402 ASSERT (Pool->Head != NULL); 403 404 // 405 // Unlink all the memory blocks from the pool, then free them. 406 // UsbHcUnlinkMemBlock can't be used to unlink and free the 407 // first block. 408 // 409 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) { 410 //UsbHcUnlinkMemBlock (Pool->Head, Block); 411 UsbHcFreeMemBlock (Pool, Block); 412 } 413 414 UsbHcFreeMemBlock (Pool, Pool->Head); 415 } 416 417 /** 418 Allocate some memory from the host controller's memory pool 419 which can be used to communicate with host controller. 420 421 @param Pool The host controller's memory pool. 422 @param Size Size of the memory to allocate. 423 424 @return The allocated memory or NULL. 425 426 **/ 427 VOID * 428 UsbHcAllocateMem ( 429 IN USBHC_MEM_POOL *Pool, 430 IN UINTN Size 431 ) 432 { 433 USBHC_MEM_BLOCK *Head; 434 USBHC_MEM_BLOCK *Block; 435 USBHC_MEM_BLOCK *NewBlock; 436 VOID *Mem; 437 UINTN AllocSize; 438 UINTN Pages; 439 440 Mem = NULL; 441 AllocSize = USBHC_MEM_ROUND (Size); 442 Head = Pool->Head; 443 ASSERT (Head != NULL); 444 445 // 446 // First check whether current memory blocks can satisfy the allocation. 447 // 448 for (Block = Head; Block != NULL; Block = Block->Next) { 449 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT); 450 451 if (Mem != NULL) { 452 ZeroMem (Mem, Size); 453 break; 454 } 455 } 456 457 if (Mem != NULL) { 458 return Mem; 459 } 460 461 // 462 // Create a new memory block if there is not enough memory 463 // in the pool. If the allocation size is larger than the 464 // default page number, just allocate a large enough memory 465 // block. Otherwise allocate default pages. 466 // 467 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) { 468 Pages = EFI_SIZE_TO_PAGES (AllocSize); 469 } else { 470 Pages = USBHC_MEM_DEFAULT_PAGES; 471 } 472 NewBlock = UsbHcAllocMemBlock (Pages); 473 474 if (NewBlock == NULL) { 475 return NULL; 476 } 477 478 // 479 // Add the new memory block to the pool, then allocate memory from it 480 // 481 UsbHcInsertMemBlockToPool (Head, NewBlock); 482 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT); 483 484 if (Mem != NULL) { 485 ZeroMem (Mem, Size); 486 } 487 488 return Mem; 489 } 490 491 /** 492 Free the allocated memory back to the memory pool. 493 494 @param Pool The memory pool of the host controller. 495 @param Mem The memory to free. 496 @param Size The size of the memory to free. 497 498 **/ 499 VOID 500 UsbHcFreeMem ( 501 IN USBHC_MEM_POOL *Pool, 502 IN VOID *Mem, 503 IN UINTN Size 504 ) 505 { 506 USBHC_MEM_BLOCK *Head; 507 USBHC_MEM_BLOCK *Block; 508 UINT8 *ToFree; 509 UINTN AllocSize; 510 UINTN Byte; 511 UINTN Bit; 512 UINTN Count; 513 514 Head = Pool->Head; 515 AllocSize = USBHC_MEM_ROUND (Size); 516 ToFree = (UINT8 *) Mem; 517 518 for (Block = Head; Block != NULL; Block = Block->Next) { 519 // 520 // scan the memory block list for the memory block that 521 // completely contains the memory to free. 522 // 523 if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) { 524 // 525 // compute the start byte and bit in the bit array 526 // 527 Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8; 528 Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8; 529 530 // 531 // reset associated bits in bit arry 532 // 533 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) { 534 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); 535 536 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit)); 537 NEXT_BIT (Byte, Bit); 538 } 539 540 break; 541 } 542 } 543 544 // 545 // If Block == NULL, it means that the current memory isn't 546 // in the host controller's pool. This is critical because 547 // the caller has passed in a wrong memory pointer 548 // 549 ASSERT (Block != NULL); 550 551 // 552 // Release the current memory block if it is empty and not the head 553 // 554 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) { 555 //UsbHcUnlinkMemBlock (Head, Block); 556 UsbHcFreeMemBlock (Pool, Block); 557 } 558 } 559 560 /** 561 Allocates pages at a specified alignment. 562 563 If Alignment is not a power of two and Alignment is not zero, then ASSERT(). 564 565 @param Pages The number of pages to allocate. 566 @param Alignment The requested alignment of the allocation. Must be a power of two. 567 @param HostAddress The system memory address to map to the PCI controller. 568 @param DeviceAddress The resulting map address for the bus master PCI controller to 569 use to access the hosts HostAddress. 570 571 @retval EFI_SUCCESS Success to allocate aligned pages. 572 @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid. 573 @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory. 574 575 **/ 576 EFI_STATUS 577 UsbHcAllocateAlignedPages ( 578 IN UINTN Pages, 579 IN UINTN Alignment, 580 OUT VOID **HostAddress, 581 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress 582 ) 583 { 584 EFI_STATUS Status; 585 EFI_PHYSICAL_ADDRESS Memory; 586 UINTN AlignedMemory; 587 UINTN AlignmentMask; 588 UINTN RealPages; 589 590 // 591 // Alignment must be a power of two or zero. 592 // 593 ASSERT ((Alignment & (Alignment - 1)) == 0); 594 595 if ((Alignment & (Alignment - 1)) != 0) { 596 return EFI_INVALID_PARAMETER; 597 } 598 599 if (Pages == 0) { 600 return EFI_INVALID_PARAMETER; 601 } 602 603 if (Alignment > EFI_PAGE_SIZE) { 604 // 605 // Calculate the total number of pages since alignment is larger than page size. 606 // 607 AlignmentMask = Alignment - 1; 608 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); 609 // 610 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. 611 // 612 ASSERT (RealPages > Pages); 613 614 Status = PeiServicesAllocatePages ( 615 EfiBootServicesData, 616 Pages, 617 &Memory 618 ); 619 if (EFI_ERROR (Status)) { 620 return EFI_OUT_OF_RESOURCES; 621 } 622 AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask; 623 } else { 624 // 625 // Do not over-allocate pages in this case. 626 // 627 Status = PeiServicesAllocatePages ( 628 EfiBootServicesData, 629 Pages, 630 &Memory 631 ); 632 if (EFI_ERROR (Status)) { 633 return EFI_OUT_OF_RESOURCES; 634 } 635 AlignedMemory = (UINTN) Memory; 636 } 637 638 *HostAddress = (VOID *) AlignedMemory; 639 *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedMemory; 640 641 return EFI_SUCCESS; 642 } 643 644 /** 645 Frees memory that was allocated with UsbHcAllocateAlignedPages(). 646 647 @param HostAddress The system memory address to map to the PCI controller. 648 @param Pages The number of pages to free. 649 650 **/ 651 VOID 652 UsbHcFreeAlignedPages ( 653 IN VOID *HostAddress, 654 IN UINTN Pages 655 ) 656 { 657 ASSERT (Pages != 0); 658 // 659 // No free memory in PEI. 660 // 661 } 662 663