Skip to content

Commit 8cc8588

Browse files
authored
Merge branch 'Limine-Bootloader:trunk' into trunk
2 parents c1aeff1 + 06f179d commit 8cc8588

10 files changed

Lines changed: 161 additions & 33 deletions

File tree

bootstrap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ if ! test -f version; then
101101
clone_repo_commit \
102102
https://github.com/Mintsuki/Flanterm.git \
103103
flanterm \
104-
112434532822dde252c84b25a6798a9c00515d66
104+
f3221ad399f08437efd6de77a5f0d9a5607a8649
105105

106106
download_by_hash \
107107
https://github.com/nothings/stb/raw/5c205738c191bcb0abc65c4febfa9bd25ff35234/stb_image.h \

common/compress/gzip.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ static size_t gz_source_read(void * user, void * buf, size_t len) {
5656
uint64_t avail = gh->source->size - gh->src_pos;
5757
if ((uint64_t)len > avail) len = (size_t)avail;
5858
if (len == 0) return 0;
59-
fread(gh->source, buf, gh->src_pos, len);
60-
gh->src_pos += len;
61-
return len;
59+
size_t got = fread(gh->source, buf, gh->src_pos, len);
60+
gh->src_pos += got;
61+
return got;
6262
}
6363

6464
/* (Re)initialize the decoder for a fresh pass over the compressed stream.

common/compress/gzip.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,10 @@ bool gzip_check(struct file_handle * fd);
3737
* decompresses the data. The returned handle takes ownership of
3838
* `compressed` and will close it when itself is closed.
3939
*
40-
* WARNING: Due to a Gzip format deficiency, ->size of the resulting
41-
* file_handle is only an approximation (i.e., it is not correct for
42-
* files larger than 4 GiB and doesn't necessarily have to reflect
43-
* the genuine decompressed size at all in adversarial circumstances).
44-
*
45-
* The real decompressed size can only be authoritatively obtained by
46-
* fully decompressing the file.
40+
* NOTE: ->size on the returned handle is set to UINT64_MAX as a
41+
* sentinel for "unknown". The gzip ISIZE trailer is decompressed-size
42+
* mod 2^32 and is not parsed here. Callers must drive ->read until
43+
* it returns 0 (end-of-stream) to discover the true size.
4744
*
4845
* Supports very fast sequential reads and random-access reads (with
4946
* an implicit rewind + skip penalty inherent to the gzip format).

common/fs/file.s2.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ void fclose(struct file_handle *fd) {
8383

8484
uint64_t fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count) {
8585
if (fd->is_memfile) {
86+
if (fd->is_high_mem) {
87+
panic(false, "fread: memfile resides above 4 GiB; caller must use load_addr_64 directly");
88+
}
8689
if (loc >= fd->size || count > fd->size - loc) {
8790
panic(false, "fread: attempted out of bounds read");
8891
}

common/fs/iso9660.s2.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,10 @@ static void iso9660_cache_root(struct volume *vol,
143143

144144
*root_size = pv.root.extent_size.little;
145145

146-
// Validate root directory size to prevent memory exhaustion
147-
if (*root_size == 0 || *root_size > ISO9660_MAX_DIR_SIZE) {
146+
// Validate root directory size to prevent memory exhaustion, and require
147+
// sector alignment so directory-traversal sector-skip arithmetic is sound.
148+
if (*root_size == 0 || *root_size > ISO9660_MAX_DIR_SIZE
149+
|| *root_size % ISO9660_SECTOR_SIZE != 0) {
148150
panic(false, "ISO9660: Invalid root directory size");
149151
}
150152

@@ -284,6 +286,11 @@ static struct iso9660_directory_entry *iso9660_next_entry(void *current, void *b
284286
if (entry->length < sizeof(struct iso9660_directory_entry))
285287
return NULL;
286288

289+
// Validate that the entire entry (as declared by its length field) is
290+
// within the buffer, so callers can safely read all entry->length bytes.
291+
if ((size_t)entry->length > (size_t)((uint8_t *)buffer_end - (uint8_t *)entry))
292+
return NULL;
293+
287294
return entry;
288295
}
289296

@@ -485,8 +492,11 @@ struct file_handle *iso9660_open(struct volume *vol, const char *path) {
485492
pmm_free(current, current_size);
486493
}
487494

488-
// Validate directory size to prevent memory exhaustion
489-
if (next_size == 0 || next_size > ISO9660_MAX_DIR_SIZE) {
495+
// Validate directory size to prevent memory exhaustion, and require
496+
// sector alignment so directory-traversal sector-skip arithmetic is
497+
// sound.
498+
if (next_size == 0 || next_size > ISO9660_MAX_DIR_SIZE
499+
|| next_size % ISO9660_SECTOR_SIZE != 0) {
490500
pmm_free(ret, sizeof(struct iso9660_file_handle));
491501
return NULL;
492502
}

common/lib/uri.c

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,41 @@ struct file_handle *uri_open(char *uri, uint32_t type, bool allow_high_mem
397397

398398
for (;;) {
399399
if (buf_len == buf_cap) {
400-
// Grow: new capacity = 2x (capped to prevent absurd jumps).
401-
uint64_t new_cap = buf_cap * 2;
400+
// Grow: double up to 64 MiB, then add 64 MiB per step.
401+
// Doubling past that wastes too much memory on large files.
402+
uint64_t new_cap = buf_cap < 0x4000000
403+
? buf_cap * 2
404+
: buf_cap + 0x4000000;
405+
uint64_t delta = new_cap - buf_cap;
406+
407+
// Try to extend in place by claiming the USABLE range
408+
// immediately below the current buffer. The allocator is
409+
// top-down, so above is already taken; below is the only
410+
// direction that can be contiguous. On success we only
411+
// pay delta extra bytes, not 2x peak.
412+
if (buf_addr >= delta &&
413+
memmap_alloc_range(buf_addr - delta, delta, type,
414+
MEMMAP_USABLE, false, false, false)) {
415+
uint64_t base = buf_addr - delta;
416+
// Move existing data down. dest < src, forward-safe.
417+
#if defined (__i386__)
418+
if (is_high) {
419+
for (uint64_t off = 0; off < buf_len; off += 0x100000) {
420+
size_t chunk = buf_len - off < 0x100000 ? (size_t)(buf_len - off) : 0x100000;
421+
memcpy_from_64(pool, buf_addr + off, chunk);
422+
memcpy_to_64(base + off, pool, chunk);
423+
}
424+
} else
425+
#endif
426+
{
427+
memmove((void *)(uintptr_t)base, buf_low, buf_len);
428+
buf_low = (void *)(uintptr_t)base;
429+
}
430+
buf_addr = base;
431+
buf_cap = new_cap;
432+
goto grew;
433+
}
434+
402435
void *new_low = NULL;
403436
uint64_t new_addr = 0;
404437
uri_alloc(new_cap, type, allow_high_mem, &new_low, &new_addr);
@@ -444,6 +477,7 @@ struct file_handle *uri_open(char *uri, uint32_t type, bool allow_high_mem
444477
}
445478
is_high = new_is_high;
446479
#endif
480+
grew:;
447481
}
448482

449483
uint64_t want = buf_cap - buf_len;
@@ -463,6 +497,16 @@ struct file_handle *uri_open(char *uri, uint32_t type, bool allow_high_mem
463497
buf_len += got;
464498
}
465499

500+
// Release the page-aligned tail past the actual data so we don't
501+
// hand the OS up to 64 MiB of slack typed as `type`. Keep at least
502+
// one page so the returned handle has a valid address.
503+
uint64_t kept = ALIGN_UP(buf_len, 4096, panic(true, "uri: alignment overflow"));
504+
if (kept == 0) kept = 4096;
505+
if (kept < buf_cap) {
506+
uri_release_range(buf_addr + kept, buf_cap - kept);
507+
buf_cap = kept;
508+
}
509+
466510
#if defined (__i386__)
467511
if (pool != NULL) pmm_free(pool, 0x100000);
468512
#endif

common/protos/limine.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ noreturn void limine_load(char *config, char *cmdline) {
493493
strcpy(k_path_copy, kernel_path);
494494
char *k_resource = NULL, *k_root = NULL, *k_path = NULL, *k_hash = NULL;
495495
uri_resolve(k_path_copy, &k_resource, &k_root, &k_path, &k_hash);
496+
// Strip the gzip `$` marker so reuse for module paths doesn't double-prefix.
497+
if (k_resource[0] == '$') {
498+
k_resource++;
499+
}
496500
// Copy k_resource and k_root since uri_resolve returns pointers to a static
497501
// buffer that gets overwritten by subsequent uri_open/uri_resolve calls
498502
k_resource = strdup(k_resource);

common/sys/lapic.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ void lapic_prep_lint(struct madt *madt, uint32_t acpi_uid, bool x2apic) {
6464

6565
struct madt_lapic_nmi *nmi = (void *)madt_ptr;
6666

67-
// Match all processors (0xff) or specific UID
68-
if (nmi->acpi_processor_uid != 0xff && nmi->acpi_processor_uid != (uint8_t)acpi_uid) {
67+
// Match all processors (0xff) or specific UID.
68+
if (nmi->acpi_processor_uid != 0xff
69+
&& (acpi_uid > 0xfe || nmi->acpi_processor_uid != acpi_uid)) {
6970
continue;
7071
}
7172

stage1/decompressor.asm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ _start:
7575
mov esi, ecx
7676
lea ecx, [eax+0x4] ; count = matchlen + 4
7777
rep movsb ; copy match
78+
cmp edx, ebx ; guard against streams that end on a match
79+
jae .Lcrc
7880
jmp .Ltoken
7981
; CRC32 verification
8082
.Lcrc:

tools/limlzpack.c

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,86 @@
2828
#include <stdlib.h>
2929
#include <string.h>
3030
#include <stdio.h>
31+
#include <stdbool.h>
3132

3233
typedef unsigned char byte;
3334

35+
static uint16_t endswap16(uint16_t value) {
36+
uint16_t ret = 0;
37+
ret |= (value >> 8) & 0x00ff;
38+
ret |= (value << 8) & 0xff00;
39+
return ret;
40+
}
41+
42+
static uint32_t endswap32(uint32_t value) {
43+
uint32_t ret = 0;
44+
ret |= (value >> 24) & 0x000000ff;
45+
ret |= (value >> 8) & 0x0000ff00;
46+
ret |= (value << 8) & 0x00ff0000;
47+
ret |= (value << 24) & 0xff000000;
48+
return ret;
49+
}
50+
51+
static uint64_t endswap64(uint64_t value) {
52+
uint64_t ret = 0;
53+
ret |= (value >> 56) & 0x00000000000000ff;
54+
ret |= (value >> 40) & 0x000000000000ff00;
55+
ret |= (value >> 24) & 0x0000000000ff0000;
56+
ret |= (value >> 8) & 0x00000000ff000000;
57+
ret |= (value << 8) & 0x000000ff00000000;
58+
ret |= (value << 24) & 0x0000ff0000000000;
59+
ret |= (value << 40) & 0x00ff000000000000;
60+
ret |= (value << 56) & 0xff00000000000000;
61+
return ret;
62+
}
63+
64+
#ifdef __BYTE_ORDER__
65+
66+
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
67+
#define bigendian true
68+
#else
69+
#define bigendian false
70+
#endif
71+
72+
#else /* !__BYTE_ORDER__ */
73+
74+
static bool bigendian = false;
75+
76+
#endif /* !__BYTE_ORDER__ */
77+
78+
#define ENDSWAP(VALUE) (bigendian ? ( \
79+
sizeof(VALUE) == 1 ? (VALUE) : \
80+
sizeof(VALUE) == 2 ? endswap16(VALUE) : \
81+
sizeof(VALUE) == 4 ? endswap32(VALUE) : \
82+
sizeof(VALUE) == 8 ? endswap64(VALUE) : (abort(), 1) \
83+
) : (VALUE))
84+
3485
/* Higher -> better compression with exponentally dimnishing gains. */
3586
#define LIMLZ_SA_NEIGHBORS 32
3687

