debug_ring.cpp
Go to the documentation of this file.
1 //
2 // Bareflank Hypervisor
3 //
4 // Copyright (C) 2015 Assured Information Security, Inc.
5 // Author: Rian Quinn <quinnr@ainfosec.com>
6 // Author: Brendan Kerrigan <kerriganb@ainfosec.com>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 #include <gsl/gsl>
23 
24 #include <map>
25 #include <debug_ring/debug_ring.h>
26 
27 // -----------------------------------------------------------------------------
28 // Mutex
29 // -----------------------------------------------------------------------------
30 
31 #include <mutex>
32 std::mutex g_debug_mutex;
33 
34 // -----------------------------------------------------------------------------
35 // Global
36 // -----------------------------------------------------------------------------
37 
38 std::map<vcpuid::type, debug_ring_resources_t *> g_drrs;
39 
40 extern "C" int64_t
42 {
43  if (drr == nullptr)
44  return GET_DRR_FAILURE;
45 
46  if (auto found_drr = g_drrs[vcpuid])
47  {
48  *drr = found_drr;
49  return GET_DRR_SUCCESS;
50  }
51 
52  return GET_DRR_FAILURE;
53 }
54 
55 // -----------------------------------------------------------------------------
56 // Debug Ring Implementation
57 // -----------------------------------------------------------------------------
58 
60 {
61  try
62  {
63  m_vcpuid = vcpuid;
64  m_drr = std::make_unique<debug_ring_resources_t>();
65 
66  m_drr->epos = 0;
67  m_drr->spos = 0;
68  m_drr->tag1 = 0xDB60DB60DB60DB60;
69  m_drr->tag2 = 0x06BD06BD06BD06BD;
70 
71  std::lock_guard<std::mutex> guard(g_debug_mutex);
72  g_drrs[vcpuid] = m_drr.get();
73  }
74  catch (...)
75  { }
76 }
77 
78 void
80 {
81  try
82  {
83  // TODO: A more interesting implementation would use an optimized
84  // memcpy to implement this code. Doing so would increase it's
85  // performance, but would require some better math, and an
86  // optimized memcpy that used both rep string instructions and
87  // SIMD instructions
88 
89  expects(m_drr);
90  expects(str.length() > 0);
91  expects(str.length() < DEBUG_RING_SIZE);
92 
93  // The length that we were given is equivalent to strlen, which does not
94  // include the '\0', so we add one to the length to account for that.
95  auto len = str.length() + 1;
96 
97  auto epos = m_drr->epos & (DEBUG_RING_SIZE - 1);
98  auto cpos = m_drr->spos & (DEBUG_RING_SIZE - 1);
99  auto space = DEBUG_RING_SIZE - (m_drr->epos - m_drr->spos);
100 
101  if (space < len)
102  {
103  // Make room for the write. Normally, with a circular buffer, you
104  // would just move the start position when a read occurs, but in
105  // this case, the vmm needs to be able to write as it wishes to the
106  // buffer. If we just move the start position based on the amount
107  // of space we need, you would end up with the first string being
108  // cropped once the ring wraps. The following code makes sure that
109  // we are making room by removing complete strings.
110  //
111  // Note: There is still a race condition with this code. If the
112  // reader reads at the same time we are writing, you could
113  // end up with a cropped string for the first string, but
114  // that's fine, as this is just debug text, and if we add
115  // locks, we would greatly increase the complexity of this
116  // code, while serializing the code, which is not a good idea.
117  //
118  while (space <= DEBUG_RING_SIZE)
119  {
120  if (cpos >= DEBUG_RING_SIZE)
121  cpos = 0;
122 
123  space++;
124  m_drr->spos++;
125 
126  if (gsl::at(m_drr->buf, cpos) == '\0' && space >= len)
127  break;
128 
129  gsl::at(m_drr->buf, cpos++) = '\0';
130  }
131  }
132 
133  for (auto i = 0U; i < len; i++)
134  {
135  if (epos >= DEBUG_RING_SIZE)
136  epos = 0;
137 
138  gsl::at(m_drr->buf, epos) = str[i];
139 
140  epos++;
141  m_drr->epos++;
142  }
143  }
144  catch (...) { }
145 }
expects(rbx)
uint64_t type
Definition: vcpuid.h:31
std::map< vcpuid::type, debug_ring_resources_t * > g_drrs
Definition: debug_ring.cpp:38
virtual void write(const std::string &str) noexcept
Definition: debug_ring.cpp:79
std::mutex g_debug_mutex
Definition: debug_ring.cpp:32
#define GET_DRR_FAILURE
Definition: error_codes.h:74
Definition: vcpuid.h:29
debug_ring_resources_t * drr
void uint64_t uint64_t uint64_t *rdx noexcept
int64_t get_drr(uint64_t vcpuid, struct debug_ring_resources_t **drr) noexcept
Definition: debug_ring.cpp:41
debug_ring(vcpuid::type vcpuid) noexcept
Definition: debug_ring.cpp:59
#define DEBUG_RING_SIZE
Definition: constants.h:206
#define GET_DRR_SUCCESS
Definition: error_codes.h:73