/* Copyright 2019 Benji Dial Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "vga.h" #include "files.h" #include "mem.h" #include "proc.h" #include enum tag_type { BOOT_COMMAND = 0x00000001, LOADER_NAME = 0x00000002, BOOT_MODULE = 0x00000003, MEMORY_INFO = 0x00000004, BOOT_DEVICE = 0x00000005, MEMORY_MAP = 0x00000006, VBE_INFO = 0x00000007, FBUF_INFO = 0x00000008, ELF_SYMBOLS = 0x00000009, APM_TABLE = 0x0000000a, EFI_I386_TABLE = 0x0000000b, EFI_AMD64_TABLE = 0x0000000c, SMBIOS_TABLE = 0x0000000d, RSDP_ACPI1 = 0x0000000e, RSDP_ACPI2 = 0x0000000f, NETWORK_INFO = 0x00000010, EFI_MEMORY_MAP = 0x00000011, EFI_SERVICES = 0x00000012, EFI_I386_HANDLE = 0x00000013, EFI_AMD64_HANDLE = 0x00000014, IMAGE_BASE_ADDR = 0x00000015 }; struct tag_start { uint32_t type; uint32_t size; } __attribute__ ((__packed__)); struct boot_device_tag { uint32_t bios_device; uint32_t partition; uint32_t subpartition; } __attribute__ ((__packed__)); enum mem_type { AVAILABLE = 1, HARDWARET = 2, ACPI = 3, PRESERVE = 4, DEFECTIVE = 5 }; struct mmap_tag_entry { uint64_t base; uint64_t length; uint32_t type; } __attribute__ ((__packed__)); struct vbe_tag { uint16_t mode; uint16_t v2_segment; uint16_t v2_offset; uint16_t v2_length; uint8_t control_info[512]; uint8_t mode_info[256]; } __attribute__ ((__packed__)); enum color_types { PALETTE = 0x00, RGB = 0x01, TEXT = 0x02 }; struct fbuf_tag { uint32_t address_low; uint32_t address_high; uint32_t pitch; uint32_t width; uint32_t height; uint8_t bpp; uint8_t color_type; uint8_t padding; } __attribute__ ((__packed__)); struct fbuf_palette_entry { uint8_t red; uint8_t green; uint8_t blue; } __attribute__ ((__packed__)); struct fbuf_rgb_info { uint8_t red_pos; uint8_t red_mask; uint8_t green_pos; uint8_t green_mask; uint8_t blue_pos; uint8_t blue_mask; } __attribute__ ((__packed__)); struct elf_tag { uint16_t count; uint16_t size; uint16_t shndx; uint16_t padding; } __attribute__ ((__packed__)); struct module_tag { uint32_t start; uint32_t end; } __attribute__ ((__packed__)); struct smbios_tag { uint8_t major_version; uint8_t minor_version; uint16_t padding[3]; } __attribute__ ((__packed__)); struct apm_table { uint16_t version; uint16_t cs_32; uint32_t ip_32; uint16_t cs_16; uint16_t ds_16; uint16_t flags; uint16_t cs_32_length; uint16_t cs_16_length; uint16_t ds_16_lenth; } __attribute__ ((__packed__)); struct boot_device_tag boot_device; bool have_boot_device = false; bool have_mmap = false; uint32_t text_base; bool have_text_base; enum error_codes { NO_BOOT_DEVICE = 0x00000000, NO_MMAP = 0x00000001, INSUFF_MEMORY = 0x00000002, MMAP_TOO_SMALL = 0x00000003, MISSING_RC = 0x00000004, BAD_RC_LINE = 0x00000005, BAD_MMAP = 0x00000006 }; struct tag_start *tag_pointer; uint32_t main(void) { put_sz("Multiboot info:"); while (tag_pointer->type) { put_sz("\n Tag type 0x"); put_32_hex(tag_pointer->type); put_sz(" with size 0x"); put_32_hex(tag_pointer->size); switch (tag_pointer->type) { case BOOT_COMMAND: put_sz(": boot arguments\n "); put_sz(*(uint8_t *)(tag_pointer + 1) ? (uint8_t *)(tag_pointer + 1) : (uint8_t *)"No arguments"); break; case LOADER_NAME: put_sz(": bootloader name\n "); put_sz((uint8_t *)(tag_pointer + 1)); break; case BOOT_MODULE: put_sz(": boot module\n Loaded at: 0x"); struct module_tag *module = (struct module_tag *)(tag_pointer + 1); put_32_hex(module->start); put_sz(" - "); put_32_hex(module->end - 1); if (*(uint8_t *)(module + 1)) { put_sz("\n Argument: "); put_sz((uint8_t *)(module + 1)); } break; case MEMORY_INFO: put_sz(": memory size\n Lower memory: 0x"); put_32_hex((tag_pointer + 1)->type); put_sz("\n Upper memory: 0x"); put_32_hex((tag_pointer + 1)->size); break; case BOOT_DEVICE: boot_device = *(struct boot_device_tag *)(tag_pointer + 1); have_boot_device = true; put_sz(": boot device\n BIOS code: "); put_32_hex(boot_device.bios_device); if (boot_device.partition != 0xffffffff) { put_sz("\n Partition number: "); put_32_hex(boot_device.partition); if (boot_device.subpartition != 0xffffffff) { put_sz("\n Subpartition number: "); put_32_hex(boot_device.subpartition); } else put_sz("\n No subpartition"); } else put_sz("\n No partition"); break; case MEMORY_MAP: { mmap_start = (struct mmap_entry *)0; uint32_t size = *(uint32_t *)(tag_pointer + 1); struct mmap_tag_entry *tag = (struct mmap_tag_entry *)(tag_pointer + 2); struct mmap_tag_entry *end = (struct mmap_tag_entry *)((uint32_t)tag_pointer + tag_pointer->size); struct mmap_entry *entry = mmap_bss; uint32_t bitmask = 0x00000001; uint32_t byte = 0; uint32_t usable = 0; put_sz(": memory map\n Regions:\n"); while (tag != end) { if (!(tag->base & 0xffffffff00000000) && tag->length) { entry->base = (uint32_t)tag->base; entry->length = (tag->base + tag->length - 1) & 0xffffffff00000000 ? 1 + ~(uint32_t)tag->base : (uint32_t)tag->length; if (!entry->base) mmap_start = entry; put_sz(" 0x"); put_32_hex(entry->base); put_sz(" - 0x"); put_32_hex(entry->base + entry->length - 1); switch (tag->type) { case AVAILABLE: put_sz(": usable\n"); entry->whose = FREE; usable += entry->length; break; case HARDWARET: case PRESERVE: put_sz(": hardware use\n"); entry->whose = HARDWARE; break; case ACPI: put_sz(": ACPI info\n"); entry->whose = HARDWARE; break; case DEFECTIVE: put_sz(": defective\n"); entry->whose = HARDWARE; break; default: put_sz(": assuming hardware use (0x"); put_32_hex(tag->type); put_sz(")\n"); entry->whose = HARDWARE; break; } mmap_bitmap[byte] |= bitmask; ++entry; if (!(bitmask <<= 1)) { bitmask = 0x00000001; if (++byte == MMAP_SIZE) return MMAP_TOO_SMALL; } } tag = (struct mmap_tag_entry *)((uint32_t)tag + size); } put_sz(" Total usable memory: 0x"); put_32_hex(usable); for (struct mmap_entry *b = mmap_bss; b < entry; ++b) for (struct mmap_entry *a = mmap_bss; a < entry; ++a) if (b->base + b->length == a->base) (b->after = a)->before = b; for (struct mmap_entry *p = mmap_start; p->after; p = p->after) while (p->whose == p->after->whose) { p->length += p->after->whose; unmark_entry(p->after); if (p->after = p->after->after) p->after->before = p; } if (mmap_start) { have_mmap = true; break; } return BAD_MMAP; } case VBE_INFO: { struct vbe_tag *vbe_info = (struct vbe_tag *)(tag_pointer + 1); put_sz(": VBE information"); if (vbe_info->v2_length) { put_sz("\n v2: 0x"); put_16_hex(vbe_info->v2_segment); put_sz(":0x"); put_16_hex(vbe_info->v2_offset); put_sz(" + 0x"); put_16_hex(vbe_info->v2_length); } put_sz("\n v3 mode: 0x"); put_16_hex(vbe_info->mode); break; } case FBUF_INFO: { struct fbuf_tag *fbuf_info = (struct fbuf_tag *)(tag_pointer + 1); put_sz(": framebuffer information\n Address: 0x"); put_32_hex(fbuf_info->address_high); put_char('.'); put_32_hex(fbuf_info->address_low); put_sz("\n Pitch: "); put_32_dec(fbuf_info->pitch); put_sz("B\n Size: "); put_32_dec(fbuf_info->width); put_sz(" x "); put_32_dec(fbuf_info->height); put_sz(" x "); put_8_dec(fbuf_info->bpp); switch (fbuf_info->color_type) { case PALETTE: put_sz("b\n Palette:"); uint32_t l = *(uint32_t *)(fbuf_info + 1); struct fbuf_palette_entry *palette = (struct fbuf_palette_entry *)((uint32_t *)(fbuf_info + 1) + 1); for (uint32_t i = 0; i < l; ++i) { put_sz("\n #"); put_8_hex(palette[i].red); put_8_hex(palette[i].green); put_8_hex(palette[i].blue); } break; case RGB: put_sz("b\n RGB:"); //TODO break; case TEXT: put_sz("b\n Text mode"); break; default: put_sz("b\n Unknown mode 0x"); put_8_hex(fbuf_info->color_type); } break; } case ELF_SYMBOLS: { struct elf_tag *tag = (struct elf_tag *)(tag_pointer + 1); struct elf_shdr *p = (struct elf_shdr *)(tag + 1); put_sz(": ELF shdr table\n shndx: 0x"); put_16_hex(tag->shndx); if (tag->count) for (uint32_t i = 0; i < tag->count; ++i) { ;//TODO p = (struct elf_shdr *)((uint32_t)p + tag->size); } break; } case APM_TABLE: { struct apm_table *table = (struct apm_table *)(tag_pointer + 1); put_sz(": APM table\n v"); put_16_dec(table->version); //TODO break; } case SMBIOS_TABLE: { struct smbios_tag *tag = (struct smbios_tag *)(tag_pointer + 1); put_sz(": SMBIOS\n v"); put_8_dec(tag->major_version); put_char('.'); put_8_dec(tag->minor_version); //TODO break; } case IMAGE_BASE_ADDR: put_sz(": image address\n 0x"); put_32_hex(text_base = *(uint32_t *)(tag_pointer + 1)); have_text_base = true; break; default: put_sz(": ignoring"); } tag_pointer = (struct tag_start *)(((uint32_t)tag_pointer + tag_pointer->size - 1 & 0xfffffff8) + 8); } if (!have_boot_device) return NO_BOOT_DEVICE; if (!have_mmap) return NO_MMAP; put_sz("\n\nInfo:"); if (have_text_base) { put_sz("\n Text section: 0x"); put_32_hex(text_base); } put_sz("\n Memory map size: 0x"); put_32_hex(sizeof(struct mmap_entry) * MMAP_SIZE); put_sz("\n Process table size: 0x"); put_32_hex(sizeof(struct proc_info) * 65536); put_sz("\n File table size: 0x"); put_32_hex(sizeof(struct file_info) * 65536); put_sz("\n\nDisks:"); for (uint8_t i = 0; i < 26; ++i) { detect_disk_parts((uint8_t)'a' + i); if (part_info[i].format) { put_sz("\n "); put_char((uint8_t)'a' + i); if (part_info[i].n_partitions) { put_char('0'); uint8_t str[] = "\n 1"; for (uint8_t m = part_info[i].n_partitions + (uint8_t)'0'; str[4] < m; ++(str[4])) put_sz(str); } } } put_sz("\n\n"); put_sz("No file support yet. Halting."); while (1) asm ("hlt"); uint8_t rc_buffer[4096]; uint16_t rc_handle = open_file("/cfg/init/once.rc"); if (!rc_handle) return MISSING_RC; while (read_line_file(rc_handle, 4095, (void *)rc_buffer)) if ((*rc_buffer != (uint8_t)'#') && !new_proc(rc_buffer)) return BAD_RC_LINE; close_file(rc_handle); rc_handle = open_file("/cfg/init/repeat.rc"); if (!rc_handle) return MISSING_RC; while (1) { while (read_line_file(rc_handle, 4095, (void *)rc_buffer)) if ((*rc_buffer != (uint8_t)'#') && !new_proc(rc_buffer)) return BAD_RC_LINE; seek_file(rc_handle, -0x80000000); seek_file(rc_handle, -0x80000000); } } void wrapped_main(void) { clear(); uint32_t error = main(); set_color(0x47); clear(); put_sz("Error: 0x"); put_32_hex(error); }