This commit is contained in:
a1ive 2025-03-02 12:37:14 +09:00
parent 40cc7a7776
commit 5a5b26563a
No known key found for this signature in database
GPG Key ID: DA9BACF4F462B55D
38 changed files with 684 additions and 694 deletions

View File

@ -1,6 +1,6 @@
# Versioning information
#
VERSION := v3.0.5
VERSION := v3.1.0
WIMBOOT_VERSION := v2.8.0
SBAT_GENERATION := 1

View File

@ -23,6 +23,7 @@
#include <cmdline.h>
#include <biosdisk.h>
#include <ntloader.h>
#include <pmapi.h>
#include <msdos.h>
#include <gpt.h>
#include "int13.h"

View File

@ -20,7 +20,9 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <ntloader.h>
#include <pmapi.h>
#include <efi.h>
#include <efidisk.h>
#include <msdos.h>
@ -39,20 +41,20 @@ locate_handle (EFI_LOCATE_SEARCH_TYPE search_type,
EFI_HANDLE *buffer;
UINTN buffer_size = 8 * sizeof (EFI_HANDLE);
buffer = efi_malloc (buffer_size);
buffer = malloc (buffer_size);
status = bs->LocateHandle (search_type, protocol, search_key,
&buffer_size, buffer);
if (status == EFI_BUFFER_TOO_SMALL)
{
efi_free (buffer);
buffer = efi_malloc (buffer_size);
free (buffer);
buffer = malloc (buffer_size);
status = bs->LocateHandle (search_type, protocol, search_key,
&buffer_size, buffer);
}
if (status != EFI_SUCCESS)
efi_free (buffer);
free (buffer);
*num_handles = buffer_size / sizeof (EFI_HANDLE);
return buffer;
@ -184,7 +186,7 @@ duplicate_device_path (const EFI_DEVICE_PATH *dp)
if (END_ENTIRE_DP (p))
break;
}
p = efi_malloc (total_size);
p = malloc (total_size);
if (! p)
return 0;
memcpy (p, dp, total_size);
@ -235,7 +237,7 @@ make_devices (void)
continue;
//print_device_path (dp);
d = efi_malloc (sizeof (*d));
d = malloc (sizeof (*d));
d->handle = *handle;
d->dp = dp;
d->ldp = ldp;
@ -244,7 +246,7 @@ make_devices (void)
devices = d;
}
efi_free (handles);
free (handles);
return devices;
}
@ -273,7 +275,7 @@ find_parent_device (struct efidisk_data *devices, struct efidisk_data *d)
if (compare_device_paths (parent->dp, dp) == 0)
break;
}
efi_free (dp);
free (dp);
return parent;
}
@ -297,7 +299,7 @@ add_device (struct efidisk_data **devices, struct efidisk_data *d)
else if (ret > 0)
break;
}
n = efi_malloc (sizeof (*n));
n = malloc (sizeof (*n));
if (! n)
return;
memcpy (n, d, sizeof (*n));
@ -415,7 +417,7 @@ free_devices (struct efidisk_data *devices)
for (p = devices; p; p = q)
{
q = p->next;
efi_free (p);
free (p);
}
}

View File

@ -21,7 +21,7 @@
#include <string.h>
#include <strings.h>
#include "fsuuid.h"
#include "cmdline.h"
#include "pmapi.h"
#include "ntloader.h"
int
@ -71,7 +71,7 @@ check_fsuuid (void *disk, uint64_t lba,
}
DBG ("%s %s\n", fs, uuid);
if (strcasecmp (uuid, nt_cmdline->fsuuid) == 0)
if (strcasecmp (uuid, pm->fsuuid) == 0)
return 1;
return 0;
}

View File

@ -23,7 +23,7 @@
#include "msdos.h"
#include "gpt.h"
#include "fsuuid.h"
#include "cmdline.h"
#include "pmapi.h"
#include "ntloader.h"
static uint8_t gpt_magic[8] = GPT_HEADER_MAGIC;
@ -68,9 +68,9 @@ check_gpt_partmap (void *disk,
if (check_fsuuid (disk, entry.start, disk_read))
{
DBG ("GPT LBA=%lld\n", (unsigned long long)entry.start);
memcpy (nt_cmdline->partid, &entry.guid, 16);
nt_cmdline->partmap = 0x00;
memcpy (nt_cmdline->diskid, &gpt.guid, 16);
memcpy (pm->partid, &entry.guid, 16);
pm->partmap = 0x00;
memcpy (pm->diskid, &gpt.guid, 16);
return 1;
}
}

View File

@ -22,7 +22,7 @@
#include <strings.h>
#include "msdos.h"
#include "fsuuid.h"
#include "cmdline.h"
#include "pmapi.h"
#include "ntloader.h"
static unsigned part_count = 0;
@ -68,9 +68,9 @@ check_mbr (void *disk, uint32_t start_lba, int (*disk_read)
{
start_addr = ((uint64_t) mbr.entries[i].start + start_lba) << 9;
DBG ("MBR Start=0x%llx Signature=%04X\n", start_addr, mbr.unique_signature);
memcpy (nt_cmdline->partid, &start_addr, sizeof (start_addr));
nt_cmdline->partmap = 0x01;
memcpy (nt_cmdline->diskid, &mbr.unique_signature, sizeof (uint32_t));
memcpy (pm->partid, &start_addr, sizeof (start_addr));
pm->partmap = 0x01;
memcpy (pm->diskid, &mbr.unique_signature, sizeof (uint32_t));
return 1;
}
}

View File

@ -19,67 +19,6 @@
#ifndef _CMDLINE_H
#define _CMDLINE_H
#include <stdint.h>
#define MAX_PATH 255
#define NTBOOT_WIM 0x00
#define NTBOOT_VHD 0x01
#define NTBOOT_WOS 0x02
#define NTBOOT_REC 0x03
#define NTBOOT_RAM 0x04
#if 0
#define NTBOOT_APP 0x05
#define NTBOOT_MEM 0x06
#endif
#define NTARG_BOOL_TRUE 1
#define NTARG_BOOL_FALSE 0
#define NTARG_BOOL_UNSET 0xff
#define NTARG_BOOL_NA 0x0f
struct nt_args
{
uint8_t textmode;
uint8_t testmode;
uint8_t hires;
uint8_t hal;
uint8_t minint;
uint8_t novga;
uint8_t novesa;
uint8_t safemode;
uint8_t altshell;
uint8_t exportcd;
uint8_t advmenu;
uint8_t optedit;
uint64_t nx;
uint64_t pae;
uint64_t timeout;
uint64_t safeboot;
uint64_t gfxmode;
uint64_t imgofs;
char loadopt[128];
char winload[64];
char sysroot[32];
uint32_t boottype;
char fsuuid[17];
uint8_t partid[16];
uint8_t diskid[16];
uint8_t partmap;
char filepath[MAX_PATH + 1];
char initrd_path[MAX_PATH + 1];
void *bcd;
uint32_t bcd_length;
void *bootmgr;
uint32_t bootmgr_length;
};
extern struct nt_args *nt_cmdline;
extern void process_cmdline (char *cmdline);
#endif /* _CMDLINE_H */

View File

@ -76,8 +76,6 @@ extern EFI_GUID efi_simple_file_system_protocol_guid;
extern EFI_GUID efi_load_file2_protocol_guid;
extern EFI_GUID efi_gop_guid;
extern void *efi_malloc (size_t size);
extern void efi_free (void *ptr);
extern void efi_free_pages (void *ptr, UINTN pages);
extern void *efi_allocate_pages (UINTN pages, EFI_MEMORY_TYPE type);

View File

@ -117,6 +117,8 @@ mm_size_sanity_check (void)
*/
typedef int (*mm_add_region_func_t) (size_t, unsigned int);
void mm_init_region (void *addr, size_t size);
extern void bios_mm_init_region (void *addr, size_t size);
extern void *bios_memalign (size_t align, size_t size);
#endif /* ! _MM_H */

View File

