commit
41d4b3af54
|
@ -124,7 +124,7 @@ make install # (or gmake where applicable)
|
|||
## How to use
|
||||
|
||||
### UEFI
|
||||
The `BOOT{IA32,X64,AA64}.EFI` files are vaild EFI applications that can be simply copied to
|
||||
The `BOOT{IA32,X64,AA64}.EFI` files are valid EFI applications that can be simply copied to
|
||||
the `/EFI/BOOT` directory of a FAT formatted EFI system partition. These files can
|
||||
be installed there and coexist with a BIOS installation of Limine (see below) so
|
||||
that the disk will be bootable on both BIOS and UEFI systems.
|
||||
|
@ -211,6 +211,11 @@ server or your existing DHCP server and a proxy DHCP server such as dnsmasq.
|
|||
|
||||
`limine.cfg` and `limine.sys` are expected to be on the server used for boot.
|
||||
|
||||
### UEFI/PXE boot
|
||||
The `BOOT{IA32,X64,AA64}.EFI` files are compatible with UEFI PXE.
|
||||
The steps needed to boot Limine are the same as with BIOS PXE,
|
||||
except that you don't need `limine.sys` in the server.
|
||||
|
||||
### Configuration
|
||||
The `limine.cfg` file contains Limine's configuration.
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <lib/rand.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <pxe/pxe.h>
|
||||
|
||||
#define DEFAULT_FASTEST_XFER_SIZE 64
|
||||
#define MAX_FASTEST_XFER_SIZE 512
|
||||
|
@ -313,6 +314,38 @@ int disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t c
|
|||
}
|
||||
}
|
||||
|
||||
static struct volume *pxe_from_efi_handle(EFI_HANDLE efi_handle) {
|
||||
static struct volume *vol = NULL;
|
||||
|
||||
// There's only one PXE volume
|
||||
if (vol) {
|
||||
return vol;
|
||||
}
|
||||
|
||||
EFI_STATUS status;
|
||||
|
||||
EFI_GUID pxe_base_code_guid = EFI_PXE_BASE_CODE_PROTOCOL_GUID;
|
||||
EFI_PXE_BASE_CODE *pxe_base_code = NULL;
|
||||
|
||||
status = gBS->HandleProtocol(efi_handle, &pxe_base_code_guid, (void **)&pxe_base_code);
|
||||
if (status) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pxe_base_code->Mode->DhcpDiscoverValid) {
|
||||
print("PXE somehow didn't use DHCP?\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pxe_base_code->Mode->UsingIpv6) {
|
||||
print("Sorry, unsupported: PXE IPv6\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vol = pxe_bind_volume(efi_handle, pxe_base_code);
|
||||
return vol;
|
||||
}
|
||||
|
||||
static alignas(4096) uint8_t unique_sector_pool[4096];
|
||||
|
||||
struct volume *disk_volume_from_efi_handle(EFI_HANDLE efi_handle) {
|
||||
|
@ -323,7 +356,7 @@ struct volume *disk_volume_from_efi_handle(EFI_HANDLE efi_handle) {
|
|||
|
||||
status = gBS->HandleProtocol(efi_handle, &block_io_guid, (void **)&block_io);
|
||||
if (status) {
|
||||
return NULL;
|
||||
return pxe_from_efi_handle(efi_handle);
|
||||
}
|
||||
|
||||
block_io->Media->WriteCaching = false;
|
||||
|
|
|
@ -49,14 +49,12 @@ struct file_handle *fopen(struct volume *part, const char *filename) {
|
|||
|
||||
struct file_handle *ret;
|
||||
|
||||
#if defined (BIOS)
|
||||
if (part->pxe) {
|
||||
if ((ret = tftp_open(0, 69, filename)) == NULL) {
|
||||
if ((ret = tftp_open(part, "", filename)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((ret = ext2_open(part, filename)) != NULL) {
|
||||
goto success;
|
||||
|
|
|
@ -43,22 +43,6 @@ int init_config_disk(struct volume *part) {
|
|||
return init_config(config_size);
|
||||
}
|
||||
|
||||
#if defined (BIOS)
|
||||
int init_config_pxe(void) {
|
||||
struct file_handle *f;
|
||||
if ((f = tftp_open(0, 69, "limine.cfg")) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t config_size = f->size + 2;
|
||||
config_addr = ext_mem_alloc(config_size);
|
||||
|
||||
fread(f, config_addr, 0, f->size);
|
||||
|
||||
return init_config(config_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NOT_CHILD (-1)
|
||||
#define DIRECT_CHILD 0
|
||||
#define INDIRECT_CHILD 1
|
||||
|
|
|
@ -26,7 +26,6 @@ struct conf_tuple {
|
|||
extern struct menu_entry *menu_tree;
|
||||
|
||||
int init_config_disk(struct volume *part);
|
||||
int init_config_pxe(void);
|
||||
int init_config(size_t config_size);
|
||||
|
||||
char *config_get_value(const char *config, size_t index, const char *key);
|
||||
|
|
|
@ -17,9 +17,14 @@
|
|||
struct volume {
|
||||
#if defined (UEFI)
|
||||
EFI_HANDLE efi_handle;
|
||||
|
||||
// Block storage
|
||||
EFI_HANDLE efi_part_handle;
|
||||
EFI_BLOCK_IO *block_io;
|
||||
|
||||
// PXE
|
||||
EFI_PXE_BASE_CODE_PROTOCOL *pxe_base_code;
|
||||
|
||||
bool unique_sector_valid;
|
||||
uint64_t unique_sector;
|
||||
uint8_t unique_sector_b2b[BLAKE2B_OUT_BYTES];
|
||||
|
|
|
@ -164,7 +164,6 @@ static struct file_handle *uri_fslabel_dispatch(char *fslabel, char *path) {
|
|||
return fopen(volume, path);
|
||||
}
|
||||
|
||||
#if defined (BIOS)
|
||||
static struct file_handle *uri_tftp_dispatch(char *root, char *path) {
|
||||
uint32_t ip;
|
||||
if (!strcmp(root, "")) {
|
||||
|
@ -176,19 +175,16 @@ static struct file_handle *uri_tftp_dispatch(char *root, char *path) {
|
|||
}
|
||||
|
||||
struct file_handle *ret;
|
||||
if ((ret = tftp_open(ip, 69, path)) == NULL) {
|
||||
if ((ret = tftp_open(boot_volume, root, path)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct file_handle *uri_boot_dispatch(char *s_part, char *path) {
|
||||
#if defined (BIOS)
|
||||
if (boot_volume->pxe)
|
||||
return uri_tftp_dispatch(s_part, path);
|
||||
#endif
|
||||
|
||||
int partition;
|
||||
|
||||
|
@ -242,10 +238,8 @@ struct file_handle *uri_open(char *uri) {
|
|||
ret = uri_guid_dispatch(root, path);
|
||||
} else if (!strcmp(resource, "fslabel")) {
|
||||
ret = uri_fslabel_dispatch(root, path);
|
||||
#if defined (BIOS)
|
||||
} else if (!strcmp(resource, "tftp")) {
|
||||
ret = uri_tftp_dispatch(root, path);
|
||||
#endif
|
||||
} else {
|
||||
panic(true, "Resource `%s` not valid.", resource);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <stdint.h>
|
||||
#include <lib/part.h>
|
||||
|
||||
#if defined (BIOS)
|
||||
|
||||
struct volume *pxe_bind_volume(void);
|
||||
void pxe_init(void);
|
||||
int pxe_call(uint16_t opcode, uint16_t buf_seg, uint16_t buf_off);
|
||||
|
@ -94,4 +96,10 @@ struct pxenv_get_cached_info {
|
|||
uint16_t buffer_limit;
|
||||
} __attribute__((packed));
|
||||
|
||||
#elif defined (UEFI)
|
||||
|
||||
struct volume *pxe_bind_volume(EFI_HANDLE efi_handle, EFI_PXE_BASE_CODE *pxe_base_code);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#if defined (BIOS)
|
||||
|
||||
#include <lib/print.h>
|
||||
#include <lib/real.h>
|
||||
#include <pxe/pxe.h>
|
||||
#include <lib/libc.h>
|
||||
#include <lib/misc.h>
|
||||
#include <mm/pmm.h>
|
||||
#if defined (BIOS)
|
||||
#include <lib/real.h>
|
||||
#elif defined (UEFI)
|
||||
#include <efi.h>
|
||||
#endif
|
||||
|
||||
#if defined (BIOS)
|
||||
|
||||
void set_pxe_fp(uint32_t fp);
|
||||
|
||||
|
@ -53,4 +57,16 @@ void pxe_init(void) {
|
|||
printv("pxe: Successfully initialized\n");
|
||||
}
|
||||
|
||||
#elif defined (UEFI)
|
||||
|
||||
struct volume *pxe_bind_volume(EFI_HANDLE efi_handle, EFI_PXE_BASE_CODE *pxe_base_code) {
|
||||
struct volume *volume = ext_mem_alloc(sizeof(struct volume));
|
||||
|
||||
volume->efi_handle = efi_handle;
|
||||
volume->pxe_base_code = pxe_base_code;
|
||||
volume->pxe = true;
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <stddef.h>
|
||||
#include <fs/file.h>
|
||||
|
||||
#if defined (BIOS)
|
||||
|
||||
#define UNDI_GET_INFORMATION 0xC
|
||||
|
||||
#define TFTP_OPEN 0x0020
|
||||
|
@ -37,9 +39,8 @@ struct pxenv_get_file_size {
|
|||
|
||||
#define TFTP_CLOSE 0x21
|
||||
|
||||
//server_ip and server_port can be 0 for default
|
||||
struct file_handle *tftp_open(uint32_t server_ip, uint16_t server_port, const char *name);
|
||||
#endif
|
||||
|
||||
uint32_t get_boot_server_info(void);
|
||||
struct file_handle *tftp_open(struct volume *part, const char *server_addr, const char *name);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
#if defined (BIOS)
|
||||
|
||||
#include <pxe/tftp.h>
|
||||
#include <pxe/pxe.h>
|
||||
#include <lib/real.h>
|
||||
#if defined (BIOS)
|
||||
# include <lib/real.h>
|
||||
#elif defined (UEFI)
|
||||
# include <efi.h>
|
||||
#endif
|
||||
#include <lib/print.h>
|
||||
#include <lib/libc.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <lib/misc.h>
|
||||
|
||||
uint32_t get_boot_server_info(void) {
|
||||
#if defined (BIOS)
|
||||
|
||||
static uint32_t get_boot_server_info(void) {
|
||||
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));
|
||||
|
@ -16,12 +20,26 @@ uint32_t get_boot_server_info(void) {
|
|||
return ph->sip;
|
||||
}
|
||||
|
||||
struct file_handle *tftp_open(uint32_t server_ip, uint16_t server_port, const char *name) {
|
||||
static uint32_t parse_ip_addr(const char *server_addr) {
|
||||
uint32_t out;
|
||||
|
||||
if (!server_addr || !strlen(server_addr)) {
|
||||
return get_boot_server_info();
|
||||
}
|
||||
|
||||
if (inet_pton(server_addr, &out)) {
|
||||
panic(true, "tftp: Invalid IPv4 address: \"%s\"", server_addr);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
struct file_handle *tftp_open(struct volume *part, const char *server_addr, const char *name) {
|
||||
uint32_t server_ip = parse_ip_addr(server_addr);
|
||||
const uint16_t server_port = 69; // This couldn't be changed previously either
|
||||
int ret = 0;
|
||||
|
||||
if (!server_ip) {
|
||||
server_ip = get_boot_server_info();
|
||||
}
|
||||
(void)part;
|
||||
|
||||
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));
|
||||
|
@ -106,4 +124,80 @@ struct file_handle *tftp_open(uint32_t server_ip, uint16_t server_port, const ch
|
|||
return handle;
|
||||
}
|
||||
|
||||
#elif defined (UEFI)
|
||||
|
||||
static EFI_IP_ADDRESS *parse_ip_addr(struct volume *part, const char *server_addr) {
|
||||
static EFI_IP_ADDRESS out;
|
||||
|
||||
if (!server_addr || !strlen(server_addr)) {
|
||||
EFI_PXE_BASE_CODE_PACKET* packet;
|
||||
if (part->pxe_base_code->Mode->PxeReplyReceived) packet = &part->pxe_base_code->Mode->PxeReply;
|
||||
else if (part->pxe_base_code->Mode->ProxyOfferReceived) packet = &part->pxe_base_code->Mode->ProxyOffer;
|
||||
else packet = &part->pxe_base_code->Mode->DhcpAck;
|
||||
memcpy(out.Addr, packet->Dhcpv4.BootpSiAddr, 4);
|
||||
} else {
|
||||
if (inet_pton(server_addr, &out.Addr)) {
|
||||
panic(true, "tftp: Invalid IPv4 address: \"%s\"", server_addr);
|
||||
}
|
||||
}
|
||||
|
||||
return &out;
|
||||
}
|
||||
|
||||
struct file_handle *tftp_open(struct volume *part, const char *server_addr, const char *name) {
|
||||
if (!part->pxe_base_code) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EFI_IP_ADDRESS *ip = parse_ip_addr(part, server_addr);
|
||||
|
||||
uint64_t file_size;
|
||||
EFI_STATUS status;
|
||||
|
||||
status = part->pxe_base_code->Mtftp(
|
||||
part->pxe_base_code,
|
||||
EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
|
||||
NULL,
|
||||
false,
|
||||
&file_size,
|
||||
NULL,
|
||||
ip,
|
||||
(uint8_t *)name,
|
||||
NULL,
|
||||
false);
|
||||
|
||||
if (status) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct file_handle *handle = ext_mem_alloc(sizeof(struct file_handle));
|
||||
|
||||
handle->size = file_size;
|
||||
handle->is_memfile = true;
|
||||
|
||||
handle->pxe = true;
|
||||
handle->pxe_ip = *(uint32_t *)&ip;
|
||||
handle->pxe_port = 69;
|
||||
|
||||
handle->fd = ext_mem_alloc(handle->size);
|
||||
|
||||
status = part->pxe_base_code->Mtftp(
|
||||
part->pxe_base_code,
|
||||
EFI_PXE_BASE_CODE_TFTP_READ_FILE,
|
||||
handle->fd,
|
||||
false,
|
||||
&file_size,
|
||||
NULL,
|
||||
ip,
|
||||
(uint8_t *)name,
|
||||
NULL,
|
||||
false);
|
||||
|
||||
if (status) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue