The Pedigree Project 0.1
InfoBlock.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/LockGuard.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/Version.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/machine/Machine.h"
25#include "pedigree/kernel/machine/Timer.h"
26#include "pedigree/kernel/machine/TimerHandler.h"
27#include "pedigree/kernel/process/InfoBlock.h"
28#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
29#include "pedigree/kernel/processor/Processor.h"
30#include "pedigree/kernel/processor/VirtualAddressSpace.h"
31#include "pedigree/kernel/processor/state_forward.h"
32#include "pedigree/kernel/processor/types.h"
33#include "pedigree/kernel/time/Time.h"
34#include "pedigree/kernel/utilities/utility.h"
35
36InfoBlockManager InfoBlockManager::m_Instance;
37
38InfoBlockManager::InfoBlockManager()
39 : TimerHandler(),
40 m_bInitialised(false),
41 m_UpdateLock(false, true),
42 m_pTimer(nullptr),
43 m_pInfoBlock(0) {}
44
45InfoBlockManager::~InfoBlockManager() {
46 if (!shutdown()) {
47 FATAL("InfoBlockManager could not drain its timer callback");
48 }
49}
50
51InfoBlockManager& InfoBlockManager::instance() {
52 return m_Instance;
53}
54
55bool InfoBlockManager::initialise() {
56 // Prepare the mapping, if we can.
58 void* infoBlock = reinterpret_cast<void*>(va.getGlobalInfoBlock());
59 if (!infoBlock)
60 return false; // Nothing to do here.
61
62 NOTICE("InfoBlockManager: Setting up global info block at " << Hex << infoBlock);
63
64 // Map for userspace.
65 physical_uintptr_t page = PhysicalMemoryManager::instance().allocatePage();
66 va.map(page, infoBlock, 0);
67
68 // Map for the kernel - trick is, our version is a page ahead.
69 m_pInfoBlock =
70 reinterpret_cast<InfoBlock*>(adjust_pointer(infoBlock, PhysicalMemoryManager::getPageSize()));
72
73 // Set up basic defaults.
74 ByteSet(m_pInfoBlock, 0, sizeof(InfoBlock));
75 StringCopy(m_pInfoBlock->sysname, "Pedigree");
76 StringCopy(m_pInfoBlock->release, "Foster");
77 StringCopy(m_pInfoBlock->version, g_pBuildRevision);
79 StringCopy(m_pInfoBlock->machine, g_pBuildTarget);
80 m_pInfoBlock->now = Time::getTimeNanoseconds();
81 m_pInfoBlock->now_s = Time::getTime();
82 m_pInfoBlock->monotonic = Time::getTicks();
83
84#if X64 && !HOSTED
85 uint32_t maxLeaf, eax, ebx, ecx, edx;
86 Processor::cpuid(0x80000000, 0, maxLeaf, ebx, ecx, edx);
87 if (maxLeaf >= 0x80000001) {
88 Processor::cpuid(0x80000001, 0, eax, ebx, ecx, edx);
89 if (edx & (1u << 27)) {
90 m_pInfoBlock->vdso_features |= INFO_BLOCK_VDSO_GETCPU_RDTSCP;
91 }
92 }
93#endif
94
95 __atomic_store_n(&m_bInitialised, true, __ATOMIC_RELEASE);
96#if X64 && !HOSTED
97 // The vDSO's time exports sample the kernel clock directly on amd64.
98 // Refreshing a shared snapshot would keep an otherwise idle CPU ticking.
99 return true;
100#else
101 Timer* timer = Machine::instance().getTimer();
102 if (timer && timer->registerHandler(this)) {
103 m_pTimer = timer;
104 return true;
105 }
106 return false;
107#endif
108}
109
110bool InfoBlockManager::shutdown() {
111 if (m_pTimer && !m_pTimer->unregisterHandler(this)) {
112 return false;
113 }
114
115 m_pTimer = nullptr;
116 __atomic_store_n(&m_bInitialised, false, __ATOMIC_RELEASE);
117 return true;
118}
119
120void InfoBlockManager::timer(uint64_t) {
121 refreshTime();
122}
123
124void InfoBlockManager::refreshTime() {
125 if (!__atomic_load_n(&m_bInitialised, __ATOMIC_ACQUIRE)) {
126 return;
127 }
128 // A timer callback must not overwrite a completed clock update with an
129 // older sample taken before the setting syscall published its new epoch.
130 LockGuard<Spinlock> guard(m_UpdateLock);
131 const Time::Timestamp now = Time::getTimeNanoseconds();
132 m_pInfoBlock->now = now;
133 m_pInfoBlock->now_s = now / Time::Multiplier::Second;
134 m_pInfoBlock->monotonic = Time::getTicks();
135}
136
137void InfoBlockManager::setPid(size_t value) {
138 if (LIKELY(__atomic_load_n(&m_bInitialised, __ATOMIC_ACQUIRE)))
139 m_pInfoBlock->pid = value;
140}
virtual Timer * getTimer()=0
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
static PhysicalMemoryManager & instance()
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
static void cpuid(uint32_t inEax, uint32_t inEcx, uint32_t &eax, uint32_t &ebx, uint32_t &ecx, uint32_t &edx)
@ Hex
Definition Log.h:124