From 478dc9887eb692a6664ede1d833ea6d1d0c03a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Mon, 14 Nov 2011 01:31:50 +0100 Subject: [PATCH] PPC: Preliminary untested boot support for Common Firmware Environment CFE is used in the upcoming Amiga X-1000 dualcore PPC board. * Largely inspired by the OF and U-Boot code. * Still largely stubbed out. * The loader builds but I don't have a machine to test it. Anyone interested? --- docs/develop/ports/ppc/cfe.txt | 7 + .../private/kernel/boot/platform/cfe/cfe.h | 54 ++ .../kernel/boot/platform/cfe/platform_arch.h | 38 ++ .../boot/platform/cfe/platform_kernel_args.h | 24 + .../boot/platform/cfe/platform_stage2_args.h | 15 + src/system/boot/platform/cfe/Handle.cpp | 86 +++ src/system/boot/platform/cfe/Handle.h | 34 + src/system/boot/platform/cfe/Jamfile | 37 ++ src/system/boot/platform/cfe/arch/Jamfile | 3 + src/system/boot/platform/cfe/arch/ppc/Jamfile | 19 + .../platform/cfe/arch/ppc/arch_start_kernel.S | 49 ++ src/system/boot/platform/cfe/arch/ppc/cpu.cpp | 32 + src/system/boot/platform/cfe/arch/ppc/mmu.cpp | 588 ++++++++++++++++++ src/system/boot/platform/cfe/cfe.cpp | 264 ++++++++ src/system/boot/platform/cfe/console.cpp | 170 +++++ src/system/boot/platform/cfe/console.h | 21 + src/system/boot/platform/cfe/debug.cpp | 46 ++ src/system/boot/platform/cfe/devices.cpp | 138 ++++ src/system/boot/platform/cfe/heap.cpp | 48 ++ src/system/boot/platform/cfe/menu.cpp | 48 ++ src/system/boot/platform/cfe/mmu.cpp | 36 ++ src/system/boot/platform/cfe/start.cpp | 177 ++++++ src/system/boot/platform/cfe/support.cpp | 23 + src/system/boot/platform/cfe/support.h | 17 + src/system/boot/platform/cfe/video.cpp | 72 +++ src/system/ldscripts/ppc/boot_loader_cfe.ld | 45 ++ 26 files changed, 2091 insertions(+) create mode 100644 docs/develop/ports/ppc/cfe.txt create mode 100644 headers/private/kernel/boot/platform/cfe/cfe.h create mode 100644 headers/private/kernel/boot/platform/cfe/platform_arch.h create mode 100644 headers/private/kernel/boot/platform/cfe/platform_kernel_args.h create mode 100644 headers/private/kernel/boot/platform/cfe/platform_stage2_args.h create mode 100644 src/system/boot/platform/cfe/Handle.cpp create mode 100644 src/system/boot/platform/cfe/Handle.h create mode 100644 src/system/boot/platform/cfe/Jamfile create mode 100644 src/system/boot/platform/cfe/arch/Jamfile create mode 100644 src/system/boot/platform/cfe/arch/ppc/Jamfile create mode 100644 src/system/boot/platform/cfe/arch/ppc/arch_start_kernel.S create mode 100644 src/system/boot/platform/cfe/arch/ppc/cpu.cpp create mode 100644 src/system/boot/platform/cfe/arch/ppc/mmu.cpp create mode 100644 src/system/boot/platform/cfe/cfe.cpp create mode 100644 src/system/boot/platform/cfe/console.cpp create mode 100644 src/system/boot/platform/cfe/console.h create mode 100644 src/system/boot/platform/cfe/debug.cpp create mode 100644 src/system/boot/platform/cfe/devices.cpp create mode 100644 src/system/boot/platform/cfe/heap.cpp create mode 100644 src/system/boot/platform/cfe/menu.cpp create mode 100644 src/system/boot/platform/cfe/mmu.cpp create mode 100644 src/system/boot/platform/cfe/start.cpp create mode 100644 src/system/boot/platform/cfe/support.cpp create mode 100644 src/system/boot/platform/cfe/support.h create mode 100644 src/system/boot/platform/cfe/video.cpp create mode 100644 src/system/ldscripts/ppc/boot_loader_cfe.ld diff --git a/docs/develop/ports/ppc/cfe.txt b/docs/develop/ports/ppc/cfe.txt new file mode 100644 index 0000000000..6648cb8919 --- /dev/null +++ b/docs/develop/ports/ppc/cfe.txt @@ -0,0 +1,7 @@ +http://www.linux-mips.org/wiki/Common_Firmware_Environment +http://www.broadcom.com/support/communications_processors/downloads.php +http://www.broadcom.com/docs/SiByte/README-1.4.2.txt +http://wiki.openwrt.org/doc/techref/bootloader/cfe +http://amigaos.net/content/2/what%E2%80%99s-new +http://lguohan.blogspot.com/2010/03/embedded-powerpc.html + diff --git a/headers/private/kernel/boot/platform/cfe/cfe.h b/headers/private/kernel/boot/platform/cfe/cfe.h new file mode 100644 index 0000000000..f81c4208b5 --- /dev/null +++ b/headers/private/kernel/boot/platform/cfe/cfe.h @@ -0,0 +1,54 @@ +/* + * Copyright 2011, François Revol, revol@free.fr. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_BOOT_PLATFORM_CFE_CFE_H +#define KERNEL_BOOT_PLATFORM_CFE_CFE_H + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CFE_EPTSEAL 0x43464531 /* 'CFE1' */ +#define CFE_MAGIC CFE_EPTSEAL + +// cfe/include/cfe_timer.h +#define CFE_HZ 10 + +/* CFE sources declare this separately in cfe_api.h */ + +/* (let's hope it's always built-in, + unlike u-boot's API which never is... */ + +#define CFE_FLG_COLDSTART 0x00000000 +#define CFE_FLG_WARMSTART 0x00000001 + +#define CFE_STDHANDLE_CONSOLE 0 + +int cfe_init(uint64 handle, uint64 entry); + +int cfe_exit(int32 warm, int32 status); +uint64 cfe_getticks(void); + +int cfe_enumdev(int idx, char *name, int namelen); + +int cfe_getstdhandle(int flag); +int cfe_open(const char *name); +int cfe_close(int handle); + +int cfe_readblk(int handle, int64 offset, void *buffer, int length); +int cfe_writeblk(int handle, int64 offset, const void *buffer, int length); + +#define CFE_OK 0 +#define CFE_ERR -1 + +status_t cfe_error(int32 err); + +#ifdef __cplusplus +} +#endif + +#endif /* KERNEL_BOOT_PLATFORM_CFE_CFE_H */ diff --git a/headers/private/kernel/boot/platform/cfe/platform_arch.h b/headers/private/kernel/boot/platform/cfe/platform_arch.h new file mode 100644 index 0000000000..4f114db0ac --- /dev/null +++ b/headers/private/kernel/boot/platform/cfe/platform_arch.h @@ -0,0 +1,38 @@ +/* + * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the OpenBeOS License. + */ +#ifndef KERNEL_BOOT_PLATFORM_CFE_ARCH_H +#define KERNEL_BOOT_PLATFORM_CFE_ARCH_H + + +#include + +struct kernel_args; + +#ifdef __cplusplus +extern "C" { +#endif + +/* memory management */ + +extern status_t arch_set_callback(void); +extern void *arch_mmu_allocate(void *address, size_t size, + uint8 protection, bool exactAddress); +extern status_t arch_mmu_free(void *address, size_t size); +extern status_t arch_mmu_init(void); + +/* CPU */ + +extern status_t boot_arch_cpu_init(void); + +/* kernel start */ + +status_t arch_start_kernel(struct kernel_args *kernelArgs, + addr_t kernelEntry, addr_t kernelStackTop); + +#ifdef __cplusplus +} +#endif + +#endif /* KERNEL_BOOT_PLATFORM_CFE_ARCH_H */ diff --git a/headers/private/kernel/boot/platform/cfe/platform_kernel_args.h b/headers/private/kernel/boot/platform/cfe/platform_kernel_args.h new file mode 100644 index 0000000000..8cf75e829e --- /dev/null +++ b/headers/private/kernel/boot/platform/cfe/platform_kernel_args.h @@ -0,0 +1,24 @@ +/* + * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the OpenBeOS License. + */ +#ifndef KERNEL_BOOT_PLATFORM_CFE_KERNEL_ARGS_H +#define KERNEL_BOOT_PLATFORM_CFE_KERNEL_ARGS_H + +#ifndef KERNEL_BOOT_KERNEL_ARGS_H +# error This file is included from only +#endif + +// must match SMP_MAX_CPUS in arch_smp.h +#define MAX_BOOT_CPUS 4 +#define MAX_PHYSICAL_MEMORY_RANGE 4 +#define MAX_PHYSICAL_ALLOCATED_RANGE 8 +#define MAX_VIRTUAL_ALLOCATED_RANGE 32 + + +typedef struct { + uint64 cfe_entry; // pointer but always 64bit + //XXX:char rtc_path[128]; +} platform_kernel_args; + +#endif /* KERNEL_BOOT_PLATFORM_CFE_KERNEL_ARGS_H */ diff --git a/headers/private/kernel/boot/platform/cfe/platform_stage2_args.h b/headers/private/kernel/boot/platform/cfe/platform_stage2_args.h new file mode 100644 index 0000000000..46073c628c --- /dev/null +++ b/headers/private/kernel/boot/platform/cfe/platform_stage2_args.h @@ -0,0 +1,15 @@ +/* + * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the OpenBeOS License. + */ +#ifndef KERNEL_BOOT_PLATFORM_CFE_STAGE2_ARGS_H +#define KERNEL_BOOT_PLATFORM_CFE_STAGE2_ARGS_H + +#ifndef KERNEL_BOOT_STAGE2_ARGS_H +# error This file is included from only +#endif + +struct platform_stage2_args { +}; + +#endif /* KERNEL_BOOT_PLATFORM_CFE_STAGE2_ARGS_H */ diff --git a/src/system/boot/platform/cfe/Handle.cpp b/src/system/boot/platform/cfe/Handle.cpp new file mode 100644 index 0000000000..b648df79f6 --- /dev/null +++ b/src/system/boot/platform/cfe/Handle.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include "Handle.h" + +#include + +#include +#include + + +Handle::Handle(int handle, bool takeOwnership) + : + fHandle(handle), + fOwnHandle(takeOwnership) +{ +} + + +Handle::Handle(void) + : + fHandle(0) +{ +} + + +Handle::~Handle() +{ + if (fOwnHandle) + cfe_close(fHandle); +} + + +void +Handle::SetHandle(int handle, bool takeOwnership) +{ + if (fHandle && fOwnHandle) + cfe_close(fHandle); + + fHandle = handle; + fOwnHandle = takeOwnership; +} + + +ssize_t +Handle::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) +{ + int32 err; + if (pos == -1) + pos = 0;//XXX + err = cfe_readblk(fHandle, pos, buffer, bufferSize); + + if (err < 0) + return cfe_error(err); + + return err; +} + + +ssize_t +Handle::WriteAt(void *cookie, off_t pos, const void *buffer, + size_t bufferSize) +{ + int32 err; + if (pos == -1) + pos = 0;//XXX + err = cfe_writeblk(fHandle, pos, buffer, bufferSize); + + if (err < 0) + return cfe_error(err); + + return err; +} + + +off_t +Handle::Size() const +{ + // ToDo: fix this! + return 1024LL * 1024 * 1024 * 1024; + // 1024 GB +} + diff --git a/src/system/boot/platform/cfe/Handle.h b/src/system/boot/platform/cfe/Handle.h new file mode 100644 index 0000000000..937b801bb4 --- /dev/null +++ b/src/system/boot/platform/cfe/Handle.h @@ -0,0 +1,34 @@ +/* + * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef HANDLE_H +#define HANDLE_H + + +#include + + +#ifdef __cplusplus + +class Handle : public ConsoleNode { + public: + Handle(int handle, bool takeOwnership = true); + Handle(); + virtual ~Handle(); + + void SetHandle(int handle, bool takeOwnership = true); + + virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize); + virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); + + virtual off_t Size() const; + + protected: + int fHandle; + bool fOwnHandle; +}; + +#endif /* __cplusplus */ + +#endif /* HANDLE_H */ diff --git a/src/system/boot/platform/cfe/Jamfile b/src/system/boot/platform/cfe/Jamfile new file mode 100644 index 0000000000..8114492e79 --- /dev/null +++ b/src/system/boot/platform/cfe/Jamfile @@ -0,0 +1,37 @@ +SubDir HAIKU_TOP src system boot platform cfe ; + +SubDirC++Flags -D_BOOT_MODE -fno-rtti ; + +UsePrivateHeaders [ FDirName graphics common ] ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons accelerants common ] ; + +KernelMergeObject boot_platform_cfe.o : + console.cpp + debug.cpp + devices.cpp + Handle.cpp + heap.cpp + menu.cpp + mmu.cpp + #network.cpp + #real_time_clock.cpp + start.cpp + support.cpp + video.cpp + + cfe.cpp + #cfe_devices.cpp + + : + : + boot_platform_generic.a + boot_platform_cfe_$(TARGET_ARCH).a +; + +SEARCH on [ FGristFiles $(genericPlatformSources) ] + = [ FDirName $(HAIKU_TOP) src system boot platform generic ] ; +#SEARCH on [ FGristFiles cfe.cpp cfe_devices.cpp ] +# = [ FDirName $(HAIKU_TOP) src system kernel platform cfe ] ; + +SubInclude HAIKU_TOP src system boot platform cfe arch ; diff --git a/src/system/boot/platform/cfe/arch/Jamfile b/src/system/boot/platform/cfe/arch/Jamfile new file mode 100644 index 0000000000..6212c17422 --- /dev/null +++ b/src/system/boot/platform/cfe/arch/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src system boot platform cfe arch ; + +SubInclude HAIKU_TOP src system boot platform cfe arch $(TARGET_ARCH) ; diff --git a/src/system/boot/platform/cfe/arch/ppc/Jamfile b/src/system/boot/platform/cfe/arch/ppc/Jamfile new file mode 100644 index 0000000000..14cc7e7567 --- /dev/null +++ b/src/system/boot/platform/cfe/arch/ppc/Jamfile @@ -0,0 +1,19 @@ +SubDir HAIKU_TOP src system boot platform cfe arch ppc ; + +SubDirHdrs $(HAIKU_TOP) src system boot platform $(TARGET_BOOT_PLATFORM) ; +UsePrivateSystemHeaders ; +UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ] + [ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ; + +SubDirC++Flags -fno-rtti ; + +KernelStaticLibrary boot_platform_cfe_ppc : + arch_mmu.cpp + arch_cpu_asm.S + arch_start_kernel.S + cpu.cpp + mmu.cpp +; + +SEARCH on [ FGristFiles arch_cpu_asm.S arch_mmu.cpp ] + = [ FDirName $(HAIKU_TOP) src system kernel arch $(TARGET_ARCH) ] ; diff --git a/src/system/boot/platform/cfe/arch/ppc/arch_start_kernel.S b/src/system/boot/platform/cfe/arch/ppc/arch_start_kernel.S new file mode 100644 index 0000000000..2156e1d7a8 --- /dev/null +++ b/src/system/boot/platform/cfe/arch/ppc/arch_start_kernel.S @@ -0,0 +1,49 @@ +/* + * Copyright 2005, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#define FUNCTION(x) .global x; .type x,@function; x + +/* status_t arch_start_kernel(struct kernel_args *kernelArgs, + addr_t kernelEntry, addr_t kernelStackTop); + + r3 - kernelArgs + r4 - kernelEntry + r5 - kernelStackTop +*/ +FUNCTION(arch_start_kernel): + // push a stack frame + stwu %r1, -32(%r1) + mflr %r0 + stw %r0, 36(%r1) + + // save the old stack pointer in r29 + stw %r29, 20(%r1) + mr %r29, %r1 + + // set up the kernel stack + subi %r1, %r5, 16 + + // clear the pointer to the previous frame + li %r0, 0 + stw %r0, 0(%r1) + + // enter the kernel + mtlr %r4 + li %r4, 0 + blrl + + /* Actually we should never get here, but at least for debugging purposes + it's quite nice to return in an orderly manner. */ + + // reset the boot loader stack + mr %r1, %r29 + lwz %r29, 20(%r1) + + // pop the stack frame + lwz %r0, 36(%r1) + mtlr %r0 + addi %r1, %r1, 32 + blr + diff --git a/src/system/boot/platform/cfe/arch/ppc/cpu.cpp b/src/system/boot/platform/cfe/arch/ppc/cpu.cpp new file mode 100644 index 0000000000..05ffdddc5b --- /dev/null +++ b/src/system/boot/platform/cfe/arch/ppc/cpu.cpp @@ -0,0 +1,32 @@ +/* + * Copyright 2005, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + +#include + +#include +#include +#include +//#include +#include + +#define TRACE_CPU +#ifdef TRACE_CPU +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +status_t +boot_arch_cpu_init(void) +{ +#warning PPC:TODO + return B_ERROR; +} + diff --git a/src/system/boot/platform/cfe/arch/ppc/mmu.cpp b/src/system/boot/platform/cfe/arch/ppc/mmu.cpp new file mode 100644 index 0000000000..b06114fc68 --- /dev/null +++ b/src/system/boot/platform/cfe/arch/ppc/mmu.cpp @@ -0,0 +1,588 @@ +/* + * Copyright 2011, François Revol, revol@free.fr. + * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2010-2011, Haiku, Inc. All Rights Reserved. + * All rights reserved. Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de. + * Alexander von Gluck, kallisti5@unixzen.com + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "support.h" + + +// set protection to WIMGNPP: -----PP +// PP: 00 - no access +// 01 - read only +// 10 - read/write +// 11 - read only +#define PAGE_READ_ONLY 0x01 +#define PAGE_READ_WRITE 0x02 + +// NULL is actually a possible physical address... +//#define PHYSINVAL ((void *)-1) +#define PHYSINVAL NULL + +//#define TRACE_MMU +#ifdef TRACE_MMU +# define TRACE(x...) dprintf(x) +#else +# define TRACE(x...) ; +#endif + + +segment_descriptor sSegments[16]; +page_table_entry_group *sPageTable; +uint32 sPageTableHashMask; + + +// begin and end of the boot loader +extern "C" uint8 __text_begin; +extern "C" uint8 _end; + + +static status_t +insert_virtual_range_to_keep(void *start, uint32 size) +{ + return insert_address_range(gKernelArgs.arch_args.virtual_ranges_to_keep, + &gKernelArgs.arch_args.num_virtual_ranges_to_keep, + MAX_VIRTUAL_RANGES_TO_KEEP, (addr_t)start, size); +} + + +static status_t +remove_virtual_range_to_keep(void *start, uint32 size) +{ + return remove_address_range(gKernelArgs.arch_args.virtual_ranges_to_keep, + &gKernelArgs.arch_args.num_virtual_ranges_to_keep, + MAX_VIRTUAL_RANGES_TO_KEEP, (addr_t)start, size); +} + + +static status_t +find_physical_memory_ranges(size_t &total) +{ + int memory; + dprintf("checking for memory...\n"); +#warning PPC:TODO + + return B_ERROR; +} + + +static bool +is_virtual_allocated(void *address, size_t size) +{ + addr_t foundBase; + return !get_free_address_range(gKernelArgs.virtual_allocated_range, + gKernelArgs.num_virtual_allocated_ranges, (addr_t)address, size, + &foundBase) || foundBase != (addr_t)address; +} + + +static bool +is_physical_allocated(void *address, size_t size) +{ + phys_addr_t foundBase; + return !get_free_physical_address_range( + gKernelArgs.physical_allocated_range, + gKernelArgs.num_physical_allocated_ranges, (addr_t)address, size, + &foundBase) || foundBase != (addr_t)address; +} + + +static bool +is_physical_memory(void *address, size_t size) +{ + return is_physical_address_range_covered(gKernelArgs.physical_memory_range, + gKernelArgs.num_physical_memory_ranges, (addr_t)address, size); +} + + +static bool +is_physical_memory(void *address) +{ + return is_physical_memory(address, 1); +} + + +static void +fill_page_table_entry(page_table_entry *entry, uint32 virtualSegmentID, + void *virtualAddress, void *physicalAddress, uint8 mode, bool secondaryHash) +{ + // lower 32 bit - set at once + ((uint32 *)entry)[1] + = (((uint32)physicalAddress / B_PAGE_SIZE) << 12) | mode; + /*entry->physical_page_number = (uint32)physicalAddress / B_PAGE_SIZE; + entry->_reserved0 = 0; + entry->referenced = false; + entry->changed = false; + entry->write_through = (mode >> 6) & 1; + entry->caching_inhibited = (mode >> 5) & 1; + entry->memory_coherent = (mode >> 4) & 1; + entry->guarded = (mode >> 3) & 1; + entry->_reserved1 = 0; + entry->page_protection = mode & 0x3;*/ + eieio(); + // we need to make sure that the lower 32 bit were + // already written when the entry becomes valid + + // upper 32 bit + entry->virtual_segment_id = virtualSegmentID; + entry->secondary_hash = secondaryHash; + entry->abbr_page_index = ((uint32)virtualAddress >> 22) & 0x3f; + entry->valid = true; +} + + +static void +map_page(void *virtualAddress, void *physicalAddress, uint8 mode) +{ + uint32 virtualSegmentID + = sSegments[addr_t(virtualAddress) >> 28].virtual_segment_id; + + uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, + (uint32)virtualAddress); + page_table_entry_group *group = &sPageTable[hash & sPageTableHashMask]; + + for (int32 i = 0; i < 8; i++) { + // 8 entries in a group + if (group->entry[i].valid) + continue; + + fill_page_table_entry(&group->entry[i], virtualSegmentID, + virtualAddress, physicalAddress, mode, false); + //TRACE("map: va = %p -> %p, mode = %d, hash = %lu\n", + // virtualAddress, physicalAddress, mode, hash); + return; + } + + hash = page_table_entry::SecondaryHash(hash); + group = &sPageTable[hash & sPageTableHashMask]; + + for (int32 i = 0; i < 8; i++) { + if (group->entry[i].valid) + continue; + + fill_page_table_entry(&group->entry[i], virtualSegmentID, + virtualAddress, physicalAddress, mode, true); + //TRACE("map: va = %p -> %p, mode = %d, second hash = %lu\n", + // virtualAddress, physicalAddress, mode, hash); + return; + } + + panic("%s: out of page table entries!\n", __func__); +} + + +static void +map_range(void *virtualAddress, void *physicalAddress, size_t size, uint8 mode) +{ + for (uint32 offset = 0; offset < size; offset += B_PAGE_SIZE) { + map_page((void *)(uint32(virtualAddress) + offset), + (void *)(uint32(physicalAddress) + offset), mode); + } +} + + +static status_t +find_allocated_ranges(void *oldPageTable, void *pageTable, + page_table_entry_group **_physicalPageTable, void **_exceptionHandlers) +{ + // we have to preserve the OpenFirmware established mappings + // if we want to continue to use its service after we've + // taken over (we will probably need less translations once + // we have proper driver support for the target hardware). + int mmu; +#warning PPC:TODO + return B_ERROR; +} + + +/*! Computes the recommended minimal page table size as + described in table 7-22 of the PowerPC "Programming + Environment for 32-Bit Microprocessors". + The page table size ranges from 64 kB (for 8 MB RAM) + to 32 MB (for 4 GB RAM). +*/ +static size_t +suggested_page_table_size(size_t total) +{ + uint32 max = 23; + // 2^23 == 8 MB + + while (max < 32) { + if (total <= (1UL << max)) + break; + + max++; + } + + return 1UL << (max - 7); + // 2^(23 - 7) == 64 kB +} + + +static void * +find_physical_memory_range(size_t size) +{ + for (uint32 i = 0; i < gKernelArgs.num_physical_memory_ranges; i++) { + if (gKernelArgs.physical_memory_range[i].size > size) + return (void *)gKernelArgs.physical_memory_range[i].start; + } + return PHYSINVAL; +} + + +static void * +find_free_physical_range(size_t size) +{ + // just do a simple linear search at the end of the allocated + // ranges (dumb memory allocation) + if (gKernelArgs.num_physical_allocated_ranges == 0) { + if (gKernelArgs.num_physical_memory_ranges == 0) + return PHYSINVAL; + + return find_physical_memory_range(size); + } + + for (uint32 i = 0; i < gKernelArgs.num_physical_allocated_ranges; i++) { + void *address = (void *)(gKernelArgs.physical_allocated_range[i].start + + gKernelArgs.physical_allocated_range[i].size); + if (!is_physical_allocated(address, size) + && is_physical_memory(address, size)) + return address; + } + return PHYSINVAL; +} + + +static void * +find_free_virtual_range(void *base, size_t size) +{ + if (base && !is_virtual_allocated(base, size)) + return base; + + void *firstFound = NULL; + void *firstBaseFound = NULL; + for (uint32 i = 0; i < gKernelArgs.num_virtual_allocated_ranges; i++) { + void *address = (void *)(gKernelArgs.virtual_allocated_range[i].start + + gKernelArgs.virtual_allocated_range[i].size); + if (!is_virtual_allocated(address, size)) { + if (!base) + return address; + + if (firstFound == NULL) + firstFound = address; + if (address >= base + && (firstBaseFound == NULL || address < firstBaseFound)) { + firstBaseFound = address; + } + } + } + return (firstBaseFound ? firstBaseFound : firstFound); +} + + +extern "C" void * +arch_mmu_allocate(void *_virtualAddress, size_t size, uint8 _protection, + bool exactAddress) +{ + // we only know page sizes + size = ROUNDUP(size, B_PAGE_SIZE); + + uint8 protection = 0; + if (_protection & B_WRITE_AREA) + protection = PAGE_READ_WRITE; + else + protection = PAGE_READ_ONLY; + + // If no address is given, use the KERNEL_BASE as base address, since + // that avoids trouble in the kernel, when we decide to keep the region. + void *virtualAddress = _virtualAddress; + if (!virtualAddress) + virtualAddress = (void*)KERNEL_BASE; + + // find free address large enough to hold "size" + virtualAddress = find_free_virtual_range(virtualAddress, size); + if (virtualAddress == NULL) + return NULL; + + // fail if the exact address was requested, but is not free + if (exactAddress && _virtualAddress && virtualAddress != _virtualAddress) { + dprintf("arch_mmu_allocate(): exact address requested, but virtual " + "range (base: %p, size: %" B_PRIuSIZE ") is not free.\n", + _virtualAddress, size); + return NULL; + } + + // we have a free virtual range for the allocation, now + // have a look for free physical memory as well (we assume + // that a) there is enough memory, and b) failing is fatal + // so that we don't have to optimize for these cases :) + + void *physicalAddress = find_free_physical_range(size); + if (physicalAddress == PHYSINVAL) { + dprintf("arch_mmu_allocate(base: %p, size: %" B_PRIuSIZE ") " + "no free physical address\n", virtualAddress, size); + return NULL; + } + + // everything went fine, so lets mark the space as used. + + dprintf("mmu_alloc: va %p, pa %p, size %" B_PRIuSIZE "\n", virtualAddress, + physicalAddress, size); + insert_virtual_allocated_range((addr_t)virtualAddress, size); + insert_physical_allocated_range((addr_t)physicalAddress, size); + + map_range(virtualAddress, physicalAddress, size, protection); + + return virtualAddress; +} + + +extern "C" status_t +arch_mmu_free(void *address, size_t size) +{ + // TODO: implement freeing a region! + return B_ERROR; +} + + +static inline void +invalidate_tlb(void) +{ + //asm volatile("tlbia"); + // "tlbia" is obviously not available on every CPU... + + // Note: this flushes the whole 4 GB address space - it + // would probably be a good idea to do less here + + addr_t address = 0; + for (uint32 i = 0; i < 0x100000; i++) { + asm volatile("tlbie %0" : : "r" (address)); + address += B_PAGE_SIZE; + } + tlbsync(); +} + + +extern "C" status_t +arch_set_callback(void) +{ + // XXX:do we need this for CFE? + return B_ERROR; +} + + +extern "C" status_t +arch_mmu_init(void) +{ + // get map of physical memory (fill in kernel_args structure) + + size_t total; + if (find_physical_memory_ranges(total) != B_OK) { + dprintf("Error: could not find physical memory ranges!\n"); + return B_ERROR; + } + dprintf("total physical memory = %" B_PRId32 "MB\n", total / (1024 * 1024)); + + // get OpenFirmware's current page table + + page_table_entry_group *oldTable; + page_table_entry_group *table; + size_t tableSize; + ppc_get_page_table(&table, &tableSize); + + oldTable = table; + + bool realMode = false; + + // TODO: read these values out of the OF settings + // NOTE: I've only ever seen -1 (0xffffffff) for these values in + // OpenFirmware.. even after loading the bootloader -- Alex + addr_t realBase = 0; + addr_t realSize = 0x400000; + + // can we just keep the page table? + size_t suggestedTableSize = suggested_page_table_size(total); + dprintf("suggested page table size = %" B_PRIuSIZE "\n", + suggestedTableSize); + if (tableSize < suggestedTableSize) { + // nah, we need a new one! + dprintf("need new page table, size = %" B_PRIuSIZE "!\n", + suggestedTableSize); +#if 0//OF + table = (page_table_entry_group *)of_claim(NULL, suggestedTableSize, + suggestedTableSize); + // KERNEL_BASE would be better as virtual address, but + // at least with Apple's OpenFirmware, it makes no + // difference - we will have to remap it later + if (table == (void *)OF_FAILED) { + panic("Could not allocate new page table " + "(size = %" B_PRIuSIZE ")!!\n", suggestedTableSize); + return B_NO_MEMORY; + } +#endif + if (table == NULL) { + // work-around for the broken Pegasos OpenFirmware + dprintf("broken OpenFirmware detected (claim doesn't work)\n"); + realMode = true; + + addr_t tableBase = 0; + for (int32 i = 0; tableBase < realBase + realSize * 3; i++) { + tableBase = suggestedTableSize * i; + } + + table = (page_table_entry_group *)tableBase; + } + + dprintf("new table at: %p\n", table); + sPageTable = table; + tableSize = suggestedTableSize; + } else { + // ToDo: we could check if the page table is much too large + // and create a smaller one in this case (in order to save + // memory). + sPageTable = table; + } + + sPageTableHashMask = tableSize / sizeof(page_table_entry_group) - 1; + if (sPageTable != oldTable) + memset(sPageTable, 0, tableSize); + + // turn off address translation via the page table/segment mechanism, + // identity map the first 256 MB (where our code/data reside) + + dprintf("MSR: %p\n", (void *)get_msr()); + + #if 0 + block_address_translation bat; + + bat.length = BAT_LENGTH_256MB; + bat.kernel_valid = true; + bat.memory_coherent = true; + bat.protection = BAT_READ_WRITE; + + set_ibat0(&bat); + set_dbat0(&bat); + isync(); + #endif + + // initialize segment descriptors, but don't set the registers + // until we're about to take over the page table - we're mapping + // pages into our table using these values + + for (int32 i = 0; i < 16; i++) + sSegments[i].virtual_segment_id = i; + + // find already allocated ranges of physical memory + // and the virtual address space + + page_table_entry_group *physicalTable = NULL; + void *exceptionHandlers = (void *)-1; + if (find_allocated_ranges(oldTable, table, &physicalTable, + &exceptionHandlers) != B_OK) { + dprintf("Error: find_allocated_ranges() failed\n"); + return B_ERROR; + } + +#if 0 + block_address_translation bats[8]; + getibats(bats); + for (int32 i = 0; i < 8; i++) { + printf("page index %u, length %u, ppn %u\n", bats[i].page_index, + bats[i].length, bats[i].physical_block_number); + } +#endif + + if (physicalTable == NULL) { + dprintf("%s: Didn't find physical address of page table\n", __func__); + if (!realMode) + return B_ERROR; + + // Pegasos work-around + #if 0 + map_range((void *)realBase, (void *)realBase, + realSize * 2, PAGE_READ_WRITE); + map_range((void *)(total - realSize), (void *)(total - realSize), + realSize, PAGE_READ_WRITE); + map_range((void *)table, (void *)table, tableSize, PAGE_READ_WRITE); + #endif + insert_physical_allocated_range(realBase, realSize * 2); + insert_virtual_allocated_range(realBase, realSize * 2); + insert_physical_allocated_range(total - realSize, realSize); + insert_virtual_allocated_range(total - realSize, realSize); + insert_physical_allocated_range((addr_t)table, tableSize); + insert_virtual_allocated_range((addr_t)table, tableSize); + + // QEMU OpenHackware work-around + insert_physical_allocated_range(0x05800000, 0x06000000 - 0x05800000); + insert_virtual_allocated_range(0x05800000, 0x06000000 - 0x05800000); + + physicalTable = table; + } + + if (exceptionHandlers == (void *)-1) { + // TODO: create mapping for the exception handlers + dprintf("Error: no mapping for the exception handlers!\n"); + } + + // Set the Open Firmware memory callback. From now on the Open Firmware + // will ask us for memory. + arch_set_callback(); + + // set up new page table and turn on translation again + + for (int32 i = 0; i < 16; i++) { + ppc_set_segment_register((void *)(i * 0x10000000), sSegments[i]); + // one segment describes 256 MB of memory + } + + ppc_set_page_table(physicalTable, tableSize); + invalidate_tlb(); + + if (!realMode) { + // clear BATs + reset_ibats(); + reset_dbats(); + ppc_sync(); + isync(); + } + + set_msr(MSR_MACHINE_CHECK_ENABLED | MSR_FP_AVAILABLE + | MSR_INST_ADDRESS_TRANSLATION | MSR_DATA_ADDRESS_TRANSLATION); + + // set kernel args + + dprintf("virt_allocated: %" B_PRIu32 "\n", + gKernelArgs.num_virtual_allocated_ranges); + dprintf("phys_allocated: %" B_PRIu32 "\n", + gKernelArgs.num_physical_allocated_ranges); + dprintf("phys_memory: %" B_PRIu32 "\n", + gKernelArgs.num_physical_memory_ranges); + + gKernelArgs.arch_args.page_table.start = (addr_t)sPageTable; + gKernelArgs.arch_args.page_table.size = tableSize; + + gKernelArgs.arch_args.exception_handlers.start = (addr_t)exceptionHandlers; + gKernelArgs.arch_args.exception_handlers.size = B_PAGE_SIZE; + + return B_OK; +} + diff --git a/src/system/boot/platform/cfe/cfe.cpp b/src/system/boot/platform/cfe/cfe.cpp new file mode 100644 index 0000000000..d73ee837c9 --- /dev/null +++ b/src/system/boot/platform/cfe/cfe.cpp @@ -0,0 +1,264 @@ +/* + * Copyright 2011, François Revol, revol@free.fr. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include + +#include +#include +#include +#include +#include + +typedef uint64 ptr64; // for clarity + +status_t cfe_error(int32 err) +{ + // not an error + if (err > 0) + return err; + + switch (err) { + case CFE_OK: + return B_OK; + case CFE_ERR: + return B_ERROR; + //TODO:add cases + default: + return B_ERROR; + } +} + +#define CFE_CMD_FW_GETINFO 0 +#define CFE_CMD_FW_RESTART 1 +#define CFE_CMD_FW_BOOT 2 +#define CFE_CMD_FW_CPUCTL 3 +#define CFE_CMD_FW_GETTIME 4 +#define CFE_CMD_FW_MEMENUM 5 +#define CFE_CMD_FW_FLUSHCACHE 6 + +#define CFE_CMD_DEV_GETHANDLE 9 +#define CFE_CMD_DEV_ENUM 10 +#define CFE_CMD_DEV_OPEN 11 +#define CFE_CMD_DEV_READ 13 +#define CFE_CMD_DEV_WRITE 14 +#define CFE_CMD_DEV_CLOSE 16 + + +struct cfe_xiocb_s { + cfe_xiocb_s(uint64 fcode, int64 handle = 0, uint64 flags = 0); + + uint64 xiocb_fcode; + int64 xiocb_status; + int64 xiocb_handle; + uint64 xiocb_flags; + uint64 xiocb_psize; + union { + struct { + uint64 buf_offset; + ptr64 buf_ptr; + uint64 buf_length; + uint64 buf_retlen; + uint64 buf_ioctlcmd; + } xiocb_buffer; +/* + struct { + } xiocb_inpstat; +*/ + struct { + int64 enum_idx; + ptr64 name_ptr; + int64 name_length; + ptr64 val_ptr; + int64 val_length; + } xiocb_envbuf; +/* + struct { + } xiocb_cpuctl; +*/ + struct { + int64 ticks; + } xiocb_time; +/* + struct { + } xiocb_meminfo; + struct { + } xiocb_fwinfo; +*/ + struct { + int64 status; + } xiocb_exitstat; + } plist; +}; + +typedef struct cfe_xiocb_s cfe_xiocb_t; + +cfe_xiocb_s::cfe_xiocb_s(uint64 fcode, int64 handle, uint64 flags) + : xiocb_fcode(fcode), + xiocb_status(0), + xiocb_handle(handle), + xiocb_flags(flags), + xiocb_psize(0) +{ + switch (fcode) { + case CFE_CMD_FW_GETINFO: + case CFE_CMD_DEV_READ: + case CFE_CMD_DEV_WRITE: + case CFE_CMD_DEV_OPEN: + xiocb_psize = sizeof(plist.xiocb_buffer); + break; + case CFE_CMD_FW_RESTART: + xiocb_psize = sizeof(plist.xiocb_exitstat); + break; + case CFE_CMD_FW_GETTIME: + xiocb_psize = sizeof(plist.xiocb_time); + break; + case CFE_CMD_DEV_ENUM: + xiocb_psize = sizeof(plist.xiocb_envbuf); + break; + //XXX: some more... + default: + break; + } + memset(&plist, 0, sizeof(plist)); +}; + + +// CFE handle +static uint64 sCFEHandle; +// CFE entry point +static uint64 sCFEEntry; + +static int cfe_iocb_dispatch(cfe_xiocb_t *xiocb) +{ + static int (*dispfunc)(intptr_t handle, intptr_t xiocb); + dispfunc = (int(*)(intptr_t, intptr_t))(void *)sCFEEntry; + if (dispfunc == NULL) + return CFE_ERR; + return (*dispfunc)((intptr_t)sCFEHandle, (intptr_t)xiocb); +} + +int +cfe_init(uint64 handle, uint64 entry) +{ + sCFEHandle = handle; + sCFEEntry = entry; + + return CFE_OK; +} + +int +cfe_exit(int32 warm, int32 status) +{ + cfe_xiocb_t xiocb(CFE_CMD_FW_RESTART, 0, + warm ? CFE_FLG_WARMSTART : CFE_FLG_COLDSTART); + xiocb.plist.xiocb_exitstat.status = status; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} + + +int cfe_enumdev(int idx, char *name, int namelen) +{ + cfe_xiocb_t xiocb(CFE_CMD_DEV_ENUM); + xiocb.plist.xiocb_envbuf.enum_idx = idx; + xiocb.plist.xiocb_envbuf.name_ptr = (uint64)name; + xiocb.plist.xiocb_envbuf.name_length = namelen; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} + + +int +cfe_getstdhandle(int flag) +{ + cfe_xiocb_t xiocb(CFE_CMD_DEV_GETHANDLE, 0, flag); + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0); + return xiocb.xiocb_status; + return xiocb.xiocb_handle; +} + + +int +cfe_open(const char *name) +{ + cfe_xiocb_t xiocb(CFE_CMD_DEV_OPEN); + xiocb.plist.xiocb_buffer.buf_offset = 0; + xiocb.plist.xiocb_buffer.buf_ptr = (uint64)name; + xiocb.plist.xiocb_buffer.buf_length = strlen(name); + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0); + return xiocb.xiocb_status; + return xiocb.xiocb_handle; +} + + +int +cfe_close(int handle) +{ + cfe_xiocb_t xiocb(CFE_CMD_DEV_CLOSE, handle); + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} + + +uint64 +cfe_getticks(void) +{ + cfe_xiocb_t xiocb(CFE_CMD_FW_GETTIME); + + cfe_iocb_dispatch(&xiocb); + + return xiocb.plist.xiocb_time.ticks; +} + + +int +cfe_readblk(int handle, int64 offset, void *buffer, int length) +{ + cfe_xiocb_t xiocb(CFE_CMD_DEV_READ, handle); + xiocb.plist.xiocb_buffer.buf_offset = offset; + xiocb.plist.xiocb_buffer.buf_ptr = (uint64)buffer; + xiocb.plist.xiocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0); + return xiocb.xiocb_status; + return xiocb.plist.xiocb_buffer.buf_retlen; +} + + + +int +cfe_writeblk(int handle, int64 offset, const void *buffer, int length) +{ + cfe_xiocb_t xiocb(CFE_CMD_DEV_WRITE, handle); + xiocb.plist.xiocb_buffer.buf_offset = offset; + xiocb.plist.xiocb_buffer.buf_ptr = (uint64)buffer; + xiocb.plist.xiocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0); + return xiocb.xiocb_status; + return xiocb.plist.xiocb_buffer.buf_retlen; +} + + diff --git a/src/system/boot/platform/cfe/console.cpp b/src/system/boot/platform/cfe/console.cpp new file mode 100644 index 0000000000..d11012bfc1 --- /dev/null +++ b/src/system/boot/platform/cfe/console.cpp @@ -0,0 +1,170 @@ +/* + * Copyright 2011, François Revol, revol@free.fr. + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "Handle.h" +#include "console.h" + +#include +#include +#include +#include + +#include + + +class Console : public Handle { + public: + Console(); +}; + +class VTConsole : public Console { + public: + VTConsole(); + void ClearScreen(); + void SetCursor(int32 x, int32 y); + void SetColor(int32 foreground, int32 background); +}; + +static VTConsole sInput, sOutput; +FILE *stdin, *stdout, *stderr; + + +// #pragma mark - + + +Console::Console() + : Handle() +{ +} + + +// #pragma mark - + + +VTConsole::VTConsole() + : Console() +{ +} + +void +VTConsole::ClearScreen() +{ + WriteAt(NULL, 0LL, "\033E", 2); +} + + +void +VTConsole::SetCursor(int32 x, int32 y) +{ + char buff[] = "\033Y "; + x = MIN(79,MAX(0,x)); + y = MIN(24,MAX(0,y)); + buff[3] += (char)x; + buff[2] += (char)y; + WriteAt(NULL, 0LL, buff, 4); +} + + +void +VTConsole::SetColor(int32 foreground, int32 background) +{ + static const char cmap[] = { + 15, 4, 2, 6, 1, 5, 3, 7, + 8, 12, 10, 14, 9, 13, 11, 0 }; + char buff[] = "\033b \033c "; + + if (foreground < 0 && foreground >= 16) + return; + if (background < 0 && background >= 16) + return; + + buff[2] += cmap[foreground]; + buff[5] += cmap[background]; + WriteAt(NULL, 0LL, buff, 6); +} + + +// #pragma mark - + + +void +console_clear_screen(void) +{ + sOutput.ClearScreen(); +} + + +int32 +console_width(void) +{ + return 80; +} + + +int32 +console_height(void) +{ + return 25; +} + + +void +console_set_cursor(int32 x, int32 y) +{ + sOutput.SetCursor(x, y); +} + + +void +console_show_cursor(void) +{ +} + + +void +console_hide_cursor(void) +{ +} + + +void +console_set_color(int32 foreground, int32 background) +{ + sOutput.SetColor(foreground, background); +} + + +int +console_wait_for_key(void) +{ + return 0; +} + + +int +console_check_for_key(void) +{ + return 0; +} + + +status_t +console_init(void) +{ + stdin = (FILE *)&sInput; + stdout = stderr = (FILE *)&sOutput; + + int handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); + if (handle < 0) + return cfe_error(handle); + + sInput.SetHandle(handle); + sOutput.SetHandle(handle); + + return B_OK; +} + diff --git a/src/system/boot/platform/cfe/console.h b/src/system/boot/platform/cfe/console.h new file mode 100644 index 0000000000..eef30f73e5 --- /dev/null +++ b/src/system/boot/platform/cfe/console.h @@ -0,0 +1,21 @@ +/* + * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the Haiku License. + */ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern status_t console_init(void); +extern int console_check_for_key(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CONSOLE_H */ diff --git a/src/system/boot/platform/cfe/debug.cpp b/src/system/boot/platform/cfe/debug.cpp new file mode 100644 index 0000000000..84bd5db546 --- /dev/null +++ b/src/system/boot/platform/cfe/debug.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2011, François Revol, revol@free.fr. + * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include + + +extern "C" void +panic(const char* format, ...) +{ + // TODO: this works only after console_init() was called. + va_list list; + + puts("*** PANIC ***"); + + va_start(list, format); + vprintf(format, list); + va_end(list); + + cfe_exit(CFE_FLG_WARMSTART, 2); +} + + +extern "C" void +dprintf(const char* format, ...) +{ + va_list list; + + va_start(list, format); + vprintf(format, list); + va_end(list); +} + + +char* +platform_debug_get_log_buffer(size_t* _size) +{ + return NULL; +} diff --git a/src/system/boot/platform/cfe/devices.cpp b/src/system/boot/platform/cfe/devices.cpp new file mode 100644 index 0000000000..46a20ce82e --- /dev/null +++ b/src/system/boot/platform/cfe/devices.cpp @@ -0,0 +1,138 @@ +/* + * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2010, Andreas Färber + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include "Handle.h" + + +char sBootPath[192]; + + +status_t +platform_add_boot_device(struct stage2_args *args, NodeList *devicesList) +{ +#warning PPC:TODO + return B_ERROR; +} + + +status_t +platform_get_boot_partition(struct stage2_args *args, Node *device, + NodeList *list, boot::Partition **_partition) +{ + NodeIterator iterator = list->GetIterator(); + boot::Partition *partition = NULL; + while ((partition = (boot::Partition *)iterator.Next()) != NULL) { + // ToDo: just take the first partition for now + *_partition = partition; + return B_OK; + } + + return B_ENTRY_NOT_FOUND; +} + + +#define DUMPED_BLOCK_SIZE 16 + +void +dumpBlock(const char *buffer, int size, const char *prefix) +{ + int i; + + for (i = 0; i < size;) { + int start = i; + + printf(prefix); + for (; i < start+DUMPED_BLOCK_SIZE; i++) { + if (!(i % 4)) + printf(" "); + + if (i >= size) + printf(" "); + else + printf("%02x", *(unsigned char *)(buffer + i)); + } + printf(" "); + + for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) { + if (i < size) { + char c = buffer[i]; + + if (c < 30) + printf("."); + else + printf("%c", c); + } else + break; + } + printf("\n"); + } +} + + +status_t +platform_add_block_devices(stage2_args *args, NodeList *devicesList) +{ + // add all block devices to the list of possible boot devices + + int cookie = 0; + char path[256]; + int status; + for (; (status = cfe_enumdev(cookie, path, sizeof(path))) == B_OK; cookie++) { + if (!strcmp(path, sBootPath)) { + // don't add the boot device twice + continue; + } + + printf("\t%s\n", path); + + int handle = cfe_open(path); + if (handle < CFE_OK) { + puts("\t\t(failed)"); + continue; + } + + Handle *device = new(nothrow) Handle(handle); + printf("\t\t(could open device, handle = %d, node = %p)\n", + handle, device); + + devicesList->Add(device); + } + printf("\t(loop ended with %ld)\n", status); + + return B_OK; +} + + +status_t +platform_register_boot_device(Node *device) +{ + disk_identifier disk; + + disk.bus_type = UNKNOWN_BUS; + disk.device_type = UNKNOWN_DEVICE; + disk.device.unknown.size = device->Size(); + + gKernelArgs.boot_volume.SetData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE, + &disk, sizeof(disk_identifier)); + + return B_OK; +} + diff --git a/src/system/boot/platform/cfe/heap.cpp b/src/system/boot/platform/cfe/heap.cpp new file mode 100644 index 0000000000..1dff002d0c --- /dev/null +++ b/src/system/boot/platform/cfe/heap.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include + + +#define TRACE_HEAP 1 +#if TRACE_HEAP +# define TRACE(x) printf x +#else +# define TRACE(x) ; +#endif + + +status_t +platform_init_heap(stage2_args *args, void **_base, void **_top) +{ + TRACE(("platform_init_heap()\n")); + + *_base = NULL; + status_t error = platform_allocate_region(_base, args->heap_size, + B_READ_AREA | B_WRITE_AREA, false); + if (error != B_OK) + return error; + + printf("heap base = %p\n", *_base); + *_top = (void *)((int8 *)*_base + args->heap_size); + printf("heap top = %p\n", *_top); + + return B_OK; +} + + +void +platform_release_heap(stage2_args *args, void *base) +{ + if (base != NULL) + platform_free_region(base, args->heap_size); +} + diff --git a/src/system/boot/platform/cfe/menu.cpp b/src/system/boot/platform/cfe/menu.cpp new file mode 100644 index 0000000000..47f9c6ff48 --- /dev/null +++ b/src/system/boot/platform/cfe/menu.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + + +void +platform_add_menus(Menu *menu) +{ + // ToDo: implement me! + + switch (menu->Type()) { + case MAIN_MENU: + break; + case SAFE_MODE_MENU: + break; + default: + break; + } +} + + +void +platform_update_menu_item(Menu *menu, MenuItem *item) +{ + platform_generic_update_text_menu_item(menu, item); +} + + +void +platform_run_menu(Menu *menu) +{ + platform_generic_run_text_menu(menu); +} + + +size_t +platform_get_user_input_text(Menu *menu, MenuItem *item, char *buffer, + size_t bufferSize) +{ + return platform_generic_get_user_input_text(menu, item, buffer, + bufferSize); +} diff --git a/src/system/boot/platform/cfe/mmu.cpp b/src/system/boot/platform/cfe/mmu.cpp new file mode 100644 index 0000000000..b9f3143c6f --- /dev/null +++ b/src/system/boot/platform/cfe/mmu.cpp @@ -0,0 +1,36 @@ +/* + * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include + + +status_t +platform_allocate_region(void **_address, size_t size, uint8 protection, + bool exactAddress) +{ + if (size == 0) + return B_BAD_VALUE; + + void *address = arch_mmu_allocate(*_address, size, protection, + exactAddress); + if (address == NULL) + return B_NO_MEMORY; + + *_address = address; + return B_OK; +} + + +status_t +platform_free_region(void *address, size_t size) +{ + return arch_mmu_free(address, size); +} + diff --git a/src/system/boot/platform/cfe/start.cpp b/src/system/boot/platform/cfe/start.cpp new file mode 100644 index 0000000000..f5df6432d3 --- /dev/null +++ b/src/system/boot/platform/cfe/start.cpp @@ -0,0 +1,177 @@ +/* + * Copyright 2011, François Revol, revol@free.fr. + * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2011, Alexander von Gluck, kallisti5@unixzen.com + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include +#include +#include +#include +#include + +#include "console.h" +#include "real_time_clock.h" + + +#define HEAP_SIZE 65536 + + +extern "C" void _start(uint64 handle, uint64 entry, uint32 _unused, + uint32 signature); +extern "C" void start(uint64 cfeHandle, uint64 cfeEntry); + +// GCC defined globals +extern void (*__ctor_list)(void); +extern void (*__ctor_end)(void); +extern uint8 __bss_start; +extern uint8 _end; + +#if 0//OF +uint32 gMachine; +#endif +static uint32 sBootOptions; + + +static void +call_ctors(void) +{ + void (**f)(void); + + for (f = &__ctor_list; f < &__ctor_end; f++) { + (**f)(); + } +} + + +static void +clear_bss(void) +{ + memset(&__bss_start, 0, &_end - &__bss_start); +} + + +extern "C" void +platform_start_kernel(void) +{ + addr_t kernelEntry = gKernelArgs.kernel_image.elf_header.e_entry; + addr_t stackTop = gKernelArgs.cpu_kstack[0].start + + gKernelArgs.cpu_kstack[0].size; + + printf("kernel entry at %p\n", (void*)kernelEntry); + printf("kernel stack top: %p\n", (void*)stackTop); + + /* TODO: ? + mmu_init_for_kernel(); + smp_boot_other_cpus(); + */ + + status_t error = arch_start_kernel(&gKernelArgs, kernelEntry, stackTop); + + panic("Kernel returned! Return value: %ld\n", error); +} + + +extern "C" void +platform_exit(void) +{ + cfe_exit(CFE_FLG_WARMSTART, 0); + panic("cfe_exit() failed."); +} + + +extern "C" uint32 +platform_boot_options(void) +{ + return sBootOptions; +} + + +extern "C" void +_start(uint64 handle, uint64 entry, uint32 _unused, uint32 signature) +{ + + if (signature != CFE_EPTSEAL) + return;//XXX:something? + + clear_bss(); + call_ctors(); + // call C++ constructors before doing anything else + + start(handle, entry); +} + + +extern "C" void +start(uint64 cfeHandle, uint64 cfeEntry) +{ + char bootargs[512]; + + // stage2 args - might be set via the command line one day + stage2_args args; + args.heap_size = HEAP_SIZE; + args.arguments = NULL; + + cfe_init(cfeHandle, cfeEntry); + + // check for arguments +#if 0//OF + if (of_getprop(gChosen, "bootargs", bootargs, sizeof(bootargs)) + != OF_FAILED) { + static const char *sArgs[] = { NULL, NULL }; + sArgs[0] = (const char *)bootargs; + args.arguments = sArgs; + } +#endif + +#if 0//OF + determine_machine(); +#endif + console_init(); + +#if 0//OF + if ((gMachine & MACHINE_QEMU) != 0) + dprintf("OpenBIOS (QEMU?) OpenFirmware machine detected\n"); + else if ((gMachine & MACHINE_PEGASOS) != 0) + dprintf("Pegasos PowerPC machine detected\n"); + else + dprintf("Apple PowerPC machine assumed\n"); +#endif + + // Initialize and take over MMU and set the OpenFirmware callbacks - it + // will ask us for memory after that instead of maintaining it itself + // (the kernel will need to adjust the callback later on as well) + arch_mmu_init(); + + if (boot_arch_cpu_init() != B_OK) + cfe_exit(CFE_FLG_WARMSTART, 1); + +#if 0//OF FIXME + if (init_real_time_clock() != B_OK) + cfe_exit(CFE_FLG_WARMSTART, 1); +#endif + + // check for key presses once + sBootOptions = 0; + int key = console_check_for_key(); + if (key == 32) { + // space bar: option menu + sBootOptions |= BOOT_OPTION_MENU; + } else if (key == 27) { + // ESC: debug output + sBootOptions |= BOOT_OPTION_DEBUG_OUTPUT; + } + + gKernelArgs.platform_args.cfe_entry = cfeEntry; + + main(&args); + // if everything goes fine, main() never returns + + cfe_exit(CFE_FLG_WARMSTART, 1); +} diff --git a/src/system/boot/platform/cfe/support.cpp b/src/system/boot/platform/cfe/support.cpp new file mode 100644 index 0000000000..93bf0e5ee2 --- /dev/null +++ b/src/system/boot/platform/cfe/support.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2011, François Revol, revol@free.fr. + * Copyright 2005, Ingo Weinhold . + * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. + * All rights reserved. Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold, bonefish@cs.tu-berlin.de + * Alexander von Gluck, kallisti5@unixzen.com + */ + + +#include "support.h" +#include + + +bigtime_t +system_time(void) +{ + bigtime_t result = cfe_getticks() * 1000000LL / CFE_HZ ; + return result; +} + diff --git a/src/system/boot/platform/cfe/support.h b/src/system/boot/platform/cfe/support.h new file mode 100644 index 0000000000..f231ab4ed1 --- /dev/null +++ b/src/system/boot/platform/cfe/support.h @@ -0,0 +1,17 @@ +/* + * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck, kallisti5@unixzen.com + */ +#ifndef SUPPORT_H +#define SUPPORT_H + + +#include + + +bigtime_t system_time(void); + +#endif diff --git a/src/system/boot/platform/cfe/video.cpp b/src/system/boot/platform/cfe/video.cpp new file mode 100644 index 0000000000..affd6dfebe --- /dev/null +++ b/src/system/boot/platform/cfe/video.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2010 Andreas Färber + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include + + +//#define TRACE_VIDEO + + +static int sScreen; + + +void +platform_blit4(addr_t frameBuffer, const uint8 *data, + uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top) +{ + panic("platform_blit4(): not implemented\n"); +} + + +extern "C" void +platform_set_palette(const uint8 *palette) +{ + switch (gKernelArgs.frame_buffer.depth) { + case 8: + break; + default: + break; + } +} + + +extern "C" void +platform_switch_to_logo(void) +{ + // in debug mode, we'll never show the logo + if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0) + return; + + return; +} + + +extern "C" void +platform_switch_to_text_mode(void) +{ + // nothing to do if we're in text mode + if (!gKernelArgs.frame_buffer.enabled) + return; + + // ToDo: implement me + + gKernelArgs.frame_buffer.enabled = false; +} + + +extern "C" status_t +platform_init_video(void) +{ + gKernelArgs.frame_buffer.enabled = false; + + return B_NO_INIT; +} + diff --git a/src/system/ldscripts/ppc/boot_loader_cfe.ld b/src/system/ldscripts/ppc/boot_loader_cfe.ld new file mode 100644 index 0000000000..327e7c49f3 --- /dev/null +++ b/src/system/ldscripts/ppc/boot_loader_cfe.ld @@ -0,0 +1,45 @@ +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc) + +ENTRY(_start) + +SECTIONS +{ + . = 0x102000 + SIZEOF_HEADERS; + + __text_begin = .; + + /* text/read-only data */ + .text : { *(.text .text.* .gnu.linkonce.t.*) } + + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .sdata2 : { *(.sdata2) } + + /* writable data */ + /* align to the same offset in the next page (for performance reasons + (not that it really matters in the boot loader)) */ + . = ALIGN(0x1000) + 0x1000 + (. & (0x1000 - 1)); + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + .data.rel.ro : { *(.data.rel.ro.local .data.rel.ro*) } + .got : { *(.got .got2) } + .sdata : { *(.sdata .sdata.* .gnu.linkonce.s.*) } + + /* uninitialized data (in same segment as writable data) */ + __bss_start = .; + .sbss : { *(.sbss .sbss.* .gnu.linkonce.sb.*) } + .bss : { + *(.bss .bss.* .gnu.linkonce.b.*) + . = ALIGN(0x1000); + } + + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors .debug_*) } +}