Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 21 additions & 58 deletions bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -35,87 +35,50 @@ clone_repo_commit() {
fi
}

download_by_hash() {
DOWNLOAD_COMMAND="curl -Lo"
if ! command -v "${DOWNLOAD_COMMAND%% *}" >/dev/null 2>&1; then
DOWNLOAD_COMMAND="wget -O"
if ! command -v "${DOWNLOAD_COMMAND%% *}" >/dev/null 2>&1; then
set +x
echo "error: Neither curl nor wget found" 1>&2
exit 1
fi
fi
SHA256_COMMAND="sha256sum"
if ! command -v "${SHA256_COMMAND%% *}" >/dev/null 2>&1; then
SHA256_COMMAND="sha256"
if ! command -v "${SHA256_COMMAND%% *}" >/dev/null 2>&1; then
set +x
echo "error: Cannot find sha256(sum) command" 1>&2
exit 1
fi
fi
if ! test -f "$2" || ! $SHA256_COMMAND "$2" | grep $3 >/dev/null 2>&1; then
rm -f "$2"
mkdir -p "$2" && rm -rf "$2"
$DOWNLOAD_COMMAND "$2" $1
if ! $SHA256_COMMAND "$2" | grep $3 >/dev/null 2>&1; then
set +x
echo "error: Cannot download file '$2' by hash" 1>&2
echo "incorrect hash:" 1>&2
$SHA256_COMMAND "$2" 1>&2
rm -f "$2"
exit 1
fi
fi
}

if ! test -f version; then
clone_repo_commit \
https://codeberg.org/OSDev/freestnd-c-hdrs-0bsd.git \
https://github.com/osdev0/freestnd-c-hdrs-0bsd.git \
freestnd-c-hdrs \
097259a899d30f0a4b7a694de2de5fdda942e923

clone_repo_commit \
https://codeberg.org/OSDev/cc-runtime.git \
https://github.com/osdev0/cc-runtime.git \
cc-runtime \
dae79833b57a01b9fd3e359ee31def69f5ae899b
cp cc-runtime/src/cc-runtime.c common/cc-runtime.s2.c
cp cc-runtime/src/cc-runtime.c decompressor/cc-runtime.c

clone_repo_commit \
https://codeberg.org/Limine/limine-protocol.git \
limine-protocol \
e42d010a761e4e9ac6bad1b578110ba72c61e1d9
https://github.com/iczelia/pdgzip.git \
pdgzip \
ce578d3f815bf591b78d1689c09b05acf173c095
cp pdgzip/pdgzip.c common/compress/pdgzip.c
cp pdgzip/pdgzip.h common/compress/pdgzip.h

clone_repo_commit \
https://codeberg.org/PicoEFI/PicoEFI.git \
picoefi \
8b79fdaa72ee548a8ea24e3dc4d87bf281312865
https://github.com/Limine-Bootloader/limine-protocol.git \
limine-protocol \
5b9d13e557590d8eab93fa7449bdd1d7ed72ba8c