@ -49,6 +49,14 @@
/** 16 bit real mode data segment */
#define REAL_DS 0x60
/* Refer to i386 symbols as needed */
#undef i386
#if __x86_64__
#define i386(symbol) __i386_ ## symbol
#else
#define i386(symbol) symbol
#endif
#ifndef ASSEMBLY
#include <stdint.h>
@ -120,37 +128,6 @@ static inline unsigned int page_len (const void *start, const void *end)
return (page_end (end) - page_start (start));
}
/**
* Bochs magic breakpoint
*
*/
static inline void bochsbp (void)
{
__asm__ __volatile__ ("xchgw %bx, %bx");
}
/** Debugging output */
#if DEBUG == 1 || DEBUG == 2
#define DBG(...) \
do \
{ \
printf (__VA_ARGS__); \
} while (0)
#else
#define DBG(...)
#endif
/** Verbose debugging output */
#if DEBUG == 2
#define DBG2(...) \
do \
{ \
printf (__VA_ARGS__); \
} while (0)
#else
#define DBG2(...)
#endif
/* Branch prediction macros */
#define likely(x) __builtin_expect (!! (x), 1)
#define unlikely(x) __builtin_expect ((x), 0)
@ -158,7 +135,6 @@ do \
#ifdef __i386__
extern void call_real (struct bootapp_callback_params *params);
extern void call_interrupt (struct bootapp_callback_params *params);
extern void __attribute__ ((noreturn)) reboot (void);
#else
static inline void call_real (struct bootapp_callback_params *params)
{
@ -168,14 +144,8 @@ static inline void call_interrupt (struct bootapp_callback_params *params)
{
(void) params;
}
static inline void reboot (void)
{
}
#endif
extern void __attribute__ ((noreturn, format (printf, 1, 2)))
die (const char *fmt, ...);
extern unsigned long __stack_chk_guard;
extern void init_cookie (void);

118
include/pmapi.h Normal file
View File

@ -0,0 +1,118 @@
/*
* ntloader -- Microsoft Windows NT6+ loader
* Copyright (C) 2025 A1ive.
*
* ntloader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* ntloader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ntloader. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PMAPI_H
#define _PMAPI_H
#include <stdint.h>
#define MAX_PATH 255
#define NTBOOT_WIM 0x00
#define NTBOOT_VHD 0x01
#define NTBOOT_WOS 0x02
#define NTBOOT_REC 0x03
#define NTBOOT_RAM 0x04
#if 0
#define NTBOOT_APP 0x05
#define NTBOOT_MEM 0x06
#endif
#define NTARG_BOOL_TRUE 1
#define NTARG_BOOL_FALSE 0
#define NTARG_BOOL_UNSET 0xff
#define NTARG_BOOL_NA 0x0f
struct nt_args
{
uint8_t textmode;
uint8_t testmode;
uint8_t hires;
uint8_t hal;
uint8_t minint;
uint8_t novga;
uint8_t novesa;
uint8_t safemode;
uint8_t altshell;
uint8_t exportcd;
uint8_t advmenu;
uint8_t optedit;
uint64_t nx;
uint64_t pae;
uint64_t timeout;
uint64_t safeboot;
uint64_t gfxmode;
uint64_t imgofs;
char loadopt[128];
char winload[64];
char sysroot[32];
uint32_t boottype;
char fsuuid[17];
uint8_t partid[16];
uint8_t diskid[16];
uint8_t partmap;
char filepath[MAX_PATH + 1];
char initrd_path[MAX_PATH + 1];
void *bcd;
uint32_t bcd_length;
void *bootmgr;
uint32_t bootmgr_length;
/* Functions */
void __attribute__ ((noreturn)) (* _reboot) (void);
void (* _putchar) (int c);
int (* _getchar) (void);
void *(* _malloc) (size_t size);
void (* _free) (void *ptr);
};
extern struct nt_args *pm;
/** Debugging output */
#if DEBUG == 1 || DEBUG == 2
#define DBG(...) \
do \
{ \
printf (__VA_ARGS__); \
} while (0)
#else
#define DBG(...)
#endif
/** Verbose debugging output */
#if DEBUG == 2
#define DBG2(...) \
do \
{ \
printf (__VA_ARGS__); \
} while (0)
#else
#define DBG2(...)
#endif
extern void __attribute__ ((noreturn, format (printf, 1, 2)))
die (const char *fmt, ...);
extern void bios_init (void);
extern void efi_init (void);
#endif /* _PMAPI */

View File

@ -29,12 +29,9 @@
extern unsigned long strtoul (const char *nptr, char **endptr, int base);
extern void *memalign (size_t align, size_t size);
extern void *calloc (size_t nmemb, size_t size);
extern void *malloc (size_t size);
extern void *zalloc (size_t size);
extern void free (void *ptr);
extern void *realloc (void *ptr, size_t size);
#endif /* _STDLIB_H */

View File

