mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-01-21 09:10:37 -05:00
191 lines
7.6 KiB
C
191 lines
7.6 KiB
C
/* x86_64_init
|
|
*
|
|
* Copyright (C) 2025 Advanced Micro Devices, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "x86_64.h"
|
|
#include "task.h"
|
|
#include "stdio.h"
|
|
#include "stdio.h"
|
|
#include "trap.h"
|
|
#include "xen/memory.h"
|
|
#include "e820.h"
|
|
#include "hypervisor.h"
|
|
#include "xen/hvm/params.h"
|
|
#include <xen/arch-x86/hvm/start_info.h>
|
|
|
|
HeapRegion_t xHeapRegions[MAX_HEAP_REGIONS];
|
|
|
|
// DEBUG variables for testing purpose
|
|
uint64_t pml4_w_user=0;
|
|
|
|
// Extern variable defined in linker script and assembly code
|
|
extern uint64_t pml4;
|
|
extern uint64_t pud;
|
|
extern uint8_t end;
|
|
extern char __system_calls_start;
|
|
extern char __system_calls_end;
|
|
extern char __apis_start;
|
|
extern char __apis_end;
|
|
extern char __rodata_start;
|
|
extern char __rodata_end;
|
|
|
|
/*
|
|
* Method to setup regions for restricted tasks.
|
|
* A restricted task has access to following
|
|
* user mode
|
|
* user data
|
|
* system calls
|
|
* utilities apis like strlen
|
|
* its process stack
|
|
*/
|
|
uint32_t xInitiRegionForRestrictedTask(MemoryRegion_t *regions) ;
|
|
void vInitMemoryAllocator(uint64_t multiboot_info_addr);
|
|
void vx86_64Init(uint64_t multiboot_info_addr) ;
|
|
void vSetupKernelPageMapping(void) ;
|
|
uint32_t xInitiRegionForRestrictedTask(MemoryRegion_t *regions) {
|
|
|
|
uint32_t num_region_used = 0;
|
|
regions[num_region_used].pvBaseAddress = &__system_calls_start;
|
|
regions[num_region_used].ulLengthInBytes = (uint32_t) (&__system_calls_end - &__system_calls_start);
|
|
regions[num_region_used].ulParameters = REGION_RO;
|
|
num_region_used++;
|
|
|
|
regions[num_region_used].pvBaseAddress = &__apis_start;
|
|
regions[num_region_used].ulLengthInBytes = (uint32_t) (&__apis_end - &__apis_start);
|
|
regions[num_region_used].ulParameters = REGION_RO;
|
|
num_region_used++;
|
|
|
|
regions[num_region_used].pvBaseAddress = &__rodata_start;
|
|
regions[num_region_used].ulLengthInBytes = (uint32_t) (&__rodata_end - &__rodata_start);
|
|
regions[num_region_used].ulParameters = REGION_RO;
|
|
num_region_used++;
|
|
|
|
return num_region_used;
|
|
}
|
|
|
|
#define PAGE_SIZE_1GB (1ULL << 30)
|
|
#define PML4_INDEX(va) (((va) >> 39) & 0x1FF)
|
|
#define PDPT_INDEX(va) (((va) >> 30) & 0x1FF)
|
|
|
|
/* Setup Mapping for Kernel */
|
|
void vSetupKernelPageMapping() {
|
|
uint64_t *page_table_l4_addr = &pml4;
|
|
uint64_t *page_table_l3_addr = &pud;
|
|
uint64_t addr = 0;
|
|
for (int i=0;i<256;i++) {
|
|
page_table_l4_addr[i] = (uint64_t) &page_table_l3_addr[i*512];
|
|
page_table_l4_addr[i] |= 0x03;
|
|
for (int j=0;j<512;j++) {
|
|
page_table_l3_addr[i*(int)512+j]=addr|(uint64_t)0x83;
|
|
addr += 0x40000000ULL;
|
|
}
|
|
}
|
|
addr = 0;
|
|
for (int i=256;i<512;i++) {
|
|
page_table_l4_addr[i] = (uint64_t) &page_table_l3_addr[i*512];
|
|
page_table_l4_addr[i] |= 0x03;
|
|
for (int j=0;j<512;j++) {
|
|
page_table_l3_addr[i*(int)512+j]=addr|(uint64_t)0x83;
|
|
addr += 0x40000000ULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void vInitMemoryAllocator(uint64_t multiboot_info_addr)
|
|
{
|
|
// Find the end address where kernel is loaded.
|
|
// Free Memory can started only from that address
|
|
uint64_t last_used_addr = (uint64_t) &end;
|
|
int heap_region_count = 0;
|
|
printf("kernel end: %p\n",last_used_addr);
|
|
if (multiboot_info_addr != (uint64_t)0) {
|
|
uint64_t* val = (uint64_t*) multiboot_info_addr;
|
|
uint32_t magic = *((uint64_t *)val);
|
|
|
|
if (magic != XEN_HVM_START_MAGIC_VALUE) {
|
|
struct multiboot_tag *tag = (struct multiboot_tag *)(multiboot_info_addr + (uint64_t)8); // Skip total size and reserved field
|
|
|
|
while (tag->type != (uint32_t)0) { // 0 indicates end tag
|
|
if (tag->type == (uint32_t)MULTIBOOT_TAG_TYPE_MEMORY) {
|
|
struct multiboot_tag_mmap *mmap_tag = (struct multiboot_tag_mmap *)tag;
|
|
for (uint32_t i = 0; i < (mmap_tag->size - 16) / mmap_tag->entry_size; i++) {
|
|
struct multiboot_mmap_entry *entry = &mmap_tag->entries[i];
|
|
if (entry->type == 1) {
|
|
uint64_t start_addr = entry->base_addr;
|
|
uint64_t end_addr = start_addr + entry->length;
|
|
if (start_addr > last_used_addr) {
|
|
xHeapRegions[heap_region_count].pucStartAddress = (uint8_t *) start_addr;
|
|
xHeapRegions[heap_region_count].xSizeInBytes = entry->length;
|
|
heap_region_count++;
|
|
} else if (end_addr > last_used_addr) {
|
|
xHeapRegions[heap_region_count].pucStartAddress = (uint8_t *)last_used_addr;
|
|
xHeapRegions[heap_region_count].xSizeInBytes = end_addr - last_used_addr;
|
|
heap_region_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
tag = (struct multiboot_tag *)((uint8_t *)tag + ((tag->size + 7) & ~7)); // Align tag size to 8
|
|
}
|
|
} else {
|
|
struct hvm_start_info *hsi = (struct hvm_start_info *)val;
|
|
long ret;
|
|
struct xen_memory_map memmap;
|
|
memmap.nr_entries = E820_MAX;
|
|
set_xen_guest_handle(memmap.buffer, e820_map);
|
|
ret = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
|
|
unsigned long end, start;
|
|
struct e820entry *entry = (struct e820entry *)e820_map;
|
|
for ( int i = 0; i < memmap.nr_entries; i++ )
|
|
{
|
|
if (entry[i].type == XEN_HVM_MEMMAP_TYPE_RAM) {
|
|
uint64_t start_addr = entry[i].addr;
|
|
uint64_t end_addr = entry[i].addr+entry[i].size;
|
|
if (start_addr > last_used_addr) {
|
|
xHeapRegions[heap_region_count].pucStartAddress = (uint8_t *) start_addr;
|
|
xHeapRegions[heap_region_count].xSizeInBytes = entry[i].size;
|
|
heap_region_count++;
|
|
} else if (end_addr > last_used_addr) {
|
|
xHeapRegions[heap_region_count].pucStartAddress = (uint8_t *)last_used_addr;
|
|
xHeapRegions[heap_region_count].xSizeInBytes = end_addr - last_used_addr;
|
|
heap_region_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
xHeapRegions[heap_region_count].pucStartAddress = 0;
|
|
xHeapRegions[heap_region_count].xSizeInBytes = 0;
|
|
vPortDefineHeapRegions( xHeapRegions );
|
|
return;
|
|
}
|
|
|
|
void vx86_64Init(uint64_t multiboot_info_addr) {
|
|
vIDTInit();
|
|
vSetupKernelPageMapping();
|
|
vInitMemoryAllocator(multiboot_info_addr);
|
|
}
|