#include "std.h" #include #define COM1_BASE_PORT 0x3F8 static inline uint8_t inb(uint16_t port) { uint8_t data; __asm__ ("inb %%dx, %%al" : "=a"(data) : "d"(port)); return data; } static inline void outb(uint16_t port, uint8_t data) { __asm__ ("outb %%al, %%dx" :: "a"(data), "d"(port)); } extern void bios_write(const char *msg); extern void *bios_getmap(void *buffer); void debug_write(const char *msg) { for (const char *c = msg; *c; c++) { outb(0xE9, *c); } bios_write(msg); } extern BOOTBOOT bootboot; #define E820_TYPE_FREE 0x1 #define E820_TYPE_RESERVED 0x2 #define E820_TYPE_RECLAIMABLE 0x3 #define E820_TYPE_NONVOLATILE 0x4 #define E820_TYPE_BADMEM 0x5 struct e820_entry { uint64_t base; uint64_t length; uint32_t type; uint32_t xattr; }; struct e820_entry memmap[128]; struct vesa_info { char signature[4]; uint16_t version; uint16_t oem_name[2]; uint8_t capab[4]; uint16_t video_mode_offset; uint16_t video_mode_segment; uint16_t num_64k_blocks; uint8_t reserved[492]; }; extern uint16_t bios_func(uint8_t inum, uint32_t reg[]); void blank_screen(uint16_t attr) { uint32_t reg[7]; reg[0] = (0x06 << 8); reg[1] = 0; reg[2] = 0xFFFF; reg[3] = attr << 8; reg[4] = 0; reg[5] = 0; reg[6] = 0; bios_func(0x10, reg); } void move_cursor(uint8_t row, uint8_t col) { uint32_t reg[7]; reg[0] = (0x02 << 8); reg[1] = 0; reg[2] = (row << 8) | col; reg[3] = 0; reg[4] = 0; reg[5] = 0; reg[6] = 0; bios_func(0x10, reg); } void display_string(uint16_t attr, const char *str) { uint32_t reg[7]; reg[0] = (0x13 << 8) | 0x01; reg[1] = strlen(str); reg[2] = 0xFFFF; reg[3] = attr; reg[4] = (uint32_t)str; reg[5] = 0; reg[6] = 0; bios_func(0x10, reg); } void debug_write_uint(unsigned v) { char buf[20], *p = buf + sizeof buf; p--; *p = 0; do { p--; *p = (v % 10) + '0'; v /= 10; } while (v); debug_write(p); } #define PG_PRESENT 0x001 #define PG_WRITE 0x002 #define PG_USER 0x004 #define PG_SIZE 0x080 #define PG_GLOBAL 0x100 __attribute__((aligned(4096))) uint64_t pml4[512]; __attribute__((aligned(4096))) uint64_t pdp[512]; __attribute__((aligned(4096))) uint64_t pd[512]; uint64_t pg_setup() { pml4[0] = (uint64_t)(uint32_t)pdp | PG_WRITE | PG_PRESENT; pdp[0] = (uint64_t)(uint32_t)pd | PG_WRITE | PG_PRESENT; for (unsigned i = 0; i < 512; i++) { pd[i] = (i * (uint64_t)0x200000) | PG_WRITE | PG_PRESENT | PG_SIZE; } uint64_t cr3 = (uint64_t)(uint32_t)pml4; return cr3; } struct PXENV { uint8_t signature[6]; uint16_t version; uint8_t length; uint8_t checksum; uint32_t rmentry; uint32_t pmoffset; }; struct exPXE { uint8_t signature[4]; uint8_t length; uint8_t checksum; uint8_t revision; uint8_t reserved; uint32_t undiromid; uint32_t bcromid; uint32_t rmentry; uint32_t pmentry; }; struct bootph { uint8_t opcode; uint8_t hardware; uint8_t hardlen; uint8_t gatehops; uint32_t ident; uint16_t seconds; uint16_t flags; uint32_t cip; uint32_t yip; uint32_t sip; uint32_t gip; uint8_t caddr[16]; uint8_t sname[64]; uint8_t bootfile[128]; uint8_t vendor[64]; }; extern uint32_t pxe_entry; extern uint32_t pxe_call(uint16_t func, uint16_t segment, uint16_t offset); extern unsigned char pxe_cmd_buf[512]; extern struct PXENV *PXENV; extern struct exPXE *exPXE; #define PXENV_GET_CACHED 0x0071 #define PXENV_TFTP_OPEN 0x0020 #define PXENV_TFTP_READ 0x0022 typedef struct __attribute__((packed)) s_PXENV_GET_CACHED { uint16_t status; uint16_t packet_type; uint16_t buffer_size; uint16_t buffer_offset; uint16_t buffer_seg; uint16_t buffer_limit; } t_PXENV_GET_CACHED; typedef struct __attribute__((packed)) s_PXENV_TFTP_OPEN { uint16_t status; uint32_t server_ip; uint32_t gateway_ip; unsigned char filename[128]; uint16_t tftp_port; uint16_t packet_size; } t_PXENV_TFTP_OPEN; typedef struct __attribute__((packed)) s_PXENV_TFTP_READ { uint16_t status; uint16_t packet_number; uint16_t buffer_size; uint16_t buffer_offset; uint16_t buffer_seg; } t_PXENV_TFTP_READ; /** * return type for fs drivers */ typedef struct { uint8_t *ptr; uint32_t size; } file_t; /** * convert ascii octal number to binary number */ int octbin(unsigned char *str,int size) { int s=0; unsigned char *c=str; while(size-->0){ s*=8; s+=*c-'0'; c++; } return s; } /** * convert ascii hex number to binary number */ int hexbin(unsigned char *str, int size) { int v=0; while(size-->0){ v <<= 4; if(*str>='0' && *str<='9') v += (int)((unsigned char)(*str)-'0'); else if(*str >= 'A' && *str <= 'F') v += (int)((unsigned char)(*str)-'A'+10); str++; } return v; } #define PRINTFS(fsname,kernel) do {\ debug_write(fsname);\ debug_write(" ");\ debug_write(kernel);\ debug_write("\r\n");\ } while (0) #include "fs.h" uint32_t pxe_sip; uint32_t pxe_gip; void get_cached() { t_PXENV_GET_CACHED *t_cached = (void *)pxe_cmd_buf; t_cached->status = 0; t_cached->packet_type = 2; t_cached->buffer_size = 0; t_cached->buffer_offset = 0; t_cached->buffer_seg = 0; t_cached->buffer_limit = 0xFFFFu; debug_write("Performing PXE call\r\n"); unsigned ret = pxe_call(PXENV_GET_CACHED, (uint16_t)(uintptr_t)pxe_cmd_buf, 0x0000); debug_write("Still alive!\r\n"); debug_write("ret="); debug_write_uint(ret); debug_write("\r\nstatus="); debug_write_uint(t_cached->status); debug_write("\r\n"); debug_write("buffer_off="); debug_write_uint(t_cached->buffer_offset); debug_write("\r\nbuffer_seg="); debug_write_uint(t_cached->buffer_seg); struct bootph *bootph = (void *)(t_cached->buffer_offset + 16 * t_cached->buffer_seg); pxe_sip = bootph->sip; pxe_gip = bootph->gip; debug_write("\r\nsip="); debug_write_uint(pxe_sip); debug_write("\r\ngip="); debug_write_uint(pxe_gip); debug_write("\r\n"); } void receive_file(void) { unsigned ret; t_PXENV_TFTP_OPEN *t_open = (void *)pxe_cmd_buf; t_open->status = 0; t_open->server_ip = pxe_sip; t_open->gateway_ip = pxe_gip; memcpy(t_open->filename, "/initrd", 8); t_open->tftp_port = 69 << 8; t_open->packet_size = 512; debug_write("Performing PXE OPEN call\r\n"); ret = pxe_call(PXENV_TFTP_OPEN, (uint16_t)(uintptr_t)pxe_cmd_buf, 0x0000); debug_write("ret="); debug_write_uint(ret); debug_write(" status="); debug_write_uint(t_open->status); debug_write("\r\n"); uint16_t packet_size = t_open->packet_size; #if 0 for (;;) { t_PXENV_TFTP_READ *t_read = (void *)pxe_cmd_buf; t_read->status = 0; t_read->buffer_offset = ; t_read->buffer_seg = ; ret = pxe_call(PXENV_TFTP_READ, (uint16_t)(uintptr_t)pxe_cmd_buf, 0x0000); debug_write("ret="); debug_write_uint(ret); debug_write(" status="); debug_write_uint(t_read->status); debug_write("\r\n"); if (t_read->buffer_size < packet_size) { break; } } #endif } void main() { blank_screen(0x10); move_cursor(0, 0); //display_string(0x14, "Netboot via fernlader v2 ...\r\n"); debug_write("Going well ...\r\n"); if (memcmp(PXENV->signature, "PXENV+", 6) != 0) { debug_write("missing PXENV+ signature\r\n"); } if (PXENV->version >= 0x0201) { debug_write("!PXE version\r\n"); if (memcmp(exPXE->signature, "!PXE", 4) != 0) { debug_write("missing !PXE signature\r\n"); } pxe_entry = exPXE->rmentry; } memcpy(bootboot.magic, BOOTBOOT_MAGIC, sizeof bootboot.magic); bootboot.size = 128; bootboot.protocol = PROTOCOL_MINIMAL | LOADER_BIOS; bootboot.numcores = 1; //display_string(0x0E, "init\r\n"); struct e820_entry *end = bios_getmap(memmap); //display_string(0x0E, "karlos\r\n"); for (int i = 0; ; i++) { if (&memmap[i] >= end) break; char buf[2]; buf[0] = memmap[i].type < 10 ? memmap[i].type + '0' : '?'; buf[1] = 0; debug_write(buf); } pg_setup(); get_cached(); receive_file(); #if 0 #if 1 t_PXENV_GET_CACHED *t_cached = (void *)pxe_cmd_buf; t_cached->status = 0; t_cached->packet_type = 2; t_cached->buffer_size = 0; t_cached->buffer_offset = 0; t_cached->buffer_seg = 0; t_cached->buffer_limit = 0xFFFFu; debug_write("Performing PXE call\r\n"); unsigned ret = pxe_call(PXENV_GET_CACHED, (uint16_t)(uintptr_t)pxe_cmd_buf, 0x0000); debug_write("Still alive!\r\n"); debug_write("ret="); debug_write_uint(ret); debug_write("\r\nstatus="); debug_write_uint(t_cached->status); debug_write("\r\n"); #endif debug_write("buffer_off="); debug_write_uint(t_cached->buffer_offset); debug_write("\r\nbuffer_seg="); debug_write_uint(t_cached->buffer_seg); struct bootph *bootph = (void *)(t_cached->buffer_offset + 16 * t_cached->buffer_seg); uint32_t sip = bootph->sip; uint32_t gip = bootph->gip; debug_write("\r\nsip="); debug_write_uint(sip); debug_write("\r\ngip="); debug_write_uint(gip); debug_write("\r\n"); #if 1 t_PXENV_TFTP_OPEN *t_open = (void *)pxe_cmd_buf; t_open->status = 0; t_open->server_ip = sip; t_open->gateway_ip = gip; memcpy(t_open->filename, "/initrd", 8); t_open->tftp_port = 69 << 8; t_open->packet_size = 512; debug_write("Performing PXE OPEN call\r\n"); ret = pxe_call(PXENV_TFTP_OPEN, (uint16_t)(uintptr_t)pxe_cmd_buf, 0x0000); debug_write("Still alive!\r\n"); debug_write("ret="); debug_write_uint(ret); debug_write("\r\nstatus="); debug_write_uint(t_open->status); debug_write("\r\n"); #endif #if 0 uint32_t reg[7]; reg[0] = (0x0E << 8) + 'J'; reg[1] = 0; reg[2] = 0; reg[3] = 0; reg[4] = 0; reg[5] = 0; reg[6] = 0; bios_func(0x10, reg); debug_write("what?\r\n"); #endif #endif __asm__ ("cli"); for (;;) { //__asm__ ("sti"); //__asm__ ("hlt"); } }