tftp: Overhaul and bug fixes

This commit is contained in:
mintsuki 2021-08-12 07:40:29 +02:00
parent 294382e3bf
commit 5f1c34a587
7 changed files with 67 additions and 82 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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;
}