@ -1,80 +1,37 @@
/* mm.c - functions for memory manager */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2005,2007,2008,2009 Free Software Foundation, Inc.
* ntloader -- Microsoft Windows NT6+ loader
* Copyright (C) 2025 A1ive.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* ntloader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* ntloader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* The design of this memory manager.
*
* This is a simple implementation of malloc with a few extensions. These are
* the extensions:
*
* - memalign is implemented efficiently.
*
* - multiple regions may be used as free space. They may not be
* contiguous.
*
* - if existing regions are insufficient to satisfy an allocation, a new
* region can be requested from firmware.
*
* Regions are managed by a singly linked list, and the meta information is
* stored in the beginning of each region. Space after the meta information
* is used to allocate memory.
*
* The memory space is used as cells instead of bytes for simplicity. This
* is important for some CPUs which may not access multiple bytes at a time
* when the first byte is not aligned at a certain boundary (typically,
* 4-byte or 8-byte). The size of each cell is equal to the size of struct
* mm_header, so the header of each allocated/free block fits into one
* cell precisely. One cell is 16 bytes on 32-bit platforms and 32 bytes
* on 64-bit platforms.
*
* There are two types of blocks: allocated blocks and free blocks.
*
* In allocated blocks, the header of each block has only its size. Note that
* this size is based on cells but not on bytes. The header is located right
* before the returned pointer, that is, the header resides at the previous
* cell.
*
* Free blocks constitutes a ring, using a singly linked list. The first free
* block is pointed to by the meta information of a region. The allocator
* attempts to pick up the second block instead of the first one. This is
* a typical optimization against defragmentation, and makes the
* implementation a bit easier.
*
* For safety, both allocated blocks and free ones are marked by magic
* numbers. Whenever anything unexpected is detected, GRUB aborts the
* operation.
* along with ntloader. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "bootapp.h"
#include "ntloader.h"
#include "pmapi.h"
#include "mm.h"
#if defined(__i386__) || defined(__x86_64__)
/*
* MM_MGMT_OVERHEAD is an upper bound of management overhead of
* each region, with any possible padding taken into account.
*
* The value must be large enough to make sure memalign(align, size)
* always succeeds after a successful call to
* mm_init_region(addr, size + align + MM_MGMT_OVERHEAD),
* bios_mm_init_region(addr, size + align + MM_MGMT_OVERHEAD),
* for any given addr, align and size (assuming no interger overflow).
*
* The worst case which has maximum overhead is shown in the figure below:
@ -101,10 +58,10 @@
* + sizeof (struct mm_header) + (MM_ALIGN - 1)
*/
#define MM_MGMT_OVERHEAD \
((MM_ALIGN - 1) \
+ sizeof (struct mm_region) \
+ sizeof (struct mm_header) \
+ (MM_ALIGN - 1))
((MM_ALIGN - 1) \
+ sizeof (struct mm_region) \
+ sizeof (struct mm_header) \
+ (MM_ALIGN - 1))
/* The size passed to mm_add_region_fn() is aligned up by this value. */
#define MM_HEAP_GROW_ALIGN 4096
@ -139,145 +96,6 @@ get_header_from_pointer (void *ptr, mm_header_t *p, mm_region_t *r)
die ("alloc magic is broken at %p: %zx\n", *p, (*p)->magic);
}
/* Initialize a region starting from ADDR and whose size is SIZE,
* to use it as free space. */
void
mm_init_region (void *addr, size_t size)
{
mm_header_t h;
mm_region_t r, *p, q;
DBG ("Using memory for heap: start=%p, end=%p\n",
addr, (char *) addr + (unsigned int) size);
/* Exclude last 4K to avoid overflows. */
/* If addr + 0x1000 overflows then whole region is in excluded zone. */
if ((intptr_t) addr > ~((intptr_t) 0x1000))
return;
/* If addr + 0x1000 + size overflows then decrease size. */
if (((intptr_t) addr + 0x1000) > ~(intptr_t) size)
size = ((intptr_t) -0x1000) - (intptr_t) addr;
/* Attempt to merge this region with every existing region */
for (p = &mm_base, q = *p; q; p = &(q->next), q = *p)
{
/*
* Is the new region immediately below an existing region? That
* is, is the address of the memory we're adding now (addr) + size
* of the memory we're adding (size) + the bytes we couldn't use
* at the start of the region we're considering (q->pre_size)
* equal to the address of q? In other words, does the memory
* looks like this?
*
* addr q
* |----size-----|-q->pre_size-|<q region>|
*/
if ((uint8_t *) addr + size + q->pre_size == (uint8_t *) q)
{
/*
* Yes, we can merge the memory starting at addr into the
* existing region from below. Align up addr to MM_ALIGN
* so that our new region has proper alignment.
*/
r = (mm_region_t) ALIGN_UP ((intptr_t) addr, MM_ALIGN);
/* Copy the region data across */
*r = *q;
/* Consider all the new size as pre-size */
r->pre_size += size;
/*
* If we have enough pre-size to create a block, create a
* block with it. Mark it as allocated and pass it to
* free (), which will sort out getting it into the free
* list.
*/
if (r->pre_size >> MM_ALIGN_LOG2)
{
h = (mm_header_t) (r + 1);
/* block size is pre-size converted to cells */
h->size = (r->pre_size >> MM_ALIGN_LOG2);
h->magic = MM_ALLOC_MAGIC;
/* region size grows by block size converted back to bytes */
r->size += h->size << MM_ALIGN_LOG2;
/* adjust pre_size to be accurate */
r->pre_size &= (MM_ALIGN - 1);
*p = r;
free (h + 1);
}
/* Replace the old region with the new region */
*p = r;
return;
}
/*
* Is the new region immediately above an existing region? That
* is:
* q addr
* |<q region>|-q->post_size-|----size-----|
*/
if ((uint8_t *) q + sizeof (*q) + q->size + q->post_size ==
(uint8_t *) addr)
{
/*
* Yes! Follow a similar pattern to above, but simpler.
* Our header starts at address - post_size, which should align us
* to a cell boundary.
*
* Cast to (void *) first to avoid the following build error:
* kern/mm.c: In function mm_init_region:
* kern/mm.c:211:15: error: cast increases required alignment of target type [-Werror=cast-align]
* 211 | h = (mm_header_t) ((uint8_t *) addr - q->post_size);
* | ^
* It is safe to do that because proper alignment is enforced in mm_size_sanity_check().
*/
h = (mm_header_t)(void *) ((uint8_t *) addr - q->post_size);
/* our size is the allocated size plus post_size, in cells */
h->size = (size + q->post_size) >> MM_ALIGN_LOG2;
h->magic = MM_ALLOC_MAGIC;
/* region size grows by block size converted back to bytes */
q->size += h->size << MM_ALIGN_LOG2;
/* adjust new post_size to be accurate */
q->post_size = (q->post_size + size) & (MM_ALIGN - 1);
free (h + 1);
return;
}
}
/*
* If you want to modify the code below, please also take a look at
* MM_MGMT_OVERHEAD and make sure it is synchronized with the code.
*/
/* Allocate a region from the head. */
r = (mm_region_t) ALIGN_UP ((intptr_t) addr, MM_ALIGN);
/* If this region is too small, ignore it. */
if (size < MM_ALIGN + (char *) r - (char *) addr + sizeof (*r))
return;
size -= (char *) r - (char *) addr + sizeof (*r);
h = (mm_header_t) (r + 1);
h->next = h;
h->magic = MM_FREE_MAGIC;
h->size = (size >> MM_ALIGN_LOG2);
r->first = h;
r->pre_size = (intptr_t) r - (intptr_t) addr;
r->size = (h->size << MM_ALIGN_LOG2);
r->post_size = size - r->size;
/* Find where to insert this region. Put a smaller one before bigger ones,
* to prevent fragmentation. */
for (p = &mm_base, q = *p; q; p = &(q->next), q = *p)
if (q->size > r->size)
break;
*p = r;
r->next = q;
}
/* Allocate the number of units N with the alignment ALIGN from the ring
* buffer given in *FIRST. ALIGN must be a power of two. Both N and
* ALIGN are in units of MM_ALIGN. Return a non-NULL if successful,
@ -425,7 +243,7 @@ real_malloc (mm_header_t *first, size_t n, size_t align)
/* Allocate SIZE bytes with the alignment ALIGN and return the pointer. */
void *
memalign (size_t align, size_t size)
bios_memalign (size_t align, size_t size)
{
mm_region_t r;
size_t n = ((size + MM_ALIGN - 1) >> MM_ALIGN_LOG2) + 1;
@ -524,50 +342,16 @@ fail:
return 0;
}
/*
* Allocate NMEMB instances of SIZE bytes and return the pointer, or error on
* integer overflow.
*/
void *
calloc (size_t nmemb, size_t size)
{
void *ret;
size_t sz = 0;
if (safe_mul (nmemb, size, &sz))
die ("overflow is detected\n");
ret = memalign (0, sz);
if (!ret)
return NULL;
memset (ret, 0, sz);
return ret;
}
/* Allocate SIZE bytes and return the pointer. */
void *
malloc (size_t size)
static void *
bios_malloc (size_t size)
{
return memalign (0, size);
}
/* Allocate SIZE bytes, clear them and return the pointer. */
void *
zalloc (size_t size)
{
void *ret;
ret = memalign (0, size);
if (ret)
memset (ret, 0, size);
return ret;
return bios_memalign (0, size);
}
/* Deallocate the pointer PTR. */
void
free (void *ptr)
static void
bios_free (void *ptr)
{
mm_header_t p;
mm_region_t r;
@ -644,38 +428,175 @@ free (void *ptr)
}
}
/* Reallocate SIZE bytes and return the pointer. The contents will be
* the same as that of PTR. */
void *
realloc (void *ptr, size_t size)
/* Initialize a region starting from ADDR and whose size is SIZE,
* to use it as free space. */
void
bios_mm_init_region (void *addr, size_t size)
{
mm_header_t p;
mm_region_t r;
void *q;
size_t n;
mm_header_t h;
mm_region_t r, *p, q;
if (! ptr)
return malloc (size);
DBG ("Using memory for heap: start=%p, end=%p\n",
addr, (char *) addr + (unsigned int) size);
if (! size)
/* Exclude last 4K to avoid overflows. */
/* If addr + 0x1000 overflows then whole region is in excluded zone. */
if ((intptr_t) addr > ~((intptr_t) 0x1000))
return;
/* If addr + 0x1000 + size overflows then decrease size. */
if (((intptr_t) addr + 0x1000) > ~(intptr_t) size)
size = ((intptr_t) -0x1000) - (intptr_t) addr;
/* Attempt to merge this region with every existing region */
for (p = &mm_base, q = *p; q; p = &(q->next), q = *p)
{
free (ptr);
return 0;
/*
* Is the new region immediately below an existing region? That
* is, is the address of the memory we're adding now (addr) + size
* of the memory we're adding (size) + the bytes we couldn't use
* at the start of the region we're considering (q->pre_size)
* equal to the address of q? In other words, does the memory
* looks like this?
*
* addr q
* |----size-----|-q->pre_size-|<q region>|
*/
if ((uint8_t *) addr + size + q->pre_size == (uint8_t *) q)
{
/*
* Yes, we can merge the memory starting at addr into the
* existing region from below. Align up addr to MM_ALIGN
* so that our new region has proper alignment.
*/
r = (mm_region_t) ALIGN_UP ((intptr_t) addr, MM_ALIGN);
/* Copy the region data across */
*r = *q;
/* Consider all the new size as pre-size */
r->pre_size += size;
/*
* If we have enough pre-size to create a block, create a
* block with it. Mark it as allocated and pass it to
* free (), which will sort out getting it into the free
* list.
*/
if (r->pre_size >> MM_ALIGN_LOG2)
{
h = (mm_header_t) (r + 1);
/* block size is pre-size converted to cells */
h->size = (r->pre_size >> MM_ALIGN_LOG2);
h->magic = MM_ALLOC_MAGIC;
/* region size grows by block size converted back to bytes */
r->size += h->size << MM_ALIGN_LOG2;
/* adjust pre_size to be accurate */
r->pre_size &= (MM_ALIGN - 1);
*p = r;
bios_free (h + 1);
}
/* Replace the old region with the new region */
*p = r;
return;
}
/*
* Is the new region immediately above an existing region? That
* is:
* q addr
* |<q region>|-q->post_size-|----size-----|
*/
if ((uint8_t *) q + sizeof (*q) + q->size + q->post_size ==
(uint8_t *) addr)
{
/*
* Yes! Follow a similar pattern to above, but simpler.
* Our header starts at address - post_size, which should align us
* to a cell boundary.
*
* Cast to (void *) first to avoid the following build error:
* kern/mm.c: In function bios_mm_init_region:
* kern/mm.c:211:15: error: cast increases required alignment of target type [-Werror=cast-align]
* 211 | h = (mm_header_t) ((uint8_t *) addr - q->post_size);
* | ^
* It is safe to do that because proper alignment is enforced in mm_size_sanity_check().
*/
h = (mm_header_t)(void *) ((uint8_t *) addr - q->post_size);
/* our size is the allocated size plus post_size, in cells */
h->size = (size + q->post_size) >> MM_ALIGN_LOG2;
h->magic = MM_ALLOC_MAGIC;
/* region size grows by block size converted back to bytes */
q->size += h->size << MM_ALIGN_LOG2;
/* adjust new post_size to be accurate */
q->post_size = (q->post_size + size) & (MM_ALIGN - 1);
bios_free (h + 1);
return;
}
}
/* FIXME: Not optimal. */
n = ((size + MM_ALIGN - 1) >> MM_ALIGN_LOG2) + 1;
get_header_from_pointer (ptr, &p, &r);
/*
* If you want to modify the code below, please also take a look at
* MM_MGMT_OVERHEAD and make sure it is synchronized with the code.
*/
if (p->size >= n)
return ptr;
/* Allocate a region from the head. */
r = (mm_region_t) ALIGN_UP ((intptr_t) addr, MM_ALIGN);
q = malloc (size);
if (! q)
return q;
/* If this region is too small, ignore it. */
if (size < MM_ALIGN + (char *) r - (char *) addr + sizeof (*r))
return;
/* We've already checked that p->size < n. */
memcpy (q, ptr, p->size << MM_ALIGN_LOG2);
free (ptr);
return q;
size -= (char *) r - (char *) addr + sizeof (*r);
h = (mm_header_t) (r + 1);
h->next = h;
h->magic = MM_FREE_MAGIC;
h->size = (size >> MM_ALIGN_LOG2);
r->first = h;
r->pre_size = (intptr_t) r - (intptr_t) addr;
r->size = (h->size << MM_ALIGN_LOG2);
r->post_size = size - r->size;
/* Find where to insert this region. Put a smaller one before bigger ones,
* to prevent fragmentation. */
for (p = &mm_base, q = *p; q; p = &(q->next), q = *p)
if (q->size > r->size)
break;
*p = r;
r->next = q;
}
static void bios_putchar (int c)
{
struct bootapp_callback_params params;
memset (&params, 0, sizeof (params));
params.vector.interrupt = 0x10;
params.eax = (0x0e00 | c);
params.ebx = 0x0007;
call_interrupt (&params);
}
static int bios_getchar (void)
{
struct bootapp_callback_params params;
memset (&params, 0, sizeof (params));
params.vector.interrupt = 0x16;
call_interrupt (&params);
return params.al;
}
void __attribute__ ((noreturn)) bios_reboot (void);
#endif
void
bios_init (void)
{
#if defined(__i386__) || defined(__x86_64__)
pm->_reboot = bios_reboot;
pm->_putchar = bios_putchar;
pm->_getchar = bios_getchar;
pm->_malloc = bios_malloc;
pm->_free = bios_free;
#endif
}

