diff --git a/src/kernel/boot/loader/Jamfile b/src/kernel/boot/loader/Jamfile new file mode 100644 index 0000000000..16824ec84c --- /dev/null +++ b/src/kernel/boot/loader/Jamfile @@ -0,0 +1,58 @@ +SubDir OBOS_TOP src kernel boot loader ; + +SubDirHdrs $(OBOS_TOP) src add-ons kernel partitioning_systems amiga ; +UsePrivateHeaders [ FDirName kernel boot platform $(OBOS_BOOT_PLATFORM) ] ; +UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; +UsePrivateHeaders [ FDirName storage ] ; + +{ + local defines = + _BOOT_MODE + BOOT_SUPPORT_PARTITION_AMIGA + ; + + defines = [ FDefines $(defines) ] ; + SubDirCcFlags $(defines) -Wall -Wno-multichar ; + SubDirC++Flags $(defines) -Wall -Wno-multichar ; +} + +KernelStaticLibrary boot_loader : + main.cpp + vfs.cpp + partitions.cpp + heap.cpp + stdio.cpp + list.c + + amiga_rdb.cpp + + kernel_cpp.cpp + : + -fno-builtin + ; + +# The following is a try to make the actual partition support +# really configurable somewhere and let the build independent +# from it: + +#local boot_partition_support = +# amiga_rdb.cpp +# ; +# +#KernelStaticLibrary boot_loader_partition : +# $(boot_partition_support) +# : +# ; + +# Tell Jam where to find the utility sources +SEARCH on [ FGristFiles kernel_cpp.cpp list.c ] + = [ FDirName $(OBOS_TOP) src kernel core util ] ; + +SEARCH on [ FGristFiles amiga_rdb.cpp ] + = [ FDirName $(OBOS_TOP) src add-ons kernel partitioning_systems amiga ] ; + +SEARCH on [ FGristFiles stage2_crt0.S ] + = [ FDirName $(OBOS_TOP) src kernel boot arch $(OBOS_ARCH) ] ; + +# SubInclude OBOS_TOP src kernel boot loader partition ; + diff --git a/src/kernel/boot/loader/main.cpp b/src/kernel/boot/loader/main.cpp new file mode 100644 index 0000000000..c578a65aea --- /dev/null +++ b/src/kernel/boot/loader/main.cpp @@ -0,0 +1,79 @@ +/* +** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + + +#include +#include +#include +#include +#include + +#include + + +extern "C" int +boot(stage2_args *args) +{ + puts("Oh yes, we are\n"); + if (heap_init(args) < B_OK) + panic("Could not initialize heap!\n"); + + puts("heap initialized..."); + + // the main platform dependent initialisation + // has already taken place at this point. + + if (vfs_init(args) < B_OK) + panic("Could not initialize VFS!\n"); + + puts("Welcome to the OpenBeOS boot loader!"); + + if (mount_boot_file_systems() < B_OK) + panic("Could not locate any supported boot devices!\n"); + + heap_release(); + return 0; +} + +#if 0 +void *get_boot_device(stage2_args *args); +void *user_menu(); +void load_boot_drivers(void *device); +void load_boot_modules(void *device); +void load_driver_settings(void *device); + + +void +load_kernel(void *deviceHandle) +{ + void *handle = open(deviceHandle, "system/kernel"); + if (handle == NULL) + panic("Could not open kernel from boot device!\n"); + + /* load kernel into memory and relocate it */ +} + + +int +main(stage2_args *args) +{ + /* pre-state2 initialization is already done at this point */ + + void *device = get_boot_device(args); + if (device == NULL) + device = user_menu(); + + if (device == NULL) + panic("No boot partition found"); + + load_kernel(device); + load_boot_drivers(device); + load_boot_modules(device); + load_driver_settings(device); + + start_kernel(); +} +#endif + diff --git a/src/kernel/boot/loader/partitions.cpp b/src/kernel/boot/loader/partitions.cpp new file mode 100644 index 0000000000..f428e3483e --- /dev/null +++ b/src/kernel/boot/loader/partitions.cpp @@ -0,0 +1,124 @@ +/* +** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + + +#include +#include +#include +#include +#include + +#include +#include + + +static partition_module_info *sPartitionModules[] = { +#ifdef BOOT_SUPPORT_PARTITION_AMIGA + &gAmigaPartitionModule, +#endif +#ifdef BOOT_SUPPORT_PARTITION_INTEL + &gIntelPartitionModule, +#endif +#ifdef BOOT_SUPPORT_PARTITION_APPLE + &gApplePartitionModule, +#endif +}; +static const int32 sNumPartitionModules = sizeof(sPartitionModules) / sizeof(partition_module_info *); + +extern list gPartitions; + + +Partition::Partition(int fd) +{ + // it's safe to close the file + fFD = dup(fd); +} + + +Partition::~Partition() +{ + close(fFD); +} + + +ssize_t +Partition::ReadAt(void *cookie, off_t position, void *buffer, size_t bufferSize) +{ + if (position > this->size) + return 0; + if (position < 0) + position = 0; + + if (position + bufferSize > this->size) + bufferSize = this->size - position; + + return read_pos(fFD, this->offset + position, buffer, bufferSize); +} + + +ssize_t +Partition::WriteAt(void *cookie, off_t position, const void *buffer, size_t bufferSize) +{ + if (position > this->size) + return 0; + if (position < 0) + position = 0; + + if (position + bufferSize > this->size) + bufferSize = this->size - position; + + return write_pos(fFD, this->offset + position, buffer, bufferSize); +} + + +// #pragma mark - + + +status_t +add_partitions_for(int fd) +{ + struct partition_data partition; + memset(&partition, 0, sizeof(partition_data)); + + // set some magic/default values + partition.id = (partition_id)&partition; + partition.block_size = 512; + partition.size = 1024*1024*1024; // ToDo: fix this! + partition.volume = (dev_t)fd; + + for (int32 i = 0; i < sNumPartitionModules; i++) { + partition_module_info *module = sPartitionModules[i]; + void *cookie; + + puts(module->pretty_name); + if (module->identify_partition(fd, &partition, &cookie) <= 0.0) + continue; + + status_t status = module->scan_partition(fd, &partition, cookie); + module->free_identify_partition_cookie(&partition, cookie); + + if (status == B_OK) + return B_OK; + } + return B_ENTRY_NOT_FOUND; +} + + +partition_data * +create_child_partition(partition_id id, int32 index, partition_id childID) +{ + partition_data &partition = *(partition_data *)id; + Partition *child = new Partition(partition.volume); + if (child == NULL) { + printf("creating partition failed: no memory\n"); + return NULL; + } + + list_add_item(&gPartitions, (void *)child); + + return child; +} + + diff --git a/src/kernel/boot/loader/stdio.cpp b/src/kernel/boot/loader/stdio.cpp new file mode 100644 index 0000000000..9520d4b5d9 --- /dev/null +++ b/src/kernel/boot/loader/stdio.cpp @@ -0,0 +1,142 @@ +/* +** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + + +#include +#include +#include + +#include +#include + +//#undef stdout +//#undef stdin +//extern FILE *stdout; +//extern FILE *stdin; + + +// ToDo: does it make sense to have the extra "\r\n" handling in here? +// or should this be done by the platform dependent part? + + +int +vfprintf(FILE *file, const char *format, va_list list) +{ + ConsoleNode *node = (ConsoleNode *)file; + char buffer[1024]; + // the buffer handling could (or should) be done better... + // we should have a vsprintf() version that accepts a + // maximum buffer size (for the kernel as well!) + + int length = vsprintf(buffer, format, list); + if (length > 0) { + int pos = 0; + char *c; + + // be nice to our audience and replace single "\n" with "\r\n" + + for (c = buffer; c[0] && (size_t)length < sizeof(buffer) - 1; c++, pos++) { + if (c[0] == '\r' && c[1] == '\n') { + c++; + pos++; + continue; + } + if (c[0] == '\n') { + // insert a '\r' here + memmove(c + 1, c, length - pos); + c[0] = '\r'; + length++; + } + } + node->Write(buffer, length); + } + + return length; +} + + +int +printf(const char *format, ...) +{ + va_list args; + + va_start(args, format); + int status = vfprintf(stdout, format, args); + va_end(args); + + return status; +} + + +int +fprintf(FILE *file, const char *format, ...) +{ + va_list args; + + va_start(args, format); + int status = vfprintf(file, format, args); + va_end(args); + + return status; +} + + +int +fputc(int character, FILE *file) +{ + if (file == NULL) + return B_FILE_ERROR; + + status_t status; + + // we only support direct console output right now... + if (character == '\n') + status = ((ConsoleNode *)file)->Write("\r\n", 2); + else + status = ((ConsoleNode *)file)->Write(&character, 1); + + if (status > 0) + return character; + + return status; +} + + +int +fputs(const char *string, FILE *file) +{ + if (file == NULL) + return B_FILE_ERROR; + + // ToDo: for consistency, we should replace "\n" with "\r\n" here, too. + + status_t status = ((ConsoleNode *)file)->Write(string, strlen(string)); + fputc('\n', file); + + return status; +} + + +int +putc(int character) +{ + return fputc(character, stdout); +} + + +int +putchar(int character) +{ + return fputc(character, stdout); +} + + +int +puts(const char *string) +{ + return fputs(string, stdout); +} + + diff --git a/src/kernel/boot/loader/vfs.cpp b/src/kernel/boot/loader/vfs.cpp new file mode 100644 index 0000000000..57413ce533 --- /dev/null +++ b/src/kernel/boot/loader/vfs.cpp @@ -0,0 +1,364 @@ +/* +** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + + +#include +#include +#include +#include + +#include +#include + + +#if 0 +struct vfs_ops { + int (*open)(void **_cookie); + int (*close)(void *cookie); + int (*read)(void *cookie, off_t pos, void *buffer, size_t bytes); + int (*write)(void *cookie, off_t pos, const void *buffer, size_t bytes); +}; + +struct vfs_node { + struct vfs_node *next; + off_t offset; + off_t size; + int32 ref_count; + struct vfs_ops *ops; +}; + +struct vfs_descriptor { + struct vfs_node *node; + struct vfs_ops *ops; + void *cookie; + off_t offset; + int32 ref_count; +}; +#endif + +#define MAX_VFS_DESCRIPTORS 32 + +list gBootDevices; +list gPartitions; +Descriptor *gDescriptors[MAX_VFS_DESCRIPTORS]; + + +Node::Node() + : + fRefCount(0) +{ + fLink.next = fLink.prev = NULL; +} + + +Node::~Node() +{ +} + + +status_t +Node::Open(void **_cookie, int mode) +{ + return B_OK; +} + + +status_t +Node::Close(void *cookie) +{ + return B_OK; +} + + +#pragma mark - + + +ConsoleNode::ConsoleNode() + : Node() +{ +} + + +ssize_t +ConsoleNode::Read(void *buffer, size_t bufferSize) +{ + return ReadAt(NULL, -1, buffer, bufferSize); +} + + +ssize_t +ConsoleNode::Write(const void *buffer, size_t bufferSize) +{ + return WriteAt(NULL, -1, buffer, bufferSize); +} + + +#pragma mark - + + +Descriptor::Descriptor(Node *node, void *cookie) + : + fNode(node), + fCookie(cookie), + fOffset(0), + fRefCount(1) +{ +} + + +Descriptor::~Descriptor() +{ +} + + +ssize_t +Descriptor::Read(void *buffer, size_t bufferSize) +{ + ssize_t bytesRead = fNode->ReadAt(fCookie, fOffset, buffer, bufferSize); + if (bytesRead > B_OK) + fOffset += bytesRead; + + return bytesRead; +} + + +ssize_t +Descriptor::Read(off_t pos, void *buffer, size_t bufferSize) +{ + return fNode->ReadAt(fCookie, pos, buffer, bufferSize); +} + + +ssize_t +Descriptor::Write(const void *buffer, size_t bufferSize) +{ + ssize_t bytesWritten = fNode->WriteAt(fCookie, fOffset, buffer, bufferSize); + if (bytesWritten > B_OK) + fOffset += bytesWritten; + + return bytesWritten; +} + + +ssize_t +Descriptor::Write(off_t pos, const void *buffer, size_t bufferSize) +{ + return fNode->WriteAt(fCookie, pos, buffer, bufferSize); +} + + +status_t +Descriptor::Acquire() +{ + fRefCount++; + return B_OK; +} + + +status_t +Descriptor::Release() +{ + if (--fRefCount == 1) { + status_t status = fNode->Close(fCookie); + if (status != B_OK) + return status; + } + + return B_OK; +} + + +#pragma mark - + + +static Descriptor * +get_descriptor(int fd) +{ + if (fd >= MAX_VFS_DESCRIPTORS) + return NULL; + + return gDescriptors[fd]; +} + + +static void +free_descriptor(int fd) +{ + if (fd >= MAX_VFS_DESCRIPTORS) + return; + + delete gDescriptors[fd]; + gDescriptors[fd] = NULL; +} + + +/** Reserves an entry of the descriptor table and + * assigns the given node to it. + */ + +int +open_node(Node *node, int mode) +{ + if (node == NULL) + return B_ERROR; + + // get free descriptor + + int fd = 0; + for (; fd < MAX_VFS_DESCRIPTORS; fd++) { + if (gDescriptors[fd] == NULL) + break; + } + if (fd == MAX_VFS_DESCRIPTORS) + return B_ERROR; + + printf("got descriptor %d\n", fd); + + // we got a free descriptor entry, now try to open the node + + void *cookie; + status_t status = node->Open(&cookie, mode); + if (status < B_OK) + return status; + + printf("could open node at %p\n", node); + + Descriptor *descriptor = new Descriptor(node, cookie); + if (descriptor == NULL) + return B_NO_MEMORY; + + gDescriptors[fd] = descriptor; + + return fd; +} + + +status_t +vfs_init(stage2_args *args) +{ + list_init(&gBootDevices); + list_init(&gPartitions); + + status_t status = platform_get_boot_devices(args, &gBootDevices); + if (status < B_OK) + return status; + + return B_OK; +} + + +status_t +mount_boot_file_systems() +{ + Node *device = NULL; + while ((device = (Node *)list_get_next_item(&gBootDevices, (void *)device)) != NULL) { + int fd = open_node(device, O_RDONLY); + if (fd < B_OK) + continue; + + puts("add partitions"); + add_partitions_for(fd); + + close(fd); + } + + if (list_is_empty(&gPartitions)) + panic("Could not find any partitions on the boot devices"); + + return B_OK; +} + + +/* +void * +mount(void *from, const char *name) +{ + ops *op = (ops *)handle; + + if (op->mount != NULL) + return op->mount(from, name); + + return NULL; +} +*/ + + +int +dup(int fd) +{ + Descriptor *descriptor = get_descriptor(fd); + if (descriptor == NULL) + return B_FILE_ERROR; + + descriptor->Acquire(); + return fd; +} + + +ssize_t +read_pos(int fd, off_t offset, void *buffer, size_t bufferSize) +{ + Descriptor *descriptor = get_descriptor(fd); + if (descriptor == NULL) + return B_FILE_ERROR; + + return descriptor->Read(offset, buffer, bufferSize); +} + + +ssize_t +read(int fd, void *buffer, size_t bufferSize) +{ + Descriptor *descriptor = get_descriptor(fd); + if (descriptor == NULL) + return B_FILE_ERROR; + + return descriptor->Read(buffer, bufferSize); +} + + +ssize_t +write_pos(int fd, off_t offset, const void *buffer, size_t bufferSize) +{ + Descriptor *descriptor = get_descriptor(fd); + if (descriptor == NULL) + return B_FILE_ERROR; + + return descriptor->Write(offset, buffer, bufferSize); +} + + +ssize_t +write(int fd, const void *buffer, size_t bufferSize) +{ + Descriptor *descriptor = get_descriptor(fd); + if (descriptor == NULL) + return B_FILE_ERROR; + + return descriptor->Write(buffer, bufferSize); +} + + +int +open(const char *name, int mode) +{ + return B_ERROR; +} + + +int +close(int fd) +{ + Descriptor *descriptor = get_descriptor(fd); + if (descriptor == NULL) + return B_FILE_ERROR; + + status_t status = descriptor->Release(); + if (!descriptor->RefCount()) + free_descriptor(fd); + + return status; +} +