clone_repo_commit \
https://github.com/jibsen/tinf.git \
tinf \
57ffa1f1d5e3dde19011b2127bd26d01689b694b
mkdir -p decompressor/tinf
cp tinf/src/tinf.h tinf/src/tinflate.c tinf/src/tinfgzip.c decompressor/tinf/
patch -p0 < decompressor/tinf.patch
rm -f decompressor/tinf/*.orig
https://github.com/PicoEFI/PicoEFI.git \
picoefi \
af14129ec21ba482873289e36311ec02f1e19964

clone_repo_commit \
https://codeberg.org/Mintsuki/Flanterm.git \
https://github.com/Mintsuki/Flanterm.git \
flanterm \
5d93c648bee81ce7d19f7a6671ec2bc3aaa834f2
dfa1922c0749faf64c4423a81b233a20c08a7db7

download_by_hash \
https://github.com/nothings/stb/raw/5c205738c191bcb0abc65c4febfa9bd25ff35234/stb_image.h \
common/lib/stb_image.h.nopatch \
594c2fe35d49488b4382dbfaec8f98366defca819d916ac95becf3e75f4200b3
cp common/lib/stb_image.h.nopatch common/lib/stb_image.h
clone_repo_commit \
https://github.com/Mintsuki/stbi-hardened.git \
stbi-hardened \
b85b7e87f6f87300f32f7de3d94e1ed083a71263
cp stbi-hardened/include/stb_image.h common/lib/stb_image.h
patch -p0 < common/stb_image.patch
rm -f common/lib/stb_image.h.orig

clone_repo_commit \
https://codeberg.org/OSDev/libfdt.git \
https://github.com/osdev0/libfdt.git \
libfdt \
7bf94e6347129d17eca263112296ad170dec28a9
fi
Expand Down
146 changes: 146 additions & 0 deletions common/compress/gzip.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/* Limine glue around pdgzip: transparent gzip decompression layer over a
* file_handle. The underlying decoder lives in common/compress/pdgzip.c
* (imported by ./bootstrap from the upstream iczelia/pdgzip repo); this
* file only wires pdgzip's streaming read-callback API into Limine's
* file_handle abstraction and adds support for random-access reads via
* rewind-and-skip.
*
* Copyright (C) 2019-2026 Mintsuki and contributors.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <lib/libc.h>
#include <lib/misc.h>
#include <lib/print.h>
#include <mm/pmm.h>
#include <compress/gzip.h>
#include <compress/pdgzip.h>

struct gzip_handle {
struct file_handle * source; /* compressed file (owned) */
pdgzip_t * gz; /* decoder backed by `scratch` */
void * scratch; /* pdgzip scratch buffer */
size_t scratch_sz;
uint64_t src_pos; /* next byte to pull from `source` */
uint64_t dec_pos; /* current decompressed stream offset */
};

/* pdgzip read callback: pull up to `len` bytes from the compressed source
starting at gh->src_pos. A short read (including zero) signals EOF to
the decoder, which is correct at the end of the file. */
static size_t gz_source_read(void * user, void * buf, size_t len) {
struct gzip_handle * gh = user;
uint64_t avail = gh->source->size - gh->src_pos;
if ((uint64_t)len > avail) len = (size_t)avail;
if (len == 0) return 0;
size_t got = fread(gh->source, buf, gh->src_pos, len);
gh->src_pos += got;
return got;
}

/* (Re)initialize the decoder for a fresh pass over the compressed stream.
pdgzip_init zeroes its own scratch, so we only need to reset our own
bookkeeping. */
static void gz_reset(struct gzip_handle * gh) {
pdgzip_cfg_t cfg = { .read = gz_source_read, .user = gh, .concat = 0 };
gh->src_pos = 0;
gh->dec_pos = 0;
gh->gz = pdgzip_init(gh->scratch, &cfg);
}

static uint64_t gzip_read(struct file_handle * file, void * buf, uint64_t loc, uint64_t count) {
struct gzip_handle * gh = file->fd;
/* Rewind on backward seeks. */
if (loc < gh->dec_pos) gz_reset(gh);
/* Skip forward to reach the requested offset. EOS during seek means
the requested location is past end-of-stream - return 0 bytes. */
while (gh->dec_pos < loc) {
uint8_t discard[4096];
uint64_t gap = loc - gh->dec_pos;
size_t chunk = gap > sizeof(discard) ? sizeof(discard) : (size_t)gap;
int64_t n = pdgzip_read(gh->gz, discard, chunk);
if (n < 0) panic(false, "gzip: decompression error during seek");
if (n == 0) return 0;
gh->dec_pos += (uint64_t)n;
}
/* Decompress the requested data. */
uint8_t * dst = buf;
uint64_t remaining = count;
while (remaining > 0) {
size_t chunk = remaining > 65536 ? 65536 : (size_t)remaining;
int64_t n = pdgzip_read(gh->gz, dst, chunk);
if (n < 0) panic(false, "gzip: decompression error");
if (n == 0) break;
dst += n;
remaining -= (uint64_t)n;
gh->dec_pos += (uint64_t)n;
}
return count - remaining;
}

static void gzip_close(struct file_handle * file) {
struct gzip_handle * gh = file->fd;
fclose(gh->source);
pmm_free(gh->scratch, gh->scratch_sz);
pmm_free(gh, sizeof(struct gzip_handle));
}

bool gzip_check(struct file_handle * fd) {
if (fd->size < 18) return false;
uint8_t magic[2]; fread(fd, magic, 0, 2);
return magic[0] == 0x1F && magic[1] == 0x8B;
}