View File

@ -1,14 +1,15 @@
# Objects
OBJECTS += kern/cmdline.o
OBJECTS += kern/cookie.o
OBJECTS += kern/die.o
OBJECTS += kern/efi.o
OBJECTS += kern/efiblock.o
OBJECTS += kern/efiboot.o
OBJECTS += kern/efifile.o
OBJECTS += kern/efimain.o
OBJECTS += kern/payload.o
OBJECTS += kern/pmapi.o
OBJECTS += kern/bios.o
OBJECTS += kern/callback.o
OBJECTS += kern/e820.o
OBJECTS += kern/int13.o

View File

@ -25,49 +25,9 @@
#include <wchar.h>
#include "ntloader.h"
#include "cmdline.h"
#include "pmapi.h"
#include "bcd.h"
static struct nt_args args =
{
.textmode = NTARG_BOOL_FALSE,
.testmode = NTARG_BOOL_FALSE,
.hires = NTARG_BOOL_UNSET, // wim = yes
.hal = NTARG_BOOL_TRUE,
.minint = NTARG_BOOL_UNSET, // wim = yes
.novga = NTARG_BOOL_FALSE,
.novesa = NTARG_BOOL_FALSE,
.safemode = NTARG_BOOL_FALSE,
.altshell = NTARG_BOOL_FALSE,
.exportcd = NTARG_BOOL_FALSE,
.advmenu = NTARG_BOOL_FALSE,
.optedit = NTARG_BOOL_FALSE,
.nx = NX_OPTIN,
.pae = PAE_DEFAULT,
.timeout = 0,
.safeboot = SAFE_MINIMAL,
.gfxmode = GFXMODE_1024X768,
.imgofs = 65536,
.loadopt = BCD_DEFAULT_CMDLINE,
.winload = "",
.sysroot = BCD_DEFAULT_SYSROOT,
.boottype = NTBOOT_WOS,
.fsuuid = "",
.partid = { 0 },
.diskid = { 0 },
.partmap = 0x01,
.initrd_path = "\\initrd.cpio",
.bcd = NULL,
.bcd_length = 0,
.bootmgr = NULL,
.bootmgr_length = 0,
};
struct nt_args *nt_cmdline;
static void
convert_path (char *str, int backslash)
{
@ -109,8 +69,6 @@ void process_cmdline (char *cmdline)
char *value;
char chr;
nt_cmdline = &args;
/* Do nothing if we have no command line */
if ((cmdline == NULL) || (cmdline[0] == '\0'))
return;
@ -150,137 +108,137 @@ void process_cmdline (char *cmdline)
{
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "uuid");
snprintf (args.fsuuid, 17, "%s", value);
snprintf (pm->fsuuid, 17, "%s", value);
}
else if (strcmp (key, "wim") == 0)
{
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "wim");
snprintf (args.filepath, 256, "%s", value);
convert_path (args.filepath, 1);
args.boottype = NTBOOT_WIM;
snprintf (pm->filepath, 256, "%s", value);
convert_path (pm->filepath, 1);
pm->boottype = NTBOOT_WIM;
}
else if (strcmp (key, "vhd") == 0)
{
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "vhd");
snprintf (args.filepath, 256, "%s", value);
convert_path (args.filepath, 1);
args.boottype = NTBOOT_VHD;
snprintf (pm->filepath, 256, "%s", value);
convert_path (pm->filepath, 1);
pm->boottype = NTBOOT_VHD;
}
else if (strcmp (key, "ram") == 0)
{
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "ram");
snprintf (args.filepath, 256, "%s", value);
convert_path (args.filepath, 1);
args.boottype = NTBOOT_RAM;
snprintf (pm->filepath, 256, "%s", value);
convert_path (pm->filepath, 1);
pm->boottype = NTBOOT_RAM;
}
else if (strcmp (key, "file") == 0)
{
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "file");
snprintf (args.filepath, 256, "%s", value);
convert_path (args.filepath, 1);
snprintf (pm->filepath, 256, "%s", value);
convert_path (pm->filepath, 1);
char *ext = strrchr (value, '.');
if (ext && strcasecmp(ext, ".wim") == 0)
args.boottype = NTBOOT_WIM;
pm->boottype = NTBOOT_WIM;
else
args.boottype = NTBOOT_VHD;
pm->boottype = NTBOOT_VHD;
}
else if (strcmp (key, "text") == 0)
{
args.textmode = NTARG_BOOL_TRUE;
pm->textmode = NTARG_BOOL_TRUE;
}
else if (strcmp (key, "testmode") == 0)
{
args.testmode = convert_bool (value);
pm->testmode = convert_bool (value);
}
else if (strcmp (key, "hires") == 0)
{
args.hires = convert_bool (value);
pm->hires = convert_bool (value);
}
else if (strcmp (key, "detecthal") == 0)
{
args.hal = convert_bool (value);
pm->hal = convert_bool (value);
}
else if (strcmp (key, "minint") == 0)
{
args.minint = convert_bool (value);
pm->minint = convert_bool (value);
}
else if (strcmp (key, "novga") == 0)
{
args.novga = convert_bool (value);
pm->novga = convert_bool (value);
}
else if (strcmp (key, "novesa") == 0)
{
args.novesa = convert_bool (value);
pm->novesa = convert_bool (value);
}
else if (strcmp (key, "altshell") == 0)
{
args.altshell = convert_bool (value);
args.safemode = NTARG_BOOL_TRUE;
pm->altshell = convert_bool (value);
pm->safemode = NTARG_BOOL_TRUE;
}
else if (strcmp (key, "exportascd") == 0)
{
args.exportcd = convert_bool (value);
pm->exportcd = convert_bool (value);
}
else if (strcmp (key, "f8") == 0)
{
args.advmenu = NTARG_BOOL_TRUE;
args.textmode = NTARG_BOOL_TRUE;
pm->advmenu = NTARG_BOOL_TRUE;
pm->textmode = NTARG_BOOL_TRUE;
}
else if (strcmp (key, "edit") == 0)
{
args.optedit = NTARG_BOOL_TRUE;
args.textmode = NTARG_BOOL_TRUE;
pm->optedit = NTARG_BOOL_TRUE;
pm->textmode = NTARG_BOOL_TRUE;
}
else if (strcmp (key, "nx") == 0)
{
if (! value || strcasecmp (value, "OptIn") == 0)
args.nx = NX_OPTIN;
pm->nx = NX_OPTIN;
else if (strcasecmp (value, "OptOut") == 0)
args.nx = NX_OPTOUT;
pm->nx = NX_OPTOUT;
else if (strcasecmp (value, "AlwaysOff") == 0)
args.nx = NX_ALWAYSOFF;
pm->nx = NX_ALWAYSOFF;
else if (strcasecmp (value, "AlwaysOn") == 0)
args.nx = NX_ALWAYSON;
pm->nx = NX_ALWAYSON;
}
else if (strcmp (key, "pae") == 0)
{
if (! value || strcasecmp (value, "Default") == 0)
args.pae = PAE_DEFAULT;
pm->pae = PAE_DEFAULT;
else if (strcasecmp (value, "Enable") == 0)
args.pae = PAE_ENABLE;
pm->pae = PAE_ENABLE;
else if (strcasecmp (value, "Disable") == 0)
args.pae = PAE_DISABLE;
pm->pae = PAE_DISABLE;
}
else if (strcmp (key, "safemode") == 0)
{
args.safemode = NTARG_BOOL_TRUE;
pm->safemode = NTARG_BOOL_TRUE;
if (! value || strcasecmp (value, "Minimal") == 0)
args.safeboot = SAFE_MINIMAL;
pm->safeboot = SAFE_MINIMAL;
else if (strcasecmp (value, "Network") == 0)
args.safeboot = SAFE_NETWORK;
pm->safeboot = SAFE_NETWORK;
else if (strcasecmp (value, "DsRepair") == 0)
args.safeboot = SAFE_DSREPAIR;
pm->safeboot = SAFE_DSREPAIR;
}
else if (strcmp (key, "gfxmode") == 0)
{
args.hires = NTARG_BOOL_NA;
pm->hires = NTARG_BOOL_NA;
if (! value || strcasecmp (value, "1024x768") == 0)
args.gfxmode = GFXMODE_1024X768;
pm->gfxmode = GFXMODE_1024X768;
else if (strcasecmp (value, "800x600") == 0)
args.gfxmode = GFXMODE_800X600;
pm->gfxmode = GFXMODE_800X600;
else if (strcasecmp (value, "1024x600") == 0)
args.gfxmode = GFXMODE_1024X600;
pm->gfxmode = GFXMODE_1024X600;
}
else if (strcmp (key, "imgofs") == 0)
{
char *endp;
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "imgofs");
args.imgofs = strtoul (value, &endp, 0);
pm->imgofs = strtoul (value, &endp, 0);
if (*endp)
die ("Invalid imgofs \"%s\"\n", value);
}
@ -288,22 +246,22 @@ void process_cmdline (char *cmdline)
{
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "loadopt");
snprintf (args.loadopt, 128, "%s", value);
convert_path (args.loadopt, 0);
snprintf (pm->loadopt, 128, "%s", value);
convert_path (pm->loadopt, 0);
}
else if (strcmp (key, "winload") == 0)
{
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "winload");
snprintf (args.winload, 64, "%s", value);
convert_path (args.winload, 1);
snprintf (pm->winload, 64, "%s", value);
convert_path (pm->winload, 1);
}
else if (strcmp (key, "sysroot") == 0)
{
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "sysroot");
snprintf (args.sysroot, 32, "%s", value);
convert_path (args.sysroot, 1);
snprintf (pm->sysroot, 32, "%s", value);
convert_path (pm->sysroot, 1);
}
else if (strcmp (key, "initrdfile") == 0 ||
strcmp (key, "initrd") == 0)
@ -311,8 +269,8 @@ void process_cmdline (char *cmdline)
if (! value || ! value[0])
die ("Argument \"%s\" needs a value\n", "initrd");
snprintf (args.initrd_path, MAX_PATH + 1, "%s", value);
convert_path (args.initrd_path, 1);
snprintf (pm->initrd_path, MAX_PATH + 1, "%s", value);
convert_path (pm->initrd_path, 1);
}
else
{
@ -326,26 +284,26 @@ void process_cmdline (char *cmdline)
value[-1] = '=';
}
if (args.hires == NTARG_BOOL_UNSET)
if (pm->hires == NTARG_BOOL_UNSET)
{
if (args.boottype == NTBOOT_WIM)
args.hires = NTARG_BOOL_TRUE;
if (pm->boottype == NTBOOT_WIM)
pm->hires = NTARG_BOOL_TRUE;
else
args.hires = NTARG_BOOL_FALSE;
pm->hires = NTARG_BOOL_FALSE;
}
if (args.minint == NTARG_BOOL_UNSET)
if (pm->minint == NTARG_BOOL_UNSET)
{
if (args.boottype == NTBOOT_WIM)
args.minint = NTARG_BOOL_TRUE;
if (pm->boottype == NTBOOT_WIM)
pm->minint = NTARG_BOOL_TRUE;
else
args.minint = NTARG_BOOL_FALSE;
pm->minint = NTARG_BOOL_FALSE;
}
if (args.winload[0] == '\0')
if (pm->winload[0] == '\0')
{
if (args.boottype == NTBOOT_WIM)
snprintf (args.winload, 64, "%s", BCD_LONG_WINLOAD);
if (pm->boottype == NTBOOT_WIM)
snprintf (pm->winload, 64, "%s", BCD_LONG_WINLOAD);
else
snprintf (args.winload, 64, "%s", BCD_SHORT_WINLOAD);
snprintf (pm->winload, 64, "%s", BCD_SHORT_WINLOAD);
}
}

