Add pxe support
This commit is contained in:
parent
10bd26962a
commit
e7ae195304
|
@ -10,3 +10,4 @@
|
||||||
.vscode
|
.vscode
|
||||||
/limine-install
|
/limine-install
|
||||||
!/limine.bin
|
!/limine.bin
|
||||||
|
!/limine-pxe.bin
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -7,6 +7,7 @@ PATH := $(shell pwd)/toolchain/bin:$(PATH)
|
||||||
all: stage2 decompressor
|
all: stage2 decompressor
|
||||||
gzip -n -9 < stage2/stage2.bin > stage2/stage2.bin.gz
|
gzip -n -9 < stage2/stage2.bin > stage2/stage2.bin.gz
|
||||||
cd bootsect && nasm bootsect.asm -fbin -o ../limine.bin
|
cd bootsect && nasm bootsect.asm -fbin -o ../limine.bin
|
||||||
|
cd pxeboot && nasm bootsect.asm -fbin -o ../limine-pxe.bin
|
||||||
|
|
||||||
clean: stage2-clean decompressor-clean test-clean
|
clean: stage2-clean decompressor-clean test-clean
|
||||||
rm -f stage2/stage2.bin.gz
|
rm -f stage2/stage2.bin.gz
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
#include <gzip/tinf.h>
|
#include <gzip/tinf.h>
|
||||||
|
|
||||||
__attribute__((noreturn))
|
__attribute__((noreturn))
|
||||||
void entry(uint8_t *compressed_stage2, size_t stage2_size, uint8_t boot_drive) {
|
void entry(uint8_t *compressed_stage2, size_t stage2_size, uint8_t boot_drive, int pxe) {
|
||||||
// The decompressor should decompress compressed_stage2 to address 0x8000.
|
// The decompressor should decompress compressed_stage2 to address 0x8000.
|
||||||
uint8_t *dest = (uint8_t *)0x8000;
|
uint8_t *dest = (uint8_t *)0x8000;
|
||||||
|
|
||||||
tinf_gzip_uncompress(dest, compressed_stage2, stage2_size);
|
tinf_gzip_uncompress(dest, compressed_stage2, stage2_size);
|
||||||
|
|
||||||
__attribute__((noreturn))
|
__attribute__((noreturn))
|
||||||
void (*stage2)(uint8_t boot_drive) = (void *)dest;
|
void (*stage2)(uint8_t boot_drive, int pxe) = (void *)dest;
|
||||||
|
|
||||||
stage2(boot_drive);
|
stage2(boot_drive, pxe);
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
BIN
limine.bin
BIN
limine.bin
Binary file not shown.
|
@ -0,0 +1,64 @@
|
||||||
|
org 0x7c00
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
start:
|
||||||
|
jmp 0x0000:.initialise_cs
|
||||||
|
.initialise_cs:
|
||||||
|
xor ax, ax
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov ss, ax
|
||||||
|
mov sp, 0x7c00
|
||||||
|
sti
|
||||||
|
call load_gdt
|
||||||
|
|
||||||
|
cli
|
||||||
|
|
||||||
|
mov eax, cr0
|
||||||
|
bts ax, 0
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
jmp 0x18:.mode32
|
||||||
|
bits 32
|
||||||
|
.mode32:
|
||||||
|
mov ax, 0x20
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
mov ss, ax
|
||||||
|
|
||||||
|
push 0x1
|
||||||
|
and edx, 0xff
|
||||||
|
push edx
|
||||||
|
|
||||||
|
push stage2.size
|
||||||
|
push (stage2 - decompressor) + 0x70000
|
||||||
|
|
||||||
|
mov esi, decompressor
|
||||||
|
mov edi, 0x70000
|
||||||
|
mov ecx, stage2.fullsize
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
call 0x70000
|
||||||
|
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
err:
|
||||||
|
hlt
|
||||||
|
jmp err
|
||||||
|
|
||||||
|
; Includes
|
||||||
|
|
||||||
|
%include '../bootsect/gdt.inc'
|
||||||
|
|
||||||
|
; ********************* Stage 2 *********************
|
||||||
|
|
||||||
|
decompressor:
|
||||||
|
incbin '../decompressor/decompressor.bin'
|
||||||
|
|
||||||
|
align 16
|
||||||
|
stage2:
|
||||||
|
incbin '../stage2/stage2.bin.gz'
|
||||||
|
.size: equ $ - stage2
|
||||||
|
.fullsize: equ $ - decompressor
|
|
@ -5,6 +5,8 @@
|
||||||
#include <lib/blib.h>
|
#include <lib/blib.h>
|
||||||
#include <mm/pmm.h>
|
#include <mm/pmm.h>
|
||||||
#include <fs/file.h>
|
#include <fs/file.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
#include <pxe/tftp.h>
|
||||||
|
|
||||||
#define SEPARATOR '\n'
|
#define SEPARATOR '\n'
|
||||||
|
|
||||||
|
@ -12,7 +14,7 @@ bool config_ready = false;
|
||||||
|
|
||||||
static char *config_addr;
|
static char *config_addr;
|
||||||
|
|
||||||
int init_config(struct part *part) {
|
int init_config_disk(struct part *part) {
|
||||||
struct file_handle f;
|
struct file_handle f;
|
||||||
|
|
||||||
if (fopen(&f, part, "/limine.cfg")) {
|
if (fopen(&f, part, "/limine.cfg")) {
|
||||||
|
@ -26,6 +28,23 @@ int init_config(struct part *part) {
|
||||||
|
|
||||||
fread(&f, config_addr, 0, f.size);
|
fread(&f, config_addr, 0, f.size);
|
||||||
|
|
||||||
|
return init_config(config_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_config_pxe(void) {
|
||||||
|
struct tftp_file_handle cfg;
|
||||||
|
if (tftp_open(&cfg, 0, 69, "limine.cfg")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
config_addr = conv_mem_alloc(cfg.file_size);
|
||||||
|
tftp_read(&cfg, config_addr, 0, cfg.file_size);
|
||||||
|
|
||||||
|
print("\nconfig: %s\n", config_addr);
|
||||||
|
|
||||||
|
return init_config(cfg.file_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_config(size_t config_size) {
|
||||||
// remove windows carriage returns, if any
|
// remove windows carriage returns, if any
|
||||||
for (size_t i = 0; i < config_size; i++) {
|
for (size_t i = 0; i < config_size; i++) {
|
||||||
if (config_addr[i] == '\r') {
|
if (config_addr[i] == '\r') {
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
|
|
||||||
extern bool config_ready;
|
extern bool config_ready;
|
||||||
|
|
||||||
int init_config(struct part *part);
|
int init_config_disk(struct part *part);
|
||||||
|
int init_config_pxe(void);
|
||||||
|
int init_config(size_t config_size);
|
||||||
int config_get_entry_name(char *ret, size_t index, size_t limit);
|
int config_get_entry_name(char *ret, size_t index, size_t limit);
|
||||||
int config_set_entry(size_t index);
|
int config_set_entry(size_t index);
|
||||||
char *config_get_value(char *buf, size_t index, size_t limit, const char *key);
|
char *config_get_value(char *buf, size_t index, size_t limit, const char *key);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <lib/libc.h>
|
#include <lib/libc.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <lib/blib.h>
|
||||||
|
|
||||||
int toupper(int c) {
|
int toupper(int c) {
|
||||||
if (c >= 'a' && c <= 'z') {
|
if (c >= 'a' && c <= 'z') {
|
||||||
|
@ -67,3 +70,24 @@ size_t strlen(const char *str) {
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int inet_pton(const char *src, void *dst) {
|
||||||
|
uint8_t array[4] = {};
|
||||||
|
const char *current = src;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
long int value = strtoui(current, 0, 10);
|
||||||
|
if (value > 255)
|
||||||
|
return -1;
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
if (*current != '\0' && *current != '.')
|
||||||
|
current++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current++;
|
||||||
|
array[i] = value;
|
||||||
|
}
|
||||||
|
memcpy(dst, array, 4);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -16,5 +16,6 @@ char *strncpy(char *, const char *, size_t);
|
||||||
size_t strlen(const char *);
|
size_t strlen(const char *);
|
||||||
int strcmp(const char *, const char *);
|
int strcmp(const char *, const char *);
|
||||||
int strncmp(const char *, const char *, size_t);
|
int strncmp(const char *, const char *, size_t);
|
||||||
|
int inet_pton(const char *src, void *dst);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
section .realmode
|
||||||
|
|
||||||
|
global pxe_call
|
||||||
|
global set_pxe_fp
|
||||||
|
|
||||||
|
set_pxe_fp:
|
||||||
|
mov eax, [esp + 4]
|
||||||
|
mov [pxe_call.pxe_fp], eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
pxe_call:
|
||||||
|
; Save GDT in case BIOS overwrites it
|
||||||
|
sgdt [.gdt]
|
||||||
|
|
||||||
|
; Save non-scratch GPRs
|
||||||
|
push ebx
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
push ebp
|
||||||
|
|
||||||
|
mov ebx, eax
|
||||||
|
|
||||||
|
; Jump to real mode
|
||||||
|
jmp 0x08:.bits16
|
||||||
|
.bits16:
|
||||||
|
bits 16
|
||||||
|
mov ax, 0x10
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
mov ss, ax
|
||||||
|
mov eax, cr0
|
||||||
|
and al, 0xfe
|
||||||
|
mov cr0, eax
|
||||||
|
jmp 0x00:.cszero
|
||||||
|
.cszero:
|
||||||
|
xor ax, ax
|
||||||
|
mov ss, ax
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
|
||||||
|
sti
|
||||||
|
|
||||||
|
push dx
|
||||||
|
push cx
|
||||||
|
push bx
|
||||||
|
call far [.pxe_fp]
|
||||||
|
add sp, 6
|
||||||
|
mov bx, ax
|
||||||
|
|
||||||
|
cli
|
||||||
|
; Restore GDT
|
||||||
|
lgdt [ss:.gdt]
|
||||||
|
|
||||||
|
; Jump back to pmode
|
||||||
|
mov eax, cr0
|
||||||
|
or al, 1
|
||||||
|
mov cr0, eax
|
||||||
|
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 eax, ebx
|
||||||
|
; Restore non-scratch GPRs
|
||||||
|
pop ebp
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop ebx
|
||||||
|
|
||||||
|
; Exit
|
||||||
|
ret
|
||||||
|
|
||||||
|
align 16
|
||||||
|
.pxe_fp: dd 0
|
||||||
|
.esp: dd 0
|
||||||
|
.gdt: dq 0
|
|
@ -5,6 +5,9 @@
|
||||||
#include <lib/part.h>
|
#include <lib/part.h>
|
||||||
#include <lib/libc.h>
|
#include <lib/libc.h>
|
||||||
#include <fs/file.h>
|
#include <fs/file.h>
|
||||||
|
#include <mm/pmm.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
#include <pxe/tftp.h>
|
||||||
|
|
||||||
// A URI takes the form of: resource://root/path
|
// A URI takes the form of: resource://root/path
|
||||||
// The following function splits up a URI into its componenets
|
// The following function splits up a URI into its componenets
|
||||||
|
@ -109,6 +112,28 @@ static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool uri_tftp_dispatch(struct file_handle *fd, char *root, char *path) {
|
||||||
|
uint32_t ip;
|
||||||
|
if (!strcmp(root, "")) {
|
||||||
|
ip = 0;
|
||||||
|
} else {
|
||||||
|
if (inet_pton(root, &ip)) {
|
||||||
|
panic("invalid ipv4 address: %s", root);
|
||||||
|
}
|
||||||
|
print("\nip: %x\n", ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tftp_file_handle *cfg = conv_mem_alloc(sizeof(struct tftp_file_handle));
|
||||||
|
if(tftp_open(cfg, ip, 69, path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd->fd = cfg;
|
||||||
|
fd->read = tftp_read;
|
||||||
|
fd->size = cfg->file_size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool uri_open(struct file_handle *fd, char *uri) {
|
bool uri_open(struct file_handle *fd, char *uri) {
|
||||||
char *resource, *root, *path;
|
char *resource, *root, *path;
|
||||||
uri_resolve(uri, &resource, &root, &path);
|
uri_resolve(uri, &resource, &root, &path);
|
||||||
|
@ -117,6 +142,8 @@ bool uri_open(struct file_handle *fd, char *uri) {
|
||||||
return uri_bios_dispatch(fd, root, path);
|
return uri_bios_dispatch(fd, root, path);
|
||||||
} else if (!strcmp(resource, "guid")) {
|
} else if (!strcmp(resource, "guid")) {
|
||||||
return uri_guid_dispatch(fd, root, path);
|
return uri_guid_dispatch(fd, root, path);
|
||||||
|
} else if (!strcmp(resource, "tftp")) {
|
||||||
|
return uri_tftp_dispatch(fd, root, path);
|
||||||
} else {
|
} else {
|
||||||
panic("Resource `%s` not valid.", resource);
|
panic("Resource `%s` not valid.", resource);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
#include <protos/linux.h>
|
#include <protos/linux.h>
|
||||||
#include <protos/chainload.h>
|
#include <protos/chainload.h>
|
||||||
#include <menu.h>
|
#include <menu.h>
|
||||||
|
#include <pxe/pxe.h>
|
||||||
|
#include <pxe/tftp.h>
|
||||||
|
|
||||||
void entry(uint8_t _boot_drive) {
|
void entry(uint8_t _boot_drive, int pxe_boot) {
|
||||||
boot_drive = _boot_drive;
|
boot_drive = _boot_drive;
|
||||||
|
|
||||||
mtrr_save();
|
mtrr_save();
|
||||||
|
@ -30,32 +32,39 @@ void entry(uint8_t _boot_drive) {
|
||||||
if (!a20_enable())
|
if (!a20_enable())
|
||||||
panic("Could not enable A20 line");
|
panic("Could not enable A20 line");
|
||||||
|
|
||||||
print("Boot drive: %x\n", boot_drive);
|
|
||||||
|
|
||||||
part_create_index();
|
part_create_index();
|
||||||
|
init_e820();
|
||||||
// Look for config file.
|
init_memmap();
|
||||||
print("Searching for config file...\n");
|
|
||||||
struct part parts[4];
|
if (pxe_boot) {
|
||||||
for (int i = 0; ; i++) {
|
pxe_init();
|
||||||
if (i == 4) {
|
if(init_config_pxe()) {
|
||||||
panic("Config file not found.");
|
panic("failed to load config file");
|
||||||
}
|
}
|
||||||
print("Checking partition %d...\n", i);
|
print("config loaded");
|
||||||
int ret = part_get(&parts[i], boot_drive, i);
|
} else {
|
||||||
if (ret) {
|
print("Boot drive: %x\n", boot_drive);
|
||||||
print("Partition not found.\n");
|
// Look for config file.
|
||||||
} else {
|
print("Searching for config file...\n");
|
||||||
print("Partition found.\n");
|
struct part parts[4];
|
||||||
if (!init_config(&parts[i])) {
|
for (int i = 0; ; i++) {
|
||||||
print("Config file found and loaded.\n");
|
if (i == 4) {
|
||||||
break;
|
panic("Config file not found.");
|
||||||
|
}
|
||||||
|
print("Checking partition %d...\n", i);
|
||||||
|
int ret = part_get(&parts[i], boot_drive, i);
|
||||||
|
if (ret) {
|
||||||
|
print("Partition not found.\n");
|
||||||
|
} else {
|
||||||
|
print("Partition found.\n");
|
||||||
|
if (!init_config_disk(&parts[i])) {
|
||||||
|
print("Config file found and loaded.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init_e820();
|
|
||||||
init_memmap();
|
|
||||||
|
|
||||||
char *cmdline = menu();
|
char *cmdline = menu();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include <lib/print.h>
|
||||||
|
#include <lib/real.h>
|
||||||
|
#include <pxe/pxe.h>
|
||||||
|
#include <lib/libc.h>
|
||||||
|
#include <lib/blib.h>
|
||||||
|
|
||||||
|
void set_pxe_fp(uint32_t fp);
|
||||||
|
|
||||||
|
void pxe_init(void) {
|
||||||
|
//pxe installation check
|
||||||
|
struct rm_regs r = { 0 };
|
||||||
|
r.ebx = 0;
|
||||||
|
r.ecx = 0;
|
||||||
|
r.eax = 0x5650;
|
||||||
|
r.es = 0;
|
||||||
|
|
||||||
|
rm_int(0x1a, &r, &r);
|
||||||
|
if ((r.eax & 0xffff) != 0x564e) {
|
||||||
|
panic("PXE installation check failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pxenv* pxenv = { 0 };
|
||||||
|
|
||||||
|
pxenv = (struct pxenv*)((r.es << 4) + (r.ebx & 0xffff));
|
||||||
|
if (memcmp(pxenv->signature, PXE_SIGNATURE, sizeof(pxenv->signature)) != 0) {
|
||||||
|
panic("PXENV structure signature corrupted");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pxenv->version < 0x201) {
|
||||||
|
//we won't support pxe < 2.1, grub does this too and it seems to work fine
|
||||||
|
panic("\npxe version too old");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bangpxe* bangpxe = (struct bangpxe*)((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4) + (pxenv->pxe_ptr & 0xffff));
|
||||||
|
|
||||||
|
if (memcmp(bangpxe->signature, PXE_BANGPXE_SIGNATURE,
|
||||||
|
sizeof(bangpxe->signature))
|
||||||
|
!= 0) {
|
||||||
|
panic("!pxe signature corrupted");
|
||||||
|
}
|
||||||
|
set_pxe_fp(bangpxe->rm_entry);
|
||||||
|
print("Successfully initialized pxe");
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
#ifndef PXE_H
|
||||||
|
#define PXE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void pxe_init(void);
|
||||||
|
int pxe_call(uint16_t opcode, uint16_t buf_seg, uint16_t buf_off) __attribute__((regparm(3)));
|
||||||
|
|
||||||
|
#define MAC_ADDR_LEN 16
|
||||||
|
typedef uint8_t MAC_ADDR_t[MAC_ADDR_LEN];
|
||||||
|
|
||||||
|
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;
|
||||||
|
MAC_ADDR_t CAddr;
|
||||||
|
uint8_t Sname[64];
|
||||||
|
uint8_t bootfile[128];
|
||||||
|
union bootph_vendor {
|
||||||
|
uint8_t d[1024];
|
||||||
|
struct bootph_vendor_v {
|
||||||
|
uint8_t magic[4];
|
||||||
|
uint32_t flags;
|
||||||
|
uint8_t pad[56];
|
||||||
|
} v;
|
||||||
|
} vendor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PXENV_UNDI_GET_INFORMATION {
|
||||||
|
uint16_t Status;
|
||||||
|
uint16_t BaseIo;
|
||||||
|
uint16_t IntNumber;
|
||||||
|
uint16_t MaxTranUnit;
|
||||||
|
uint16_t HwType;
|
||||||
|
uint16_t HwAddrLen;
|
||||||
|
uint8_t CurrentNodeAddress[16];
|
||||||
|
uint8_t PermNodeAddress[16];
|
||||||
|
uint16_t ROMAddress;
|
||||||
|
uint16_t RxBufCt;
|
||||||
|
uint16_t TxBufCt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PXE_SIGNATURE "PXENV+"
|
||||||
|
struct pxenv {
|
||||||
|
uint8_t signature[6];
|
||||||
|
uint16_t version;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t checksum;
|
||||||
|
uint32_t rm_entry;
|
||||||
|
uint32_t pm_offset;
|
||||||
|
uint16_t pm_selector;
|
||||||
|
uint16_t stack_seg;
|
||||||
|
uint16_t stack_size;
|
||||||
|
uint16_t bc_code_seg;
|
||||||
|
uint16_t bc_code_size;
|
||||||
|
uint16_t bc_data_seg;
|
||||||
|
uint16_t bc_data_size;
|
||||||
|
uint16_t undi_data_seg;
|
||||||
|
uint16_t undi_data_size;
|
||||||
|
uint16_t undi_code_seg;
|
||||||
|
uint16_t undi_code_size;
|
||||||
|
uint32_t pxe_ptr;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define PXE_BANGPXE_SIGNATURE "!PXE"
|
||||||
|
struct bangpxe {
|
||||||
|
uint8_t signature[4];
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t chksum;
|
||||||
|
uint8_t rev;
|
||||||
|
uint8_t reserved;
|
||||||
|
uint32_t undiromid;
|
||||||
|
uint32_t baseromid;
|
||||||
|
uint32_t rm_entry;
|
||||||
|
uint32_t pm_entry;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define PXENV_GET_CACHED_INFO 0x0071
|
||||||
|
struct pxenv_get_cached_info {
|
||||||
|
uint16_t status;
|
||||||
|
uint16_t packet_type;
|
||||||
|
uint16_t buffer_size;
|
||||||
|
uint32_t buffer;
|
||||||
|
uint16_t buffer_limit;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include <pxe/tftp.h>
|
||||||
|
#include <pxe/pxe.h>
|
||||||
|
#include <lib/real.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
#include <lib/libc.h>
|
||||||
|
#include <mm/pmm.h>
|
||||||
|
#include <lib/blib.h>
|
||||||
|
|
||||||
|
int tftp_open(struct tftp_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PXENV_UNDI_GET_INFORMATION undi_info = { 0 };
|
||||||
|
ret = pxe_call(UNDI_GET_INFORMATION, ((uint16_t)rm_seg(&undi_info)), (uint16_t)rm_off(&undi_info));
|
||||||
|
if (ret) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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,
|
||||||
|
};
|
||||||
|
strcpy((char*)fsize.name, name);
|
||||||
|
ret = pxe_call(TFTP_GET_FILE_SIZE, ((uint16_t)rm_seg(&fsize)), (uint16_t)rm_off(&fsize));
|
||||||
|
if (ret) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle->file_size = fsize.file_size;
|
||||||
|
|
||||||
|
volatile 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("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;
|
||||||
|
|
||||||
|
while (to_transfer > 0) {
|
||||||
|
volatile 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");
|
||||||
|
}
|
||||||
|
memcpy(handle->data + progress, buf, read.bsize);
|
||||||
|
|
||||||
|
if (read.bsize < mtu) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef TFTP_H
|
||||||
|
#define TFTP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.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;
|
||||||
|
uint32_t sip;
|
||||||
|
uint32_t gip;
|
||||||
|
uint8_t name[128];
|
||||||
|
uint16_t port;
|
||||||
|
uint16_t packet_size;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define TFTP_READ 0x22
|
||||||
|
struct pxenv_read {
|
||||||
|
uint16_t status;
|
||||||
|
uint16_t pn;
|
||||||
|
uint16_t bsize;
|
||||||
|
uint16_t boff;
|
||||||
|
uint16_t bseg;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define TFTP_GET_FILE_SIZE 0x25
|
||||||
|
struct pxenv_get_file_size {
|
||||||
|
uint16_t status;
|
||||||
|
uint32_t sip;
|
||||||
|
uint32_t gip;
|
||||||
|
uint8_t name[128];
|
||||||
|
uint32_t file_size;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue