You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
4.4 KiB
144 lines
4.4 KiB
/* |
|
* Copyright (C) 2014 René Kijewski <rene.kijewski@fu-berlin.de> |
|
* |
|
* This library is free software; you can redistribute it and/or |
|
* modify it under the terms of the GNU Lesser General Public |
|
* License as published by the Free Software Foundation; either |
|
* version 2.1 of the License, or (at your option) any later version. |
|
* |
|
* This library is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
* Lesser General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU Lesser General Public |
|
* License along with this library; if not, write to the Free Software |
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
*/ |
|
|
|
/** |
|
* @ingroup boards_x86-multiboot |
|
* @{ |
|
* |
|
* @file |
|
* @brief Startup code to be loaded by multiboot enabled bootloaders. |
|
* |
|
* @author René Kijewski <rene.kijewski@fu-berlin.de> |
|
* |
|
* @} |
|
*/ |
|
|
|
#include <cpu.h> |
|
#include <multiboot.h> |
|
#include <x86_kernel_memory.h> |
|
#include <x86_memory.h> |
|
#include <x86_reboot.h> |
|
#include <x86_videoram.h> |
|
|
|
#include <inttypes.h> |
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
|
|
#ifndef BREAK_STARTUP |
|
# define BREAK_STARTUP (0) |
|
#endif |
|
|
|
static void __attribute__((noreturn)) startup(uint32_t multiboot_magic, const multiboot_info_t *multiboot_info); |
|
void __attribute__((noreturn, optimize("Os", "omit-frame-pointer"), no_instrument_function)) _start(void); |
|
|
|
extern const multiboot_header_t multiboot_header __attribute__((section("._multiboot_header"))); |
|
const multiboot_header_t multiboot_header = { |
|
.magic = MULTIBOOT_HEADER_MAGIC, |
|
.flags = MULTIBOOT_HEADER_FLAGS, |
|
.checksum = (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)), |
|
.header_addr = (uintptr_t) &multiboot_header, |
|
.load_addr = (uintptr_t) &_kernel_memory_start, |
|
.load_end_addr = (uintptr_t) &_section_data_end, |
|
.bss_end_addr = (uintptr_t) &_section_bss_end, |
|
.entry_addr = (uintptr_t) &_start, |
|
}; |
|
|
|
void __attribute__((noreturn, optimize("Os", "omit-frame-pointer"), no_instrument_function)) _start(void) |
|
{ |
|
__asm__ volatile ("xor %ebp, %ebp"); |
|
__asm__ volatile ("push %ebp"); |
|
__asm__ volatile ("push %ebx"); |
|
__asm__ volatile ("push %eax"); |
|
__asm__ volatile ("push %ebp"); |
|
__asm__ volatile ("jmp *%0" :: "r"(&startup)); |
|
__builtin_unreachable(); |
|
} |
|
|
|
static const multiboot_info_t *multiboot_info; |
|
|
|
bool x86_get_memory_region(uint64_t *start, uint64_t *len, unsigned long *pos) |
|
{ |
|
while (1) { |
|
if (*pos >= multiboot_info->mmap_length) { |
|
return false; |
|
} |
|
|
|
const multiboot_memory_map_t *mmap = (void *)(multiboot_info->mmap_addr + *pos); |
|
*pos += mmap->size + 4; |
|
|
|
*start = mmap->addr; |
|
*len = mmap->len; |
|
|
|
uint64_t end = *start + *len; |
|
printf(" %08lx%08lx - %08lx%08lx ", (long) (*start >> 32), (long) *start, (long) (end >> 32), (long) end); |
|
|
|
if (mmap->type != 1) { |
|
// not free (ignore reclaimable RAM) |
|
const char *msg; |
|
switch (mmap->type) { |
|
case 2: msg = "reseved"; break; |
|
case 3: msg = "ACPI [reclaimable]"; break; |
|
case 4: msg = "ACPI [NVS]"; break; |
|
case 5: msg = "bad memory"; break; |
|
default: msg = "unknown"; |
|
} |
|
printf("(unusable: %s)\r\n", msg); |
|
} |
|
else { |
|
puts("(usable)"); |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
static void have_a_break(void) |
|
{ |
|
volatile bool cnt = false; |
|
while (!cnt) { |
|
__asm__ volatile ("pause"); |
|
} |
|
} |
|
|
|
static void __attribute__((noreturn)) startup(uint32_t multiboot_magic, const multiboot_info_t *multiboot_info_) |
|
{ |
|
x86_init_gdt(); /* load GDT early */ |
|
x86_load_empty_idt(); /* just a safeguard to cause a tripple fault, not really needed */ |
|
|
|
#if BREAK_STARTUP |
|
have_a_break(); |
|
#else |
|
(void) have_a_break; |
|
#endif |
|
|
|
memset(&_section_bss_start, 0, &_section_bss_end - &_section_bss_start + 1); |
|
|
|
videoram_puts(" Booting RIOT \r\n"); |
|
if (multiboot_magic != MULTIBOOT_BOOTLOADER_MAGIC) { |
|
videoram_puts(" Multiboot magic is wrong \r\n"); |
|
x86_hlt(); |
|
} |
|
else if (!(multiboot_info->flags && MULTIBOOT_INFO_MEM_MAP)) { |
|
videoram_puts(" Multiboot is lacking memory map information \r\n"); |
|
x86_hlt(); |
|
} |
|
|
|
multiboot_info = multiboot_info_; |
|
x86_startup(); |
|
}
|
|
|