struct file_handle * gzip_open(struct file_handle * compressed) {
/* The decompressed size is not known up front. The 4-byte ISIZE trailer
is unreliable (modulo 2^32, spec defect) and callers must instead
drain until gzip_read returns 0 bytes (EOS). Advertise an unknown
size via UINT64_MAX. */
struct gzip_handle * gh = ext_mem_alloc(sizeof(struct gzip_handle));
gh->source = compressed;
gh->scratch_sz = pdgzip_state_size();
gh->scratch = ext_mem_alloc(gh->scratch_sz);
gz_reset(gh);
/* Depends on ext_mem_alloc returning zeroed memory. */
struct file_handle * ret = ext_mem_alloc(sizeof(struct file_handle));
ret->fd = gh;
ret->read = (void *) gzip_read;
ret->close = (void *) gzip_close;
ret->size = UINT64_MAX;
ret->vol = compressed->vol;
if (compressed->path != NULL && compressed->path_len > 0) {
ret->path = ext_mem_alloc(compressed->path_len);
memcpy(ret->path, compressed->path, compressed->path_len);
ret->path_len = compressed->path_len;
}
#if defined (UEFI)
ret->efi_part_handle = compressed->efi_part_handle;
#endif
ret->pxe = compressed->pxe;
ret->pxe_ip = compressed->pxe_ip;
ret->pxe_port = compressed->pxe_port;
return ret;
}
50 changes: 50 additions & 0 deletions common/compress/gzip.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* embeddable gzip decoder: Copyright (C) 2026 Kamila Szewczyk <k@iczelia.net>
* limine: Copyright (C) 2019-2026 Mintsuki and contributors.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef COMPRESS__GZIP_H__
#define COMPRESS__GZIP_H__

#include <fs/file.h>

/* Check if a file handle points to gzip-compressed data (0x1F 0x8B magic). */
bool gzip_check(struct file_handle * fd);

/* Wrap a gzip-compressed file handle in a decompressing layer.
*
* Returns a new file_handle whose read callback transparently
* decompresses the data. The returned handle takes ownership of
* `compressed` and will close it when itself is closed.
*
* NOTE: ->size on the returned handle is set to UINT64_MAX as a
* sentinel for "unknown". The gzip ISIZE trailer is decompressed-size
* mod 2^32 and is not parsed here. Callers must drive ->read until
* it returns 0 (end-of-stream) to discover the true size.
*
* Supports very fast sequential reads and random-access reads (with
* an implicit rewind + skip penalty inherent to the gzip format).
*/
struct file_handle * gzip_open(struct file_handle * compressed);

#endif
12 changes: 11 additions & 1 deletion common/drivers/disk.s2.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,13 @@ void disk_create_index(void) {
bool is_atapi = (dpte != NULL && (dpte->flags & (1 << 6)));
block->is_optical = is_atapi || (block->sector_size == 2048 && is_removable);

// Ugly workaround for VMware, because it puts the optical drive at 0x9f but does
// not expose DPTE.
if (drive == 0x9f && block->sector_size == 2048) {
is_removable = true;
block->is_optical = true;
}

if (!is_removable && !block->is_optical) {
if (consumed_bda_disks == bda_disk_count) {
pmm_free(block, sizeof(struct volume));
Expand Down Expand Up @@ -620,12 +627,15 @@ struct volume *disk_volume_from_efi_handle(EFI_HANDLE efi_handle) {
// Fallback to unique sector matching
uint64_t bdev_size = ((uint64_t)block_io->Media->LastBlock + 1) * (uint64_t)block_io->Media->BlockSize;
if (bdev_size >= UNIQUE_SECTOR_POOL_SIZE) {
// Pre-calculate unique sectors before reading query data into
// the pool, since find_unique_sectors() uses the same buffer.
find_unique_sectors();

status = block_io->ReadBlocks(block_io, block_io->Media->MediaId,
0,
UNIQUE_SECTOR_POOL_SIZE,
unique_sector_pool);
if (status == 0) {
find_unique_sectors();

uint8_t b2b[BLAKE2B_OUT_BYTES];
blake2b(b2b, unique_sector_pool, UNIQUE_SECTOR_POOL_SIZE);
Expand Down
Loading
Loading