/* Implementation of block I/O write */ STATIC EFI_STATUS RamDiskWriteBlocks( IN EFI_BLOCK_IO *This, IN UINT32 MediaId, IN EFI_LBA LBA, IN UINTN BufferSize, IN VOID *Buffer) { EFI_BLOCK_IO_MEDIA *Media; RAM_DISK_DEV *RamDiskDev; EFI_PHYSICAL_ADDRESS RamDiskLBA; Media = This->Media; if(Media->ReadOnly) return EFI_WRITE_PROTECTED; if(BufferSize % Media->BlockSize != 0) return EFI_BAD_BUFFER_SIZE; if(LBA > Media->LastBlock) return EFI_DEVICE_ERROR; if(LBA + BufferSize / Media->BlockSize - 1 > Media->LastBlock) return EFI_DEVICE_ERROR; RamDiskDev = RAM_DISK_FROM_THIS(This); RamDiskLBA = RamDiskDev->Start + MultU64x32(LBA,Media->BlockSize); CopyMem((VOID*)(UINTN)RamDiskLBA,Buffer,BufferSize); return EFI_SUCCESS; }
/** Write by using the Disk IO protocol on the parent device. Lba addresses must be converted to byte offsets. @param[in] This Protocol instance pointer. @param[in] MediaId Id of the media, changes every time the media is replaced. @param[in] Lba The starting Logical Block Address to read from @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[in] Buffer Buffer containing data to be written to device. @retval EFI_SUCCESS The data was written correctly to the device. @retval EFI_WRITE_PROTECTED The device can not be written to. @retval EFI_DEVICE_ERROR The device reported an error while performing the write. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not valid for the device. **/ EFI_STATUS EFIAPI PartitionWriteBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, IN VOID *Buffer ) { PARTITION_PRIVATE_DATA *Private; UINT64 Offset; Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This); if (BufferSize % Private->BlockSize != 0) { return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE); } Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; if (Offset + BufferSize > Private->End) { return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER); } // // Because some kinds of partition have different block size from their parent // device, we call the Disk IO protocol on the parent device, not the Block IO // protocol // return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer); }
EFIAPI AcquireSpinLock ( IN OUT SPIN_LOCK *SpinLock ) { UINT64 Tick; UINT64 Start, End; UINT64 Timeout; Tick = 0; Start = 0; End = 0; if (PcdGet32 (PcdSpinLockTimeout) > 0) { Tick = GetPerformanceCounter (); Timeout = DivU64x32 ( MultU64x32 ( GetPerformanceCounterProperties (&Start, &End), PcdGet32 (PcdSpinLockTimeout) ), 1000000 ); if (Start < End) { Tick += Timeout; } else { Tick -= Timeout; } } while (!AcquireSpinLockOrFail (SpinLock)) { CpuPause (); ASSERT ((Start < End) ^ (Tick <= GetPerformanceCounter ())); } return SpinLock; }
/** This function retrieves the period of timer interrupts in 100 ns units, returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is returned, then the timer is currently disabled. @param This The EFI_TIMER_ARCH_PROTOCOL instance. @param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. If 0 is returned, then the timer is currently disabled. @retval EFI_SUCCESS The timer period was returned in TimerPeriod. @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. **/ EFI_STATUS EFIAPI SP805GetTimerPeriod ( IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, OUT UINT64 *TimerPeriod ) { EFI_STATUS Status = EFI_SUCCESS; UINT64 ReturnValue; if (TimerPeriod == NULL) { return EFI_INVALID_PARAMETER; } // Check if the watchdog is stopped if ( (MmioRead32(SP805_WDOG_CONTROL_REG) & SP805_WDOG_CTRL_INTEN) == 0 ) { // It is stopped, so return zero. ReturnValue = 0; } else { // Convert the Watchdog ticks into TimerPeriod // Ensure 64bit arithmetic throughout because the Watchdog ticks may already // be at the maximum 32 bit value and we still need to multiply that by 600. ReturnValue = MultU64x32( MmioRead32(SP805_WDOG_LOAD_REG), 600 ); } *TimerPeriod = ReturnValue; return Status; }
/** Reads the specified number of bytes into a buffer from the specified block. The Read() function reads the requested number of bytes from the requested block and stores them in the provided buffer. Implementations should be mindful that the firmware volume might be in the ReadDisabled state. If it is in this state, the Read() function must return the status code EFI_ACCESS_DENIED without modifying the contents of the buffer. The Read() function must also prevent spanning block boundaries. If a read is requested that would span a block boundary, the read must read up to the boundary but not beyond. The output parameter NumBytes must be set to correctly indicate the number of bytes actually read. The caller must be aware that a read may be partially completed. @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. @param Lba The starting logical block index from which to read. @param Offset Offset into the block at which to begin reading. @param NumBytes Pointer to a UINTN. At entry, *NumBytes contains the total size of the buffer. At exit, *NumBytes contains the total number of bytes read. @param Buffer Pointer to a caller-allocated buffer that will be used to hold the data that is read. @retval EFI_SUCCESS The firmware volume was read successfully and contents are in Buffer. @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary. On output, NumBytes contains the total number of bytes returned in Buffer. @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be read. **/ EFI_STATUS EFIAPI FvbProtocolRead ( IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Offset, IN OUT UINTN *NumBytes, IN OUT UINT8 *Buffer ) { EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; UINT8 *FvbDataPtr; FvbDevice = FVB_DEVICE_FROM_THIS (This); if ((Lba > 1) || (Offset > FvbDevice->BlockSize)) { return EFI_INVALID_PARAMETER; } if ((Offset + *NumBytes) > FvbDevice->BlockSize) { *NumBytes = FvbDevice->BlockSize - Offset; } FvbDataPtr = (UINT8*) FvbDevice->BufferPtr + MultU64x32 (Lba, (UINT32) FvbDevice->BlockSize) + Offset; if (*NumBytes > 0) { CopyMem (Buffer, FvbDataPtr, *NumBytes); PlatformFvbDataRead (This, Lba, Offset, *NumBytes, Buffer); } return EFI_SUCCESS; }
/** Gets the next cluster in the cluster chain @param PrivateData Global memory map for accessing global variables @param Volume The volume @param Cluster The cluster @param NextCluster The cluster number of the next cluster @retval EFI_SUCCESS The address is got @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. @retval EFI_DEVICE_ERROR Read disk error **/ EFI_STATUS FatGetNextCluster ( IN PEI_FAT_PRIVATE_DATA *PrivateData, IN PEI_FAT_VOLUME *Volume, IN UINT32 Cluster, OUT UINT32 *NextCluster ) { EFI_STATUS Status; UINT64 FatEntryPos; UINT32 Dummy; *NextCluster = 0; if (Volume->FatType == Fat32) { FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster); Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster); *NextCluster &= 0x0fffffff; // // Pad high bits for our FAT_CLUSTER_... macro definitions to work // if ((*NextCluster) >= 0x0ffffff7) { *NextCluster |= (-1 &~0xf); } } else if (Volume->FatType == Fat16) { FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster); Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster); // // Pad high bits for our FAT_CLUSTER_... macro definitions to work // if ((*NextCluster) >= 0xfff7) { *NextCluster |= (-1 &~0xf); } } else { FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy); Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster); if ((Cluster & 0x01) != 0) { *NextCluster = (*NextCluster) >> 4; } else {
/** This function adjusts the period of timer interrupts to the value specified by TimerPeriod. If the timer period is updated, then the selected timer period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. If an error occurs while attempting to update the timer period, then the timer hardware will be put back in its state prior to this call, and EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt is disabled. This is not the same as disabling the CPU's interrupts. Instead, it must either turn off the timer hardware, or it must adjust the interrupt controller so that a CPU interrupt is not generated when the timer interrupt fires. @param This The EFI_TIMER_ARCH_PROTOCOL instance. @param TimerPeriod The rate to program the timer interrupt in 100 nS units. If the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. If the timer is programmable, then the timer period will be rounded up to the nearest timer period that is supported by the timer hardware. If TimerPeriod is set to 0, then the timer interrupts will be disabled. @retval EFI_SUCCESS The timer period was changed. @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt. @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error. **/ STATIC EFI_STATUS EFIAPI SP805SetTimerPeriod ( IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, IN UINT64 TimerPeriod // In 100ns units ) { EFI_STATUS Status; UINT64 Ticks64bit; SP805Unlock (); Status = EFI_SUCCESS; if (TimerPeriod == 0) { // This is a watchdog stop request SP805Stop (); } else { // Calculate the Watchdog ticks required for a delay of (TimerTicks * 100) nanoseconds // The SP805 will count down to zero and generate an interrupt. // // WatchdogTicks = ((TimerPeriod * 100 * SP805_CLOCK_FREQUENCY) / 1GHz); // // i.e.: // // WatchdogTicks = (TimerPeriod * SP805_CLOCK_FREQUENCY) / 10 MHz ; Ticks64bit = MultU64x32 (TimerPeriod, PcdGet32 (PcdSP805WatchdogClockFrequencyInHz)); Ticks64bit = DivU64x32 (Ticks64bit, 10 * 1000 * 1000); // The registers in the SP805 are only 32 bits if (Ticks64bit > MAX_UINT32) { // We could load the watchdog with the maximum supported value but // if a smaller value was requested, this could have the watchdog // triggering before it was intended. // Better generate an error to let the caller know. Status = EFI_DEVICE_ERROR; goto EXIT; } // Update the watchdog with a 32-bit value. MmioWrite32 (SP805_WDOG_LOAD_REG, (UINT32)Ticks64bit); // Start the watchdog SP805Start (); } mTimerPeriod = TimerPeriod; EXIT: // Ensure the watchdog is locked before exiting. SP805Lock (); ASSERT_EFI_ERROR (Status); return Status; }
/** Calculate the Duration in microseconds. Duration is multiplied by 1000, instead of Frequency being divided by 1000 or multiplying the result by 1000, in order to maintain precision. Since Duration is a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow. The time is calculated as (Duration * 1000) / Timer_Frequency. @param[in] Duration The event duration in timer ticks. @return A 64-bit value which is the Elapsed time in microseconds. **/ UINT64 DurationInMicroSeconds ( IN UINT64 Duration ) { UINT64 Temp; Temp = MultU64x32 (Duration, 1000); return DivU64x32 (Temp, TimerInfo.Frequency); }
/** Install child handles if the Handle supports GPT partition structure. @param[in] BlockIo Parent BlockIo interface. @param[in] DiskIo Disk Io protocol. @param[in] Lba The starting Lba of the Partition Table @param[out] PartHeader Stores the partition table that is read @retval TRUE The partition table is valid @retval FALSE The partition table is not valid **/ BOOLEAN PartitionValidGptTable ( IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_LBA Lba, OUT EFI_PARTITION_TABLE_HEADER *PartHeader ) { EFI_STATUS Status; UINT32 BlockSize; EFI_PARTITION_TABLE_HEADER *PartHdr; UINT32 MediaId; BlockSize = BlockIo->Media->BlockSize; MediaId = BlockIo->Media->MediaId; PartHdr = AllocateZeroPool (BlockSize); if (PartHdr == NULL) { DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); return FALSE; } // // Read the EFI Partition Table Header // Status = DiskIo->ReadDisk ( DiskIo, MediaId, MultU64x32 (Lba, BlockSize), BlockSize, PartHdr ); if (EFI_ERROR (Status)) { FreePool (PartHdr); return FALSE; } if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) || !PartitionCheckCrc (BlockSize, &PartHdr->Header) || PartHdr->MyLBA != Lba ) { DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n")); FreePool (PartHdr); return FALSE; } CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER)); if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) { FreePool (PartHdr); return FALSE; } DEBUG ((EFI_D_INFO, " Valid efi partition table header\n")); FreePool (PartHdr); return TRUE; }
/** This function adjusts the period of timer interrupts to the value specified by TimerPeriod. If the timer period is updated, then the selected timer period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. If an error occurs while attempting to update the timer period, then the timer hardware will be put back in its state prior to this call, and EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt is disabled. This is not the same as disabling the CPU's interrupts. Instead, it must either turn off the timer hardware, or it must adjust the interrupt controller so that a CPU interrupt is not generated when the timer interrupt fires. @param This The EFI_TIMER_ARCH_PROTOCOL instance. @param TimerPeriod The rate to program the timer interrupt in 100 nS units. If the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. If the timer is programmable, then the timer period will be rounded up to the nearest timer period that is supported by the timer hardware. If TimerPeriod is set to 0, then the timer interrupts will be disabled. @retval EFI_SUCCESS The timer period was changed. @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt. @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error. **/ EFI_STATUS EFIAPI SP805SetTimerPeriod ( IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, IN UINT64 TimerPeriod // In 100ns units ) { EFI_STATUS Status = EFI_SUCCESS; UINT64 Ticks64bit; SP805Unlock(); if( TimerPeriod == 0 ) { // This is a watchdog stop request SP805Stop(); goto EXIT; } else { // Calculate the Watchdog ticks required for a delay of (TimerTicks * 100) nanoseconds // The SP805 will count down to ZERO once, generate an interrupt and // then it will again reload the initial value and start again. // On the second time when it reaches ZERO, it will actually reset the board. // Therefore, we need to load half the required delay. // // WatchdogTicks = ((TimerPeriod * 100 * SP805_CLOCK_FREQUENCY) / 1GHz) / 2 ; // // i.e.: // // WatchdogTicks = (TimerPeriod * SP805_CLOCK_FREQUENCY) / 20 MHz ; Ticks64bit = DivU64x32(MultU64x32(TimerPeriod, (UINTN)PcdGet32(PcdSP805WatchdogClockFrequencyInHz)), 20000000); // The registers in the SP805 are only 32 bits if(Ticks64bit > (UINT64)0xFFFFFFFF) { // We could load the watchdog with the maximum supported value but // if a smaller value was requested, this could have the watchdog // triggering before it was intended. // Better generate an error to let the caller know. Status = EFI_DEVICE_ERROR; goto EXIT; } // Update the watchdog with a 32-bit value. MmioWrite32(SP805_WDOG_LOAD_REG, (UINT32)Ticks64bit); // Start the watchdog SP805Start(); } EXIT: // Ensure the watchdog is locked before exiting. SP805Lock(); return Status; }
/** Write BufferSize bytes from Lba into Buffer. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId The media ID that the write request is for. @param[in] Lba The starting logical block address to be written. The caller is responsible for writing to only legitimate locations. @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[in] Buffer A pointer to the source buffer for the data. @retval EFI_SUCCESS The data was written correctly to the device. @retval EFI_WRITE_PROTECTED The device can not be written to. @retval EFI_DEVICE_ERROR The device reported an error while performing the write. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, or the buffer is not on proper alignment. **/ EFI_STATUS EFIAPI RamDiskBlkIoWriteBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, IN VOID *Buffer ) { RAM_DISK_PRIVATE_DATA *PrivateData; UINTN NumberOfBlocks; PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This); if (MediaId != PrivateData->Media.MediaId) { return EFI_MEDIA_CHANGED; } if (TRUE == PrivateData->Media.ReadOnly) { return EFI_WRITE_PROTECTED; } if (Buffer == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize == 0) { return EFI_SUCCESS; } if ((BufferSize % PrivateData->Media.BlockSize) != 0) { return EFI_BAD_BUFFER_SIZE; } if (Lba > PrivateData->Media.LastBlock) { return EFI_INVALID_PARAMETER; } NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize; if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) { return EFI_INVALID_PARAMETER; } CopyMem ( (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)), Buffer, BufferSize ); return EFI_SUCCESS; }
/** Write BufferSize bytes from Lba into Buffer. This function writes the requested number of blocks to the device. All blocks are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA, EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is being used, the Event associated with this request will not be signaled. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId The media ID that the write request is for. @param[in] Lba The starting logical block address to be written. The caller is responsible for writing to only legitimate locations. @param[in, out] Token A pointer to the token associated with the transaction. @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[in] Buffer A pointer to the source buffer for the data. @retval EFI_SUCCESS The write request was queued if Event is not NULL. The data was written correctly to the device if the Event is NULL. @retval EFI_WRITE_PROTECTED The device can not be written to. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. @retval EFI_DEVICE_ERROR The device reported an error while performing the write. @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, or the buffer is not on proper alignment. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. **/ EFI_STATUS EFIAPI PartitionWriteBlocksEx ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN OUT EFI_BLOCK_IO2_TOKEN *Token, IN UINTN BufferSize, IN VOID *Buffer ) { PARTITION_PRIVATE_DATA *Private; UINT64 Offset; UINT32 UnderRun; Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); if (Token == NULL) { return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER); } if (BufferSize % Private->BlockSize != 0) { return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE); } Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; if (Offset + BufferSize > Private->End) { return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER); } // // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must // be multiple of BlockSize. If the Spec will be updated the DiskIO to support // BlockIO2, this limitation will be removed and call DiskIO here. // Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun); if (UnderRun != 0) { return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED); } // // Because some kinds of partition have different block size from their parent, // in that case it couldn't call parent Block I/O2. // if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) { return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED); } return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer); }
/** Convert ASCII numeric string to a UINTN value. @param Buffer Pointer to the 8-byte unsigned int value. @return UINTN value of the ASCII string. **/ UINT64 AtoU64 ( IN UINT8 *Buffer ) { UINT64 Value; UINT8 Character; Value = 0; while ((Character = *Buffer++) != '\0') { Value = MultU64x32 (Value, 10) + (Character - '0'); } return Value; }
/** Print information about the Blk IO devices. If the device supports PXE dump out extra information @param File Open File for the device **/ VOID EblPrintBlkIoInfo ( IN EFI_OPEN_FILE *File ) { UINT64 DeviceSize; UINTN Index; UINTN Max; EFI_OPEN_FILE *FsFile; if (File == NULL) { return; } AsciiPrint (" %a: ", File->DeviceName); // print out name of file system, if any, on this block device Max = EfiGetDeviceCounts (EfiOpenFileSystem); if (Max != 0) { for (Index = 0; Index < Max; Index++) { FsFile = EfiDeviceOpenByType (EfiOpenFileSystem, Index); if (FsFile != NULL) { if (FsFile->EfiHandle == File->EfiHandle) { AsciiPrint ("fs%d: ", Index); EfiClose (FsFile); break; } EfiClose (FsFile); } } } // Print out useful Block IO media properties if (File->FsBlockIoMedia->RemovableMedia) { AsciiPrint ("Removable "); } if (!File->FsBlockIoMedia->MediaPresent) { AsciiPrint ("No Media\n"); } else { if (File->FsBlockIoMedia->LogicalPartition) { AsciiPrint ("Partition "); } DeviceSize = MultU64x32 (File->FsBlockIoMedia->LastBlock + 1, File->FsBlockIoMedia->BlockSize); AsciiPrint ("Size = 0x%lX\n", DeviceSize); } EfiClose (File); }
/** Stalls the CPU for at least the given number of nanoseconds. Stalls the CPU for the number of nanoseconds specified by NanoSeconds. @param NanoSeconds The minimum number of nanoseconds to delay. @return NanoSeconds **/ UINTN EFIAPI NanoSecondDelay ( IN UINTN NanoSeconds ) { InternalAcpiDelay ( (UINT32)DivU64x32 ( MultU64x32 ( NanoSeconds, ACPI_TIMER_FREQUENCY ), 1000000000u ) ); return NanoSeconds; }
UINT64 InternalGetPerformanceCounterFrequency ( VOID ) { BOOLEAN InterruptState; UINT64 Count; if (mPerformanceCounterFrequency == 0) { InterruptState = SaveAndDisableInterrupts (); Count = GetPerformanceCounter (); MicroSecondDelay (100); mPerformanceCounterFrequency = MultU64x32 (GetPerformanceCounter () - Count, 10000); SetInterruptState (InterruptState); } return mPerformanceCounterFrequency; }
EFI_STATUS EFIAPI UnixMetronomeDriverWaitForTick ( IN EFI_METRONOME_ARCH_PROTOCOL *This, IN UINT32 TickNumber ) /*++ Routine Description: The WaitForTick() function waits for the number of ticks specified by TickNumber from a known time source in the platform. If TickNumber of ticks are detected, then EFI_SUCCESS is returned. The actual time passed between entry of this function and the first tick is between 0 and TickPeriod 100 nS units. If you want to guarantee that at least TickPeriod time has elapsed, wait for two ticks. This function waits for a hardware event to determine when a tick occurs. It is possible for interrupt processing, or exception processing to interrupt the execution of the WaitForTick() function. Depending on the hardware source for the ticks, it is possible for a tick to be missed. This function cannot guarantee that ticks will not be missed. If a timeout occurs waiting for the specified number of ticks, then EFI_TIMEOUT is returned. Arguments: This - The EFI_METRONOME_ARCH_PROTOCOL instance. TickNumber - Number of ticks to wait. Returns: EFI_SUCCESS - The wait for the number of ticks specified by TickNumber succeeded. --*/ { UINT64 SleepTime; // // Calculate the time to sleep. Win API smallest unit to sleep is 1 millisec // Tick Period is in 100ns units, divide by 10000 to convert to ms // SleepTime = DivU64x32 (MultU64x32 ((UINT64) TickNumber, TICK_PERIOD) + 9999, 10000); gUnix->Sleep ((UINT32) SleepTime); return EFI_SUCCESS; }
/** Stalls the CPU for at least the given number of microseconds. Stalls the CPU for the number of microseconds specified by MicroSeconds. @param MicroSeconds The minimum number of microseconds to delay. @return MicroSeconds **/ UINTN EFIAPI MicroSecondDelay ( IN UINTN MicroSeconds ) { InternalAcpiDelay ( (UINT32)DivU64x32 ( MultU64x32 ( MicroSeconds, V_ACPI_TMR_FREQUENCY ), 1000000u ) ); return MicroSeconds; }
/** Check if the CRC field in the Partition table header is valid for Partition entry array. @param[in] BlockIo Parent BlockIo interface @param[in] DiskIo Disk Io Protocol. @param[in] PartHeader Partition table header structure @retval TRUE the CRC is valid @retval FALSE the CRC is invalid **/ BOOLEAN PartitionCheckGptEntryArrayCRC ( IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_PARTITION_TABLE_HEADER *PartHeader ) { EFI_STATUS Status; UINT8 *Ptr; UINT32 Crc; UINTN Size; // // Read the EFI Partition Entries // Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry); if (Ptr == NULL) { DEBUG ((EFI_D_ERROR, " Allocate pool error\n")); return FALSE; } Status = DiskIo->ReadDisk ( DiskIo, BlockIo->Media->MediaId, MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, Ptr ); if (EFI_ERROR (Status)) { FreePool (Ptr); return FALSE; } Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry; Status = gBS->CalculateCrc32 (Ptr, Size, &Crc); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n")); FreePool (Ptr); return FALSE; } FreePool (Ptr); return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc); }
/** Internal function to add memory pool operation to the table. @param Marker The variable argument list to get the opcode and associated attributes. @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation. @retval EFI_SUCCESS Opcode is added. **/ EFI_STATUS BootScriptMemPoll ( IN VA_LIST Marker ) { EFI_BOOT_SCRIPT_WIDTH Width; UINT64 Address; UINT8 *BitMask; UINT8 *BitValue; UINT64 Duration; UINT64 LoopTimes; UINT64 Delay; Width = VA_ARG (Marker, EFI_BOOT_SCRIPT_WIDTH); Address = VA_ARG (Marker, UINT64); BitMask = VA_ARG (Marker, UINT8 *); BitValue = VA_ARG (Marker, UINT8 *); Duration = (UINT64)VA_ARG (Marker, UINT64); LoopTimes = (UINT64)VA_ARG (Marker, UINT64); // // Framework version: Duration is used for Stall(), which is Microseconds. // Total time is: Duration(Microseconds) * LoopTimes. // PI version: Duration is always 100ns. Delay is LoopTimes. // Total time is: 100ns * Delay. // So Delay = Duration(Microseconds) * LoopTimes / 100ns // = Duration * 1000ns * LoopTimes / 100ns // = Duration * 10 * LoopTimes // Delay = MultU64x64 (MultU64x32 (Duration, 10), LoopTimes); // // Framework version: First BitMask, then BitValue // PI version: First Data, then DataMask // So we revert their order in function call // return mS3SaveState->Write ( mS3SaveState, EFI_BOOT_SCRIPT_MEM_POLL_OPCODE, Width, Address, BitValue, BitMask, Delay ); }
/** Read BufferSize bytes from Lba into Buffer. This function reads the requested number of blocks from the device. All the blocks are read, or an error is returned. If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and non-blocking I/O is being used, the Event associated with this request will not be signaled. @param[in] This Indicates a pointer to the calling context. @param[in] MediaId Id of the media, changes every time the media is replaced. @param[in] Lba The starting Logical Block Address to read from. @param[in, out] Token A pointer to the token associated with the transaction. @param[in] BufferSize Size of Buffer, must be a multiple of device block size. @param[out] Buffer A pointer to the destination buffer for the data. The caller is responsible for either having implicit or explicit ownership of the buffer. @retval EFI_SUCCESS The read request was queued if Token->Event is not NULL.The data was read correctly from the device if the Token->Event is NULL. @retval EFI_DEVICE_ERROR The device reported an error while performing the read. @retval EFI_NO_MEDIA There is no media in the device. @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, or the buffer is not on proper alignment. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. **/ EFI_STATUS EFIAPI PartitionReadBlocksEx ( IN EFI_BLOCK_IO2_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN OUT EFI_BLOCK_IO2_TOKEN *Token, IN UINTN BufferSize, OUT VOID *Buffer ) { EFI_STATUS Status; PARTITION_PRIVATE_DATA *Private; UINT64 Offset; PARTITION_ACCESS_TASK *Task; Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); if (BufferSize % Private->BlockSize != 0) { return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE); } Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; if (Offset + BufferSize > Private->End) { return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER); } if ((Token != NULL) && (Token->Event != NULL)) { Task = PartitionCreateAccessTask (Token); if (Task == NULL) { return EFI_OUT_OF_RESOURCES; } Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer); if (EFI_ERROR (Status)) { gBS->CloseEvent (Task->DiskIo2Token.Event); FreePool (Task); } } else { Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer); } return Status; }
UINTN EFIAPI MicroSecondDelay ( IN UINTN MicroSeconds ) { UINT64 NanoSeconds; NanoSeconds = MultU64x32(MicroSeconds, 1000); while (NanoSeconds > (UINTN)-1) { NanoSecondDelay((UINTN)-1); NanoSeconds -= (UINTN)-1; } NanoSecondDelay(NanoSeconds); return MicroSeconds; }
/** This function adjusts the period of timer interrupts to the value specified by TimerPeriod. If the timer period is updated, then the selected timer period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. If an error occurs while attempting to update the timer period, then the timer hardware will be put back in its state prior to this call, and EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt is disabled. This is not the same as disabling the CPU's interrupts. Instead, it must either turn off the timer hardware, or it must adjust the interrupt controller so that a CPU interrupt is not generated when the timer interrupt fires. @param This The EFI_TIMER_ARCH_PROTOCOL instance. @param TimerPeriod The rate to program the timer interrupt in 100 nS units. If the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. If the timer is programmable, then the timer period will be rounded up to the nearest timer period that is supported by the timer hardware. If TimerPeriod is set to 0, then the timer interrupts will be disabled. @retval EFI_SUCCESS The timer period was changed. @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt. @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error. **/ EFI_STATUS EFIAPI TimerDriverSetTimerPeriod ( IN EFI_TIMER_ARCH_PROTOCOL *This, IN UINT64 TimerPeriod ) { EFI_STATUS Status; UINT64 TimerTicks; // always disable the timer MmioAnd32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, ~SP804_TIMER_CTRL_ENABLE); if (TimerPeriod == 0) { // Leave timer disabled from above, and... // Disable timer 0/1 interrupt for a TimerPeriod of 0 Status = gInterrupt->DisableInterruptSource (gInterrupt, gVector); } else { // Convert TimerPeriod into 1MHz clock counts (us units = 100ns units * 10) TimerTicks = DivU64x32 (TimerPeriod, 10); TimerTicks = MultU64x32 (TimerTicks, PcdGet32(PcdSP804TimerFrequencyInMHz)); // if it's larger than 32-bits, pin to highest value if (TimerTicks > 0xffffffff) { TimerTicks = 0xffffffff; } // Program the SP804 timer with the new count value MmioWrite32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_LOAD_REG, TimerTicks); // enable the timer MmioOr32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_ENABLE); // enable timer 0/1 interrupts Status = gInterrupt->EnableInterruptSource (gInterrupt, gVector); } // Save the new timer period mTimerPeriod = TimerPeriod; return Status; }
VOID GetCPUProperties (VOID) { UINT32 reg[4]; UINT64 msr = 0; EFI_STATUS Status; EFI_HANDLE *HandleBuffer; // EFI_GUID **ProtocolGuidArray; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE00 Pci; UINTN HandleCount; // UINTN ArrayCount; UINTN HandleIndex; // UINTN ProtocolIndex; UINT32 qpibusspeed; //units=kHz UINT32 qpimult = 2; UINT32 BusSpeed = 0; //units kHz UINT64 tmpU; UINT16 did, vid; UINTN Segment; UINTN Bus; UINTN Device; UINTN Function; CHAR8 str[128]; //initial values gCPUStructure.MaxRatio = 10; //keep it as K*10 gCPUStructure.MinRatio = 10; //same gCPUStructure.SubDivider = 0; //gCPUStructure.MaxSpeed = 0; gSettings.CpuFreqMHz = 0; gCPUStructure.FSBFrequency = MultU64x32(gCPUStructure.ExternalClock, kilo); //kHz -> Hz // gCPUStructure.CPUFrequency = 0; // gCPUStructure.TSCFrequency = MultU64x32(gCPUStructure.CurrentSpeed, Mega); //MHz -> Hz // gCPUStructure.CPUFrequency = gCPUStructure.TSCFrequency; gCPUStructure.ProcessorInterconnectSpeed = 0; gCPUStructure.Mobile = FALSE; //not same as gMobile if (!gCPUStructure.CurrentSpeed) { gCPUStructure.CurrentSpeed = (UINT32)DivU64x32(gCPUStructure.TSCCalibr + (Mega >> 1), Mega); }
/** Stalls the CPU for at least the given number of nanoseconds. Stalls the CPU for the number of nanoseconds specified by NanoSeconds. @param NanoSeconds The minimum number of nanoseconds to delay. @return NanoSeconds **/ UINTN EFIAPI NanoSecondDelay ( IN UINTN NanoSeconds ) { if (InternalGetApciDescrptionTable() == NULL) { return NanoSeconds; } InternalAcpiDelay ( (UINT32)DivU64x32 ( MultU64x32 ( NanoSeconds, 3579545 ), 1000000000u ) ); return NanoSeconds; }
EFI_STATUS EFIAPI EmuTimerDriverGetTimerPeriod ( IN EFI_TIMER_ARCH_PROTOCOL *This, OUT UINT64 *TimerPeriod ) /*++ Routine Description: This function retrieves the period of timer interrupts in 100 ns units, returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is returned, then the timer is currently disabled. Arguments: This - The EFI_TIMER_ARCH_PROTOCOL instance. TimerPeriod - A pointer to the timer period to retrieve in 100 ns units. If 0 is returned, then the timer is currently disabled. Returns: EFI_SUCCESS - The timer period was returned in TimerPeriod. EFI_INVALID_PARAMETER - TimerPeriod is NULL. **/ { if (TimerPeriod == NULL) { return EFI_INVALID_PARAMETER; } *TimerPeriod = MultU64x32 (mTimerPeriodMs, 10000); return EFI_SUCCESS; }
EFI_STATUS EFIAPI InitRDReadBlocks( IN EFI_BLOCK_IO *This, IN UINT32 MediaId, IN EFI_LBA LBA, IN UINTN BufferSize, OUT VOID *Buffer) { void* block_ptr; EFI_BLOCK_IO_MEDIA *Media = This->Media; if(BufferSize % Media->BlockSize != 0) return EFI_BAD_BUFFER_SIZE; if(LBA > Media->LastBlock) return EFI_DEVICE_ERROR; if(LBA + BufferSize / Media->BlockSize - 1 > Media->LastBlock) return EFI_DEVICE_ERROR; block_ptr = initrd_buf + MultU64x32(LBA,INITRD_BLOCKSIZE); memcpy(Buffer,block_ptr,BufferSize); return EFI_SUCCESS; }
VOID EFIAPI RegisterTimerArchProtocol ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **)&gTimerAp); if (!EFI_ERROR (Status)) { Status = gTimerAp->GetTimerPeriod (gTimerAp, &gTimerPeriod); ASSERT_EFI_ERROR (Status); // Convert to Nanoseconds. gTimerPeriod = MultU64x32 (gTimerPeriod, 100); if (gTimerEvent == NULL) { Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, (VOID **)&gTimerEvent); ASSERT_EFI_ERROR (Status); } } }
/** returns given time as miliseconds. * assumes 31 days per month, so it's not correct, * but is enough for basic checks. */ UINT64 GetEfiTimeInMs ( IN EFI_TIME *T ) { UINT64 TimeMs; TimeMs = T->Year - 1900; // is 64bit multiply workign in 32 bit? TimeMs = MultU64x32 (TimeMs, 12) + T->Month; TimeMs = MultU64x32 (TimeMs, 31) + T->Day; // counting with 31 day TimeMs = MultU64x32 (TimeMs, 24) + T->Hour; TimeMs = MultU64x32 (TimeMs, 60) + T->Minute; TimeMs = MultU64x32 (TimeMs, 60) + T->Second; TimeMs = MultU64x32 (TimeMs, 1000) + DivU64x32(T->Nanosecond, 1000000); return TimeMs; }
/** Stalls the CPU for the number of microseconds specified by MicroSeconds. @param MicroSeconds The minimum number of microseconds to delay. @return The value of MicroSeconds inputted. **/ UINTN EFIAPI MicroSecondDelay ( IN UINTN MicroSeconds ) { UINT64 TimerTicks64; UINT64 SystemCounterVal; // Calculate counter ticks that can represent requested delay TimerTicks64 = MultU64x32 (MicroSeconds, TICKS_PER_MICRO_SEC); // Read System Counter value SystemCounterVal = ArmArchTimerGetSystemCount (); TimerTicks64 += SystemCounterVal; // Wait until delay count is expired. while (SystemCounterVal < TimerTicks64) { SystemCounterVal = ArmArchTimerGetSystemCount (); } return MicroSeconds; }