summaryrefslogtreecommitdiffstats
path: root/MdePkg/Library/BasePeCoffLib/RiscV/PeCoffLoaderEx.c
blob: adbfe9ccf5801679bab998b6920eff851e48213b (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
/** @file
  PE/Coff loader for RISC-V PE image

  Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "BasePeCoffLibInternals.h"
#include <Library/BaseLib.h>

/**
  Performs an RISC-V specific relocation fixup and is a no-op on
  other instruction sets.
  RISC-V splits 32-bit fixup into 20bit and 12-bit with two relocation
  types. We have to know the lower 12-bit fixup first then we can deal
  carry over on high 20-bit fixup. So we log the high 20-bit in
  FixupData.

  @param  Reloc       The pointer to the relocation record.
  @param  Fixup       The pointer to the address to fix up.
  @param  FixupData   The pointer to a buffer to log the fixups.
  @param  Adjust      The offset to adjust the fixup.

  @return Status code.

**/
RETURN_STATUS
PeCoffLoaderRelocateImageEx (
  IN UINT16     *Reloc,
  IN OUT CHAR8  *Fixup,
  IN OUT CHAR8  **FixupData,
  IN UINT64     Adjust
  )
{
  UINT32  Value;
  UINT32  Value2;
  UINT32  *RiscVHi20Fixup;

  switch ((*Reloc) >> 12) {
    case EFI_IMAGE_REL_BASED_RISCV_HI20:
      *(UINT64 *)(*FixupData) = (UINT64)(UINTN)Fixup;
      break;

    case EFI_IMAGE_REL_BASED_RISCV_LOW12I:
      RiscVHi20Fixup =  (UINT32 *)(*(UINT64 *)(*FixupData));
      if (RiscVHi20Fixup != NULL) {
        Value  = (UINT32)(RV_X (*RiscVHi20Fixup, 12, 20) << 12);
        Value2 = (UINT32)(RV_X (*(UINT32 *)Fixup, 20, 12));
        if (Value2 & (RISCV_IMM_REACH/2)) {
          Value2 |= ~(RISCV_IMM_REACH-1);
        }

        Value                    += Value2;
        Value                    += (UINT32)Adjust;
        Value2                    = RISCV_CONST_HIGH_PART (Value);
        *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \
                                    (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12));
        *(UINT32 *)Fixup = (RV_X (Value, 0, 12) << 20) | \
                           (RV_X (*(UINT32 *)Fixup, 0, 20));
      }

      break;

    case EFI_IMAGE_REL_BASED_RISCV_LOW12S:
      RiscVHi20Fixup =  (UINT32 *)(*(UINT64 *)(*FixupData));
      if (RiscVHi20Fixup != NULL) {
        Value  = (UINT32)(RV_X (*RiscVHi20Fixup, 12, 20) << 12);
        Value2 = (UINT32)(RV_X (*(UINT32 *)Fixup, 7, 5) | (RV_X (*(UINT32 *)Fixup, 25, 7) << 5));
        if (Value2 & (RISCV_IMM_REACH/2)) {
          Value2 |= ~(RISCV_IMM_REACH-1);
        }

        Value                    += Value2;
        Value                    += (UINT32)Adjust;
        Value2                    = RISCV_CONST_HIGH_PART (Value);
        *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \
                                    (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12));
        Value2           = *(UINT32 *)Fixup & 0x01fff07f;
        Value           &= RISCV_IMM_REACH - 1;
        *(UINT32 *)Fixup = Value2 | (UINT32)(((RV_X (Value, 0, 5) << 7) | (RV_X (Value, 5, 7) << 25)));
      }

      break;

    default:
      return RETURN_UNSUPPORTED;
  }

  return RETURN_SUCCESS;
}

/**
  Returns TRUE if the machine type of PE/COFF image is supported. Supported
  does not mean the image can be executed it means the PE/COFF loader supports
  loading and relocating of the image type. It's up to the caller to support
  the entry point.

  @param  Machine   Machine type from the PE Header.

  @return TRUE if this PE/COFF loader can load the image

**/
BOOLEAN
PeCoffLoaderImageFormatSupported (
  IN  UINT16  Machine
  )
{
  if (Machine ==  IMAGE_FILE_MACHINE_RISCV64) {
    return TRUE;
  }

  return FALSE;
}

/**
  Performs an Itanium-based specific re-relocation fixup and is a no-op on other
  instruction sets. This is used to re-relocated the image into the EFI virtual
  space for runtime calls.

  @param  Reloc       The pointer to the relocation record.
  @param  Fixup       The pointer to the address to fix up.
  @param  FixupData   The pointer to a buffer to log the fixups.
  @param  Adjust      The offset to adjust the fixup.

  @return Status code.

**/
RETURN_STATUS
PeHotRelocateImageEx (
  IN UINT16     *Reloc,
  IN OUT CHAR8  *Fixup,
  IN OUT CHAR8  **FixupData,
  IN UINT64     Adjust
  )
{
  return RETURN_UNSUPPORTED;
}