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 // Register ourselves with the main timer.
96 __atomic_store_n(&m_bInitialised, true, __ATOMIC_RELEASE);
97 Timer* timer = Machine::instance().getTimer();
98 if (timer && timer->registerHandler(this)) {
99 m_pTimer = timer;
100 return true;
101 }
102 return false;
103}
104
105bool InfoBlockManager::shutdown() {
106 if (m_pTimer && !m_pTimer->unregisterHandler(this)) {
107 return false;
108 }
109
110 m_pTimer = nullptr;
111 __atomic_store_n(&m_bInitialised, false, __ATOMIC_RELEASE);
112 return true;
113}
114
115void InfoBlockManager::timer(uint64_t) {
116 refreshTime();
117}
118
119void InfoBlockManager::refreshTime() {
120 if (!__atomic_load_n(&m_bInitialised, __ATOMIC_ACQUIRE)) {
121 return;
122 }
123 // A timer callback must not overwrite a completed clock update with an
124 // older sample taken before the setting syscall published its new epoch.
125 LockGuard<Spinlock> guard(m_UpdateLock);
126 const Time::Timestamp now = Time::getTimeNanoseconds();
127 m_pInfoBlock->now = now;
128 m_pInfoBlock->now_s = now / Time::Multiplier::Second;
129 m_pInfoBlock->monotonic = Time::getTicks();
130}
131
132void InfoBlockManager::setPid(size_t value) {
133 if (LIKELY(__atomic_load_n(&m_bInitialised, __ATOMIC_ACQUIRE)))
134 m_pInfoBlock->pid = value;
135}
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