View File

@ -24,7 +24,7 @@
*
*/
#include "ntloader.h"
#include "pmapi.h"
/** Stack cookie */
unsigned long __stack_chk_guard;

View File

@ -1,68 +0,0 @@
/*
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Fatal errors
*
*/
#include <stdarg.h>
#include <stdio.h>
#include "ntloader.h"
#include "efi.h"
/**
* Handle fatal errors
*
* @v fmt Error message format string
* @v ... Arguments
*/
void die (const char *fmt, ...)
{
EFI_RUNTIME_SERVICES *rs;
va_list args;
/* Print message */
va_start (args, fmt);
vprintf (fmt, args);
va_end (args);
/* Wait for keypress */
printf ("Press a key to reboot...");
getchar();
printf ("\n");
/* Reboot system */
if (efi_systab)
{
rs = efi_systab->RuntimeServices;
rs->ResetSystem (EfiResetWarm, 0, 0, NULL);
printf ("Failed to reboot\n");
}
else
{
reboot();
}
/* Should be impossible to reach this */
__builtin_unreachable();
}

View File

@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include "ntloader.h"
#include "pmapi.h"
#include "e820.h"
/** Buffer for INT 15,e820 calls */

View File

@ -17,6 +17,7 @@
*/
#include "ntloader.h"
#include "pmapi.h"
#include "efi.h"
#include "efi/Protocol/BlockIo.h"
#include "efi/Protocol/DevicePath.h"
@ -55,7 +56,7 @@ EFI_GUID efi_load_file2_protocol_guid
EFI_GUID efi_gop_guid
= EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
void *efi_malloc (size_t size)
static void *efi_malloc (size_t size)
{
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_STATUS efirc;
@ -66,7 +67,7 @@ void *efi_malloc (size_t size)
return ptr;
}
void efi_free (void *ptr)
static void efi_free (void *ptr)
{
efi_systab->BootServices->FreePool (ptr);
ptr = 0;
@ -89,3 +90,43 @@ void *efi_allocate_pages (UINTN pages, EFI_MEMORY_TYPE type)
die ("Could not allocate memory.\n");
return (void *) (intptr_t) addr;
}
static void efi_putchar (int c)
{
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout;
wchar_t wbuf[2];
conout = efi_systab->ConOut;
wbuf[0] = c;
wbuf[1] = 0;
conout->OutputString (conout, wbuf);
}
static int efi_getchar (void)
{
EFI_BOOT_SERVICES *bs;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin;
EFI_INPUT_KEY key;
UINTN index;
bs = efi_systab->BootServices;
conin = efi_systab->ConIn;
bs->WaitForEvent (1, &conin->WaitForKey, &index);
conin->ReadKeyStroke (conin, &key);
return (int) key.UnicodeChar;
}
static void __attribute__ ((noreturn)) efi_reboot (void)
{
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
rs->ResetSystem (EfiResetWarm, 0, 0, NULL);
__builtin_unreachable ();
}
void efi_init (void)
{
pm->_reboot = efi_reboot;
pm->_putchar = efi_putchar;
pm->_getchar = efi_getchar;
pm->_malloc = efi_malloc;
pm->_free = efi_free;
}

