mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-10 01:29:59 +00:00
387 lines
8.7 KiB
C
387 lines
8.7 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
mx6uart.c
|
|
|
|
Abstract:
|
|
|
|
This module contains support for the i.MX6 serial UART.
|
|
|
|
--*/
|
|
|
|
// ------------------------------------------------------------------- Includes
|
|
|
|
#include "common.h"
|
|
|
|
// ---------------------------------------------------------------- Definitions
|
|
|
|
#define MX6_UCR1_UARTEN (1 << 0)
|
|
#define MX6_UCR2_TXEN (1 << 2)
|
|
#define MX6_UCR2_RXEN (1 << 1)
|
|
#define MX6_UCR2_PREN (1 << 8)
|
|
#define MX6_UCR2_STPB (1 << 6)
|
|
#define MX6_UCR2_WRDSZ (1 << 5)
|
|
#define MX6_USR1_TRDY (1 << 13)
|
|
#define MX6_USR2_RDR (1 << 0)
|
|
#define MX6_RXD_CHARRDY (1 << 15)
|
|
#define MX6_RXD_ERR (1 << 14)
|
|
#define MX6_RXD_FRMERR (1 << 12)
|
|
#define MX6_RXD_PARERR (1 << 10)
|
|
#define MX6_RXD_DATA_MASK 0xFF
|
|
|
|
#define MX6_UFCR_TXTL_SHIFT 10
|
|
#define MX6_UFCR_TXTL_MAX 32
|
|
#define MX6_UFCR_TXTL_MASK 0x3F
|
|
|
|
#define MX6_USR1_PRTERRY_MASK (1 << 15)
|
|
#define MX6_USR1_ESCF_MASK (1 << 11)
|
|
#define MX6_USR1_FRMER_MASK (1 << 10)
|
|
#define MX6_USR1_AGTIM_MASK (1 << 8)
|
|
#define MX6_USR1_DTRD_MASK (1 << 7)
|
|
#define MX6_USR1_AIRINT_MASK (1 << 5)
|
|
#define MX6_USR1_AWAKE_MASK (1 << 4)
|
|
|
|
#define MX6_USR2_RDRDY_MASK 1
|
|
#define MX6_UTS_RXEMPTY_MASK (1 << 5)
|
|
|
|
// ----------------------------------------------------------------- Data Types
|
|
|
|
#include <pshpack1.h>
|
|
|
|
typedef struct _MX6_UART_REGISTERS
|
|
{
|
|
ULONG Rxd; // 0x00: UART Receiver Register
|
|
ULONG reserved1[15];
|
|
ULONG Txd; // 0x40: UART Transmitter Register
|
|
ULONG reserved2[15];
|
|
ULONG Ucr1; // 0x80: UART Control Register 1
|
|
ULONG Ucr2; // 0x84: UART Control Register 2
|
|
ULONG Ucr3; // 0x88: UART Control Register 3
|
|
ULONG Ucr4; // 0x8C: UART Control Register 4
|
|
ULONG Ufcr; // 0x90: UART FIFO Control Register
|
|
ULONG Usr1; // 0x94: UART Status Register 1
|
|
ULONG Usr2; // 0x98: UART Status Register 2
|
|
ULONG Uesc; // 0x9C: UART Escape Character Register
|
|
ULONG Utim; // 0xA0: UART Escape Timer Register
|
|
ULONG Ubir; // 0xA4: UART BRM Incremental Register
|
|
ULONG reserved3;
|
|
ULONG Ubrc; // 0xAC: UART Baud Rate Count Register
|
|
ULONG Onems; // 0xB0: UART One Millisecond Register
|
|
ULONG Uts; // 0xB4: UART Test Register
|
|
ULONG Umcr; // 0xB8: UART RS-485 Mode Control Register
|
|
} MX6_UART_REGISTERS, *PMX6_UART_REGISTERS;
|
|
|
|
#include <poppack.h> // pshpack1.h
|
|
|
|
C_ASSERT(FIELD_OFFSET(MX6_UART_REGISTERS, Umcr) == 0xB8);
|
|
|
|
// ------------------------------------------------------------------ Functions
|
|
|
|
BOOLEAN
|
|
MX6InitializePort(
|
|
_In_opt_ _Null_terminated_ PCHAR LoadOptions,
|
|
_Inout_ PCPPORT Port,
|
|
BOOLEAN MemoryMapped,
|
|
UCHAR AccessSize,
|
|
UCHAR BitWidth)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine ensures the hardware has been initialized by previous
|
|
boot stages and applies configuration required by this module.
|
|
|
|
Arguments:
|
|
|
|
LoadOptions - Optional load option string. Currently unused.
|
|
|
|
Port - Supplies a pointer to a CPPORT object which will be filled in as
|
|
part of the port initialization.
|
|
|
|
MemoryMapped - Supplies a boolean which indicates if the UART is accessed
|
|
through memory-mapped registers or legacy port I/O.
|
|
|
|
AccessSize - Supplies an ACPI Generic Access Size value which indicates the
|
|
type of bus access that should be performed when accessing the UART.
|
|
|
|
BitWidth - Supplies a number indicating how wide the UART's registers are.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the port has been successfully initialized, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
volatile PMX6_UART_REGISTERS Registers;
|
|
ULONG Ucr1Reg;
|
|
ULONG Ucr2Reg;
|
|
ULONG UfcrReg;
|
|
|
|
UNREFERENCED_PARAMETER(LoadOptions);
|
|
UNREFERENCED_PARAMETER(AccessSize);
|
|
UNREFERENCED_PARAMETER(BitWidth);
|
|
|
|
if (MemoryMapped == FALSE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Registers = (PMX6_UART_REGISTERS)Port->Address;
|
|
|
|
//
|
|
// Verify UART is enabled. UEFI should have enabled the UART.
|
|
//
|
|
|
|
Ucr1Reg = READ_REGISTER_ULONG(&Registers->Ucr1);
|
|
if ((Ucr1Reg & MX6_UCR1_UARTEN) == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Verify transmitter and receiver are enabled. These must be enabled
|
|
// or else writing to the RXD and TXD registers will cause a bus error.
|
|
//
|
|
|
|
Ucr2Reg = READ_REGISTER_ULONG(&Registers->Ucr2);
|
|
if (((Ucr2Reg & MX6_UCR2_TXEN) == 0) ||
|
|
((Ucr2Reg & MX6_UCR2_RXEN) == 0))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Configure transmitter trigger level to maximum.
|
|
//
|
|
|
|
UfcrReg = READ_REGISTER_ULONG(&Registers->Ufcr);
|
|
UfcrReg = (UfcrReg & ~MX6_UFCR_TXTL_MASK) |
|
|
(MX6_UFCR_TXTL_MAX << MX6_UFCR_TXTL_SHIFT);
|
|
|
|
WRITE_REGISTER_ULONG(&Registers->Ufcr, UfcrReg);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
MX6SetBaud(
|
|
_Inout_ PCPPORT Port,
|
|
ULONG Rate)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine configures a UART device to use the specified baudrate.
|
|
This routine is currently a no-op because we rely on UEFI to configure
|
|
the baud rate.
|
|
|
|
Arguments:
|
|
|
|
Port - Supplies the address of the port object that describes the UART.
|
|
|
|
Rate - Supplies the desired baud rate in bits per second.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the baud rate was programmed, FALSE if it was not.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ((Port == NULL) || (Port->Address == NULL))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Remember the baud rate.
|
|
//
|
|
|
|
Port->BaudRate = Rate;
|
|
return FALSE;
|
|
}
|
|
|
|
UART_STATUS
|
|
MX6GetByte(
|
|
_Inout_ PCPPORT Port,
|
|
_Out_ PUCHAR Byte)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fetch a data byte from the UART device and return it.
|
|
|
|
Arguments:
|
|
|
|
Port - Supplies the address of the port object that describes the UART.
|
|
|
|
Byte - Supplies the address of variable to hold the result.
|
|
|
|
Return Value:
|
|
|
|
UART_STATUS code.
|
|
|
|
--*/
|
|
|
|
{
|
|
volatile PMX6_UART_REGISTERS Registers;
|
|
ULONG RxdReg;
|
|
|
|
if ((Port == NULL) || (Port->Address == NULL))
|
|
{
|
|
return UartNotReady;
|
|
}
|
|
|
|
Registers = (PMX6_UART_REGISTERS)Port->Address;
|
|
|
|
//
|
|
// Read an entry from the RX FIFO.
|
|
//
|
|
|
|
RxdReg = READ_REGISTER_ULONG(&Registers->Rxd);
|
|
|
|
//
|
|
// Check if the entry is valid (i.e. was a byte actually received).
|
|
//
|
|
|
|
if ((RxdReg & MX6_RXD_CHARRDY) == 0)
|
|
{
|
|
return UartNoData;
|
|
}
|
|
|
|
//
|
|
// Check if an error occurred.
|
|
//
|
|
|
|
if ((RxdReg & MX6_RXD_ERR) != 0)
|
|
{
|
|
return UartError;
|
|
}
|
|
|
|
//
|
|
// Mask off the data and return it
|
|
//
|
|
|
|
*Byte = (UCHAR)(RxdReg & MX6_RXD_DATA_MASK);
|
|
return UartSuccess;
|
|
}
|
|
|
|
UART_STATUS
|
|
MX6PutByte(
|
|
_Inout_ PCPPORT Port,
|
|
UCHAR Byte,
|
|
BOOLEAN BusyWait)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a data byte out to the UART device.
|
|
|
|
Arguments:
|
|
|
|
Port - Supplies the address of the port object that describes the UART.
|
|
|
|
Byte - Supplies the data to emit.
|
|
|
|
BusyWait - Supplies a flag to control whether this routine will busy
|
|
wait (spin) for the UART hardware to be ready to transmit.
|
|
|
|
Return Value:
|
|
|
|
UART_STATUS code.
|
|
|
|
--*/
|
|
|
|
{
|
|
volatile PMX6_UART_REGISTERS Registers;
|
|
ULONG Usr1Reg;
|
|
|
|
if ((Port == NULL) || (Port->Address == NULL))
|
|
{
|
|
return UartNotReady;
|
|
}
|
|
|
|
Registers = (PMX6_UART_REGISTERS)Port->Address;
|
|
|
|
//
|
|
// Wait for the transmit interface to be ready (TRDY bit HIGH).
|
|
//
|
|
|
|
if (BusyWait != FALSE)
|
|
{
|
|
do
|
|
{
|
|
Usr1Reg = READ_REGISTER_ULONG(&Registers->Usr1);
|
|
} while ((Usr1Reg & MX6_USR1_TRDY) == 0);
|
|
}
|
|
else
|
|
{
|
|
Usr1Reg = READ_REGISTER_ULONG(&Registers->Usr1);
|
|
if ((Usr1Reg & MX6_USR1_TRDY) == 0)
|
|
{
|
|
return UartNotReady;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Send the byte.
|
|
//
|
|
|
|
WRITE_REGISTER_ULONG(&Registers->Txd, Byte);
|
|
return UartSuccess;
|
|
}
|
|
|
|
BOOLEAN
|
|
MX6RxReady(
|
|
_Inout_ PCPPORT Port)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if there is data pending in the UART.
|
|
|
|
Arguments:
|
|
|
|
Port - Supplies the address of the port object that describes the UART.
|
|
|
|
Return Value:
|
|
|
|
TRUE if data is available, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
volatile PMX6_UART_REGISTERS Registers;
|
|
ULONG Usr2Reg;
|
|
|
|
if ((Port == NULL) || (Port->Address == NULL))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Registers = (PMX6_UART_REGISTERS)Port->Address;
|
|
|
|
//
|
|
// Return TRUE if the "Receive Data Ready" bit is set
|
|
//
|
|
|
|
Usr2Reg = READ_REGISTER_ULONG(&Registers->Usr2);
|
|
return (Usr2Reg & MX6_USR2_RDR) != 0;
|
|
}
|
|
|
|
// -------------------------------------------------------------------- Globals
|
|
|
|
UART_HARDWARE_DRIVER MX6HardwareDriver = {
|
|
MX6InitializePort,
|
|
MX6SetBaud,
|
|
MX6GetByte,
|
|
MX6PutByte,
|
|
MX6RxReady};
|