From 5f1c34a58755d1d3c9ccf8a61d24dfd06d3fa407 Mon Sep 17 00:00:00 2001 From: mintsuki Date: Thu, 12 Aug 2021 07:40:29 +0200 Subject: [PATCH] tftp: Overhaul and bug fixes --- stage23/fs/file.s2.c | 8 +------ stage23/lib/config.c | 13 ++++++----- stage23/lib/pxe.asm | 52 ++++++++++++++++++++++++++----------------- stage23/lib/uri.c | 9 ++------ stage23/pxe/pxe.h | 2 +- stage23/pxe/tftp.h | 13 +++-------- stage23/pxe/tftp.s2.c | 52 +++++++++++++++++-------------------------- 7 files changed, 67 insertions(+), 82 deletions(-) diff --git a/stage23/fs/file.s2.c b/stage23/fs/file.s2.c index 2f42ab5b..74994402 100644 --- a/stage23/fs/file.s2.c +++ b/stage23/fs/file.s2.c @@ -28,16 +28,10 @@ int fopen(struct file_handle *ret, struct volume *part, const char *filename) { #if bios == 1 if (part->pxe) { - struct tftp_file_handle *fd = ext_mem_alloc(sizeof(struct tftp_file_handle)); - - int r = tftp_open(fd, 0, 69, filename); + int r = tftp_open(ret, 0, 69, filename); if (r) return r; - ret->fd = (void *)fd; - ret->read = (void *)tftp_read; - ret->size = fd->file_size; - return 0; } #endif diff --git a/stage23/lib/config.c b/stage23/lib/config.c index 640741fb..dc549373 100644 --- a/stage23/lib/config.c +++ b/stage23/lib/config.c @@ -35,14 +35,17 @@ int init_config_disk(struct volume *part) { #if bios == 1 int init_config_pxe(void) { - struct tftp_file_handle cfg; - if (tftp_open(&cfg, 0, 69, "limine.cfg")) { + struct file_handle f; + if (tftp_open(&f, 0, 69, "limine.cfg")) { return -1; } - config_addr = ext_mem_alloc(cfg.file_size); - tftp_read(&cfg, config_addr, 0, cfg.file_size); - return init_config(cfg.file_size); + size_t config_size = f.size + 1; + config_addr = ext_mem_alloc(config_size); + + fread(&f, config_addr, 0, f.size); + + return init_config(config_size); } #endif diff --git a/stage23/lib/pxe.asm b/stage23/lib/pxe.asm index 70b4545b..af47b141 100644 --- a/stage23/lib/pxe.asm +++ b/stage23/lib/pxe.asm @@ -9,17 +9,23 @@ set_pxe_fp: ret pxe_call: - ; Save GDT in case BIOS overwrites it + ; Save GDT in case BIOS overwrites it sgdt [.gdt] + ; Save IDT + sidt [.idt] + + ; Load BIOS IVT + lidt [.rm_idt] + ; Save non-scratch GPRs push ebx push esi push edi push ebp - mov ebx, eax - + lea ebp, [esp + 20] + ; Jump to real mode jmp 0x08:.bits16 .bits16: @@ -44,32 +50,36 @@ pxe_call: sti - push dx - push cx - push bx + push word [bp + 4] + push word [bp + 8] + push word [bp + 0] call far [.pxe_fp] add sp, 6 - mov bx, ax cli - ; Restore GDT - lgdt [ss:.gdt] + + ; Restore GDT + o32 lgdt [cs:.gdt] + + ; Restore IDT + o32 lidt [cs:.idt] ; Jump back to pmode - mov eax, cr0 - or al, 1 - mov cr0, eax + mov ebx, cr0 + or bl, 1 + mov cr0, ebx jmp 0x18:.bits32 .bits32: bits 32 - mov ax, 0x20 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax + mov bx, 0x20 + mov ds, bx + mov es, bx + mov fs, bx + mov gs, bx + mov ss, bx + + and eax, 0xffff - mov eax, ebx ; Restore non-scratch GPRs pop ebp pop edi @@ -81,5 +91,7 @@ pxe_call: align 16 .pxe_fp: dd 0 - .esp: dd 0 .gdt: dq 0 + .idt: dq 0 + .rm_idt: dw 0x3ff + dd 0 diff --git a/stage23/lib/uri.c b/stage23/lib/uri.c index 4c6d0f53..c7eb1519 100644 --- a/stage23/lib/uri.c +++ b/stage23/lib/uri.c @@ -148,19 +148,14 @@ static bool uri_tftp_dispatch(struct file_handle *fd, char *root, char *path) { ip = 0; } else { if (inet_pton(root, &ip)) { - panic("invalid ipv4 address: %s", root); + panic("tftp: Invalid ipv4 address: %s", root); } } - struct tftp_file_handle *cfg = ext_mem_alloc(sizeof(struct tftp_file_handle)); - if(tftp_open(cfg, ip, 69, path)) { + if (tftp_open(fd, ip, 69, path)) { return false; } - fd->is_memfile = false; - fd->fd = cfg; - fd->read = tftp_read; - fd->size = cfg->file_size; return true; } #endif diff --git a/stage23/pxe/pxe.h b/stage23/pxe/pxe.h index 84c86510..db148d2c 100644 --- a/stage23/pxe/pxe.h +++ b/stage23/pxe/pxe.h @@ -6,7 +6,7 @@ struct volume *pxe_bind_volume(void); void pxe_init(void); -int pxe_call(uint16_t opcode, uint16_t buf_seg, uint16_t buf_off) __attribute__((regparm(3))); +int pxe_call(uint16_t opcode, uint16_t buf_seg, uint16_t buf_off); #define MAC_ADDR_LEN 16 typedef uint8_t MAC_ADDR_t[MAC_ADDR_LEN]; diff --git a/stage23/pxe/tftp.h b/stage23/pxe/tftp.h index 08d9cc26..60febf66 100644 --- a/stage23/pxe/tftp.h +++ b/stage23/pxe/tftp.h @@ -3,17 +3,10 @@ #include #include +#include #define UNDI_GET_INFORMATION 0xC -struct tftp_file_handle { - uint32_t server_ip; - uint16_t server_port; - uint16_t packet_size; - size_t file_size; - void *data; -}; - #define TFTP_OPEN 0x0020 struct pxenv_open { uint16_t status; @@ -45,8 +38,8 @@ struct pxenv_get_file_size { #define TFTP_CLOSE 0x21 //server_ip and server_port can be 0 for default -int tftp_open(struct tftp_file_handle* handle, uint32_t server_ip, uint16_t server_port, const char* name); -int tftp_read(void *fd, void *buf, uint64_t loc, uint64_t count); +int tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_port, const char *name); + uint32_t get_boot_server_info(void); #endif diff --git a/stage23/pxe/tftp.s2.c b/stage23/pxe/tftp.s2.c index 6a2c705f..510b4e5a 100644 --- a/stage23/pxe/tftp.s2.c +++ b/stage23/pxe/tftp.s2.c @@ -16,14 +16,11 @@ uint32_t get_boot_server_info(void) { return ph->sip; } -int tftp_open(struct tftp_file_handle *handle, uint32_t server_ip, uint16_t server_port, const char *name) { +int tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_port, const char *name) { int ret = 0; + if (!server_ip) { - struct pxenv_get_cached_info cachedinfo = { 0 }; - cachedinfo.packet_type = 2; - pxe_call(PXENV_GET_CACHED_INFO, ((uint16_t)rm_seg(&cachedinfo)), (uint16_t)rm_off(&cachedinfo)); - struct bootph *ph = (struct bootph*)(void *) (((((uint32_t)cachedinfo.buffer) >> 16) << 4) + (((uint32_t)cachedinfo.buffer) & 0xFFFF)); - server_ip = ph->sip; + server_ip = get_boot_server_info(); } struct PXENV_UNDI_GET_INFORMATION undi_info = { 0 }; @@ -35,10 +32,6 @@ int tftp_open(struct tftp_file_handle *handle, uint32_t server_ip, uint16_t serv //TODO figure out a more proper way to do this. uint16_t mtu = undi_info.MaxTranUnit - 48; - handle->server_ip = server_ip; - handle->server_port = server_port; - handle->packet_size = mtu; - struct pxenv_get_file_size fsize = { .status = 0, .sip = server_ip, @@ -49,63 +42,58 @@ int tftp_open(struct tftp_file_handle *handle, uint32_t server_ip, uint16_t serv return -1; } - handle->file_size = fsize.file_size; + handle->size = fsize.file_size; + handle->is_memfile = true; - volatile struct pxenv_open open = { + struct pxenv_open open = { .status = 0, .sip = server_ip, .port = (server_port) << 8, .packet_size = mtu }; strcpy((char*)open.name, name); + ret = pxe_call(TFTP_OPEN, ((uint16_t)rm_seg(&open)), (uint16_t)rm_off(&open)); if (ret) { print("tftp: Failed to open file %x or bad packet size", open.status); return -1; } + mtu = open.packet_size; uint8_t *buf = conv_mem_alloc(mtu); - handle->data = ext_mem_alloc(handle->file_size); - memset(handle->data, 0, handle->file_size); - size_t to_transfer = handle->file_size; - size_t progress = 0; + handle->fd = ext_mem_alloc(handle->size); + size_t progress = 0; bool slow = false; - while (to_transfer > 0) { - volatile struct pxenv_read read = { + while (progress < handle->size) { + struct pxenv_read read = { .boff = ((uint16_t)rm_off(buf)), .bseg = ((uint16_t)rm_seg(buf)), }; + ret = pxe_call(TFTP_READ, ((uint16_t)rm_seg(&read)), (uint16_t)rm_off(&read)); if (ret) { - panic("failed reading"); + panic("tftp: Read failure"); } - memcpy(handle->data + progress, buf, read.bsize); - if (read.bsize < mtu && !slow) { + memcpy(handle->fd + progress, buf, read.bsize); + + progress += read.bsize; + + if (read.bsize < mtu && !slow && progress < handle->size) { slow = true; print("tftp: Server is sending the file in smaller packets (it sent %d bytes), download might take longer.\n", read.bsize); } - to_transfer -= read.bsize; - progress += read.bsize; } uint16_t close = 0; ret = pxe_call(TFTP_CLOSE, ((uint16_t)rm_seg(&close)), (uint16_t)rm_off(&close)); if (ret) { - panic("close failed"); + panic("tftp: Close failure"); } - return 0; -} -int tftp_read(void* fd, void *buf, uint64_t loc, uint64_t count) { - struct tftp_file_handle *handle = (struct tftp_file_handle*)fd; - if ((loc + count) > handle->file_size) { - return -1; - } - memcpy(buf, handle->data + loc, count); return 0; }