View File

@ -27,7 +27,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "ntloader.h"
#include "pmapi.h"
#include "vdisk.h"
#include "efi.h"
#include "efiblock.h"

View File

@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
#include "ntloader.h"
#include "cmdline.h"
#include "pmapi.h"
#include "vdisk.h"
#include "efi.h"
#include "efiboot.h"
@ -87,7 +87,7 @@ efi_open_protocol_wrapper (EFI_HANDLE handle, EFI_GUID *protocol,
&efi_gop_blocked_guid,
&efi_gop_blocked,
NULL) == 0) &&
(nt_cmdline->textmode))
(pm->textmode))
{
DBG ("Forcing text mode output\n");
return EFI_INVALID_PARAMETER;
@ -119,14 +119,14 @@ void efi_boot (EFI_DEVICE_PATH_PROTOCOL *path,
/* Allocate memory */
data = efi_allocate_pages (
BYTES_TO_PAGES (nt_cmdline->bootmgr_length), EfiLoaderCode);
BYTES_TO_PAGES (pm->bootmgr_length), EfiLoaderCode);
/* Copy image */
memcpy (data, nt_cmdline->bootmgr, nt_cmdline->bootmgr_length);
memcpy (data, pm->bootmgr, pm->bootmgr_length);
/* Load image */
efirc = bs->LoadImage (FALSE, efi_image_handle, path, data,
nt_cmdline->bootmgr_length, &handle);
pm->bootmgr_length, &handle);
if (efirc != 0)
{
die ("Could not load bootmgfw.efi: %#lx\n",

View File

@ -22,7 +22,7 @@
#include <wchar.h>
#include "ntloader.h"
#include "vdisk.h"
#include "cmdline.h"
#include "pmapi.h"
#include "charset.h"
#include "payload.h"
#include "efi.h"
@ -66,7 +66,7 @@ efi_load_sfs_initrd (UINTN *len, EFI_HANDLE handle)
wchar_t wpath[MAX_PATH + 1];
*utf8_to_ucs2 (wpath, MAX_PATH + 1,
(uint8_t *) nt_cmdline->initrd_path) = L'\0';
(uint8_t *) pm->initrd_path) = L'\0';
/* Open file system */
efirc = bs->OpenProtocol (handle,

View File

@ -17,8 +17,10 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include "ntloader.h"
#include "cmdline.h"
#include "pmapi.h"
#include "charset.h"
#include "efi.h"
#include "efifile.h"
@ -56,7 +58,7 @@ const char sbat[ sizeof (SBAT_CSV) - 1 ] __sbat = SBAT_CSV;
static void efi_cmdline (EFI_LOADED_IMAGE_PROTOCOL *loaded)
{
size_t cmdline_len = (loaded->LoadOptionsSize / sizeof (wchar_t));
char *cmdline = efi_malloc (4 * cmdline_len + 1);
char *cmdline = malloc (4 * cmdline_len + 1);
/* Convert command line to ASCII */
*ucs2_to_utf8 ((uint8_t *) cmdline,
@ -65,7 +67,7 @@ static void efi_cmdline (EFI_LOADED_IMAGE_PROTOCOL *loaded)
/* Process command line */
process_cmdline (cmdline);
efi_free (cmdline);
free (cmdline);
}
/**
@ -96,6 +98,8 @@ EFI_STATUS EFIAPI efi_main (EFI_HANDLE image_handle,
/* Initialise stack cookie */
init_cookie();
efi_init ();
/* Print welcome banner */
printf ("\n\nntloader " VERSION "\n\n");

View File

@ -27,6 +27,7 @@
#include <string.h>
#include <stdio.h>
#include "ntloader.h"
#include "pmapi.h"
#include "int13.h"
#include "vdisk.h"

View File

@ -28,6 +28,7 @@
#include "vdisk.h"
#include "payload.h"
#include "cmdline.h"
#include "pmapi.h"
#include "paging.h"
#include "e820.h"
#include "biosdisk.h"
@ -88,7 +89,7 @@ static void call_interrupt_wrapper (struct bootapp_callback_params *params)
}
else if ((params->vector.interrupt == 0x10) &&
(params->ax == 0x4f01) &&
(nt_cmdline->textmode))
(pm->textmode))
{
/* Mark all VESA video modes as unsupported */
uint16_t *attributes = REAL_PTR (params->es, params->di);
@ -237,6 +238,8 @@ int main (void)
/* Initialise stack cookie */
init_cookie();
bios_init ();
/* Print welcome banner */
printf ("\n\nntloader " VERSION "\n\n");
@ -264,7 +267,7 @@ int main (void)
callback.drive = initialise_int13();
/* Load bootmgr.exe into memory */
if (load_pe (nt_cmdline->bootmgr, nt_cmdline->bootmgr_length, &pe) != 0)
if (load_pe (pm->bootmgr, pm->bootmgr_length, &pe) != 0)
die ("FATAL: Could not load bootmgr.exe\n");
/* Relocate initrd above 4GB if possible, to free up 32-bit memory */

View File

@ -29,6 +29,7 @@
#include <string.h>
#include <assert.h>
#include "ntloader.h"
#include "pmapi.h"
#include "e820.h"
#include "paging.h"

View File

@ -27,7 +27,7 @@
#include "cpio.h"
#include "ntloader.h"
#include "bcd.h"
#include "cmdline.h"
#include "pmapi.h"
#include "efi.h"
#ifdef __x86_64__
@ -96,8 +96,8 @@ static int add_file (const char *name, void *data, size_t len)
(!efi_systab && strcasecmp (name, "bootmgr.exe") == 0))
{
DBG ("...found bootmgr file %s\n", name);
nt_cmdline->bootmgr_length = len;
nt_cmdline->bootmgr = data;
pm->bootmgr_length = len;
pm->bootmgr = data;
}
return 0;
@ -111,8 +111,8 @@ static int add_file (const char *name, void *data, size_t len)
*/
void extract_initrd (void *ptr, size_t len)
{
nt_cmdline->bcd_length = BCD_LEN;
nt_cmdline->bcd = BCD_RAW;
pm->bcd_length = BCD_LEN;
pm->bcd = BCD_RAW;
printf ("...load BCD @%p %c%c%c%c [%x]\n", BCD_RAW,
BCD_RAW[0], BCD_RAW[1], BCD_RAW[2], BCD_RAW[3], BCD_LEN);
vdisk_add_file ("BCD", BCD_RAW, BCD_LEN, read_mem_file);
@ -120,7 +120,7 @@ void extract_initrd (void *ptr, size_t len)
if (cpio_extract (ptr, len, add_file) != 0)
die ("FATAL: could not extract initrd files\n");
if (!nt_cmdline->bootmgr)
if (!pm->bootmgr)
die ("FATAL: no bootmgr\n");
bcd_patch_data ();

96
kern/pmapi.c Normal file
View File

@ -0,0 +1,96 @@
/*
* ntloader -- Microsoft Windows NT6+ loader
* Copyright (C) 2025 A1ive.
*
* ntloader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* ntloader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ntloader. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include "bcd.h"
#include "pmapi.h"
#ifdef __x86_64__
extern struct nt_args i386(pm_struct);
#else
struct nt_args pm_struct =
{
.textmode = NTARG_BOOL_FALSE,
.testmode = NTARG_BOOL_FALSE,
.hires = NTARG_BOOL_UNSET, // wim = yes
.hal = NTARG_BOOL_TRUE,
.minint = NTARG_BOOL_UNSET, // wim = yes
.novga = NTARG_BOOL_FALSE,
.novesa = NTARG_BOOL_FALSE,
.safemode = NTARG_BOOL_FALSE,
.altshell = NTARG_BOOL_FALSE,
.exportcd = NTARG_BOOL_FALSE,
.advmenu = NTARG_BOOL_FALSE,
.optedit = NTARG_BOOL_FALSE,
.nx = NX_OPTIN,
.pae = PAE_DEFAULT,
.timeout = 0,
.safeboot = SAFE_MINIMAL,
.gfxmode = GFXMODE_1024X768,
.imgofs = 65536,
.loadopt = BCD_DEFAULT_CMDLINE,
.winload = "",
.sysroot = BCD_DEFAULT_SYSROOT,
.boottype = NTBOOT_WOS,
.fsuuid = "",
.partid = { 0 },
.diskid = { 0 },
.partmap = 0x01,
.initrd_path = "\\initrd.cpio",
.bcd = NULL,
.bcd_length = 0,
.bootmgr = NULL,
.bootmgr_length = 0,
};
#endif
struct nt_args *pm = &i386(pm_struct);
/**
* Handle fatal errors
*
* @v fmt Error message format string
* @v ... Arguments
*/
void die (const char *fmt, ...)
{
va_list args;
/* Print message */
va_start (args, fmt);
vprintf (fmt, args);
va_end (args);
/* Wait for keypress */
printf ("Press a key to reboot...");
getchar ();
printf ("\n");
/* Reboot system */
pm->_reboot ();
/* Should be impossible to reach this */
__builtin_unreachable ();
}

View File

@ -58,13 +58,13 @@ startup:
call main
/* Should never return */
jmp reboot
jmp bios_reboot
.size startup, . - startup
/* Reboot system */
.section ".text", "ax", @progbits
.globl reboot
reboot:
.globl bios_reboot
bios_reboot:
/* Attempt a warm reboot via the keyboard controller */
movw $WARM_REBOOT_MAGIC, WARM_REBOOT_FLAG
movb $KC_CMD_RESET, %al
@ -74,7 +74,7 @@ reboot:
/* If even that failed, hang the system */
1: hlt
jmp 1b
.size reboot, . - reboot
.size bios_reboot, . - bios_reboot
/* Global descriptor table */
.section ".rodata16", "aw", @progbits

View File

@ -26,17 +26,17 @@
#include "ntloader.h"
#include "reg.h"
#include "bcd.h"
#include "cmdline.h"
#include "pmapi.h"
#include "charset.h"
#include "efi.h"
static void
bcd_replace_suffix (const wchar_t *src, const wchar_t *dst)
{
uint8_t *p = nt_cmdline->bcd;
uint8_t *p = pm->bcd;
uint32_t ofs;
const size_t len = sizeof(wchar_t) * 5; // . E F I \0
for (ofs = 0; ofs + len < nt_cmdline->bcd_length; ofs++)
for (ofs = 0; ofs + len < pm->bcd_length; ofs++)
{
if (memcmp (p + ofs, src, len) == 0)
{
@ -206,19 +206,19 @@ bcd_patch_dp (hive_t *hive, HKEY objects, uint32_t boottype,
}
/* os device */
if (nt_cmdline->fsuuid[0])
if (pm->fsuuid[0])
data[ofs + 0x00] = 0x06; // 05=boot, 06=disk
else
data[ofs + 0x00] = 0x05;
data[ofs + 0x08] = 0x48;
memcpy (data + ofs + 0x10, nt_cmdline->partid, 16);
data[ofs + 0x24] = nt_cmdline->partmap;
memcpy (data + ofs + 0x28, nt_cmdline->diskid, 16);
memcpy (data + ofs + 0x10, pm->partid, 16);
data[ofs + 0x24] = pm->partmap;
memcpy (data + ofs + 0x28, pm->diskid, 16);
if (boottype == NTBOOT_WIM ||
boottype == NTBOOT_VHD ||
boottype == NTBOOT_RAM)
utf8_to_ucs2 ((uint16_t *)(data + ofs + 0x48), MAX_PATH,
(uint8_t *)nt_cmdline->filepath);
(uint8_t *)pm->filepath);
DBG ("...patched %ls->%ls (device%x)\n", guid, keyname, boottype);
}
@ -229,8 +229,8 @@ bcd_patch_data (void)
HKEY root, objects;
hive_t hive =
{
.size = nt_cmdline->bcd_length,
.data = nt_cmdline->bcd,
.size = pm->bcd_length,
.data = pm->bcd,
};
/* Open BCD hive */
@ -243,7 +243,7 @@ bcd_patch_data (void)
DBG ("BCD hive load OK.\n");
/* Check entry type */
switch (nt_cmdline->boottype)
switch (pm->boottype)
{
case NTBOOT_VHD:
entry_guid = GUID_VHDB;
@ -263,7 +263,7 @@ bcd_patch_data (void)
bcd_patch_szw (&hive, objects, GUID_BOOTMGR,
BCDOPT_ORDER, entry_guid); // menu display order
bcd_patch_u64 (&hive, objects, GUID_BOOTMGR,
BCDOPT_TIMEOUT, nt_cmdline->timeout); // timeout
BCDOPT_TIMEOUT, pm->timeout); // timeout
/* Patch Objects->{Resume} */
bcd_patch_dp (&hive, objects, NTBOOT_REC,
@ -276,14 +276,14 @@ bcd_patch_data (void)
BCDOPT_SYSROOT, BCD_DEFAULT_HIBERFIL); // hiberfil
/* Patch Objects->{Ramdisk} */
if (nt_cmdline->boottype == NTBOOT_RAM)
if (pm->boottype == NTBOOT_RAM)
{
bcd_delete_key (&hive, objects, GUID_RAMDISK, BCDOPT_SDIDEV);
bcd_delete_key (&hive, objects, GUID_RAMDISK, BCDOPT_SDIPATH);
bcd_patch_bool (&hive, objects, GUID_RAMDISK,
BCDOPT_EXPORTCD, nt_cmdline->exportcd);
BCDOPT_EXPORTCD, pm->exportcd);
bcd_patch_u64 (&hive, objects, GUID_RAMDISK,
BCDOPT_IMGOFS, nt_cmdline->imgofs);
BCDOPT_IMGOFS, pm->imgofs);
}
else
{
@ -293,48 +293,48 @@ bcd_patch_data (void)
/* Patch Objects->{Options} */
bcd_patch_sz (&hive, objects, GUID_OPTN,
BCDOPT_CMDLINE, nt_cmdline->loadopt);
BCDOPT_CMDLINE, pm->loadopt);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_TESTMODE, nt_cmdline->testmode);
BCDOPT_TESTMODE, pm->testmode);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_DETHAL, nt_cmdline->hal);
BCDOPT_DETHAL, pm->hal);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_WINPE, nt_cmdline->minint);
BCDOPT_WINPE, pm->minint);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_NOVGA, nt_cmdline->novga);
BCDOPT_NOVGA, pm->novga);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_NOVESA, nt_cmdline->novesa);
BCDOPT_NOVESA, pm->novesa);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_ADVOPT, nt_cmdline->advmenu);
BCDOPT_ADVOPT, pm->advmenu);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_OPTEDIT, nt_cmdline->optedit);
BCDOPT_OPTEDIT, pm->optedit);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_TEXT, nt_cmdline->textmode);
BCDOPT_TEXT, pm->textmode);
bcd_patch_u64 (&hive, objects, GUID_OPTN,
BCDOPT_NX, nt_cmdline->nx);
BCDOPT_NX, pm->nx);
bcd_patch_u64 (&hive, objects, GUID_OPTN,
BCDOPT_PAE, nt_cmdline->pae);
BCDOPT_PAE, pm->pae);
/* Patch Objects->{Resolution} */
if (nt_cmdline->hires == NTARG_BOOL_NA)
if (pm->hires == NTARG_BOOL_NA)
{
bcd_delete_key (&hive, objects, GUID_OPTN, BCDOPT_HIGHRES);
bcd_patch_u64 (&hive, objects, GUID_OPTN,
BCDOPT_GFXMODE, nt_cmdline->gfxmode);
BCDOPT_GFXMODE, pm->gfxmode);
}
else
{
bcd_delete_key (&hive, objects, GUID_OPTN, BCDOPT_GFXMODE);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_HIGHRES, nt_cmdline->hires);
BCDOPT_HIGHRES, pm->hires);
}
if (nt_cmdline->safemode)
if (pm->safemode)
{
bcd_patch_u64 (&hive, objects, GUID_OPTN,
BCDOPT_SAFEMODE, nt_cmdline->safeboot);
BCDOPT_SAFEMODE, pm->safeboot);
bcd_patch_bool (&hive, objects, GUID_OPTN,
BCDOPT_ALTSHELL, nt_cmdline->altshell);
BCDOPT_ALTSHELL, pm->altshell);
}
else
{
@ -343,14 +343,14 @@ bcd_patch_data (void)
}
/* Patch Objects->{Entry} */
bcd_patch_dp (&hive, objects, nt_cmdline->boottype,
bcd_patch_dp (&hive, objects, pm->boottype,
entry_guid, BCDOPT_APPDEV); // app device
bcd_patch_dp (&hive, objects, nt_cmdline->boottype,
bcd_patch_dp (&hive, objects, pm->boottype,
entry_guid, BCDOPT_OSDDEV); // os device
bcd_patch_sz (&hive, objects, entry_guid,
BCDOPT_WINLOAD, nt_cmdline->winload);
BCDOPT_WINLOAD, pm->winload);
bcd_patch_sz (&hive, objects, entry_guid,
BCDOPT_SYSROOT, nt_cmdline->sysroot);
BCDOPT_SYSROOT, pm->sysroot);
if (efi_systab)
bcd_replace_suffix (L".exe", L".efi");

