Skip to content

Commit

Permalink
[platform][qemu-m68k] expand the bootinfo parsing code
Browse files Browse the repository at this point in the history
Break into a separate .c file.
  • Loading branch information
travisg committed Sep 7, 2024
1 parent d9362e4 commit dbef9ff
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 35 deletions.
91 changes: 91 additions & 0 deletions platform/qemu-virt-m68k/bootinfo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2024 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#include "bootinfo.h"

#include <lk/compiler.h>
#include <lk/trace.h>
#include <lk/debug.h>
#include <stdio.h>

#define LOCAL_TRACE 0

extern uint8_t __bss_end;

static const char *bootinfo_tag_to_string(enum BOOTINFO_TAGS tag) {
switch (tag) {
case BOOTINFO_TAG_END: return "END";
case BOOTINFO_TAG_MACHTYPE: return "MACHTYPE";
case BOOTINFO_TAG_CPUTYPE: return "CPUTYPE";
case BOOTINFO_TAG_FPUTYPE: return "FPUTYPE";
case BOOTINFO_TAG_MMUTYPE: return "MMUTYPE";
case BOOTINFO_TAG_MEMCHUNK: return "MEMCHUNK";
case BOOTINFO_TAG_RAMDISK: return "RAMDISK";
case BOOTINFO_TAG_COMMAND_LINE: return "COMMAND_LINE";
case BOOTINFO_TAG_RNG_SEED: return "RNG_SEED";
case BOOTINFO_TAG_VIRT_QEMU_VERSION: return "VIRT_QEMU_VERSION";
case BOOTINFO_TAG_VIRT_GF_PIC_BASE: return "VIRT_GF_PIC_BASE";
case BOOTINFO_TAG_VIRT_GF_RTC_BASE: return "VIRT_GF_RTC_BASE";
case BOOTINFO_TAG_VIRT_GF_TTY_BASE: return "VIRT_GF_TTY_BASE";
case BOOTINFO_TAG_VIRT_VIRTIO_BASE: return "VIRT_VIRTIO_BASE";
case BOOTINFO_TAG_VIRT_CTRL_BASE: return "VIRT_CTRL_BASE";
default: return "UNKNOWN";
}
}

static void dump_bootinfo_record(const struct bootinfo_item *item) {
printf("item %p: tag %hx (%s), size %hu\n", item, item->tag, bootinfo_tag_to_string(item->tag), item->size);
if (item->size > 4) {
hexdump8(item->data, item->size - 4);
}
}

void dump_all_bootinfo_records(void) {
const uint8_t *ptr = &__bss_end;

printf("bootinfo records at %p:\n", ptr);
for (;;) {
const struct bootinfo_item *item = (const struct bootinfo_item *)ptr;
if (item->tag == BOOTINFO_TAG_END) {
break;
}

dump_bootinfo_record(item);

// move to the next field
ptr += item->size;
}
}

// look for tags that qemu left at the end of the kernel that hold various
// pieces of system configuration info.
const void *bootinfo_find_record(uint16_t id, uint16_t *size_out) {
const uint8_t *ptr = &__bss_end;

*size_out = 0;
for (;;) {
const struct bootinfo_item *item = (const struct bootinfo_item *)ptr;
if (item->tag == BOOTINFO_TAG_END) {
return NULL;
}

if (LOCAL_TRACE > 2) {
dump_bootinfo_record(item);
}

if (item->tag == id) {
*size_out = item->size - 4;
return item->data;
} else if (item->tag == 0) { // end token
return NULL;
}

// move to the next field
ptr += item->size;
}
}

64 changes: 64 additions & 0 deletions platform/qemu-virt-m68k/bootinfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2024 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#pragma once

#include <stdint.h>

// parse bootinfo
struct bootinfo_item {
uint16_t tag;
uint16_t size;
uint32_t data[0];
};

