summaryrefslogtreecommitdiffstats
path: root/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c
blob: 43fbf650909aca2eae509033cefb5b2fe224ef39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/** @file
  Library that implements the helper functions to parse and pack a Transfer
  List as specified by the A-profile Firmware Handoff Specification.

  Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent

  @par Reference(s):
    - https://github.com/FirmwareHandoff/firmware_handoff

  @par Glossary:
    - TL - Transfer list
    - TE - Transfer entry
    - Tlh - Transfer list header
**/

#include <Base.h>
#include <Library/ArmTransferListLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>

/**
  Return the first Transfer Entry Node in the Transfer List.

  @param [in]   Tlh       TransferListHeader

  @return Pointer to the Transfer Entry Node if successful otherwise NULL

**/
TRANSFER_ENTRY_HEADER *
EFIAPI
TlGetFirstEntry (
  IN TRANSFER_LIST_HEADER  *Tlh
  )
{
  return TlGetNextEntry (Tlh, NULL);
}

/**
  Return the next Transfer Entry Node in the Transfer List from
  last Transfer Entry Node.

  @param [in]   Tlh       TransferListHeader
  @param [in]   CurrentTe  Pointer to the Current Transfer Entry.
                           If this is NULL, the first Transfer Entry is returned.

  @return Pointer to the Transfer Entry Node if successful otherwise NULL

**/
TRANSFER_ENTRY_HEADER *
EFIAPI
TlGetNextEntry (
  IN TRANSFER_LIST_HEADER   *Tlh,
  IN TRANSFER_ENTRY_HEADER  *CurrentTe
  )
{
  TRANSFER_ENTRY_HEADER  *Te;
  UINTN                  CurrentAddr;
  UINTN                  EndAddr;

  if (Tlh == NULL) {
    return NULL;
  }

  EndAddr = (UINTN)Tlh + Tlh->UsedSize;

  if (CurrentTe != NULL) {
    CurrentAddr = (UINTN)CurrentTe + CurrentTe->HeaderSize + CurrentTe->DataSize;
  } else {
    CurrentAddr = (UINTN)Tlh + Tlh->HeaderSize;
  }

  CurrentAddr = ALIGN_VALUE (CurrentAddr, (1 << Tlh->Alignment));

  Te = (TRANSFER_ENTRY_HEADER *)CurrentAddr;

  if (((CurrentAddr + sizeof (TRANSFER_LIST_HEADER)) < CurrentAddr) ||
      ((CurrentAddr + sizeof (TRANSFER_ENTRY_HEADER)) > EndAddr) ||
      ((CurrentAddr + Te->HeaderSize + Te->DataSize) < CurrentAddr) ||
      ((CurrentAddr + Te->HeaderSize + Te->DataSize) > EndAddr))
  {
    return NULL;
  }

  return Te;
}

/**
  Return the first Transfer Entry Node in the Transfer List
  matched with given tag-id.

  @param [in]   Tlh       TransferListHeader
  @param [in]   TagId     Tag id

  @return Pointer to the Transfer Entry Node if successful otherwise NULL

**/
TRANSFER_ENTRY_HEADER *
EFIAPI
TlFindFirstEntry (
  IN TRANSFER_LIST_HEADER  *Tlh,
  IN UINT16                TagId
  )
{
  TRANSFER_ENTRY_HEADER  *Te;

  Te = TlGetFirstEntry (Tlh);

  while ((Te != NULL) && ((Te->TagId != TagId) || Te->Reserved0 != 0)) {
    Te = TlGetNextEntry (Tlh, Te);
  }

  return Te;
}

/**
  Return the Next Transfer Entry Node in the Transfer List
  matched with given tag-id from last Transfer Entry Node.

  @param [in]   Tlh        TransferListHeader
  @param [in]   CurrentTe  Pointer to the Current Transfer Entry.
                           If this is NULL, the first Transfer Entry is returned.
  @param [in]   TagId      Tag id

  @return Pointer to the Transfer Entry Node if successful otherwise NULL

**/
TRANSFER_ENTRY_HEADER *
EFIAPI
TlFindNextEntry (
  IN TRANSFER_LIST_HEADER   *Tlh,
  IN TRANSFER_ENTRY_HEADER  *CurrentTe,
  IN UINT16                 TagId
  )
{
  TRANSFER_ENTRY_HEADER  *Te;

  if (CurrentTe == NULL) {
    return TlFindFirstEntry (Tlh, TagId);
  } else {
    Te = TlGetNextEntry (Tlh, CurrentTe);
  }

  while ((Te != NULL) && ((Te->TagId != TagId) || Te->Reserved0 != 0)) {
    Te = TlGetNextEntry (Tlh, Te);
  }

  return Te;
}

/**
  Return the data in Transfer Entry.

  @param [in]   Te       TransferEntryHeader

  @return Pointer to the Data of Transfer Entry Node if successful otherwise NULL

**/
VOID *
EFIAPI
TlGetEntryData (
  IN TRANSFER_ENTRY_HEADER  *Te
  )
{
  if ((Te == NULL) || (Te->DataSize == 0)) {
    return NULL;
  }

  return (VOID *)((UINTN)Te + Te->HeaderSize);
}