protos/limine: Add bootloader performance feature
This feature provides the same information as the new Boot Loader Interface variables, but encoded in a nicer way for Limine protocol executables.
diff --git a/PROTOCOL.md b/PROTOCOL.md
index daadb9e8..d8ccc964 100644
--- a/PROTOCOL.md
+++ b/PROTOCOL.md
@@ -1381,3 +1381,43 @@ given by bootloader tags, and as such the `/chosen` node properties should be ig
Note: If the DTB contained `memory@...` nodes, they will get removed.
Executables may not rely on these nodes and should use the Memory Map feature instead.
+
+### Bootloader Performance Feature
+
+ID:
+```c
+#define LIMINE_BOOTLOADER_PERFORMANCE_REQUEST { LIMINE_COMMON_MAGIC, 0x6b50ad9bf36d13ad, 0xdc4c7e88fc759e17 }
+```
+
+Request:
+```c
+struct limine_bootloader_performance_request {
+ uint64_t id[4];
+ uint64_t revision;
+ struct limine_bootloader_performance_response *response;
+};
+```
+
+Response:
+```c
+struct limine_bootloader_performance_response {
+ uint64_t revision;
+ uint64_t reset_usec;
+ uint64_t init_usec;
+ uint64_t exec_usec;
+};
+```
+
+* `reset_usec` - time of system reset in microseconds relative to an arbitrary point in the past.
+* `init_usec` - time of bootloader initialisation in microseconds relative to an arbitrary point in
+the past.
+* `exec_usec` - time of executable handoff in microseconds relative to an arbitrary point in the
+past.
+
+Note: Data provided by this feature is purely informational. The ACPI Firmware Performance Data
+Table may have more correct data and should be preferred if it exists. Bootloaders may implement
+this feature using the FPDT.
+
+Note: The bootloader may assume `reset_usec` is zero if it cannot or does not know the time of
+system reset, due to implementation or platform restrictions. `reset_usec` will usually be 0 or a
+value near zero, but may be any value relative to any point in the past.
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 99942d98..cd88f557 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -1395,6 +1395,27 @@ FEAT_END
}
#endif
+ // Bootloader Performance
+ // rdtsc_usec depends on EFI boot services
+FEAT_START
+ if (usec_at_bootloader_entry == 0) {
+ break;
+ }
+
+ struct limine_bootloader_performance_request *perf_request = get_request(LIMINE_BOOTLOADER_PERFORMANCE_REQUEST);
+ if (perf_request == NULL) {
+ break;
+ }
+
+ struct limine_bootloader_performance_response *perf_response =
+ ext_mem_alloc(sizeof(struct limine_bootloader_performance_response));
+
+ perf_response->reset_usec = 0;
+ perf_response->init_usec = usec_at_bootloader_entry;
+ perf_response->exec_usec = rdtsc_usec();
+ perf_request->response = reported_addr(perf_response);
+FEAT_END
+
#if defined (UEFI)
efi_exit_boot_services();
#endif
diff --git a/limine.h b/limine.h
index d1d20089..e27d1b18 100644
--- a/limine.h
+++ b/limine.h
@@ -747,6 +747,23 @@ struct limine_riscv_bsp_hartid_request {
LIMINE_PTR(struct limine_riscv_bsp_hartid_response *) response;
};
+/* Bootloader Performance */
+
+#define LIMINE_BOOTLOADER_PERFORMANCE_REQUEST { LIMINE_COMMON_MAGIC, 0x6b50ad9bf36d13ad, 0xdc4c7e88fc759e17 }
+
+struct limine_bootloader_performance_response {
+ uint64_t revision;
+ uint64_t reset_usec;
+ uint64_t init_usec;
+ uint64_t exec_usec;
+};
+
+struct limine_bootloader_performance_request {
+ uint64_t id[4];
+ uint64_t revision;
+ LIMINE_PTR(struct limine_bootloader_performance_response *) response;
+};
+
#ifdef __cplusplus
}
#endif