// bootinfo tags (from QEMU)
enum BOOTINFO_TAGS {
BOOTINFO_TAG_END = 0,
BOOTINFO_TAG_MACHTYPE = 1,
BOOTINFO_TAG_CPUTYPE = 2,
BOOTINFO_TAG_FPUTYPE = 3,
BOOTINFO_TAG_MMUTYPE = 4,
BOOTINFO_TAG_MEMCHUNK = 5,
BOOTINFO_TAG_RAMDISK = 6,
BOOTINFO_TAG_COMMAND_LINE = 7,
BOOTINFO_TAG_RNG_SEED = 8,
BOOTINFO_TAG_VIRT_QEMU_VERSION = 0x8000,
BOOTINFO_TAG_VIRT_GF_PIC_BASE = 0x8001,
BOOTINFO_TAG_VIRT_GF_RTC_BASE = 0x8002,
BOOTINFO_TAG_VIRT_GF_TTY_BASE = 0x8003,
BOOTINFO_TAG_VIRT_VIRTIO_BASE = 0x8004,
BOOTINFO_TAG_VIRT_CTRL_BASE = 0x8005,
};

void dump_all_bootinfo_records(void);
const void *bootinfo_find_record(uint16_t id, uint16_t *size_out);

// for BOOTINFO_TAG_*TYPE tags
struct bootinfo_item_type {
uint32_t type;
};

// for BOOTINFO_TAG_VIRT_QEMU_VERSION
struct bootinfo_item_qemu_version {
uint8_t major;
uint8_t minor;
uint8_t micro;
uint8_t unused__;
};

// for BOOTINFO_TAG_MEMCHUNK
struct bootinfo_item_memchunk {
uint32_t base;
uint32_t size;
};

// for VIRT_*_BASE tags
struct bootinfo_item_device {
uint32_t base;
uint32_t irq_base;
};
49 changes: 14 additions & 35 deletions platform/qemu-virt-m68k/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,60 +25,39 @@
#include <kernel/novm.h>
#endif

#include "bootinfo.h"
#include "platform_p.h"

#define LOCAL_TRACE 0

extern uint8_t __bss_end;

// parse bootinfo
struct bootinfo_item {
uint16_t tag;
uint16_t size;
uint32_t data[0];
};

// look for tags that qemu left at the end of the kernel that hold various
// pieces of system configuration info.
static void *bootinfo_find_record(uint16_t id, uint16_t *size_out) {
uint8_t *ptr = &__bss_end;

*size_out = 0;
for (;;) {
struct bootinfo_item *item = (struct bootinfo_item *)ptr;

LTRACEF_LEVEL(2, "item %p: tag %hx, size %hu\n", item, item->tag, item->size);

if (item->tag == id) {
*size_out = item->size - 4;
return item->data;
} else if (item->tag == 0) { // end token
return NULL;
}

// move to the next field
ptr += item->size;
}
}

void platform_early_init(void) {
goldfish_tty_early_init();
pic_early_init();
goldfish_rtc_early_init();

// Dump the bootinfo structure
if (LK_DEBUGLEVEL >= INFO) {
dump_all_bootinfo_records();
}

// look for tag 0x5, which describes the memory layout of the system
uint16_t size;
void *ptr = bootinfo_find_record(0x5, &size);
const void *ptr = bootinfo_find_record(BOOTINFO_TAG_MEMCHUNK, &size);
if (!ptr) {
panic("68K VIRT: unable to find MEMCHUNK BOOTINFO record\n");
}
if (size < 8) {
panic("68K VIRT: MEMCHUNK BOOTINFO record too small\n");
}
LTRACEF("MEMCHUNK ptr %p, size %hu\n", ptr, size);

uint32_t membase = *(uint32_t *)ptr;
uint32_t memsize = *(uint32_t *)((uintptr_t)ptr + 4);
uint32_t membase = *(const uint32_t *)ptr;
uint32_t memsize = *(const uint32_t *)((uintptr_t)ptr + 4);

dprintf(INFO, "VIRT: memory base %#x size %#x\n", membase, memsize);
novm_add_arena("mem", membase, memsize);

// TODO: read the rest of the device bootinfo records and dynamically locate devices
}

void platform_init(void) {
Expand Down
1 change: 1 addition & 0 deletions platform/qemu-virt-m68k/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ MODULE_DEPS += dev/virtio/block
MODULE_DEPS += dev/virtio/gpu
MODULE_DEPS += dev/virtio/net

MODULE_SRCS += $(LOCAL_DIR)/bootinfo.c
MODULE_SRCS += $(LOCAL_DIR)/goldfish_rtc.c
MODULE_SRCS += $(LOCAL_DIR)/goldfish_tty.c
MODULE_SRCS += $(LOCAL_DIR)/pic.c
Expand Down

0 comments on commit dbef9ff

Please sign in to comment.