View File

@ -29,7 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ntloader.h"
#include "pmapi.h"
#include "cpio.h"
/**

View File

@ -28,7 +28,7 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "ntloader.h"
#include "pmapi.h"
#include "peloader.h"
/**

View File

@ -22,7 +22,7 @@
#include <string.h>
#include <wchar.h>
#ifndef NTLOADER_UTIL
#include "ntloader.h"
#include "pmapi.h"
#endif
#include "reg.h"

View File

@ -29,7 +29,7 @@
#include <stdio.h>
#include <assert.h>
#include "ctype.h"
#include "ntloader.h"
#include "pmapi.h"
#include "vdisk.h"
/** Virtual files */

View File

@ -1,8 +1,8 @@
# Objects
OBJECTS += posix/stdio.o
OBJECTS += posix/stdlib.o
OBJECTS += posix/string.o
OBJECTS += posix/vsprintf.o
OBJECTS += posix/libgcc.o
OBJECTS += posix/mm.o
RM_FILES += posix/*.s posix/*.o

View File

@ -26,9 +26,7 @@
#include <stdio.h>
#include <string.h>
#include "bootapp.h"
#include "ntloader.h"
#include "efi.h"
#include "pmapi.h"
/**
* Print character to console
@ -37,36 +35,11 @@
*/
int putchar (int character)
{
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout;
struct bootapp_callback_params params;
wchar_t wbuf[2];
/* Convert LF to CR,LF */
if (character == '\n')
putchar ('\r');
pm->_putchar ('\r');
/* Print character to bochs debug port */
#if defined(__i386__) || defined(__x86_64__)
__asm__ __volatile__ ("outb %b0, $0xe9"
: : "a" (character));
#endif
/* Print character to EFI/BIOS console as applicable */
if (efi_systab)
{
conout = efi_systab->ConOut;
wbuf[0] = character;
wbuf[1] = 0;
conout->OutputString (conout, wbuf);
}
else
{
memset (&params, 0, sizeof (params));
params.vector.interrupt = 0x10;
params.eax = (0x0e00 | character);
params.ebx = 0x0007;
call_interrupt (&params);
}
pm->_putchar (character);
return 0;
}
@ -78,29 +51,5 @@ int putchar (int character)
*/
int getchar (void)
{
EFI_BOOT_SERVICES *bs;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin;
EFI_INPUT_KEY key;
UINTN index;
struct bootapp_callback_params params;
int character;
/* Get character */
if (efi_systab)
{
bs = efi_systab->BootServices;
conin = efi_systab->ConIn;
bs->WaitForEvent (1, &conin->WaitForKey, &index);
conin->ReadKeyStroke (conin, &key);
character = key.UnicodeChar;
}
else
{
memset (&params, 0, sizeof (params));
params.vector.interrupt = 0x16;
call_interrupt (&params);
character = params.al;
}
return character;
return pm->_getchar ();
}

62
posix/stdlib.c Normal file
View File

@ -0,0 +1,62 @@
/*
* ntloader -- Microsoft Windows NT6+ loader
* Copyright (C) 2025 A1ive.
*
* ntloader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* ntloader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ntloader. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "ntloader.h"
#include "pmapi.h"
void *calloc (size_t nmemb, size_t size)
{
void *ret;
size_t sz = 0;
if (safe_mul (nmemb, size, &sz))
die ("overflow is detected");
ret = pm->_malloc (sz);
if (!ret)
return NULL;
memset (ret, 0, sz);
return ret;
}
void *malloc (size_t size)
{
return pm->_malloc (size);
}
void *zalloc (size_t size)
{
void *ret;
ret = pm->_malloc (size);
if (ret)
memset (ret, 0, size);
return ret;
}
void free (void *ptr)
{
pm->_free (ptr);
}

View File

@ -26,13 +26,6 @@
#include "ntloader.h"
/* Refer to i386 symbols as needed */
#if __x86_64__
#define i386(symbol) __i386_ ## symbol
#else
#define i386(symbol) symbol
#endif
/** Standard number of setup sectors */
#define SETUP_SECTS 4