summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/CpuHotplugSmm/Smbase.c
blob: ea21153d9145748f9e5c05159014b911b72437d5 (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
/** @file
  SMBASE relocation for hot-plugged CPUs.

  Copyright (c) 2020, Red Hat, Inc.

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include <Base.h>                             // BASE_1MB
#include <Library/BaseMemoryLib.h>            // CopyMem()
#include <Library/DebugLib.h>                 // DEBUG()

#include "Smbase.h"

extern CONST UINT8 mPostSmmPen[];
extern CONST UINT16 mPostSmmPenSize;

/**
  Allocate a non-SMRAM reserved memory page for the Post-SMM Pen for hot-added
  CPUs.

  This function may only be called from the entry point function of the driver.

  @param[out] PenAddress   The address of the allocated (normal RAM) reserved
                           page.

  @param[in] BootServices  Pointer to the UEFI boot services table. Used for
                           allocating the normal RAM (not SMRAM) reserved page.

  @retval EFI_SUCCESS          Allocation successful.

  @retval EFI_BAD_BUFFER_SIZE  The Post-SMM Pen template is not smaller than
                               EFI_PAGE_SIZE.

  @return                      Error codes propagated from underlying services.
                               DEBUG_ERROR messages have been logged. No
                               resources have been allocated.
**/
EFI_STATUS
SmbaseAllocatePostSmmPen (
  OUT UINT32                  *PenAddress,
  IN  CONST EFI_BOOT_SERVICES *BootServices
  )
{
  EFI_STATUS           Status;
  EFI_PHYSICAL_ADDRESS Address;

  //
  // The pen code must fit in one page, and the last byte must remain free for
  // signaling the SMM Monarch.
  //
  if (mPostSmmPenSize >= EFI_PAGE_SIZE) {
    Status = EFI_BAD_BUFFER_SIZE;
    DEBUG ((DEBUG_ERROR, "%a: mPostSmmPenSize=%u: %r\n", __FUNCTION__,
      mPostSmmPenSize, Status));
    return Status;
  }

  Address = BASE_1MB - 1;
  Status = BootServices->AllocatePages (AllocateMaxAddress,
                           EfiReservedMemoryType, 1, &Address);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: AllocatePages(): %r\n", __FUNCTION__, Status));
    return Status;
  }

  DEBUG ((DEBUG_INFO, "%a: Post-SMM Pen at 0x%Lx\n", __FUNCTION__, Address));
  *PenAddress = (UINT32)Address;
  return EFI_SUCCESS;
}

/**
  Copy the Post-SMM Pen template code into the reserved page allocated with
  SmbaseAllocatePostSmmPen().

  Note that this effects an "SMRAM to normal RAM" copy.

  The SMM Monarch is supposed to call this function from the root MMI handler.

  @param[in] PenAddress  The allocation address returned by
                         SmbaseAllocatePostSmmPen().
**/
VOID
SmbaseReinstallPostSmmPen (
  IN UINT32 PenAddress
  )
{
  CopyMem ((VOID *)(UINTN)PenAddress, mPostSmmPen, mPostSmmPenSize);
}

/**
  Release the reserved page allocated with SmbaseAllocatePostSmmPen().

  This function may only be called from the entry point function of the driver,
  on the error path.

  @param[in] PenAddress    The allocation address returned by
                           SmbaseAllocatePostSmmPen().

  @param[in] BootServices  Pointer to the UEFI boot services table. Used for
                           releasing the normal RAM (not SMRAM) reserved page.
**/
VOID
SmbaseReleasePostSmmPen (
  IN UINT32                  PenAddress,
  IN CONST EFI_BOOT_SERVICES *BootServices
  )
{
  BootServices->FreePages (PenAddress, 1);
}