mirror of
https://github.com/grub4dos/ntloader.git
synced 2025-05-09 04:01:08 +08:00
pmapi
This commit is contained in:
parent
40cc7a7776
commit
5a5b26563a
2
Makefile
2
Makefile
@ -1,6 +1,6 @@
|
||||
# Versioning information
|
||||
#
|
||||
VERSION := v3.0.5
|
||||
VERSION := v3.1.0
|
||||
WIMBOOT_VERSION := v2.8.0
|
||||
SBAT_GENERATION := 1
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
118
include/pmapi.h
Normal 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 */
|
@ -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 */
|
||||
|
@ -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 (¶ms, 0, sizeof (params));
|
||||
params.vector.interrupt = 0x10;
|
||||
params.eax = (0x0e00 | c);
|
||||
params.ebx = 0x0007;
|
||||
call_interrupt (¶ms);
|
||||
}
|
||||
|
||||
static int bios_getchar (void)
|
||||
{
|
||||
struct bootapp_callback_params params;
|
||||
memset (¶ms, 0, sizeof (params));
|
||||
params.vector.interrupt = 0x16;
|
||||
call_interrupt (¶ms);
|
||||
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
|
||||
}
|
@ -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
|
||||
|
172
kern/cmdline.c
172
kern/cmdline.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ntloader.h"
|
||||
#include "pmapi.h"
|
||||
|
||||
/** Stack cookie */
|
||||
unsigned long __stack_chk_guard;
|
||||
|
68
kern/die.c
68
kern/die.c
@ -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();
|
||||
}
|
@ -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 */
|
||||
|
45
kern/efi.c
45
kern/efi.c
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "ntloader.h"
|
||||
#include "pmapi.h"
|
||||
#include "int13.h"
|
||||
#include "vdisk.h"
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "ntloader.h"
|
||||
#include "pmapi.h"
|
||||
#include "e820.h"
|
||||
#include "paging.h"
|
||||
|
||||
|
@ -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
96
kern/pmapi.c
Normal 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 ();
|
||||
}
|
@ -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
|
||||
|
72
libnt/bcd.c
72
libnt/bcd.c
@ -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");
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ntloader.h"
|
||||
#include "pmapi.h"
|
||||
#include "cpio.h"
|
||||
|
||||
/**
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "ntloader.h"
|
||||
#include "pmapi.h"
|
||||
#include "peloader.h"
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#ifndef NTLOADER_UTIL
|
||||
#include "ntloader.h"
|
||||
#include "pmapi.h"
|
||||
#endif
|
||||
#include "reg.h"
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "ctype.h"
|
||||
#include "ntloader.h"
|
||||
#include "pmapi.h"
|
||||
#include "vdisk.h"
|
||||
|
||||
/** Virtual files */
|
||||
|
@ -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
|
||||
|
@ -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 (¶ms, 0, sizeof (params));
|
||||
params.vector.interrupt = 0x10;
|
||||
params.eax = (0x0e00 | character);
|
||||
params.ebx = 0x0007;
|
||||
call_interrupt (¶ms);
|
||||
}
|
||||
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 (¶ms, 0, sizeof (params));
|
||||
params.vector.interrupt = 0x16;
|
||||
call_interrupt (¶ms);
|
||||
character = params.al;
|
||||
}
|
||||
|
||||
return character;
|
||||
return pm->_getchar ();
|
||||
}
|
||||
|
62
posix/stdlib.c
Normal file
62
posix/stdlib.c
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user