37-
struct sa_cmp_ctx { int * rank; size_t n, k; };
88+
struct sa_cmp_ctx { int32_t *rank; size_t n, k; };
3889
static struct sa_cmp_ctx g_sa_ctx;
3990

40-
static int sa_cmp_idx(int i, int j) {
41-
int ri, rj;
91+
static int32_t sa_cmp_idx(int32_t i, int32_t j) {
92+
int32_t ri, rj;
4293
if (g_sa_ctx.rank[i] != g_sa_ctx.rank[j])
4394
return g_sa_ctx.rank[i] - g_sa_ctx.rank[j];
44-
ri = (i + (int)g_sa_ctx.k < (int)g_sa_ctx.n) ? g_sa_ctx.rank[i + g_sa_ctx.k] : -1;
45-
rj = (j + (int)g_sa_ctx.k < (int)g_sa_ctx.n) ? g_sa_ctx.rank[j + g_sa_ctx.k] : -1;
95+
ri = (i + (int32_t)g_sa_ctx.k < (int32_t)g_sa_ctx.n) ? g_sa_ctx.rank[i + g_sa_ctx.k] : -1;
96+
rj = (j + (int32_t)g_sa_ctx.k < (int32_t)g_sa_ctx.n) ? g_sa_ctx.rank[j + g_sa_ctx.k] : -1;
4697
return ri - rj;
4798
}
4899

49100
static int sa_qsort_cmp(const void * a, const void * b) {
50-
int i = *(const int *) a, j = *(const int *) b;
51-
return sa_cmp_idx(i, j);
101+
int32_t d = sa_cmp_idx(*(const int32_t *)a, *(const int32_t *)b);
102+
return (d > 0) - (d < 0);
52103
}
53104

54-
static int saca(const byte * s, size_t n, int * sa, int * rank, int * tmp) {
105+
static int saca(const byte * s, size_t n, int32_t * sa, int32_t * rank, int32_t * tmp) {
55106
size_t i;
56107
if (!n)
57108
return 0;
58109
for (i = 0; i < n; ++i) {
59-
sa[i] = (int)i; rank[i] = (int)s[i];
110+
sa[i] = (int32_t)i; rank[i] = (int32_t)s[i];
60111
}
61112
for (g_sa_ctx.k = 1;; g_sa_ctx.k <<= 1) {
62113
g_sa_ctx.rank = rank; g_sa_ctx.n = n;
@@ -82,7 +133,7 @@ struct match_choice { uint32_t len; uint16_t off; };
82133
struct parse_choice { uint32_t lit, mlen; uint16_t off; };
83134

84135
static int longest_matches(const byte * src, size_t n, struct match_choice * mch) {
85-
int * sa, * rank, * tmp, * inv;
136+
int32_t *sa, *rank, *tmp, *inv;
86137
size_t i;
87138
if (!n)
88139
return 0;
@@ -95,17 +146,18 @@ static int longest_matches(const byte * src, size_t n, struct match_choice * mch
95146
return -1;
96147
}
97148
for (i = 0; i < n; ++i)
98-
inv[sa[i]] = (int)i;
149+
inv[sa[i]] = (int32_t)i;
99150
for (i = 0; i < n; ++i) {
100-
int r = inv[i], d, rr;
151+
int32_t r = inv[i], rr;
152+
int d;
101153
size_t best_len = 0;
102154
uint16_t best_off = 0;
103155
for (d = -LIMLZ_SA_NEIGHBORS; d <= LIMLZ_SA_NEIGHBORS; ++d) {
104156
size_t j, l, off;
105157
if (!d)
106158
continue;
107159
rr = r + d;
108-
if (rr < 0 || rr >= (int)n)
160+
if (rr < 0 || rr >= (int32_t)n)
109161
continue;
110162
j = (size_t)sa[rr];
111163
if (j >= i)
@@ -218,6 +270,7 @@ static size_t limlzpack(void * dst, size_t dstcap, const void * srcv, size_t src
218270
dp[i] = best_cost; pick[i].lit = best_lit;
219271
pick[i].mlen = best_len; pick[i].off = best_off;
220272
}
273+
int terminated = 0;
221274
for (i = 0; i < srcsz; ) {
222275
byte * tokenp;
223276
size_t lit = pick[i].lit, ml = pick[i].mlen;
@@ -241,6 +294,7 @@ static size_t limlzpack(void * dst, size_t dstcap, const void * srcv, size_t src
241294
i += lit;
242295
if (i >= srcsz) {
243296
*tokenp = (byte)(token_hi << 3);
297+
terminated = 1;
244298
break;
245299
}
246300
unsigned mode_bit = (off > 255) ? 1u : 0u;
@@ -260,6 +314,14 @@ static size_t limlzpack(void * dst, size_t dstcap, const void * srcv, size_t src
260314
goto fail;
261315
i += ml;
262316
}
317+
/* A match-ended parse leaves no trailing token; the decompressor keys
318+
* termination off a zero-or-more-byte literal copy reaching ipe, so always
319+
* emit a final lit=0 token when the main loop didn't already. */
320+
if (!terminated) {
321+
if (out >= out_end)
322+
goto fail;
323+
*out++ = 0;
324+
}
263325
free(mch); free(pick); free(bestm); free(dp);
264326
return (size_t)(out - dstp);
265327
fail:
@@ -285,6 +347,11 @@ static uint32_t crc32_nibble(const byte *data, size_t len) {
285347
}
286348

287349
int main(int argc, char *argv[]) {
350+
#ifndef __BYTE_ORDER__
351+
uint32_t endcheck = 0x12345678;
352+
uint8_t endbyte = *((uint8_t *)&endcheck);
353+
bigendian = endbyte == 0x12;
354+
#endif
288355
if (argc != 3) {
289356
fprintf(stderr, "? %s <input> <output>\n", argv[0]); return 1;
290357
}
@@ -308,7 +375,7 @@ int main(int argc, char *argv[]) {
308375
if (!outsz) {
309376
fprintf(stderr, "? limlzpack\n"); return 1;
310377
}
311-
uint32_t crc = crc32_nibble(inbuf, insz);
378+
uint32_t crc = ENDSWAP(crc32_nibble(inbuf, insz));
312379
fwrite(&crc, sizeof(crc), 1, fout);
313380
fwrite(outbuf, 1, outsz, fout);
314381
fclose(fout);

0 commit comments

Comments
 (0)