tftp: Overhaul and bug fixes
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 <stdint.h>
#include <stddef.h>
+#include <fs/file.h>
#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;
}
