[project] Lose the battle between tabs & spaces
I'm a tabs guy. I like tabs, it's an elegant way to represent indentation instead of brute-forcing it. But I have to admit that the world seems to be going towards spaces, and tooling tends not to play nice with tabs. So here we go, changing the whole repo to spaces since I'm getting tired of all the inconsistent formatting.
This commit is contained in:
committed by
Justin C. Miller
parent
d36b2d8057
commit
8f529046a9
@@ -24,139 +24,139 @@ static_assert(sizeof(allocation_register) == page_size);
|
||||
|
||||
void
|
||||
allocator::init(
|
||||
allocation_register *&allocs,
|
||||
modules_page *&modules,
|
||||
uefi::boot_services *bs)
|
||||
allocation_register *&allocs,
|
||||
modules_page *&modules,
|
||||
uefi::boot_services *bs)
|
||||
{
|
||||
new (&g_alloc) allocator(*bs);
|
||||
allocs = g_alloc.m_register;
|
||||
modules = g_alloc.m_modules;
|
||||
new (&g_alloc) allocator(*bs);
|
||||
allocs = g_alloc.m_register;
|
||||
modules = g_alloc.m_modules;
|
||||
}
|
||||
|
||||
|
||||
allocator::allocator(uefi::boot_services &bs) :
|
||||
m_bs(bs),
|
||||
m_register(nullptr),
|
||||
m_modules(nullptr)
|
||||
m_bs(bs),
|
||||
m_register(nullptr),
|
||||
m_modules(nullptr)
|
||||
{
|
||||
add_register();
|
||||
add_modules();
|
||||
add_register();
|
||||
add_modules();
|
||||
}
|
||||
|
||||
void
|
||||
allocator::add_register()
|
||||
{
|
||||
allocation_register *reg = nullptr;
|
||||
allocation_register *reg = nullptr;
|
||||
|
||||
try_or_raise(
|
||||
m_bs.allocate_pages(uefi::allocate_type::any_pages,
|
||||
uefi::memory_type::loader_data, 1, reinterpret_cast<void**>(®)),
|
||||
L"Failed allocating allocation register page");
|
||||
try_or_raise(
|
||||
m_bs.allocate_pages(uefi::allocate_type::any_pages,
|
||||
uefi::memory_type::loader_data, 1, reinterpret_cast<void**>(®)),
|
||||
L"Failed allocating allocation register page");
|
||||
|
||||
m_bs.set_mem(reg, sizeof(allocation_register), 0);
|
||||
m_bs.set_mem(reg, sizeof(allocation_register), 0);
|
||||
|
||||
if (m_register)
|
||||
m_register->next = reg;
|
||||
if (m_register)
|
||||
m_register->next = reg;
|
||||
|
||||
m_register = reg;
|
||||
return;
|
||||
m_register = reg;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
allocator::add_modules()
|
||||
{
|
||||
modules_page *mods = reinterpret_cast<modules_page*>(
|
||||
allocate_pages(1, alloc_type::init_args, true));
|
||||
modules_page *mods = reinterpret_cast<modules_page*>(
|
||||
allocate_pages(1, alloc_type::init_args, true));
|
||||
|
||||
if (m_modules)
|
||||
m_modules->next = reinterpret_cast<uintptr_t>(mods);
|
||||
if (m_modules)
|
||||
m_modules->next = reinterpret_cast<uintptr_t>(mods);
|
||||
|
||||
mods->modules = reinterpret_cast<module*>(mods + 1);
|
||||
m_modules = mods;
|
||||
m_next_mod = mods->modules;
|
||||
return;
|
||||
mods->modules = reinterpret_cast<module*>(mods + 1);
|
||||
m_modules = mods;
|
||||
m_next_mod = mods->modules;
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
allocator::allocate_pages(size_t count, alloc_type type, bool zero)
|
||||
{
|
||||
if (count & ~0xffffffffull) {
|
||||
error::raise(uefi::status::unsupported,
|
||||
L"Cannot allocate more than 16TiB in pages at once.",
|
||||
__LINE__);
|
||||
}
|
||||
if (count & ~0xffffffffull) {
|
||||
error::raise(uefi::status::unsupported,
|
||||
L"Cannot allocate more than 16TiB in pages at once.",
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
if (!m_register || m_register->count == 0xff)
|
||||
add_register();
|
||||
if (!m_register || m_register->count == 0xff)
|
||||
add_register();
|
||||
|
||||
void *pages = nullptr;
|
||||
void *pages = nullptr;
|
||||
|
||||
try_or_raise(
|
||||
m_bs.allocate_pages(uefi::allocate_type::any_pages,
|
||||
uefi::memory_type::loader_data, count, &pages),
|
||||
L"Failed allocating usable pages");
|
||||
try_or_raise(
|
||||
m_bs.allocate_pages(uefi::allocate_type::any_pages,
|
||||
uefi::memory_type::loader_data, count, &pages),
|
||||
L"Failed allocating usable pages");
|
||||
|
||||
page_allocation &ent = m_register->entries[m_register->count++];
|
||||
ent.address = reinterpret_cast<uintptr_t>(pages);
|
||||
ent.count = count;
|
||||
ent.type = type;
|
||||
page_allocation &ent = m_register->entries[m_register->count++];
|
||||
ent.address = reinterpret_cast<uintptr_t>(pages);
|
||||
ent.count = count;
|
||||
ent.type = type;
|
||||
|
||||
if (zero)
|
||||
m_bs.set_mem(pages, count * page_size, 0);
|
||||
if (zero)
|
||||
m_bs.set_mem(pages, count * page_size, 0);
|
||||
|
||||
return pages;
|
||||
return pages;
|
||||
}
|
||||
|
||||
module *
|
||||
allocator::allocate_module_untyped(size_t size)
|
||||
{
|
||||
size_t remaining =
|
||||
reinterpret_cast<uintptr_t>(m_modules) + page_size
|
||||
- reinterpret_cast<uintptr_t>(m_next_mod);
|
||||
size_t remaining =
|
||||
reinterpret_cast<uintptr_t>(m_modules) + page_size
|
||||
- reinterpret_cast<uintptr_t>(m_next_mod);
|
||||
|
||||
if (size > remaining)
|
||||
add_modules();
|
||||
if (size > remaining)
|
||||
add_modules();
|
||||
|
||||
++m_modules->count;
|
||||
module *m = m_next_mod;
|
||||
m_next_mod = offset_ptr<module>(m_next_mod, size);
|
||||
++m_modules->count;
|
||||
module *m = m_next_mod;
|
||||
m_next_mod = offset_ptr<module>(m_next_mod, size);
|
||||
|
||||
m->mod_length = size;
|
||||
return m;
|
||||
m->mod_length = size;
|
||||
return m;
|
||||
}
|
||||
|
||||
void *
|
||||
allocator::allocate(size_t size, bool zero)
|
||||
{
|
||||
void *p = nullptr;
|
||||
try_or_raise(
|
||||
m_bs.allocate_pool(uefi::memory_type::loader_data, size, &p),
|
||||
L"Could not allocate pool memory");
|
||||
void *p = nullptr;
|
||||
try_or_raise(
|
||||
m_bs.allocate_pool(uefi::memory_type::loader_data, size, &p),
|
||||
L"Could not allocate pool memory");
|
||||
|
||||
if (zero)
|
||||
m_bs.set_mem(p, size, 0);
|
||||
if (zero)
|
||||
m_bs.set_mem(p, size, 0);
|
||||
|
||||
return p;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
allocator::free(void *p)
|
||||
{
|
||||
try_or_raise(
|
||||
m_bs.free_pool(p),
|
||||
L"Freeing pool memory");
|
||||
try_or_raise(
|
||||
m_bs.free_pool(p),
|
||||
L"Freeing pool memory");
|
||||
}
|
||||
|
||||
void
|
||||
allocator::memset(void *start, size_t size, uint8_t value)
|
||||
{
|
||||
m_bs.set_mem(start, size, value);
|
||||
m_bs.set_mem(start, size, value);
|
||||
}
|
||||
|
||||
void
|
||||
allocator::copy(void *to, void *from, size_t size)
|
||||
{
|
||||
m_bs.copy_mem(to, from, size);
|
||||
m_bs.copy_mem(to, from, size);
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
/// Page allocator class definition
|
||||
|
||||
namespace uefi {
|
||||
class boot_services;
|
||||
class boot_services;
|
||||
}
|
||||
|
||||
namespace kernel {
|
||||
namespace init {
|
||||
enum class allocation_type : uint8_t;
|
||||
struct allocation_register;
|
||||
struct module;
|
||||
struct modules_page;
|
||||
enum class allocation_type : uint8_t;
|
||||
struct allocation_register;
|
||||
struct module;
|
||||
struct modules_page;
|
||||
}}
|
||||
|
||||
namespace boot {
|
||||
@@ -22,46 +22,46 @@ using alloc_type = kernel::init::allocation_type;
|
||||
class allocator
|
||||
{
|
||||
public:
|
||||
using allocation_register = kernel::init::allocation_register;
|
||||
using module = kernel::init::module;
|
||||
using modules_page = kernel::init::modules_page;
|
||||
using allocation_register = kernel::init::allocation_register;
|
||||
using module = kernel::init::module;
|
||||
using modules_page = kernel::init::modules_page;
|
||||
|
||||
allocator(uefi::boot_services &bs);
|
||||
allocator(uefi::boot_services &bs);
|
||||
|
||||
void * allocate(size_t size, bool zero = false);
|
||||
void free(void *p);
|
||||
void * allocate(size_t size, bool zero = false);
|
||||
void free(void *p);
|
||||
|
||||
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
||||
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
||||
|
||||
template <typename M>
|
||||
M * allocate_module(size_t extra = 0) {
|
||||
return static_cast<M*>(allocate_module_untyped(sizeof(M) + extra));
|
||||
}
|
||||
template <typename M>
|
||||
M * allocate_module(size_t extra = 0) {
|
||||
return static_cast<M*>(allocate_module_untyped(sizeof(M) + extra));
|
||||
}
|
||||
|
||||
void memset(void *start, size_t size, uint8_t value);
|
||||
void copy(void *to, void *from, size_t size);
|
||||
void memset(void *start, size_t size, uint8_t value);
|
||||
void copy(void *to, void *from, size_t size);
|
||||
|
||||
inline void zero(void *start, size_t size) { memset(start, size, 0); }
|
||||
inline void zero(void *start, size_t size) { memset(start, size, 0); }
|
||||
|
||||
/// Initialize the global allocator
|
||||
/// \arg allocs [out] Poiinter to the initial allocation register
|
||||
/// \arg modules [out] Pointer to the initial modules_page
|
||||
/// \arg bs UEFI boot services
|
||||
static void init(
|
||||
allocation_register *&allocs,
|
||||
modules_page *&modules,
|
||||
uefi::boot_services *bs);
|
||||
/// Initialize the global allocator
|
||||
/// \arg allocs [out] Poiinter to the initial allocation register
|
||||
/// \arg modules [out] Pointer to the initial modules_page
|
||||
/// \arg bs UEFI boot services
|
||||
static void init(
|
||||
allocation_register *&allocs,
|
||||
modules_page *&modules,
|
||||
uefi::boot_services *bs);
|
||||
|
||||
private:
|
||||
void add_register();
|
||||
void add_modules();
|
||||
module * allocate_module_untyped(size_t size);
|
||||
void add_register();
|
||||
void add_modules();
|
||||
module * allocate_module_untyped(size_t size);
|
||||
|
||||
uefi::boot_services &m_bs;
|
||||
uefi::boot_services &m_bs;
|
||||
|
||||
allocation_register *m_register;
|
||||
modules_page *m_modules;
|
||||
module *m_next_mod;
|
||||
allocation_register *m_register;
|
||||
modules_page *m_modules;
|
||||
module *m_next_mod;
|
||||
};
|
||||
|
||||
} // namespace memory
|
||||
|
||||
@@ -19,195 +19,195 @@ size_t COLS = 0;
|
||||
console *console::s_console = nullptr;
|
||||
|
||||
static const wchar_t digits[] = {u'0', u'1', u'2', u'3', u'4', u'5',
|
||||
u'6', u'7', u'8', u'9', u'a', u'b', u'c', u'd', u'e', u'f'};
|
||||
u'6', u'7', u'8', u'9', u'a', u'b', u'c', u'd', u'e', u'f'};
|
||||
|
||||
|
||||
size_t
|
||||
wstrlen(const wchar_t *s)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (s && *s++) count++;
|
||||
return count;
|
||||
size_t count = 0;
|
||||
while (s && *s++) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
console::console(uefi::protos::simple_text_output *out) :
|
||||
m_rows {0},
|
||||
m_cols {0},
|
||||
m_out {out}
|
||||
m_rows {0},
|
||||
m_cols {0},
|
||||
m_out {out}
|
||||
{
|
||||
try_or_raise(
|
||||
m_out->query_mode(m_out->mode->mode, &m_cols, &m_rows),
|
||||
L"Failed to get text output mode.");
|
||||
try_or_raise(
|
||||
m_out->clear_screen(),
|
||||
L"Failed to clear screen");
|
||||
s_console = this;
|
||||
try_or_raise(
|
||||
m_out->query_mode(m_out->mode->mode, &m_cols, &m_rows),
|
||||
L"Failed to get text output mode.");
|
||||
try_or_raise(
|
||||
m_out->clear_screen(),
|
||||
L"Failed to clear screen");
|
||||
s_console = this;
|
||||
}
|
||||
|
||||
void
|
||||
console::announce()
|
||||
{
|
||||
m_out->set_attribute(uefi::attribute::light_cyan);
|
||||
m_out->output_string(L"jsix loader ");
|
||||
m_out->set_attribute(uefi::attribute::light_cyan);
|
||||
m_out->output_string(L"jsix loader ");
|
||||
|
||||
m_out->set_attribute(uefi::attribute::light_magenta);
|
||||
m_out->output_string(GIT_VERSION_WIDE);
|
||||
m_out->set_attribute(uefi::attribute::light_magenta);
|
||||
m_out->output_string(GIT_VERSION_WIDE);
|
||||
|
||||
m_out->set_attribute(uefi::attribute::light_gray);
|
||||
m_out->output_string(L" booting...\r\n");
|
||||
m_out->set_attribute(uefi::attribute::light_gray);
|
||||
m_out->output_string(L" booting...\r\n");
|
||||
}
|
||||
|
||||
size_t
|
||||
console::print_hex(uint32_t n) const
|
||||
{
|
||||
wchar_t buffer[9];
|
||||
wchar_t *p = buffer;
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
uint8_t nibble = (n >> (i*4)) & 0xf;
|
||||
*p++ = digits[nibble];
|
||||
}
|
||||
*p = 0;
|
||||
m_out->output_string(buffer);
|
||||
return 8;
|
||||
wchar_t buffer[9];
|
||||
wchar_t *p = buffer;
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
uint8_t nibble = (n >> (i*4)) & 0xf;
|
||||
*p++ = digits[nibble];
|
||||
}
|
||||
*p = 0;
|
||||
m_out->output_string(buffer);
|
||||
return 8;
|
||||
}
|
||||
|
||||
size_t
|
||||
console::print_long_hex(uint64_t n) const
|
||||
{
|
||||
wchar_t buffer[17];
|
||||
wchar_t *p = buffer;
|
||||
for (int i = 15; i >= 0; --i) {
|
||||
uint8_t nibble = (n >> (i*4)) & 0xf;
|
||||
*p++ = digits[nibble];
|
||||
}
|
||||
*p = 0;
|
||||
m_out->output_string(buffer);
|
||||
return 16;
|
||||
wchar_t buffer[17];
|
||||
wchar_t *p = buffer;
|
||||
for (int i = 15; i >= 0; --i) {
|
||||
uint8_t nibble = (n >> (i*4)) & 0xf;
|
||||
*p++ = digits[nibble];
|
||||
}
|
||||
*p = 0;
|
||||
m_out->output_string(buffer);
|
||||
return 16;
|
||||
}
|
||||
|
||||
size_t
|
||||
console::print_dec(uint32_t n) const
|
||||
{
|
||||
wchar_t buffer[11];
|
||||
wchar_t *p = buffer + 10;
|
||||
*p-- = 0;
|
||||
do {
|
||||
*p-- = digits[n % 10];
|
||||
n /= 10;
|
||||
} while (n != 0);
|
||||
wchar_t buffer[11];
|
||||
wchar_t *p = buffer + 10;
|
||||
*p-- = 0;
|
||||
do {
|
||||
*p-- = digits[n % 10];
|
||||
n /= 10;
|
||||
} while (n != 0);
|
||||
|
||||
m_out->output_string(++p);
|
||||
return 10 - (p - buffer);
|
||||
m_out->output_string(++p);
|
||||
return 10 - (p - buffer);
|
||||
}
|
||||
|
||||
size_t
|
||||
console::print_long_dec(uint64_t n) const
|
||||
{
|
||||
wchar_t buffer[21];
|
||||
wchar_t *p = buffer + 20;
|
||||
*p-- = 0;
|
||||
do {
|
||||
*p-- = digits[n % 10];
|
||||
n /= 10;
|
||||
} while (n != 0);
|
||||
wchar_t buffer[21];
|
||||
wchar_t *p = buffer + 20;
|
||||
*p-- = 0;
|
||||
do {
|
||||
*p-- = digits[n % 10];
|
||||
n /= 10;
|
||||
} while (n != 0);
|
||||
|
||||
m_out->output_string(++p);
|
||||
return 20 - (p - buffer);
|
||||
m_out->output_string(++p);
|
||||
return 20 - (p - buffer);
|
||||
}
|
||||
|
||||
size_t
|
||||
console::vprintf(const wchar_t *fmt, va_list args) const
|
||||
{
|
||||
wchar_t buffer[256];
|
||||
const wchar_t *r = fmt;
|
||||
wchar_t *w = buffer;
|
||||
size_t count = 0;
|
||||
wchar_t buffer[256];
|
||||
const wchar_t *r = fmt;
|
||||
wchar_t *w = buffer;
|
||||
size_t count = 0;
|
||||
|
||||
while (r && *r) {
|
||||
if (*r != L'%') {
|
||||
count++;
|
||||
*w++ = *r++;
|
||||
continue;
|
||||
}
|
||||
while (r && *r) {
|
||||
if (*r != L'%') {
|
||||
count++;
|
||||
*w++ = *r++;
|
||||
continue;
|
||||
}
|
||||
|
||||
*w = 0;
|
||||
m_out->output_string(buffer);
|
||||
w = buffer;
|
||||
*w = 0;
|
||||
m_out->output_string(buffer);
|
||||
w = buffer;
|
||||
|
||||
r++; // chomp the %
|
||||
r++; // chomp the %
|
||||
|
||||
switch (*r++) {
|
||||
case L'%':
|
||||
m_out->output_string(const_cast<wchar_t*>(L"%"));
|
||||
count++;
|
||||
break;
|
||||
switch (*r++) {
|
||||
case L'%':
|
||||
m_out->output_string(const_cast<wchar_t*>(L"%"));
|
||||
count++;
|
||||
break;
|
||||
|
||||
case L'x':
|
||||
count += print_hex(va_arg(args, uint32_t));
|
||||
break;
|
||||
case L'x':
|
||||
count += print_hex(va_arg(args, uint32_t));
|
||||
break;
|
||||
|
||||
case L'd':
|
||||
case L'u':
|
||||
count += print_dec(va_arg(args, uint32_t));
|
||||
break;
|
||||
case L'd':
|
||||
case L'u':
|
||||
count += print_dec(va_arg(args, uint32_t));
|
||||
break;
|
||||
|
||||
case L's':
|
||||
{
|
||||
wchar_t *s = va_arg(args, wchar_t*);
|
||||
count += wstrlen(s);
|
||||
m_out->output_string(s);
|
||||
}
|
||||
break;
|
||||
case L's':
|
||||
{
|
||||
wchar_t *s = va_arg(args, wchar_t*);
|
||||
count += wstrlen(s);
|
||||
m_out->output_string(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case L'l':
|
||||
switch (*r++) {
|
||||
case L'x':
|
||||
count += print_long_hex(va_arg(args, uint64_t));
|
||||
break;
|
||||
case L'l':
|
||||
switch (*r++) {
|
||||
case L'x':
|
||||
count += print_long_hex(va_arg(args, uint64_t));
|
||||
break;
|
||||
|
||||
case L'd':
|
||||
case L'u':
|
||||
count += print_long_dec(va_arg(args, uint64_t));
|
||||
break;
|
||||
case L'd':
|
||||
case L'u':
|
||||
count += print_long_dec(va_arg(args, uint64_t));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*w = 0;
|
||||
m_out->output_string(buffer);
|
||||
return count;
|
||||
*w = 0;
|
||||
m_out->output_string(buffer);
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t
|
||||
console::printf(const wchar_t *fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
size_t result = vprintf(fmt, args);
|
||||
size_t result = vprintf(fmt, args);
|
||||
|
||||
va_end(args);
|
||||
return result;
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t
|
||||
console::print(const wchar_t *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
size_t result = get().vprintf(fmt, args);
|
||||
size_t result = get().vprintf(fmt, args);
|
||||
|
||||
va_end(args);
|
||||
return result;
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace uefi {
|
||||
namespace protos {
|
||||
struct simple_text_output;
|
||||
struct simple_text_output;
|
||||
}}
|
||||
|
||||
namespace boot {
|
||||
@@ -17,28 +17,28 @@ namespace boot {
|
||||
class console
|
||||
{
|
||||
public:
|
||||
console(uefi::protos::simple_text_output *out);
|
||||
console(uefi::protos::simple_text_output *out);
|
||||
|
||||
void announce();
|
||||
void announce();
|
||||
|
||||
size_t print_hex(uint32_t n) const;
|
||||
size_t print_dec(uint32_t n) const;
|
||||
size_t print_long_hex(uint64_t n) const;
|
||||
size_t print_long_dec(uint64_t n) const;
|
||||
size_t printf(const wchar_t *fmt, ...) const;
|
||||
size_t print_hex(uint32_t n) const;
|
||||
size_t print_dec(uint32_t n) const;
|
||||
size_t print_long_hex(uint64_t n) const;
|
||||
size_t print_long_dec(uint64_t n) const;
|
||||
size_t printf(const wchar_t *fmt, ...) const;
|
||||
|
||||
static console & get() { return *s_console; }
|
||||
static size_t print(const wchar_t *fmt, ...);
|
||||
static console & get() { return *s_console; }
|
||||
static size_t print(const wchar_t *fmt, ...);
|
||||
|
||||
private:
|
||||
friend class status_line;
|
||||
friend class status_line;
|
||||
|
||||
size_t vprintf(const wchar_t *fmt, va_list args) const;
|
||||
size_t vprintf(const wchar_t *fmt, va_list args) const;
|
||||
|
||||
size_t m_rows, m_cols;
|
||||
uefi::protos::simple_text_output *m_out;
|
||||
size_t m_rows, m_cols;
|
||||
uefi::protos::simple_text_output *m_out;
|
||||
|
||||
static console *s_console;
|
||||
static console *s_console;
|
||||
};
|
||||
|
||||
size_t wstrlen(const wchar_t *s);
|
||||
|
||||
@@ -7,8 +7,8 @@ namespace boot {
|
||||
namespace error {
|
||||
|
||||
struct error_code_desc {
|
||||
uefi::status code;
|
||||
const wchar_t *name;
|
||||
uefi::status code;
|
||||
const wchar_t *name;
|
||||
};
|
||||
|
||||
struct error_code_desc error_table[] = {
|
||||
@@ -17,46 +17,46 @@ struct error_code_desc error_table[] = {
|
||||
#include "uefi/errors.inc"
|
||||
#undef STATUS_ERROR
|
||||
#undef STATUS_WARNING
|
||||
{ uefi::status::success, nullptr }
|
||||
{ uefi::status::success, nullptr }
|
||||
};
|
||||
|
||||
const wchar_t *
|
||||
message(uefi::status status)
|
||||
{
|
||||
int32_t i = -1;
|
||||
while (error_table[++i].name != nullptr) {
|
||||
if (error_table[i].code == status) return error_table[i].name;
|
||||
}
|
||||
int32_t i = -1;
|
||||
while (error_table[++i].name != nullptr) {
|
||||
if (error_table[i].code == status) return error_table[i].name;
|
||||
}
|
||||
|
||||
if (uefi::is_error(status))
|
||||
return L"Unknown Error";
|
||||
else
|
||||
return L"Unknown Warning";
|
||||
if (uefi::is_error(status))
|
||||
return L"Unknown Error";
|
||||
else
|
||||
return L"Unknown Warning";
|
||||
}
|
||||
|
||||
[[ noreturn ]] static void
|
||||
cpu_assert(uefi::status s, const wchar_t *message, size_t line)
|
||||
{
|
||||
asm volatile (
|
||||
"movq $0xeeeeeeebadbadbad, %%r8;"
|
||||
"movq %0, %%r9;"
|
||||
"movq %1, %%r10;"
|
||||
"movq %2, %%r11;"
|
||||
"movq $0, %%rdx;"
|
||||
"divq %%rdx;"
|
||||
:
|
||||
: "r"((uint64_t)s), "r"(message), "r"(line)
|
||||
: "rax", "rdx", "r8", "r9", "r10");
|
||||
while (1) asm("hlt");
|
||||
asm volatile (
|
||||
"movq $0xeeeeeeebadbadbad, %%r8;"
|
||||
"movq %0, %%r9;"
|
||||
"movq %1, %%r10;"
|
||||
"movq %2, %%r11;"
|
||||
"movq $0, %%rdx;"
|
||||
"divq %%rdx;"
|
||||
:
|
||||
: "r"((uint64_t)s), "r"(message), "r"(line)
|
||||
: "rax", "rdx", "r8", "r9", "r10");
|
||||
while (1) asm("hlt");
|
||||
}
|
||||
|
||||
[[ noreturn ]] void
|
||||
raise(uefi::status status, const wchar_t *message, size_t line)
|
||||
{
|
||||
if(status_line::fail(message, status))
|
||||
while (1) asm("hlt");
|
||||
else
|
||||
cpu_assert(status, message, line);
|
||||
if(status_line::fail(message, status))
|
||||
while (1) asm("hlt");
|
||||
else
|
||||
cpu_assert(status, message, line);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,6 @@ raise(uefi::status status, const wchar_t *message, size_t line)
|
||||
|
||||
void debug_break()
|
||||
{
|
||||
volatile int go = 0;
|
||||
while (!go);
|
||||
volatile int go = 0;
|
||||
while (!go);
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ void debug_break();
|
||||
/// \arg s An expression evaluating to a UEFI status
|
||||
/// \arg m The error message to use on failure
|
||||
#define try_or_raise(s, m) \
|
||||
do { \
|
||||
uefi::status _s = (s); \
|
||||
if (uefi::is_error(_s)) ::boot::error::raise(_s, (m), __LINE__); \
|
||||
} while(0)
|
||||
do { \
|
||||
uefi::status _s = (s); \
|
||||
if (uefi::is_error(_s)) ::boot::error::raise(_s, (m), __LINE__); \
|
||||
} while(0)
|
||||
|
||||
|
||||
@@ -19,91 +19,91 @@ namespace fs {
|
||||
using memory::alloc_type;
|
||||
|
||||
file::file(uefi::protos::file *f) :
|
||||
m_file(f)
|
||||
m_file(f)
|
||||
{
|
||||
}
|
||||
|
||||
file::file(file &o) :
|
||||
m_file(o.m_file)
|
||||
m_file(o.m_file)
|
||||
{
|
||||
o.m_file = nullptr;
|
||||
o.m_file = nullptr;
|
||||
}
|
||||
|
||||
file::file(file &&o) :
|
||||
m_file(o.m_file)
|
||||
m_file(o.m_file)
|
||||
{
|
||||
o.m_file = nullptr;
|
||||
o.m_file = nullptr;
|
||||
}
|
||||
|
||||
file::~file()
|
||||
{
|
||||
if (m_file)
|
||||
m_file->close();
|
||||
if (m_file)
|
||||
m_file->close();
|
||||
}
|
||||
|
||||
file
|
||||
file::open(const wchar_t *path)
|
||||
{
|
||||
uefi::protos::file *fh = nullptr;
|
||||
uefi::protos::file *fh = nullptr;
|
||||
|
||||
try_or_raise(
|
||||
m_file->open(&fh, path, uefi::file_mode::read, uefi::file_attr::none),
|
||||
L"Could not open relative path to file");
|
||||
try_or_raise(
|
||||
m_file->open(&fh, path, uefi::file_mode::read, uefi::file_attr::none),
|
||||
L"Could not open relative path to file");
|
||||
|
||||
return file(fh);
|
||||
return file(fh);
|
||||
}
|
||||
|
||||
buffer
|
||||
file::load()
|
||||
{
|
||||
uint8_t info_buf[sizeof(uefi::protos::file_info) + 100];
|
||||
size_t size = sizeof(info_buf);
|
||||
uefi::guid info_guid = uefi::protos::file_info::guid;
|
||||
uint8_t info_buf[sizeof(uefi::protos::file_info) + 100];
|
||||
size_t size = sizeof(info_buf);
|
||||
uefi::guid info_guid = uefi::protos::file_info::guid;
|
||||
|
||||
try_or_raise(
|
||||
m_file->get_info(&info_guid, &size, &info_buf),
|
||||
L"Could not get file info");
|
||||
try_or_raise(
|
||||
m_file->get_info(&info_guid, &size, &info_buf),
|
||||
L"Could not get file info");
|
||||
|
||||
uefi::protos::file_info *info =
|
||||
reinterpret_cast<uefi::protos::file_info*>(&info_buf);
|
||||
uefi::protos::file_info *info =
|
||||
reinterpret_cast<uefi::protos::file_info*>(&info_buf);
|
||||
|
||||
size_t pages = memory::bytes_to_pages(info->file_size);
|
||||
void *data = g_alloc.allocate_pages(pages, alloc_type::file);
|
||||
size_t pages = memory::bytes_to_pages(info->file_size);
|
||||
void *data = g_alloc.allocate_pages(pages, alloc_type::file);
|
||||
|
||||
size = info->file_size;
|
||||
try_or_raise(
|
||||
m_file->read(&size, data),
|
||||
L"Could not read from file");
|
||||
size = info->file_size;
|
||||
try_or_raise(
|
||||
m_file->read(&size, data),
|
||||
L"Could not read from file");
|
||||
|
||||
return { .pointer = data, .count = size };
|
||||
return { .pointer = data, .count = size };
|
||||
}
|
||||
|
||||
file
|
||||
get_boot_volume(uefi::handle image, uefi::boot_services *bs)
|
||||
{
|
||||
status_line status(L"Looking up boot volume");
|
||||
status_line status(L"Looking up boot volume");
|
||||
|
||||
const uefi::guid le_guid = uefi::protos::loaded_image::guid;
|
||||
uefi::protos::loaded_image *loaded_image = nullptr;
|
||||
const uefi::guid le_guid = uefi::protos::loaded_image::guid;
|
||||
uefi::protos::loaded_image *loaded_image = nullptr;
|
||||
|
||||
try_or_raise(
|
||||
bs->handle_protocol(image, &le_guid,
|
||||
reinterpret_cast<void**>(&loaded_image)),
|
||||
L"Could not find currently running UEFI loaded image");
|
||||
try_or_raise(
|
||||
bs->handle_protocol(image, &le_guid,
|
||||
reinterpret_cast<void**>(&loaded_image)),
|
||||
L"Could not find currently running UEFI loaded image");
|
||||
|
||||
const uefi::guid sfs_guid = uefi::protos::simple_file_system::guid;
|
||||
uefi::protos::simple_file_system *fs;
|
||||
try_or_raise(
|
||||
bs->handle_protocol(loaded_image->device_handle, &sfs_guid,
|
||||
reinterpret_cast<void**>(&fs)),
|
||||
L"Could not find filesystem protocol for boot volume");
|
||||
const uefi::guid sfs_guid = uefi::protos::simple_file_system::guid;
|
||||
uefi::protos::simple_file_system *fs;
|
||||
try_or_raise(
|
||||
bs->handle_protocol(loaded_image->device_handle, &sfs_guid,
|
||||
reinterpret_cast<void**>(&fs)),
|
||||
L"Could not find filesystem protocol for boot volume");
|
||||
|
||||
uefi::protos::file *f;
|
||||
try_or_raise(
|
||||
fs->open_volume(&f),
|
||||
L"Could not open the boot volume");
|
||||
uefi::protos::file *f;
|
||||
try_or_raise(
|
||||
fs->open_volume(&f),
|
||||
L"Could not open the boot volume");
|
||||
|
||||
return file(f);
|
||||
return file(f);
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#include "counted.h"
|
||||
|
||||
namespace uefi {
|
||||
struct boot_services;
|
||||
struct boot_services;
|
||||
namespace protos {
|
||||
struct file;
|
||||
struct file;
|
||||
}}
|
||||
|
||||
namespace boot {
|
||||
@@ -18,26 +18,26 @@ namespace fs {
|
||||
class file
|
||||
{
|
||||
public:
|
||||
file(file &&o);
|
||||
file(file &o);
|
||||
~file();
|
||||
file(file &&o);
|
||||
file(file &o);
|
||||
~file();
|
||||
|
||||
/// Open another file or directory, relative to this one.
|
||||
/// \arg path Relative path to the target file from this one
|
||||
file open(const wchar_t *path);
|
||||
/// Open another file or directory, relative to this one.
|
||||
/// \arg path Relative path to the target file from this one
|
||||
file open(const wchar_t *path);
|
||||
|
||||
/// Load the contents of this file into memory.
|
||||
/// \returns A buffer describing the loaded memory. The
|
||||
/// memory will be page-aligned.
|
||||
buffer load();
|
||||
/// Load the contents of this file into memory.
|
||||
/// \returns A buffer describing the loaded memory. The
|
||||
/// memory will be page-aligned.
|
||||
buffer load();
|
||||
|
||||
private:
|
||||
friend file get_boot_volume(uefi::handle, uefi::boot_services*);
|
||||
friend file get_boot_volume(uefi::handle, uefi::boot_services*);
|
||||
|
||||
file(uefi::protos::file *f);
|
||||
file(uefi::protos::file *f);
|
||||
|
||||
uefi::protos::file *m_file;
|
||||
uefi::boot_services *m_bs;
|
||||
uefi::protos::file *m_file;
|
||||
uefi::boot_services *m_bs;
|
||||
};
|
||||
|
||||
/// Get the filesystem this loader was loaded from.
|
||||
|
||||
@@ -10,92 +10,92 @@ namespace hw {
|
||||
void *
|
||||
find_acpi_table(uefi::system_table *st)
|
||||
{
|
||||
status_line status(L"Searching for ACPI table");
|
||||
status_line status(L"Searching for ACPI table");
|
||||
|
||||
// Find ACPI tables. Ignore ACPI 1.0 if a 2.0 table is found.
|
||||
uintptr_t acpi1_table = 0;
|
||||
// Find ACPI tables. Ignore ACPI 1.0 if a 2.0 table is found.
|
||||
uintptr_t acpi1_table = 0;
|
||||
|
||||
for (size_t i = 0; i < st->number_of_table_entries; ++i) {
|
||||
uefi::configuration_table *table = &st->configuration_table[i];
|
||||
for (size_t i = 0; i < st->number_of_table_entries; ++i) {
|
||||
uefi::configuration_table *table = &st->configuration_table[i];
|
||||
|
||||
// If we find an ACPI 2.0 table, return it immediately
|
||||
if (table->vendor_guid == uefi::vendor_guids::acpi2)
|
||||
return table->vendor_table;
|
||||
// If we find an ACPI 2.0 table, return it immediately
|
||||
if (table->vendor_guid == uefi::vendor_guids::acpi2)
|
||||
return table->vendor_table;
|
||||
|
||||
if (table->vendor_guid == uefi::vendor_guids::acpi1) {
|
||||
// Mark a v1 table with the LSB high
|
||||
acpi1_table = reinterpret_cast<uintptr_t>(table->vendor_table);
|
||||
acpi1_table |= 1;
|
||||
}
|
||||
}
|
||||
if (table->vendor_guid == uefi::vendor_guids::acpi1) {
|
||||
// Mark a v1 table with the LSB high
|
||||
acpi1_table = reinterpret_cast<uintptr_t>(table->vendor_table);
|
||||
acpi1_table |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!acpi1_table) {
|
||||
error::raise(uefi::status::not_found, L"Could not find ACPI table");
|
||||
} else if (acpi1_table & 1) {
|
||||
status_line::warn(L"Only found ACPI 1.0 table");
|
||||
}
|
||||
if (!acpi1_table) {
|
||||
error::raise(uefi::status::not_found, L"Could not find ACPI table");
|
||||
} else if (acpi1_table & 1) {
|
||||
status_line::warn(L"Only found ACPI 1.0 table");
|
||||
}
|
||||
|
||||
return reinterpret_cast<void*>(acpi1_table);
|
||||
return reinterpret_cast<void*>(acpi1_table);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
rdmsr(uint32_t addr)
|
||||
{
|
||||
uint32_t low, high;
|
||||
__asm__ __volatile__ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr));
|
||||
return (static_cast<uint64_t>(high) << 32) | low;
|
||||
uint32_t low, high;
|
||||
__asm__ __volatile__ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr));
|
||||
return (static_cast<uint64_t>(high) << 32) | low;
|
||||
}
|
||||
|
||||
static void
|
||||
wrmsr(uint32_t addr, uint64_t value)
|
||||
{
|
||||
uint32_t low = value & 0xffffffff;
|
||||
uint32_t high = value >> 32;
|
||||
__asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high));
|
||||
uint32_t low = value & 0xffffffff;
|
||||
uint32_t high = value >> 32;
|
||||
__asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high));
|
||||
}
|
||||
|
||||
void
|
||||
setup_control_regs()
|
||||
{
|
||||
uint64_t cr4 = 0;
|
||||
asm volatile ( "mov %%cr4, %0" : "=r" (cr4) );
|
||||
cr4 |=
|
||||
0x000080 | // Enable global pages
|
||||
0x000200 | // Enable FXSAVE/FXRSTOR
|
||||
0x010000 | // Enable FSGSBASE
|
||||
0x020000 | // Enable PCIDs
|
||||
0;
|
||||
asm volatile ( "mov %0, %%cr4" :: "r" (cr4) );
|
||||
uint64_t cr4 = 0;
|
||||
asm volatile ( "mov %%cr4, %0" : "=r" (cr4) );
|
||||
cr4 |=
|
||||
0x000080 | // Enable global pages
|
||||
0x000200 | // Enable FXSAVE/FXRSTOR
|
||||
0x010000 | // Enable FSGSBASE
|
||||
0x020000 | // Enable PCIDs
|
||||
0;
|
||||
asm volatile ( "mov %0, %%cr4" :: "r" (cr4) );
|
||||
|
||||
// Set up IA32_EFER
|
||||
constexpr uint32_t IA32_EFER = 0xC0000080;
|
||||
uint64_t efer = rdmsr(IA32_EFER);
|
||||
efer |=
|
||||
0x0001 | // Enable SYSCALL
|
||||
0x0800 | // Enable NX bit
|
||||
0;
|
||||
wrmsr(IA32_EFER, efer);
|
||||
// Set up IA32_EFER
|
||||
constexpr uint32_t IA32_EFER = 0xC0000080;
|
||||
uint64_t efer = rdmsr(IA32_EFER);
|
||||
efer |=
|
||||
0x0001 | // Enable SYSCALL
|
||||
0x0800 | // Enable NX bit
|
||||
0;
|
||||
wrmsr(IA32_EFER, efer);
|
||||
}
|
||||
|
||||
void
|
||||
check_cpu_supported()
|
||||
{
|
||||
status_line status {L"Checking CPU features"};
|
||||
status_line status {L"Checking CPU features"};
|
||||
|
||||
cpu::cpu_id cpu;
|
||||
uint64_t missing = cpu.missing();
|
||||
if (missing) {
|
||||
cpu::cpu_id cpu;
|
||||
uint64_t missing = cpu.missing();
|
||||
if (missing) {
|
||||
#define CPU_FEATURE_OPT(...)
|
||||
#define CPU_FEATURE_REQ(name, ...) \
|
||||
if (!cpu.has_feature(cpu::feature::name)) { \
|
||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||
}
|
||||
if (!cpu.has_feature(cpu::feature::name)) { \
|
||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||
}
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_REQ
|
||||
#undef CPU_FEATURE_OPT
|
||||
|
||||
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||
}
|
||||
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,108 +23,108 @@ using memory::alloc_type;
|
||||
|
||||
buffer
|
||||
load_file(
|
||||
fs::file &disk,
|
||||
const program_desc &desc)
|
||||
fs::file &disk,
|
||||
const program_desc &desc)
|
||||
{
|
||||
status_line status(L"Loading file", desc.path);
|
||||
status_line status(L"Loading file", desc.path);
|
||||
|
||||
fs::file file = disk.open(desc.path);
|
||||
buffer b = file.load();
|
||||
fs::file file = disk.open(desc.path);
|
||||
buffer b = file.load();
|
||||
|
||||
//console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
||||
return b;
|
||||
//console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
create_module(buffer data, const program_desc &desc, bool loaded)
|
||||
{
|
||||
size_t path_len = wstrlen(desc.path);
|
||||
init::module_program *mod = g_alloc.allocate_module<init::module_program>(path_len);
|
||||
mod->mod_type = init::module_type::program;
|
||||
mod->base_address = reinterpret_cast<uintptr_t>(data.pointer);
|
||||
if (loaded)
|
||||
mod->mod_flags = static_cast<init::module_flags>(
|
||||
static_cast<uint8_t>(mod->mod_flags) |
|
||||
static_cast<uint8_t>(init::module_flags::no_load));
|
||||
size_t path_len = wstrlen(desc.path);
|
||||
init::module_program *mod = g_alloc.allocate_module<init::module_program>(path_len);
|
||||
mod->mod_type = init::module_type::program;
|
||||
mod->base_address = reinterpret_cast<uintptr_t>(data.pointer);
|
||||
if (loaded)
|
||||
mod->mod_flags = static_cast<init::module_flags>(
|
||||
static_cast<uint8_t>(mod->mod_flags) |
|
||||
static_cast<uint8_t>(init::module_flags::no_load));
|
||||
|
||||
// TODO: support non-ascii path characters and do real utf-16 to utf-8
|
||||
// conversion
|
||||
for (int i = 0; i < path_len; ++i)
|
||||
mod->filename[i] = desc.path[i];
|
||||
mod->filename[path_len] = 0;
|
||||
// TODO: support non-ascii path characters and do real utf-16 to utf-8
|
||||
// conversion
|
||||
for (int i = 0; i < path_len; ++i)
|
||||
mod->filename[i] = desc.path[i];
|
||||
mod->filename[path_len] = 0;
|
||||
}
|
||||
|
||||
init::program *
|
||||
load_program(
|
||||
fs::file &disk,
|
||||
const program_desc &desc,
|
||||
bool add_module)
|
||||
fs::file &disk,
|
||||
const program_desc &desc,
|
||||
bool add_module)
|
||||
{
|
||||
status_line status(L"Loading program", desc.name);
|
||||
status_line status(L"Loading program", desc.name);
|
||||
|
||||
buffer data = load_file(disk, desc);
|
||||
buffer data = load_file(disk, desc);
|
||||
|
||||
if (add_module)
|
||||
create_module(data, desc, true);
|
||||
if (add_module)
|
||||
create_module(data, desc, true);
|
||||
|
||||
elf::file program(data.pointer, data.count);
|
||||
if (!program.valid())
|
||||
error::raise(uefi::status::load_error, L"ELF file not valid");
|
||||
elf::file program(data.pointer, data.count);
|
||||
if (!program.valid())
|
||||
error::raise(uefi::status::load_error, L"ELF file not valid");
|
||||
|
||||
size_t num_sections = 0;
|
||||
for (auto &seg : program.programs()) {
|
||||
if (seg.type == elf::segment_type::load)
|
||||
++num_sections;
|
||||
}
|
||||
size_t num_sections = 0;
|
||||
for (auto &seg : program.programs()) {
|
||||
if (seg.type == elf::segment_type::load)
|
||||
++num_sections;
|
||||
}
|
||||
|
||||
init::program_section *sections = new init::program_section [num_sections];
|
||||
init::program_section *sections = new init::program_section [num_sections];
|
||||
|
||||
size_t next_section = 0;
|
||||
for (auto &seg : program.programs()) {
|
||||
if (seg.type != elf::segment_type::load)
|
||||
continue;
|
||||
size_t next_section = 0;
|
||||
for (auto &seg : program.programs()) {
|
||||
if (seg.type != elf::segment_type::load)
|
||||
continue;
|
||||
|
||||
init::program_section §ion = sections[next_section++];
|
||||
init::program_section §ion = sections[next_section++];
|
||||
|
||||
size_t page_count = memory::bytes_to_pages(seg.mem_size);
|
||||
size_t page_count = memory::bytes_to_pages(seg.mem_size);
|
||||
|
||||
if (seg.mem_size > seg.file_size) {
|
||||
void *pages = g_alloc.allocate_pages(page_count, alloc_type::program, true);
|
||||
void *source = offset_ptr<void>(data.pointer, seg.offset);
|
||||
g_alloc.copy(pages, source, seg.file_size);
|
||||
section.phys_addr = reinterpret_cast<uintptr_t>(pages);
|
||||
} else {
|
||||
section.phys_addr = program.base() + seg.offset;
|
||||
}
|
||||
if (seg.mem_size > seg.file_size) {
|
||||
void *pages = g_alloc.allocate_pages(page_count, alloc_type::program, true);
|
||||
void *source = offset_ptr<void>(data.pointer, seg.offset);
|
||||
g_alloc.copy(pages, source, seg.file_size);
|
||||
section.phys_addr = reinterpret_cast<uintptr_t>(pages);
|
||||
} else {
|
||||
section.phys_addr = program.base() + seg.offset;
|
||||
}
|
||||
|
||||
section.virt_addr = seg.vaddr;
|
||||
section.size = seg.mem_size;
|
||||
section.type = static_cast<init::section_flags>(seg.flags);
|
||||
}
|
||||
section.virt_addr = seg.vaddr;
|
||||
section.size = seg.mem_size;
|
||||
section.type = static_cast<init::section_flags>(seg.flags);
|
||||
}
|
||||
|
||||
init::program *prog = new init::program;
|
||||
prog->sections = { .pointer = sections, .count = num_sections };
|
||||
prog->phys_base = program.base();
|
||||
prog->entrypoint = program.entrypoint();
|
||||
return prog;
|
||||
init::program *prog = new init::program;
|
||||
prog->sections = { .pointer = sections, .count = num_sections };
|
||||
prog->phys_base = program.base();
|
||||
prog->entrypoint = program.entrypoint();
|
||||
return prog;
|
||||
}
|
||||
|
||||
void
|
||||
load_module(
|
||||
fs::file &disk,
|
||||
const program_desc &desc)
|
||||
fs::file &disk,
|
||||
const program_desc &desc)
|
||||
{
|
||||
status_line status(L"Loading module", desc.name);
|
||||
status_line status(L"Loading module", desc.name);
|
||||
|
||||
buffer data = load_file(disk, desc);
|
||||
create_module(data, desc, false);
|
||||
buffer data = load_file(disk, desc);
|
||||
create_module(data, desc, false);
|
||||
}
|
||||
|
||||
void
|
||||
verify_kernel_header(init::program &program)
|
||||
{
|
||||
status_line status(L"Verifying kernel header");
|
||||
status_line status(L"Verifying kernel header");
|
||||
|
||||
const init::header *header =
|
||||
reinterpret_cast<const init::header *>(program.sections[0].phys_addr);
|
||||
@@ -138,15 +138,15 @@ verify_kernel_header(init::program &program)
|
||||
if (header->version < init::min_header_version)
|
||||
error::raise(uefi::status::unsupported, L"Kernel header version not supported");
|
||||
|
||||
console::print(L" Loaded kernel vserion: %d.%d.%d %x\r\n",
|
||||
console::print(L" Loaded kernel vserion: %d.%d.%d %x\r\n",
|
||||
header->version_major, header->version_minor, header->version_patch,
|
||||
header->version_gitsha);
|
||||
|
||||
/*
|
||||
for (auto §ion : program.sections)
|
||||
console::print(L" Section: p:0x%lx v:0x%lx fs:0x%x ms:0x%x\r\n",
|
||||
section.phys_addr, section.virt_addr, section.file_size, section.mem_size);
|
||||
*/
|
||||
/*
|
||||
for (auto §ion : program.sections)
|
||||
console::print(L" Section: p:0x%lx v:0x%lx fs:0x%x ms:0x%x\r\n",
|
||||
section.phys_addr, section.virt_addr, section.file_size, section.mem_size);
|
||||
*/
|
||||
}
|
||||
|
||||
} // namespace loader
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
|
||||
namespace kernel {
|
||||
namespace init {
|
||||
struct program;
|
||||
struct module;
|
||||
struct program;
|
||||
struct module;
|
||||
}}
|
||||
|
||||
namespace boot {
|
||||
|
||||
namespace fs {
|
||||
class file;
|
||||
class file;
|
||||
}
|
||||
|
||||
namespace loader {
|
||||
|
||||
struct program_desc
|
||||
{
|
||||
const wchar_t *name;
|
||||
const wchar_t *path;
|
||||
const wchar_t *name;
|
||||
const wchar_t *path;
|
||||
};
|
||||
|
||||
/// Load a file from disk into memory.
|
||||
@@ -29,8 +29,8 @@ struct program_desc
|
||||
/// \arg desc The program descriptor identifying the file
|
||||
buffer
|
||||
load_file(
|
||||
fs::file &disk,
|
||||
const program_desc &desc);
|
||||
fs::file &disk,
|
||||
const program_desc &desc);
|
||||
|
||||
/// Parse and load an ELF file in memory into a loaded image.
|
||||
/// \arg disk The opened UEFI filesystem to load from
|
||||
@@ -38,17 +38,17 @@ load_file(
|
||||
/// \arg add_module Also create a module for this loaded program
|
||||
kernel::init::program *
|
||||
load_program(
|
||||
fs::file &disk,
|
||||
const program_desc &desc,
|
||||
bool add_module = false);
|
||||
fs::file &disk,
|
||||
const program_desc &desc,
|
||||
bool add_module = false);
|
||||
|
||||
/// Load a file from disk into memory, creating an init args module
|
||||
/// \arg disk The opened UEFI filesystem to load from
|
||||
/// \arg desc The program descriptor identifying the file
|
||||
void
|
||||
load_module(
|
||||
fs::file &disk,
|
||||
const program_desc &desc);
|
||||
fs::file &disk,
|
||||
const program_desc &desc);
|
||||
|
||||
/// Verify that a loaded ELF has the j6 kernel header
|
||||
/// \arg program The program to check for a header
|
||||
|
||||
@@ -36,7 +36,7 @@ const loader::program_desc fb_driver = {L"UEFI framebuffer driver", L"drv.uefi_f
|
||||
const loader::program_desc panic_handler = {L"Serial panic handler", L"panic.serial.elf"};
|
||||
|
||||
const loader::program_desc extra_programs[] = {
|
||||
{L"test application", L"testapp.elf"},
|
||||
{L"test application", L"testapp.elf"},
|
||||
};
|
||||
|
||||
/// Change a pointer to point to the higher-half linear-offset version
|
||||
@@ -44,7 +44,7 @@ const loader::program_desc extra_programs[] = {
|
||||
template <typename T>
|
||||
void change_pointer(T *&pointer)
|
||||
{
|
||||
pointer = offset_ptr<T>(pointer, kernel::memory::page_offset);
|
||||
pointer = offset_ptr<T>(pointer, kernel::memory::page_offset);
|
||||
}
|
||||
|
||||
/// The main procedure for the portion of the loader that runs while
|
||||
@@ -53,50 +53,50 @@ void change_pointer(T *&pointer)
|
||||
init::args *
|
||||
uefi_preboot(uefi::handle image, uefi::system_table *st)
|
||||
{
|
||||
uefi::boot_services *bs = st->boot_services;
|
||||
uefi::runtime_services *rs = st->runtime_services;
|
||||
uefi::boot_services *bs = st->boot_services;
|
||||
uefi::runtime_services *rs = st->runtime_services;
|
||||
|
||||
status_line status {L"Performing UEFI pre-boot"};
|
||||
status_line status {L"Performing UEFI pre-boot"};
|
||||
|
||||
hw::check_cpu_supported();
|
||||
memory::init_pointer_fixup(bs, rs);
|
||||
hw::check_cpu_supported();
|
||||
memory::init_pointer_fixup(bs, rs);
|
||||
|
||||
init::args *args = new init::args;
|
||||
g_alloc.zero(args, sizeof(init::args));
|
||||
init::args *args = new init::args;
|
||||
g_alloc.zero(args, sizeof(init::args));
|
||||
|
||||
args->magic = init::args_magic;
|
||||
args->version = init::args_version;
|
||||
args->runtime_services = rs;
|
||||
args->acpi_table = hw::find_acpi_table(st);
|
||||
memory::mark_pointer_fixup(&args->runtime_services);
|
||||
args->magic = init::args_magic;
|
||||
args->version = init::args_version;
|
||||
args->runtime_services = rs;
|
||||
args->acpi_table = hw::find_acpi_table(st);
|
||||
memory::mark_pointer_fixup(&args->runtime_services);
|
||||
|
||||
paging::allocate_tables(args);
|
||||
paging::allocate_tables(args);
|
||||
|
||||
return args;
|
||||
return args;
|
||||
}
|
||||
|
||||
/// Load the kernel and other programs from disk
|
||||
void
|
||||
load_resources(init::args *args, video::screen *screen, uefi::handle image, uefi::boot_services *bs)
|
||||
{
|
||||
status_line status {L"Loading programs"};
|
||||
status_line status {L"Loading programs"};
|
||||
|
||||
fs::file disk = fs::get_boot_volume(image, bs);
|
||||
fs::file disk = fs::get_boot_volume(image, bs);
|
||||
|
||||
if (screen) {
|
||||
video::make_module(screen);
|
||||
loader::load_module(disk, fb_driver);
|
||||
}
|
||||
if (screen) {
|
||||
video::make_module(screen);
|
||||
loader::load_module(disk, fb_driver);
|
||||
}
|
||||
|
||||
buffer symbol_table = loader::load_file(disk, {L"symbol table", L"symbol_table.dat"});
|
||||
args->symbol_table = reinterpret_cast<uintptr_t>(symbol_table.pointer);
|
||||
args->symbol_table = reinterpret_cast<uintptr_t>(symbol_table.pointer);
|
||||
|
||||
args->kernel = loader::load_program(disk, kern_desc, true);
|
||||
args->init = loader::load_program(disk, init_desc);
|
||||
args->kernel = loader::load_program(disk, kern_desc, true);
|
||||
args->init = loader::load_program(disk, init_desc);
|
||||
args->panic = loader::load_program(disk, panic_handler);
|
||||
|
||||
for (auto &desc : extra_programs)
|
||||
loader::load_module(disk, desc);
|
||||
for (auto &desc : extra_programs)
|
||||
loader::load_module(disk, desc);
|
||||
|
||||
loader::verify_kernel_header(*args->kernel);
|
||||
}
|
||||
@@ -104,20 +104,20 @@ load_resources(init::args *args, video::screen *screen, uefi::handle image, uefi
|
||||
memory::efi_mem_map
|
||||
uefi_exit(init::args *args, uefi::handle image, uefi::boot_services *bs)
|
||||
{
|
||||
status_line status {L"Exiting UEFI", nullptr, false};
|
||||
status_line status {L"Exiting UEFI", nullptr, false};
|
||||
|
||||
memory::efi_mem_map map;
|
||||
map.update(*bs);
|
||||
memory::efi_mem_map map;
|
||||
map.update(*bs);
|
||||
|
||||
args->mem_map = memory::build_kernel_map(map);
|
||||
args->frame_blocks = memory::build_frame_blocks(args->mem_map);
|
||||
args->mem_map = memory::build_kernel_map(map);
|
||||
args->frame_blocks = memory::build_frame_blocks(args->mem_map);
|
||||
|
||||
map.update(*bs);
|
||||
try_or_raise(
|
||||
bs->exit_boot_services(image, map.key),
|
||||
L"Failed to exit boot services");
|
||||
map.update(*bs);
|
||||
try_or_raise(
|
||||
bs->exit_boot_services(image, map.key),
|
||||
L"Failed to exit boot services");
|
||||
|
||||
return map;
|
||||
return map;
|
||||
}
|
||||
|
||||
} // namespace boot
|
||||
@@ -126,53 +126,53 @@ uefi_exit(init::args *args, uefi::handle image, uefi::boot_services *bs)
|
||||
extern "C" uefi::status
|
||||
efi_main(uefi::handle image, uefi::system_table *st)
|
||||
{
|
||||
using namespace boot;
|
||||
using namespace boot;
|
||||
|
||||
uefi::boot_services *bs = st->boot_services;
|
||||
console con(st->con_out);
|
||||
uefi::boot_services *bs = st->boot_services;
|
||||
console con(st->con_out);
|
||||
|
||||
init::allocation_register *allocs = nullptr;
|
||||
init::modules_page *modules = nullptr;
|
||||
memory::allocator::init(allocs, modules, bs);
|
||||
init::allocation_register *allocs = nullptr;
|
||||
init::modules_page *modules = nullptr;
|
||||
memory::allocator::init(allocs, modules, bs);
|
||||
|
||||
video::screen *screen = video::pick_mode(bs);
|
||||
con.announce();
|
||||
video::screen *screen = video::pick_mode(bs);
|
||||
con.announce();
|
||||
|
||||
init::args *args = uefi_preboot(image, st);
|
||||
load_resources(args, screen, image, bs);
|
||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||
init::args *args = uefi_preboot(image, st);
|
||||
load_resources(args, screen, image, bs);
|
||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||
|
||||
args->allocations = allocs;
|
||||
args->modules = reinterpret_cast<uintptr_t>(modules);
|
||||
args->allocations = allocs;
|
||||
args->modules = reinterpret_cast<uintptr_t>(modules);
|
||||
|
||||
status_bar status {screen}; // Switch to fb status display
|
||||
status_bar status {screen}; // Switch to fb status display
|
||||
|
||||
// Map the kernel and panic handler to the appropriate addresses
|
||||
// Map the kernel and panic handler to the appropriate addresses
|
||||
paging::map_program(args, *args->kernel);
|
||||
paging::map_program(args, *args->panic);
|
||||
|
||||
memory::fix_frame_blocks(args);
|
||||
memory::fix_frame_blocks(args);
|
||||
|
||||
init::entrypoint kentry =
|
||||
reinterpret_cast<init::entrypoint>(args->kernel->entrypoint);
|
||||
//status.next();
|
||||
init::entrypoint kentry =
|
||||
reinterpret_cast<init::entrypoint>(args->kernel->entrypoint);
|
||||
//status.next();
|
||||
|
||||
hw::setup_control_regs();
|
||||
memory::virtualize(args->pml4, map, st->runtime_services);
|
||||
//status.next();
|
||||
hw::setup_control_regs();
|
||||
memory::virtualize(args->pml4, map, st->runtime_services);
|
||||
//status.next();
|
||||
|
||||
change_pointer(args);
|
||||
change_pointer(args->pml4);
|
||||
change_pointer(args);
|
||||
change_pointer(args->pml4);
|
||||
|
||||
change_pointer(args->kernel);
|
||||
change_pointer(args->kernel->sections.pointer);
|
||||
change_pointer(args->init);
|
||||
change_pointer(args->init->sections.pointer);
|
||||
change_pointer(args->kernel);
|
||||
change_pointer(args->kernel->sections.pointer);
|
||||
change_pointer(args->init);
|
||||
change_pointer(args->init->sections.pointer);
|
||||
|
||||
//status.next();
|
||||
//status.next();
|
||||
|
||||
kentry(args);
|
||||
debug_break();
|
||||
return uefi::status::unsupported;
|
||||
kentry(args);
|
||||
debug_break();
|
||||
return uefi::status::unsupported;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,56 +22,56 @@ void **fixup_pointers[64];
|
||||
void
|
||||
update_marked_addresses(uefi::event, void *context)
|
||||
{
|
||||
uefi::runtime_services *rs =
|
||||
reinterpret_cast<uefi::runtime_services*>(context);
|
||||
uefi::runtime_services *rs =
|
||||
reinterpret_cast<uefi::runtime_services*>(context);
|
||||
|
||||
for (size_t i = 0; i < fixup_pointer_index; ++i) {
|
||||
if (fixup_pointers[i])
|
||||
rs->convert_pointer(0, fixup_pointers[i]);
|
||||
}
|
||||
for (size_t i = 0; i < fixup_pointer_index; ++i) {
|
||||
if (fixup_pointers[i])
|
||||
rs->convert_pointer(0, fixup_pointers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init_pointer_fixup(uefi::boot_services *bs, uefi::runtime_services *rs)
|
||||
{
|
||||
status_line status(L"Initializing pointer virtualization event");
|
||||
status_line status(L"Initializing pointer virtualization event");
|
||||
|
||||
uefi::event event;
|
||||
bs->set_mem(&fixup_pointers, sizeof(fixup_pointers), 0);
|
||||
fixup_pointer_index = 0;
|
||||
uefi::event event;
|
||||
bs->set_mem(&fixup_pointers, sizeof(fixup_pointers), 0);
|
||||
fixup_pointer_index = 0;
|
||||
|
||||
try_or_raise(
|
||||
bs->create_event(
|
||||
uefi::evt::signal_virtual_address_change,
|
||||
uefi::tpl::callback,
|
||||
(uefi::event_notify)&update_marked_addresses,
|
||||
rs,
|
||||
&event),
|
||||
L"Error creating memory virtualization event");
|
||||
try_or_raise(
|
||||
bs->create_event(
|
||||
uefi::evt::signal_virtual_address_change,
|
||||
uefi::tpl::callback,
|
||||
(uefi::event_notify)&update_marked_addresses,
|
||||
rs,
|
||||
&event),
|
||||
L"Error creating memory virtualization event");
|
||||
}
|
||||
|
||||
void
|
||||
mark_pointer_fixup(void **p)
|
||||
{
|
||||
fixup_pointers[fixup_pointer_index++] = p;
|
||||
fixup_pointers[fixup_pointer_index++] = p;
|
||||
}
|
||||
|
||||
void
|
||||
virtualize(void *pml4, efi_mem_map &map, uefi::runtime_services *rs)
|
||||
{
|
||||
paging::add_current_mappings(reinterpret_cast<paging::page_table*>(pml4));
|
||||
paging::add_current_mappings(reinterpret_cast<paging::page_table*>(pml4));
|
||||
|
||||
for (auto &desc : map)
|
||||
desc.virtual_start = desc.physical_start + ::memory::page_offset;
|
||||
for (auto &desc : map)
|
||||
desc.virtual_start = desc.physical_start + ::memory::page_offset;
|
||||
|
||||
// Write our new PML4 pointer to CR3
|
||||
asm volatile ( "mov %0, %%cr3" :: "r" (pml4) );
|
||||
__sync_synchronize();
|
||||
// Write our new PML4 pointer to CR3
|
||||
asm volatile ( "mov %0, %%cr3" :: "r" (pml4) );
|
||||
__sync_synchronize();
|
||||
|
||||
try_or_raise(
|
||||
rs->set_virtual_address_map(
|
||||
map.length, map.size, map.version, map.entries),
|
||||
L"Error setting virtual address map");
|
||||
try_or_raise(
|
||||
rs->set_virtual_address_map(
|
||||
map.length, map.size, map.version, map.entries),
|
||||
L"Error setting virtual address map");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
namespace uefi {
|
||||
struct boot_services;
|
||||
struct runtime_services;
|
||||
struct boot_services;
|
||||
struct runtime_services;
|
||||
}
|
||||
|
||||
namespace boot {
|
||||
@@ -19,7 +19,7 @@ constexpr size_t page_size = 0x1000;
|
||||
|
||||
/// Get the number of pages needed to hold `bytes` bytes
|
||||
inline constexpr size_t bytes_to_pages(size_t bytes) {
|
||||
return ((bytes - 1) / page_size) + 1;
|
||||
return ((bytes - 1) / page_size) + 1;
|
||||
}
|
||||
|
||||
/// \defgroup pointer_fixup
|
||||
@@ -42,9 +42,9 @@ void mark_pointer_fixup(void **p);
|
||||
/// \arg pml4 The root page table for the new mappings
|
||||
/// \arg map The UEFI memory map, used to update runtime services
|
||||
void virtualize(
|
||||
void *pml4,
|
||||
efi_mem_map &map,
|
||||
uefi::runtime_services *rs);
|
||||
void *pml4,
|
||||
efi_mem_map &map,
|
||||
uefi::runtime_services *rs);
|
||||
|
||||
} // namespace boot
|
||||
} // namespace memory
|
||||
|
||||
@@ -21,180 +21,180 @@ using kernel::init::mem_type;
|
||||
void
|
||||
efi_mem_map::update(uefi::boot_services &bs)
|
||||
{
|
||||
size_t l = total;
|
||||
uefi::status status = bs.get_memory_map(
|
||||
&l, entries, &key, &size, &version);
|
||||
length = l;
|
||||
size_t l = total;
|
||||
uefi::status status = bs.get_memory_map(
|
||||
&l, entries, &key, &size, &version);
|
||||
length = l;
|
||||
|
||||
if (status == uefi::status::success)
|
||||
return;
|
||||
if (status == uefi::status::success)
|
||||
return;
|
||||
|
||||
if (status != uefi::status::buffer_too_small)
|
||||
error::raise(status, L"Error getting memory map size");
|
||||
if (status != uefi::status::buffer_too_small)
|
||||
error::raise(status, L"Error getting memory map size");
|
||||
|
||||
if (entries) {
|
||||
try_or_raise(
|
||||
bs.free_pool(reinterpret_cast<void*>(entries)),
|
||||
L"Freeing previous memory map space");
|
||||
}
|
||||
if (entries) {
|
||||
try_or_raise(
|
||||
bs.free_pool(reinterpret_cast<void*>(entries)),
|
||||
L"Freeing previous memory map space");
|
||||
}
|
||||
|
||||
total = length + 10 * size;
|
||||
total = length + 10 * size;
|
||||
|
||||
try_or_raise(
|
||||
bs.allocate_pool(
|
||||
uefi::memory_type::loader_data, total,
|
||||
reinterpret_cast<void**>(&entries)),
|
||||
L"Allocating space for memory map");
|
||||
try_or_raise(
|
||||
bs.allocate_pool(
|
||||
uefi::memory_type::loader_data, total,
|
||||
reinterpret_cast<void**>(&entries)),
|
||||
L"Allocating space for memory map");
|
||||
|
||||
length = total;
|
||||
try_or_raise(
|
||||
bs.get_memory_map(&length, entries, &key, &size, &version),
|
||||
L"Getting UEFI memory map");
|
||||
length = total;
|
||||
try_or_raise(
|
||||
bs.get_memory_map(&length, entries, &key, &size, &version),
|
||||
L"Getting UEFI memory map");
|
||||
}
|
||||
|
||||
static const wchar_t *memory_type_names[] = {
|
||||
L"reserved memory type",
|
||||
L"loader code",
|
||||
L"loader data",
|
||||
L"boot services code",
|
||||
L"boot services data",
|
||||
L"runtime services code",
|
||||
L"runtime services data",
|
||||
L"conventional memory",
|
||||
L"unusable memory",
|
||||
L"acpi reclaim memory",
|
||||
L"acpi memory nvs",
|
||||
L"memory mapped io",
|
||||
L"memory mapped io port space",
|
||||
L"pal code",
|
||||
L"persistent memory"
|
||||
L"reserved memory type",
|
||||
L"loader code",
|
||||
L"loader data",
|
||||
L"boot services code",
|
||||
L"boot services data",
|
||||
L"runtime services code",
|
||||
L"runtime services data",
|
||||
L"conventional memory",
|
||||
L"unusable memory",
|
||||
L"acpi reclaim memory",
|
||||
L"acpi memory nvs",
|
||||
L"memory mapped io",
|
||||
L"memory mapped io port space",
|
||||
L"pal code",
|
||||
L"persistent memory"
|
||||
};
|
||||
|
||||
static const wchar_t *kernel_memory_type_names[] = {
|
||||
L"free",
|
||||
L"pending",
|
||||
L"acpi",
|
||||
L"uefi_runtime",
|
||||
L"mmio",
|
||||
L"persistent"
|
||||
L"free",
|
||||
L"pending",
|
||||
L"acpi",
|
||||
L"uefi_runtime",
|
||||
L"mmio",
|
||||
L"persistent"
|
||||
};
|
||||
|
||||
static const wchar_t *
|
||||
memory_type_name(uefi::memory_type t)
|
||||
{
|
||||
if (t < uefi::memory_type::max_memory_type)
|
||||
return memory_type_names[static_cast<uint32_t>(t)];
|
||||
if (t < uefi::memory_type::max_memory_type)
|
||||
return memory_type_names[static_cast<uint32_t>(t)];
|
||||
|
||||
return L"Bad Type Value";
|
||||
return L"Bad Type Value";
|
||||
}
|
||||
|
||||
static const wchar_t *
|
||||
kernel_memory_type_name(kernel::init::mem_type t)
|
||||
{
|
||||
return kernel_memory_type_names[static_cast<uint32_t>(t)];
|
||||
return kernel_memory_type_names[static_cast<uint32_t>(t)];
|
||||
}
|
||||
|
||||
inline bool
|
||||
can_merge(mem_entry &prev, mem_type type, uefi::memory_descriptor &next)
|
||||
{
|
||||
return
|
||||
prev.type == type &&
|
||||
prev.start + (page_size * prev.pages) == next.physical_start &&
|
||||
prev.attr == (next.attribute & 0xffffffff);
|
||||
return
|
||||
prev.type == type &&
|
||||
prev.start + (page_size * prev.pages) == next.physical_start &&
|
||||
prev.attr == (next.attribute & 0xffffffff);
|
||||
}
|
||||
|
||||
counted<mem_entry>
|
||||
build_kernel_map(efi_mem_map &map)
|
||||
{
|
||||
status_line status {L"Creating kernel memory map"};
|
||||
status_line status {L"Creating kernel memory map"};
|
||||
|
||||
size_t map_size = map.num_entries() * sizeof(mem_entry);
|
||||
size_t num_pages = bytes_to_pages(map_size);
|
||||
mem_entry *kernel_map = reinterpret_cast<mem_entry*>(
|
||||
g_alloc.allocate_pages(num_pages, alloc_type::mem_map, true));
|
||||
size_t map_size = map.num_entries() * sizeof(mem_entry);
|
||||
size_t num_pages = bytes_to_pages(map_size);
|
||||
mem_entry *kernel_map = reinterpret_cast<mem_entry*>(
|
||||
g_alloc.allocate_pages(num_pages, alloc_type::mem_map, true));
|
||||
|
||||
size_t nent = 0;
|
||||
bool first = true;
|
||||
for (auto &desc : map) {
|
||||
/*
|
||||
// EFI map dump
|
||||
console::print(L" eRange %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
desc.physical_start, desc.attribute, desc.type, memory_type_name(desc.type), desc.number_of_pages);
|
||||
*/
|
||||
size_t nent = 0;
|
||||
bool first = true;
|
||||
for (auto &desc : map) {
|
||||
/*
|
||||
// EFI map dump
|
||||
console::print(L" eRange %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
desc.physical_start, desc.attribute, desc.type, memory_type_name(desc.type), desc.number_of_pages);
|
||||
*/
|
||||
|
||||
mem_type type;
|
||||
switch (desc.type) {
|
||||
case uefi::memory_type::reserved:
|
||||
case uefi::memory_type::unusable_memory:
|
||||
case uefi::memory_type::acpi_memory_nvs:
|
||||
case uefi::memory_type::pal_code:
|
||||
continue;
|
||||
mem_type type;
|
||||
switch (desc.type) {
|
||||
case uefi::memory_type::reserved:
|
||||
case uefi::memory_type::unusable_memory:
|
||||
case uefi::memory_type::acpi_memory_nvs:
|
||||
case uefi::memory_type::pal_code:
|
||||
continue;
|
||||
|
||||
case uefi::memory_type::loader_code:
|
||||
case uefi::memory_type::boot_services_code:
|
||||
case uefi::memory_type::boot_services_data:
|
||||
case uefi::memory_type::conventional_memory:
|
||||
case uefi::memory_type::loader_data:
|
||||
type = mem_type::free;
|
||||
break;
|
||||
case uefi::memory_type::loader_code:
|
||||
case uefi::memory_type::boot_services_code:
|
||||
case uefi::memory_type::boot_services_data:
|
||||
case uefi::memory_type::conventional_memory:
|
||||
case uefi::memory_type::loader_data:
|
||||
type = mem_type::free;
|
||||
break;
|
||||
|
||||
case uefi::memory_type::runtime_services_code:
|
||||
case uefi::memory_type::runtime_services_data:
|
||||
type = mem_type::uefi_runtime;
|
||||
break;
|
||||
case uefi::memory_type::runtime_services_code:
|
||||
case uefi::memory_type::runtime_services_data:
|
||||
type = mem_type::uefi_runtime;
|
||||
break;
|
||||
|
||||
case uefi::memory_type::acpi_reclaim_memory:
|
||||
type = mem_type::acpi;
|
||||
break;
|
||||
case uefi::memory_type::acpi_reclaim_memory:
|
||||
type = mem_type::acpi;
|
||||
break;
|
||||
|
||||
case uefi::memory_type::memory_mapped_io:
|
||||
case uefi::memory_type::memory_mapped_io_port_space:
|
||||
type = mem_type::mmio;
|
||||
break;
|
||||
case uefi::memory_type::memory_mapped_io:
|
||||
case uefi::memory_type::memory_mapped_io_port_space:
|
||||
type = mem_type::mmio;
|
||||
break;
|
||||
|
||||
case uefi::memory_type::persistent_memory:
|
||||
type = mem_type::persistent;
|
||||
break;
|
||||
case uefi::memory_type::persistent_memory:
|
||||
type = mem_type::persistent;
|
||||
break;
|
||||
|
||||
default:
|
||||
error::raise(
|
||||
uefi::status::invalid_parameter,
|
||||
L"Got an unexpected memory type from UEFI memory map");
|
||||
}
|
||||
default:
|
||||
error::raise(
|
||||
uefi::status::invalid_parameter,
|
||||
L"Got an unexpected memory type from UEFI memory map");
|
||||
}
|
||||
|
||||
// TODO: validate uefi's map is sorted
|
||||
if (first) {
|
||||
first = false;
|
||||
mem_entry &ent = kernel_map[nent++];
|
||||
ent.start = desc.physical_start;
|
||||
ent.pages = desc.number_of_pages;
|
||||
ent.type = type;
|
||||
ent.attr = (desc.attribute & 0xffffffff);
|
||||
continue;
|
||||
}
|
||||
// TODO: validate uefi's map is sorted
|
||||
if (first) {
|
||||
first = false;
|
||||
mem_entry &ent = kernel_map[nent++];
|
||||
ent.start = desc.physical_start;
|
||||
ent.pages = desc.number_of_pages;
|
||||
ent.type = type;
|
||||
ent.attr = (desc.attribute & 0xffffffff);
|
||||
continue;
|
||||
}
|
||||
|
||||
mem_entry &prev = kernel_map[nent - 1];
|
||||
if (can_merge(prev, type, desc)) {
|
||||
prev.pages += desc.number_of_pages;
|
||||
} else {
|
||||
mem_entry &next = kernel_map[nent++];
|
||||
next.start = desc.physical_start;
|
||||
next.pages = desc.number_of_pages;
|
||||
next.type = type;
|
||||
next.attr = (desc.attribute & 0xffffffff);
|
||||
}
|
||||
}
|
||||
mem_entry &prev = kernel_map[nent - 1];
|
||||
if (can_merge(prev, type, desc)) {
|
||||
prev.pages += desc.number_of_pages;
|
||||
} else {
|
||||
mem_entry &next = kernel_map[nent++];
|
||||
next.start = desc.physical_start;
|
||||
next.pages = desc.number_of_pages;
|
||||
next.type = type;
|
||||
next.attr = (desc.attribute & 0xffffffff);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// kernel map dump
|
||||
for (unsigned i = 0; i < nent; ++i) {
|
||||
const mem_entry &e = kernel_map[i];
|
||||
console::print(L" kRange %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
e.start, e.attr, e.type, kernel_memory_type_name(e.type), e.pages);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// kernel map dump
|
||||
for (unsigned i = 0; i < nent; ++i) {
|
||||
const mem_entry &e = kernel_map[i];
|
||||
console::print(L" kRange %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
e.start, e.attr, e.type, kernel_memory_type_name(e.type), e.pages);
|
||||
}
|
||||
*/
|
||||
|
||||
return { .pointer = kernel_map, .count = nent };
|
||||
return { .pointer = kernel_map, .count = nent };
|
||||
}
|
||||
|
||||
inline size_t bitmap_size(size_t frames) { return (frames + 63) / 64; }
|
||||
@@ -203,99 +203,99 @@ inline size_t num_blocks(size_t frames) { return (frames + (frames_per_block-1))
|
||||
counted<kernel::init::frame_block>
|
||||
build_frame_blocks(const counted<kernel::init::mem_entry> &kmap)
|
||||
{
|
||||
status_line status {L"Creating kernel frame accounting map"};
|
||||
status_line status {L"Creating kernel frame accounting map"};
|
||||
|
||||
size_t block_count = 0;
|
||||
size_t total_bitmap_size = 0;
|
||||
for (size_t i = 0; i < kmap.count; ++i) {
|
||||
const mem_entry &ent = kmap[i];
|
||||
if (ent.type != mem_type::free)
|
||||
continue;
|
||||
size_t block_count = 0;
|
||||
size_t total_bitmap_size = 0;
|
||||
for (size_t i = 0; i < kmap.count; ++i) {
|
||||
const mem_entry &ent = kmap[i];
|
||||
if (ent.type != mem_type::free)
|
||||
continue;
|
||||
|
||||
block_count += num_blocks(ent.pages);
|
||||
total_bitmap_size += bitmap_size(ent.pages) * sizeof(uint64_t);
|
||||
}
|
||||
block_count += num_blocks(ent.pages);
|
||||
total_bitmap_size += bitmap_size(ent.pages) * sizeof(uint64_t);
|
||||
}
|
||||
|
||||
size_t total_size = block_count * sizeof(frame_block) + total_bitmap_size;
|
||||
size_t total_size = block_count * sizeof(frame_block) + total_bitmap_size;
|
||||
|
||||
frame_block *blocks = reinterpret_cast<frame_block*>(
|
||||
g_alloc.allocate_pages(bytes_to_pages(total_size), alloc_type::frame_map, true));
|
||||
frame_block *blocks = reinterpret_cast<frame_block*>(
|
||||
g_alloc.allocate_pages(bytes_to_pages(total_size), alloc_type::frame_map, true));
|
||||
|
||||
frame_block *next_block = blocks;
|
||||
for (size_t i = 0; i < kmap.count; ++i) {
|
||||
const mem_entry &ent = kmap[i];
|
||||
if (ent.type != mem_type::free)
|
||||
continue;
|
||||
frame_block *next_block = blocks;
|
||||
for (size_t i = 0; i < kmap.count; ++i) {
|
||||
const mem_entry &ent = kmap[i];
|
||||
if (ent.type != mem_type::free)
|
||||
continue;
|
||||
|
||||
size_t page_count = ent.pages;
|
||||
uintptr_t base_addr = ent.start;
|
||||
while (page_count) {
|
||||
frame_block *blk = next_block++;
|
||||
size_t page_count = ent.pages;
|
||||
uintptr_t base_addr = ent.start;
|
||||
while (page_count) {
|
||||
frame_block *blk = next_block++;
|
||||
|
||||
blk->flags = static_cast<kernel::init::frame_flags>(ent.attr);
|
||||
blk->base = base_addr;
|
||||
base_addr += frames_per_block * page_size;
|
||||
blk->flags = static_cast<kernel::init::frame_flags>(ent.attr);
|
||||
blk->base = base_addr;
|
||||
base_addr += frames_per_block * page_size;
|
||||
|
||||
if (page_count >= frames_per_block) {
|
||||
page_count -= frames_per_block;
|
||||
blk->count = frames_per_block;
|
||||
blk->map1 = ~0ull;
|
||||
g_alloc.memset(blk->map2, sizeof(blk->map2), 0xff);
|
||||
} else {
|
||||
blk->count = page_count;
|
||||
unsigned i = 0;
|
||||
if (page_count >= frames_per_block) {
|
||||
page_count -= frames_per_block;
|
||||
blk->count = frames_per_block;
|
||||
blk->map1 = ~0ull;
|
||||
g_alloc.memset(blk->map2, sizeof(blk->map2), 0xff);
|
||||
} else {
|
||||
blk->count = page_count;
|
||||
unsigned i = 0;
|
||||
|
||||
uint64_t b1 = (page_count + 4095) / 4096;
|
||||
blk->map1 = (1 << b1) - 1;
|
||||
uint64_t b1 = (page_count + 4095) / 4096;
|
||||
blk->map1 = (1 << b1) - 1;
|
||||
|
||||
uint64_t b2 = (page_count + 63) / 64;
|
||||
uint64_t b2q = b2 / 64;
|
||||
uint64_t b2r = b2 % 64;
|
||||
g_alloc.memset(blk->map2, b2q, 0xff);
|
||||
blk->map2[b2q] = (1 << b2r) - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint64_t b2 = (page_count + 63) / 64;
|
||||
uint64_t b2q = b2 / 64;
|
||||
uint64_t b2r = b2 % 64;
|
||||
g_alloc.memset(blk->map2, b2q, 0xff);
|
||||
blk->map2[b2q] = (1 << b2r) - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t *bitmap = reinterpret_cast<uint64_t*>(next_block);
|
||||
for (unsigned i = 0; i < block_count; ++i) {
|
||||
frame_block &blk = blocks[i];
|
||||
blk.bitmap = bitmap;
|
||||
uint64_t *bitmap = reinterpret_cast<uint64_t*>(next_block);
|
||||
for (unsigned i = 0; i < block_count; ++i) {
|
||||
frame_block &blk = blocks[i];
|
||||
blk.bitmap = bitmap;
|
||||
|
||||
size_t b = blk.count / 64;
|
||||
size_t r = blk.count % 64;
|
||||
g_alloc.memset(blk.bitmap, b*8, 0xff);
|
||||
blk.bitmap[b] = (1 << r) - 1;
|
||||
size_t b = blk.count / 64;
|
||||
size_t r = blk.count % 64;
|
||||
g_alloc.memset(blk.bitmap, b*8, 0xff);
|
||||
blk.bitmap[b] = (1 << r) - 1;
|
||||
|
||||
bitmap += bitmap_size(blk.count);
|
||||
}
|
||||
bitmap += bitmap_size(blk.count);
|
||||
}
|
||||
|
||||
return { .pointer = blocks, .count = block_count };
|
||||
return { .pointer = blocks, .count = block_count };
|
||||
}
|
||||
|
||||
void
|
||||
fix_frame_blocks(kernel::init::args *args)
|
||||
{
|
||||
counted<frame_block> &blocks = args->frame_blocks;
|
||||
counted<frame_block> &blocks = args->frame_blocks;
|
||||
|
||||
size_t size = blocks.count * sizeof(frame_block);
|
||||
for (unsigned i = 0; i < blocks.count; ++i)
|
||||
size += bitmap_size(blocks[i].count) * sizeof(uint64_t);
|
||||
size_t size = blocks.count * sizeof(frame_block);
|
||||
for (unsigned i = 0; i < blocks.count; ++i)
|
||||
size += bitmap_size(blocks[i].count) * sizeof(uint64_t);
|
||||
|
||||
size_t pages = bytes_to_pages(size);
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(blocks.pointer);
|
||||
size_t pages = bytes_to_pages(size);
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(blocks.pointer);
|
||||
|
||||
// Map the frame blocks to the appropriate address
|
||||
paging::map_pages(args, addr,
|
||||
::memory::bitmap_start, pages, true, false);
|
||||
// Map the frame blocks to the appropriate address
|
||||
paging::map_pages(args, addr,
|
||||
::memory::bitmap_start, pages, true, false);
|
||||
|
||||
uintptr_t offset = ::memory::bitmap_start - addr;
|
||||
uintptr_t offset = ::memory::bitmap_start - addr;
|
||||
|
||||
for (unsigned i = 0; i < blocks.count; ++i) {
|
||||
frame_block &blk = blocks[i];
|
||||
blk.bitmap = offset_ptr<uint64_t>(blk.bitmap, offset);
|
||||
}
|
||||
for (unsigned i = 0; i < blocks.count; ++i) {
|
||||
frame_block &blk = blocks[i];
|
||||
blk.bitmap = offset_ptr<uint64_t>(blk.bitmap, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
#include "pointer_manipulation.h"
|
||||
|
||||
namespace uefi {
|
||||
struct boot_services;
|
||||
struct memory_descriptor;
|
||||
struct boot_services;
|
||||
struct memory_descriptor;
|
||||
}
|
||||
|
||||
namespace kernel {
|
||||
namespace init {
|
||||
struct args;
|
||||
struct frame_block;
|
||||
struct mem_entry;
|
||||
struct args;
|
||||
struct frame_block;
|
||||
struct mem_entry;
|
||||
}}
|
||||
|
||||
namespace boot {
|
||||
@@ -24,29 +24,29 @@ namespace memory {
|
||||
/// as well as the data on how to read it.
|
||||
struct efi_mem_map
|
||||
{
|
||||
using desc = uefi::memory_descriptor;
|
||||
using iterator = offset_iterator<desc>;
|
||||
using desc = uefi::memory_descriptor;
|
||||
using iterator = offset_iterator<desc>;
|
||||
|
||||
size_t length; ///< Total length of the map data
|
||||
size_t total; ///< Total allocated space for map data
|
||||
size_t size; ///< Size of an entry in the array
|
||||
size_t key; ///< Key for detecting changes
|
||||
uint32_t version; ///< Version of the `memory_descriptor` struct
|
||||
desc *entries; ///< The array of UEFI descriptors
|
||||
size_t length; ///< Total length of the map data
|
||||
size_t total; ///< Total allocated space for map data
|
||||
size_t size; ///< Size of an entry in the array
|
||||
size_t key; ///< Key for detecting changes
|
||||
uint32_t version; ///< Version of the `memory_descriptor` struct
|
||||
desc *entries; ///< The array of UEFI descriptors
|
||||
|
||||
efi_mem_map() : length(0), total(0), size(0), key(0), version(0), entries(nullptr) {}
|
||||
efi_mem_map() : length(0), total(0), size(0), key(0), version(0), entries(nullptr) {}
|
||||
|
||||
/// Update the map from UEFI
|
||||
void update(uefi::boot_services &bs);
|
||||
/// Update the map from UEFI
|
||||
void update(uefi::boot_services &bs);
|
||||
|
||||
/// Get the count of entries in the array
|
||||
inline size_t num_entries() const { return length / size; }
|
||||
/// Get the count of entries in the array
|
||||
inline size_t num_entries() const { return length / size; }
|
||||
|
||||
/// Return an iterator to the beginning of the array
|
||||
inline iterator begin() { return iterator(entries, size); }
|
||||
/// Return an iterator to the beginning of the array
|
||||
inline iterator begin() { return iterator(entries, size); }
|
||||
|
||||
/// Return an iterator to the end of the array
|
||||
inline iterator end() { return offset_ptr<desc>(entries, length); }
|
||||
/// Return an iterator to the end of the array
|
||||
inline iterator end() { return offset_ptr<desc>(entries, length); }
|
||||
};
|
||||
|
||||
/// Add the kernel's memory map as a module to the kernel args.
|
||||
|
||||
@@ -60,13 +60,13 @@ constexpr uint64_t table_flags = 0x003;
|
||||
inline void *
|
||||
pop_pages(counted<void> &pages, size_t count)
|
||||
{
|
||||
if (count > pages.count)
|
||||
error::raise(uefi::status::out_of_resources, L"Page table cache empty", 0x7ab1e5);
|
||||
if (count > pages.count)
|
||||
error::raise(uefi::status::out_of_resources, L"Page table cache empty", 0x7ab1e5);
|
||||
|
||||
void *next = pages.pointer;
|
||||
pages.pointer = offset_ptr<void>(pages.pointer, count*page_size);
|
||||
pages.count -= count;
|
||||
return next;
|
||||
void *next = pages.pointer;
|
||||
pages.pointer = offset_ptr<void>(pages.pointer, count*page_size);
|
||||
pages.count -= count;
|
||||
return next;
|
||||
}
|
||||
|
||||
/// Iterator over page table entries.
|
||||
@@ -74,204 +74,204 @@ template <unsigned D = 4>
|
||||
class page_entry_iterator
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg virt Virtual address this iterator is starting at
|
||||
/// \arg pml4 Root of the page tables to iterate
|
||||
/// \arg pages Cache of usable table pages
|
||||
page_entry_iterator(
|
||||
uintptr_t virt,
|
||||
page_table *pml4,
|
||||
counted<void> &pages) :
|
||||
m_pages(pages)
|
||||
{
|
||||
m_table[0] = pml4;
|
||||
for (unsigned i = 0; i < D; ++i) {
|
||||
m_index[i] = static_cast<uint16_t>((virt >> (12 + 9*(3-i))) & 0x1ff);
|
||||
ensure_table(i);
|
||||
}
|
||||
}
|
||||
/// Constructor.
|
||||
/// \arg virt Virtual address this iterator is starting at
|
||||
/// \arg pml4 Root of the page tables to iterate
|
||||
/// \arg pages Cache of usable table pages
|
||||
page_entry_iterator(
|
||||
uintptr_t virt,
|
||||
page_table *pml4,
|
||||
counted<void> &pages) :
|
||||
m_pages(pages)
|
||||
{
|
||||
m_table[0] = pml4;
|
||||
for (unsigned i = 0; i < D; ++i) {
|
||||
m_index[i] = static_cast<uint16_t>((virt >> (12 + 9*(3-i))) & 0x1ff);
|
||||
ensure_table(i);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t vaddress() const {
|
||||
uintptr_t address = 0;
|
||||
for (unsigned i = 0; i < D; ++i)
|
||||
address |= static_cast<uintptr_t>(m_index[i]) << (12 + 9*(3-i));
|
||||
if (address & (1ull<<47)) // canonicalize the address
|
||||
address |= (0xffffull<<48);
|
||||
return address;
|
||||
}
|
||||
uintptr_t vaddress() const {
|
||||
uintptr_t address = 0;
|
||||
for (unsigned i = 0; i < D; ++i)
|
||||
address |= static_cast<uintptr_t>(m_index[i]) << (12 + 9*(3-i));
|
||||
if (address & (1ull<<47)) // canonicalize the address
|
||||
address |= (0xffffull<<48);
|
||||
return address;
|
||||
}
|
||||
|
||||
void increment()
|
||||
{
|
||||
for (unsigned i = D - 1; i >= 0; --i) {
|
||||
if (++m_index[i] <= 511) {
|
||||
for (unsigned j = i + 1; j < D; ++j)
|
||||
ensure_table(j);
|
||||
return;
|
||||
}
|
||||
void increment()
|
||||
{
|
||||
for (unsigned i = D - 1; i >= 0; --i) {
|
||||
if (++m_index[i] <= 511) {
|
||||
for (unsigned j = i + 1; j < D; ++j)
|
||||
ensure_table(j);
|
||||
return;
|
||||
}
|
||||
|
||||
m_index[i] = 0;
|
||||
}
|
||||
}
|
||||
m_index[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t & operator*() { return entry(D-1); }
|
||||
uint64_t & operator*() { return entry(D-1); }
|
||||
|
||||
private:
|
||||
inline uint64_t & entry(unsigned level) { return m_table[level]->entries[m_index[level]]; }
|
||||
inline uint64_t & entry(unsigned level) { return m_table[level]->entries[m_index[level]]; }
|
||||
|
||||
void ensure_table(unsigned level)
|
||||
{
|
||||
// We're only dealing with D levels of paging, and
|
||||
// there must always be a PML4.
|
||||
if (level < 1 || level >= D)
|
||||
return;
|
||||
void ensure_table(unsigned level)
|
||||
{
|
||||
// We're only dealing with D levels of paging, and
|
||||
// there must always be a PML4.
|
||||
if (level < 1 || level >= D)
|
||||
return;
|
||||
|
||||
// Entry in the parent that points to the table we want
|
||||
uint64_t & parent_ent = entry(level - 1);
|
||||
// Entry in the parent that points to the table we want
|
||||
uint64_t & parent_ent = entry(level - 1);
|
||||
|
||||
if (!(parent_ent & 1)) {
|
||||
page_table *table = reinterpret_cast<page_table*>(pop_pages(m_pages, 1));
|
||||
parent_ent = (reinterpret_cast<uintptr_t>(table) & ~0xfffull) | table_flags;
|
||||
m_table[level] = table;
|
||||
} else {
|
||||
m_table[level] = reinterpret_cast<page_table*>(parent_ent & ~0xfffull);
|
||||
}
|
||||
}
|
||||
if (!(parent_ent & 1)) {
|
||||
page_table *table = reinterpret_cast<page_table*>(pop_pages(m_pages, 1));
|
||||
parent_ent = (reinterpret_cast<uintptr_t>(table) & ~0xfffull) | table_flags;
|
||||
m_table[level] = table;
|
||||
} else {
|
||||
m_table[level] = reinterpret_cast<page_table*>(parent_ent & ~0xfffull);
|
||||
}
|
||||
}
|
||||
|
||||
counted<void> &m_pages;
|
||||
page_table *m_table[D];
|
||||
uint16_t m_index[D];
|
||||
counted<void> &m_pages;
|
||||
page_table *m_table[D];
|
||||
uint16_t m_index[D];
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
add_offset_mappings(page_table *pml4, counted<void> &pages)
|
||||
{
|
||||
uintptr_t phys = 0;
|
||||
uintptr_t virt = ::memory::page_offset; // Start of offset-mapped area
|
||||
size_t page_count = 64 * 1024; // 64 TiB of 1 GiB pages
|
||||
constexpr size_t GiB = 0x40000000ull;
|
||||
uintptr_t phys = 0;
|
||||
uintptr_t virt = ::memory::page_offset; // Start of offset-mapped area
|
||||
size_t page_count = 64 * 1024; // 64 TiB of 1 GiB pages
|
||||
constexpr size_t GiB = 0x40000000ull;
|
||||
|
||||
page_entry_iterator<2> iterator{virt, pml4, pages};
|
||||
page_entry_iterator<2> iterator{virt, pml4, pages};
|
||||
|
||||
while (true) {
|
||||
*iterator = phys | huge_page_flags;
|
||||
if (--page_count == 0)
|
||||
break;
|
||||
while (true) {
|
||||
*iterator = phys | huge_page_flags;
|
||||
if (--page_count == 0)
|
||||
break;
|
||||
|
||||
iterator.increment();
|
||||
phys += GiB;
|
||||
}
|
||||
iterator.increment();
|
||||
phys += GiB;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_kernel_pds(page_table *pml4, counted<void> &pages)
|
||||
{
|
||||
for (unsigned i = pml4e_kernel; i < table_entries; ++i)
|
||||
pml4->set(i, pop_pages(pages, 1), table_flags);
|
||||
for (unsigned i = pml4e_kernel; i < table_entries; ++i)
|
||||
pml4->set(i, pop_pages(pages, 1), table_flags);
|
||||
}
|
||||
|
||||
void
|
||||
add_current_mappings(page_table *new_pml4)
|
||||
{
|
||||
// Get the pointer to the current PML4
|
||||
page_table *old_pml4 = 0;
|
||||
asm volatile ( "mov %%cr3, %0" : "=r" (old_pml4) );
|
||||
// Get the pointer to the current PML4
|
||||
page_table *old_pml4 = 0;
|
||||
asm volatile ( "mov %%cr3, %0" : "=r" (old_pml4) );
|
||||
|
||||
// Only copy mappings in the lower half
|
||||
for (int i = 0; i < ::memory::pml4e_kernel; ++i) {
|
||||
uint64_t entry = old_pml4->entries[i];
|
||||
if (entry & 1)
|
||||
new_pml4->entries[i] = entry;
|
||||
}
|
||||
// Only copy mappings in the lower half
|
||||
for (int i = 0; i < ::memory::pml4e_kernel; ++i) {
|
||||
uint64_t entry = old_pml4->entries[i];
|
||||
if (entry & 1)
|
||||
new_pml4->entries[i] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
allocate_tables(kernel::init::args *args)
|
||||
{
|
||||
status_line status(L"Allocating initial page tables");
|
||||
status_line status(L"Allocating initial page tables");
|
||||
|
||||
static constexpr size_t pd_tables = 256; // number of pages for kernelspace PDs
|
||||
static constexpr size_t extra_tables = 64; // number of extra pages
|
||||
static constexpr size_t pd_tables = 256; // number of pages for kernelspace PDs
|
||||
static constexpr size_t extra_tables = 64; // number of extra pages
|
||||
|
||||
// number of pages for kernelspace PDs + PML4
|
||||
static constexpr size_t kernel_tables = pd_tables + 1;
|
||||
// number of pages for kernelspace PDs + PML4
|
||||
static constexpr size_t kernel_tables = pd_tables + 1;
|
||||
|
||||
static constexpr size_t tables_needed = kernel_tables + extra_tables;
|
||||
static constexpr size_t tables_needed = kernel_tables + extra_tables;
|
||||
|
||||
void *addr = g_alloc.allocate_pages(tables_needed, alloc_type::page_table, true);
|
||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
||||
void *addr = g_alloc.allocate_pages(tables_needed, alloc_type::page_table, true);
|
||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
||||
|
||||
args->pml4 = pml4;
|
||||
args->page_tables = { .pointer = pml4 + 1, .count = tables_needed - 1 };
|
||||
args->pml4 = pml4;
|
||||
args->page_tables = { .pointer = pml4 + 1, .count = tables_needed - 1 };
|
||||
|
||||
console::print(L" First page (pml4) at: 0x%lx\r\n", pml4);
|
||||
console::print(L" First page (pml4) at: 0x%lx\r\n", pml4);
|
||||
|
||||
add_kernel_pds(pml4, args->page_tables);
|
||||
add_offset_mappings(pml4, args->page_tables);
|
||||
add_kernel_pds(pml4, args->page_tables);
|
||||
add_offset_mappings(pml4, args->page_tables);
|
||||
|
||||
//console::print(L" Set up initial mappings, %d spare tables.\r\n", args->table_count);
|
||||
//console::print(L" Set up initial mappings, %d spare tables.\r\n", args->table_count);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr bool has_flag(E set, E flag) {
|
||||
return
|
||||
(static_cast<uint64_t>(set) & static_cast<uint64_t>(flag)) ==
|
||||
static_cast<uint64_t>(flag);
|
||||
return
|
||||
(static_cast<uint64_t>(set) & static_cast<uint64_t>(flag)) ==
|
||||
static_cast<uint64_t>(flag);
|
||||
}
|
||||
|
||||
void
|
||||
map_pages(
|
||||
kernel::init::args *args,
|
||||
uintptr_t phys, uintptr_t virt,
|
||||
size_t count, bool write_flag, bool exe_flag)
|
||||
kernel::init::args *args,
|
||||
uintptr_t phys, uintptr_t virt,
|
||||
size_t count, bool write_flag, bool exe_flag)
|
||||
{
|
||||
if (!count)
|
||||
return;
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
paging::page_table *pml4 =
|
||||
reinterpret_cast<paging::page_table*>(args->pml4);
|
||||
paging::page_table *pml4 =
|
||||
reinterpret_cast<paging::page_table*>(args->pml4);
|
||||
|
||||
page_entry_iterator<4> iterator{virt, pml4, args->page_tables};
|
||||
page_entry_iterator<4> iterator{virt, pml4, args->page_tables};
|
||||
|
||||
uint64_t flags = page_flags;
|
||||
if (!exe_flag)
|
||||
flags |= (1ull << 63); // set NX bit
|
||||
if (write_flag)
|
||||
flags |= 2;
|
||||
uint64_t flags = page_flags;
|
||||
if (!exe_flag)
|
||||
flags |= (1ull << 63); // set NX bit
|
||||
if (write_flag)
|
||||
flags |= 2;
|
||||
|
||||
while (true) {
|
||||
*iterator = phys | flags;
|
||||
if (--count == 0)
|
||||
break;
|
||||
while (true) {
|
||||
*iterator = phys | flags;
|
||||
if (--count == 0)
|
||||
break;
|
||||
|
||||
iterator.increment();
|
||||
phys += page_size;
|
||||
}
|
||||
iterator.increment();
|
||||
phys += page_size;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
map_section(
|
||||
kernel::init::args *args,
|
||||
const kernel::init::program_section §ion)
|
||||
kernel::init::args *args,
|
||||
const kernel::init::program_section §ion)
|
||||
{
|
||||
using kernel::init::section_flags;
|
||||
using kernel::init::section_flags;
|
||||
|
||||
map_pages(
|
||||
args,
|
||||
section.phys_addr,
|
||||
section.virt_addr,
|
||||
memory::bytes_to_pages(section.size),
|
||||
has_flag(section.type, section_flags::write),
|
||||
has_flag(section.type, section_flags::execute));
|
||||
map_pages(
|
||||
args,
|
||||
section.phys_addr,
|
||||
section.virt_addr,
|
||||
memory::bytes_to_pages(section.size),
|
||||
has_flag(section.type, section_flags::write),
|
||||
has_flag(section.type, section_flags::execute));
|
||||
}
|
||||
|
||||
void
|
||||
map_program(
|
||||
kernel::init::args *args,
|
||||
kernel::init::args *args,
|
||||
kernel::init::program &program)
|
||||
{
|
||||
for (auto §ion : program.sections)
|
||||
paging::map_section(args, section);
|
||||
for (auto §ion : program.sections)
|
||||
paging::map_section(args, section);
|
||||
}
|
||||
|
||||
} // namespace paging
|
||||
|
||||
@@ -11,18 +11,18 @@ namespace paging {
|
||||
/// Struct to allow easy accessing of a memory page being used as a page table.
|
||||
struct page_table
|
||||
{
|
||||
uint64_t entries[512];
|
||||
uint64_t entries[512];
|
||||
|
||||
inline page_table * get(int i, uint16_t *flags = nullptr) const {
|
||||
uint64_t entry = entries[i];
|
||||
if ((entry & 1) == 0) return nullptr;
|
||||
if (flags) *flags = entry & 0xfff;
|
||||
return reinterpret_cast<page_table *>(entry & ~0xfffull);
|
||||
}
|
||||
inline page_table * get(int i, uint16_t *flags = nullptr) const {
|
||||
uint64_t entry = entries[i];
|
||||
if ((entry & 1) == 0) return nullptr;
|
||||
if (flags) *flags = entry & 0xfff;
|
||||
return reinterpret_cast<page_table *>(entry & ~0xfffull);
|
||||
}
|
||||
|
||||
inline void set(int i, void *p, uint16_t flags) {
|
||||
entries[i] = reinterpret_cast<uint64_t>(p) | (flags & 0xfff);
|
||||
}
|
||||
inline void set(int i, void *p, uint16_t flags) {
|
||||
entries[i] = reinterpret_cast<uint64_t>(p) | (flags & 0xfff);
|
||||
}
|
||||
};
|
||||
|
||||
/// Allocate memory to be used for initial page tables. Initial offset-mapped
|
||||
@@ -46,16 +46,16 @@ void add_current_mappings(page_table *new_pml4);
|
||||
/// \arg write_flag If true, mark the pages writeable
|
||||
/// \arg exe_flag If true, mark the pages executable
|
||||
void map_pages(
|
||||
kernel::init::args *args,
|
||||
uintptr_t phys, uintptr_t virt,
|
||||
size_t count, bool write_flag, bool exe_flag);
|
||||
kernel::init::args *args,
|
||||
uintptr_t phys, uintptr_t virt,
|
||||
size_t count, bool write_flag, bool exe_flag);
|
||||
|
||||
/// Map the sections of a program in physical memory to their virtual memory
|
||||
/// addresses in the given page tables.
|
||||
/// \arg args The kernel args struct, used for the page table cache and pml4
|
||||
/// \arg program The program to load
|
||||
void map_program(
|
||||
kernel::init::args *args,
|
||||
kernel::init::args *args,
|
||||
kernel::init::program &program);
|
||||
|
||||
} // namespace paging
|
||||
|
||||
@@ -17,15 +17,15 @@ static constexpr int level_warn = 1;
|
||||
static constexpr int level_fail = 2;
|
||||
|
||||
static const wchar_t *level_tags[] = {
|
||||
L" ok ",
|
||||
L" warn ",
|
||||
L"failed"
|
||||
L" ok ",
|
||||
L" warn ",
|
||||
L"failed"
|
||||
};
|
||||
|
||||
static const uefi::attribute level_colors[] = {
|
||||
uefi::attribute::green,
|
||||
uefi::attribute::brown,
|
||||
uefi::attribute::light_red
|
||||
uefi::attribute::green,
|
||||
uefi::attribute::brown,
|
||||
uefi::attribute::light_red
|
||||
};
|
||||
|
||||
status *status::s_current = nullptr;
|
||||
@@ -33,235 +33,235 @@ unsigned status::s_current_type = 0;
|
||||
unsigned status_bar::s_count = 0;
|
||||
|
||||
status_line::status_line(const wchar_t *message, const wchar_t *context, bool fails_clean) :
|
||||
status(fails_clean),
|
||||
m_level(level_ok),
|
||||
m_depth(0),
|
||||
m_outer(nullptr)
|
||||
status(fails_clean),
|
||||
m_level(level_ok),
|
||||
m_depth(0),
|
||||
m_outer(nullptr)
|
||||
{
|
||||
if (status::s_current_type == status_line::type) {
|
||||
m_outer = static_cast<status_line*>(s_current);
|
||||
m_depth = (m_outer ? 1 + m_outer->m_depth : 0);
|
||||
}
|
||||
s_current = this;
|
||||
s_current_type = status_line::type;
|
||||
if (status::s_current_type == status_line::type) {
|
||||
m_outer = static_cast<status_line*>(s_current);
|
||||
m_depth = (m_outer ? 1 + m_outer->m_depth : 0);
|
||||
}
|
||||
s_current = this;
|
||||
s_current_type = status_line::type;
|
||||
|
||||
auto out = console::get().m_out;
|
||||
m_line = out->mode->cursor_row;
|
||||
auto out = console::get().m_out;
|
||||
m_line = out->mode->cursor_row;
|
||||
|
||||
int indent = 2 * m_depth;
|
||||
out->set_cursor_position(indent, m_line);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(message);
|
||||
int indent = 2 * m_depth;
|
||||
out->set_cursor_position(indent, m_line);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(message);
|
||||
|
||||
if (context) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(context);
|
||||
}
|
||||
if (context) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(context);
|
||||
}
|
||||
|
||||
out->output_string(L"\r\n");
|
||||
print_status_tag();
|
||||
out->output_string(L"\r\n");
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
status_line::~status_line()
|
||||
{
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_line");
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_line");
|
||||
|
||||
if (m_outer && m_level > m_outer->m_level) {
|
||||
m_outer->m_level = m_level;
|
||||
m_outer->print_status_tag();
|
||||
}
|
||||
s_current = m_outer;
|
||||
if (m_outer && m_level > m_outer->m_level) {
|
||||
m_outer->m_level = m_level;
|
||||
m_outer->print_status_tag();
|
||||
}
|
||||
s_current = m_outer;
|
||||
}
|
||||
|
||||
void
|
||||
status_line::print_status_tag()
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
int col = out->mode->cursor_column;
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
int col = out->mode->cursor_column;
|
||||
|
||||
uefi::attribute color = level_colors[m_level];
|
||||
const wchar_t *tag = level_tags[m_level];
|
||||
uefi::attribute color = level_colors[m_level];
|
||||
const wchar_t *tag = level_tags[m_level];
|
||||
|
||||
out->set_cursor_position(50, m_line);
|
||||
out->set_cursor_position(50, m_line);
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"[");
|
||||
out->set_attribute(color);
|
||||
out->output_string(tag);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"]\r\n");
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"[");
|
||||
out->set_attribute(color);
|
||||
out->output_string(tag);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"]\r\n");
|
||||
|
||||
out->set_cursor_position(col, row);
|
||||
out->set_cursor_position(col, row);
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_warn(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
print_status_tag();
|
||||
}
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::yellow);
|
||||
out->output_string(message);
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::yellow);
|
||||
out->output_string(message);
|
||||
|
||||
const wchar_t *error = error::message(status);
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
const wchar_t *error = error::message(status);
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_fail(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
print_status_tag();
|
||||
}
|
||||
if (m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::red);
|
||||
out->output_string(message);
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::red);
|
||||
out->output_string(message);
|
||||
|
||||
const wchar_t *error = error::message(status);
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
const wchar_t *error = error::message(status);
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_bar::status_bar(video::screen *screen) :
|
||||
status(),
|
||||
m_outer(nullptr)
|
||||
status(),
|
||||
m_outer(nullptr)
|
||||
{
|
||||
m_size = (screen->mode.vertical / num_boxes) - 1;
|
||||
m_top = screen->mode.vertical - m_size;
|
||||
m_horiz = screen->mode.horizontal;
|
||||
m_fb = reinterpret_cast<uint32_t*>(screen->framebuffer.pointer);
|
||||
m_type = static_cast<uint16_t>(screen->mode.layout);
|
||||
next();
|
||||
m_size = (screen->mode.vertical / num_boxes) - 1;
|
||||
m_top = screen->mode.vertical - m_size;
|
||||
m_horiz = screen->mode.horizontal;
|
||||
m_fb = reinterpret_cast<uint32_t*>(screen->framebuffer.pointer);
|
||||
m_type = static_cast<uint16_t>(screen->mode.layout);
|
||||
next();
|
||||
|
||||
if (status::s_current_type == status_bar::type)
|
||||
m_outer = static_cast<status_bar*>(s_current);
|
||||
s_current = this;
|
||||
s_current_type = status_bar::type;
|
||||
if (status::s_current_type == status_bar::type)
|
||||
m_outer = static_cast<status_bar*>(s_current);
|
||||
s_current = this;
|
||||
s_current_type = status_bar::type;
|
||||
}
|
||||
|
||||
status_bar::~status_bar()
|
||||
{
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_bar");
|
||||
draw_box();
|
||||
s_current = m_outer;
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_bar");
|
||||
draw_box();
|
||||
s_current = m_outer;
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::do_warn(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
m_status = status;
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
draw_box();
|
||||
}
|
||||
m_status = status;
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
draw_box();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::do_fail(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
m_status = status;
|
||||
if (m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
draw_box();
|
||||
}
|
||||
m_status = status;
|
||||
if (m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
draw_box();
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
make_color(uint8_t r, uint8_t g, uint8_t b, uint16_t type)
|
||||
{
|
||||
switch (static_cast<video::layout>(type)) {
|
||||
case video::layout::bgr8:
|
||||
return
|
||||
(static_cast<uint32_t>(b) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(r) << 16);
|
||||
switch (static_cast<video::layout>(type)) {
|
||||
case video::layout::bgr8:
|
||||
return
|
||||
(static_cast<uint32_t>(b) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(r) << 16);
|
||||
|
||||
case video::layout::rgb8:
|
||||
return
|
||||
(static_cast<uint32_t>(r) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(b) << 16);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case video::layout::rgb8:
|
||||
return
|
||||
(static_cast<uint32_t>(r) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(b) << 16);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::draw_box()
|
||||
{
|
||||
static const uint32_t colors[] = {0x909090, 0xf0f0f0};
|
||||
constexpr unsigned ncolors = sizeof(colors) / sizeof(uint32_t);
|
||||
static const uint32_t colors[] = {0x909090, 0xf0f0f0};
|
||||
constexpr unsigned ncolors = sizeof(colors) / sizeof(uint32_t);
|
||||
|
||||
if (m_fb == nullptr)
|
||||
return;
|
||||
if (m_fb == nullptr)
|
||||
return;
|
||||
|
||||
unsigned x0 = m_current * m_size;
|
||||
unsigned x1 = x0 + m_size - 3;
|
||||
unsigned y0 = m_top;
|
||||
unsigned y1 = m_top + m_size - 3;
|
||||
unsigned x0 = m_current * m_size;
|
||||
unsigned x1 = x0 + m_size - 3;
|
||||
unsigned y0 = m_top;
|
||||
unsigned y1 = m_top + m_size - 3;
|
||||
|
||||
uint32_t color = 0;
|
||||
switch (m_level) {
|
||||
case level_ok:
|
||||
color = colors[m_current % ncolors];
|
||||
break;
|
||||
case level_warn:
|
||||
color = make_color(0xff, 0xb2, 0x34, m_type);
|
||||
break;
|
||||
case level_fail:
|
||||
color = make_color(0xfb, 0x0a, 0x1e, m_type);
|
||||
break;
|
||||
default:
|
||||
color = 0;
|
||||
}
|
||||
uint32_t color = 0;
|
||||
switch (m_level) {
|
||||
case level_ok:
|
||||
color = colors[m_current % ncolors];
|
||||
break;
|
||||
case level_warn:
|
||||
color = make_color(0xff, 0xb2, 0x34, m_type);
|
||||
break;
|
||||
case level_fail:
|
||||
color = make_color(0xfb, 0x0a, 0x1e, m_type);
|
||||
break;
|
||||
default:
|
||||
color = 0;
|
||||
}
|
||||
|
||||
for (unsigned y = y0; y < y1; ++y)
|
||||
for (unsigned x = x0; x < x1; ++x)
|
||||
m_fb[y * m_horiz + x] = color;
|
||||
for (unsigned y = y0; y < y1; ++y)
|
||||
for (unsigned x = x0; x < x1; ++x)
|
||||
m_fb[y * m_horiz + x] = color;
|
||||
|
||||
if (m_level > level_ok) {
|
||||
unsigned nbars = static_cast<uint64_t>(m_status) & 0xffff;
|
||||
constexpr unsigned bar_height = 4;
|
||||
if (m_level > level_ok) {
|
||||
unsigned nbars = static_cast<uint64_t>(m_status) & 0xffff;
|
||||
constexpr unsigned bar_height = 4;
|
||||
|
||||
for (unsigned i = 1; i <= nbars; ++i) {
|
||||
y0 = m_top - 2 * i * bar_height;
|
||||
y1 = y0 + bar_height;
|
||||
for (unsigned i = 1; i <= nbars; ++i) {
|
||||
y0 = m_top - 2 * i * bar_height;
|
||||
y1 = y0 + bar_height;
|
||||
|
||||
for (unsigned y = y0; y < y1; ++y)
|
||||
for (unsigned x = x0; x < x1; ++x)
|
||||
m_fb[y * m_horiz + x] = color;
|
||||
}
|
||||
}
|
||||
for (unsigned y = y0; y < y1; ++y)
|
||||
for (unsigned x = x0; x < x1; ++x)
|
||||
m_fb[y * m_horiz + x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -6,125 +6,125 @@
|
||||
#include <uefi/types.h>
|
||||
|
||||
namespace uefi {
|
||||
struct boot_services;
|
||||
struct boot_services;
|
||||
}
|
||||
|
||||
namespace boot {
|
||||
|
||||
namespace video {
|
||||
struct screen;
|
||||
struct screen;
|
||||
}
|
||||
|
||||
// Abstract base class for status reporters.
|
||||
class status
|
||||
{
|
||||
public:
|
||||
status(bool fails_clean = true) : m_fails_clean(fails_clean) {}
|
||||
status(bool fails_clean = true) : m_fails_clean(fails_clean) {}
|
||||
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) = 0;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) = 0;
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) = 0;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) = 0;
|
||||
|
||||
/// Set the state to warning, and print a message. If the state is already at
|
||||
/// warning or error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The warning message to print, if text is supported
|
||||
/// \arg status If set, the error or warning code that should be represented
|
||||
/// \returns True if there was a status handler to display the warning
|
||||
inline static bool warn(const wchar_t *message, uefi::status status = uefi::status::success) {
|
||||
if (!s_current) return false;
|
||||
s_current->do_warn(message, status);
|
||||
return s_current->m_fails_clean;
|
||||
}
|
||||
/// Set the state to warning, and print a message. If the state is already at
|
||||
/// warning or error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The warning message to print, if text is supported
|
||||
/// \arg status If set, the error or warning code that should be represented
|
||||
/// \returns True if there was a status handler to display the warning
|
||||
inline static bool warn(const wchar_t *message, uefi::status status = uefi::status::success) {
|
||||
if (!s_current) return false;
|
||||
s_current->do_warn(message, status);
|
||||
return s_current->m_fails_clean;
|
||||
}
|
||||
|
||||
/// Set the state to error, and print a message. If the state is already at
|
||||
/// error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The error message to print, if text is supported
|
||||
/// \arg status The error or warning code that should be represented
|
||||
/// \returns True if there was a status handler to display the failure
|
||||
inline static bool fail(const wchar_t *message, uefi::status status) {
|
||||
if (!s_current) return false;
|
||||
s_current->do_fail(message, status);
|
||||
return s_current->m_fails_clean;
|
||||
}
|
||||
/// Set the state to error, and print a message. If the state is already at
|
||||
/// error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The error message to print, if text is supported
|
||||
/// \arg status The error or warning code that should be represented
|
||||
/// \returns True if there was a status handler to display the failure
|
||||
inline static bool fail(const wchar_t *message, uefi::status status) {
|
||||
if (!s_current) return false;
|
||||
s_current->do_fail(message, status);
|
||||
return s_current->m_fails_clean;
|
||||
}
|
||||
|
||||
protected:
|
||||
static status *s_current;
|
||||
static unsigned s_current_type;
|
||||
static status *s_current;
|
||||
static unsigned s_current_type;
|
||||
|
||||
private:
|
||||
bool m_fails_clean;
|
||||
bool m_fails_clean;
|
||||
};
|
||||
|
||||
/// Scoped status line reporter. Prints a message and an "OK" if no errors
|
||||
/// or warnings were reported before destruction, otherwise reports the
|
||||
/// error or warning.
|
||||
class status_line :
|
||||
public status
|
||||
public status
|
||||
{
|
||||
public:
|
||||
constexpr static unsigned type = 1;
|
||||
constexpr static unsigned type = 1;
|
||||
|
||||
/// Constructor.
|
||||
/// \arg message Description of the operation in progress
|
||||
/// \arg context If non-null, printed after `message` and a colon
|
||||
/// \arg fails_clean If true, this object can handle printing failure
|
||||
status_line(
|
||||
const wchar_t *message,
|
||||
const wchar_t *context = nullptr,
|
||||
bool fails_clean = true);
|
||||
~status_line();
|
||||
/// Constructor.
|
||||
/// \arg message Description of the operation in progress
|
||||
/// \arg context If non-null, printed after `message` and a colon
|
||||
/// \arg fails_clean If true, this object can handle printing failure
|
||||
status_line(
|
||||
const wchar_t *message,
|
||||
const wchar_t *context = nullptr,
|
||||
bool fails_clean = true);
|
||||
~status_line();
|
||||
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) override;
|
||||
|
||||
private:
|
||||
void print_status_tag();
|
||||
void print_status_tag();
|
||||
|
||||
size_t m_line;
|
||||
int m_level;
|
||||
int m_depth;
|
||||
size_t m_line;
|
||||
int m_level;
|
||||
int m_depth;
|
||||
|
||||
status_line *m_outer;
|
||||
status_line *m_outer;
|
||||
};
|
||||
|
||||
/// Scoped status bar reporter. Draws a row of boxes along the bottom of
|
||||
/// the screen, turning one red if there's an error in that step.
|
||||
class status_bar :
|
||||
public status
|
||||
public status
|
||||
{
|
||||
public:
|
||||
constexpr static unsigned type = 2;
|
||||
constexpr static unsigned type = 2;
|
||||
|
||||
/// Constructor.
|
||||
status_bar(video::screen *screen);
|
||||
~status_bar();
|
||||
/// Constructor.
|
||||
status_bar(video::screen *screen);
|
||||
~status_bar();
|
||||
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) override;
|
||||
|
||||
inline void next() {
|
||||
m_current = s_count++;
|
||||
m_level = 0;
|
||||
m_status = uefi::status::success;
|
||||
draw_box();
|
||||
}
|
||||
inline void next() {
|
||||
m_current = s_count++;
|
||||
m_level = 0;
|
||||
m_status = uefi::status::success;
|
||||
draw_box();
|
||||
}
|
||||
|
||||
private:
|
||||
void draw_box();
|
||||
void draw_box();
|
||||
|
||||
uint32_t *m_fb;
|
||||
uint32_t m_size;
|
||||
uint32_t m_top;
|
||||
uint32_t m_horiz;
|
||||
uint32_t *m_fb;
|
||||
uint32_t m_size;
|
||||
uint32_t m_top;
|
||||
uint32_t m_horiz;
|
||||
|
||||
int m_level;
|
||||
uefi::status m_status;
|
||||
int m_level;
|
||||
uefi::status m_status;
|
||||
|
||||
uint16_t m_type;
|
||||
uint16_t m_current;
|
||||
uint16_t m_type;
|
||||
uint16_t m_current;
|
||||
|
||||
status_bar *m_outer;
|
||||
status_bar *m_outer;
|
||||
|
||||
static unsigned s_count;
|
||||
static unsigned s_count;
|
||||
};
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -10,11 +10,11 @@ extern "C" {
|
||||
__attribute__ ((__weak__))
|
||||
void *memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
uint8_t *cdest = reinterpret_cast<uint8_t*>(dest);
|
||||
const uint8_t *csrc = reinterpret_cast<const uint8_t*>(src);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cdest[i] = csrc[i];
|
||||
return dest;
|
||||
uint8_t *cdest = reinterpret_cast<uint8_t*>(dest);
|
||||
const uint8_t *csrc = reinterpret_cast<const uint8_t*>(src);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cdest[i] = csrc[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
/// Basic memset() implementation for clang. Clang requires freestanding code
|
||||
@@ -23,15 +23,15 @@ void *memcpy(void *dest, const void *src, size_t n)
|
||||
__attribute__ ((__weak__))
|
||||
void *memset(void *dest, int c, size_t n)
|
||||
{
|
||||
uint8_t *cdest = reinterpret_cast<uint8_t*>(dest);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cdest[i] = static_cast<uint8_t>(c);
|
||||
return dest;
|
||||
uint8_t *cdest = reinterpret_cast<uint8_t*>(dest);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cdest[i] = static_cast<uint8_t>(c);
|
||||
return dest;
|
||||
}
|
||||
|
||||
int _purecall()
|
||||
{
|
||||
::boot::error::raise(uefi::status::unsupported, L"Pure virtual call");
|
||||
::boot::error::raise(uefi::status::unsupported, L"Pure virtual call");
|
||||
}
|
||||
|
||||
/// Clang can emit calls to atexit() in constructors or destructors, but
|
||||
|
||||
@@ -20,102 +20,102 @@ using kernel::init::module_type;
|
||||
static uefi::protos::graphics_output *
|
||||
get_gop(uefi::boot_services *bs)
|
||||
{
|
||||
uefi::protos::graphics_output *gop = nullptr;
|
||||
uefi::guid guid = uefi::protos::graphics_output::guid;
|
||||
uefi::protos::graphics_output *gop = nullptr;
|
||||
uefi::guid guid = uefi::protos::graphics_output::guid;
|
||||
|
||||
uefi::status has_gop = bs->locate_protocol(&guid, nullptr,
|
||||
(void **)&gop);
|
||||
uefi::status has_gop = bs->locate_protocol(&guid, nullptr,
|
||||
(void **)&gop);
|
||||
|
||||
if (has_gop != uefi::status::success)
|
||||
return nullptr;
|
||||
if (has_gop != uefi::status::success)
|
||||
return nullptr;
|
||||
|
||||
return gop;
|
||||
return gop;
|
||||
}
|
||||
|
||||
screen *
|
||||
pick_mode(uefi::boot_services *bs)
|
||||
{
|
||||
uefi::protos::graphics_output *gop = get_gop(bs);
|
||||
if (!gop) {
|
||||
console::print(L"No framebuffer found.\r\n");
|
||||
return nullptr;
|
||||
}
|
||||
uefi::protos::graphics_output *gop = get_gop(bs);
|
||||
if (!gop) {
|
||||
console::print(L"No framebuffer found.\r\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uefi::graphics_output_mode_info *info = gop->mode->info;
|
||||
uefi::graphics_output_mode_info *info = gop->mode->info;
|
||||
|
||||
uint32_t best = gop->mode->mode;
|
||||
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
||||
int pixmode = static_cast<int>(info->pixel_format);
|
||||
uint32_t best = gop->mode->mode;
|
||||
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
||||
int pixmode = static_cast<int>(info->pixel_format);
|
||||
|
||||
const uint32_t modes = gop->mode->max_mode;
|
||||
for (uint32_t i = 0; i < modes; ++i) {
|
||||
size_t size = 0;
|
||||
uefi::graphics_output_mode_info *new_info = nullptr;
|
||||
const uint32_t modes = gop->mode->max_mode;
|
||||
for (uint32_t i = 0; i < modes; ++i) {
|
||||
size_t size = 0;
|
||||
uefi::graphics_output_mode_info *new_info = nullptr;
|
||||
|
||||
try_or_raise(
|
||||
gop->query_mode(i, &size, &new_info),
|
||||
L"Failed to find a graphics mode the driver claimed to support");
|
||||
try_or_raise(
|
||||
gop->query_mode(i, &size, &new_info),
|
||||
L"Failed to find a graphics mode the driver claimed to support");
|
||||
|
||||
const uint32_t new_res = new_info->horizontal_resolution * new_info->vertical_resolution;
|
||||
int new_pixmode = static_cast<int>(new_info->pixel_format);
|
||||
const uint32_t new_res = new_info->horizontal_resolution * new_info->vertical_resolution;
|
||||
int new_pixmode = static_cast<int>(new_info->pixel_format);
|
||||
|
||||
if (new_pixmode <= pixmode && new_res >= res) {
|
||||
best = i;
|
||||
res = new_res;
|
||||
pixmode = new_pixmode;
|
||||
}
|
||||
}
|
||||
if (new_pixmode <= pixmode && new_res >= res) {
|
||||
best = i;
|
||||
res = new_res;
|
||||
pixmode = new_pixmode;
|
||||
}
|
||||
}
|
||||
|
||||
screen *s = new screen;
|
||||
s->mode = {
|
||||
.vertical = gop->mode->info->vertical_resolution,
|
||||
.horizontal = gop->mode->info->horizontal_resolution,
|
||||
.scanline = gop->mode->info->pixels_per_scanline,
|
||||
.layout = layout::unknown,
|
||||
};
|
||||
screen *s = new screen;
|
||||
s->mode = {
|
||||
.vertical = gop->mode->info->vertical_resolution,
|
||||
.horizontal = gop->mode->info->horizontal_resolution,
|
||||
.scanline = gop->mode->info->pixels_per_scanline,
|
||||
.layout = layout::unknown,
|
||||
};
|
||||
|
||||
s->framebuffer = {
|
||||
.pointer = reinterpret_cast<void*>(gop->mode->frame_buffer_base),
|
||||
.count = gop->mode->frame_buffer_size
|
||||
};
|
||||
s->framebuffer = {
|
||||
.pointer = reinterpret_cast<void*>(gop->mode->frame_buffer_base),
|
||||
.count = gop->mode->frame_buffer_size
|
||||
};
|
||||
|
||||
wchar_t const * type = nullptr;
|
||||
switch (info->pixel_format) {
|
||||
case uefi::pixel_format::rgb8:
|
||||
type = L"rgb8";
|
||||
s->mode.layout = layout::rgb8;
|
||||
break;
|
||||
wchar_t const * type = nullptr;
|
||||
switch (info->pixel_format) {
|
||||
case uefi::pixel_format::rgb8:
|
||||
type = L"rgb8";
|
||||
s->mode.layout = layout::rgb8;
|
||||
break;
|
||||
|
||||
case uefi::pixel_format::bgr8:
|
||||
type = L"bgr8";
|
||||
s->mode.layout = layout::bgr8;
|
||||
break;
|
||||
case uefi::pixel_format::bgr8:
|
||||
type = L"bgr8";
|
||||
s->mode.layout = layout::bgr8;
|
||||
break;
|
||||
|
||||
default:
|
||||
type = L"unknown";
|
||||
}
|
||||
default:
|
||||
type = L"unknown";
|
||||
}
|
||||
|
||||
console::print(L"Found framebuffer: %dx%d[%d] type %s @0x%x\r\n",
|
||||
info->horizontal_resolution, info->vertical_resolution,
|
||||
info->pixels_per_scanline, type, gop->mode->frame_buffer_base);
|
||||
console::print(L"Found framebuffer: %dx%d[%d] type %s @0x%x\r\n",
|
||||
info->horizontal_resolution, info->vertical_resolution,
|
||||
info->pixels_per_scanline, type, gop->mode->frame_buffer_base);
|
||||
|
||||
try_or_raise(
|
||||
gop->set_mode(best),
|
||||
L"Failed to set graphics mode");
|
||||
try_or_raise(
|
||||
gop->set_mode(best),
|
||||
L"Failed to set graphics mode");
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
make_module(screen *s)
|
||||
{
|
||||
using kernel::init::module_framebuffer;
|
||||
module_framebuffer *modfb = g_alloc.allocate_module<module_framebuffer>();
|
||||
modfb->mod_type = module_type::framebuffer;
|
||||
modfb->type = fb_type::uefi;
|
||||
using kernel::init::module_framebuffer;
|
||||
module_framebuffer *modfb = g_alloc.allocate_module<module_framebuffer>();
|
||||
modfb->mod_type = module_type::framebuffer;
|
||||
modfb->type = fb_type::uefi;
|
||||
|
||||
modfb->framebuffer = s->framebuffer;
|
||||
modfb->mode = s->mode;
|
||||
modfb->framebuffer = s->framebuffer;
|
||||
modfb->mode = s->mode;
|
||||
}
|
||||
|
||||
} // namespace video
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "init_args.h"
|
||||
|
||||
namespace uefi {
|
||||
struct boot_services;
|
||||
struct boot_services;
|
||||
}
|
||||
|
||||
namespace boot {
|
||||
@@ -18,8 +18,8 @@ using kernel::init::video_mode;
|
||||
using layout = kernel::init::fb_layout;
|
||||
|
||||
struct screen {
|
||||
buffer framebuffer;
|
||||
video_mode mode;
|
||||
buffer framebuffer;
|
||||
video_mode mode;
|
||||
};
|
||||
|
||||
/// Pick the best video mode and set up the screen
|
||||
|
||||
Reference in New Issue
Block a user