From b047e34dcb213b3f553a95c4df0c831b36de14e4 Mon Sep 17 00:00:00 2001 From: Thomas Oltmann Date: Thu, 21 May 2026 14:44:16 +0200 Subject: [PATCH] Drop down to real mode for PXE call --- src/main.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/nbp.S | 9 ++++++ src/pxe.S | 29 +++++++++++++++--- src/std.h | 2 ++ 4 files changed, 117 insertions(+), 11 deletions(-) diff --git a/src/main.c b/src/main.c index 5663678..3cc70a0 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,15 @@ outb(uint16_t port, uint8_t data) 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 @@ -93,6 +102,20 @@ display_string(uint16_t attr, const char *str) 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 @@ -136,27 +159,51 @@ struct exPXE { uint32_t pmentry; }; -//extern uint32_t pxe_call(uint16_t func, offset, segment); +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 + +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; + void main() { blank_screen(0x10); move_cursor(0, 0); //display_string(0x14, "Netboot via fernlader v2 ...\r\n"); - bios_write("Going well ...\r\n"); + debug_write("Going well ...\r\n"); if (memcmp(PXENV->signature, "PXENV+", 6) != 0) { - bios_write("missing PXENV+ signature\r\n"); + debug_write("missing PXENV+ signature\r\n"); } if (PXENV->version >= 0x0201) { - bios_write("!PXE version\r\n"); + debug_write("!PXE version\r\n"); if (memcmp(exPXE->signature, "!PXE", 4) != 0) { - bios_write("missing !PXE signature\r\n"); + debug_write("missing !PXE signature\r\n"); } + pxe_entry = exPXE->rmentry; } memcpy(bootboot.magic, BOOTBOOT_MAGIC, sizeof bootboot.magic); @@ -172,11 +219,38 @@ main() char buf[2]; buf[0] = memmap[i].type < 10 ? memmap[i].type + '0' : '?'; buf[1] = 0; - bios_write(buf); + debug_write(buf); } pg_setup(); +#if 0 + t_PXENV_TFTP_OPEN *t_open = (void *)pxe_cmd_buf; + t_open->status = 0; + t_open->server_ip = 0x0100000Au; + t_open->gateway_ip = 0; + memcpy(t_open->filename, "/initrd", 8); + t_open->tftp_port = 69 << 8; + t_open->packet_size = 512; +#endif + +#if 1 + t_PXENV_GET_CACHED *t_get = (void *)pxe_cmd_buf; + t_get->status = 0; + t_get->packet_type = 2; + t_get->buffer_size = 0; + t_get->buffer_offset = 0; + t_get->buffer_seg = 0; + t_get->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_get->status); +#endif + #if 0 uint32_t reg[7]; reg[0] = (0x0E << 8) + 'J'; @@ -188,7 +262,7 @@ main() reg[6] = 0; bios_func(0x10, reg); - bios_write("what?\r\n"); + debug_write("what?\r\n"); #endif for (;;) { diff --git a/src/nbp.S b/src/nbp.S index 4e9ed61..52580a6 100644 --- a/src/nbp.S +++ b/src/nbp.S @@ -13,6 +13,9 @@ _start: cli mov %ss, %ax mov %ax, %cs:real_ss + mov %es, %ax + mov %ax, %cs:real_es + xor %eax, %eax mov %es, %ax shl $4, %eax @@ -71,6 +74,12 @@ exPXE: .long 0 .global real_ss real_ss: .word 0 + .global real_es +real_es: .word 0 + + .global pxe_cmd_buf +pxe_cmd_buf:.space 512, 0 + .global GDT GDT: // entry 0: null descriptor .space 8, 0 diff --git a/src/pxe.S b/src/pxe.S index 99b53db..f35b34e 100644 --- a/src/pxe.S +++ b/src/pxe.S @@ -4,21 +4,42 @@ .data -pxe_entry: .word 0 + .global pxe_entry +pxe_entry: .long 0 +pxe_retval: .word 0 .text .global pxe_call .code32 pxe_call: push %ebp mov %esp, %ebp + push %ebx + + mov 0x08(%ebp), %ebx # op + mov 0x0C(%ebp), %ecx # off + mov 0x10(%ebp), %edx # seg PROT16 + REAL - call (pxe_entry) - push %eax + mov %cs:(real_es), %ax + mov %ax, %es + push %dx + push %cx + push %bx + + lcall *(pxe_entry) + mov %ax, pxe_retval + + add $6, %sp + + PROT PROT32 - pop %eax + mov pxe_retval, %ax + movzwl %ax, %eax + + pop %ebx leave ret diff --git a/src/std.h b/src/std.h index e34f6ff..552efb6 100644 --- a/src/std.h +++ b/src/std.h @@ -24,6 +24,8 @@ typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; +typedef unsigned int uintptr_t; + // stdbool.h #define true ((_Bool)1)