aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile12
-rw-r--r--NEWS3
-rw-r--r--README1
-rw-r--r--com32/cmenu/libmenu/syslnx.c52
-rw-r--r--com32/elflink/ldlinux/Makefile5
-rw-r--r--com32/elflink/ldlinux/adv.c4
-rw-r--r--com32/elflink/ldlinux/advwrite.c3
-rw-r--r--com32/elflink/ldlinux/chainboot.c4
-rw-r--r--com32/elflink/ldlinux/cli.c44
-rw-r--r--com32/elflink/ldlinux/config.h2
-rw-r--r--com32/elflink/ldlinux/execute.c32
-rw-r--r--com32/elflink/ldlinux/get_key.c2
-rw-r--r--com32/elflink/ldlinux/getadv.c2
-rw-r--r--com32/elflink/ldlinux/ldlinux.c85
-rw-r--r--com32/elflink/ldlinux/msg.c214
-rw-r--r--com32/elflink/ldlinux/readconfig.c33
-rw-r--r--com32/elflink/ldlinux/setadv.c2
-rw-r--r--com32/gpllib/Makefile2
-rw-r--r--com32/hdt/hdt-cli.c2
-rw-r--r--com32/include/cli.h2
-rw-r--r--com32/include/klibc/compiler.h2
-rw-r--r--com32/include/menu.h1
-rw-r--r--com32/include/stdio.h6
-rw-r--r--com32/include/syslinux/boot.h1
-rw-r--r--com32/include/syslinux/features.h48
-rw-r--r--com32/lib/asprintf.c5
-rw-r--r--com32/lib/bufprintf.c8
-rw-r--r--com32/lib/free.c113
-rw-r--r--com32/lib/malloc.c155
-rw-r--r--com32/lib/realloc.c98
-rw-r--r--com32/lib/sys/module/common.c8
-rw-r--r--com32/lib/sys/module/elf_module.c19
-rw-r--r--com32/lib/sys/module/exec.c24
-rw-r--r--com32/lib/sys/module/i386/elf_module.c21
-rw-r--r--com32/lib/sys/module/x86_64/elf_module.c21
-rw-r--r--com32/lib/sys/screensize.c2
-rw-r--r--com32/lib/sys/vesa/background.c1
-rw-r--r--com32/lib/syslinux/runimage.c26
-rw-r--r--com32/lib/zalloc.c17
-rw-r--r--com32/menu/menumain.c10
-rw-r--r--com32/menu/readconfig.c7
-rw-r--r--com32/sysdump/README2
-rw-r--r--core/bios.c3
-rw-r--r--core/bios.inc1
-rw-r--r--core/call16.c5
-rw-r--r--core/callback.inc6
-rw-r--r--core/cleanup.c2
-rw-r--r--core/com32.inc2
-rw-r--r--core/comboot.inc449
-rw-r--r--core/conio.c309
-rw-r--r--core/diskboot.inc5
-rw-r--r--core/diskfs.inc11
-rw-r--r--core/diskstart.inc4
-rw-r--r--core/elflink/load_env32.c24
-rw-r--r--core/font.c6
-rw-r--r--core/fs/chdir.c4
-rw-r--r--core/fs/fs.c279
-rw-r--r--core/fs/getcwd.c2
-rw-r--r--core/fs/lib/searchconfig.c4
-rw-r--r--core/fs/pxe/pxe.c27
-rw-r--r--core/fs/pxe/pxe.h1
-rw-r--r--core/fs/readdir.c6
-rw-r--r--core/fs/xfs/misc.h50
-rw-r--r--core/fs/xfs/xfs.c439
-rw-r--r--core/fs/xfs/xfs.h752
-rw-r--r--core/fs/xfs/xfs_ag.h189
-rw-r--r--core/fs/xfs/xfs_dinode.c61
-rw-r--r--core/fs/xfs/xfs_dinode.h23
-rw-r--r--core/fs/xfs/xfs_dir2.c759
-rw-r--r--core/fs/xfs/xfs_dir2.h54
-rw-r--r--core/fs/xfs/xfs_fs.h501
-rw-r--r--core/fs/xfs/xfs_readdir.c404
-rw-r--r--core/fs/xfs/xfs_readdir.h30
-rw-r--r--core/fs/xfs/xfs_sb.h206
-rw-r--r--core/fs/xfs/xfs_types.h135
-rw-r--r--core/graphics.c15
-rw-r--r--core/highmem.inc158
-rw-r--r--core/idle.c4
-rw-r--r--core/idle.inc6
-rw-r--r--core/include/bios.h10
-rw-r--r--core/include/fs.h7
-rw-r--r--core/isolinux.asm10
-rw-r--r--core/kaboom.c2
-rw-r--r--core/kernel.inc3
-rw-r--r--core/layout.inc5
-rw-r--r--core/ldlinux.asm2
-rw-r--r--core/localboot.c2
-rw-r--r--core/localboot.inc2
-rw-r--r--core/mem/free.c2
-rw-r--r--core/mem/malloc.c8
-rw-r--r--core/plaincon.c2
-rw-r--r--core/pxelinux.asm9
-rw-r--r--core/rawcon.c2
-rw-r--r--core/serirq.c4
-rw-r--r--core/stack.inc2
-rw-r--r--core/timer.inc8
-rw-r--r--diag/geodsp/Makefile2
-rw-r--r--doc/comboot.txt940
-rw-r--r--doc/extlinux.txt4
-rw-r--r--doc/mboot.txt2
-rw-r--r--doc/syslinux.txt60
-rw-r--r--efi/main.c3
-rw-r--r--extlinux/main.c235
-rw-r--r--extlinux/misc.h50
-rw-r--r--extlinux/xfs.h25
-rw-r--r--extlinux/xfs_fs.h501
-rw-r--r--extlinux/xfs_sb.h476
-rw-r--r--extlinux/xfs_types.h135
-rw-r--r--libinstaller/syslxfs.h5
-rw-r--r--man/syslinux.138
-rw-r--r--mbr/mbr.S13
-rw-r--r--mk/embedded.mk2
-rw-r--r--modules/Makefile61
-rw-r--r--modules/int18.asm16
-rw-r--r--modules/poweroff.asm102
-rw-r--r--modules/pxechain.asm558
-rw-r--r--modules/ver.asm606
-rw-r--r--modules/writestr.inc47
118 files changed, 5826 insertions, 4172 deletions
diff --git a/Makefile b/Makefile
index a04f6321..7add22e7 100644
--- a/Makefile
+++ b/Makefile
@@ -123,12 +123,12 @@ include $(MAKEDIR)/syslinux.mk
#
ifndef EFI_BUILD
-MODULES = memdisk/memdisk memdump/memdump.com modules/*.com \
+MODULES = memdisk/memdisk memdump/memdump.com \
com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
- com32/elflink/ldlinux/*.c32
+ com32/elflink/ldlinux/*.c32 com32/cmenu/libmenu/*.c32
else
# memdump is BIOS specific code exclude it for EFI
# FIXME: Prune other BIOS-centric modules
@@ -136,11 +136,11 @@ MODULES = com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
- com32/elflink/ldlinux/*.c32
+ com32/elflink/ldlinux/*.c32 com32/cmenu/libmenu/*.c32
endif
# List of module objects that should be installed for all derivatives
-INSTALLABLE_MODULES = $(filter-out com32/gpllib%,$(MODULES))
+INSTALLABLE_MODULES = $(MODULES)
# syslinux.exe is BTARGET so as to not require everyone to have the
# mingw suite installed
@@ -162,7 +162,7 @@ BOBJECTS = $(BTARGET) \
ifdef EFI_BUILD
-BSUBDIRS = codepage com32 lzo core modules mbr sample efi
+BSUBDIRS = codepage com32 lzo core mbr sample efi
ISUBDIRS = efi utils
INSTALLSUBDIRS = efi
@@ -170,7 +170,7 @@ INSTALLSUBDIRS = efi
else
BSUBDIRS = codepage com32 lzo core memdisk sample diag mbr memdump dos \
- modules gpxe libinstaller win32 win64 dosutil
+ gpxe libinstaller win32 win64 dosutil
ITARGET =
IOBJECTS = $(ITARGET) \
diff --git a/NEWS b/NEWS
index 0292c25c..37c0e545 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,9 @@ Changes in 5.00:
* ldlinux: A new "PATH" directive was added to the ldlinux.c32
config parser that specifies a colon-separated list of
directories to search when attempting to load modules.
+ * ALL: Delete all references to/code for 16-bit COMBOOT files.
+ COMBOOT files (.cbt and .com) are no longer supported under
+ Syslinux.
Changes in 4.06:
* Support for NTFS, by Paulo Alcantara.
diff --git a/README b/README
index bb1aeb65..f00fd0f7 100644
--- a/README
+++ b/README
@@ -7,7 +7,6 @@ See the files in the doc directory for documentation about SYSLINUX:
extlinux.txt - Documentation specific to EXTLINUX.
menu.txt - About the menu systems.
usbkey.txt - About using SYSLINUX on USB keys.
- comboot.txt - About the extension API.
memdisk.txt - Documentation about MEMDISK.
Also see the files:
diff --git a/com32/cmenu/libmenu/syslnx.c b/com32/cmenu/libmenu/syslnx.c
index c681f585..5060c5db 100644
--- a/com32/cmenu/libmenu/syslnx.c
+++ b/com32/cmenu/libmenu/syslnx.c
@@ -19,16 +19,6 @@
com32sys_t inreg, outreg; // Global registers for this module
-char issyslinux(void)
-{
- REG_EAX(inreg) = 0x00003000;
- REG_EBX(inreg) = REG_ECX(inreg) = REG_EDX(inreg) = 0xFFFFFFFF;
- __intcall(0x21, &inreg, &outreg);
- return (REG_EAX(outreg) == 0x59530000) &&
- (REG_EBX(outreg) == 0x4c530000) &&
- (REG_ECX(outreg) == 0x4e490000) && (REG_EDX(outreg) == 0x58550000);
-}
-
void runsyslinuxcmd(const char *cmd)
{
char *bounce;
@@ -60,43 +50,15 @@ unsigned int getversion(char *deriv, unsigned int *numfun)
return __syslinux_version.version;
}
-void runsyslinuximage(const char *cmd, long ipappend)
+char issyslinux(void)
{
- unsigned int numfun = 0;
- char *ptr, *cmdline;
- char *bounce;
+ return !!getversion(NULL, NULL);
+}
+void runsyslinuximage(const char *cmd, long ipappend)
+{
(void)ipappend; // XXX: Unused?!
- getversion(NULL, &numfun);
- // Function 16h not supported Fall back to runcommand
- if (numfun < 0x16)
- runsyslinuxcmd(cmd);
- // Try the Run Kernel Image function
- // Split command line into
- bounce = lmalloc(strlen(cmd) + 1);
- if (!bounce)
- return;
-
- strcpy(bounce, cmd);
- ptr = bounce;
- // serach for first space or end of string
- while ((*ptr) && (*ptr != ' '))
- ptr++;
- if (!*ptr)
- cmdline = ptr; // no command line
- else {
- *ptr++ = '\0'; // terminate kernal name
- cmdline = ptr + 1;
- while (*cmdline != ' ')
- cmdline++; // find first non-space
- }
- // Now call the interrupt
- REG_BX(inreg) = OFFS(cmdline);
- REG_ES(inreg) = SEG(cmdline);
- REG_SI(inreg) = OFFS(bounce);
- REG_DS(inreg) = SEG(bounce);
- REG_EDX(inreg) = 0;
-
- __intcall(0x22, &inreg, &outreg); // If successful does not return
+ getversion(NULL, NULL);
+ runsyslinuxcmd(cmd);
}
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile
index 7da6e287..aa35f475 100644
--- a/com32/elflink/ldlinux/Makefile
+++ b/com32/elflink/ldlinux/Makefile
@@ -13,18 +13,19 @@
VPATH = $(SRC)
include $(MAKEDIR)/elf.mk
-CFLAGS += -I$(topdir)/core/elflink -I$(topdir)/core/include -I$(topdir)/com32/lib
+CFLAGS += -I$(topdir)/core/elflink -I$(topdir)/core/include -I$(topdir)/com32/lib -fvisibility=hidden
LIBS = --whole-archive $(objdir)/com32/lib/libcom32min.a
OBJS = ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o adv.o \
execute.o chainboot.o kernel.o get_key.o advwrite.o setadv.o \
- eprintf.o loadhigh.o
+ eprintf.o loadhigh.o msg.o
all: ldlinux.c32 ldlinux_lnx.a
ldlinux.c32 : $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+LNXCFLAGS += -D__export='__attribute__((visibility("default")))'
LNXLIBOBJS = get_key.lo
ldlinux_lnx.a: $(LNXLIBOBJS)
rm -f $@
diff --git a/com32/elflink/ldlinux/adv.c b/com32/elflink/ldlinux/adv.c
index ae473908..677fe92d 100644
--- a/com32/elflink/ldlinux/adv.c
+++ b/com32/elflink/ldlinux/adv.c
@@ -35,8 +35,8 @@
#include <syslinux/firmware.h>
#include <klibc/compiler.h>
-void *__syslinux_adv_ptr;
-size_t __syslinux_adv_size;
+__export void *__syslinux_adv_ptr;
+__export size_t __syslinux_adv_size;
void __constructor __syslinux_init(void)
{
diff --git a/com32/elflink/ldlinux/advwrite.c b/com32/elflink/ldlinux/advwrite.c
index 95a311a8..47e45534 100644
--- a/com32/elflink/ldlinux/advwrite.c
+++ b/com32/elflink/ldlinux/advwrite.c
@@ -31,10 +31,11 @@
* Write back the ADV
*/
+#include <klibc/compiler.h>
#include <syslinux/adv.h>
#include <syslinux/firmware.h>
-int syslinux_adv_write(void)
+__export int syslinux_adv_write(void)
{
return firmware->adv_ops->write();
}
diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c
index 4a4a2e1a..ff19c530 100644
--- a/com32/elflink/ldlinux/chainboot.c
+++ b/com32/elflink/ldlinux/chainboot.c
@@ -54,10 +54,8 @@ void chainboot_file(const char *file, uint32_t type)
goto bail;
rv = open_file(file, &fd);
- if (rv == -1) {
- free(buf);
+ if (rv == -1)
goto bail;
- }
reg.eax.l = max;
reg.ebx.l = 0;
diff --git a/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c
index ebeaeece..b94c6835 100644
--- a/com32/elflink/ldlinux/cli.c
+++ b/com32/elflink/ldlinux/cli.c
@@ -119,12 +119,11 @@ static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to,
const char *edit_cmdline(const char *input, int top /*, int width */ ,
int (*pDraw_Menu) (int, int, int),
- void (*show_fkey) (int))
+ void (*show_fkey) (int), bool *timedout)
{
- static char cmdline[MAX_CMDLINE_LEN];
- char temp_cmdline[MAX_CMDLINE_LEN] = { };
+ char cmdline[MAX_CMDLINE_LEN] = { };
int key, len, prev_len, cursor;
- int redraw = 1; /* We enter with the menu already drawn */
+ int redraw = 0;
int x, y;
bool done = false;
const char *ret;
@@ -139,12 +138,17 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
width = 80;
}
- cmdline[MAX_CMDLINE_LEN - 1] = '\0';
-
len = cursor = 0;
prev_len = 0;
x = y = 0;
+ /*
+ * Before we start messing with the x,y coordinates print 'input'
+ * so that it follows whatever text has been written to the screen
+ * previously.
+ */
+ eprintf("%s ", input);
+
while (!done) {
if (redraw > 1) {
/* Clear and redraw whole screen */
@@ -154,6 +158,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
if (pDraw_Menu)
(*pDraw_Menu) (-1, top, 1);
prev_len = 0;
+ eprintf("\033[2J\033[H");
// printf("\033[0m\033[2J\033[H");
}
@@ -164,8 +169,6 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
/* Redraw the command line */
eprintf("\033[?7l\033[?25l");
- if (y)
- eprintf("\033[%dA", y);
eprintf("\033[1G%s ", input);
x = strlen(input);
@@ -202,6 +205,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
switch (key) {
case KEY_NONE:
/* We timed out. */
+ *timedout = true;
return NULL;
case KEY_CTRL('L'):
@@ -214,12 +218,6 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
done = true;
break;
- case KEY_ESC:
- case KEY_CTRL('C'):
- ret = NULL;
- done = true;
- break;
-
case KEY_BACKSPACE:
case KEY_DEL:
if (cursor) {
@@ -351,11 +349,9 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
comm_counter =
list_entry(next, typeof(*comm_counter), list);
- if (&comm_counter->list == &cli_history_head) {
- strcpy(cmdline, temp_cmdline);
- } else {
+ if (&comm_counter->list != &cli_history_head)
strcpy(cmdline, comm_counter->command);
- }
+
cursor = len = strlen(cmdline);
redraw = 1;
}
@@ -375,11 +371,9 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
comm_counter =
list_entry(prev, typeof(*comm_counter), list);
- if (&comm_counter->list == &cli_history_head) {
- strcpy(cmdline, temp_cmdline);
- } else {
+ if (&comm_counter->list != &cli_history_head)
strcpy(cmdline, comm_counter->command);
- }
+
cursor = len = strlen(cmdline);
redraw = 1;
}
@@ -435,9 +429,8 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
default:
if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) {
if (cursor == len) {
- temp_cmdline[len] = key;
cmdline[len++] = key;
- temp_cmdline[len] = cmdline[len] = '\0';
+ cmdline[len] = '\0';
putchar(key);
cursor++;
x++;
@@ -450,9 +443,6 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
} else {
memmove(cmdline + cursor + 1, cmdline + cursor,
len - cursor + 1);
- memmove(temp_cmdline + cursor + 1, temp_cmdline + cursor,
- len - cursor + 1);
- temp_cmdline[cursor] = key;
cmdline[cursor++] = key;
len++;
redraw = 1;
diff --git a/com32/elflink/ldlinux/config.h b/com32/elflink/ldlinux/config.h
index 63e33b69..c551fb19 100644
--- a/com32/elflink/ldlinux/config.h
+++ b/com32/elflink/ldlinux/config.h
@@ -48,5 +48,7 @@ extern int new_linux_kernel(char *okernel, char *ocmdline);
extern void pm_load_high(com32sys_t *regs);
extern void ldlinux_enter_command(void);
+extern void ldlinux_console_init(void);
+extern const char *apply_extension(const char *kernel, const char *ext);
#endif /* __CONFIG_H__ */
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 6ccde49d..727df50a 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -39,7 +39,6 @@ const struct image_types image_boot_types[] = {
{ "bss", IMAGE_TYPE_BSS },
{ "pxe", IMAGE_TYPE_PXE },
{ "fdimage", IMAGE_TYPE_FDIMAGE },
- { "comboot", IMAGE_TYPE_COMBOOT },
{ "com32", IMAGE_TYPE_COM32 },
{ "config", IMAGE_TYPE_CONFIG },
{ NULL, 0 },
@@ -47,7 +46,7 @@ const struct image_types image_boot_types[] = {
extern int create_args_and_load(char *);
-void execute(const char *cmdline, uint32_t type)
+__export void execute(const char *cmdline, uint32_t type)
{
const char *kernel, *args;
const char *p;
@@ -84,7 +83,17 @@ void execute(const char *cmdline, uint32_t type)
const struct image_types *t;
for (t = image_boot_types; t->name; t++) {
if (!strcmp(kernel + 1, t->name)) {
- /* Strip the type specifier and retry */
+ /*
+ * Strip the type specifier, apply the
+ * filename extension if COM32 and
+ * retry.
+ */
+ if (t->type == IMAGE_TYPE_COM32) {
+ p = apply_extension(p, ".c32");
+ if (!p)
+ return;
+ }
+
execute(p, t->type);
return;
}
@@ -92,8 +101,15 @@ void execute(const char *cmdline, uint32_t type)
}
if (type == IMAGE_TYPE_COM32) {
+ /*
+ * We may be called with the console in an unknown
+ * state, so initialise it.
+ */
+ ldlinux_console_init();
+
/* new entry for elf format c32 */
- create_args_and_load((char *)cmdline);
+ if (create_args_and_load((char *)cmdline))
+ printf("Failed to load COM32 file %s\n", kernel);
/*
* The old COM32 module code would run the module then
@@ -102,9 +118,14 @@ void execute(const char *cmdline, uint32_t type)
* e.g. from vesamenu.c32.
*/
unload_modules_since("ldlinux.c32");
+
+ /* Restore the console */
+ ldlinux_console_init();
+
ldlinux_enter_command();
} else if (type == IMAGE_TYPE_CONFIG) {
char *argv[] = { "ldlinux.c32", NULL };
+ int rv;
/* kernel contains the config file name */
realpath(ConfigName, kernel, FILENAME_MAX);
@@ -113,7 +134,8 @@ void execute(const char *cmdline, uint32_t type)
if (*args)
mangle_name(config_cwd, args);
- start_ldlinux(argv);
+ rv = start_ldlinux(argv);
+ printf("Failed to exec ldlinux.c32: %s\n", strerror(rv));
} else if (type == IMAGE_TYPE_LOCALBOOT) {
local_boot(strtoul(kernel, NULL, 0));
} else if (type == IMAGE_TYPE_PXE || type == IMAGE_TYPE_BSS ||
diff --git a/com32/elflink/ldlinux/get_key.c b/com32/elflink/ldlinux/get_key.c
index 123171ae..cece0f81 100644
--- a/com32/elflink/ldlinux/get_key.c
+++ b/com32/elflink/ldlinux/get_key.c
@@ -166,7 +166,7 @@ int raw_read(int fd, void *buf, size_t count)
extern int raw_read(int fd, void *buf, size_t count);
#endif
-int get_key(FILE * f, clock_t timeout)
+__export int get_key(FILE * f, clock_t timeout)
{
char buffer[KEY_MAXLEN];
int nc, rv;
diff --git a/com32/elflink/ldlinux/getadv.c b/com32/elflink/ldlinux/getadv.c
index 5578313e..1c27f1b8 100644
--- a/com32/elflink/ldlinux/getadv.c
+++ b/com32/elflink/ldlinux/getadv.c
@@ -36,7 +36,7 @@
#include <klibc/compiler.h>
#include <inttypes.h>
-const void *syslinux_getadv(int tag, size_t * size)
+__export const void *syslinux_getadv(int tag, size_t * size)
{
const uint8_t *p;
size_t left;
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index 59c55980..6f9f20fa 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -21,8 +21,6 @@ struct file_ext {
};
static const struct file_ext file_extensions[] = {
- { ".com", IMAGE_TYPE_COMBOOT },
- { ".cbt", IMAGE_TYPE_COMBOOT },
{ ".c32", IMAGE_TYPE_COM32 },
{ ".img", IMAGE_TYPE_FDIMAGE },
{ ".bss", IMAGE_TYPE_BSS },
@@ -46,7 +44,7 @@ static inline const char *find_command(const char *str)
return p;
}
-uint32_t parse_image_type(const char *kernel)
+__export uint32_t parse_image_type(const char *kernel)
{
const struct file_ext *ext;
const char *p;
@@ -102,7 +100,7 @@ static const char *get_extension(const char *kernel)
return NULL;
}
-static const char *apply_extension(const char *kernel, const char *ext)
+const char *apply_extension(const char *kernel, const char *ext)
{
const char *p;
char *k;
@@ -121,12 +119,15 @@ static const char *apply_extension(const char *kernel, const char *ext)
memcpy(k, kernel, len);
/* Append the extension */
- memcpy(k + len, ext, elen);
+ if (strncmp(p - elen, ext, elen)) {
+ memcpy(k + len, ext, elen);
+ len += elen;
+ }
/* Copy the rest of the command line */
- strcpy(k + len + elen, p);
+ strcpy(k + len, p);
- k[len + elen + strlen(p)] = '\0';
+ k[len + strlen(p)] = '\0';
return k;
}
@@ -138,7 +139,7 @@ static const char *apply_extension(const char *kernel, const char *ext)
* the the kernel. If we return the caller should call enter_cmdline()
* so that the user can help us out.
*/
-void load_kernel(const char *command_line)
+__export void load_kernel(const char *command_line)
{
struct menu_entry *me;
const char *cmdline;
@@ -201,28 +202,14 @@ bad_kernel:
* line.
*/
if (onerrorlen) {
- rsprintf(&cmdline, "%s %s", onerror, default_cmd);
- execute(cmdline, IMAGE_TYPE_COM32);
- }
-}
-
-static void enter_cmdline(void)
-{
- const char *cmdline;
-
- /* Enter endless command line prompt, should support "exit" */
- while (1) {
- cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file);
- printf("\n");
-
- /* return if user only press enter or we timed out */
- if (!cmdline || cmdline[0] == '\0') {
- if (ontimeoutlen)
- load_kernel(ontimeout);
- return;
- }
-
- load_kernel(cmdline);
+ me = find_label(onerror);
+ if (me)
+ rsprintf(&cmdline, "%s %s", me->cmdline, default_cmd);
+ else
+ rsprintf(&cmdline, "%s %s", onerror, default_cmd);
+
+ type = parse_image_type(cmdline);
+ execute(cmdline, type);
}
}
@@ -241,10 +228,35 @@ void ldlinux_auto_boot(void)
load_kernel(default_cmd);
}
+static void enter_cmdline(void)
+{
+ const char *cmdline;
+
+ /* Enter endless command line prompt, should support "exit" */
+ while (1) {
+ bool to = false;
+
+ if (noescape) {
+ ldlinux_auto_boot();
+ continue;
+ }
+
+ cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file, &to);
+ printf("\n");
+
+ /* return if user only press enter or we timed out */
+ if (!cmdline || cmdline[0] == '\0') {
+ if (to && ontimeoutlen)
+ load_kernel(ontimeout);
+ else
+ ldlinux_auto_boot();
+ } else
+ load_kernel(cmdline);
+ }
+}
+
void ldlinux_enter_command(void)
{
- if (noescape)
- ldlinux_auto_boot();
enter_cmdline();
}
@@ -259,14 +271,19 @@ static void __destructor close_console(void)
close(i);
}
-int main(int argc __unused, char **argv __unused)
+void ldlinux_console_init(void)
+{
+ openconsole(&dev_stdcon_r, &dev_ansiserial_w);
+}
+
+__export int main(int argc __unused, char **argv __unused)
{
const void *adv;
const char *cmdline;
size_t count = 0;
char *config_argv[2] = { NULL, NULL };
- openconsole(&dev_stdcon_r, &dev_ansiserial_w);
+ ldlinux_console_init();
if (ConfigName[0])
config_argv[0] = ConfigName;
diff --git a/com32/elflink/ldlinux/msg.c b/com32/elflink/ldlinux/msg.c
new file mode 100644
index 00000000..2efcc792
--- /dev/null
+++ b/com32/elflink/ldlinux/msg.c
@@ -0,0 +1,214 @@
+#include <com32.h>
+#include <stdio.h>
+#include <bios.h>
+#include <graphics.h>
+
+static uint8_t TextAttribute; /* Text attribute for message file */
+static uint8_t DisplayMask; /* Display modes mask */
+
+/* Routine to interpret next print char */
+static void (*NextCharJump)(uint8_t);
+
+void msg_initvars(void);
+static void msg_setfg(uint8_t data);
+static void msg_putchar(uint8_t ch);
+
+/*
+ *
+ * get_msg_file: Load a text file and write its contents to the screen,
+ * interpreting color codes.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int get_msg_file(char *filename)
+{
+ FILE *f;
+ char ch;
+
+ f = fopen(filename, "r");
+ if (!f)
+ return -1;
+
+ TextAttribute = 0x7; /* Default grey on white */
+ DisplayMask = 0x7; /* Display text in all modes */
+ msg_initvars();
+
+ /*
+ * Read the text file a byte at a time and interpret that
+ * byte.
+ */
+ while ((ch = getc(f)) != EOF) {
+ /* DOS EOF? */
+ if (ch == 0x1A)
+ break;
+
+ /*
+ * 01h = text mode
+ * 02h = graphics mode
+ */
+ UsingVGA &= 0x1;
+ UsingVGA += 1;
+
+ NextCharJump(ch); /* Do what shall be done */
+ }
+
+ fclose(f);
+ return 0;
+}
+
+static void msg_setbg(uint8_t data)
+{
+ if (unhexchar(&data) == 0) {
+ data <<= 4;
+ if (DisplayMask & UsingVGA) {
+ TextAttribute = data;
+ }
+
+ NextCharJump = msg_setfg;
+ } else {
+ TextAttribute = 0x7; /* Default attribute */
+ NextCharJump = msg_putchar;
+ }
+}
+
+static void msg_setfg(uint8_t data)
+{
+ if (unhexchar(&data) == 0) {
+ if (DisplayMask & UsingVGA) {
+ /* setbg set foreground to 0 */
+ TextAttribute |= data;
+ }
+ } else
+ TextAttribute = 0x7; /* Default attribute */
+
+ NextCharJump = msg_putchar;
+}
+
+static inline void msg_ctrl_o(void)
+{
+ NextCharJump = msg_setbg;
+}
+
+static void msg_novga(void)
+{
+ syslinux_force_text_mode();
+ msg_initvars();
+}
+
+static void msg_viewimage(void)
+{
+ FILE *f;
+
+ *VGAFilePtr = '\0'; /* Zero-terminate filename */
+
+ mangle_name(VGAFileMBuf, VGAFileBuf);
+ f = fopen(VGAFileMBuf, "r");
+ if (!f) {
+ /* Not there */
+ NextCharJump = msg_putchar;
+ return;
+ }
+
+ vgadisplayfile(f);
+ fclose(f);
+ msg_initvars();
+}
+
+/*
+ * Getting VGA filename
+ */
+static void msg_filename(uint8_t data)
+{
+ /* <LF> = end of filename */
+ if (data == 0x0A) {
+ msg_viewimage();
+ return;
+ }
+
+ /* Ignore space/control char */
+ if (data > ' ') {
+ if ((char *)VGAFilePtr < (VGAFileBuf + sizeof(VGAFileBuf)))
+ *VGAFilePtr++ = data;
+ }
+}
+
+static void msg_vga(void)
+{
+ NextCharJump = msg_filename;
+ VGAFilePtr = (uint16_t *)VGAFileBuf;
+}
+
+/* Convert ANSI colors to PC display attributes */
+static int convert_to_pcdisplay[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+static void msg_normal(uint8_t data)
+{
+ uint8_t bg, fg;
+
+ /* Write to serial port */
+ if (DisplayMask & 0x4)
+ write_serial(data);
+
+ if (!(DisplayMask & UsingVGA))
+ return; /* Not screen */
+
+ if (!(DisplayCon & 0x01))
+ return;
+
+ fg = convert_to_pcdisplay[(TextAttribute & 0x7)];
+ bg = convert_to_pcdisplay[((TextAttribute >> 4) & 0x7)];
+
+ printf("\033[");
+ if (TextAttribute & 0x40)
+ printf("1;"); /* Foreground bright */
+
+ printf("3%dm\033[", fg);
+
+ if (TextAttribute & 0x80)
+ printf("5;"); /* Foreground blink */
+
+ printf("4%dm%c\033[0m", bg, data);
+}
+
+static void msg_modectl(uint8_t data)
+{
+ data &= 0x07;
+ DisplayMask = data;
+ NextCharJump = msg_putchar;
+}
+
+static void msg_putchar(uint8_t ch)
+{
+ /* 10h to 17h are mode controls */
+ if (ch >= 0x10 && ch < 0x18) {
+ msg_modectl(ch);
+ return;
+ }
+
+ switch (ch) {
+ case 0x0F: /* ^O = color code follows */
+ msg_ctrl_o();
+ break;
+ case 0x0D: /* Ignore <CR> */
+ break;
+ case 0x19: /* <EM> = return to text mode */
+ msg_novga();
+ break;
+ case 0x18: /* <CAN> = VGA filename follows */
+ msg_vga();
+ break;
+ default:
+ msg_normal(ch);
+ break;
+ }
+}
+
+/*
+ * Subroutine to initialize variables, also needed after loading
+ * graphics file.
+ */
+void msg_initvars(void)
+{
+ /* Initialize state machine */
+ NextCharJump = msg_putchar;
+}
diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
index 2fa0641e..6a419c6d 100644
--- a/com32/elflink/ldlinux/readconfig.c
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -80,12 +80,13 @@ short includelevel = 1; //nesting level
short defaultlevel = 0; //the current level of default
short vkernel = 0; //have we seen any "label" statements?
short displaycon = 1; //conio.inc
-short nohalt = 1; //idle.inc
+extern short NoHalt; //idle.c
-const char *default_cmd = NULL; //"default" command line
const char *onerror = NULL; //"onerror" command line
const char *ontimeout = NULL; //"ontimeout" command line
+__export const char *default_cmd = NULL; //"default" command line
+
/* Empty refstring */
const char *empty_string;
@@ -599,7 +600,7 @@ uint32_t parse_argb(char **p)
//static const char *append = NULL;
extern const char *append;
//static unsigned int ipappend = 0;
-unsigned int ipappend = 0;
+__export unsigned int ipappend = 0;
extern uint16_t PXERetry;
static struct labeldata ld;
@@ -636,21 +637,7 @@ static char *is_message_name(char *cmdstr, enum message_number *msgnr)
return NULL;
}
-static int cat_file(const char *filename)
-{
- FILE *f;
- char line[2048];
-
- f = fopen(filename, "r");
- if (!f)
- return -1;
-
- while (fgets(line, sizeof(line), f) != NULL)
- eprintf("%s", line);
-
- fclose(f);
- return 0;
-}
+extern void get_msg_file(char *);
void cat_help_file(int key)
{
@@ -704,7 +691,7 @@ void cat_help_file(int key)
if (cm->fkeyhelp[fkey].textname) {
eprintf("\n");
- cat_file(cm->fkeyhelp[fkey].textname);
+ get_msg_file((char *)cm->fkeyhelp[fkey].textname);
}
}
@@ -732,7 +719,7 @@ extern uint8_t FlowInput;
extern uint8_t FlowOutput;
extern uint16_t SerialPort;
extern uint16_t BaudDivisor;
-extern uint8_t SerialNotice;
+static uint8_t SerialNotice = 1;
#define DEFAULT_BAUD 9600
#define BAUD_DIVISOR 115200
@@ -748,7 +735,6 @@ static inline void io_delay(void)
outb(0, 0x80);
}
-extern void get_msg_file(char *);
extern void loadfont(char *);
extern void loadkeys(char *);
@@ -1196,7 +1182,7 @@ do_include:
} else if (looking_at(p, "nocomplete")) {
nocomplete = atoi(skipspace(p + 10));
} else if (looking_at(p, "nohalt")) {
- nohalt = atoi(skipspace(p + 8));
+ NoHalt = atoi(skipspace(p + 8));
} else if (looking_at(p, "onerror")) {
refstr_put(m->onerror);
m->onerror = refstrdup(skipspace(p + 7));
@@ -1368,7 +1354,8 @@ static int parse_one_config(const char *filename)
parse_config_file(f);
if (config_cwd[0]) {
- chdir(config_cwd);
+ if (chdir(config_cwd) < 0)
+ printf("Failed to chdir to %s\n", config_cwd);
config_cwd[0] = '\0';
}
diff --git a/com32/elflink/ldlinux/setadv.c b/com32/elflink/ldlinux/setadv.c
index 40f00a4e..2e386213 100644
--- a/com32/elflink/ldlinux/setadv.c
+++ b/com32/elflink/ldlinux/setadv.c
@@ -45,7 +45,7 @@
#include <errno.h>
#include <alloca.h>
-int syslinux_setadv(int tag, size_t size, const void *data)
+__export int syslinux_setadv(int tag, size_t size, const void *data)
{
uint8_t *p, *advtmp;
size_t rleft, left;
diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile
index 3e2bd03d..71f335da 100644
--- a/com32/gpllib/Makefile
+++ b/com32/gpllib/Makefile
@@ -27,7 +27,7 @@ libcom32gpl.c32 : $(LIBOBJS)
$(LD) -shared $(LDFLAGS) -o $@ $^
tidy dist clean:
- find . \( -name \*.o -o -name \*.c32 -o -name .\*.d -o -name \*.tmp \) -print0 | \
+ find . \( -name \*.o -o -name .\*.d -o -name \*.tmp \) -print0 | \
xargs -0r rm -f
spotless: clean
diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c
index 7542da83..216b6bde 100644
--- a/com32/hdt/hdt-cli.c
+++ b/com32/hdt/hdt-cli.c
@@ -649,7 +649,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
if ((current_module->nomodule == true) && ( module != NULL)) {
dprintf("CLI_DEBUG exec: Reworking arguments with argc=%d\n",argc);
char **new_argv=NULL;
- new_argv=malloc((argc + 2)*sizeof(char));
+ new_argv=malloc((argc + 2)*sizeof(char *));
for (int argc_iter=0; argc_iter<argc; argc_iter++) {
dprintf("CLI_DEBUG exec rework : copy %d to %d (%s)\n",argc_iter,argc_iter+1,argv[argc_iter]);
new_argv[argc_iter+1] = malloc(strlen(argv[argc_iter]));
diff --git a/com32/include/cli.h b/com32/include/cli.h
index 513c1719..eee4576f 100644
--- a/com32/include/cli.h
+++ b/com32/include/cli.h
@@ -14,7 +14,7 @@ extern void clear_screen(void);
extern int mygetkey(clock_t timeout);
extern const char *edit_cmdline(const char *input, int top /*, int width */ ,
int (*pDraw_Menu) (int, int, int),
- void (*show_fkey) (int));
+ void (*show_fkey) (int), bool *);
extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
#endif
diff --git a/com32/include/klibc/compiler.h b/com32/include/klibc/compiler.h
index 210971f1..e8548b59 100644
--- a/com32/include/klibc/compiler.h
+++ b/com32/include/klibc/compiler.h
@@ -139,4 +139,6 @@
/* Weak symbols */
#define __weak __attribute__((weak))
+#define __export __attribute__((visibility("default")))
+
#endif
diff --git a/com32/include/menu.h b/com32/include/menu.h
index 5a4c901e..bc0182f7 100644
--- a/com32/include/menu.h
+++ b/com32/include/menu.h
@@ -87,7 +87,6 @@ enum kernel_type {
KT_BSS, /* Boot sector with patch */
KT_PXE, /* PXE NBP */
KT_FDIMAGE, /* Floppy disk image */
- KT_COMBOOT, /* COMBOOT image */
KT_COM32, /* COM32 image */
KT_CONFIG, /* Configuration file */
};
diff --git a/com32/include/stdio.h b/com32/include/stdio.h
index 902a0e80..813a0edc 100644
--- a/com32/include/stdio.h
+++ b/com32/include/stdio.h
@@ -124,9 +124,9 @@ __extern int rename(const char *, const char *);
*
* Returns 0 if 'data' was converted succesfully, -1 otherwise.
*/
-static inline int unhexchar(char *data)
+static inline int unhexchar(unsigned char *data)
{
- char num = *data;
+ unsigned char num = *data;
if (num >= '0' && num <= '9') {
*data = num - '0';
@@ -134,7 +134,7 @@ static inline int unhexchar(char *data)
} else {
num |= 0x20; /* upper case -> lower case */
if (num >= 'a' && num <= 'f') {
- *data = num - 'a' - 10;
+ *data = num - 'a' + 10;
return 0;
}
}
diff --git a/com32/include/syslinux/boot.h b/com32/include/syslinux/boot.h
index aea32d9c..74a311df 100644
--- a/com32/include/syslinux/boot.h
+++ b/com32/include/syslinux/boot.h
@@ -61,7 +61,6 @@ extern const struct image_types image_boot_types[];
#define IMAGE_TYPE_BSS 3
#define IMAGE_TYPE_PXE 4
#define IMAGE_TYPE_FDIMAGE 5
-#define IMAGE_TYPE_COMBOOT 6
#define IMAGE_TYPE_COM32 7
#define IMAGE_TYPE_CONFIG 8
#define IMAGE_TYPE_LOCALBOOT 9
diff --git a/com32/include/syslinux/features.h b/com32/include/syslinux/features.h
deleted file mode 100644
index d25d08d5..00000000
--- a/com32/include/syslinux/features.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom
- * the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall
- * be included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-#ifndef _SYSLINUX_FEATURES_H
-#define _SYSLINUX_FEATURES_H
-
-#define SYSLINUX_FEATURE_LOCAL_BOOT (0*8+0)
-#define SYSLINUX_FEATURE_NOOP_IDLE (0*8+1)
-
-extern uint8_t feature_flags;
-extern uint8_t feature_flags_len;
-
-static inline int syslinux_has_feature(unsigned int __flag)
-{
- unsigned int __byte = __flag >> 3;
- unsigned int __bit = __flag & 7;
-
- if (__byte <= feature_flags_len)
- return (feature_flags[__byte] >> __bit) & 1;
- else
- return 0;
-}
-
-#endif /* _SYSLINUX_FEATURE_H */
diff --git a/com32/lib/asprintf.c b/com32/lib/asprintf.c
index ef5b4b2f..eab20118 100644
--- a/com32/lib/asprintf.c
+++ b/com32/lib/asprintf.c
@@ -21,9 +21,10 @@ int asprintf(char **bufp, const char *format, ...)
*bufp = p = malloc(bytes);
if (!p)
- return -1;
+ rv = -1;
+ else
+ rv = vsnprintf(p, bytes, format, ap);
- rv = vsnprintf(p, bytes, format, ap);
va_end(ap);
return rv;
diff --git a/com32/lib/bufprintf.c b/com32/lib/bufprintf.c
index 939bcec3..d2812311 100644
--- a/com32/lib/bufprintf.c
+++ b/com32/lib/bufprintf.c
@@ -17,8 +17,10 @@ int vbufprintf(struct print_buf *buf, const char *format, va_list ap)
char *newbuf;
newbuf = realloc(buf->buf, newsize);
- if (!newbuf)
- return -1;
+ if (!newbuf) {
+ rv = -1;
+ goto bail;
+ }
buf->buf = newbuf;
buf->size = newsize;
@@ -26,6 +28,8 @@ int vbufprintf(struct print_buf *buf, const char *format, va_list ap)
rv = vsnprintf(buf->buf + buf->len, buf->size - buf->len, format, ap2);
buf->len += rv;
+bail:
+ va_end(ap2);
return rv;
}
diff --git a/com32/lib/free.c b/com32/lib/free.c
deleted file mode 100644
index be23865a..00000000
--- a/com32/lib/free.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * free.c
- *
- * Very simple linked-list based malloc()/free().
- */
-
-#include <stdlib.h>
-#include "malloc.h"
-
-static struct free_arena_header *__free_block(struct free_arena_header *ah)
-{
- struct free_arena_header *pah, *nah;
-
- pah = ah->a.prev;
- nah = ah->a.next;
- if (pah->a.type == ARENA_TYPE_FREE &&
- (char *)pah + pah->a.size == (char *)ah) {
- /* Coalesce into the previous block */
- pah->a.size += ah->a.size;
- pah->a.next = nah;
- nah->a.prev = pah;
-
-#ifdef DEBUG_MALLOC
- ah->a.type = ARENA_TYPE_DEAD;
-#endif
-
- ah = pah;
- pah = ah->a.prev;
- } else {
- /* Need to add this block to the free chain */
- ah->a.type = ARENA_TYPE_FREE;
-
- ah->next_free = __malloc_head.next_free;
- ah->prev_free = &__malloc_head;
- __malloc_head.next_free = ah;
- ah->next_free->prev_free = ah;
- }
-
- /* In either of the previous cases, we might be able to merge
- with the subsequent block... */
- if (nah->a.type == ARENA_TYPE_FREE &&
- (char *)ah + ah->a.size == (char *)nah) {
- ah->a.size += nah->a.size;
-
- /* Remove the old block from the chains */
- nah->next_free->prev_free = nah->prev_free;
- nah->prev_free->next_free = nah->next_free;
- ah->a.next = nah->a.next;
- nah->a.next->a.prev = ah;
-
-#ifdef DEBUG_MALLOC
- nah->a.type = ARENA_TYPE_DEAD;
-#endif
- }
-
- /* Return the block that contains the called block */
- return ah;
-}
-
-/*
- * This is used to insert a block which is not previously on the
- * free list. Only the a.size field of the arena header is assumed
- * to be valid.
- */
-void __inject_free_block(struct free_arena_header *ah)
-{
- struct free_arena_header *nah;
- size_t a_end = (size_t) ah + ah->a.size;
- size_t n_end;
-
- for (nah = __malloc_head.a.next; nah->a.type != ARENA_TYPE_HEAD;
- nah = nah->a.next) {
- n_end = (size_t) nah + nah->a.size;
-
- /* Is nah entirely beyond this block? */
- if ((size_t) nah >= a_end)
- break;
-
- /* Is this block entirely beyond nah? */
- if ((size_t) ah >= n_end)
- continue;
-
- /* Otherwise we have some sort of overlap - reject this block */
- return;
- }
-
- /* Now, nah should point to the successor block */
- ah->a.next = nah;
- ah->a.prev = nah->a.prev;
- nah->a.prev = ah;
- ah->a.prev->a.next = ah;
-
- __free_block(ah);
-}
-
-void free(void *ptr)
-{
- struct free_arena_header *ah;
-
- if (!ptr)
- return;
-
- ah = (struct free_arena_header *)
- ((struct arena_header *)ptr - 1);
-
-#ifdef DEBUG_MALLOC
- assert(ah->a.type == ARENA_TYPE_USED);
-#endif
-
- __free_block(ah);
-
- /* Here we could insert code to return memory to the system. */
-}
diff --git a/com32/lib/malloc.c b/com32/lib/malloc.c
deleted file mode 100644
index ce35f3d1..00000000
--- a/com32/lib/malloc.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * malloc.c
- *
- * Very simple linked-list based malloc()/free().
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <com32.h>
-#include <syslinux/memscan.h>
-#include "malloc.h"
-
-struct free_arena_header __malloc_head = {
- {
- ARENA_TYPE_HEAD,
- 0,
- &__malloc_head,
- &__malloc_head,
- },
- &__malloc_head,
- &__malloc_head
-};
-
-/* This is extern so it can be overridden by the user application */
-extern size_t __stack_size;
-extern void *__mem_end; /* Produced after argv parsing */
-
-static inline size_t sp(void)
-{
- size_t sp;
- asm volatile ("movl %%esp,%0":"=rm" (sp));
- return sp;
-}
-
-#define E820_MEM_MAX 0xfff00000 /* 4 GB - 1 MB */
-
-static int consider_memory_area(void *dummy, addr_t start,
- addr_t len, bool valid)
-{
- struct free_arena_header *fp;
- addr_t end;
-
- (void)dummy;
-
- if (valid && start < E820_MEM_MAX) {
- if (len > E820_MEM_MAX - start)
- len = E820_MEM_MAX - start;
-
- end = start + len;
-
- if (end > __com32.cs_memsize) {
- if (start <= __com32.cs_memsize) {
- start = __com32.cs_memsize;
- len = end - start;
- }
-
- if (len >= 2 * sizeof(struct arena_header)) {
- fp = (struct free_arena_header *)start;
- fp->a.size = len;
- __inject_free_block(fp);
- }
- }
- }
-
- return 0;
-}
-
-static void __constructor init_memory_arena(void)
-{
- struct free_arena_header *fp;
- size_t start, total_space;
-
- start = (size_t) ARENA_ALIGN_UP(__mem_end);
- total_space = sp() - start;
-
- if (__stack_size == 0 || __stack_size > total_space >> 1)
- __stack_size = total_space >> 1; /* Half for the stack, half for the heap... */
-
- if (total_space < __stack_size + 4 * sizeof(struct arena_header))
- __stack_size = total_space - 4 * sizeof(struct arena_header);
-
- fp = (struct free_arena_header *)start;
- fp->a.size = total_space - __stack_size;
-
- __inject_free_block(fp);
-
- /* Scan the memory map to look for other suitable regions */
- if (!__com32.cs_memsize)
- return; /* Old Syslinux core, can't do this... */
-
- syslinux_scan_memory(consider_memory_area, NULL);
-}
-
-static void *__malloc_from_block(struct free_arena_header *fp, size_t size)
-{
- size_t fsize;
- struct free_arena_header *nfp, *na;
-
- fsize = fp->a.size;
-
- /* We need the 2* to account for the larger requirements of a free block */
- if (fsize >= size + 2 * sizeof(struct arena_header)) {
- /* Bigger block than required -- split block */
- nfp = (struct free_arena_header *)((char *)fp + size);
- na = fp->a.next;
-
- nfp->a.type = ARENA_TYPE_FREE;
- nfp->a.size = fsize - size;
- fp->a.type = ARENA_TYPE_USED;
- fp->a.size = size;
-
- /* Insert into all-block chain */
- nfp->a.prev = fp;
- nfp->a.next = na;
- na->a.prev = nfp;
- fp->a.next = nfp;
-
- /* Replace current block on free chain */
- nfp->next_free = fp->next_free;
- nfp->prev_free = fp->prev_free;
- fp->next_free->prev_free = nfp;
- fp->prev_free->next_free = nfp;
- } else {
- /* Allocate the whole block */
- fp->a.type = ARENA_TYPE_USED;
-
- /* Remove from free chain */
- fp->next_free->prev_free = fp->prev_free;
- fp->prev_free->next_free = fp->next_free;
- }
-
- return (void *)(&fp->a + 1);
-}
-
-void *malloc(size_t size)
-{
- struct free_arena_header *fp;
-
- if (size == 0)
- return NULL;
-
- /* Add the obligatory arena header, and round up */
- size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
-
- for (fp = __malloc_head.next_free; fp->a.type != ARENA_TYPE_HEAD;
- fp = fp->next_free) {
- if (fp->a.size >= size) {
- /* Found fit -- allocate out of this block */
- return __malloc_from_block(fp, size);
- }
- }
-
- /* Nothing found... need to request a block from the kernel */
- return NULL; /* No kernel to get stuff from */
-}
diff --git a/com32/lib/realloc.c b/com32/lib/realloc.c
deleted file mode 100644
index 2969e313..00000000
--- a/com32/lib/realloc.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * realloc.c
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <minmax.h>
-
-#include "malloc.h"
-
-void *realloc(void *ptr, size_t size)
-{
- struct free_arena_header *ah, *nah;
- void *newptr;
- size_t newsize, oldsize, xsize;
-
- if (!ptr)
- return malloc(size);
-
- if (size == 0) {
- free(ptr);
- return NULL;
- }
-
- ah = (struct free_arena_header *)
- ((struct arena_header *)ptr - 1);
-
- /* Actual size of the old block */
- oldsize = ah->a.size;
-
- /* Add the obligatory arena header, and round up */
- newsize = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
-
- if (oldsize >= newsize && newsize >= (oldsize >> 2) &&
- oldsize - newsize < 4096) {
- /* This allocation is close enough already. */
- return ptr;
- } else {
- xsize = oldsize;
-
- nah = ah->a.next;
- if ((char *)nah == (char *)ah + ah->a.size &&
- nah->a.type == ARENA_TYPE_FREE &&
- oldsize + nah->a.size >= newsize) {
- /* Merge in subsequent free block */
- ah->a.next = nah->a.next;
- ah->a.next->a.prev = ah;
- nah->next_free->prev_free = nah->prev_free;
- nah->prev_free->next_free = nah->next_free;
- xsize = (ah->a.size += nah->a.size);
- }
-
- if (xsize >= newsize) {
- /* We can reallocate in place */
- if (xsize >= newsize + 2 * sizeof(struct arena_header)) {
- /* Residual free block at end */
- nah = (struct free_arena_header *)((char *)ah + newsize);
- nah->a.type = ARENA_TYPE_FREE;
- nah->a.size = xsize - newsize;
- ah->a.size = newsize;
-
- /* Insert into block list */
- nah->a.next = ah->a.next;
- ah->a.next = nah;
- nah->a.next->a.prev = nah;
- nah->a.prev = ah;
-
- /* Insert into free list */
- if (newsize > oldsize) {
- /* Hack: this free block is in the path of a memory object
- which has already been grown at least once. As such, put
- it at the *end* of the freelist instead of the beginning;
- trying to save it for future realloc()s of the same block. */
- nah->prev_free = __malloc_head.prev_free;
- nah->next_free = &__malloc_head;
- __malloc_head.prev_free = nah;
- nah->prev_free->next_free = nah;
- } else {
- nah->next_free = __malloc_head.next_free;
- nah->prev_free = &__malloc_head;
- __malloc_head.next_free = nah;
- nah->next_free->prev_free = nah;
- }
- }
- /* otherwise, use up the whole block */
- return ptr;
- } else {
- /* Last resort: need to allocate a new block and copy */
- oldsize -= sizeof(struct arena_header);
- newptr = malloc(size);
- if (newptr) {
- memcpy(newptr, ptr, min(size, oldsize));
- free(ptr);
- }
- return newptr;
- }
- }
-}
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 50b8a9f6..5b0d9ee8 100644
--- a/com32/lib/sys/module/common.c
+++ b/com32/lib/sys/module/common.c
@@ -71,15 +71,19 @@ FILE *findpath(char *name)
p = PATH;
again:
i = 0;
- while (*p && *p != ':' && i < FILENAME_MAX) {
+ while (*p && *p != ':' && i < FILENAME_MAX - 1) {
path[i++] = *p++;
}
if (*p == ':')
p++;
+ /* Ensure we have a '/' separator */
+ if (path[i] != '/' && i < FILENAME_MAX - 1)
+ path[i++] = '/';
+
n = name;
- while (*n && i < FILENAME_MAX)
+ while (*n && i < FILENAME_MAX - 1)
path[i++] = *n++;
path[i] = '\0';
diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c
index 4ee296c4..0d27c92b 100644
--- a/com32/lib/sys/module/elf_module.c
+++ b/com32/lib/sys/module/elf_module.c
@@ -98,13 +98,6 @@ static int prepare_dynlinking(struct elf_module *module) {
dyn_entry++;
}
- // Now compute the number of symbols in the symbol table
- if (module->ghash_table != NULL) {
- module->symtable_size = module->ghash_table[1];
- } else {
- module->symtable_size = module->hash_table[1];
- }
-
return 0;
}
@@ -191,6 +184,7 @@ int module_load(struct elf_module *module) {
Elf_Sym *main_sym;
Elf_Ehdr elf_hdr;
module_ctor_t *ctor;
+ struct elf_module *head = NULL;
// Do not allow duplicate modules
if (module_find(module->name) != NULL) {
@@ -224,6 +218,8 @@ int module_load(struct elf_module *module) {
CHECKED(res, prepare_dynlinking(module), error);
//printf("check... 4\n");
+ head = list_entry((&modules_head)->next, typeof(*head), list);
+
/* Find modules we need to load as dependencies */
if (module->str_table) {
int i;
@@ -249,7 +245,11 @@ int module_load(struct elf_module *module) {
p = dep;
argv[0] = p;
- spawn_load(p, 1, argv);
+ res = spawn_load(p, 1, argv);
+ if (res < 0) {
+ printf("Failed to load %s\n", p);
+ goto error;
+ }
}
}
@@ -294,6 +294,9 @@ int module_load(struct elf_module *module) {
return 0;
error:
+ if (head)
+ unload_modules_since(head->name);
+
// Remove the module from the module list (if applicable)
list_del_init(&module->list);
diff --git a/com32/lib/sys/module/exec.c b/com32/lib/sys/module/exec.c
index 29d0a2fd..559bafc7 100644
--- a/com32/lib/sys/module/exec.c
+++ b/com32/lib/sys/module/exec.c
@@ -194,8 +194,10 @@ int spawn_load(const char *name, int argc, char **argv)
return -1;
if (get_module_type(module) == EXEC_MODULE) {
- if (!argc || !argv || strcmp(argv[0], name))
- return -1;
+ if (!argc || !argv || strcmp(argv[0], name)) {
+ res = -1;
+ goto out;
+ }
}
if (!strcmp(cur_module->name, module->name)) {
@@ -218,10 +220,8 @@ int spawn_load(const char *name, int argc, char **argv)
}
res = module_load(module);
- if (res != 0) {
- _module_unload(module);
- return res;
- }
+ if (res != 0)
+ goto out;
type = get_module_type(module);
prev_module = cur_module;
@@ -259,14 +259,14 @@ int spawn_load(const char *name, int argc, char **argv)
cur_module = prev_module;
res = module_unload(module);
- if (res != 0) {
- return res;
- }
-
- return ((unsigned int)ret_val & 0xFF);
+ if (res != 0)
+ goto out;
}
- return 0;
+out:
+ if (res)
+ _module_unload(module);
+ return res;
}
void exec_term(void)
diff --git a/com32/lib/sys/module/i386/elf_module.c b/com32/lib/sys/module/i386/elf_module.c
index d0eb1a8e..a3792554 100644
--- a/com32/lib/sys/module/i386/elf_module.c
+++ b/com32/lib/sys/module/i386/elf_module.c
@@ -30,7 +30,9 @@ int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) {
int i;
int res = 0;
char *pht = NULL;
+ char *sht = NULL;
Elf32_Phdr *cr_pht;
+ Elf32_Shdr *cr_sht;
Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr
Elf32_Addr max_addr = 0x00000000; // Max. ELF vaddr
@@ -142,6 +144,25 @@ int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) {
}
}
+ // Get to the SHT
+ image_seek(elf_hdr->e_shoff, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Setup the symtable size
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ cr_sht = (Elf32_Shdr*)(sht + i * elf_hdr->e_shentsize);
+
+ if (cr_sht->sh_type == SHT_DYNSYM) {
+ module->symtable_size = cr_sht->sh_size;
+ break;
+ }
+ }
+
+ free(sht);
+
// Setup dynamic segment location
module->dyn_table = module_get_absolute(dyn_addr, module);
diff --git a/com32/lib/sys/module/x86_64/elf_module.c b/com32/lib/sys/module/x86_64/elf_module.c
index 9300f989..64404a17 100644
--- a/com32/lib/sys/module/x86_64/elf_module.c
+++ b/com32/lib/sys/module/x86_64/elf_module.c
@@ -30,7 +30,9 @@ int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) {
int i;
int res = 0;
char *pht = NULL;
+ char *sht = NULL;
Elf64_Phdr *cr_pht;
+ Elf64_Shdr *cr_sht;
Elf64_Addr min_addr = 0x0000000000000000; // Min. ELF vaddr
Elf64_Addr max_addr = 0x0000000000000000; // Max. ELF vaddr
@@ -142,6 +144,25 @@ int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) {
}
}
+ // Get to the SHT
+ image_seek(elf_hdr->e_shoff, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Setup the symtable size
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ cr_sht = (Elf64_Shdr*)(sht + i * elf_hdr->e_shentsize);
+
+ if (cr_sht->sh_type == SHT_DYNSYM) {
+ module->symtable_size = cr_sht->sh_size;
+ break;
+ }
+ }
+
+ free(sht);
+
// Setup dynamic segment location
module->dyn_table = module_get_absolute(dyn_addr, module);
diff --git a/com32/lib/sys/screensize.c b/com32/lib/sys/screensize.c
index 340227cd..bcd4496c 100644
--- a/com32/lib/sys/screensize.c
+++ b/com32/lib/sys/screensize.c
@@ -14,7 +14,7 @@ int getscreensize(int fd, int *rows, int *cols)
*rows = fp->o.rows;
*cols = fp->o.cols;
- if (!rows || !cols) {
+ if (!*rows || !*cols) {
errno = ENOTTY;
return -1;
}
diff --git a/com32/lib/sys/vesa/background.c b/com32/lib/sys/vesa/background.c
index 93577461..15e90895 100644
--- a/com32/lib/sys/vesa/background.c
+++ b/com32/lib/sys/vesa/background.c
@@ -205,7 +205,6 @@ static int read_jpeg_file(FILE * fp, uint8_t * header, int len)
unsigned int bytes_per_row[1];
rv = floadfile(fp, &jpeg_file, &length_of_file, header, len);
- fclose(fp);
if (rv)
goto err;
diff --git a/com32/lib/syslinux/runimage.c b/com32/lib/syslinux/runimage.c
index 4391114c..d3db75f3 100644
--- a/com32/lib/syslinux/runimage.c
+++ b/com32/lib/syslinux/runimage.c
@@ -42,26 +42,22 @@ extern unsigned int ipappend;
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type)
{
- char *bbfilename = NULL;
char *bbcmdline = NULL;
+ size_t len;
+ int rv;
-
- bbfilename = lstrdup(filename);
- if (!bbfilename)
- goto fail;
-
- bbcmdline = lstrdup(cmdline);
+ /* +2 for NULL and space */
+ len = strlen(filename) + strlen(cmdline) + 2;
+ bbcmdline = malloc(len);
if (!bbcmdline)
- goto fail;
+ return;
+
+ rv = snprintf(bbcmdline, len, "%s %s", filename, cmdline);
+ if (rv == -1 || (size_t)rv >= len)
+ return;
if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
ipappend = ipappend_flags;
- execute(bbfilename, type);
-
-fail:
- if (bbcmdline)
- lfree(bbcmdline);
- if (bbfilename)
- lfree(bbfilename);
+ execute(bbcmdline, type);
}
diff --git a/com32/lib/zalloc.c b/com32/lib/zalloc.c
deleted file mode 100644
index 0e6ed28d..00000000
--- a/com32/lib/zalloc.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * zalloc.c
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-void *zalloc(size_t size)
-{
- void *ptr;
-
- ptr = malloc(size);
- if (ptr)
- memset(ptr, 0, size);
-
- return ptr;
-}
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index 487f8299..dc99da6e 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -1110,7 +1110,7 @@ int main(int argc, char *argv[])
{
const char *cmdline;
struct menu *m;
- int rows, cols, cursorrow;
+ int rows, cols;
int i;
(void)argc;
@@ -1152,15 +1152,11 @@ int main(int argc, char *argv[])
local_cursor_enable(true);
cmdline = run_menu();
- if (clearmenu) {
+ if (clearmenu)
clear_screen();
- cursorrow = 1;
- } else {
- cursorrow = END_ROW;
- }
local_cursor_enable(false);
- printf("\033[?25h\033[%d;1H\033[0m", cursorrow);
+ printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
if (cmdline) {
uint32_t type = parse_image_type(cmdline);
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index 3690e480..dd6d5f91 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -35,7 +35,7 @@ struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
/* These are global parameters regardless of which menu we're displaying */
int shiftkey = 0; /* Only display menu if shift key pressed */
int hiddenmenu = 0;
-int clearmenu = 1;
+int clearmenu = 0;
long long totaltimeout = 0;
const char *hide_key[KEY_MAX];
@@ -189,9 +189,6 @@ static struct menu *new_menu(struct menu *parent,
m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
m->menu_background = refstr_get(parent->menu_background);
- refstr_put(m->title);
- m->title = refstr_get(parent->title);
-
m->color_table = copy_color_table(parent->color_table);
for (i = 0; i < 12; i++) {
@@ -749,8 +746,6 @@ static void parse_config_file(FILE * f)
refstr_put(command);
} else if ((ep = looking_at(p, "clear"))) {
clearmenu = 1;
- } else if ((ep = looking_at(p, "noclear"))) {
- clearmenu = 0;
} else if ((ep = is_message_name(p, &msgnr))) {
refstr_put(m->messages[msgnr]);
m->messages[msgnr] = refstrdup(skipspace(ep));
diff --git a/com32/sysdump/README b/com32/sysdump/README
index 2b825775..7d10e32b 100644
--- a/com32/sysdump/README
+++ b/com32/sysdump/README
@@ -1,4 +1,4 @@
-This is a very simple COMBOOT program which can be used to dump memory
+This is a very simple COM32 program which can be used to dump memory
regions over a serial port. To use it, type on the SYSLINUX command
line:
diff --git a/core/bios.c b/core/bios.c
index 5b4a8cef..7b41f398 100644
--- a/core/bios.c
+++ b/core/bios.c
@@ -462,6 +462,9 @@ struct vesa_ops bios_vesa_ops = {
static uint32_t min_lowmem_heap = 65536;
extern char __lowmem_heap[];
uint8_t KbdFlags; /* Check for keyboard escapes */
+__export uint8_t KbdMap[256]; /* Keyboard map */
+
+__export uint16_t PXERetry;
static inline void check_escapes(void)
{
diff --git a/core/bios.inc b/core/bios.inc
index 33a3cd4c..2e150594 100644
--- a/core/bios.inc
+++ b/core/bios.inc
@@ -18,7 +18,6 @@
%ifndef _BIOS_INC
%define _BIOS_INC
- global BIOS_fbm, BIOS_timer
; Interrupt vectors
absolute 4*1Ch
diff --git a/core/call16.c b/core/call16.c
index 0943a721..471aef96 100644
--- a/core/call16.c
+++ b/core/call16.c
@@ -20,7 +20,7 @@
#include <stdio.h>
#include "core.h"
-const com32sys_t zero_regs; /* Common all-zero register set */
+__export const com32sys_t zero_regs; /* Common all-zero register set */
static inline uint32_t eflags(void)
{
@@ -38,7 +38,8 @@ static inline uint32_t eflags(void)
return v;
}
-void call16(void (*func)(void), const com32sys_t *ireg, com32sys_t *oreg)
+__export void call16(void (*func)(void), const com32sys_t *ireg,
+ com32sys_t *oreg)
{
com32sys_t xreg = *ireg;
diff --git a/core/callback.inc b/core/callback.inc
index d98d8008..454b4522 100644
--- a/core/callback.inc
+++ b/core/callback.inc
@@ -37,12 +37,12 @@
; - Return segment (== real mode cs == 0)
; - Return flags
;
- global core_farcall
+ global core_farcall:function hidden
core_farcall:
mov eax,[esp+1*4] ; CS:IP
jmp core_syscall
- global core_intcall
+ global core_intcall:function hidden
core_intcall:
movzx eax,byte [esp+1*4] ; INT number
mov eax,[eax*4] ; Get CS:IP from low memory
@@ -142,7 +142,7 @@ core_syscall:
; followed by the return CS:IP and the CS:IP of the target function.
; The value of IF is copied from the calling routine.
;
- global core_cfarcall
+ global core_cfarcall:function hidden
core_cfarcall:
pushfd ; Save IF among other things...
push ebx
diff --git a/core/cleanup.c b/core/cleanup.c
index 4abefcd0..de318d98 100644
--- a/core/cleanup.c
+++ b/core/cleanup.c
@@ -47,7 +47,7 @@ void bios_cleanup_hardware(void)
*
* Shut down anything transient.
*/
-void cleanup_hardware(void)
+__export void cleanup_hardware(void)
{
firmware->cleanup();
}
diff --git a/core/com32.inc b/core/com32.inc
index 929f50ec..9c565f1d 100644
--- a/core/com32.inc
+++ b/core/com32.inc
@@ -40,7 +40,7 @@ com32_entry equ free_high_memory
;
; Danger, Will Robinson: it's not clear the use of
; core_xfer_buf is safe here.
- global __entry_esp, __com32
+ global __com32:data hidden
alignz 4
__entry_esp:
dd 0 ; Dummy to avoid _exit issues
diff --git a/core/comboot.inc b/core/comboot.inc
index fcd6c756..3197c8a7 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -95,7 +95,7 @@ comboot_setup_api:
; Restore the original state of the COMBOOT API vectors, and free
; any low memory allocated by the comboot module.
;
- global comboot_cleanup_api
+ global comboot_cleanup_api:function hidden
comboot_cleanup_api:
pusha
mov si,DOSSaveVectors
@@ -114,7 +114,7 @@ DOSSaveVectors resd 32
comboot_vectors:
dw comboot_return ; INT 20 = exit
- dw comboot_int21 ; INT 21 = DOS-compatible system calls
+ dw comboot_err(21h) ; INT 21 = DOS-compatible system calls
dw comboot_int22 ; INT 22 = native system calls
dw comboot_err(23h) ; INT 23 = DOS Ctrl-C handler
dw comboot_err(24h) ; INT 24 = DOS critical error handler
@@ -148,31 +148,6 @@ comboot_vectors:
section .text16
-; INT 21h: generic DOS system call
-comboot_int21: sti
- push ds
- push es
- push fs
- push gs
- pushad
- cld
- mov bp,cs
- mov ds,bp
- mov es,bp
- mov bp,sp ; Set up stack frame
-
- pm_call pm_adjust_screen ; The COMBOOT program might hav changed the screen
-
- mov cx,int21_count
- mov si,int21_table
-.again: lodsb
- cmp al,P_AH
- lodsw
- loopne .again
- ; The last function in the list is the
- ; "no such function" function
- clc
- call ax ; Call the invoked function
comboot_resume:
mov bp,sp ; In case the function clobbers BP
setc P_FLAGSL ; Propagate CF->error
@@ -212,7 +187,7 @@ comboot_bogus_tail:
jmp kaboom
; Proper return vector
-; Note: this gets invoked both via INT 21h and directly via INT 20h.
+; Note: this gets invoked directly via INT 20h.
; We don't need to cld explicitly here, because comboot_exit does that
; when invoking RESET_STACK_AND_SEGS.
comboot_return:
@@ -367,348 +342,36 @@ comapi_err:
ret
;
-; INT 22h AX=0001h Get SYSLINUX version
+; INT 22h AX=001Ch Get pointer to auxillary data vector
;
-comapi_get_version:
- ; Number of API functions supported
- mov P_AX,int22_count
- ; SYSLINUX version
- mov P_CX,(VERSION_MAJOR << 8)+VERSION_MINOR
- ; SYSLINUX derivative ID byte
- mov P_DX,my_id
- ; For future use
- mov P_BX,cs ; cs == 0
-
+comapi_getadv:
mov P_ES,ds
- ; ES:SI -> version banner
- mov P_SI,syslinux_banner + 2 ; Skip leading CR LF
- ; ES:DI -> copyright string
- mov P_DI,copyright_str + 1 ; Skip leading space
-
-comapi_nop:
- clc
- ret
-
-;
-; INT 22h AX=0002h Write string
-;
-; Write null-terminated string in ES:BX
-;
-comapi_writestr:
- mov ds,P_ES
- mov si,P_BX
- pm_call pm_writestr
- clc
- ret
-
-;
-; INT 22h AX=0003h Run command
-;
-; Terminates the COMBOOT program and executes the command line in
-; ES:BX as if it had been entered by the user.
-;
-comapi_run:
- mov es,P_ES
- mov bx,P_BX
- pm_call pm_env32_run
- ret
-
-;
-; INT 22h AX=0004h Run default command
-;
-; Terminates the COMBOOT program and executes the default command line
-; as if a timeout had happened or the user pressed <Enter>.
-;
-comapi_run_default:
- push auto_boot
- jmp comboot_exit
-
-;
-; INT 22h AX=0005h Force text mode
-;
-; Puts the video in standard text mode
-;
-comapi_textmode:
- pm_call syslinux_force_text_mode
- clc
- ret
-
-;
-; INT 22h AX=0006h Open file
-;
-comapi_open:
- mov es,P_ES
- mov si,P_SI
- pm_call pm_open_file
- mov P_EAX,eax
- mov P_CX,cx
- mov P_SI,si
- ret
-
-;
-; INT 22h AX=0007h Read file
-;
-comapi_read:
- mov es,P_ES
- mov bx,P_BX
- mov si,P_SI
- mov cx,P_CX
- pm_call getfssec
- jnc .noteof
- xor si,si ; SI <- 0 on EOF, CF <- 0
-.noteof: mov P_SI,si
- mov P_ECX,ecx
- ret
-
-;
-; INT 22h AX=0008h Close file
-;
-comapi_close:
- mov si,P_SI
- pm_call pm_close_file
- clc
- ret
-
-;
-; INT 22h AX=0009h Call PXE stack
-;
-%if IS_PXELINUX
-comapi_pxecall:
- mov bx,P_BX
- mov es,P_ES
- mov di,P_DI
- call pxenv
- mov ax,[PXEStatus]
- mov P_AX,ax
+ mov P_BX,adv0.data
+ mov P_CX,ADV_LEN
ret
-%else
-comapi_pxecall equ comapi_err ; Not available
-%endif
;
-; INT 22h AX=000Bh Get Serial Console Configuration
+; INT 22h AX=001Dh Write auxillary data vector
;
-comapi_serialcfg:
- pm_call pm_serialcfg
- mov P_DX,ax
- mov P_CX,cx
- mov P_BX,bx
- clc
- ret
+comapi_writeadv equ adv_write
;
-; INT 22h AX=000Ch Perform final cleanup
+; INT 22h AX=0024h Cleanup, shuffle and boot raw
;
-comapi_cleanup:
+comapi_shufraw:
%if IS_PXELINUX
; Unload PXE if requested
test dl,3
setnz [KeepPXE]
- sub bp,sp ; unload_pxe may move the stack around
+ sub bp,sp ; unload_pxe may move the stack around
pm_call unload_pxe
- add bp,sp ; restore frame pointer...
+ add bp,sp ; restore frame pointer...
%elif IS_SYSLINUX || IS_EXTLINUX
; Restore original FDC table
mov eax,[OrigFDCTabPtr]
mov [fdctab],eax
%endif
pm_call cleanup_hardware
- clc
- ret
-
-;
-; INT 22h AX=000Dh Obsolete
-;
-
-;
-; INT 22h AX=000Eh Get configuration file name
-;
-comapi_configfile:
- mov P_ES,cs
- mov P_BX,ConfigName
- clc
- ret
-
-;
-; INT 22h AX=000Fh Get IPAPPEND strings
-;
-comapi_ipappend:
- mov P_ES,cs
- mov P_CX,numIPAppends
- mov P_BX,IPAppends
- clc
- ret
-
-;
-; INT 22h AX=0010h Resolve hostname
-;
-%if IS_PXELINUX
- extern pm_pxe_dns_resolv
-comapi_dnsresolv:
- mov ds,P_ES
- mov si,P_BX
- pm_call pm_pxe_dns_resolv
- mov P_EAX,eax
- clc
- ret
-%else
-comapi_dnsresolv equ comapi_err
-%endif
-
- section .text16
-
-;
-; INT 22h AX=0011h Obsolete
-;
-
-;
-; INT 22h AX=0012h Obsolete
-;
-
-;
-; INT 22h AX=0013h Idle call
-;
-comapi_idle:
- call do_idle
- clc
- ret
-
-;
-; INT 22h AX=0014h Local boot
-;
-comapi_localboot:
- mov ax,P_DX
- pm_call pm_local_boot
- ret
-
-;
-; INT 22h AX=0015h Feature flags
-;
-comapi_features:
- mov P_ES,cs
- mov P_BX,feature_flags
- mov P_CX,feature_flags_len
- clc
- ret
-
-;
-; INT 22h AX=0016h Run kernel image
-;
-comapi_runkernel:
- ret
-
-;
-; INT 22h AX=0017h Report video mode change
-;
-comapi_usingvga:
- mov ax,P_BX
- cmp ax,0Fh ; Unknown flags = failure
- ja .error
- mov cx,P_CX
- mov dx,P_DX
- pm_call pm_using_vga
- clc
- ret
-.error:
- stc
- ret
-
-;
-; INT 22h AX=0018h Query custom font
-;
-comapi_userfont:
- mov al,[UserFont]
- and al,al
- jz .done
- mov al,[VGAFontSize]
- pm_call pm_userfont
- mov P_ES,es
- mov P_BX,bx
-
-.done: ; CF=0 here
- mov P_AL,al
- ret
-
-;
-; INT 22h AX=0019h Read disk
-;
-%if IS_SYSLINUX || IS_ISOLINUX || IS_EXTLINUX
-comapi_readdisk:
- cmp P_EDI,0 ; Reserved for future expansion
- jnz .err
- mov eax,P_EDX
- mov edx,P_ESI
- mov es,P_ES
- mov bx,P_BX
- mov bp,P_CX ; WE CANNOT use P_* after touching bp!
- call getlinsec
- clc
- ret
-.err:
- stc
- ret
-%else
-comapi_readdisk equ comapi_err
-%endif
-
-;
-; INT 22h AX=001Ah Obsolete
-;
-
-;
-; INT 22h AX=001Bh Obsolete
-;
-
-;
-; INT 22h AX=001Ch Get pointer to auxillary data vector
-;
-comapi_getadv:
- mov P_ES,ds
- mov P_BX,adv0.data
- mov P_CX,ADV_LEN
- ret
-
-;
-; INT 22h AX=001Dh Write auxillary data vector
-;
-comapi_writeadv equ adv_write
-
-;
-; INT 22h AX=001Eh Keyboard remapping table
-comapi_kbdtable:
- cmp P_DX,0
- jne .err
- mov P_AX,1 ; Version
- mov P_CX,256 ; Length
- mov P_ES,cs
- mov P_BX,KbdMap
- ret
-.err:
- stc
- ret
-
-;
-; INT 22h AX=001Fh Get current working directory
-;
-comapi_getcwd:
- mov P_ES,cs
- mov P_BX,CurrentDirName
- clc
- ret
-
-;
-; INT 22h AX=0023h Query shuffler size
-;
-comapi_shufsize:
- ; +15 is padding to guarantee alignment
- mov P_CX,__bcopyxx_len + 15
- ret
-
-;
-; INT 22h AX=0024h Cleanup, shuffle and boot raw
-;
-comapi_shufraw:
- call comapi_cleanup
mov edi,P_EDI
mov esi,P_ESI
mov ecx,P_ECX
@@ -723,62 +386,44 @@ comapi_initadv:
section .data16
-%macro int21 2
- db %1
- dw %2
-%endmacro
-
-int21_table:
- int21 00h, comboot_return
- int21 01h, comboot_getkey
- int21 02h, comboot_writechr
- int21 04h, comboot_writeserial
- int21 08h, comboot_getkeynoecho
- int21 09h, comboot_writestr
- int21 0Bh, comboot_checkkey
- int21 30h, comboot_checkver
- int21 4Ch, comboot_return
- int21 -1, comboot_bad_int21
-int21_count equ ($-int21_table)/3
-
alignz 2
int22_table:
dw comapi_err ; 0000 unimplemented syscall
- dw comapi_get_version ; 0001 get SYSLINUX version
- dw comapi_writestr ; 0002 write string
- dw comapi_run ; 0003 run specified command
- dw comapi_run_default ; 0004 run default command
- dw comapi_textmode ; 0005 force text mode
- dw comapi_open ; 0006 open file
- dw comapi_read ; 0007 read file
- dw comapi_close ; 0008 close file
- dw comapi_pxecall ; 0009 call PXE stack
+ dw comapi_err ; 0001 get SYSLINUX version
+ dw comapi_err ; 0002 write string
+ dw comapi_err ; 0003 run specified command
+ dw comapi_err ; 0004 run default command
+ dw comapi_err ; 0005 force text mode
+ dw comapi_err ; 0006 open file
+ dw comapi_err ; 0007 read file
+ dw comapi_err ; 0008 close file
+ dw comapi_err ; 0009 call PXE stack
dw comapi_err ; 000A derivative-specific info
- dw comapi_serialcfg ; 000B get serial port config
- dw comapi_cleanup ; 000C perform final cleanup
+ dw comapi_err ; 000B get serial port config
+ dw comapi_err ; 000C perform final cleanup
dw comapi_err ; 000D clean up then bootstrap
- dw comapi_configfile ; 000E get name of config file
- dw comapi_ipappend ; 000F get ipappend strings
- dw comapi_dnsresolv ; 0010 resolve hostname
+ dw comapi_err ; 000E get name of config file
+ dw comapi_err ; 000F get ipappend strings
+ dw comapi_err ; 0010 resolve hostname
dw comapi_err ; 0011 maximum shuffle descriptors
dw comapi_err ; 0012 cleanup, shuffle and boot
- dw comapi_idle ; 0013 idle call
- dw comapi_localboot ; 0014 local boot
- dw comapi_features ; 0015 feature flags
- dw comapi_runkernel ; 0016 run kernel image
- dw comapi_usingvga ; 0017 report video mode change
- dw comapi_userfont ; 0018 query custom font
- dw comapi_readdisk ; 0019 read disk
+ dw comapi_err ; 0013 idle call
+ dw comapi_err ; 0014 local boot
+ dw comapi_err ; 0015 feature flags
+ dw comapi_err ; 0016 run kernel image
+ dw comapi_err ; 0017 report video mode change
+ dw comapi_err ; 0018 query custom font
+ dw comapi_err ; 0019 read disk
dw comapi_err ; 001A cleanup, shuffle and boot to pm
dw comapi_err ; 001B cleanup, shuffle and boot to rm
dw comapi_getadv ; 001C get pointer to ADV
dw comapi_writeadv ; 001D write ADV to disk
- dw comapi_kbdtable ; 001E keyboard remapping table
- dw comapi_getcwd ; 001F get current working directory
+ dw comapi_err ; 001E keyboard remapping table
+ dw comapi_err ; 001F get current working directory
dw comapi_err ; 0020 open directory
dw comapi_err ; 0021 read directory
dw comapi_err ; 0022 close directory
- dw comapi_shufsize ; 0023 query shuffler size
+ dw comapi_err ; 0023 query shuffler size
dw comapi_shufraw ; 0024 cleanup, shuffle and boot raw
dw comapi_initadv ; 0025 initialize adv structure
int22_count equ ($-int22_table)/2
@@ -788,32 +433,14 @@ APIKeyFlag db 0
zero_string db 0 ; Empty, null-terminated string
-;
-; This is the feature flag array for INT 22h AX=0015h
-;
-; Note: PXELINUX clears the idle is noop flag if appropriate
-; in pxe_detect_nic_type
-;
- global feature_flags, feature_flags_len
-feature_flags:
- db 1 ; Have local boot, idle is not noop
-feature_flags_len equ ($-feature_flags)
-
err_notdos db ': attempted DOS system call INT ',0
err_comlarge db 'COMBOOT image too large.', CR, LF, 0
- global VGAFontSize, UserFont
- alignz 2
-VGAFontSize dw 16 ; Defaults to 16 byte font
-UserFont db 0 ; Using a user-specified font
-
section .bss16
alignb 4
DOSErrTramp resd 33 ; Error trampolines
- global ConfigName
-ConfigName resb FILENAME_MAX
%ifndef HAVE_CURRENTDIRNAME
- global CurrentDirName
+ global CurrentDirName:data hidden
CurrentDirName resb FILENAME_MAX
%endif
diff --git a/core/conio.c b/core/conio.c
index d34c9cf2..a351fd14 100644
--- a/core/conio.c
+++ b/core/conio.c
@@ -38,30 +38,21 @@ union screen _screensize;
/*
* Serial console stuff.
*/
-uint16_t SerialPort = 0; /* Serial port base (or 0 for no serial port) */
-uint16_t BaudDivisor = 115200/9600; /* Baud rate divisor */
-uint8_t FlowOutput = 0; /* Output to assert for serial flow */
-uint8_t FlowInput = 0; /* Input bits for serial flow */
-uint8_t FlowIgnore = 0; /* Ignore input unless these bits set */
+__export uint16_t SerialPort = 0; /* Serial port base (or 0 for no serial port) */
+__export uint8_t FlowInput = 0; /* Input bits for serial flow */
+__export uint16_t BaudDivisor = 115200/9600; /* Baud rate divisor */
+__export uint8_t FlowIgnore = 0; /* Ignore input unless these bits set */
+__export uint16_t DisplayCon = 0x01; /* Display console enabled */
+__export uint8_t FlowOutput = 0; /* Output to assert for serial flow */
uint8_t ScrollAttribute = 0x07; /* Grey on white (normal text color) */
-uint16_t DisplayCon = 0x01; /* Display console enabled */
-static uint8_t TextAttribute; /* Text attribute for message file */
-static uint8_t DisplayMask; /* Display modes mask */
-
-/* Routine to interpret next print char */
-static void (*NextCharJump)(char);
-
-void msg_initvars(void);
-static void msg_setfg(char data);
-static void msg_putchar(char ch);
/*
* loadkeys: Load a LILO-style keymap
*
* Returns 0 on success, or -1 on error.
*/
-int loadkeys(char *filename)
+__export int loadkeys(char *filename)
{
FILE *f;
@@ -76,53 +67,10 @@ int loadkeys(char *filename)
}
/*
- *
- * get_msg_file: Load a text file and write its contents to the screen,
- * interpreting color codes.
- *
- * Returns 0 on success, -1 on failure.
- */
-int get_msg_file(char *filename)
-{
- FILE *f;
- char ch;
-
- f = fopen(filename, "r");
- if (!f)
- return -1;
-
- TextAttribute = 0x7; /* Default grey on white */
- DisplayMask = 0x7; /* Display text in all modes */
- msg_initvars();
-
- /*
- * Read the text file a byte at a time and interpret that
- * byte.
- */
- while ((ch = getc(f)) != EOF) {
- /* DOS EOF? */
- if (ch == 0x1A)
- break;
-
- /*
- * 01h = text mode
- * 02h = graphics mode
- */
- UsingVGA &= 0x1;
- UsingVGA += 1;
-
- NextCharJump(ch); /* Do what shall be done */
- }
-
- fclose(f);
- return 0;
-}
-
-/*
* write_serial: If serial output is enabled, write character on
* serial port.
*/
-void write_serial(char data)
+__export void write_serial(char data)
{
if (!SerialPort)
return;
@@ -179,16 +127,10 @@ void pm_serialcfg(com32sys_t *regs)
serialcfg(&regs->eax.w[0], &regs->ecx.w[0], &regs->ebx.w[0]);
}
-static void write_serial_displaymask(char data)
-{
- if (DisplayMask & 0x4)
- write_serial(data);
-}
-
/*
* write_serial_str: write_serial for strings
*/
-void write_serial_str(char *data)
+__export void write_serial_str(char *data)
{
char ch;
@@ -197,15 +139,6 @@ void write_serial_str(char *data)
}
/*
- * write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
- */
-static void write_serial_str_displaymask(char *data)
-{
- if (DisplayMask & 0x4)
- write_serial_str(data);
-}
-
-/*
* pollchar: check if we have an input character pending
*
* Returns 1 if character pending.
@@ -250,7 +183,7 @@ int bios_pollchar(void)
return data;
}
-int pollchar(void)
+__export int pollchar(void)
{
return firmware->i_ops->pollchar();
}
@@ -334,7 +267,7 @@ char bios_getchar(char *hi)
/*
* getchar: Read a character from keyboard or serial port
*/
-char getchar(char *hi)
+__export char getchar(char *hi)
{
return firmware->i_ops->getchar(hi);
}
@@ -343,223 +276,3 @@ void pm_getchar(com32sys_t *regs)
{
regs->eax.b[0] = getchar((char *)&regs->eax.b[1]);
}
-
-static void msg_setbg(char data)
-{
- if (unhexchar(&data) == 0) {
- data <<= 4;
- if (DisplayMask & UsingVGA)
- TextAttribute = data;
-
- NextCharJump = msg_setfg;
- } else {
- TextAttribute = 0x7; /* Default attribute */
- NextCharJump = msg_putchar;
- }
-}
-
-static void msg_setfg(char data)
-{
- if (unhexchar(&data) == 0) {
- if (DisplayMask & UsingVGA) {
- /* setbg set foreground to 0 */
- TextAttribute |= data;
- }
- } else
- TextAttribute = 0x7; /* Default attribute */
-
- NextCharJump = msg_putchar;
-}
-
-static inline void msg_ctrl_o(void)
-{
- NextCharJump = msg_setbg;
-}
-
-static void msg_gotoxy(void)
-{
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
-}
-
-static void msg_newline(void)
-{
- com32sys_t ireg, oreg;
- char crlf_msg[] = { '\r', '\n', '\0' };
-
- write_serial_str_displaymask(crlf_msg);
-
- if (!(DisplayMask & UsingVGA))
- return;
-
- CursorCol = 0;
- if ((CursorRow + 1) <= VidRows)
- CursorRow++;
- else {
- CursorRow = VidRows; /* New cursor at the bottom */
- firmware->o_ops->scroll_up(VidRows, VidCols, ScrollAttribute);
- }
-
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
-}
-
-static void msg_formfeed(void)
-{
- char crff_msg[] = { '\r', '\f', '\0' };
-
- write_serial_str_displaymask(crff_msg);
-
- if (DisplayMask & UsingVGA) {
- CursorDX = 0x0; /* Upper left hand corner */
-
- firmware->o_ops->erase(0, 0, VidCols, VidRows, TextAttribute);
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
- }
-}
-
-static void msg_novga(void)
-{
- syslinux_force_text_mode();
- msg_initvars();
-}
-
-static void msg_viewimage(void)
-{
- FILE *f;
-
- *VGAFilePtr = '\0'; /* Zero-terminate filename */
-
- mangle_name(VGAFileMBuf, VGAFileBuf);
- f = fopen(VGAFileMBuf, "r");
- if (!f) {
- /* Not there */
- NextCharJump = msg_putchar;
- return;
- }
-
- vgadisplayfile(f);
- fclose(f);
- msg_initvars();
-}
-
-/*
- * Getting VGA filename
- */
-static void msg_filename(char data)
-{
- /* <LF> = end of filename */
- if (data == 0x0A) {
- msg_viewimage();
- return;
- }
-
- /* Ignore space/control char */
- if (data > ' ') {
- if ((char *)VGAFilePtr < (VGAFileBuf + sizeof(VGAFileBuf)))
- *VGAFilePtr++ = data;
- }
-}
-
-static void msg_vga(void)
-{
- NextCharJump = msg_filename;
- VGAFilePtr = (uint16_t *)VGAFileBuf;
-}
-
-static void msg_line_wrap(void)
-{
- if (!(DisplayMask & UsingVGA))
- return;
-
- CursorCol = 0;
- if ((CursorRow + 1) <= VidRows)
- CursorRow++;
- else {
- /* Scroll up one line */
- firmware->o_ops->scroll_up(VidRows, VidCols, ScrollAttribute);
- }
-
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
-}
-
-static void msg_normal(char data)
-{
- com32sys_t ireg, oreg;
-
- /* Write to serial port */
- write_serial_displaymask(data);
-
- if (!(DisplayMask & UsingVGA))
- return; /* Not screen */
-
- if (!(DisplayCon & 0x01))
- return;
-
- /* Write to screen */
- firmware->o_ops->write_char(data, TextAttribute);
-
- if ((CursorCol + 1) <= VidCols) {
- CursorCol++;
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
- } else
- msg_line_wrap(); /* Screen wraparound */
-}
-
-static void msg_modectl(char data)
-{
- data &= 0x07;
- DisplayMask = data;
- NextCharJump = msg_putchar;
-}
-
-static void msg_putchar(char ch)
-{
- /* 10h to 17h are mode controls */
- if (ch >= 0x10 && ch < 0x18) {
- msg_modectl(ch);
- return;
- }
-
- switch (ch) {
- case 0x0F: /* ^O = color code follows */
- msg_ctrl_o();
- break;
- case 0x0D: /* Ignore <CR> */
- break;
- case 0x0A: /* <LF> = newline */
- msg_newline();
- break;
- case 0x0C: /* <FF> = clear screen */
- msg_formfeed();
- break;
- case 0x07: /* <BEL> = beep */
- if (firmware->o_ops->beep)
- firmware->o_ops->beep();
- break;
- case 0x19: /* <EM> = return to text mode */
- msg_novga();
- break;
- case 0x18: /* <CAN> = VGA filename follows */
- msg_vga();
- break;
- default:
- msg_normal(ch);
- break;
- }
-}
-
-/*
- * Subroutine to initialize variables, also needed after loading
- * graphics file.
- */
-void msg_initvars(void)
-{
- com32sys_t ireg, oreg;
- int x, y;
-
- firmware->o_ops->get_cursor(&x, &y);
- CursorCol = x;
- CursorRow = y;
-
- /* Initialize state machine */
- NextCharJump = msg_putchar;
-}
diff --git a/core/diskboot.inc b/core/diskboot.inc
index be816263..ce75b8c9 100644
--- a/core/diskboot.inc
+++ b/core/diskboot.inc
@@ -103,7 +103,6 @@ superblock_len_fat32 equ $-superblock+54
zb 54 ; Maximum needed size
superblock_max equ $-superblock
- global SecPerClust
SecPerClust equ bxSecPerClust
;
@@ -385,7 +384,11 @@ getonesec_cbios:
;
; kaboom: write a message and bail out.
;
+%ifdef BINFMT
global kaboom
+%else
+ global kaboom:function hidden
+%endif
disk_error:
kaboom:
xor si,si
diff --git a/core/diskfs.inc b/core/diskfs.inc
index dcbc924a..827f5003 100644
--- a/core/diskfs.inc
+++ b/core/diskfs.inc
@@ -60,7 +60,7 @@ vk_end: equ $ ; Should be <= vk_size
; Memory below this point is reserved for the BIOS and the MBR
;
section .earlybss
- global trackbuf
+ global trackbuf:data hidden
trackbufsize equ 8192
trackbuf resb trackbufsize ; Track buffer goes here
; ends at 2800h
@@ -91,24 +91,15 @@ auto_boot:
jmp kaboom
section .bss16
- global CmdOptPtr, KbdMap
alignb 4
ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
KernelExtPtr resw 1 ; During search, final null pointer
-CmdOptPtr resw 1 ; Pointer to first option on cmd line
-KbdFlags resb 1 ; Check for keyboard escapes
FuncFlag resb 1 ; Escape sequences received from keyboard
KernelType resb 1 ; Kernel type, from vkernel, if known
-KbdMap resb 256 ; Keyboard map
global KernelName
KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .config
- global PXERetry
-PXERetry dw 0 ; Extra PXE retries
section .data16
- global SerialNotice
-SerialNotice db 1 ; Only print this once
global IPAppends, numIPAppends
%if IS_PXELINUX
extern IPOption
diff --git a/core/diskstart.inc b/core/diskstart.inc
index 603a6db2..875b4093 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -92,7 +92,7 @@ BannerPtr dw syslinux_banner - LDLINUX_SYS
; Base directory name and subvolume, if applicable.
;
%define HAVE_CURRENTDIRNAME
- global CurrentDirName, SubvolName
+ global CurrentDirName:data hidden, SubvolName:data hidden
CurrentDirName times CURRENTDIR_MAX db 0
SubvolName times SUBVOL_MAX db 0
@@ -232,7 +232,7 @@ verify_checksum:
;
; This routine assumes CS == DS.
;
- global getlinsec
+ global getlinsec:function hidden
getlinsec:
pushad
add eax,[Hidden] ; Add partition offset
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index f3dd1e77..1fa43bd6 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -57,7 +57,7 @@ void init_module_subsystem(struct elf_module *module)
list_add(&module->list, &modules_head);
}
-int start_ldlinux(char **argv)
+__export int start_ldlinux(char **argv)
{
int rv;
@@ -69,9 +69,19 @@ again:
* unload all the modules loaded since ldlinux.c32,
* and restart initialisation. This is especially
* important for config files.
+ *
+ * But before we do that, try our best to make sure
+ * that spawn_load() is gonna succeed, e.g. that we
+ * can find LDLINUX it in PATH.
*/
struct elf_module *ldlinux;
+ FILE *f;
+
+ f = findpath(LDLINUX);
+ if (!f)
+ return ENOENT;
+ fclose(f);
ldlinux = unload_modules_since(LDLINUX);
/*
@@ -113,14 +123,13 @@ void load_env32(com32sys_t * regs __unused)
dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
- PATH = malloc(strlen(PATH_DEFAULT) + 1);
+ PATH = malloc(strlen(CurrentDirName) + 1);
if (!PATH) {
printf("Couldn't allocate memory for PATH\n");
return;
}
- strcpy(PATH, PATH_DEFAULT);
- PATH[strlen(PATH_DEFAULT)] = '\0';
+ strcpy(PATH, CurrentDirName);
size = (size_t)__dynstr_end - (size_t)__dynstr_start;
core_module.strtable_size = size;
@@ -150,7 +159,7 @@ void load_env32(com32sys_t * regs __unused)
writestr("\nFailed to load ldlinux.c32");
}
-int create_args_and_load(char *cmdline)
+__export int create_args_and_load(char *cmdline)
{
char *p, **argv;
int argc;
@@ -175,9 +184,10 @@ int create_args_and_load(char *cmdline)
* Generate a copy of argv on the stack as this is
* traditionally where process arguments go.
*
- * argv[0] must be the command name.
+ * argv[0] must be the command name. Remember to allocate
+ * space for the sentinel NULL.
*/
- argv = alloca(argc * sizeof(char *));
+ argv = alloca((argc + 1) * sizeof(char *));
for (i = 0, p = cmdline; i < argc; i++) {
char *start;
diff --git a/core/font.c b/core/font.c
index 1e4e606d..edc9de8e 100644
--- a/core/font.c
+++ b/core/font.c
@@ -27,7 +27,9 @@
#include "graphics.h"
#include "core.h"
-__lowmem char fontbuf[8192];
+__export uint8_t UserFont = 0; /* Using a user-specified font */
+
+__export __lowmem char fontbuf[8192];
uint16_t GXPixCols = 1; /* Graphics mode pixel columns */
uint16_t GXPixRows = 1; /* Graphics mode pixel rows */
@@ -36,7 +38,7 @@ uint16_t GXPixRows = 1; /* Graphics mode pixel rows */
* loadfont: Load a .psf font file and install it onto the VGA console
* (if we're not on a VGA screen then ignore.)
*/
-void loadfont(const char *filename)
+__export void loadfont(const char *filename)
{
struct psfheader {
uint16_t magic;
diff --git a/core/fs/chdir.c b/core/fs/chdir.c
index 903cabce..5d3a545f 100644
--- a/core/fs/chdir.c
+++ b/core/fs/chdir.c
@@ -54,7 +54,7 @@ static size_t generic_inode_to_path(struct inode *inode, char *dst, size_t bufsi
return s;
}
-size_t realpath(char *dst, const char *src, size_t bufsize)
+__export size_t realpath(char *dst, const char *src, size_t bufsize)
{
int rv;
struct file *file;
@@ -83,7 +83,7 @@ size_t realpath(char *dst, const char *src, size_t bufsize)
return s;
}
-int chdir(const char *src)
+__export int chdir(const char *src)
{
int rv;
struct file *file;
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 21e7684a..40f97d5e 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -9,13 +9,13 @@
#include "fs.h"
#include "cache.h"
-char *PATH;
+__export char *PATH;
/* The currently mounted filesystem */
-struct fs_info *this_fs = NULL; /* Root filesystem */
+__export struct fs_info *this_fs = NULL; /* Root filesystem */
/* Actual file structures (we don't have malloc yet...) */
-struct file files[MAX_OPEN];
+__export struct file files[MAX_OPEN];
/* Symlink hard limits */
#define MAX_SYMLINK_CNT 20
@@ -74,7 +74,7 @@ static inline void free_file(struct file *file)
memset(file, 0, sizeof *file);
}
-void _close_file(struct file *file)
+__export void _close_file(struct file *file)
{
if (file->fs)
file->fs->fs_ops->close_file(file);
@@ -84,7 +84,7 @@ void _close_file(struct file *file)
/*
* Find and open the configuration file
*/
-int open_config(void)
+__export int open_config(void)
{
int fd, handle;
struct file_info *fp;
@@ -116,7 +116,7 @@ void pm_mangle_name(com32sys_t *regs)
mangle_name(dst, src);
}
-void mangle_name(char *dst, const char *src)
+__export void mangle_name(char *dst, const char *src)
{
this_fs->fs_ops->mangle_name(dst, src);
}
@@ -219,11 +219,10 @@ void pm_searchdir(com32sys_t *regs)
int searchdir(const char *name)
{
- struct inode *inode = NULL;
- struct inode *parent = NULL;
+ static char root_name[] = "/";
struct file *file;
- char *pathbuf = NULL;
- char *part, *p, echar;
+ char *path, *inode_name, *next_inode_name;
+ struct inode *tmp, *inode = NULL;
int symlink_count = MAX_SYMLINK_CNT;
dprintf("searchdir: %s root: %p cwd: %p\n",
@@ -245,113 +244,165 @@ int searchdir(const char *name)
/* else, try the generic-path-lookup method */
- parent = get_inode(this_fs->cwd);
- p = pathbuf = strdup(name);
- if (!pathbuf)
- goto err;
+ /* Copy the path */
+ path = strdup(name);
+ if (!path) {
+ dprintf("searchdir: Couldn't copy path\n");
+ goto err_path;
+ }
+
+ /* Work with the current directory, by default */
+ inode = get_inode(this_fs->cwd);
+ if (!inode) {
+ dprintf("searchdir: Couldn't use current directory\n");
+ goto err_curdir;
+ }
- do {
- got_link:
- if (*p == '/') {
- put_inode(parent);
- parent = get_inode(this_fs->root);
+ for (inode_name = path; inode_name; inode_name = next_inode_name) {
+ /* Root directory? */
+ if (inode_name[0] == '/') {
+ next_inode_name = inode_name + 1;
+ inode_name = root_name;
+ } else {
+ /* Find the next inode name */
+ next_inode_name = strchr(inode_name + 1, '/');
+ if (next_inode_name) {
+ /* Terminate the current inode name and point to next */
+ *next_inode_name++ = '\0';
+ }
+ }
+ if (next_inode_name) {
+ /* Advance beyond redundant slashes */
+ while (*next_inode_name == '/')
+ next_inode_name++;
+
+ /* Check if we're at the end */
+ if (*next_inode_name == '\0')
+ next_inode_name = NULL;
+ }
+ dprintf("searchdir: inode_name: %s\n", inode_name);
+ if (next_inode_name)
+ dprintf("searchdir: Remaining: %s\n", next_inode_name);
+
+ /* Root directory? */
+ if (inode_name[0] == '/') {
+ /* Release any chain that's already been established */
+ put_inode(inode);
+ inode = get_inode(this_fs->root);
+ continue;
}
- do {
- inode = get_inode(parent);
-
- while (*p == '/')
- p++;
-
- if (!*p)
- break;
-
- part = p;
- while ((echar = *p) && echar != '/')
- p++;
- *p++ = '\0';
-
- if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
- if (inode->parent) {
- put_inode(parent);
- parent = get_inode(inode->parent);
- put_inode(inode);
- inode = NULL;
- if (!echar) {
- /* Terminal double dots */
- inode = parent;
- parent = inode->parent ?
- get_inode(inode->parent) : NULL;
- }
- }
- } else if (part[0] != '.' || part[1] != '\0') {
- inode = this_fs->fs_ops->iget(part, parent);
- if (!inode)
- goto err;
- if (inode->mode == DT_LNK) {
- char *linkbuf, *q;
- int name_len = echar ? strlen(p) : 0;
- int total_len = inode->size + name_len + 2;
- int link_len;
-
- if (!this_fs->fs_ops->readlink ||
- --symlink_count == 0 || /* limit check */
- total_len > MAX_SYMLINK_BUF)
- goto err;
-
- linkbuf = malloc(total_len);
- if (!linkbuf)
- goto err;
-
- link_len = this_fs->fs_ops->readlink(inode, linkbuf);
- if (link_len <= 0) {
- free(linkbuf);
- goto err;
- }
-
- q = linkbuf + link_len;
-
- if (echar) {
- if (link_len > 0 && q[-1] != '/')
- *q++ = '/';
-
- memcpy(q, p, name_len+1);
- } else {
- *q = '\0';
- }
-
- free(pathbuf);
- p = pathbuf = linkbuf;
- put_inode(inode);
- inode = NULL;
- goto got_link;
- }
-
- inode->name = strdup(part);
- dprintf("path component: %s\n", inode->name);
-
- inode->parent = parent;
- parent = NULL;
-
- if (!echar)
- break;
-
- if (inode->mode != DT_DIR)
- goto err;
-
- parent = inode;
- inode = NULL;
+ /* Current directory? */
+ if (!strncmp(inode_name, ".", sizeof "."))
+ continue;
+
+ /* Parent directory? */
+ if (!strncmp(inode_name, "..", sizeof "..")) {
+ /* If there is no parent, just ignore it */
+ if (!inode->parent)
+ continue;
+
+ /* Add a reference to the parent so we can release the child */
+ tmp = get_inode(inode->parent);
+
+ /* Releasing the child will drop the parent back down to 1 */
+ put_inode(inode);
+
+ inode = tmp;
+ continue;
+ }
+
+ /* Anything else */
+ tmp = inode;
+ inode = this_fs->fs_ops->iget(inode_name, inode);
+ if (!inode) {
+ /* Failure. Release the chain */
+ put_inode(tmp);
+ break;
+ }
+
+ /* Sanity-check */
+ if (inode->parent && inode->parent != tmp) {
+ dprintf("searchdir: iget returned a different parent\n");
+ put_inode(inode);
+ inode = NULL;
+ put_inode(tmp);
+ break;
+ }
+ inode->parent = tmp;
+ inode->name = strdup(inode_name);
+ dprintf("searchdir: path component: %s\n", inode->name);
+
+ /* Symlink handling */
+ if (inode->mode == DT_LNK) {
+ char *new_path;
+ int new_len, copied;
+
+ /* target path + NUL */
+ new_len = inode->size + 1;
+
+ if (next_inode_name) {
+ /* target path + slash + remaining + NUL */
+ new_len += strlen(next_inode_name) + 1;
+ }
+
+ if (!this_fs->fs_ops->readlink ||
+ /* limit checks */
+ --symlink_count == 0 ||
+ new_len > MAX_SYMLINK_BUF)
+ goto err_new_len;
+
+ new_path = malloc(new_len);
+ if (!new_path)
+ goto err_new_path;
+
+ copied = this_fs->fs_ops->readlink(inode, new_path);
+ if (copied <= 0)
+ goto err_copied;
+ new_path[copied] = '\0';
+ dprintf("searchdir: Symlink: %s\n", new_path);
+
+ if (next_inode_name) {
+ new_path[copied] = '/';
+ strcpy(new_path + copied + 1, next_inode_name);
+ dprintf("searchdir: New path: %s\n", new_path);
}
- } while (echar);
- } while (0);
- free(pathbuf);
- pathbuf = NULL;
- put_inode(parent);
- parent = NULL;
+ free(path);
+ path = next_inode_name = new_path;
- if (!inode)
+ /* Add a reference to the parent so we can release the child */
+ tmp = get_inode(inode->parent);
+
+ /* Releasing the child will drop the parent back down to 1 */
+ put_inode(inode);
+
+ inode = tmp;
+ continue;
+err_copied:
+ free(new_path);
+err_new_path:
+err_new_len:
+ put_inode(inode);
+ inode = NULL;
+ break;
+ }
+
+ /* If there's more to process, this should be a directory */
+ if (next_inode_name && inode->mode != DT_DIR) {
+ dprintf("searchdir: Expected a directory\n");
+ put_inode(inode);
+ inode = NULL;
+ break;
+ }
+ }
+err_curdir:
+ free(path);
+err_path:
+ if (!inode) {
+ dprintf("searchdir: Not found\n");
goto err;
+ }
file->inode = inode;
file->offset = 0;
@@ -360,16 +411,12 @@ int searchdir(const char *name)
err:
dprintf("serachdir: error seraching file %s\n", name);
- put_inode(inode);
- put_inode(parent);
- if (pathbuf)
- free(pathbuf);
_close_file(file);
err_no_close:
return -1;
}
-int open_file(const char *name, struct com32_filedata *filedata)
+__export int open_file(const char *name, struct com32_filedata *filedata)
{
int rv;
struct file *file;
@@ -419,7 +466,7 @@ void pm_open_file(com32sys_t *regs)
}
}
-void close_file(uint16_t handle)
+__export void close_file(uint16_t handle)
{
struct file *file;
diff --git a/core/fs/getcwd.c b/core/fs/getcwd.c
index ee62411f..70b93152 100644
--- a/core/fs/getcwd.c
+++ b/core/fs/getcwd.c
@@ -1,7 +1,7 @@
#include <string.h>
#include "fs.h"
-char *core_getcwd(char *buf, size_t size)
+__export char *core_getcwd(char *buf, size_t size)
{
char *ret = NULL;
diff --git a/core/fs/lib/searchconfig.c b/core/fs/lib/searchconfig.c
index f2d740b3..b2a964e8 100644
--- a/core/fs/lib/searchconfig.c
+++ b/core/fs/lib/searchconfig.c
@@ -4,8 +4,8 @@
#include <core.h>
#include <fs.h>
-char ConfigName[FILENAME_MAX];
-char config_cwd[FILENAME_MAX];
+__export char ConfigName[FILENAME_MAX];
+__export char config_cwd[FILENAME_MAX];
/*
* This searches for a specified set of filenames in a specified set
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index 6f490ce8..11270044 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <string.h>
#include <core.h>
+#include <bios.h>
#include <fs.h>
#include <minmax.h>
#include <sys/cpu.h>
@@ -796,8 +797,10 @@ static void __pxe_searchdir(const char *filename, struct file *file)
sendreq:
timeout = *timeout_ptr++;
- if (!timeout)
+ if (!timeout) {
+ free_socket(inode);
return; /* No file available... */
+ }
oldtime = jiffies();
socket->tftp_remoteip = ip;
@@ -1268,9 +1271,9 @@ static const void *memory_scan(uintptr_t start, int (*func)(const void *))
static const struct pxe_t *memory_scan_for_pxe_struct(void)
{
- extern uint16_t BIOS_fbm; /* Starting segment */
+ uint16_t start = bios_fbm(); /* Starting segment */
- return memory_scan(BIOS_fbm << 10, is_pxe);
+ return memory_scan(start << 10, is_pxe);
}
static const struct pxenv_t *memory_scan_for_pxenv_struct(void)
@@ -1675,11 +1678,11 @@ void unload_pxe(uint16_t flags)
uint16_t Status; /* All calls have this as the first member */
} unload_call;
- dprintf("FBM before unload = %d\n", BIOS_fbm);
+ dprintf("FBM before unload = %d\n", bios_fbm());
err = reset_pxe();
- dprintf("FBM after reset_pxe = %d, err = %d\n", BIOS_fbm, err);
+ dprintf("FBM after reset_pxe = %d, err = %d\n", bios_fbm(), err);
/* If we want to keep PXE around, we still need to reset it */
if (flags || err)
@@ -1699,8 +1702,8 @@ void unload_pxe(uint16_t flags)
}
api = 0xff00;
- if (real_base_mem <= BIOS_fbm) { /* Sanity check */
- dprintf("FBM %d < real_base_mem %d\n", BIOS_fbm, real_base_mem);
+ if (real_base_mem <= bios_fbm()) { /* Sanity check */
+ dprintf("FBM %d < real_base_mem %d\n", bios_fbm(), real_base_mem);
goto cant_free;
}
api++;
@@ -1708,20 +1711,20 @@ void unload_pxe(uint16_t flags)
/* Check that PXE actually unhooked the INT 0x1A chain */
int_addr = (size_t)GET_PTR(*(far_ptr_t *)(4 * 0x1a));
int_addr >>= 10;
- if (int_addr >= real_base_mem || int_addr < BIOS_fbm) {
- BIOS_fbm = real_base_mem;
- dprintf("FBM after unload_pxe = %d\n", BIOS_fbm);
+ if (int_addr >= real_base_mem || int_addr < bios_fbm()) {
+ set_bios_fbm(real_base_mem);
+ dprintf("FBM after unload_pxe = %d\n", bios_fbm());
return;
}
dprintf("Can't free FBM, real_base_mem = %d, "
"FBM = %d, INT 1A = %08x (%d)\n",
- real_base_mem, BIOS_fbm,
+ real_base_mem, bios_fbm(),
*(uint32_t *)(4 * 0x1a), int_addr);
cant_free:
printf("Failed to free base memory error %04x-%08x (%d/%dK)\n",
- api, *(uint32_t *)(4 * 0x1a), BIOS_fbm, real_base_mem);
+ api, *(uint32_t *)(4 * 0x1a), bios_fbm(), real_base_mem);
return;
}
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index 99a2cf25..3439dd6a 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -201,7 +201,6 @@ extern bool have_uuid;
extern uint8_t uuid_type;
extern uint8_t uuid[];
-extern uint16_t BIOS_fbm;
extern const uint8_t TimeoutTable[];
/*
diff --git a/core/fs/readdir.c b/core/fs/readdir.c
index d071affd..e2d593fc 100644
--- a/core/fs/readdir.c
+++ b/core/fs/readdir.c
@@ -7,7 +7,7 @@
/*
* Open a directory
*/
-DIR *opendir(const char *path)
+__export DIR *opendir(const char *path)
{
int rv;
struct file *file;
@@ -29,7 +29,7 @@ DIR *opendir(const char *path)
/*
* Read one directory entry at one time.
*/
-struct dirent *readdir(DIR *dir)
+__export struct dirent *readdir(DIR *dir)
{
static struct dirent buf;
struct file *dd_dir = (struct file *)dir;
@@ -47,7 +47,7 @@ struct dirent *readdir(DIR *dir)
/*
* Close a directory
*/
-int closedir(DIR *dir)
+__export int closedir(DIR *dir)
{
struct file *dd_dir = (struct file *)dir;
_close_file(dd_dir);
diff --git a/core/fs/xfs/misc.h b/core/fs/xfs/misc.h
new file mode 100644
index 00000000..7f2f1b33
--- /dev/null
+++ b/core/fs/xfs/misc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MISC_H_
+#define MISC_H_
+
+/* Return a 64-bit litte-endian value from a given 64-bit big-endian one */
+static inline uint64_t be64_to_cpu(uint64_t val)
+{
+ return (uint64_t)((((uint64_t)val & (uint64_t)0x00000000000000ffULL) << 56) |
+ (((uint64_t)val & (uint64_t)0x000000000000ff00ULL) << 40) |
+ (((uint64_t)val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+ (((uint64_t)val & (uint64_t)0x00000000ff000000ULL) << 8) |
+ (((uint64_t)val & (uint64_t)0x000000ff00000000ULL) >> 8) |
+ (((uint64_t)val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+ (((uint64_t)val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+ (((uint64_t)val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
+/* Return a 32-bit litte-endian value from a given 32-bit big-endian one */
+static inline uint32_t be32_to_cpu(uint32_t val)
+{
+ return (uint32_t)((((uint32_t)val & (uint32_t)0x000000ffUL) << 24) |
+ (((uint32_t)val & (uint32_t)0x0000ff00UL) << 8) |
+ (((uint32_t)val & (uint32_t)0x00ff0000UL) >> 8) |
+ (((uint32_t)val & (uint32_t)0xff000000UL) >> 24));
+}
+
+/* Return a 16-bit litte-endian value from a given 16-bit big-endian one */
+static inline uint16_t be16_to_cpu(uint16_t val)
+{
+ return (uint16_t)((((uint16_t)val & (uint16_t)0x00ffU) << 8) |
+ (((uint16_t)val & (uint16_t)0xff00U) >> 8));
+}
+
+#endif /* MISC_H_ */
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
new file mode 100644
index 00000000..89a9aef2
--- /dev/null
+++ b/core/fs/xfs/xfs.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include <ilog2.h>
+#include <klibc/compiler.h>
+#include <ctype.h>
+
+#include "codepage.h"
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+#include "xfs_dir2.h"
+#include "xfs_readdir.h"
+
+static inline int xfs_fmt_local_readdir(struct file *file,
+ struct dirent *dirent, xfs_dinode_t *core)
+{
+ return xfs_readdir_dir2_block(file, dirent, core);
+}
+
+static inline int xfs_fmt_extents_readdir(struct file *file,
+ struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ int retval;
+
+ if (be32_to_cpu(core->di_nextents) <= 1) {
+ /* Single-block Directories */
+ retval = xfs_readdir_dir2_block(file, dirent, core);
+ } else if (xfs_dir2_isleaf(file->fs, core)) {
+ /* Leaf Directory */
+ retval = xfs_readdir_dir2_leaf(file, dirent, core);
+ } else {
+ /* Node Directory */
+ retval = xfs_readdir_dir2_node(file, dirent, core);
+ }
+
+ return retval;
+}
+
+static int xfs_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ xfs_dinode_t *core;
+ struct inode *inode = file->inode;
+ int retval = -1;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino %llx)", inode->ino);
+ return -1;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL)
+ retval = xfs_fmt_local_readdir(file, dirent, core);
+ else if (core->di_format == XFS_DINODE_FMT_EXTENTS)
+ retval = xfs_fmt_extents_readdir(file, dirent, core);
+
+ return retval;
+}
+
+static uint32_t xfs_getfssec(struct file *file, char *buf, int sectors,
+ bool *have_more)
+{
+ return generic_getfssec(file, buf, sectors, have_more);
+}
+
+static int xfs_next_extent(struct inode *inode, uint32_t lstart)
+{
+ struct fs_info *fs = inode->fs;
+ xfs_dinode_t *core = NULL;
+ xfs_bmbt_irec_t rec;
+ block_t bno;
+ xfs_bmdr_block_t *rblock;
+ int fsize;
+ xfs_bmbt_ptr_t *pp;
+ xfs_btree_block_t *blk;
+ uint16_t nextents;
+ block_t nextbno;
+ uint32_t index;
+
+ (void)lstart;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino %llx)", inode->ino);
+ goto out;
+ }
+
+ /* The data fork contains the file's data extents */
+ if (XFS_PVT(inode)->i_cur_extent == be32_to_cpu(core->di_nextents))
+ goto out;
+
+ if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+ XFS_PVT(inode)->i_cur_extent++);
+
+ bno = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+
+ XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+ inode->next_extent.pstart = bno << BLOCK_SHIFT(fs) >> SECTOR_SHIFT(fs);
+ inode->next_extent.len = ((rec.br_blockcount << BLOCK_SHIFT(fs)) +
+ SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ xfs_debug("XFS_DINODE_FMT_BTREE");
+ index = XFS_PVT(inode)->i_cur_extent++;
+ rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+ pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+ bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
+
+ /* Find the leaf */
+ for (;;) {
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ if (be16_to_cpu(blk->bb_level) == 0)
+ break;
+
+ pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+ xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+ bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
+ }
+
+ /* Find the right extent among threaded leaves */
+ for (;;) {
+ nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+ nextents = be16_to_cpu(blk->bb_numrecs);
+ if (nextents - index > 0) {
+ bmbt_irec_get(&rec, XFS_BMDR_REC_ADDR(blk, index + 1));
+
+ bno = fsblock_to_bytes(fs, rec.br_startblock)
+ >> BLOCK_SHIFT(fs);
+
+ XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+ inode->next_extent.pstart = bno << BLOCK_SHIFT(fs)
+ >> SECTOR_SHIFT(fs);
+ inode->next_extent.len = ((rec.br_blockcount
+ << BLOCK_SHIFT(fs))
+ + SECTOR_SIZE(fs) - 1)
+ >> SECTOR_SHIFT(fs);
+ break;
+ }
+
+ index -= nextents;
+ bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ }
+ }
+
+ return 0;
+
+out:
+ return -1;
+}
+
+static inline struct inode *xfs_fmt_local_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ return xfs_dir2_local_find_entry(dname, parent, core);
+}
+
+static inline struct inode *xfs_fmt_extents_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ struct inode *inode;
+
+ if (be32_to_cpu(core->di_nextents) <= 1) {
+ /* Single-block Directories */
+ inode = xfs_dir2_block_find_entry(dname, parent, core);
+ } else if (xfs_dir2_isleaf(parent->fs, core)) {
+ /* Leaf Directory */
+ inode = xfs_dir2_leaf_find_entry(dname, parent, core);
+ } else {
+ /* Node Directory */
+ inode = xfs_dir2_node_find_entry(dname, parent, core);
+ }
+
+ return inode;
+}
+
+static inline struct inode *xfs_fmt_btree_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ return xfs_dir2_node_find_entry(dname, parent, core);
+}
+
+static struct inode *xfs_iget(const char *dname, struct inode *parent)
+{
+ struct fs_info *fs = parent->fs;
+ xfs_dinode_t *core = NULL;
+ struct inode *inode = NULL;
+
+ xfs_debug("dname %s parent %p parent ino %lu", dname, parent, parent->ino);
+
+ core = xfs_dinode_get_core(fs, parent->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)", parent->ino);
+ goto out;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+ inode = xfs_fmt_local_find_entry(dname, parent, core);
+ } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ inode = xfs_fmt_extents_find_entry(dname, parent, core);
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ inode = xfs_fmt_btree_find_entry(dname, parent, core);
+ } else {
+ xfs_debug("format %hhu", core->di_format);
+ xfs_debug("TODO: format \"local\" and \"extents\" are the only "
+ "supported ATM");
+ goto out;
+ }
+
+ if (!inode) {
+ xfs_debug("Entry not found!");
+ goto out;
+ }
+
+ if (inode->mode == DT_REG) {
+ XFS_PVT(inode)->i_offset = 0;
+ XFS_PVT(inode)->i_cur_extent = 0;
+ } else if (inode->mode == DT_DIR) {
+ XFS_PVT(inode)->i_btree_offset = 0;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ }
+
+ return inode;
+
+out:
+ return NULL;
+}
+
+static int xfs_readlink(struct inode *inode, char *buf)
+{
+ struct fs_info *fs = inode->fs;
+ xfs_dinode_t *core;
+ int pathlen = -1;
+ xfs_bmbt_irec_t rec;
+ block_t db;
+ char *dir_buf;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)", inode->ino);
+ goto out;
+ }
+
+ pathlen = be64_to_cpu(core->di_size);
+ if (!pathlen)
+ goto out;
+
+ if (pathlen < 0 || pathlen > MAXPATHLEN) {
+ xfs_error("inode (%llu) bad symlink length (%d)",
+ inode->ino, pathlen);
+ goto out;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+ memcpy(buf, (char *)&core->di_literal_area[0], pathlen);
+ } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ db = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+ dir_buf = xfs_dir2_get_dirblks(fs, db, rec.br_blockcount);
+
+ /*
+ * Syslinux only supports filesystem block size larger than or equal to
+ * 4 KiB. Thus, one directory block is far enough to hold the maximum
+ * symbolic link file content, which is only 1024 bytes long.
+ */
+ memcpy(buf, dir_buf, pathlen);
+ free(dir_buf);
+ }
+
+out:
+ return pathlen;
+}
+
+static struct inode *xfs_iget_root(struct fs_info *fs)
+{
+ xfs_dinode_t *core = NULL;
+ struct inode *inode = xfs_new_inode(fs);
+
+ xfs_debug("Looking for the root inode...");
+
+ core = xfs_dinode_get_core(fs, XFS_INFO(fs)->rootino);
+ if (!core) {
+ xfs_error("Inode core's magic number does not match!");
+ xfs_debug("magic number 0x%04x", be16_to_cpu(core->di_magic));
+ goto out;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, XFS_INFO(fs)->rootino);
+
+ xfs_debug("Root inode has been found!");
+
+ if ((be16_to_cpu(core->di_mode) & S_IFMT) != S_IFDIR) {
+ xfs_error("root inode is not a directory ?! No makes sense...");
+ goto out;
+ }
+
+ inode->ino = XFS_INFO(fs)->rootino;
+ inode->mode = DT_DIR;
+ inode->size = be64_to_cpu(core->di_size);
+
+ return inode;
+
+out:
+ free(inode);
+
+ return NULL;
+}
+
+static inline int xfs_read_superblock(struct fs_info *fs, xfs_sb_t *sb)
+{
+ struct disk *disk = fs->fs_dev->disk;
+
+ if (!disk->rdwr_sectors(disk, sb, XFS_SB_DADDR, 1, false))
+ return -1;
+
+ return 0;
+}
+
+static struct xfs_fs_info *xfs_new_sb_info(xfs_sb_t *sb)
+{
+ struct xfs_fs_info *info;
+
+ info = malloc(sizeof *info);
+ if (!info)
+ malloc_error("xfs_fs_info structure");
+
+ info->blocksize = be32_to_cpu(sb->sb_blocksize);
+ info->block_shift = sb->sb_blocklog;
+ info->dirblksize = 1 << (sb->sb_blocklog + sb->sb_dirblklog);
+ info->dirblklog = sb->sb_dirblklog;
+ info->inopb_shift = sb->sb_inopblog;
+ info->agblk_shift = sb->sb_agblklog;
+ info->rootino = be64_to_cpu(sb->sb_rootino);
+ info->agblocks = be32_to_cpu(sb->sb_agblocks);
+ info->agblocks_shift = sb->sb_agblklog;
+ info->agcount = be32_to_cpu(sb->sb_agcount);
+ info->inodesize = be16_to_cpu(sb->sb_inodesize);
+ info->inode_shift = sb->sb_inodelog;
+
+ return info;
+}
+
+static int xfs_fs_init(struct fs_info *fs)
+{
+ struct disk *disk = fs->fs_dev->disk;
+ xfs_sb_t sb;
+ struct xfs_fs_info *info;
+
+ xfs_debug("fs %p", fs);
+
+ SECTOR_SHIFT(fs) = disk->sector_shift;
+ SECTOR_SIZE(fs) = 1 << SECTOR_SHIFT(fs);
+
+ if (xfs_read_superblock(fs, &sb)) {
+ xfs_error("Superblock read failed");
+ goto out;
+ }
+
+ if (!xfs_is_valid_magicnum(&sb)) {
+ xfs_error("Invalid superblock");
+ goto out;
+ }
+
+ xfs_debug("magicnum 0x%lX", be32_to_cpu(sb.sb_magicnum));
+
+ info = xfs_new_sb_info(&sb);
+ if (!info) {
+ xfs_error("Failed to fill in filesystem-specific info structure");
+ goto out;
+ }
+
+ fs->fs_info = info;
+
+ xfs_debug("block_shift %u blocksize 0x%lX (%lu)", info->block_shift,
+ info->blocksize, info->blocksize);
+
+ xfs_debug("rootino 0x%llX (%llu)", info->rootino, info->rootino);
+
+ BLOCK_SHIFT(fs) = info->block_shift;
+ BLOCK_SIZE(fs) = info->blocksize;
+
+ cache_init(fs->fs_dev, BLOCK_SHIFT(fs));
+
+ XFS_INFO(fs)->dirleafblk = xfs_dir2_db_to_da(fs, XFS_DIR2_LEAF_FIRSTDB(fs));
+
+ return BLOCK_SHIFT(fs);
+
+out:
+ return -1;
+}
+
+const struct fs_ops xfs_fs_ops = {
+ .fs_name = "xfs",
+ .fs_flags = FS_USEMEM | FS_THISIND,
+ .fs_init = xfs_fs_init,
+ .iget_root = xfs_iget_root,
+ .searchdir = NULL,
+ .getfssec = xfs_getfssec,
+ .open_config = generic_open_config,
+ .close_file = generic_close_file,
+ .mangle_name = generic_mangle_name,
+ .readdir = xfs_readdir,
+ .iget = xfs_iget,
+ .next_extent = xfs_next_extent,
+ .readlink = xfs_readlink,
+};
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
new file mode 100644
index 00000000..da57221a
--- /dev/null
+++ b/core/fs/xfs/xfs.h
@@ -0,0 +1,752 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * Some parts borrowed from Linux kernel tree (linux/fs/xfs):
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_H_
+#define XFS_H_
+
+#include <disk.h>
+#include <fs.h>
+#include <dprintf.h>
+
+#include "xfs_types.h"
+#include "xfs_ag.h"
+
+#define xfs_error(fmt, args...) \
+ printf("xfs: " fmt "\n", ## args);
+
+#define xfs_debug(fmt, args...) \
+ dprintf("%s: " fmt "\n", __func__, ## args);
+
+struct xfs_fs_info;
+
+#define XFS_INFO(fs) ((struct xfs_fs_info *)((fs)->fs_info))
+#define XFS_PVT(ino) ((struct xfs_inode *)((ino)->pvt))
+
+#define XFS_INO_MASK(k) (uint32_t)((1ULL << (k)) - 1)
+#define XFS_INO_OFFSET_BITS(fs) (fs)->inopb_shift
+#define XFS_INO_AGINO_BITS(fs) \
+ (XFS_INFO((fs))->inopb_shift + XFS_INFO((fs))->agblk_shift)
+
+#define XFS_INO_TO_AGINO(fs, i) \
+ ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(fs)))
+
+#define XFS_INO_TO_AGNO(fs, ino) \
+ ((xfs_agnumber_t)((ino) >> (XFS_INFO((fs))->inopb_shift + \
+ XFS_INFO((fs))->agblk_shift)))
+
+#define XFS_INO_TO_OFFSET(fs, i) \
+ ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(fs)))
+
+#define XFS_AGNO_TO_FSB(fs, agno) \
+ ((block_t)((agno) << XFS_INFO((fs))->agblocks_shift))
+
+#define XFS_AGI_OFFS(fs, mp) \
+ ((xfs_agi_t *)((uint8_t *)(mp) + 2 * SECTOR_SIZE((fs))))
+
+#define XFS_GET_DIR_INO4(di) \
+ (((uint32_t)(di).i[0] << 24) | ((di).i[1] << 16) | ((di).i[2] << 8) | \
+ ((di).i[3]))
+
+#define XFS_DI_HI(di) \
+ (((uint32_t)(di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
+
+#define XFS_DI_LO(di) \
+ (((uint32_t)(di).i[4] << 24) | ((di).i[5] << 16) | ((di).i[6] << 8) | \
+ ((di).i[7]))
+
+#define XFS_GET_DIR_INO8(di) \
+ (((xfs_ino_t)XFS_DI_LO(di) & 0xffffffffULL) | \
+ ((xfs_ino_t)XFS_DI_HI(di) << 32))
+
+#define XFS_FSB_TO_AGNO(fs, fsbno) \
+ ((xfs_agnumber_t)((fsbno) >> XFS_INFO((fs))->agblk_shift))
+#define XFS_FSB_TO_AGBNO(fs, fsbno) \
+ ((xfs_agblock_t)((fsbno) & (uint32_t)((1ULL << \
+ XFS_INFO((fs))->agblk_shift) - 1)))
+
+#define agblock_to_bytes(fs, x) \
+ ((uint64_t)(x) << BLOCK_SHIFT((fs)))
+#define agino_to_bytes(fs, x) \
+ ((uint64_t)(x) << XFS_INFO((fs))->inode_shift)
+#define agnumber_to_bytes(fs, x) \
+ agblock_to_bytes(fs, (uint64_t)(x) * XFS_INFO((fs))->agblocks)
+#define fsblock_to_bytes(fs,x) \
+ (agnumber_to_bytes(fs, XFS_FSB_TO_AGNO(fs, (x))) + \
+ agblock_to_bytes(fs, XFS_FSB_TO_AGBNO(fs, (x))))
+#define ino_to_bytes(fs, x) \
+ (agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, (x))) + \
+ agino_to_bytes(fs, XFS_INO_TO_AGINO(fs, (x))))
+
+/* Superblock's LBA */
+#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */
+
+/* Magic numbers */
+#define XFS_AGI_MAGIC "XAGI"
+#define XFS_IBT_MAGIC "IABT"
+#define XFS_DINODE_MAGIC "IN"
+
+#define XFS_DIR2_BLOCK_MAGIC 0x58443242U /* XD2B: single block dirs */
+#define XFS_DIR2_DATA_MAGIC 0x58443244U /* XD2D: multiblock dirs */
+#define XFS_DIR2_FREE_MAGIC 0x58443246U /* XD2F: free index blocks */
+
+#define XFS_DIR2_NULL_DATAPTR ((uint32_t)0)
+
+/* File types and modes */
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define MAXPATHLEN 1024
+/*
+ * NOTE: The fields in the superblock are stored in big-endian format on disk.
+ */
+typedef struct xfs_sb {
+ uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
+ uint32_t sb_blocksize; /* logical block size, bytes */
+ xfs_drfsbno_t sb_dblocks; /* number of data blocks */
+ xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
+ xfs_drtbno_t sb_rextents; /* number of realtime extents */
+ uuid_t sb_uuid; /* file system unique id */
+ xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
+ xfs_ino_t sb_rootino; /* root inode number */
+ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
+ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
+ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
+ xfs_agblock_t sb_agblocks; /* size of an allocation group */
+ xfs_agnumber_t sb_agcount; /* number of allocation groups */
+ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
+ xfs_extlen_t sb_logblocks; /* number of log blocks */
+ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
+ uint16_t sb_sectsize; /* volume sector size, bytes */
+ uint16_t sb_inodesize; /* inode size, bytes */
+ uint16_t sb_inopblock; /* inodes per block */
+ char sb_fname[12]; /* file system name */
+ uint8_t sb_blocklog; /* log2 of sb_blocksize */
+ uint8_t sb_sectlog; /* log2 of sb_sectsize */
+ uint8_t sb_inodelog; /* log2 of sb_inodesize */
+ uint8_t sb_inopblog; /* log2 of sb_inopblock */
+ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
+ uint8_t sb_rextslog; /* log2 of sb_rextents */
+ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
+ uint8_t sb_imax_pct; /* max % of fs for inode space */
+ /* statistics */
+ /*
+ * These fields must remain contiguous. If you really
+ * want to change their layout, make sure you fix the
+ * code in xfs_trans_apply_sb_deltas().
+ */
+ uint64_t sb_icount; /* allocated inodes */
+ uint64_t sb_ifree; /* free inodes */
+ uint64_t sb_fdblocks; /* free data blocks */
+ uint64_t sb_frextents; /* free realtime extents */
+ /*
+ * End contiguous fields.
+ */
+ xfs_ino_t sb_uquotino; /* user quota inode */
+ xfs_ino_t sb_gquotino; /* group quota inode */
+ uint16_t sb_qflags; /* quota flags */
+ uint8_t sb_flags; /* misc. flags */
+ uint8_t sb_shared_vn; /* shared version number */
+ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
+ uint32_t sb_unit; /* stripe or raid unit */
+ uint32_t sb_width; /* stripe or raid width */
+ uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
+ uint8_t sb_logsectlog; /* log2 of the log sector size */
+ uint16_t sb_logsectsize; /* sector size for the log, bytes */
+ uint32_t sb_logsunit; /* stripe unit size for the log */
+ uint32_t sb_features2; /* additional feature bits */
+
+ /*
+ * bad features2 field as a result of failing to pad the sb
+ * structure to 64 bits. Some machines will be using this field
+ * for features2 bits. Easiest just to mark it bad and not use
+ * it for anything else.
+ */
+ uint32_t sb_bad_features2;
+ uint8_t pad[304]; /* must be padded to a sector boundary */
+} __attribute__((__packed__)) xfs_sb_t;
+
+/* In-memory structure that stores filesystem-specific information.
+ * The information stored is basically retrieved from the XFS superblock
+ * to be used statically around the driver.
+ */
+struct xfs_fs_info {
+ uint32_t blocksize; /* Filesystem block size */
+ uint8_t block_shift; /* Filesystem block size in bits */
+ uint32_t dirblksize;
+ uint8_t dirblklog;
+ uint8_t inopb_shift;
+ uint8_t agblk_shift;
+ uint32_t dirleafblk;
+
+ /* AG number bits (MSB of the inode number) */
+ uint8_t ag_number_ino_shift;
+
+ xfs_ino_t rootino; /* Root inode number for the filesystem */
+ xfs_agblock_t agblocks; /* Size of each AG in blocks */
+ uint8_t agblocks_shift; /* agblocks in bits */
+ xfs_agnumber_t agcount; /* Number of AGs in the filesytem */
+ uint16_t inodesize; /* Size of the inode in bytes */
+ uint8_t inode_shift; /* Inode size in bits */
+} __attribute__((__packed__));
+
+typedef struct xfs_agi {
+ /*
+ * Common allocation group header information
+ */
+ uint32_t agi_magicnum; /* magic number == XFS_AGI_MAGIC */
+ uint32_t agi_versionnum; /* header version == XFS_AGI_VERSION */
+ uint32_t agi_seqno; /* sequence # starting from 0 */
+ uint32_t agi_length; /* size in blocks of a.g. */
+ /*
+ * Inode information
+ * Inodes are mapped by interpreting the inode number, so no
+ * mapping data is needed here.
+ */
+ uint32_t agi_count; /* count of allocated inodes */
+ uint32_t agi_root; /* root of inode btree */
+ uint32_t agi_level; /* levels in inode btree */
+ uint32_t agi_freecount; /* number of free inodes */
+ uint32_t agi_newino; /* new inode just allocated */
+ uint32_t agi_dirino; /* last directory inode chunk */
+ /*
+ * Hash table of inodes which have been unlinked but are
+ * still being referenced.
+ */
+ uint32_t agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
+} __attribute__((__packed__)) xfs_agi_t;
+
+/*
+ * Bmap btree record and extent descriptor.
+ * l0:63 is an extent flag (value 1 indicates non-normal).
+ * l0:9-62 are startoff.
+ * l0:0-8 and l1:21-63 are startblock.
+ * l1:0-20 are blockcount.
+ */
+typedef struct xfs_bmbt_rec {
+ uint64_t l0;
+ uint64_t l1;
+} __attribute__((__packed__)) xfs_bmbt_rec_t;
+
+typedef xfs_bmbt_rec_t xfs_bmdr_rec_t;
+
+/*
+ * Possible extent states.
+ */
+typedef enum {
+ XFS_EXT_NORM,
+ XFS_EXT_UNWRITTEN,
+ XFS_EXT_DMAPI_OFFLINE,
+ XFS_EXT_INVALID,
+} xfs_exntst_t;
+
+typedef struct xfs_bmbt_irec
+{
+ xfs_fileoff_t br_startoff; /* starting file offset */
+ xfs_fsblock_t br_startblock; /* starting block number */
+ xfs_filblks_t br_blockcount; /* number of blocks */
+ xfs_exntst_t br_state; /* extent state */
+} __attribute__((__packed__)) xfs_bmbt_irec_t;
+
+static inline void bmbt_irec_get(xfs_bmbt_irec_t *dest,
+ const xfs_bmbt_rec_t *src)
+{
+ uint64_t l0, l1;
+
+ l0 = be64_to_cpu(src->l0);
+ l1 = be64_to_cpu(src->l1);
+
+ dest->br_startoff = ((xfs_fileoff_t)l0 & 0x7ffffffffffffe00ULL) >> 9;
+ dest->br_startblock = (((xfs_fsblock_t)l0 & 0x00000000000001ffULL) << 43) |
+ (((xfs_fsblock_t)l1) >> 21);
+ dest->br_blockcount = (xfs_filblks_t)(l1 & 0x00000000001fffffULL);
+ dest->br_state = (l0 & 0x8000000000000000ULL) ?
+ XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
+}
+
+typedef struct xfs_timestamp {
+ int32_t t_sec;
+ int32_t t_nsec;
+} __attribute__((__packed__)) xfs_timestamp_t;
+
+/*
+ * Fork identifiers.
+ */
+#define XFS_DATA_FORK 0
+#define xFS_ATTR_FORK 1
+
+typedef enum xfs_dinode_fmt {
+ XFS_DINODE_FMT_DEV,
+ XFS_DINODE_FMT_LOCAL,
+ XFS_DINODE_FMT_EXTENTS,
+ XFS_DINODE_FMT_BTREE,
+ XFS_DINODE_FMT_UUID,
+} xfs_dinode_fmt_t;
+
+typedef struct xfs_dinode {
+ uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */
+ uint16_t di_mode; /* mode and type of file */
+ uint8_t di_version; /* inode version */
+ uint8_t di_format; /* format of di_c data */
+ uint16_t di_onlink; /* old number of links to file */
+ uint32_t di_uid; /* owner's user id */
+ uint32_t di_gid; /* owner's group id */
+ uint32_t di_nlink; /* number of links to file */
+ uint16_t di_projid_lo; /* lower part of owner's project id */
+ uint16_t di_projid_hi; /* higher part owner's project id */
+ uint8_t di_pad[6]; /* unused, zeroed space */
+ uint16_t di_flushiter; /* incremented on flush */
+ xfs_timestamp_t di_atime; /* time last accessed */
+ xfs_timestamp_t di_mtime; /* time last modified */
+ xfs_timestamp_t di_ctime; /* time created/inode modified */
+ uint64_t di_size; /* number of bytes in file */
+ uint64_t di_nblocks; /* # of direct & btree blocks used */
+ uint32_t di_extsize; /* basic/minimum extent size for file */
+ uint32_t di_nextents; /* number of extents in data fork */
+ uint16_t di_anextents; /* number of extents in attribute fork*/
+ uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */
+ int8_t di_aformat; /* format of attr fork's data */
+ uint32_t di_dmevmask; /* DMIG event mask */
+ uint16_t di_dmstate; /* DMIG state info */
+ uint16_t di_flags; /* random flags, XFS_DIFLAG_... */
+ uint32_t di_gen; /* generation number */
+
+ /* di_next_unlinked is the only non-core field in the old dinode */
+ uint32_t di_next_unlinked;/* agi unlinked list ptr */
+ uint8_t di_literal_area[1];
+} __attribute__((packed)) xfs_dinode_t;
+
+/*
+ * Inode size for given fs.
+ */
+#define XFS_LITINO(fs) \
+ ((int)((XFS_INFO(fs)->inodesize) - sizeof(struct xfs_dinode) - 1))
+
+#define XFS_BROOT_SIZE_ADJ \
+ (XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
+
+/*
+ * Inode data & attribute fork sizes, per inode.
+ */
+#define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0)
+#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3))
+
+#define XFS_DFORK_DSIZE(dip, fs) \
+ (XFS_DFORK_Q(dip) ? \
+ XFS_DFORK_BOFF(dip) : \
+ XFS_LITINO(fs))
+#define XFS_DFORK_ASIZE(dip, fs) \
+ (XFS_DFORK_Q(dip) ? \
+ XFS_LITINO(fs) - XFS_DFORK_BOFF(dip) : \
+ 0)
+#define XFS_DFORK_SIZE(dip, fs, w) \
+ ((w) == XFS_DATA_FORK ? \
+ XFS_DFORK_DSIZE(dip, fs) : \
+ XFS_DFORK_ASIZE(dip, fs))
+
+struct xfs_inode {
+ xfs_agblock_t i_agblock;
+ block_t i_ino_blk;
+ uint64_t i_block_offset;
+ uint64_t i_offset;
+ uint32_t i_cur_extent;
+ uint32_t i_btree_offset;
+ uint16_t i_leaf_ent_offset;
+};
+
+typedef struct { uint8_t i[8]; } __attribute__((__packed__)) xfs_dir2_ino8_t;
+typedef struct { uint8_t i[4]; } __attribute__((__packed__)) xfs_dir2_ino4_t;
+
+typedef union {
+ xfs_dir2_ino8_t i8;
+ xfs_dir2_ino4_t i4;
+} __attribute__((__packed__)) xfs_dir2_inou_t;
+
+typedef struct { uint8_t i[2]; } __attribute__((__packed__)) xfs_dir2_sf_off_t;
+
+typedef struct xfs_dir2_sf_hdr {
+ uint8_t count; /* count of entries */
+ uint8_t i8count; /* count of 8-byte inode #s */
+ xfs_dir2_inou_t parent; /* parent dir inode number */
+} __attribute__((__packed__)) xfs_dir2_sf_hdr_t;
+
+typedef struct xfs_dir2_sf_entry {
+ uint8_t namelen; /* actual name length */
+ xfs_dir2_sf_off_t offset; /* saved offset */
+ uint8_t name[1]; /* name, variable size */
+ xfs_dir2_inou_t inumber; /* inode number, var. offset */
+} __attribute__((__packed__)) xfs_dir2_sf_entry_t;
+
+typedef struct xfs_dir2_sf {
+ xfs_dir2_sf_hdr_t hdr; /* shortform header */
+ xfs_dir2_sf_entry_t list[1]; /* shortform entries */
+} __attribute__((__packed__)) xfs_dir2_sf_t;
+
+typedef xfs_ino_t xfs_intino_t;
+
+static inline xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp,
+ xfs_dir2_inou_t *from)
+{
+ return ((sfp)->hdr.i8count == 0 ? \
+ (xfs_intino_t)XFS_GET_DIR_INO4((from)->i4) : \
+ (xfs_intino_t)XFS_GET_DIR_INO8((from)->i8));
+}
+
+/*
+ * DIR2 Data block structures.
+ *
+ * A pure data block looks like the following drawing on disk:
+ *
+ * +-------------------------------------------------+
+ * | xfs_dir2_data_hdr_t |
+ * +-------------------------------------------------+
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | ... |
+ * +-------------------------------------------------+
+ * | unused space |
+ * +-------------------------------------------------+
+ *
+ * As all the entries are variable size structure the accessors below should
+ * be used to iterate over them.
+ *
+ * In addition to the pure data blocks for the data and node formats.
+ * most structures are also used for the combined data/freespace "block"
+ * format below.
+ */
+#define XFS_DIR2_DATA_ALIGN_LOG 3
+#define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG)
+#define XFS_DIR2_DATA_FREE_TAG 0xffff
+#define XFS_DIR2_DATA_FD_COUNT 3
+
+/*
+ * Directory address space divided into sections.
+ * spaces separated by 32GB.
+ */
+#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
+
+typedef struct xfs_dir2_data_free {
+ uint16_t offset;
+ uint16_t length;
+} __attribute__((__packed__)) xfs_dir2_data_free_t;
+
+typedef struct xfs_dir2_data_hdr {
+ uint32_t magic;
+ xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
+} __attribute__((__packed__)) xfs_dir2_data_hdr_t;
+
+typedef struct xfs_dir2_data_entry {
+ uint64_t inumber; /* inode number */
+ uint8_t namelen; /* name length */
+ uint8_t name[]; /* name types, no null */
+ /* uint16_t tag; */ /* starting offset of us */
+} __attribute__((__packed__)) xfs_dir2_data_entry_t;
+
+typedef struct xfs_dir2_data_unused {
+ uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */
+ uint16_t length; /* total free length */
+ /* variable offset */
+ /* uint16_t tag; */ /* starting offset of us */
+} __attribute__((__packed__)) xfs_dir2_data_unused_t;
+
+/**
+ * rol32 - rotate a 32-bit value left
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline uint32_t rol32(uint32_t word, signed int shift)
+{
+ return (word << shift) | (word >> (32 - shift));
+}
+
+#define roundup(x, y) ( \
+{ \
+ const typeof(y) __y = y; \
+ (((x) + (__y - 1)) / __y) * __y; \
+} \
+)
+
+static inline int xfs_dir2_data_entsize(int n)
+{
+ return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n +
+ (unsigned int)sizeof(uint16_t), XFS_DIR2_DATA_ALIGN);
+}
+
+static inline uint16_t *
+xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep)
+{
+ return (uint16_t *)((char *)dep +
+ xfs_dir2_data_entsize(dep->namelen) - sizeof(uint16_t));
+}
+
+static inline uint16_t *
+xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup)
+{
+ return (uint16_t *)((char *)dup +
+ be16_to_cpu(dup->length) - sizeof(uint16_t));
+}
+
+typedef struct xfs_dir2_block_tail {
+ uint32_t count; /* count of leaf entries */
+ uint32_t stale; /* count of stale lf entries */
+} __attribute__((__packed__)) xfs_dir2_block_tail_t;
+
+static inline struct xfs_dir2_block_tail *
+xfs_dir2_block_tail_p(struct xfs_fs_info *fs_info, struct xfs_dir2_data_hdr *hdr)
+{
+ return ((struct xfs_dir2_block_tail *)
+ ((char *)hdr + fs_info->dirblksize)) - 1;
+}
+
+static inline uint32_t
+xfs_dir2_db_to_da(struct fs_info *fs, uint32_t db)
+{
+ return db << XFS_INFO(fs)->dirblklog;
+}
+
+static inline int64_t
+xfs_dir2_dataptr_to_byte(uint32_t dp)
+{
+ return (int64_t)dp << XFS_DIR2_DATA_ALIGN_LOG;
+}
+
+static inline uint32_t
+xfs_dir2_byte_to_db(struct fs_info *fs, int64_t by)
+{
+ return (uint32_t)
+ (by >> (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog));
+}
+
+static inline uint32_t
+xfs_dir2_dataptr_to_db(struct fs_info *fs, uint32_t dp)
+{
+ return xfs_dir2_byte_to_db(fs, xfs_dir2_dataptr_to_byte(dp));
+}
+
+static inline unsigned int
+xfs_dir2_byte_to_off(struct fs_info *fs, int64_t by)
+{
+ return (unsigned int)(by &
+ (( 1 << (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog)) - 1));
+}
+
+static inline unsigned int
+xfs_dir2_dataptr_to_off(struct fs_info *fs, uint32_t dp)
+{
+ return xfs_dir2_byte_to_off(fs, xfs_dir2_dataptr_to_byte(dp));
+}
+
+#define XFS_DIR2_LEAF_SPACE 1
+#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
+#define XFS_DIR2_LEAF_FIRSTDB(fs) \
+ xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET)
+
+typedef struct xfs_da_blkinfo {
+ uint32_t forw;
+ uint32_t back;
+ uint16_t magic;
+ uint16_t pad;
+} __attribute__((__packed__)) xfs_da_blkinfo_t;
+
+typedef struct xfs_dir2_leaf_hdr {
+ xfs_da_blkinfo_t info;
+ uint16_t count;
+ uint16_t stale;
+} __attribute__((__packed__)) xfs_dir2_leaf_hdr_t;
+
+typedef struct xfs_dir2_leaf_entry {
+ uint32_t hashval; /* hash value of name */
+ uint32_t address; /* address of data entry */
+} __attribute__((__packed__)) xfs_dir2_leaf_entry_t;
+
+typedef struct xfs_dir2_leaf {
+ xfs_dir2_leaf_hdr_t hdr; /* leaf header */
+ xfs_dir2_leaf_entry_t ents[]; /* entries */
+} __attribute__((__packed__)) xfs_dir2_leaf_t;
+
+#define XFS_DA_NODE_MAGIC 0xfebeU /* magic number: non-leaf blocks */
+#define XFS_ATTR_LEAF_MAGIC 0xfbeeU /* magic number: attribute leaf blks */
+#define XFS_DIR2_LEAF1_MAGIC 0xd2f1U /* magic number: v2 dirlf single blks */
+#define XFS_DIR2_LEAFN_MAGIC 0xd2ffU /* magic number: V2 dirlf multi blks */
+
+typedef struct xfs_da_intnode {
+ struct xfs_da_node_hdr { /* constant-structure header block */
+ xfs_da_blkinfo_t info; /* block type, links, etc. */
+ uint16_t count; /* count of active entries */
+ uint16_t level; /* level above leaves (leaf == 0) */
+ } hdr;
+ struct xfs_da_node_entry {
+ uint32_t hashval; /* hash value for this descendant */
+ uint32_t before; /* Btree block before this key */
+ } btree[1];
+} __attribute__((__packed__)) xfs_da_intnode_t;
+
+typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
+typedef struct xfs_da_node_entry xfs_da_node_entry_t;
+
+static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb)
+{
+ return sb->sb_magicnum == *(uint32_t *)XFS_SB_MAGIC;
+}
+
+static inline bool xfs_is_valid_agi(xfs_agi_t *agi)
+{
+ return agi->agi_magicnum == *(uint32_t *)XFS_AGI_MAGIC;
+}
+
+static inline struct inode *xfs_new_inode(struct fs_info *fs)
+{
+ struct inode *inode;
+
+ inode = alloc_inode(fs, 0, sizeof(struct xfs_inode));
+ if (!inode)
+ malloc_error("xfs_inode structure");
+
+ return inode;
+}
+
+static inline void fill_xfs_inode_pvt(struct fs_info *fs, struct inode *inode,
+ xfs_ino_t ino)
+{
+ XFS_PVT(inode)->i_agblock =
+ agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, ino)) >> BLOCK_SHIFT(fs);
+ XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+ XFS_PVT(inode)->i_block_offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) <<
+ XFS_INFO(fs)->inode_shift;
+}
+
+/*
+ * Generic btree header.
+ *
+ * This is a combination of the actual format used on disk for short and long
+ * format btrees. The first three fields are shared by both format, but
+ * the pointers are different and should be used with care.
+ *
+ * To get the size of the actual short or long form headers please use
+ * the size macros belows. Never use sizeof(xfs_btree_block);
+ */
+typedef struct xfs_btree_block {
+ uint32_t bb_magic; /* magic number for block type */
+ uint16_t bb_level; /* 0 is a leaf */
+ uint16_t bb_numrecs; /* current # of data records */
+ union {
+ struct {
+ uint32_t bb_leftsib;
+ uint32_t bb_rightsib;
+ } s; /* short form pointers */
+ struct {
+ uint64_t bb_leftsib;
+ uint64_t bb_rightsib;
+ } l; /* long form pointers */
+ } bb_u; /* rest */
+} xfs_btree_block_t;
+
+#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */
+#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */
+
+/*
+ * Bmap root header, on-disk form only.
+ */
+typedef struct xfs_bmdr_block {
+ uint16_t bb_level; /* 0 is a leaf */
+ uint16_t bb_numrecs; /* current # of data records */
+} xfs_bmdr_block_t;
+
+/*
+ * Key structure for non-leaf levels of the tree.
+ */
+typedef struct xfs_bmbt_key {
+ uint64_t br_startoff; /* starting file offset */
+} xfs_bmbt_key_t, xfs_bmdr_key_t;
+
+/* btree pointer type */
+typedef uint64_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
+
+/*
+ * Btree block header size depends on a superblock flag.
+ *
+ * (not quite yet, but soon)
+ */
+#define XFS_BMBT_BLOCK_LEN(fs) XFS_BTREE_LBLOCK_LEN
+
+#define XFS_BMBT_REC_ADDR(fs, block, index) \
+ ((xfs_bmbt_rec_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ ((index) - 1) * sizeof(xfs_bmbt_rec_t)))
+
+#define XFS_BMBT_KEY_ADDR(fs, block, index) \
+ ((xfs_bmbt_key_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ ((index) - 1) * sizeof(xfs_bmbt_key_t)))
+
+#define XFS_BMBT_PTR_ADDR(fs, block, index, maxrecs) \
+ ((xfs_bmbt_ptr_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ (maxrecs) * sizeof(xfs_bmbt_key_t) + \
+ ((index) - 1) * sizeof(xfs_bmbt_ptr_t)))
+
+#define XFS_BMDR_REC_ADDR(block, index) \
+ ((xfs_bmdr_rec_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ ((index) - 1) * sizeof(xfs_bmdr_rec_t)))
+
+#define XFS_BMDR_KEY_ADDR(block, index) \
+ ((xfs_bmdr_key_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ ((index) - 1) * sizeof(xfs_bmdr_key_t)))
+
+#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \
+ ((xfs_bmdr_ptr_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ (maxrecs) * sizeof(xfs_bmdr_key_t) + \
+ ((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
+
+/*
+ * Calculate number of records in a bmap btree inode root.
+ */
+static inline int
+xfs_bmdr_maxrecs(int blocklen, int leaf)
+{
+ blocklen -= sizeof(xfs_bmdr_block_t);
+
+ if (leaf)
+ return blocklen / sizeof(xfs_bmdr_rec_t);
+
+ return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
+}
+
+#endif /* XFS_H_ */
diff --git a/core/fs/xfs/xfs_ag.h b/core/fs/xfs/xfs_ag.h
new file mode 100644
index 00000000..a2988b10
--- /dev/null
+++ b/core/fs/xfs/xfs_ag.h
@@ -0,0 +1,189 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_AG_H_
+#define XFS_AG_H_
+
+#include "xfs_types.h"
+
+/*
+ * Allocation group header
+ * This is divided into three structures, placed in sequential 512-byte
+ * buffers after a copy of the superblock (also in a 512-byte buffer).
+ */
+
+typedef uint32_t xfs_agino_t;
+
+struct xfs_buf;
+struct xfs_mount;
+struct xfs_trans;
+
+#define XFS_AGF_MAGIC "XAGF"
+#define XFS_AGF_VERSION 1
+#define XFS_AGI_VERSION 1
+
+#define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION)
+#define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION)
+
+/*
+ * Btree number 0 is bno, 1 is cnt. This value gives the size of the
+ * arrays below.
+ */
+#define XFS_BTNUM_AGF ((int)XFS_BTNUM_CNTi + 1)
+
+/*
+ * The second word of agf_levels in the first a.g. overlaps the EFS
+ * superblock's magic number. Since the magic numbers valid for EFS
+ * are > 64k, our value cannot be confused for an EFS superblock's.
+ */
+
+typedef struct xfs_agf {
+ /*
+ * Common allocation group header information
+ */
+ uint32_t agf_magicnum; /* magic number == XFS_AGF_MAGIC */
+ uint32_t agf_versionnum; /* header version == XFS_AGF_VERSION */
+ uint32_t agf_seqno; /* sequence # starting from 0 */
+ uint32_t agf_length; /* size in blocks of a.g. */
+ /*
+ * Freespace information
+ */
+ uint32_t agf_roots[XFS_BTNUM_AGF]; /* root blocks */
+ uint32_t agf_spare0; /* spare field */
+ uint32_t agf_levels[XFS_BTNUM_AGF]; /* btree levels */
+ uint32_t agf_spare1; /* spare field */
+ uint32_t agf_flfirst; /* first freelist block's index */
+ uint32_t agf_fllast; /* last freelist block's index */
+ uint32_t agf_flcount; /* count of blocks in freelist */
+ uint32_t agf_freeblks; /* total free blocks */
+ uint32_t agf_longest; /* longest free space */
+ uint32_t agf_btreeblks; /* # of blocks held in AGF btrees */
+} xfs_agf_t;
+
+#define XFS_AGF_MAGICNUM 0x00000001
+#define XFS_AGF_VERSIONNUM 0x00000002
+#define XFS_AGF_SEQNO 0x00000004
+#define XFS_AGF_LENGTH 0x00000008
+#define XFS_AGF_ROOTS 0x00000010
+#define XFS_AGF_LEVELS 0x00000020
+#define XFS_AGF_FLFIRST 0x00000040
+#define XFS_AGF_FLLAST 0x00000080
+#define XFS_AGF_FLCOUNT 0x00000100
+#define XFS_AGF_FREEBLKS 0x00000200
+#define XFS_AGF_LONGEST 0x00000400
+#define XFS_AGF_BTREEBLKS 0x00000800
+#define XFS_AGF_NUM_BITS 12
+#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1)
+
+#define XFS_AGF_FLAGS \
+ { XFS_AGF_MAGICNUM, "MAGICNUM" }, \
+ { XFS_AGF_VERSIONNUM, "VERSIONNUM" }, \
+ { XFS_AGF_SEQNO, "SEQNO" }, \
+ { XFS_AGF_LENGTH, "LENGTH" }, \
+ { XFS_AGF_ROOTS, "ROOTS" }, \
+ { XFS_AGF_LEVELS, "LEVELS" }, \
+ { XFS_AGF_FLFIRST, "FLFIRST" }, \
+ { XFS_AGF_FLLAST, "FLLAST" }, \
+ { XFS_AGF_FLCOUNT, "FLCOUNT" }, \
+ { XFS_AGF_FREEBLKS, "FREEBLKS" }, \
+ { XFS_AGF_LONGEST, "LONGEST" }, \
+ { XFS_AGF_BTREEBLKS, "BTREEBLKS" }
+
+/* disk block (xfs_daddr_t) in the AG */
+#define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log))
+#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp))
+#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)((bp)->b_addr))
+
+extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
+ xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
+
+/*
+ * Size of the unlinked inode hash table in the agi.
+ */
+#define XFS_AGI_UNLINKED_BUCKETS 64
+
+#define XFS_AGI_MAGICNUM 0x00000001
+#define XFS_AGI_VERSIONNUM 0x00000002
+#define XFS_AGI_SEQNO 0x00000004
+#define XFS_AGI_LENGTH 0x00000008
+#define XFS_AGI_COUNT 0x00000010
+#define XFS_AGI_ROOT 0x00000020
+#define XFS_AGI_LEVEL 0x00000040
+#define XFS_AGI_FREECOUNT 0x00000080
+#define XFS_AGI_NEWINO 0x00000100
+#define XFS_AGI_DIRINO 0x00000200
+#define XFS_AGI_UNLINKED 0x00000400
+#define XFS_AGI_NUM_BITS 11
+#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1)
+
+/* disk block (xfs_daddr_t) in the AG */
+#define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
+#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp))
+#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)((bp)->b_addr))
+
+extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
+ xfs_agnumber_t agno, struct xfs_buf **bpp);
+
+/*
+ * The third a.g. block contains the a.g. freelist, an array
+ * of block pointers to blocks owned by the allocation btree code.
+ */
+#define XFS_AGFL_DADDR(mp) ((xfs_daddr_t)(3 << (mp)->m_sectbb_log))
+#define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp))
+#define XFS_AGFL_SIZE(mp) ((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t))
+#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)((bp)->b_addr))
+
+typedef struct xfs_agfl {
+ uint32_t agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */
+} xfs_agfl_t;
+
+/*
+ * tags for inode radix tree
+ */
+#define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup
+ in xfs_inode_ag_iterator */
+#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */
+
+#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)
+#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \
+ (MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + MIN(cl + 1, XFS_AG_MAXLEVELS(mp)))
+#define XFS_MIN_FREELIST(a,mp) \
+ (XFS_MIN_FREELIST_RAW( \
+ be32_to_cpu((a)->agf_levels[XFS_BTNUM_BNOi]), \
+ be32_to_cpu((a)->agf_levels[XFS_BTNUM_CNTi]), mp))
+#define XFS_MIN_FREELIST_PAG(pag,mp) \
+ (XFS_MIN_FREELIST_RAW( \
+ (unsigned int)(pag)->pagf_levels[XFS_BTNUM_BNOi], \
+ (unsigned int)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp))
+
+/*
+ * For checking for bad ranges of xfs_daddr_t's, covering multiple
+ * allocation groups or a single xfs_daddr_t that's a superblock copy.
+ */
+#define XFS_AG_CHECK_DADDR(mp,d,len) \
+ ((len) == 1 ? \
+ ASSERT((d) == XFS_SB_DADDR || \
+ xfs_daddr_to_agbno(mp, d) != XFS_SB_DADDR) : \
+ ASSERT(xfs_daddr_to_agno(mp, d) == \
+ xfs_daddr_to_agno(mp, (d) + (len) - 1)))
+
+#endif /* XFS_AG_H_ */
diff --git a/core/fs/xfs/xfs_dinode.c b/core/fs/xfs/xfs_dinode.c
new file mode 100644
index 00000000..8e2d8d04
--- /dev/null
+++ b/core/fs/xfs/xfs_dinode.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+
+#include "xfs_dinode.h"
+
+xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino)
+{
+ block_t blk;
+ xfs_dinode_t *core;
+ uint64_t offset;
+
+ xfs_debug("ino %lu", ino);
+
+ blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+ offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) << XFS_INFO(fs)->inode_shift;
+ if (offset > BLOCK_SIZE(fs)) {
+ xfs_error("Invalid inode offset in block!");
+ xfs_debug("offset: 0x%llx", offset);
+ goto out;
+ }
+
+ xfs_debug("blk %llu block offset 0x%llx", blk, blk << BLOCK_SHIFT(fs));
+ xfs_debug("inode offset in block (in bytes) is 0x%llx", offset);
+
+ core = (xfs_dinode_t *)((uint8_t *)get_cache(fs->fs_dev, blk) + offset);
+ if (be16_to_cpu(core->di_magic) !=
+ be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC)) {
+ xfs_error("Inode core's magic number does not match!");
+ xfs_debug("magic number 0x%04x", (be16_to_cpu(core->di_magic)));
+ goto out;
+ }
+
+ return core;
+
+out:
+ return NULL;
+}
diff --git a/core/fs/xfs/xfs_dinode.h b/core/fs/xfs/xfs_dinode.h
new file mode 100644
index 00000000..80deec78
--- /dev/null
+++ b/core/fs/xfs/xfs_dinode.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_DINODE_H_
+#define XFS_DINODE_H_
+
+xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino);
+
+#endif /* XFS_DINODE_H_ */
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
new file mode 100644
index 00000000..c52196ae
--- /dev/null
+++ b/core/fs/xfs/xfs_dir2.c
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+
+#include "xfs_dir2.h"
+
+char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end)
+{
+ char *s;
+ char *p;
+
+ s = malloc(end - start + 1);
+ if (!s)
+ malloc_error("string");
+
+ p = s;
+ while (start < end)
+ *p++ = *start++;
+
+ *p = '\0';
+
+ return s;
+}
+
+uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen)
+{
+ uint32_t hash;
+
+ /*
+ * Do four characters at a time as long as we can.
+ */
+ for (hash = 0; namelen >= 4; namelen -=4, name += 4)
+ hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^
+ (name[3] << 0) ^ rol32(hash, 7 * 4);
+
+ /*
+ * Now do the rest of the characters.
+ */
+ switch (namelen) {
+ case 3:
+ return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^
+ rol32(hash, 7 * 3);
+ case 2:
+ return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2);
+ case 1:
+ return (name[0] << 0) ^ rol32(hash, 7 * 1);
+ default: /* case 0: */
+ return hash;
+ }
+}
+
+void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
+ xfs_filblks_t c)
+{
+ int count = c << XFS_INFO(fs)->dirblklog;
+ uint8_t *p;
+ uint8_t *buf;
+ off_t offset = 0;
+
+ buf = malloc(c * XFS_INFO(fs)->dirblksize);
+ if (!buf)
+ malloc_error("buffer memory");
+
+ memset(buf, 0, XFS_INFO(fs)->dirblksize);
+
+ while (count--) {
+ p = (uint8_t *)get_cache(fs->fs_dev, startblock++);
+ memcpy(buf + offset, p, BLOCK_SIZE(fs));
+ offset += BLOCK_SIZE(fs);
+ }
+
+ return buf;
+}
+
+struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+ xfs_dir2_sf_entry_t *sf_entry;
+ uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
+ struct fs_info *fs = parent->fs;
+ struct inode *inode;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore = NULL;
+
+ xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+ (!sf->hdr.i8count ? 4 : 0));
+ while (count--) {
+ uint8_t *start_name = &sf_entry->name[0];
+ uint8_t *end_name = start_name + sf_entry->namelen;
+ char *name;
+
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ xfs_debug("entry name: %s", name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen +
+ (sf->hdr.i8count ? 8 : 4));
+ }
+
+ return NULL;
+
+found:
+ inode = xfs_new_inode(fs);
+
+ ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen));
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto out;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, ino);
+
+ inode->ino = ino;
+ inode->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ inode->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ inode->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", inode->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ inode->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ return inode;
+
+out:
+ free(inode);
+
+ return NULL;
+}
+
+struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t r;
+ block_t dir_blk;
+ struct fs_info *fs = parent->fs;
+ uint8_t *dirblk_buf;
+ uint8_t *p, *endp;
+ xfs_dir2_data_hdr_t *hdr;
+ struct inode *inode = NULL;
+ xfs_dir2_block_tail_t *btp;
+ xfs_dir2_data_unused_t *dup;
+ xfs_dir2_data_entry_t *dep;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+
+ bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+ dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+ hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+ if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+ xfs_error("Block directory header's magic number does not match!");
+ xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
+ goto out;
+ }
+
+ p = (uint8_t *)(hdr + 1);
+
+ btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+ endp = (uint8_t *)((xfs_dir2_leaf_entry_t *)btp - be32_to_cpu(btp->count));
+
+ while (p < endp) {
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+
+ dup = (xfs_dir2_data_unused_t *)p;
+ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+ p += be16_to_cpu(dup->length);
+ continue;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ p += xfs_dir2_data_entsize(dep->namelen);
+ }
+
+out:
+ free(dirblk_buf);
+
+ return NULL;
+
+found:
+ inode = xfs_new_inode(fs);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, ino);
+
+ inode->ino = ino;
+ XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+ inode->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ inode->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ inode->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", inode->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ inode->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(dirblk_buf);
+ return inode;
+
+failed:
+ free(inode);
+ free(dirblk_buf);
+
+ return NULL;
+}
+
+struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_leaf_t *leaf;
+ xfs_bmbt_irec_t irec;
+ block_t leaf_blk, dir_blk;
+ xfs_dir2_leaf_entry_t *lep;
+ int low;
+ int high;
+ int mid = 0;
+ uint32_t hash = 0;
+ uint32_t hashwant;
+ uint32_t newdb, curdb = -1;
+ xfs_dir2_data_entry_t *dep;
+ struct inode *ip;
+ xfs_dir2_data_hdr_t *data_hdr;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+ uint8_t *buf = NULL;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
+ be32_to_cpu(core->di_nextents) - 1);
+ leaf_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
+ BLOCK_SHIFT(parent->fs);
+
+ leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(parent->fs, leaf_blk,
+ irec.br_blockcount);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+ xfs_error("Single leaf block header's magic number does not match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
+ /* Binary search */
+ for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
+ low <= high; ) {
+ mid = (low + high) >> 1;
+ if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+ break;
+ if (hash < hashwant)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ /* If hash is not the one we want, then the directory does not contain the
+ * entry we're looking for and there is nothing to do anymore.
+ */
+ if (hash != hashwant)
+ goto out;
+
+ while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+ mid--;
+
+ for (lep = &leaf->ents[mid];
+ mid < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->hashval) == hashwant;
+ lep++, mid++) {
+ /* Skip over stale leaf entries. */
+ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+ continue;
+
+ newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
+ if (newdb != curdb) {
+ if (buf)
+ free(buf);
+
+ bmbt_irec_get(&irec,
+ ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + newdb);
+ dir_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
+ BLOCK_SHIFT(parent->fs);
+ buf = xfs_dir2_get_dirblks(parent->fs, dir_blk, irec.br_blockcount);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not match!");
+ goto out1;
+ }
+
+ curdb = newdb;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)((char *)buf +
+ xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ }
+
+out1:
+ free(buf);
+out:
+ free(leaf);
+
+ return NULL;
+
+found:
+ ip = xfs_new_inode(parent->fs);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(parent->fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(parent->fs, ip, ino);
+
+ ip->ino = ino;
+ XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
+ BLOCK_SHIFT(parent->fs);
+ ip->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ ip->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ ip->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", ip->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ ip->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(buf);
+ free(leaf);
+
+ return ip;
+
+failed:
+ free(ip);
+ free(buf);
+ free(leaf);
+
+ return ip;
+}
+
+static xfs_fsblock_t
+select_child(xfs_dfiloff_t off,
+ xfs_bmbt_key_t *kp,
+ xfs_bmbt_ptr_t *pp,
+ int nrecs)
+{
+ int i;
+
+ for (i = 0; i < nrecs; i++) {
+ if (be64_to_cpu(kp[i].br_startoff) == off)
+ return be64_to_cpu(pp[i]);
+ if (be64_to_cpu(kp[i].br_startoff) > off) {
+ if (i == 0)
+ return be64_to_cpu(pp[i]);
+ else
+ return be64_to_cpu(pp[i-1]);
+ }
+ }
+
+ return be64_to_cpu(pp[nrecs - 1]);
+}
+
+block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+ block_t fsblkno, int *error)
+{
+ uint32_t idx;
+ xfs_bmbt_irec_t irec;
+ block_t bno;
+ block_t nextbno;
+ xfs_bmdr_block_t *rblock;
+ int fsize;
+ int nextents;
+ xfs_bmbt_ptr_t *pp;
+ xfs_bmbt_key_t *kp;
+ xfs_btree_block_t *blk;
+ xfs_bmbt_rec_t *xp;
+
+ *error = 0;
+ if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ xfs_debug("XFS_DINODE_FMT_EXTENTS");
+ for (idx = 0; idx < be32_to_cpu(core->di_nextents); idx++) {
+ bmbt_irec_get(&irec,
+ ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + idx);
+ if (fsblkno >= irec.br_startoff &&
+ fsblkno < irec.br_startoff + irec.br_blockcount)
+ break;
+ }
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ xfs_debug("XFS_DINODE_FMT_BTREE");
+ bno = NULLFSBLOCK;
+ rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+ pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+ kp = XFS_BMDR_KEY_ADDR(rblock, 1);
+ bno = fsblock_to_bytes(fs,
+ select_child(fsblkno, kp, pp,
+ be16_to_cpu(rblock->bb_numrecs))) >> BLOCK_SHIFT(fs);
+
+ /* Find the leaf */
+ for (;;) {
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ if (be16_to_cpu(blk->bb_level) == 0)
+ break;
+ pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+ xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+ kp = XFS_BMBT_KEY_ADDR(fs, blk, 1);
+ bno = fsblock_to_bytes(fs,
+ select_child(fsblkno, kp, pp,
+ be16_to_cpu(blk->bb_numrecs))) >> BLOCK_SHIFT(fs);
+ }
+
+ /* Find the records among leaves */
+ for (;;) {
+ nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+ nextents = be16_to_cpu(blk->bb_numrecs);
+ xp = (xfs_bmbt_rec_t *)XFS_BMBT_REC_ADDR(fs, blk, 1);
+ for (idx = 0; idx < nextents; idx++) {
+ bmbt_irec_get(&irec, xp + idx);
+ if (fsblkno >= irec.br_startoff &&
+ fsblkno < irec.br_startoff + irec.br_blockcount) {
+ nextbno = NULLFSBLOCK;
+ break;
+ }
+ }
+ if (nextbno == NULLFSBLOCK)
+ break;
+ bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ }
+ }
+
+ if (fsblkno < irec.br_startoff ||
+ fsblkno >= irec.br_startoff + irec.br_blockcount)
+ *error = 1;
+
+ return fsblock_to_bytes(fs,
+ fsblkno - irec.br_startoff + irec.br_startblock) >>
+ BLOCK_SHIFT(fs);
+}
+
+struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ block_t fsblkno;
+ xfs_da_intnode_t *node = NULL;
+ uint32_t hashwant;
+ uint32_t hash = 0;
+ xfs_da_node_entry_t *btree;
+ uint16_t max;
+ uint16_t span;
+ uint16_t probe;
+ int error;
+ xfs_dir2_data_hdr_t *data_hdr;
+ xfs_dir2_leaf_t *leaf;
+ xfs_dir2_leaf_entry_t *lep;
+ xfs_dir2_data_entry_t *dep;
+ struct inode *ip;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ int low;
+ int high;
+ int mid = 0;
+ uint32_t newdb, curdb = -1;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+ uint8_t *buf = NULL;
+
+ hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core,
+ xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET),
+ &error);
+ if (error) {
+ xfs_error("Cannot find right rec!");
+ return NULL;
+ }
+
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+ xfs_error("Node's magic number does not match!");
+ goto out;
+ }
+
+ do {
+ if (!node->hdr.count)
+ goto out;
+
+ /* Given a hash to lookup, you read the node's btree array and first
+ * "hashval" in the array that exceeds the given hash and it can then
+ * be found in the block pointed by the "before" value.
+ */
+ max = be16_to_cpu(node->hdr.count);
+
+ probe = span = max/2;
+ for (btree = &node->btree[probe];
+ span > 4; btree = &node->btree[probe]) {
+ span /= 2;
+ hash = be32_to_cpu(btree->hashval);
+
+ if (hash < hashwant)
+ probe += span;
+ else if (hash > hashwant)
+ probe -= span;
+ else
+ break;
+ }
+
+ while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashwant)) {
+ btree--;
+ probe--;
+ }
+
+ while ((probe < max) && (be32_to_cpu(btree->hashval) < hashwant)) {
+ btree++;
+ probe++;
+ }
+
+ if (probe == max)
+ fsblkno = be32_to_cpu(node->btree[max-1].before);
+ else
+ fsblkno = be32_to_cpu(node->btree[probe].before);
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno, &error);
+ if (error) {
+ xfs_error("Cannot find right rec!");
+ goto out;
+ }
+
+ free(node);
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs,
+ fsblkno, 1);
+ } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+
+ leaf = (xfs_dir2_leaf_t*)node;
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+ xfs_error("Leaf's magic number does not match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
+ low <= high; ) {
+ mid = (low + high) >> 1;
+
+ if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+ break;
+ if (hash < hashwant)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ /* If hash is not the one we want, then the directory does not contain the
+ * entry we're looking for and there is nothing to do anymore.
+ */
+ if (hash != hashwant)
+ goto out;
+
+ while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+ mid--;
+
+ for (lep = &leaf->ents[mid];
+ mid < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->hashval) == hashwant;
+ lep++, mid++) {
+ /* Skip over stale leaf entries. */
+ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+ continue;
+
+ newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
+ if (newdb != curdb) {
+ if (buf)
+ free(buf);
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core, newdb, &error);
+ if (error) {
+ xfs_error("Cannot find data block!");
+ goto out;
+ }
+
+ buf = xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not match!");
+ goto out1;
+ }
+
+ curdb = newdb;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)((char *)buf +
+ xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ }
+
+out1:
+ free(buf);
+
+out:
+ free(node);
+
+ return NULL;
+
+found:
+ ip = xfs_new_inode(parent->fs);
+ ino = be64_to_cpu(dep->inumber);
+ ncore = xfs_dinode_get_core(parent->fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(parent->fs, ip, ino);
+ ip->ino = ino;
+ XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
+ BLOCK_SHIFT(parent->fs);
+ ip->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ ip->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ ip->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", ip->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ ip->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(buf);
+ free(node);
+
+ return ip;
+
+failed:
+ free(ip);
+ free(buf);
+ free(node);
+
+ return NULL;
+}
diff --git a/core/fs/xfs/xfs_dir2.h b/core/fs/xfs/xfs_dir2.h
new file mode 100644
index 00000000..e1b96227
--- /dev/null
+++ b/core/fs/xfs/xfs_dir2.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_DIR2_H_
+#define XFS_DIR2_H_
+
+#include <core.h>
+#include <fs.h>
+
+#include "xfs.h"
+
+char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end);
+void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
+ xfs_filblks_t c);
+uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen);
+block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+ block_t fsblkno, int *error);
+
+struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+
+static inline bool xfs_dir2_isleaf(struct fs_info *fs, xfs_dinode_t *dip)
+{
+ uint64_t last = 0;
+ xfs_bmbt_irec_t irec;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&dip->di_literal_area[0]) +
+ be32_to_cpu(dip->di_nextents) - 1);
+ last = irec.br_startoff + irec.br_blockcount;
+
+ return (last == XFS_INFO(fs)->dirleafblk + (1 << XFS_INFO(fs)->dirblklog));
+}
+
+#endif /* XFS_DIR2_H_ */
diff --git a/core/fs/xfs/xfs_fs.h b/core/fs/xfs/xfs_fs.h
new file mode 100644
index 00000000..587820ec
--- /dev/null
+++ b/core/fs/xfs/xfs_fs.h
@@ -0,0 +1,501 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 1995-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_FS_H_
+#define XFS_FS_H_
+
+/*
+ * SGI's XFS filesystem's major stuff (constants, structures)
+ */
+
+/*
+ * Direct I/O attribute record used with XFS_IOC_DIOINFO
+ * d_miniosz is the min xfer size, xfer size multiple and file seek offset
+ * alignment.
+ */
+struct dioattr {
+ uint32_t d_mem; /* data buffer memory alignment */
+ uint32_t d_miniosz; /* min xfer size */
+ uint32_t d_maxiosz; /* max xfer size */
+};
+
+/*
+ * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+ uint32_t fsx_xflags; /* xflags field value (get/set) */
+ uint32_t fsx_extsize; /* extsize field value (get/set)*/
+ uint32_t fsx_nextents; /* nextents field value (get) */
+ uint32_t fsx_projid; /* project identifier (get/set) */
+ unsigned char fsx_pad[12];
+};
+
+/*
+ * Flags for the bs_xflags/fsx_xflags field
+ * There should be a one-to-one correspondence between these flags and the
+ * XFS_DIFLAG_s.
+ */
+#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
+#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
+#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
+#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
+#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
+#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
+#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
+#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
+#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
+#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
+#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
+#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
+
+/*
+ * Structure for XFS_IOC_GETBMAP.
+ * On input, fill in bmv_offset and bmv_length of the first structure
+ * to indicate the area of interest in the file, and bmv_entries with
+ * the number of array elements given back. The first structure is
+ * updated on return to give the offset and length for the next call.
+ */
+struct getbmap {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output) */
+};
+
+/*
+ * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries
+ * are used exactly as in the getbmap structure. The getbmapx structure
+ * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field
+ * is only used for the first structure. It contains input flags
+ * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled
+ * in by the XFS_IOC_GETBMAPX command for each returned structure after
+ * the first.
+ */
+struct getbmapx {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output). */
+ int32_t bmv_iflags; /* input flags (1st structure) */
+ int32_t bmv_oflags; /* output flags (after 1st structure)*/
+ int32_t bmv_unused1; /* future use */
+ int32_t bmv_unused2; /* future use */
+};
+
+/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */
+#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */
+#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
+#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
+#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */
+#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */
+#define BMV_IF_VALID \
+ (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \
+ BMV_IF_DELALLOC|BMV_IF_NO_HOLES)
+
+/* bmv_oflags values - returned for each non-header segment */
+#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
+#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */
+#define BMV_OF_LAST 0x4 /* segment is the last in the file */
+
+/*
+ * Structure for XFS_IOC_FSSETDM.
+ * For use by backup and restore programs to set the XFS on-disk inode
+ * fields di_dmevmask and di_dmstate. These must be set to exactly and
+ * only values previously obtained via xfs_bulkstat! (Specifically the
+ * xfs_bstat_t fields bs_dmevmask and bs_dmstate.)
+ */
+struct fsdmidata {
+ uint32_t fsd_dmevmask; /* corresponds to di_dmevmask */
+ __u16 fsd_padding;
+ __u16 fsd_dmstate; /* corresponds to di_dmstate */
+};
+
+/*
+ * File segment locking set data type for 64 bit access.
+ * Also used for all the RESV/FREE interfaces.
+ */
+typedef struct xfs_flock64 {
+ __s16 l_type;
+ __s16 l_whence;
+ int64_t l_start;
+ int64_t l_len; /* len == 0 means until end of file */
+ int32_t l_sysid;
+ uint32_t l_pid;
+ int32_t l_pad[4]; /* reserve area */
+} xfs_flock64_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY_V1
+ */
+typedef struct xfs_fsop_geom_v1 {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+} xfs_fsop_geom_v1_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY
+ */
+typedef struct xfs_fsop_geom {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+ uint32_t logsunit; /* log stripe unit, bytes */
+} xfs_fsop_geom_t;
+
+/* Output for XFS_FS_COUNTS */
+typedef struct xfs_fsop_counts {
+ uint64_t freedata; /* free data section blocks */
+ uint64_t freertx; /* free rt extents */
+ uint64_t freeino; /* free inodes */
+ uint64_t allocino; /* total allocated inodes */
+} xfs_fsop_counts_t;
+
+/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */
+typedef struct xfs_fsop_resblks {
+ uint64_t resblks;
+ uint64_t resblks_avail;
+} xfs_fsop_resblks_t;
+
+#define XFS_FSOP_GEOM_VERSION 0
+
+#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */
+#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */
+#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */
+#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */
+#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */
+#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */
+#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */
+#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */
+#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */
+#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
+
+
+/*
+ * Minimum and maximum sizes need for growth checks
+ */
+#define XFS_MIN_AG_BLOCKS 64
+#define XFS_MIN_LOG_BLOCKS 512ULL
+#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+ ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
+
+/* Used for sanity checks on superblock */
+#define XFS_MAX_DBLOCKS(s) ((xfs_drfsbno_t)(s)->sb_agcount * (s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((xfs_drfsbno_t)((s)->sb_agcount - 1) * \
+ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+/*
+ * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT
+ */
+typedef struct xfs_growfs_data {
+ uint64_t newblocks; /* new data subvol size, fsblocks */
+ uint32_t imaxpct; /* new inode space percentage limit */
+} xfs_growfs_data_t;
+
+typedef struct xfs_growfs_log {
+ uint32_t newblocks; /* new log size, fsblocks */
+ uint32_t isint; /* 1 if new log is internal */
+} xfs_growfs_log_t;
+
+typedef struct xfs_growfs_rt {
+ uint64_t newblocks; /* new realtime size, fsblocks */
+ uint32_t extsize; /* new realtime extent size, fsblocks */
+} xfs_growfs_rt_t;
+
+
+/*
+ * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
+ */
+typedef struct xfs_bstime {
+ time_t tv_sec; /* seconds */
+ int32_t tv_nsec; /* and nanoseconds */
+} xfs_bstime_t;
+
+typedef struct xfs_bstat {
+ uint64_t bs_ino; /* inode number */
+ __u16 bs_mode; /* type and mode */
+ __u16 bs_nlink; /* number of links */
+ uint32_t bs_uid; /* user id */
+ uint32_t bs_gid; /* group id */
+ uint32_t bs_rdev; /* device value */
+ int32_t bs_blksize; /* block size */
+ int64_t bs_size; /* file size */
+ xfs_bstime_t bs_atime; /* access time */
+ xfs_bstime_t bs_mtime; /* modify time */
+ xfs_bstime_t bs_ctime; /* inode change time */
+ int64_t bs_blocks; /* number of blocks */
+ uint32_t bs_xflags; /* extended flags */
+ int32_t bs_extsize; /* extent size */
+ int32_t bs_extents; /* number of extents */
+ uint32_t bs_gen; /* generation count */
+ __u16 bs_projid_lo; /* lower part of project id */
+#define bs_projid bs_projid_lo /* (previously just bs_projid) */
+ __u16 bs_forkoff; /* inode fork offset in bytes */
+ __u16 bs_projid_hi; /* higher part of project id */
+ unsigned char bs_pad[10]; /* pad space, unused */
+ uint32_t bs_dmevmask; /* DMIG event mask */
+ __u16 bs_dmstate; /* DMIG state info */
+ __u16 bs_aextents; /* attribute number of extents */
+} xfs_bstat_t;
+
+/*
+ * The user-level BulkStat Request interface structure.
+ */
+typedef struct xfs_fsop_bulkreq {
+ uint64_t __user *lastip; /* last inode # pointer */
+ int32_t icount; /* count of entries in buffer */
+ void __user *ubuffer;/* user buffer for inode desc. */
+ int32_t __user *ocount; /* output count pointer */
+} xfs_fsop_bulkreq_t;
+
+
+/*
+ * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS).
+ */
+typedef struct xfs_inogrp {
+ uint64_t xi_startino; /* starting inode number */
+ int32_t xi_alloccount; /* # bits set in allocmask */
+ uint64_t xi_allocmask; /* mask of allocated inodes */
+} xfs_inogrp_t;
+
+
+/*
+ * Error injection.
+ */
+typedef struct xfs_error_injection {
+ int32_t fd;
+ int32_t errtag;
+} xfs_error_injection_t;
+
+
+/*
+ * The user-level Handle Request interface structure.
+ */
+typedef struct xfs_fsop_handlereq {
+ uint32_t fd; /* fd for FD_TO_HANDLE */
+ void __user *path; /* user pathname */
+ uint32_t oflags; /* open flags */
+ void __user *ihandle;/* user supplied handle */
+ uint32_t ihandlen; /* user supplied length */
+ void __user *ohandle;/* user buffer for handle */
+ uint32_t __user *ohandlen;/* user buffer length */
+} xfs_fsop_handlereq_t;
+
+/*
+ * Compound structures for passing args through Handle Request interfaces
+ * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle
+ * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and
+ * XFS_IOC_ATTRMULTI_BY_HANDLE
+ */
+
+typedef struct xfs_fsop_setdm_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle information */
+ struct fsdmidata __user *data; /* DMAPI data */
+} xfs_fsop_setdm_handlereq_t;
+
+typedef struct xfs_attrlist_cursor {
+ uint32_t opaque[4];
+} xfs_attrlist_cursor_t;
+
+typedef struct xfs_fsop_attrlist_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
+ uint32_t flags; /* which namespace to use */
+ uint32_t buflen; /* length of buffer supplied */
+ void __user *buffer; /* returned names */
+} xfs_fsop_attrlist_handlereq_t;
+
+typedef struct xfs_attr_multiop {
+ uint32_t am_opcode;
+#define ATTR_OP_GET 1 /* return the indicated attr's value */
+#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
+#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
+ int32_t am_error;
+ void __user *am_attrname;
+ void __user *am_attrvalue;
+ uint32_t am_length;
+ uint32_t am_flags;
+} xfs_attr_multiop_t;
+
+typedef struct xfs_fsop_attrmulti_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ uint32_t opcount;/* count of following multiop */
+ struct xfs_attr_multiop __user *ops; /* attr_multi data */
+} xfs_fsop_attrmulti_handlereq_t;
+
+/*
+ * per machine unique filesystem identifier types.
+ */
+typedef struct { uint32_t val[2]; } xfs_fsid_t; /* file system id type */
+
+typedef struct xfs_fid {
+ __u16 fid_len; /* length of remainder */
+ __u16 fid_pad;
+ uint32_t fid_gen; /* generation number */
+ uint64_t fid_ino; /* 64 bits inode number */
+} xfs_fid_t;
+
+typedef struct xfs_handle {
+ union {
+ int64_t align; /* force alignment of ha_fid */
+ xfs_fsid_t _ha_fsid; /* unique file system identifier */
+ } ha_u;
+ xfs_fid_t ha_fid; /* file system specific file ID */
+} xfs_handle_t;
+#define ha_fsid ha_u._ha_fsid
+
+#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \
+ - (char *) &(handle)) \
+ + (handle).ha_fid.fid_len)
+
+/*
+ * Flags for going down operation
+ */
+#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */
+#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
+#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
+
+/*
+ * ioctl commands that are used by Linux filesystems
+ */
+#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS
+#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS
+#define XFS_IOC_GETVERSION FS_IOC_GETVERSION
+
+/*
+ * ioctl commands that replace IRIX fcntl()'s
+ * For 'documentation' purposed more than anything else,
+ * the "cmd #" field reflects the IRIX fcntl number.
+ */
+#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
+#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
+#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
+#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
+#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
+#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
+#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
+#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata)
+#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64)
+#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64)
+#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap)
+#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr)
+/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */
+/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */
+#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap)
+#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)
+
+/*
+ * ioctl commands that replace IRIX syssgi()'s
+ */
+#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1)
+#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq)
+#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq)
+#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext)
+#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data)
+#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log)
+#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt)
+#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts)
+#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks)
+#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks)
+#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection)
+#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection)
+/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */
+/* XFS_IOC_FREEZE -- FIFREEZE 119 */
+/* XFS_IOC_THAW -- FITHAW 120 */
+#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq)
+#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq)
+#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)
+#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)
+#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t)
+/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
+
+
+#ifndef HAVE_BBMACROS
+/*
+ * Block I/O parameterization. A basic block (BB) is the lowest size of
+ * filesystem allocation, and must equal 512. Length units given to bio
+ * routines are in BB's.
+ */
+#define BBSHIFT 9
+#define BBSIZE (1<<BBSHIFT)
+#define BBMASK (BBSIZE-1)
+#define BTOBB(bytes) (((uint64_t)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BTOBBT(bytes) ((uint64_t)(bytes) >> BBSHIFT)
+#define BBTOB(bbs) ((bbs) << BBSHIFT)
+#endif
+
+#endif /* XFS_FS_H_ */
diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c
new file mode 100644
index 00000000..0e013e55
--- /dev/null
+++ b/core/fs/xfs/xfs_readdir.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+#include "xfs_dir2.h"
+
+#include "xfs_readdir.h"
+
+static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
+ uint32_t offset, xfs_ino_t ino, char *name,
+ size_t namelen)
+{
+ xfs_dinode_t *core;
+
+ dirent->d_ino = ino;
+ dirent->d_off = offset;
+ dirent->d_reclen = offsetof(struct dirent, d_name) + namelen + 1;
+
+ core = xfs_dinode_get_core(fs, ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)", ino);
+ return -1;
+ }
+
+ if (be16_to_cpu(core->di_mode) & S_IFDIR)
+ dirent->d_type = DT_DIR;
+ else if (be16_to_cpu(core->di_mode) & S_IFREG)
+ dirent->d_type = DT_REG;
+ else if (be16_to_cpu(core->di_mode) & S_IFLNK)
+ dirent->d_type = DT_LNK;
+
+ memcpy(dirent->d_name, name, namelen + 1);
+
+ return 0;
+}
+
+int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+ xfs_dir2_sf_entry_t *sf_entry;
+ uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
+ uint32_t offset = file->offset;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_ino_t ino;
+ struct fs_info *fs = file->fs;
+ int retval = 0;
+
+ xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
+
+ if (file->offset + 1 > count)
+ return -1;
+
+ file->offset++;
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+ (!sf->hdr.i8count ? 4 : 0));
+
+ if (file->offset - 1) {
+ offset = file->offset;
+ while (--offset) {
+ sf_entry = (xfs_dir2_sf_entry_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen +
+ (sf->hdr.i8count ? 8 : 4));
+ }
+ }
+
+ start_name = &sf_entry->name[0];
+ end_name = start_name + sf_entry->namelen;
+
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen));
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, (char *)name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+
+ return retval;
+}
+
+int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t r;
+ block_t dir_blk;
+ struct fs_info *fs = file->fs;
+ uint8_t *dirblk_buf;
+ uint8_t *p;
+ uint32_t offset;
+ xfs_dir2_data_hdr_t *hdr;
+ xfs_dir2_block_tail_t *btp;
+ xfs_dir2_data_unused_t *dup;
+ xfs_dir2_data_entry_t *dep;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_ino_t ino;
+ int retval = 0;
+
+ bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+ dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+ hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+ if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+ xfs_error("Block directory header's magic number does not match!");
+ xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
+
+ free(dirblk_buf);
+
+ return -1;
+ }
+
+ btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+
+ if (file->offset + 1 > be32_to_cpu(btp->count))
+ return -1;
+
+ file->offset++;
+
+ p = (uint8_t *)(hdr + 1);
+
+ if (file->offset - 1) {
+ offset = file->offset;
+ while (--offset) {
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ dup = (xfs_dir2_data_unused_t *)p;
+ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+ p += be16_to_cpu(dup->length);
+ continue;
+ }
+
+ p += xfs_dir2_data_entsize(dep->namelen);
+ }
+ }
+
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(dirblk_buf);
+ free(name);
+
+ return retval;
+}
+
+int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t irec;
+ struct fs_info *fs = file->fs;
+ xfs_dir2_leaf_t *leaf;
+ block_t leaf_blk, dir_blk;
+ xfs_dir2_leaf_entry_t *lep;
+ uint32_t db;
+ unsigned int offset;
+ xfs_dir2_data_entry_t *dep;
+ xfs_dir2_data_hdr_t *data_hdr;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_intino_t ino;
+ uint8_t *buf = NULL;
+ int retval = 0;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
+ be32_to_cpu(core->di_nextents) - 1);
+ leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
+ BLOCK_SHIFT(file->fs);
+
+ leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(fs, leaf_blk,
+ irec.br_blockcount);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+ xfs_error("Single leaf block header's magic number does not match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ if (file->offset + 1 > be16_to_cpu(leaf->hdr.count))
+ goto out;
+
+ lep = &leaf->ents[file->offset++];
+
+ /* Skip over stale leaf entries */
+ for ( ; be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
+ lep++, file->offset++);
+
+ db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + db);
+
+ dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
+
+ buf = xfs_dir2_get_dirblks(fs, dir_blk, irec.br_blockcount);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic number does not match!");
+ goto out1;
+ }
+
+ offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
+
+ dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+ free(buf);
+ free(leaf);
+
+ return retval;
+
+out1:
+ free(buf);
+
+out:
+ free(leaf);
+
+ return -1;
+}
+
+int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ struct fs_info *fs = file->fs;
+ xfs_bmbt_irec_t irec;
+ uint32_t node_off = 0;
+ block_t fsblkno;
+ xfs_da_intnode_t *node = NULL;
+ struct inode *inode = file->inode;
+ int error;
+ xfs_dir2_data_hdr_t *data_hdr;
+ xfs_dir2_leaf_t *leaf;
+ xfs_dir2_leaf_entry_t *lep;
+ unsigned int offset;
+ xfs_dir2_data_entry_t *dep;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ uint32_t db;
+ uint8_t *buf = NULL;
+ int retval = 0;
+
+ do {
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+ ++node_off);
+ } while (irec.br_startoff < xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET));
+
+ fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
+
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+ xfs_error("Node's magic number does not match!");
+ goto out;
+ }
+
+try_next_btree:
+ if (!node->hdr.count ||
+ XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count))
+ goto out;
+
+ fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before);
+ fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error);
+ if (error) {
+ xfs_error("Cannot find leaf rec!");
+ goto out;
+ }
+
+ leaf = (xfs_dir2_leaf_t*)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+ xfs_error("Leaf's magic number does not match!");
+ goto out1;
+ }
+
+ if (!leaf->hdr.count ||
+ XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) {
+ XFS_PVT(inode)->i_btree_offset++;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ free(leaf);
+ goto try_next_btree;
+ }
+
+ lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset];
+
+ /* Skip over stale leaf entries */
+ for ( ; XFS_PVT(inode)->i_leaf_ent_offset < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
+ lep++, XFS_PVT(inode)->i_leaf_ent_offset++);
+
+ if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) {
+ XFS_PVT(inode)->i_btree_offset++;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ free(leaf);
+ goto try_next_btree;
+ } else {
+ XFS_PVT(inode)->i_leaf_ent_offset++;
+ }
+
+ db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+
+ fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error);
+ if (error) {
+ xfs_error("Cannot find data block!");
+ goto out1;
+ }
+
+ buf = xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not match!");
+ goto out2;
+ }
+
+ offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
+
+ dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber), name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+ free(buf);
+ free(leaf);
+ free(node);
+
+ return retval;
+
+out2:
+ free(buf);
+
+out1:
+ free(leaf);
+
+out:
+ free(node);
+
+ XFS_PVT(inode)->i_btree_offset = 0;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+
+ return -1;
+}
diff --git a/core/fs/xfs/xfs_readdir.h b/core/fs/xfs/xfs_readdir.h
new file mode 100644
index 00000000..2e564ec8
--- /dev/null
+++ b/core/fs/xfs/xfs_readdir.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_READDIR_H_
+#define XFS_READDIR_H_
+
+int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+
+#endif /* XFS_READDIR_H_ */
diff --git a/core/fs/xfs/xfs_sb.h b/core/fs/xfs/xfs_sb.h
new file mode 100644
index 00000000..12024ab3
--- /dev/null
+++ b/core/fs/xfs/xfs_sb.h
@@ -0,0 +1,206 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_SB_H_
+#define XFS_SB_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef unsigned char uuid_t[16];
+
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define XFS_SB_MAGIC "XFSB" /* 'XFSB' */
+#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */
+#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */
+#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */
+#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
+#define XFS_SB_VERSION_NUMBITS 0x000f
+#define XFS_SB_VERSION_ALLFBITS 0xfff0
+#define XFS_SB_VERSION_SASHFBITS 0xf000
+#define XFS_SB_VERSION_REALFBITS 0x0ff0
+#define XFS_SB_VERSION_ATTRBIT 0x0010
+#define XFS_SB_VERSION_NLINKBIT 0x0020
+#define XFS_SB_VERSION_QUOTABIT 0x0040
+#define XFS_SB_VERSION_ALIGNBIT 0x0080
+#define XFS_SB_VERSION_DALIGNBIT 0x0100
+#define XFS_SB_VERSION_SHAREDBIT 0x0200
+#define XFS_SB_VERSION_LOGV2BIT 0x0400
+#define XFS_SB_VERSION_SECTORBIT 0x0800
+#define XFS_SB_VERSION_EXTFLGBIT 0x1000
+#define XFS_SB_VERSION_DIRV2BIT 0x2000
+#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */
+#define XFS_SB_VERSION_MOREBITSBIT 0x8000
+#define XFS_SB_VERSION_OKSASHFBITS \
+ (XFS_SB_VERSION_EXTFLGBIT | \
+ XFS_SB_VERSION_DIRV2BIT | \
+ XFS_SB_VERSION_BORGBIT)
+#define XFS_SB_VERSION_OKREALFBITS \
+ (XFS_SB_VERSION_ATTRBIT | \
+ XFS_SB_VERSION_NLINKBIT | \
+ XFS_SB_VERSION_QUOTABIT | \
+ XFS_SB_VERSION_ALIGNBIT | \
+ XFS_SB_VERSION_DALIGNBIT | \
+ XFS_SB_VERSION_SHAREDBIT | \
+ XFS_SB_VERSION_LOGV2BIT | \
+ XFS_SB_VERSION_SECTORBIT | \
+ XFS_SB_VERSION_MOREBITSBIT)
+#define XFS_SB_VERSION_OKREALBITS \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_OKREALFBITS | \
+ XFS_SB_VERSION_OKSASHFBITS)
+
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2. Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
+#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
+#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
+#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */
+#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */
+
+#define XFS_SB_VERSION2_OKREALFBITS \
+ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
+ XFS_SB_VERSION2_ATTR2BIT | \
+ XFS_SB_VERSION2_PROJID32BIT)
+#define XFS_SB_VERSION2_OKSASHFBITS \
+ (0)
+#define XFS_SB_VERSION2_OKREALBITS \
+ (XFS_SB_VERSION2_OKREALFBITS | \
+ XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * Sequence number values for the fields.
+ */
+typedef enum {
+ XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
+ XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
+ XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
+ XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
+ XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
+ XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
+ XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
+ XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
+ XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
+ XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
+ XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
+ XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+ XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+ XFS_SBS_FIELDCOUNT
+} xfs_sb_field_t;
+
+/*
+ * Mask values, defined based on the xfs_sb_field_t values.
+ * Only define the ones we're using.
+ */
+#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x)
+#define XFS_SB_UUID XFS_SB_MVAL(UUID)
+#define XFS_SB_FNAME XFS_SB_MVAL(FNAME)
+#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO)
+#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO)
+#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO)
+#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM)
+#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO)
+#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO)
+#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS)
+#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
+#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
+#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS)
+#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2)
+#define XFS_SB_BAD_FEATURES2 XFS_SB_MVAL(BAD_FEATURES2)
+#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
+#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
+#define XFS_SB_MOD_BITS \
+ (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
+ XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
+ XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
+ XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
+ XFS_SB_BAD_FEATURES2)
+
+
+/*
+ * Misc. Flags - warning - these will be cleared by xfs_repair unless
+ * a feature bit is set when the flag is used.
+ */
+#define XFS_SBF_NOFLAGS 0x00 /* no flags set */
+#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */
+
+/*
+ * define max. shared version we can interoperate with
+ */
+#define XFS_SB_MAX_SHARED_VN 0
+
+#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
+
+/*
+ * end of superblock version macros
+ */
+
+#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
+#define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr))
+
+#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
+#define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \
+ xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d))
+#define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \
+ XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno))
+
+/*
+ * File system sector to basic block conversions.
+ */
+#define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log)
+
+/*
+ * File system block to basic block conversions.
+ */
+#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSB(mp,bb) \
+ (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log)
+
+/*
+ * File system block to byte conversions.
+ */
+#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSB(mp,b) \
+ ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask)
+
+#endif /* XFS_SB_H_ */
diff --git a/core/fs/xfs/xfs_types.h b/core/fs/xfs/xfs_types.h
new file mode 100644
index 00000000..92808865
--- /dev/null
+++ b/core/fs/xfs/xfs_types.h
@@ -0,0 +1,135 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_TYPES_H_
+#define XFS_TYPES_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef enum { B_FALSE,B_TRUE } boolean_t;
+typedef uint32_t prid_t; /* project ID */
+typedef uint32_t inst_t; /* an instruction */
+
+typedef int64_t xfs_off_t; /* <file offset> type */
+typedef unsigned long long xfs_ino_t; /* <inode> type */
+typedef int64_t xfs_daddr_t; /* <disk address> type */
+typedef char * xfs_caddr_t; /* <core address> type */
+typedef uint32_t xfs_dev_t;
+typedef uint32_t xfs_nlink_t;
+
+/* __psint_t is the same size as a pointer */
+typedef int32_t __psint_t;
+typedef uint32_t __psunsigned_t;
+
+typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
+typedef uint32_t xfs_extlen_t; /* extent length in blocks */
+typedef uint32_t xfs_agnumber_t; /* allocation group number */
+typedef int32_t xfs_extnum_t; /* # of extents in a file */
+typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
+typedef int64_t xfs_fsize_t; /* bytes in a file */
+typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */
+
+typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */
+typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */
+
+typedef int64_t xfs_lsn_t; /* log sequence number */
+typedef int32_t xfs_tid_t; /* transaction identifier */
+
+typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
+typedef uint32_t xfs_dahash_t; /* dir/attr hash value */
+
+/*
+ * These types are 64 bits on disk but are either 32 or 64 bits in memory.
+ * Disk based types:
+ */
+typedef uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
+typedef uint64_t xfs_dfiloff_t; /* block number in a file */
+typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */
+
+/*
+ * Memory based types are conditional.
+ */
+typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */
+typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
+
+typedef uint64_t xfs_fileoff_t; /* block number in a file */
+typedef int64_t xfs_sfiloff_t; /* signed block number in a file */
+typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
+
+/*
+ * Null values for the types.
+ */
+#define NULLDFSBNO ((xfs_dfsbno_t)-1)
+#define NULLDRFSBNO ((xfs_drfsbno_t)-1)
+#define NULLDRTBNO ((xfs_drtbno_t)-1)
+#define NULLDFILOFF ((xfs_dfiloff_t)-1)
+
+#define NULLFSBLOCK ((xfs_fsblock_t)-1)
+#define NULLRFSBLOCK ((xfs_rfsblock_t)-1)
+#define NULLRTBLOCK ((xfs_rtblock_t)-1)
+#define NULLFILEOFF ((xfs_fileoff_t)-1)
+
+#define NULLAGBLOCK ((xfs_agblock_t)-1)
+#define NULLAGNUMBER ((xfs_agnumber_t)-1)
+#define NULLEXTNUM ((xfs_extnum_t)-1)
+
+#define NULLCOMMITLSN ((xfs_lsn_t)-1)
+
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */
+#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */
+#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */
+
+/*
+ * Min numbers of data/attr fork btree root pointers.
+ */
+#define MINDBTPTRS 3
+#define MINABTPTRS 2
+
+/*
+ * MAXNAMELEN is the length (including the terminating null) of
+ * the longest permissible file (component) name.
+ */
+#define MAXNAMELEN 256
+
+typedef enum {
+ XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
+} xfs_lookup_t;
+
+typedef enum {
+ XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+ XFS_BTNUM_MAX
+} xfs_btnum_t;
+
+struct xfs_name {
+ const unsigned char *name;
+ int len;
+};
+
+#endif /* XFS_TYPES_H_ */
diff --git a/core/graphics.c b/core/graphics.c
index bdf48a85..834372ff 100644
--- a/core/graphics.c
+++ b/core/graphics.c
@@ -25,12 +25,13 @@
#include "bios.h"
#include "graphics.h"
-uint8_t UsingVGA = 0;
+__export uint8_t UsingVGA = 0;
uint16_t VGAPos; /* Pointer into VGA memory */
-uint16_t *VGAFilePtr; /* Pointer into VGAFileBuf */
+__export uint16_t *VGAFilePtr; /* Pointer into VGAFileBuf */
+__export uint16_t VGAFontSize = 16; /* Defaults to 16 byte font */
-char VGAFileBuf[VGA_FILE_BUF_SIZE]; /* Unmangled VGA image name */
-char VGAFileMBuf[FILENAME_MAX]; /* Mangled VGA image name */
+__export char VGAFileBuf[VGA_FILE_BUF_SIZE]; /* Unmangled VGA image name */
+__export char VGAFileMBuf[FILENAME_MAX]; /* Mangled VGA image name */
static uint8_t VGARowBuffer[640 + 80]; /* Decompression buffer */
static uint8_t VGAPlaneBuffer[(640/8) * 4]; /* Plane buffers */
@@ -229,7 +230,7 @@ static void outputvga(const void *in, void *out)
/*
* Display a graphical splash screen.
*/
-void vgadisplayfile(FILE *_fd)
+__export void vgadisplayfile(FILE *_fd)
{
char *p;
int size;
@@ -304,7 +305,7 @@ void vgadisplayfile(FILE *_fd)
/*
* Disable VGA graphics.
*/
-void syslinux_force_text_mode(void)
+__export void syslinux_force_text_mode(void)
{
com32sys_t ireg, oreg;
@@ -356,7 +357,7 @@ void vgashowcursor(void)
vgacursorcommon('_');
}
-void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows)
+__export void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows)
{
UsingVGA = vga;
GXPixCols = pix_cols;
diff --git a/core/highmem.inc b/core/highmem.inc
deleted file mode 100644
index ea386ffc..00000000
--- a/core/highmem.inc
+++ /dev/null
@@ -1,158 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
-;;
-;; 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, Inc., 53 Temple Place Ste 330,
-;; Boston MA 02111-1307, USA; either version 2 of the License, or
-;; (at your option) any later version; incorporated herein by reference.
-;;
-;; -----------------------------------------------------------------------
-
-;;
-;; highmem.inc
-;;
-;; Probe for the size of high memory. This can be overridden by a
-;; mem= command on the command line while booting a new kernel.
-;;
-
- section .text16
-
-;
-; This is set up as a subroutine; it will set up the global variable
-; HighMemSize. All registers are preserved.
-;
-highmemsize:
- push es
- pushfd
- pushad
-
- push cs
- pop es
-
-;
-; First, try INT 15:E820 (get BIOS memory map)
-;
-; Note: we may have to scan this multiple times, because some (daft) BIOSes
-; report main memory as multiple contiguous ranges...
-;
-get_e820:
- mov dword [E820Max],-(1 << 20) ; Max amount of high memory
- mov dword [E820Mem],(1 << 20) ; End of detected high memory
-.start_over:
- mov di,E820Buf
- xor ax,ax
- mov cx,10
- rep stosw ; Clear buffer
- xor ebx,ebx ; Start with first record
- jmp short .do_e820 ; Skip "at end" check first time!
-.int_loop: and ebx,ebx ; If we're back at beginning...
- jz .e820_done ; ... we're done
-.do_e820: mov eax,0000E820h
- mov edx,534D4150h ; "SMAP" backwards
- xor ecx,ecx
- mov cl,20 ; ECX <- 20 (size of buffer)
- mov di,E820Buf
- int 15h
- jnc .no_carry
- ; If carry, ebx == 0 means error, ebx != 0 means we're done
- and ebx,ebx
- jnz .e820_done
- jmp no_e820
-.no_carry:
- cmp eax,534D4150h
- jne no_e820
- cmp cx,20
- jb no_e820
-
-;
-; Look for a memory block starting at <= 1 MB and continuing upward
-;
- cmp dword [E820Buf+4], byte 0
- ja .int_loop ; Start >= 4 GB?
- mov eax, [E820Buf]
- cmp dword [E820Buf+16],1
- je .is_ram ; Is it memory?
- ;
- ; Non-memory range. Remember this as a limit; some BIOSes get the length
- ; of primary RAM incorrect!
- ;
-.not_ram:
- cmp eax, (1 << 20)
- jb .int_loop ; Starts in lowmem region
- cmp eax,[E820Max]
- jae .int_loop ; Already above limit
- mov [E820Max],eax ; Set limit
- jmp .int_loop
-
-.is_ram:
- cmp eax,[E820Mem]
- ja .int_loop ; Not contiguous with our starting point
- add eax,[E820Buf+8]
- jc .overflow
- cmp dword [E820Buf+12],0
- je .nooverflow
-.overflow:
- or eax,-1
-.nooverflow:
- cmp eax,[E820Mem]
- jbe .int_loop ; All is below our baseline
- mov [E820Mem],eax
- jmp .start_over ; Start over in case we find an adjacent range
-
-.e820_done:
- mov eax,[E820Mem]
- cmp eax,[E820Max]
- jna .not_limited
- mov eax,[E820Max]
-.not_limited:
- cmp eax,(1 << 20)
- ja got_highmem ; Did we actually find memory?
- ; otherwise fall through
-
-;
-; INT 15:E820 failed. Try INT 15:E801.
-;
-no_e820:
- mov ax,0e801h ; Query high memory (semi-recent)
- int 15h
- jc no_e801
- cmp ax,3c00h
- ja no_e801 ; > 3C00h something's wrong with this call
- jb e801_hole ; If memory hole we can only use low part
-
- mov ax,bx
- shl eax,16 ; 64K chunks
- add eax,(16 << 20) ; Add first 16M
- jmp short got_highmem
-
-;
-; INT 15:E801 failed. Try INT 15:88.
-;
-no_e801:
- mov ah,88h ; Query high memory (oldest)
- int 15h
- cmp ax,14*1024 ; Don't trust memory >15M
- jna e801_hole
- mov ax,14*1024
-e801_hole:
- and eax,0ffffh
- shl eax,10 ; Convert from kilobytes
- add eax,(1 << 20) ; First megabyte
-got_highmem:
-%if HIGHMEM_SLOP != 0
- sub eax,HIGHMEM_SLOP
-%endif
- mov [HighMemSize],eax
- popad
- popfd
- pop es
- ret ; Done!
-
- section .bss16
- alignb 4
-E820Buf resd 5 ; INT 15:E820 data buffer
-E820Mem resd 1 ; Memory detected by E820
-E820Max resd 1 ; Is E820 memory capped?
-; HighMemSize is defined in com32.inc
diff --git a/core/idle.c b/core/idle.c
index 3f57393b..9514df88 100644
--- a/core/idle.c
+++ b/core/idle.c
@@ -25,7 +25,7 @@
#define TICKS_TO_IDLE 4 /* Also in idle.inc */
extern uint32_t _IdleTimer;
-extern uint16_t NoHalt;
+__export uint16_t NoHalt = 0;
int (*idle_hook_func)(void);
@@ -34,7 +34,7 @@ void reset_idle(void)
_IdleTimer = jiffies();
}
-void __idle(void)
+__export void __idle(void)
{
if (jiffies() - _IdleTimer < TICKS_TO_IDLE)
return;
diff --git a/core/idle.inc b/core/idle.inc
index c93d1773..65d6c5c8 100644
--- a/core/idle.inc
+++ b/core/idle.inc
@@ -22,7 +22,7 @@ reset_idle:
sti ; Guard against BIOS/PXE brokenness...
ret
- global do_idle
+ global do_idle:function hidden
do_idle:
push eax
push ds
@@ -72,10 +72,8 @@ do_idle:
section .data16
alignz 4
- global _IdleTimer
+ global _IdleTimer:data hidden
_IdleTimer dd 0
- global NoHalt
-NoHalt dw 0
hlt_err db 'ERROR: idle with IF=0', CR, LF, 0
diff --git a/core/include/bios.h b/core/include/bios.h
index 49a75f5a..9334c41a 100644
--- a/core/include/bios.h
+++ b/core/include/bios.h
@@ -35,6 +35,16 @@
#define BIOS_magic 0x0472 /* BIOS reset magic */
#define BIOS_vidrows 0x0484 /* Number of screen rows */
+static inline uint16_t bios_fbm(void)
+{
+ return *(volatile uint16_t *)BIOS_fbm;
+}
+
+static inline void set_bios_fbm(uint16_t mem)
+{
+ *(volatile uint16_t *)BIOS_fbm = mem;
+}
+
#define serial_buf_size 4096
#define IO_DELAY_PORT 0x80 /* Invalid port (we hope!) */
diff --git a/core/include/fs.h b/core/include/fs.h
index 4d6c18be..554dc97f 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -101,9 +101,9 @@ struct inode {
const char *name; /* Name, valid for generic path search only */
int refcnt;
int mode; /* FILE , DIR or SYMLINK */
- uint32_t size;
- uint32_t blocks; /* How many blocks the file take */
- uint32_t ino; /* Inode number */
+ uint64_t size;
+ uint64_t blocks; /* How many blocks the file take */
+ uint64_t ino; /* Inode number */
uint32_t atime; /* Access time */
uint32_t mtime; /* Modify time */
uint32_t ctime; /* Create time */
@@ -182,7 +182,6 @@ static inline struct file *handle_to_file(uint16_t handle)
return handle ? &files[handle-1] : NULL;
}
-#define PATH_DEFAULT "/boot/syslinux/:/boot/"
extern char *PATH;
/* fs.c */
diff --git a/core/isolinux.asm b/core/isolinux.asm
index 39e5e5c5..673134b0 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -68,6 +68,7 @@ trackbuf resb trackbufsize ; Track buffer goes here
; Some of these are touched before the whole image
; is loaded. DO NOT move this to .bss16/.uibss.
section .earlybss
+ global BIOSName
alignb 4
FirstSecSum resd 1 ; Checksum of bytes 64-2048
ImageDwords resd 1 ; isolinux.bin size, dwords
@@ -1207,24 +1208,15 @@ debug_tracer: pushad
%endif ; DEBUG_TRACERS
section .bss16
- global CmdOptPtr, KbdMap
alignb 4
ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
KernelExtPtr resw 1 ; During search, final null pointer
-CmdOptPtr resw 1 ; Pointer to first option on cmd line
-KbdFlags resb 1 ; Check for keyboard escapes
FuncFlag resb 1 ; Escape sequences received from keyboard
KernelType resb 1 ; Kernel type, from vkernel, if known
-KbdMap resb 256 ; Keyboard map
global KernelName
KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .config
- global PXERetry
-PXERetry dw 0 ; Extra PXE retries
section .data16
- global SerialNotice
-SerialNotice db 1 ; Only print this once
global IPAppends, numIPAppends
%if IS_PXELINUX
extern IPOption
diff --git a/core/kaboom.c b/core/kaboom.c
index 726ca2be..0b025dd0 100644
--- a/core/kaboom.c
+++ b/core/kaboom.c
@@ -18,7 +18,7 @@ __noreturn __bad_SEG(const volatile void *p)
#undef kaboom
-__noreturn _kaboom(void)
+__export __noreturn _kaboom(void)
{
extern void kaboom(void);
call16(kaboom, &zero_regs, NULL);
diff --git a/core/kernel.inc b/core/kernel.inc
index 245cd6db..5e1c7a39 100644
--- a/core/kernel.inc
+++ b/core/kernel.inc
@@ -62,9 +62,6 @@ linux_fdctab resb 12
cmd_line_here equ $ ; F800 Should be out of the way
endstruc
- global cmd_line
-cmd_line equ core_real_mode + cmd_line_here
-
;
; Old kernel command line signature
;
diff --git a/core/layout.inc b/core/layout.inc
index 24843923..be797ede 100644
--- a/core/layout.inc
+++ b/core/layout.inc
@@ -52,7 +52,6 @@ LATEBSS_START equ 0B800h
;
; 32-bit stack layout
;
- global STACK32_LEN
STACK32_LEN equ 64*1024
section .stack nobits write align=4096
@@ -135,7 +134,7 @@ serial_buf_size equ 4096 ; Should be a power of 2
;
extern xfer_buf_seg
section .xfer_buf write nobits align=65536
- global core_xfer_buf
+ global core_xfer_buf:data hidden
core_xfer_buf resb 65536
;
@@ -145,7 +144,7 @@ core_xfer_buf resb 65536
;
extern real_mode_seg
section .real_mode write nobits align=65536
- global core_real_mode
+ global core_real_mode:data hidden
core_real_mode resb 65536
comboot_seg equ real_mode_seg ; COMBOOT image loading zone
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index a2f859d0..a1f96b77 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -39,6 +39,8 @@ ROOT_FS_OPS:
dd ext2_fs_ops
extern ntfs_fs_ops
dd ntfs_fs_ops
+ extern xfs_fs_ops
+ dd xfs_fs_ops
extern btrfs_fs_ops
dd btrfs_fs_ops
dd 0
diff --git a/core/localboot.c b/core/localboot.c
index 03ac866d..0f4b5820 100644
--- a/core/localboot.c
+++ b/core/localboot.c
@@ -34,7 +34,7 @@ extern void local_boot16(void);
* Boot a specified local disk. AX specifies the BIOS disk number; or
* -1 in case we should execute INT 18h ("next device.")
*/
-void local_boot(int16_t ax)
+__export void local_boot(int16_t ax)
{
com32sys_t ireg, oreg;
int i;
diff --git a/core/localboot.inc b/core/localboot.inc
index ce971ae4..b7840427 100644
--- a/core/localboot.inc
+++ b/core/localboot.inc
@@ -1,5 +1,5 @@
section .text16
- global local_boot16
+ global local_boot16:function hidden
local_boot16:
mov cx,0
mov ss,cx
diff --git a/core/mem/free.c b/core/mem/free.c
index b0eb7146..6fb8cfdd 100644
--- a/core/mem/free.c
+++ b/core/mem/free.c
@@ -81,7 +81,7 @@ void bios_free(void *ptr)
__free_block(ah);
}
-void free(void *ptr)
+__export void free(void *ptr)
{
dprintf("free(%p) @ %p\n", ptr, __builtin_return_address(0));
diff --git a/core/mem/malloc.c b/core/mem/malloc.c
index fe8af5ad..a3d6b45d 100644
--- a/core/mem/malloc.c
+++ b/core/mem/malloc.c
@@ -96,12 +96,12 @@ static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
return p;
}
-void *malloc(size_t size)
+__export void *malloc(size_t size)
{
return _malloc(size, HEAP_MAIN, MALLOC_CORE);
}
-void *lmalloc(size_t size)
+__export void *lmalloc(size_t size)
{
void *p;
@@ -217,12 +217,12 @@ void *bios_realloc(void *ptr, size_t size)
}
}
-void *realloc(void *ptr, size_t size)
+__export void *realloc(void *ptr, size_t size)
{
return firmware->mem->realloc(ptr, size);
}
-void *zalloc(size_t size)
+__export void *zalloc(size_t size)
{
void *ptr;
diff --git a/core/plaincon.c b/core/plaincon.c
index dfeb9784..8f8ca7ca 100644
--- a/core/plaincon.c
+++ b/core/plaincon.c
@@ -9,7 +9,7 @@
* Write a single character in AL to the console without
* mangling any registers; handle video pages correctly.
*/
-void writechr(char data)
+__export void writechr(char data)
{
com32sys_t ireg, oreg;
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index d927b2b2..95f76617 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -280,24 +280,15 @@ Kernel_EAX resd 1
Kernel_SI resw 1
section .bss16
- global CmdOptPtr, KbdMap
alignb 4
ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
KernelExtPtr resw 1 ; During search, final null pointer
-CmdOptPtrj resw 1 ; Pointer to first option on cmd line
-KbdFlags resb 1 ; Check for keyboard escapes
FuncFlag resb 1 ; Escape sequences received from keyboard
KernelType resb 1 ; Kernel type, from vkernel, if known
-KbdMap resb 256 ; Keyboard map
global KernelName
KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .config
- global PXERetry
-PXERetry dw 0 ; Extra PXE retries
section .data16
- global SerialNotice
-SerialNotice db 1 ; Only print this once
extern IPOption
global IPAppends, numIPAppends
alignz 2
diff --git a/core/rawcon.c b/core/rawcon.c
index 1a52c954..92f0898a 100644
--- a/core/rawcon.c
+++ b/core/rawcon.c
@@ -10,7 +10,7 @@
#include "bios.h"
#include "graphics.h"
-void writechr(char data)
+__export void writechr(char data)
{
if (UsingVGA & 0x08)
syslinux_force_text_mode();
diff --git a/core/serirq.c b/core/serirq.c
index e0675c9a..e230b98d 100644
--- a/core/serirq.c
+++ b/core/serirq.c
@@ -123,7 +123,7 @@ static inline void install_irq_vectors(uint32_t *dst, int first)
}
}
-void sirq_install(void)
+__export void sirq_install(void)
{
char val, val2;
@@ -164,7 +164,7 @@ void sirq_install(void)
outb(0xA1, 0);
}
-void sirq_cleanup_nowipe(void)
+__export void sirq_cleanup_nowipe(void)
{
uint32_t *dst;
int i;
diff --git a/core/stack.inc b/core/stack.inc
index 788db647..838d6bab 100644
--- a/core/stack.inc
+++ b/core/stack.inc
@@ -38,7 +38,7 @@
section .data16
alignz 4
- global BaseStack
+ global BaseStack:data hidden
BaseStack dd StackHome ; ESP of the "home" stack pointer
dw 0 ; SS of the "home" stack pointer
diff --git a/core/timer.inc b/core/timer.inc
index 9f42fdf2..80647983 100644
--- a/core/timer.inc
+++ b/core/timer.inc
@@ -32,7 +32,7 @@ timer_init:
mov dword [BIOS_timer_hook],timer_irq
ret
- global bios_timer_cleanup
+ global bios_timer_cleanup:function hidden
bios_timer_cleanup:
; Unhook INT 1Ch
mov eax,[BIOS_timer_next]
@@ -43,18 +43,18 @@ bios_timer_cleanup:
; The specified frequency is 14.31818 MHz/12/65536; this turns out
; to be a period of 54.92542 ms, or 0x36.ece8(187c) hexadecimal.
;
- global timer_irq
+ global timer_irq:function hidden
timer_irq:
inc dword [cs:__jiffies]
add word [cs:__ms_timer_adj],0xece8
adc dword [cs:__ms_timer],0x36
jmp 0:0
- global BIOS_timer_next
+ global BIOS_timer_next:data hidden
BIOS_timer_next equ $-4
section .data16
alignz 4
- global __jiffies, __ms_timer
+ global __jiffies:data hidden, __ms_timer
__jiffies dd 0 ; Clock tick timer
__ms_timer dd 0 ; Millisecond timer
__ms_timer_adj dw 0 ; Millisecond timer correction factor
diff --git a/diag/geodsp/Makefile b/diag/geodsp/Makefile
index 1217c9cc..2fd05c96 100644
--- a/diag/geodsp/Makefile
+++ b/diag/geodsp/Makefile
@@ -25,7 +25,7 @@ VPATH = $(SRC)
BTARGET = geodsp1s.bin geodspms.bin \
geodsp1s.img.xz geodspms.img.xz
-NASMOPT = -i $(coredir)/ -i $(SRC)/ -Ox -f bin
+NASMOPT = -i $(coredir)/ -i $(SRC)/ -Ox -f bin -dBINFMT
NASMOPT += -w+orphan-labels
CFLAGS = -g -O
diff --git a/doc/comboot.txt b/doc/comboot.txt
deleted file mode 100644
index 6e9d7ab5..00000000
--- a/doc/comboot.txt
+++ /dev/null
@@ -1,940 +0,0 @@
-
- COMBOOT and COM32 files
-
-
-Syslinux supports simple standalone programs, using a file format
-similar to DOS ".com" files. A 32-bit version, called COM32, is also
-provided. A simple API provides access to a limited set of filesystem
-and console functions.
-
-
- ++++ COMBOOT file format ++++
-
-A COMBOOT file is a raw binary file containing 16-bit code. It should
-be linked to run at offset 0x100, and contain no absolute segment
-references. It is run in 16-bit real mode.
-
-A COMBOOT image can be written to be compatible with MS-DOS. Such a
-file will usually have extension ".com". A COMBOOT file which is not
-compatible with MS-DOS will usually have extension ".cbt".
-
-Before running the program, Syslinux sets up the following fields in
-the Program Segment Prefix (PSP), a structure at offset 0 in the
-program segment:
-
- Offset Size Meaning
- 0 word Contains an INT 20h instruction
- 2 word Contains the paragraph (16-byte "segment" address) at
- the end of memory available to the program.
- 128 byte Length of the command line arguments, including the leading
- space but not including the final CR character.
- 129 127b Command line arguments, starting with a space and ending
- with a CR character (ASCII 13).
-
-The program is allowed to use memory between the PSP paragraph (which
-all the CS, DS, ES and SS registers point to at program start) and the
-paragraph value given at offset 2.
-
-On startup, SP is set up to point to the end of the 64K segment, at
-0xfffe. Under DOS it is possible for SP to contain a smaller
-value if memory is very tight; this is never the case under Syslinux.
-
-The program should make no assumptions about what segment address it
-will be loaded at; instead it should look at the segment registers on
-program startup. Both DOS and Syslinux will guarantee CS == DS == ES
-== SS on program start; the program should not assume anything about
-the values of FS or GS.
-
-To exit, a program can either execute a near RET (which will jump to
-offset 0 which contains an INT 20h instruction, terminating the
-program), or execute INT 20h or INT 21h AH=00h or INT 21h AH=4Ch.
-If compatiblity with Syslinux 1.xx is desired, use INT 20h.
-
-
- ++++ COM32R file format ++++
-
-A COM32R file is a raw binary file containing 32-bit code. It should
-be self-relocating, as it will be loaded by the Syslinux core at any
-4K aligned address. It will be run in flat-memory 32-bit protected
-mode. Under Syslinux, it will be run in CPL 0, however, since it may
-be possible to create a COM32 execution engine that would run under
-something like Linux DOSEMU, it is recommended that the code does not
-assume CPL 0 unless absolutely necessary.
-
-A COM32R program must start with the byte sequence B8 FE 4C CD 21 (mov
-eax,21cd4cfeh) as a magic number.
-
-The COM32R format replaces the earlier COM32 format, which was linked
-to a fixed address (0x101000).
-
-A COM32R file should have extension ".c32".
-
-On startup, CS will be set up as a flat 32-bit code segment, and DS ==
-ES == SS will be set up as the equivalent flat 32-bit data segment.
-FS and GS are reserved for future use and are currently initialized to
-zero. A COM32R image should not assume any particular values of
-segment selectors.
-
-ESP is set up at the end of available memory and also serves as
-notification to the program how much memory is available.
-
-The following arguments are passed to the program on the stack:
-
- Address Size Meaning
- [ESP] dword Return (termination) address
- [ESP+4] dword Number of additional arguments (currently 8)
- [ESP+8] dword Pointer to the command line arguments (null-terminated string)
- [ESP+12] dword Pointer to INT call helper function
- [ESP+16] dword Pointer to low memory bounce buffer
- [ESP+20] dword Size of low memory bounce buffer
- [ESP+24] dword Pointer to FAR call helper function (new in 2.05)
- [ESP+28] dword Pointer to CDECL helper function (new in 3.54)
- [ESP+32] dword Amount of memory controlled by the Syslinux core (new in 3.74)
- [ESP+36] dword Pointer to the filename of the com32 module (new in 3.86)
- [ESP+40] dword Pointer to protected-mode functions (new in 4.00)
-
-The libcom32 startup code loads this into a structure named __com32,
-defined in <com32.h>:
-
-extern struct com32_sys_args {
- uint32_t cs_sysargs;
- char *cs_cmdline;
- void __cdecl(*cs_intcall)(uint8_t, const com32sys_t *, com32sys_t *);
- void *cs_bounce;
- uint32_t cs_bounce_size;
- void __cdecl(*cs_farcall)(uint32_t, const com32sys_t *, com32sys_t *);
- int __cdecl(*cs_cfarcall)(uint32_t, const void *, uint32_t);
- uint32_t cs_memsize;
- const char *cs_name;
- const struct com32_pmapi *cs_pm;
-} __com32;
-
-The intcall helper function can be used to issue BIOS or Syslinux API
-calls, and takes the interrupt number as first argument. The second
-argument is a pointer to the input register definition, an instance of
-the following structure (available in <com32.h>):
-
-typedef union {
- uint32_t l;
- uint16_t w[2];
- uint8_t b[4];
-} reg32_t;
-
-typedef struct {
- uint16_t gs; /* Offset 0 */
- uint16_t fs; /* Offset 2 */
- uint16_t es; /* Offset 4 */
- uint16_t ds; /* Offset 6 */
-
- reg32_t edi; /* Offset 8 */
- reg32_t esi; /* Offset 12 */
- reg32_t ebp; /* Offset 16 */
- reg32_t _unused_esp; /* Offset 20 */
- reg32_t ebx; /* Offset 24 */
- reg32_t edx; /* Offset 28 */
- reg32_t ecx; /* Offset 32 */
- reg32_t eax; /* Offset 36 */
-
- reg32_t eflags; /* Offset 40 */
-} com32sys_t;
-
-The third argument is a pointer to the output register definition, an
-instance of the same structure. The third argument can also be zero
-(NULL).
-
-Since BIOS or Syslinux API calls can generally only manipulate data
-below address 0x100000, a "bounce buffer" in low memory, at least 64K
-in size, is available, to copy data in and out.
-
-The farcall helper function behaves similarly, but takes as its first
-argument the CS:IP (in the form (CS << 16) + IP) of procedure to be
-invoked via a FAR CALL.
-
-The cfarcall helper function takes (CS << 16)+IP, a pointer to a stack
-frame, a size of that stack frame, and returns the return value of EAX
-(which may need to be appropriate truncated by the user.)
-
-Starting in version 4.00, some of these API calls are available as
-protected-mode function calls, using the regparm(3) calling convention
-(the first three argumetns in EAX, EDX, ECX; the rest on the stack.)
-Those functions are defined in struct com32_pmapi, defined in
-<syslinux/pmapi.h>.
-
-
- ++++ SYSLINUX API CALLS +++
-
-Syslinux provides the following API calls. Syslinux 1.xx only
-supported INT 20h - terminate program. [] indicates the first version
-of Syslinux which supported this feature (correctly.)
-
-NOTE: Most of the API functionality is still experimental. Expect to
-find bugs.
-
-
- ++++ DOS-COMPATIBLE API CALLS ++++
-
-INT 20h [1.48] Terminate program
-INT 21h AH=00h [2.00] Terminate program
-INT 21h AH=4Ch [2.00] Terminate program
-
- All of these terminate the program.
-
-
-INT 21h AH=01h [2.01] Get Key with Echo
-
- Reads a key from the console input, with echo to the console
- output. The read character is returned in AL. Extended
- characters received from the keyboard are returned as NUL (00h)
- + the extended character code.
-
-
-INT 21h AH=02h [2.01] Write Character
-
- Writes a character in DL to the console (video and serial)
- output.
-
-
-INT 21h AH=04h [2.01] Write Character to Serial Port
-
- Writes a character in DL to the serial console output
- (if enabled.) If no serial port is configured, this routine
- does nothing.
-
-
-INT 21h AH=08h [2.09] Get Key without Echo
-
- Reads a key fron the console input, without echoing it to the
- console output. The read character is returned in AL.
-
-
-INT 21h AH=09h [2.01] Write DOS String to Console
-
- Writes a DOS $-terminated string in DS:DX to the console.
-
-
-INT 21h AH=0Bh [2.00] Check Keyboard
-
- Returns AL=FFh if there is a keystroke waiting (which can then
- be read with INT 21h, AH=01h or AH=08h), otherwise AL=00h.
-
-
-INT 21h AH=30h [2.00] Check DOS Version
-
- This function returns AX=BX=CX=DX=0, corresponding to a
- hypothetical "DOS 0.0", but the high parts of EAX-EBX-ECX-EDX
- spell "SYSLINUX":
-
- EAX=59530000h EBX=4C530000h ECX=4E490000h EDX=58550000h
-
- This function can thus be used to distinguish running on
- Syslinux from running on DOS.
-
-
- ++++ SYSLINUX-SPECIFIC API CALLS ++++
-
-Syslinux-specific API calls are executed using INT 22h, with a
-function number in AX. INT 22h is used by DOS for internal purposes;
-do not execute INT 22h under DOS.
-
-DOS-compatible function INT 21h, AH=30h can be used to detect if the
-Syslinux API calls are available.
-
-Any register not specifically listed as modified is preserved;
-however, future versions of Syslinux may add additional output
-registers to existing calls.
-
-All calls return CF=0 on success, CF=1 on failure. The noted outputs
-apply if CF=0 only unless otherwise noted. All calls clobber the
-arithmetric flags (CF, PF, AF, ZF, SF and OF) but leave all other
-flags unchanged unless otherwise noted.
-
-
-AX=0001h [2.00] Get Version
-
- Input: AX 0001h
- Output: AX number of INT 22h API functions available
- CH Syslinux major version number
- CL Syslinux minor version number
- DL Syslinux derivative ID (e.g. 32h = PXELINUX)
- ES:SI Syslinux version string
- ES:DI Syslinux copyright string
-
- This API call returns the Syslinux version and API
- information.
-
- Note: before version 3.86, the version string had a leading CR LF
- and the copyright string had a leading space. The strings might
- still contain trailing CR and/or LF.
-
-
-AX=0002h [2.01] Write String
-
- Input: AX 0002h
- ES:BX null-terminated string
- Output: None
-
- Writes a null-terminated string on the console.
-
-
-AX=0003h [2.01] Run command
-
- Input: AX 0003h
- ES:BX null-terminated command string
- Output: Does not return
-
- This API call terminates the program and executes the command
- string as if the user had entered it at the Syslinux command
- line. This API call does not return.
-
-
-AX=0004h [2.01] Run default command
-
- Input: AX 0004h
- Output: Does not return
-
- This API call terminates the program and executes the default
- command string as if the user had pressed Enter alone on the
- Syslinux command line. This API call does not return.
-
-
-AX=0005h [2.00] Force text mode
-
- Input: AX 0005h
- Output: None
-
- If the screen was in graphics mode (due to displaying a splash
- screen using the <Ctrl-X> command in a message file, or
- similar), return to text mode.
-
-
-AX=0006h [2.08] Open file
-
- Input: AX 0006h
- ES:SI null-terminated filename
- Output: SI file handle
- EAX length of file in bytes, or -1
- CX file block size
-
- Open a file for reading. The exact syntax of the filenames
- allowed depends on the particular Syslinux derivative.
-
- The Syslinux file system is block-oriented. The size of a
- block will always be a power of two and no greater than 16K.
-
- Note: Syslinux considers a zero-length file to be nonexistent.
-
- In 3.70 or later, EAX can contain -1 indicating that the file
- length is unknown.
-
- 32-BIT VERSION:
-
- int cs_pm->open_file(const char *filename, struct com32_filedata *data)
-
- filename - null-terminated filename
- data - pointer to a file data buffer
-
- Returns the file handle, or -1 on failure.
- The file data buffer contains block size and file size.
-
-
-AX=0007h [2.08] Read file
-
- Input: AX 0007h
- SI file handle
- ES:BX buffer
- CX number of blocks to read
- Output: SI file handle, or 0 if EOF was reached
- ECX number of bytes read [3.70]
-
- Read blocks from a file. Note that the file handle that is
- returned in SI may not be the same value that was passed in.
-
- If end of file was reached (SI=0), the file was automatically
- closed.
-
- In 3.70 or later, ECX returns the number of bytes read. This
- will always be a multiple of the block size unless EOF is
- reached.
-
- The address of the buffer (ES:BX) should be at least 512-byte
- aligned. Syslinux guarantees at least this alignment for the
- COMBOOT load segment or the COM32 bounce buffer.
-
- Keep in mind that a "file" may be a TFTP connection, and that
- leaving a file open for an extended period of time may result
- in a timeout.
-
- WARNING: Calling this function with an invalid file handle
- will probably crash the system.
-
- 32-BIT VERSION:
-
- size_t cs_pm->read_file(uint16_t *handle, void *buf, size_t blocks)
-
- handle - file handle (input and output, set to zero on end of file)
- buf - buffer to write to
- blocks - number of blocks to read
-
- Returns number of bytes read, or 0 on failure.
-
-
-AX=0008h [2.08] Close file
-
- Input: AX 0008h
- SI file handle
- Output: None
-
- Close a file before reaching the end of file.
-
- WARNING: Calling this function with an invalid file handle
- will probably crash the system.
-
- 32-BIT VERSION:
-
- void cs_pm->close_file(uint16_t handle)
-
- handle - file handle to close
-
-
-AX=0009h [2.00] Call PXE Stack [PXELINUX ONLY]
-
- Input: AX 0009h
- BX PXE function number
- ES:DI PXE parameter structure buffer
- Output: AX PXE return status code
-
- Invoke an arbitrary PXE stack function. On SYSLINUX/ISOLINUX,
- this function returns with an error (CF=1) and no action is
- taken. On PXELINUX, this function always returns with CF=0
- indicating that the PXE stack was successfully invoked; check
- the status code in AX and in the first word of the data buffer
- to determine if the PXE call succeeded or not.
-
- The PXE stack will have the UDP stack OPEN; if you change that
- you cannot call any of the file-related API functions, and
- must restore UDP OPEN before returning to PXELINUX.
-
- PXELINUX reserves UDP port numbers from 49152 to 65535 for its
- own use; port numbers below that range is available.
-
-
-AX=000Ah [2.00] Get Derivative-Specific Information
-
- [SYSLINUX, EXTLINUX]
- Input: AX 000Ah
- CL 9 (to get a valid return in CL for all versions)
- Output: AL 31h (SYSLINUX), 34h (EXTLINUX)
- DL drive number
- CL sector size as a power of 2 (9 = 512 bytes) [3.35]
- CH mode [3.73]
- 1 = CBIOS mode
- 2 = EBIOS mode
- ES:BX pointer to partition table entry (if DL >= 80h)
- FS:SI pointer to initial ES:DI value [3.53]
- GS:DI pointer to partition offset (QWORD) [4.00]
-
- Note: This function was broken in EXTLINUX 3.00-3.02.
-
- On boot, ES:DI is supposed to point to the BIOS $PnP
- structure, although in practice most operating systems
- will search for it in memory. However, preserving
- this while chainloading is probably a good idea.
-
- Note that FS:SI is a pointer to a memory location
- containing the original ES:DI value, not the value
- itself.
-
-
- [PXELINUX]
- Input: AX 000Ah
- Output: AL 32h (PXELINUX)
- DX PXE API version detected (DH=major, DL=minor)
- ECX Local IP number (network byte order) [3.85]
- ES:BX pointer to PXENV+ or !PXE structure
- FS:SI pointer to original stack with invocation record
- GS:DI pointer to network information [4.00]
-
- Note: DX notes the API version detected by PXELINUX,
- which may be more conservative than the actual version
- available. For exact information examine the API
- version entry in the PXENV+ structure, or the API
- version entries in the ROMID structures pointed from
- the !PXE structure.
-
- PXELINUX will use, and provide, the !PXE structure
- over the PXENV+ structure. Examine the structure
- signature to determine which particular structure was
- provided.
-
- The FS:SI pointer points to the top of the original stack
- provided by the PXE stack, with the following values
- pushed at the time PXELINUX is started:
-
- [fs:si+0] GS <- top of stack
- [fs:si+2] FS
- [fs:si+4] ES
- [fs:si+6] DS
- [fs:si+8] EDI
- [fs:si+12] ESI
- [fs:si+16] EBP
- [fs:si+20] -
- [fs:si+24] EBX
- [fs:si+28] EDX
- [fs:si+32] ECX
- [fs:si+36] EAX
- [fs:si+40] EFLAGS
- [fs:si+44] PXE return IP <- t.o.s. when PXELINUX invoked
- [fs:si+46] PXE return CS
-
- GS:DI points to a structure of the following form:
-
- [gs:di+0] 4 - IPv4
- [gs:di+4] My IP
- [gs:di+8] Boot server IP
- [gs:di+12] Gateway IP
- [gs:di+16] Netmask
-
- [ISOLINUX]
- Input: AX 000Ah
- Output: AL 33h (ISOLINUX)
- DL drive number
- CL 11 (sector size as a power of 2) [3.35]
- CH mode [3.73]
- 0 = El Torito
- 1 = Hybrid (hard disk), CBIOS mode
- 2 = Hybrid (hard disk), EBIOS mode
- ES:BX pointer to El Torito spec packet
- FS:SI pointer to initial ES:DI value [3.53]
- GS:DI pointer to partition offset (QWORD) [4.00]
-
- Note: Some very broken El Torito implementations do
- not provide the spec packet information. If so, ES:BX
- may point to all zeroes or to garbage. Call INT 13h,
- AX=4B01h to obtain the spec packet directly from the
- BIOS if necessary.
-
-
-AX=000Bh [2.00] Get Serial Console Configuration
-
- Input: AX 000Bh
- Output: DX serial port I/O base (e.g. 3F8h = COM1...)
- CX baud rate divisor (1 = 115200 bps, 2 = 57600 bps...)
- BX flow control configuration bits (see syslinux.txt)
- -> bit 15 is set if the video console is disabled
-
- If no serial port is configured, DX will be set to 0 and the
- other registers are undefined.
-
-
-AX=000Ch [2.00] Perform final cleanup
- Input: AX 000Ch
- DX derivative-specific flags (0000h = clean up all)
- Output: None
-
- This routine performs any "final cleanup" the boot loader
- would normally perform before loading a kernel, such as
- unloading the PXE stack in the case of PXELINUX. AFTER
- INVOKING THIS CALL, NO OTHER API CALLS MAY BE INVOKED, NOR MAY
- THE PROGRAM TERMINATE AND RETURN TO THE BOOT LOADER. This
- call basically tells the boot loader "get out of the way, I'll
- handle it from here."
-
- For COM32 images, the boot loader will continue to provide
- interrupt and BIOS call thunking services as long its memory
- areas (0x0800-0xffff, 0x100000-0x100fff) are not overwritten.
- MAKE SURE TO DISABLE INTERRUPTS, AND INSTALL NEW GDT AND IDTS
- BEFORE OVERWRITING THESE MEMORY AREAS.
-
- The permissible values for DX is an OR of these values:
-
- SYSLINUX: 0000h Normal cleanup
-
- PXELINUX: 0000h Normal cleanup
- 0003h Keep UNDI and PXE stacks loaded
-
- ISOLINUX: 0000h Normal cleanup
-
- EXTLINUX: 0000h Normal cleanup
-
- All other values are undefined, and may have different
- meanings in future versions of Syslinux.
-
-
-AX=000Dh [2.08] Obsoleted in 3.80
-
-
-AX=000Eh [2.11] Get configuration file name
- Input: AX 0000Eh
- Output: ES:BX null-terminated file name string
-
- Returns the name of the configuration file. Note that it is
- possible that the configuration file doesn't actually exist.
-
-
-AX=000Fh [3.00] Get IPAPPEND strings [PXELINUX]
- Input: AX 000Fh
- Output: CX number of strings (currently 2)
- ES:BX pointer to an array of NEAR pointers in
- the same segment, one for each of the above
- strings
-
- Returns the same strings that the "ipappend" option would have
- added to the command line, one for each bit of the "ipappend"
- flag value, so entry 0 is the "ip=" string and entry 1 is the
- "BOOTIF=" string.
-
-
-AX=0010h [3.00] Resolve hostname [PXELINUX]
- Input: AX 0010h
- ES:BX pointer to null-terminated hostname
- Output: EAX IP address of hostname (zero if not found)
-
- Queries the DNS server(s) for a specific hostname. If the
- hostname does not contain a dot (.), the local domain name
- is automatically appended.
-
- This function only return CF=1 if the function is not
- supported. If the function is supported, but the hostname did
- not resolve, it returns with CF=0, EAX=0.
-
- The IP address is returned in network byte order, i.e. if the
- IP address is 1.2.3.4, EAX will contain 0x04030201. Note that
- all uses of IP addresses in PXE are also in network byte order.
-
-
-AX=0011h [3.05] Obsoleted in 3.80
-
-
-AX=0012h [3.50] Obsoleted in 3.80
-
-
-AX=0013h [3.08] Idle loop call
- Input: AX 0013h
- Output: None
-
- Call this routine while sitting in an idle loop. It performs
- any periodic activities required by the filesystem code. At
- the moment, this is a no-op on all derivatives except
- PXELINUX, where it executes PXE calls to answer ARP queries.
-
- Starting with version 3.10, this API call harmlessly returns
- failure (CF=1) if invoked on a platform which does not need
- idle calls. Additionally, it's safe to call this API call on
- previous Syslinux versions (2.00 or later); it will just
- harmlessly fail. Thus, if this call returns failure (CF=1),
- it means that there is no technical reason to call this
- function again, although doing so is of course safe.
-
-
-AX=0014h [3.10] Local boot [PXELINUX, ISOLINUX]
- Input: AX 0014h
- DX Local boot parameter
- Output: Does not return
-
- This function invokes the equivalent of the "localboot"
- configuration file option. The parameter in DX is the same
- parameter as would be entered after "localboot" in the
- configuration file; this parameter is derivative-specific --
- see syslinux.txt for the definition.
-
-
-AX=0015h [3.10] Get feature flags
- Input: AX 0015h
- Output: ES:BX pointer to flags in memory
- CX number of flag bytes
-
- This function reports whether or not this Syslinux version and
- derivative supports specific features. Keep in mind that
- future versions might have more bits; remember to treat any
- bits beyond the end of the array (as defined by the value in
- CX) as zero.
-
- Currently the following feature flag is defined:
-
- Byte Bit Definition
- ----------------------------------------------------
- 0 0 Local boot (AX=0014h) supported
- 1 Idle loop call (AX=0013h) is a no-op
-
- All other flags are reserved.
-
-
-AX=0016h [3.10] Run kernel image
- Input: AX 0016h
- DS:SI Filename of kernel image (zero-terminated string)
- ES:BX Command line (zero-terminated string)
- ECX IPAPPEND flags [PXELINUX]
- EDX Type of file (since 3.50)
- Output: Does not return if successful; returns with CF=1 if
- the kernel image is not found.
-
- This function is similiar to AX=0003h Run command, except that
- the filename and command line are treated as if specified in a
- KERNEL and APPEND statement of a LABEL statement, which means:
-
- - The filename has to be exact; no variants are tried;
- - No global APPEND statement is applied;
- - ALLOWOPTIONS and IMPLICIT statements in the configuration
- file do not apply. It is therefore important that the
- COMBOOT module doesn't allow the end user to violate the
- intent of the administrator.
-
- Additionally, this function returns with a failure if the file
- doesn't exist, instead of returning to the command line. (It
- may still return to the command line if the image is somehow
- corrupt, however.)
-
- The file types are defined as follows:
-
- Equivalent
- EDX Config Extensions Type of file
- 0 KERNEL Determined by filename extension
- 1 LINUX none Linux kernel image
- 2 BOOT .bs .bin Bootstrap program
- 3 BSS .bss Boot sector with patch [SYSLINUX]
- 4 PXE .0 PXE Network Bootstrap Prog [PXELINUX]
- 5 FDIMAGE .img Floppy disk image [ISOLINUX]
- 6 COMBOOT .com .cbt 16-bit COMBOOT program
- 7 COM32 .c32 COM32 program
- 8 CONFIG Configuration file
-
-
-AX=0017h [3.30] Report video mode change
- Input: AX 0017h
- BX Video mode flags
- Bit 0: graphics mode
- Bit 1: non-default mode
- Bit 2: VESA mode
- Bit 3: text functions not supported
- CX For graphics modes, pixel columns
- DX For graphics modes, pixel rows
- Output: None
-
- This function is used to report video mode changes to
- Syslinux. It does NOT actually change the video mode, but
- rather, allows Syslinux to take appropriate action in response
- to a video mode change. Modes that cannot be exited either
- with the conventional BIOS mode set command (INT 10h, AH=00h)
- or the VESA VBE mode set command (INT 10h, AX=4F02h) should
- not be used.
-
- This function returns with a failure if BX contains any bits
- which are undefined in the current version of Syslinux.
-
- The following bits in BX are currently defined:
-
- Bit 0: graphics mode
-
- Indicates that the mode is a graphics mode, as opposed
- to a text mode.
-
- Bit 1: non-standard mode
-
- A non-standard mode is any mode except text mode and
- graphics mode 0012h (VGA 640x480, 16 color.)
-
- Bit 2: VESA mode
-
- This mode is a VESA mode, and has to be exited with
- the VESA VBE API (INT 10h, AX=4F02h) as opposed to the
- conventional BIOS API (INT 10h, AH=00h).
-
- Bit 3: Text functions not supported
-
- This indicates that the BIOS text output functions
- (INT 10h, AH=02h, 03h, 06h, 09h, 0Eh, 11h) don't work.
- If this bit is set, Syslinux will reset the mode
- before printing any characters on the screen.
-
- This is common for VESA modes.
-
-
-AX=0018h [3.30] Query custom font
- Input: AX 0018h
- Output: AL Height of custom font in scan lines, or zero
- ES:BX Pointer to custom font in memory
-
- This call queries if a custom display font has been loaded via
- the "font" configuration file command. If no custom font has
- been loaded, AL contains zero.
-
-
-AX=0019h [3.50] Read disk [SYSLINUX, ISOLINUX, EXTLINUX]
- Input: AX 0019h
- EDX Sector number (LSW)
- ESI Sector number (MSW) [4.00]
- EDI Reserved - MUST BE ZERO
- CX Sector count
- ES:BX Buffer address
- Output: None
-
- Read disk blocks from the active filesystem (partition); for
- disks, sector number zero is the boot sector. For ISOLINUX,
- this call reads the CD-ROM.
-
- For compatiblity with all systems, the buffer should
- *neither* cross 64K boundaries, *nor* wrap around the segment.
-
- This routine reports "boot failed" (and does not return) on
- disk error.
-
- Note: for ISOLINUX in hybrid mode, this call uses simulated
- 2048-byte CD-ROM sector numbers.
-
-
-AX=001Ah [3.50] Obsoleted in 3.80
-
-
-AX=001Bh [3.50] Obsoleted in 3.80
-
-
-AX=001Ch [3.60] Get pointer to auxilliary data vector
- Input: AX 001Ch
- Output: ES:BX Auxilliary data vector
- CX Size of the ADV (currently 500 bytes)
-
- The auxillary data vector is a tagged data structure used
- to carry a small amount of information (up to 500 bytes) from
- one boot to another.
-
-
-AX=001Dh [3.60] Write auxilliary data vector
- Input: AX 001Dh
- Output: None
-
- Write the auxilliary data vector back to disk. Returns
- failure for non-disk-based derivatives unless the "auxdata"
- configuration command is used to specify a disk location
- (not yet implemented.)
-
- In a future version, PXELINUX may end up attempting to save
- the ADV on the server via TFTP write.
-
-
-AX=001Eh [3.74] Keyboard remapping table
- Input: AX 001Eh
- DX 0000h - all other values reserved
- Output: AX format version (1)
- CX length in bytes (256)
- ES:BX pointer to keyboard table
-
- This call queries the keyboard remapping table. For the current
- version, the format code is always 1 and the length is always
- 256. This version can be updated simply by overwriting the version
- in memory; this may not be true in the future.
-
-
-AX=001Fh [3.74] Get current working directory
- Input: AX 0001Fh
- Output: ES:BX null-terminated directory name string
-
- Returns the current working directory.
-
-
-AX=0020h [3.74] Obsoleted in 4.00
-AX=0021h [3.74] Obsoleted in 4.00
-AX=0022h [3.74] Obsoleted in 4.00
-
- These three functions provided opendir/readdir/closedir
- functionality in the late 3.xx series. They have been
- replaced by the protected-mode interface.
-
-
-AX=0023h [3.80] Get shuffler parameters
- Input: AX 0023h
- Output: CX size of shuffler "safe area" in bytes
- Other registers reserved for future use
-
- This call gives the size of the required shuffler "safe area",
- in bytes; for call 0024h. In the future, it may provide
- additional parameters.
-
-
-AX=0024h [3.80] Cleanup, shuffle and boot, raw version
- Input: AX 0024h
- DX derivative-specific flags (see function 000Ch)
- EDI shuffle descriptor list safe area
- ESI shuffle descriptor list source
- ECX byte count of shuffle descriptor list
- Output: Does not return
-
- This routine performs final cleanup, then performs a sequence
- of copies, and jumps to a specified real mode entry point.
- This is a more general version of function 000Dh, which can
- also be used to load other types of programs.
-
- Unlike previous obsolete versions of this function, there are
- no restrictions that copies must not touch memory below
- address 7C00h. Either the shuffle descriptor list or the safe
- area (or both) may be located in high memory.
-
- ESI points to a list of descriptors each of the form:
-
- Offset Size Meaning
- 0 dword destination address
- 4 dword source address (-1 = zero)
- 8 dword length in bytes (0 = end of list)
-
- The copies are overlap-safe, like memmove().
-
- Before actually executing the move list, the list is moved to
- the address specified in EDI. The caller is responsibe to
- ensure that the moved descriptor list plus a "safe area"
- immediately afterwards (the size of which is specified by
- function 0023h) is not disturbed by the copy sequence. It is,
- however, safe to overwrite descriptors already consumed.
-
- If the source address is -1 (FFFFFFFFh) then the block
- specified by the destination address and the length is set to
- all zero.
-
- The list is terminated by an entry with length 0. For that
- entry, the destination is used as an entry point, and the
- source represents the type of entry point:
-
- 0 16-bit protected mode (dst is CS.base)
- 1 Flat 32-bit protected mode (dst is EIP)
-
- This routine does not set up any GPR register state
- whatsoever, including stack. It is the responsibility of the
- caller to make sure the entry point provided sets up any
- registers needed.
-
- For mode 0 (16-bit real mode), EAX will contain CR0 with bit 0
- masked out, suitable for loading into CR0 to immediately enter
- real mode. Note: if real-mode entry is planned,
- (CS.base & 0xfff0000f) should == 0 for compatibility with KVM,
- and possibly other virtualization solutions.
-
- In both mode 0 and mode 1, the data segments will be loaded
- with read/write data segments, matching the respective code
- segment. For mode 0, B=0 and the limits will be 64K, for mode
- 1, B=1 and the limits will be 4 GB.
-
-
- ++++ 32-BIT ONLY API CALLS ++++
-
-void *cs_pm->lmalloc(size_t bytes)
-
- Allocate a buffer in low memory (below 1 MB).
-
-
-void cs_pm->lfree(void *ptr)
-
- Free a buffer allocated with cs_pm->lmalloc().
-
-
-DIR *cs_pm->opendir(const char *pathname)
-
- Open a directory.
-
-
-struct dirent *cs_pm->readdir(DIR *dir)
-
- Read an entry from a directory. The entry is returned in a
- static buffer.
-
-
-int cs_pm->closedir(DIR *dir)
-
- Close a directory.
diff --git a/doc/extlinux.txt b/doc/extlinux.txt
index 9b267018..d8cbb5df 100644
--- a/doc/extlinux.txt
+++ b/doc/extlinux.txt
@@ -49,8 +49,8 @@ slight modifications.
5. EXTLINUX now has "boot-once" support. The boot-once information is
stored in an on-disk datastructure, part of extlinux.sys, called
the "Auxillary Data Vector". The Auxilliary Data Vector is also
- available to COMBOOT/COM32 modules that want to store small amounts
- of information.
+ available to COM32 modules that want to store small amounts of
+ information.
To set the boot-once information, do:
diff --git a/doc/mboot.txt b/doc/mboot.txt
index ef00ca5c..4f8c7b10 100644
--- a/doc/mboot.txt
+++ b/doc/mboot.txt
@@ -2,7 +2,7 @@
mboot.c32
---------
-mboot.c32 is a 32-bit comboot module that allows Syslinux and its
+mboot.c32 is a 32-bit ELF module that allows Syslinux and its
variants to load and boot kernels that use the Multiboot standard
(e.g. the Xen virtual machine monitor, and the Fiasco and GNU Mach
microkernels).
diff --git a/doc/syslinux.txt b/doc/syslinux.txt
index e9923a63..caf3a06c 100644
--- a/doc/syslinux.txt
+++ b/doc/syslinux.txt
@@ -214,7 +214,7 @@ LABEL label
append myoptions
Note: The "kernel" doesn't have to be a Linux kernel; it can
- be a boot sector or a COMBOOT file (see below.)
+ be a boot sector (see below.)
Since version 3.32 label names are no longer mangled into DOS
format (for SYSLINUX.)
@@ -226,7 +226,6 @@ LABEL label
BSS image - BSS image (.bss)
PXE image - PXE Network Bootstrap Program (.0)
FDIMAGE image - Floppy disk image (.img)
- COMBOOT image - COMBOOT program (.com, .cbt)
COM32 image - COM32 program (.c32)
CONFIG image - New configuration file
Using one of these keywords instead of KERNEL forces the
@@ -455,7 +454,9 @@ PATH path
when attempting to load modules. This directive is useful for
specifying the directories containing the lib*.c32 library
files as other modules may be dependent on these files, but
- may not reside in the same directory.
+ may not reside in the same directory. The list of directories
+ is searched in order. Please see the section below on PATH
+ RULES.
Blank lines are ignored.
@@ -564,17 +565,15 @@ The command line prompt supports the following keystrokes:
<Ctrl-N> display network information (PXELINUX only)
- ++++ COMBOOT IMAGES AND OTHER OPERATING SYSTEMS ++++
+ ++++ OTHER OPERATING SYSTEMS ++++
This version of Syslinux supports chain loading of other operating
-systems (such as MS-DOS and its derivatives, including Windows 95/98),
-as well as COMBOOT-style standalone executables (a subset of DOS .COM
-files; see separate section below.)
+systems (such as MS-DOS and its derivatives, including Windows 95/98).
Chain loading requires the boot sector of the foreign operating system
to be stored in a file in the root directory of the filesystem.
-Because neither Linux kernels, boot sector images, nor COMBOOT files
-have reliable magic numbers, Syslinux will look at the file extension.
+Because neither Linux kernels, nor boot sector images have reliable
+magic numbers, Syslinux will look at the file extension.
The following extensions are recognized (case insensitive):
none or other Linux kernel image
@@ -582,9 +581,7 @@ The following extensions are recognized (case insensitive):
.bin "CD boot sector" [ISOLINUX only]
.bs Boot sector [SYSLINUX only]
.bss Boot sector, DOS superblock will be patched in [SYSLINUX only]
- .c32 COM32 image (32-bit COMBOOT)
- .cbt COMBOOT image (not runnable from DOS)
- .com COMBOOT image (runnable from DOS)
+ .c32 COM32 image (32-bit ELF)
.img Disk image [ISOLINUX only]
For filenames given on the command line, Syslinux will search for the
@@ -593,7 +590,7 @@ filename is not found. Filenames in KERNEL statements must be fully
qualified.
If this is specified with one of the keywords LINUX, BOOT, BSS,
-FDIMAGE, COMBOOT, COM32, or CONFIG instead of KERNEL, the filetype is
+FDIMAGE, COM32, or CONFIG instead of KERNEL, the filetype is
considered to be the one specified regardless of the filename.
@@ -673,17 +670,6 @@ syslinux.exe instead.
copy initrd.gz a:
- ++++ COMBOOT EXECUTABLES ++++
-
-Syslinux supports simple standalone programs, using a file format
-similar to DOS ".com" files. A 32-bit version, called COM32, is also
-provided. A simple API provides access to a limited set of filesystem
-and console functions.
-
-See the file comboot.txt for more information on COMBOOT and COM32
-programs.
-
-
++++ NOVICE PROTECTION ++++
Syslinux will attempt to detect booting on a machine with too little
@@ -775,6 +761,32 @@ In recent versions of Linux, this ID is available as
/proc/sys/kernel/bootloader_type.
+ ++++ PATH RULES ++++
+
+The current working directory is *always* searched first, before PATH,
+when attempting to open a filename. The current working directory is
+not affected when specifying a file with an absolute path. For
+example, given the following file system layout,
+
+ /boot/
+ /bin/
+ ls.c32
+ libls.c32
+ /foo/
+ libls.c32
+
+assuming that the current working directory is /boot/foo, and assuming
+that libls.c32 is a dependency of ls.c32, executing /boot/bin/ls.c32
+will cause /boot/foo/libls.c32 to be loaded, not /boot/bin/libls.c32,
+even if /boot/bin is specified in the PATH directive of a config file.
+
+The reason that things work this way is that typically a user will
+install all library files in the Syslinux installation directory, as
+specified with the --directory installer option. This method allows
+the user to omit the PATH directive from their config file and still
+have things work correctly.
+
+
++++ BUG REPORTS ++++
I would appreciate hearing of any problems you have with Syslinux. I
diff --git a/efi/main.c b/efi/main.c
index 39782cb2..754cbc53 100644
--- a/efi/main.c
+++ b/efi/main.c
@@ -19,14 +19,11 @@ char CurrentDirName[CURRENTDIR_MAX];
struct com32_sys_args __com32;
uint32_t _IdleTimer = 0;
-uint16_t NoHalt = 0;
char __lowmem_heap[32];
uint32_t BIOS_timer_next;
uint32_t timer_irq;
uint8_t KbdMap[256];
-uint16_t VGAFontSize = 16;
char aux_seg[256];
-uint8_t UserFont = 0;
uint16_t BIOSName;
#undef kaboom
diff --git a/extlinux/main.c b/extlinux/main.c
index d1909745..e925a1d8 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -14,7 +14,8 @@
/*
* extlinux.c
*
- * Install the syslinux boot block on an fat, ntfs, ext2/3/4 and btrfs filesystem
+ * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs and xfs
+ * filesystem.
*/
#define _GNU_SOURCE /* Enable everything */
@@ -46,6 +47,10 @@
#include "btrfs.h"
#include "fat.h"
#include "ntfs.h"
+#include "xfs.h"
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "misc.h"
#include "version.h"
#include "syslxint.h"
#include "syslxcom.h" /* common functions shared with extlinux and syslinux */
@@ -64,6 +69,13 @@
#define EXT2_SUPER_OFFSET 1024
#endif
+/* Since we have unused 2048 bytes in the primary AG of an XFS partition,
+ * we will use the first 0~512 bytes starting from 2048 for the Syslinux
+ * boot sector.
+ */
+#define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
+#define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
+
/* the btrfs partition first 64K blank area is used to store boot sector and
boot image, the boot sector is from 0~512, the boot image starts after */
#define BTRFS_BOOTSECT_AREA 65536
@@ -295,7 +307,8 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
nsect += 2; /* Two sectors for the ADV */
sectp = alloca(sizeof(sector_t) * nsect);
- if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) {
+ if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS ||
+ fs_type == XFS) {
if (sectmap(fd, sectp, nsect)) {
perror("bmap");
exit(1);
@@ -328,6 +341,7 @@ int install_bootblock(int fd, const char *device)
struct btrfs_super_block sb2;
struct fat_boot_sector sb3;
struct ntfs_boot_sector sb4;
+ xfs_sb_t sb5;
bool ok = false;
if (fs_type == EXT2) {
@@ -335,6 +349,7 @@ int install_bootblock(int fd, const char *device)
perror("reading superblock");
return 1;
}
+
if (sb.s_magic == EXT2_SUPER_MAGIC)
ok = true;
} else if (fs_type == BTRFS) {
@@ -350,6 +365,7 @@ int install_bootblock(int fd, const char *device)
perror("reading fat superblock");
return 1;
}
+
if (fat_check_sb_fields(&sb3))
ok = true;
} else if (fs_type == NTFS) {
@@ -360,12 +376,34 @@ int install_bootblock(int fd, const char *device)
if (ntfs_check_sb_fields(&sb4))
ok = true;
+ } else if (fs_type == XFS) {
+ if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) {
+ perror("reading xfs superblock");
+ return 1;
+ }
+
+ if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) {
+ if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) {
+ fprintf(stderr,
+ "You need to have 4 KiB filesystem block size for "
+ " being able to install Syslinux in your XFS "
+ "partition (because there is no enough space in MBR to "
+ "determine where Syslinux bootsector can be installed "
+ "regardless the filesystem block size)\n");
+ return 1;
+ }
+
+ ok = true;
+ }
}
+
if (!ok) {
- fprintf(stderr, "no fat, ntfs, ext2/3/4 or btrfs superblock found on %s\n",
- device);
+ fprintf(stderr,
+ "no fat, ntfs, ext2/3/4, btrfs or xfs superblock found on %s\n",
+ device);
return 1;
}
+
if (fs_type == VFAT) {
struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
@@ -385,6 +423,12 @@ int install_bootblock(int fd, const char *device)
perror("writing ntfs bootblock");
return 1;
}
+ } else if (fs_type == XFS) {
+ if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len,
+ XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) {
+ perror("writing xfs bootblock");
+ return 1;
+ }
} else {
if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
!= syslinux_bootsect_len) {
@@ -396,11 +440,61 @@ int install_bootblock(int fd, const char *device)
return 0;
}
+static int rewrite_boot_image(int devfd, const char *filename)
+{
+ int fd;
+ int ret;
+ int modbytes;
+ char path[PATH_MAX];
+ char slash;
+
+ /* Let's create LDLINUX.SYS file again (if it already exists, of course) */
+ fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
+ S_IRUSR | S_IRGRP | S_IROTH);
+ if (fd < 0) {
+ perror(filename);
+ return -1;
+ }
+
+ /* Write boot image data into LDLINUX.SYS file */
+ ret = xpwrite(fd, boot_image, boot_image_len, 0);
+ if (ret != boot_image_len) {
+ perror("writing bootblock");
+ goto error;
+ }
+
+ /* Write ADV */
+ ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len);
+ if (ret != 2 * ADV_SIZE) {
+ fprintf(stderr, "%s: write failure on %s\n", program, filename);
+ goto error;
+ }
+
+ sscanf(filename, "%s%cldlinux.sys", path, &slash);
+
+ /* Map the file, and patch the initial sector accordingly */
+ modbytes = patch_file_and_bootblock(fd, path, devfd);
+
+ /* Write the patch area again - this relies on the file being overwritten
+ * in place! */
+ ret = xpwrite(fd, boot_image, modbytes, 0);
+ if (ret != modbytes) {
+ fprintf(stderr, "%s: write failure on %s\n", program, filename);
+ goto error;
+ }
+
+ return fd;
+
+error:
+ close(fd);
+
+ return -1;
+}
+
int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
{
char *file, *oldfile, *c32file;
int fd = -1, dirfd = -1;
- int modbytes;
int r1, r2, r3;
r1 = asprintf(&file, "%s%sldlinux.sys",
@@ -431,30 +525,9 @@ int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
}
close(fd);
- fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
- S_IRUSR | S_IRGRP | S_IROTH);
- if (fd < 0) {
- perror(file);
+ fd = rewrite_boot_image(devfd, file);
+ if (fd < 0)
goto bail;
- }
-
- /* Write it the first time */
- if (xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ||
- xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
- boot_image_len) != 2 * ADV_SIZE) {
- fprintf(stderr, "%s: write failure on %s\n", program, file);
- goto bail;
- }
-
- /* Map the file, and patch the initial sector accordingly */
- modbytes = patch_file_and_bootblock(fd, path, devfd);
-
- /* Write the patch area again - this relies on the file being
- overwritten in place! */
- if (xpwrite(fd, boot_image, modbytes, 0) != modbytes) {
- fprintf(stderr, "%s: write failure on %s\n", program, file);
- goto bail;
- }
/* Attempt to set immutable flag and remove all write access */
/* Only set immutable flag if file is owned by root */
@@ -565,6 +638,70 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst)
}
/*
+ * Due to historical reasons (SGI IRIX's design of disk layouts), the first
+ * sector in the primary AG on XFS filesystems contains the superblock, which is
+ * a problem with bootloaders that rely on BIOSes (that load VBRs which are
+ * (located in the first sector of the partition).
+ *
+ * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's
+ * superblock.
+ */
+static int xfs_install_file(const char *path, int devfd, struct stat *rst)
+{
+ static char file[PATH_MAX];
+ int dirfd = -1;
+ int fd = -1;
+
+ snprintf(file, PATH_MAX, "%s%sldlinux.sys",
+ path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
+
+ dirfd = open(path, O_RDONLY | O_DIRECTORY);
+ if (dirfd < 0) {
+ perror(path);
+ goto bail;
+ }
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ if (errno != ENOENT) {
+ perror(file);
+ goto bail;
+ }
+ } else {
+ clear_attributes(fd);
+ }
+
+ close(fd);
+
+ fd = rewrite_boot_image(devfd, file);
+ if (fd < 0)
+ goto bail;
+
+ /* Attempt to set immutable flag and remove all write access */
+ /* Only set immutable flag if file is owned by root */
+ set_attributes(fd);
+
+ if (fstat(fd, rst)) {
+ perror(file);
+ goto bail;
+ }
+
+ close(dirfd);
+ close(fd);
+
+ return 0;
+
+bail:
+ if (dirfd >= 0)
+ close(dirfd);
+
+ if (fd >= 0)
+ close(fd);
+
+ return 1;
+}
+
+/*
* * test if path is a subvolume:
* * this function return
* * 0-> path exists but it is not a subvolume
@@ -798,11 +935,14 @@ static char * get_default_subvol(char * rootdir, char * subvol)
static int install_file(const char *path, int devfd, struct stat *rst)
{
- if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
- return ext2_fat_install_file(path, devfd, rst);
- else if (fs_type == BTRFS)
- return btrfs_install_file(path, devfd, rst);
- return 1;
+ if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
+ return ext2_fat_install_file(path, devfd, rst);
+ else if (fs_type == BTRFS)
+ return btrfs_install_file(path, devfd, rst);
+ else if (fs_type == XFS)
+ return xfs_install_file(path, devfd, rst);
+
+ return 1;
}
#ifdef __KLIBC__
@@ -897,14 +1037,22 @@ static const char *find_device(const char *mtab_file, dev_t dev)
}
break;
+ case XFS:
+ if (!strcmp(mnt->mnt_type, "xfs") && !stat(mnt->mnt_fsname, &dst) &&
+ dst.st_rdev == dev) {
+ done = true;
+ break;
+ }
case NONE:
break;
}
+
if (done) {
devname = strdup(mnt->mnt_fsname);
break;
}
}
+
endmntent(mtab);
return devname;
@@ -1150,6 +1298,7 @@ static int open_device(const char *path, struct stat *st, const char **_devname)
fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
return -1;
}
+
if (sfs.f_type == EXT2_SUPER_MAGIC)
fs_type = EXT2;
else if (sfs.f_type == BTRFS_SUPER_MAGIC)
@@ -1158,10 +1307,13 @@ static int open_device(const char *path, struct stat *st, const char **_devname)
fs_type = VFAT;
else if (sfs.f_type == NTFS_SB_MAGIC ||
sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
- fs_type = NTFS;
+ fs_type = NTFS;
+ else if (sfs.f_type == XFS_SUPER_MAGIC)
+ fs_type = XFS;
if (!fs_type) {
- fprintf(stderr, "%s: not a fat, ntfs, ext2/3/4 or btrfs filesystem: %s\n",
+ fprintf(stderr,
+ "%s: not a fat, ntfs, ext2/3/4, btrfs or xfs filesystem: %s\n",
program, path);
return -1;
}
@@ -1195,6 +1347,16 @@ static int btrfs_read_adv(int devfd)
return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
}
+static inline int xfs_read_adv(int devfd)
+{
+ const size_t adv_size = 2 * ADV_SIZE;
+
+ if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
+ return -1;
+
+ return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
+}
+
static int ext_read_adv(const char *path, int devfd, const char **namep)
{
int err;
@@ -1203,6 +1365,9 @@ static int ext_read_adv(const char *path, int devfd, const char **namep)
if (fs_type == BTRFS) {
/* btrfs "ldlinux.sys" is in 64k blank area */
return btrfs_read_adv(devfd);
+ } else if (fs_type == XFS) {
+ /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
+ return xfs_read_adv(devfd);
} else {
err = read_adv(path, name = "ldlinux.sys");
if (err == 2) /* ldlinux.sys does not exist */
diff --git a/extlinux/misc.h b/extlinux/misc.h
new file mode 100644
index 00000000..7f2f1b33
--- /dev/null
+++ b/extlinux/misc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MISC_H_
+#define MISC_H_
+
+/* Return a 64-bit litte-endian value from a given 64-bit big-endian one */
+static inline uint64_t be64_to_cpu(uint64_t val)
+{
+ return (uint64_t)((((uint64_t)val & (uint64_t)0x00000000000000ffULL) << 56) |
+ (((uint64_t)val & (uint64_t)0x000000000000ff00ULL) << 40) |
+ (((uint64_t)val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+ (((uint64_t)val & (uint64_t)0x00000000ff000000ULL) << 8) |
+ (((uint64_t)val & (uint64_t)0x000000ff00000000ULL) >> 8) |
+ (((uint64_t)val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+ (((uint64_t)val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+ (((uint64_t)val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
+/* Return a 32-bit litte-endian value from a given 32-bit big-endian one */
+static inline uint32_t be32_to_cpu(uint32_t val)
+{
+ return (uint32_t)((((uint32_t)val & (uint32_t)0x000000ffUL) << 24) |
+ (((uint32_t)val & (uint32_t)0x0000ff00UL) << 8) |
+ (((uint32_t)val & (uint32_t)0x00ff0000UL) >> 8) |
+ (((uint32_t)val & (uint32_t)0xff000000UL) >> 24));
+}
+
+/* Return a 16-bit litte-endian value from a given 16-bit big-endian one */
+static inline uint16_t be16_to_cpu(uint16_t val)
+{
+ return (uint16_t)((((uint16_t)val & (uint16_t)0x00ffU) << 8) |
+ (((uint16_t)val & (uint16_t)0xff00U) >> 8));
+}
+
+#endif /* MISC_H_ */
diff --git a/extlinux/xfs.h b/extlinux/xfs.h
new file mode 100644
index 00000000..412c2662
--- /dev/null
+++ b/extlinux/xfs.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef XFS_H_
+#define XFS_H_
+
+#define XFS_SUPER_MAGIC 0x58465342
+
+#endif /* XFS_H_ */
diff --git a/extlinux/xfs_fs.h b/extlinux/xfs_fs.h
new file mode 100644
index 00000000..587820ec
--- /dev/null
+++ b/extlinux/xfs_fs.h
@@ -0,0 +1,501 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 1995-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_FS_H_
+#define XFS_FS_H_
+
+/*
+ * SGI's XFS filesystem's major stuff (constants, structures)
+ */
+
+/*
+ * Direct I/O attribute record used with XFS_IOC_DIOINFO
+ * d_miniosz is the min xfer size, xfer size multiple and file seek offset
+ * alignment.
+ */
+struct dioattr {
+ uint32_t d_mem; /* data buffer memory alignment */
+ uint32_t d_miniosz; /* min xfer size */
+ uint32_t d_maxiosz; /* max xfer size */
+};
+
+/*
+ * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+ uint32_t fsx_xflags; /* xflags field value (get/set) */
+ uint32_t fsx_extsize; /* extsize field value (get/set)*/
+ uint32_t fsx_nextents; /* nextents field value (get) */
+ uint32_t fsx_projid; /* project identifier (get/set) */
+ unsigned char fsx_pad[12];
+};
+
+/*
+ * Flags for the bs_xflags/fsx_xflags field
+ * There should be a one-to-one correspondence between these flags and the
+ * XFS_DIFLAG_s.
+ */
+#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
+#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
+#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
+#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
+#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
+#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
+#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
+#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
+#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
+#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
+#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
+#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
+
+/*
+ * Structure for XFS_IOC_GETBMAP.
+ * On input, fill in bmv_offset and bmv_length of the first structure
+ * to indicate the area of interest in the file, and bmv_entries with
+ * the number of array elements given back. The first structure is
+ * updated on return to give the offset and length for the next call.
+ */
+struct getbmap {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output) */
+};
+
+/*
+ * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries
+ * are used exactly as in the getbmap structure. The getbmapx structure
+ * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field
+ * is only used for the first structure. It contains input flags
+ * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled
+ * in by the XFS_IOC_GETBMAPX command for each returned structure after
+ * the first.
+ */
+struct getbmapx {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output). */
+ int32_t bmv_iflags; /* input flags (1st structure) */
+ int32_t bmv_oflags; /* output flags (after 1st structure)*/
+ int32_t bmv_unused1; /* future use */
+ int32_t bmv_unused2; /* future use */
+};
+
+/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */
+#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */
+#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
+#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
+#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */
+#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */
+#define BMV_IF_VALID \
+ (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \
+ BMV_IF_DELALLOC|BMV_IF_NO_HOLES)
+
+/* bmv_oflags values - returned for each non-header segment */
+#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
+#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */
+#define BMV_OF_LAST 0x4 /* segment is the last in the file */
+
+/*
+ * Structure for XFS_IOC_FSSETDM.
+ * For use by backup and restore programs to set the XFS on-disk inode
+ * fields di_dmevmask and di_dmstate. These must be set to exactly and
+ * only values previously obtained via xfs_bulkstat! (Specifically the
+ * xfs_bstat_t fields bs_dmevmask and bs_dmstate.)
+ */
+struct fsdmidata {
+ uint32_t fsd_dmevmask; /* corresponds to di_dmevmask */
+ __u16 fsd_padding;
+ __u16 fsd_dmstate; /* corresponds to di_dmstate */
+};
+
+/*
+ * File segment locking set data type for 64 bit access.
+ * Also used for all the RESV/FREE interfaces.
+ */
+typedef struct xfs_flock64 {
+ __s16 l_type;
+ __s16 l_whence;
+ int64_t l_start;
+ int64_t l_len; /* len == 0 means until end of file */
+ int32_t l_sysid;
+ uint32_t l_pid;
+ int32_t l_pad[4]; /* reserve area */
+} xfs_flock64_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY_V1
+ */
+typedef struct xfs_fsop_geom_v1 {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+} xfs_fsop_geom_v1_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY
+ */
+typedef struct xfs_fsop_geom {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+ uint32_t logsunit; /* log stripe unit, bytes */
+} xfs_fsop_geom_t;
+
+/* Output for XFS_FS_COUNTS */
+typedef struct xfs_fsop_counts {
+ uint64_t freedata; /* free data section blocks */
+ uint64_t freertx; /* free rt extents */
+ uint64_t freeino; /* free inodes */
+ uint64_t allocino; /* total allocated inodes */
+} xfs_fsop_counts_t;
+
+/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */
+typedef struct xfs_fsop_resblks {
+ uint64_t resblks;
+ uint64_t resblks_avail;
+} xfs_fsop_resblks_t;
+
+#define XFS_FSOP_GEOM_VERSION 0
+
+#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */
+#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */
+#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */
+#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */
+#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */
+#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */
+#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */
+#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */
+#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */
+#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
+
+
+/*
+ * Minimum and maximum sizes need for growth checks
+ */
+#define XFS_MIN_AG_BLOCKS 64
+#define XFS_MIN_LOG_BLOCKS 512ULL
+#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+ ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
+
+/* Used for sanity checks on superblock */
+#define XFS_MAX_DBLOCKS(s) ((xfs_drfsbno_t)(s)->sb_agcount * (s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((xfs_drfsbno_t)((s)->sb_agcount - 1) * \
+ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+/*
+ * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT
+ */
+typedef struct xfs_growfs_data {
+ uint64_t newblocks; /* new data subvol size, fsblocks */
+ uint32_t imaxpct; /* new inode space percentage limit */
+} xfs_growfs_data_t;
+
+typedef struct xfs_growfs_log {
+ uint32_t newblocks; /* new log size, fsblocks */
+ uint32_t isint; /* 1 if new log is internal */
+} xfs_growfs_log_t;
+
+typedef struct xfs_growfs_rt {
+ uint64_t newblocks; /* new realtime size, fsblocks */
+ uint32_t extsize; /* new realtime extent size, fsblocks */
+} xfs_growfs_rt_t;
+
+
+/*
+ * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
+ */
+typedef struct xfs_bstime {
+ time_t tv_sec; /* seconds */
+ int32_t tv_nsec; /* and nanoseconds */
+} xfs_bstime_t;
+
+typedef struct xfs_bstat {
+ uint64_t bs_ino; /* inode number */
+ __u16 bs_mode; /* type and mode */
+ __u16 bs_nlink; /* number of links */
+ uint32_t bs_uid; /* user id */
+ uint32_t bs_gid; /* group id */
+ uint32_t bs_rdev; /* device value */
+ int32_t bs_blksize; /* block size */
+ int64_t bs_size; /* file size */
+ xfs_bstime_t bs_atime; /* access time */
+ xfs_bstime_t bs_mtime; /* modify time */
+ xfs_bstime_t bs_ctime; /* inode change time */
+ int64_t bs_blocks; /* number of blocks */
+ uint32_t bs_xflags; /* extended flags */
+ int32_t bs_extsize; /* extent size */
+ int32_t bs_extents; /* number of extents */
+ uint32_t bs_gen; /* generation count */
+ __u16 bs_projid_lo; /* lower part of project id */
+#define bs_projid bs_projid_lo /* (previously just bs_projid) */
+ __u16 bs_forkoff; /* inode fork offset in bytes */
+ __u16 bs_projid_hi; /* higher part of project id */
+ unsigned char bs_pad[10]; /* pad space, unused */
+ uint32_t bs_dmevmask; /* DMIG event mask */
+ __u16 bs_dmstate; /* DMIG state info */
+ __u16 bs_aextents; /* attribute number of extents */
+} xfs_bstat_t;
+
+/*
+ * The user-level BulkStat Request interface structure.
+ */
+typedef struct xfs_fsop_bulkreq {
+ uint64_t __user *lastip; /* last inode # pointer */
+ int32_t icount; /* count of entries in buffer */
+ void __user *ubuffer;/* user buffer for inode desc. */
+ int32_t __user *ocount; /* output count pointer */
+} xfs_fsop_bulkreq_t;
+
+
+/*
+ * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS).
+ */
+typedef struct xfs_inogrp {
+ uint64_t xi_startino; /* starting inode number */
+ int32_t xi_alloccount; /* # bits set in allocmask */
+ uint64_t xi_allocmask; /* mask of allocated inodes */
+} xfs_inogrp_t;
+
+
+/*
+ * Error injection.
+ */
+typedef struct xfs_error_injection {
+ int32_t fd;
+ int32_t errtag;
+} xfs_error_injection_t;
+
+
+/*
+ * The user-level Handle Request interface structure.
+ */
+typedef struct xfs_fsop_handlereq {
+ uint32_t fd; /* fd for FD_TO_HANDLE */
+ void __user *path; /* user pathname */
+ uint32_t oflags; /* open flags */
+ void __user *ihandle;/* user supplied handle */
+ uint32_t ihandlen; /* user supplied length */
+ void __user *ohandle;/* user buffer for handle */
+ uint32_t __user *ohandlen;/* user buffer length */
+} xfs_fsop_handlereq_t;
+
+/*
+ * Compound structures for passing args through Handle Request interfaces
+ * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle
+ * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and
+ * XFS_IOC_ATTRMULTI_BY_HANDLE
+ */
+
+typedef struct xfs_fsop_setdm_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle information */
+ struct fsdmidata __user *data; /* DMAPI data */
+} xfs_fsop_setdm_handlereq_t;
+
+typedef struct xfs_attrlist_cursor {
+ uint32_t opaque[4];
+} xfs_attrlist_cursor_t;
+
+typedef struct xfs_fsop_attrlist_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
+ uint32_t flags; /* which namespace to use */
+ uint32_t buflen; /* length of buffer supplied */
+ void __user *buffer; /* returned names */
+} xfs_fsop_attrlist_handlereq_t;
+
+typedef struct xfs_attr_multiop {
+ uint32_t am_opcode;
+#define ATTR_OP_GET 1 /* return the indicated attr's value */
+#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
+#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
+ int32_t am_error;
+ void __user *am_attrname;
+ void __user *am_attrvalue;
+ uint32_t am_length;
+ uint32_t am_flags;
+} xfs_attr_multiop_t;
+
+typedef struct xfs_fsop_attrmulti_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ uint32_t opcount;/* count of following multiop */
+ struct xfs_attr_multiop __user *ops; /* attr_multi data */
+} xfs_fsop_attrmulti_handlereq_t;
+
+/*
+ * per machine unique filesystem identifier types.
+ */
+typedef struct { uint32_t val[2]; } xfs_fsid_t; /* file system id type */
+
+typedef struct xfs_fid {
+ __u16 fid_len; /* length of remainder */
+ __u16 fid_pad;
+ uint32_t fid_gen; /* generation number */
+ uint64_t fid_ino; /* 64 bits inode number */
+} xfs_fid_t;
+
+typedef struct xfs_handle {
+ union {
+ int64_t align; /* force alignment of ha_fid */
+ xfs_fsid_t _ha_fsid; /* unique file system identifier */
+ } ha_u;
+ xfs_fid_t ha_fid; /* file system specific file ID */
+} xfs_handle_t;
+#define ha_fsid ha_u._ha_fsid
+
+#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \
+ - (char *) &(handle)) \
+ + (handle).ha_fid.fid_len)
+
+/*
+ * Flags for going down operation
+ */
+#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */
+#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
+#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
+
+/*
+ * ioctl commands that are used by Linux filesystems
+ */
+#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS
+#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS
+#define XFS_IOC_GETVERSION FS_IOC_GETVERSION
+
+/*
+ * ioctl commands that replace IRIX fcntl()'s
+ * For 'documentation' purposed more than anything else,
+ * the "cmd #" field reflects the IRIX fcntl number.
+ */
+#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
+#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
+#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
+#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
+#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
+#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
+#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
+#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata)
+#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64)
+#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64)
+#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap)
+#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr)
+/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */
+/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */
+#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap)
+#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)
+
+/*
+ * ioctl commands that replace IRIX syssgi()'s
+ */
+#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1)
+#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq)
+#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq)
+#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext)
+#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data)
+#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log)
+#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt)
+#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts)
+#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks)
+#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks)
+#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection)
+#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection)
+/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */
+/* XFS_IOC_FREEZE -- FIFREEZE 119 */
+/* XFS_IOC_THAW -- FITHAW 120 */
+#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq)
+#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq)
+#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)
+#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)
+#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t)
+/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
+
+
+#ifndef HAVE_BBMACROS
+/*
+ * Block I/O parameterization. A basic block (BB) is the lowest size of
+ * filesystem allocation, and must equal 512. Length units given to bio
+ * routines are in BB's.
+ */
+#define BBSHIFT 9
+#define BBSIZE (1<<BBSHIFT)
+#define BBMASK (BBSIZE-1)
+#define BTOBB(bytes) (((uint64_t)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BTOBBT(bytes) ((uint64_t)(bytes) >> BBSHIFT)
+#define BBTOB(bbs) ((bbs) << BBSHIFT)
+#endif
+
+#endif /* XFS_FS_H_ */
diff --git a/extlinux/xfs_sb.h b/extlinux/xfs_sb.h
new file mode 100644
index 00000000..8f72d6ad
--- /dev/null
+++ b/extlinux/xfs_sb.h
@@ -0,0 +1,476 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_SB_H_
+#define XFS_SB_H__
+
+#include <stddef.h>
+
+#include <sys/types.h>
+#include <uuid/uuid.h>
+
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define XFS_SB_MAGIC "XFSB" /* 'XFSB' */
+#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */
+#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */
+#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */
+#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
+#define XFS_SB_VERSION_NUMBITS 0x000f
+#define XFS_SB_VERSION_ALLFBITS 0xfff0
+#define XFS_SB_VERSION_SASHFBITS 0xf000
+#define XFS_SB_VERSION_REALFBITS 0x0ff0
+#define XFS_SB_VERSION_ATTRBIT 0x0010
+#define XFS_SB_VERSION_NLINKBIT 0x0020
+#define XFS_SB_VERSION_QUOTABIT 0x0040
+#define XFS_SB_VERSION_ALIGNBIT 0x0080
+#define XFS_SB_VERSION_DALIGNBIT 0x0100
+#define XFS_SB_VERSION_SHAREDBIT 0x0200
+#define XFS_SB_VERSION_LOGV2BIT 0x0400
+#define XFS_SB_VERSION_SECTORBIT 0x0800
+#define XFS_SB_VERSION_EXTFLGBIT 0x1000
+#define XFS_SB_VERSION_DIRV2BIT 0x2000
+#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */
+#define XFS_SB_VERSION_MOREBITSBIT 0x8000
+#define XFS_SB_VERSION_OKSASHFBITS \
+ (XFS_SB_VERSION_EXTFLGBIT | \
+ XFS_SB_VERSION_DIRV2BIT | \
+ XFS_SB_VERSION_BORGBIT)
+#define XFS_SB_VERSION_OKREALFBITS \
+ (XFS_SB_VERSION_ATTRBIT | \
+ XFS_SB_VERSION_NLINKBIT | \
+ XFS_SB_VERSION_QUOTABIT | \
+ XFS_SB_VERSION_ALIGNBIT | \
+ XFS_SB_VERSION_DALIGNBIT | \
+ XFS_SB_VERSION_SHAREDBIT | \
+ XFS_SB_VERSION_LOGV2BIT | \
+ XFS_SB_VERSION_SECTORBIT | \
+ XFS_SB_VERSION_MOREBITSBIT)
+#define XFS_SB_VERSION_OKREALBITS \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_OKREALFBITS | \
+ XFS_SB_VERSION_OKSASHFBITS)
+
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2. Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
+#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
+#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
+#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */
+#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */
+
+#define XFS_SB_VERSION2_OKREALFBITS \
+ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
+ XFS_SB_VERSION2_ATTR2BIT | \
+ XFS_SB_VERSION2_PROJID32BIT)
+#define XFS_SB_VERSION2_OKSASHFBITS \
+ (0)
+#define XFS_SB_VERSION2_OKREALBITS \
+ (XFS_SB_VERSION2_OKREALFBITS | \
+ XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * Superblock - in core version. Must match the ondisk version below.
+ * Must be padded to 64 bit alignment.
+ */
+typedef struct xfs_sb {
+ uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
+ uint32_t sb_blocksize; /* logical block size, bytes */
+ xfs_drfsbno_t sb_dblocks; /* number of data blocks */
+ xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
+ xfs_drtbno_t sb_rextents; /* number of realtime extents */
+ uuid_t sb_uuid; /* file system unique id */
+ xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
+ xfs_ino_t sb_rootino; /* root inode number */
+ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
+ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
+ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
+ xfs_agblock_t sb_agblocks; /* size of an allocation group */
+ xfs_agnumber_t sb_agcount; /* number of allocation groups */
+ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
+ xfs_extlen_t sb_logblocks; /* number of log blocks */
+ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
+ uint16_t sb_sectsize; /* volume sector size, bytes */
+ uint16_t sb_inodesize; /* inode size, bytes */
+ uint16_t sb_inopblock; /* inodes per block */
+ char sb_fname[12]; /* file system name */
+ uint8_t sb_blocklog; /* log2 of sb_blocksize */
+ uint8_t sb_sectlog; /* log2 of sb_sectsize */
+ uint8_t sb_inodelog; /* log2 of sb_inodesize */
+ uint8_t sb_inopblog; /* log2 of sb_inopblock */
+ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
+ uint8_t sb_rextslog; /* log2 of sb_rextents */
+ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
+ uint8_t sb_imax_pct; /* max % of fs for inode space */
+ /* statistics */
+ /*
+ * These fields must remain contiguous. If you really
+ * want to change their layout, make sure you fix the
+ * code in xfs_trans_apply_sb_deltas().
+ */
+ uint64_t sb_icount; /* allocated inodes */
+ uint64_t sb_ifree; /* free inodes */
+ uint64_t sb_fdblocks; /* free data blocks */
+ uint64_t sb_frextents; /* free realtime extents */
+ /*
+ * End contiguous fields.
+ */
+ xfs_ino_t sb_uquotino; /* user quota inode */
+ xfs_ino_t sb_gquotino; /* group quota inode */
+ uint16_t sb_qflags; /* quota flags */
+ uint8_t sb_flags; /* misc. flags */
+ uint8_t sb_shared_vn; /* shared version number */
+ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
+ uint32_t sb_unit; /* stripe or raid unit */
+ uint32_t sb_width; /* stripe or raid width */
+ uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
+ uint8_t sb_logsectlog; /* log2 of the log sector size */
+ uint16_t sb_logsectsize; /* sector size for the log, bytes */
+ uint32_t sb_logsunit; /* stripe unit size for the log */
+ uint32_t sb_features2; /* additional feature bits */
+
+ /*
+ * bad features2 field as a result of failing to pad the sb
+ * structure to 64 bits. Some machines will be using this field
+ * for features2 bits. Easiest just to mark it bad and not use
+ * it for anything else.
+ */
+ uint32_t sb_bad_features2;
+
+ /* must be padded to 64 bit alignment */
+} xfs_sb_t;
+
+/*
+ * Sequence number values for the fields.
+ */
+typedef enum {
+ XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
+ XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
+ XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
+ XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
+ XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
+ XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
+ XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
+ XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
+ XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
+ XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
+ XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
+ XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+ XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+ XFS_SBS_FIELDCOUNT
+} xfs_sb_field_t;
+
+/*
+ * Mask values, defined based on the xfs_sb_field_t values.
+ * Only define the ones we're using.
+ */
+#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x)
+#define XFS_SB_UUID XFS_SB_MVAL(UUID)
+#define XFS_SB_FNAME XFS_SB_MVAL(FNAME)
+#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO)
+#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO)
+#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO)
+#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM)
+#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO)
+#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO)
+#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS)
+#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
+#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
+#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS)
+#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2)
+#define XFS_SB_BAD_FEATURES2 XFS_SB_MVAL(BAD_FEATURES2)
+#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
+#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
+#define XFS_SB_MOD_BITS \
+ (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
+ XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
+ XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
+ XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
+ XFS_SB_BAD_FEATURES2)
+
+
+/*
+ * Misc. Flags - warning - these will be cleared by xfs_repair unless
+ * a feature bit is set when the flag is used.
+ */
+#define XFS_SBF_NOFLAGS 0x00 /* no flags set */
+#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */
+
+/*
+ * define max. shared version we can interoperate with
+ */
+#define XFS_SB_MAX_SHARED_VN 0
+
+#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
+
+static inline int xfs_sb_good_version(xfs_sb_t *sbp)
+{
+ /* We always support version 1-3 */
+ if (sbp->sb_versionnum >= XFS_SB_VERSION_1 &&
+ sbp->sb_versionnum <= XFS_SB_VERSION_3)
+ return 1;
+
+ /* We support version 4 if all feature bits are supported */
+ if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) {
+ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) ||
+ ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) &&
+ (sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS)))
+ return 0;
+
+ if ((sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) &&
+ sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
+ return 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Detect a mismatched features2 field. Older kernels read/wrote
+ * this into the wrong slot, so to be safe we keep them in sync.
+ */
+static inline int xfs_sb_has_mismatched_features2(xfs_sb_t *sbp)
+{
+ return (sbp->sb_bad_features2 != sbp->sb_features2);
+}
+
+static inline unsigned xfs_sb_version_tonew(unsigned v)
+{
+ if (v == XFS_SB_VERSION_1)
+ return XFS_SB_VERSION_4;
+
+ if (v == XFS_SB_VERSION_2)
+ return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
+
+ return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT |
+ XFS_SB_VERSION_NLINKBIT;
+}
+
+static inline unsigned xfs_sb_version_toold(unsigned v)
+{
+ if (v & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT))
+ return 0;
+ if (v & XFS_SB_VERSION_NLINKBIT)
+ return XFS_SB_VERSION_3;
+ if (v & XFS_SB_VERSION_ATTRBIT)
+ return XFS_SB_VERSION_2;
+ return XFS_SB_VERSION_1;
+}
+
+static inline int xfs_sb_version_hasattr(xfs_sb_t *sbp)
+{
+ return sbp->sb_versionnum == XFS_SB_VERSION_2 ||
+ sbp->sb_versionnum == XFS_SB_VERSION_3 ||
+ (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT));
+}
+
+static inline void xfs_sb_version_addattr(xfs_sb_t *sbp)
+{
+ if (sbp->sb_versionnum == XFS_SB_VERSION_1)
+ sbp->sb_versionnum = XFS_SB_VERSION_2;
+ else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
+ sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
+ else
+ sbp->sb_versionnum = XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
+}
+
+static inline int xfs_sb_version_hasnlink(xfs_sb_t *sbp)
+{
+ return sbp->sb_versionnum == XFS_SB_VERSION_3 ||
+ (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT));
+}
+
+static inline void xfs_sb_version_addnlink(xfs_sb_t *sbp)
+{
+ if (sbp->sb_versionnum <= XFS_SB_VERSION_2)
+ sbp->sb_versionnum = XFS_SB_VERSION_3;
+ else
+ sbp->sb_versionnum |= XFS_SB_VERSION_NLINKBIT;
+}
+
+static inline int xfs_sb_version_hasquota(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT);
+}
+
+static inline void xfs_sb_version_addquota(xfs_sb_t *sbp)
+{
+ if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
+ sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT;
+ else
+ sbp->sb_versionnum = xfs_sb_version_tonew(sbp->sb_versionnum) |
+ XFS_SB_VERSION_QUOTABIT;
+}
+
+static inline int xfs_sb_version_hasalign(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT);
+}
+
+static inline int xfs_sb_version_hasdalign(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT);
+}
+
+static inline int xfs_sb_version_hasshared(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT);
+}
+
+static inline int xfs_sb_version_hasdirv2(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
+}
+
+static inline int xfs_sb_version_haslogv2(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT);
+}
+
+static inline int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT);
+}
+
+static inline int xfs_sb_version_hassector(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
+}
+
+static inline int xfs_sb_version_hasasciici(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT);
+}
+
+static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT);
+}
+
+/*
+ * sb_features2 bit version macros.
+ *
+ * For example, for a bit defined as XFS_SB_VERSION2_FUNBIT, has a macro:
+ *
+ * SB_VERSION_HASFUNBIT(xfs_sb_t *sbp)
+ * ((xfs_sb_version_hasmorebits(sbp) &&
+ * ((sbp)->sb_features2 & XFS_SB_VERSION2_FUNBIT)
+ */
+
+static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp)
+{
+ return xfs_sb_version_hasmorebits(sbp) &&
+ (sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT);
+}
+
+static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp)
+{
+ return xfs_sb_version_hasmorebits(sbp) &&
+ (sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT);
+}
+
+static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp)
+{
+ sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
+ sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT;
+}
+
+static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp)
+{
+ sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT;
+ if (!sbp->sb_features2)
+ sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT;
+}
+
+static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
+{
+ return xfs_sb_version_hasmorebits(sbp) &&
+ (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT);
+}
+
+/*
+ * end of superblock version macros
+ */
+
+#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */
+#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
+#define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr))
+
+#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
+#define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \
+ xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d))
+#define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \
+ XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno))
+
+/*
+ * File system sector to basic block conversions.
+ */
+#define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log)
+
+/*
+ * File system block to basic block conversions.
+ */
+#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSB(mp,bb) \
+ (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log)
+
+/*
+ * File system block to byte conversions.
+ */
+#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSB(mp,b) \
+ ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask)
+
+#endif /* XFS_SB_H_ */
diff --git a/extlinux/xfs_types.h b/extlinux/xfs_types.h
new file mode 100644
index 00000000..92808865
--- /dev/null
+++ b/extlinux/xfs_types.h
@@ -0,0 +1,135 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_TYPES_H_
+#define XFS_TYPES_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef enum { B_FALSE,B_TRUE } boolean_t;
+typedef uint32_t prid_t; /* project ID */
+typedef uint32_t inst_t; /* an instruction */
+
+typedef int64_t xfs_off_t; /* <file offset> type */
+typedef unsigned long long xfs_ino_t; /* <inode> type */
+typedef int64_t xfs_daddr_t; /* <disk address> type */
+typedef char * xfs_caddr_t; /* <core address> type */
+typedef uint32_t xfs_dev_t;
+typedef uint32_t xfs_nlink_t;
+
+/* __psint_t is the same size as a pointer */
+typedef int32_t __psint_t;
+typedef uint32_t __psunsigned_t;
+
+typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
+typedef uint32_t xfs_extlen_t; /* extent length in blocks */
+typedef uint32_t xfs_agnumber_t; /* allocation group number */
+typedef int32_t xfs_extnum_t; /* # of extents in a file */
+typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
+typedef int64_t xfs_fsize_t; /* bytes in a file */
+typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */
+
+typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */
+typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */
+
+typedef int64_t xfs_lsn_t; /* log sequence number */
+typedef int32_t xfs_tid_t; /* transaction identifier */
+
+typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
+typedef uint32_t xfs_dahash_t; /* dir/attr hash value */
+
+/*
+ * These types are 64 bits on disk but are either 32 or 64 bits in memory.
+ * Disk based types:
+ */
+typedef uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
+typedef uint64_t xfs_dfiloff_t; /* block number in a file */
+typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */
+
+/*
+ * Memory based types are conditional.
+ */
+typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */
+typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
+
+typedef uint64_t xfs_fileoff_t; /* block number in a file */
+typedef int64_t xfs_sfiloff_t; /* signed block number in a file */
+typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
+
+/*
+ * Null values for the types.
+ */
+#define NULLDFSBNO ((xfs_dfsbno_t)-1)
+#define NULLDRFSBNO ((xfs_drfsbno_t)-1)
+#define NULLDRTBNO ((xfs_drtbno_t)-1)
+#define NULLDFILOFF ((xfs_dfiloff_t)-1)
+
+#define NULLFSBLOCK ((xfs_fsblock_t)-1)
+#define NULLRFSBLOCK ((xfs_rfsblock_t)-1)
+#define NULLRTBLOCK ((xfs_rtblock_t)-1)
+#define NULLFILEOFF ((xfs_fileoff_t)-1)
+
+#define NULLAGBLOCK ((xfs_agblock_t)-1)
+#define NULLAGNUMBER ((xfs_agnumber_t)-1)
+#define NULLEXTNUM ((xfs_extnum_t)-1)
+
+#define NULLCOMMITLSN ((xfs_lsn_t)-1)
+
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */
+#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */
+#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */
+
+/*
+ * Min numbers of data/attr fork btree root pointers.
+ */
+#define MINDBTPTRS 3
+#define MINABTPTRS 2
+
+/*
+ * MAXNAMELEN is the length (including the terminating null) of
+ * the longest permissible file (component) name.
+ */
+#define MAXNAMELEN 256
+
+typedef enum {
+ XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
+} xfs_lookup_t;
+
+typedef enum {
+ XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+ XFS_BTNUM_MAX
+} xfs_btnum_t;
+
+struct xfs_name {
+ const unsigned char *name;
+ int len;
+};
+
+#endif /* XFS_TYPES_H_ */
diff --git a/libinstaller/syslxfs.h b/libinstaller/syslxfs.h
index 7a231461..4d8f3b2c 100644
--- a/libinstaller/syslxfs.h
+++ b/libinstaller/syslxfs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 Paulo Alcantara <pcacjr@gmail.com>
+ * Copyright 2011-2012 Paulo Alcantara <pcacjr@zytor.com>
*
* 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
@@ -12,13 +12,14 @@
#ifndef _SYSLXFS_H_
#define _SYSLXFS_H_
-/* Global fs_type for handling fat, ntfs, ext2/3/4 and btrfs */
+/* Global fs_type for handling fat, ntfs, ext2/3/4, btrfs and xfs */
enum filesystem {
NONE,
EXT2,
BTRFS,
VFAT,
NTFS,
+ XFS,
};
extern int fs_type;
diff --git a/man/syslinux.1 b/man/syslinux.1
index af44979b..adcaf94d 100644
--- a/man/syslinux.1
+++ b/man/syslinux.1
@@ -141,8 +141,7 @@ and if no "append" is given the default is to use the global entry (if any).
Use "append -" to use no options at all. Up to 128 "label" entries are
permitted.
.IP
-The "image" doesn't have to be a Linux kernel; it can be a boot sector or a
-COMBOOT file (see below.)
+The "image" doesn't have to be a Linux kernel; it can be a boot sector (see below.)
.RE
.TP
.BI implicit\ flag_val
@@ -297,25 +296,21 @@ For example:
.TP
\fI<SUB>\fP = \fI<Ctrl-Z>\fP = ASCII 26
End of file (DOS convention).
-.SS Comboot Images and other operating systems
+.SS Other operating systems
This version of \fBsyslinux\fP supports chain loading of other operating
-systems (such as MS-DOS and its derivatives, including Windows 95/98),
-as well as COMBOOT-style standalone executables (a subset of DOS .COM
-files; see separate section below.)
+systems (such as MS-DOS and its derivatives, including Windows 95/98).
.PP
Chain loading requires the boot sector of the foreign operating system
to be stored in a file in the root directory of the filesystem.
-Because neither Linux kernels, boot sector images, nor COMBOOT files
-have reliable magic numbers, \fBsyslinux\fP will look at the file
+Because neither Linux kernels, nor boot sector images have reliable magic
+numbers, \fBsyslinux\fP will look at the file
extension. The following extensions are recognised:
.PP
.nf
.ta \w'none or other 'u
none or other Linux kernel image
-CBT COMBOOT image (not runnable from DOS)
BSS Boot sector (DOS superblock will be patched in)
BS Boot sector
-COM COMBOOT image (runnable from DOS)
.fi
.PP
For filenames given on the command line, \fBsyslinux\fP will search for the
@@ -323,29 +318,6 @@ file by adding extensions in the order listed above if the plain
filename is not found. Filenames in KERNEL statements must be fully
qualified.
.PP
-A COMBOOT file is a standalone executable in DOS .COM format. They
-can, among other things, be produced by the Etherboot package by
-Markus Gutschke and Ken Yap. The following requirements apply for
-these files to be sufficiently "standalone" for \fBsyslinux\fP to be able to
-load and run them:
-.IP \(bu
-The program must not execute any DOS calls (since there is no
-DOS), although it may call the BIOS. The only exception is that
-the program may execute INT 20h (Terminate Program) to return to
-the \fBsyslinux\fP prompt. Note especially that INT 21h AH=4Ch, INT 21h
-AH=31h or INT 27h are not supported.
-.IP \(bu
-Only the fields pspInt20 at offset 00h, pspNextParagraph at offset 02h and
-pspCommandTail at offset 80h (contains the arguments from the \fBsyslinux\fP command
-line) in the PSP are supported. All other fields will contain zero.
-.IP \(bu
-The program must not modify any main memory outside its 64K segment if it
-returns to \fBsyslinux\fP via INT 20h.
-.PP
-\fBSyslinux\fP currently doesn't provide any form of API for the use of
-COMBOOT files. If there is need, a future version may contain an INT
-interface to some \fBsyslinux\fP functions; please contact me if you have a
-need or ideas for such an API.
.SS Novice protection
\fBSyslinux\fP will attempt to detect if the user is trying to boot on a 286
or lower class machine, or a machine with less than 608K of low ("DOS")
diff --git a/mbr/mbr.S b/mbr/mbr.S
index b71cfb7c..270a3568 100644
--- a/mbr/mbr.S
+++ b/mbr/mbr.S
@@ -265,6 +265,19 @@ boot:
movl %eax, 8(%si) /* Adjust in-memory partition table entry */
call read_sector
jc disk_error
+
+ /* Check if the read sector is a XFS superblock */
+ cmpl $0x42534658, (bootsec) /* "XFSB" */
+ jne no_xfs
+
+ /* We put the Syslinux boot sector at offset 0x800 (4 sectors), so we
+ * need to adjust %eax (%eax + 4) to read the right sector into 0x7C00.
+ */
+ addl $0x800 >> 0x09, %eax /* plus 4 sectors */
+ call read_sector
+ jc disk_error
+
+no_xfs:
cmpw $0xaa55, (bootsec+510)
jne missing_os /* Not a valid boot sector */
movw $driveno, %sp /* driveno == bootsec-6 */
diff --git a/mk/embedded.mk b/mk/embedded.mk
index a4de9ab3..ffebe83c 100644
--- a/mk/embedded.mk
+++ b/mk/embedded.mk
@@ -48,7 +48,7 @@ GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
-
+GCCOPT += $(call gcc_ok,-fvisibility=hidden)
LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
diff --git a/modules/Makefile b/modules/Makefile
deleted file mode 100644
index e985af4a..00000000
--- a/modules/Makefile
+++ /dev/null
@@ -1,61 +0,0 @@
-## -----------------------------------------------------------------------
-##
-## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
-##
-## 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, Inc., 53 Temple Place Ste 330,
-## Boston MA 02111-1307, USA; either version 2 of the License, or
-## (at your option) any later version; incorporated herein by reference.
-##
-## -----------------------------------------------------------------------
-
-##
-## Non-COM32 simple Syslinux modules
-##
-
-VPATH = $(SRC)
-include $(MAKEDIR)/embedded.mk
-
-INCLUDES = -I$(com32)/include
-NASMOPT = -I$(SRC)/ -I$(SRC)/../core/
-
-BINS = pxechain.com poweroff.com int18.com ver.com
-
-all: $(BINS)
-
-.PRECIOUS: %.o
-
-.PRECIOUS: %.elf
-%.elf: c32entry.o %.o $(LIB)
- $(LD) -Ttext 0x101000 -e _start -o $@ $^
-
-%.c32: %.elf
- $(OBJCOPY) -O binary $< $@
-
-%.com: %.asm
- ( $(NASM) -M -DDEPEND -o $@ $< ; echo '' ) > .$@.d ; true
- $(NASM) $(NASMOPT) -f bin -o $@ -l $*.lst $<
-
-$(LIB): $(LIBOBJS)
- rm -f $@
- $(AR) cq $@ $^
- $(RANLIB) $@
-
-%.lss: %.ppm.gz $(PPMTOLSS16)
- $(GZIPPROG) -cd $< | \
- $(PPMTOLSS16) \#000000=0 \#d0d0d0=7 \#f6f6f6=15 \
- > $@
-
-%.ppm.gz: %.png
- $(PNGTOPNM) $< | gzip -9 > $@
-
-tidy dist:
- rm -f *.o *.a *.lst *.elf *.map .*.d
-
-clean: tidy
-
-spotless: clean
- rm -f $(BINS)
-
--include .*.d
diff --git a/modules/int18.asm b/modules/int18.asm
deleted file mode 100644
index a13ada75..00000000
--- a/modules/int18.asm
+++ /dev/null
@@ -1,16 +0,0 @@
- bits 16
- org 100h
-_start:
- mov ax,5
- int 22h
- mov ah,09h
- mov dx,msg
- int 21h
- mov ax,000Ch
- xor dx,dx
- int 22h
- int 18h
- jmp 0F000h:0FFF0h ; INT 18h should not return...
-
- section .data
-msg: db 'Local boot via INT 18...', 13, 10, '$'
diff --git a/modules/poweroff.asm b/modules/poweroff.asm
deleted file mode 100644
index f4f19a2f..00000000
--- a/modules/poweroff.asm
+++ /dev/null
@@ -1,102 +0,0 @@
-; ****************************************************************************
-;
-; poweroff.asm
-;
-; Copyright 2009 Sebastian Herbszt
-;
-; APM poweroff module.
-;
-; 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, Inc., 53 Temple Place Ste 330,
-; Boston MA 02111-1307, USA; either version 2 of the License, or
-; (at your option) any later version; incorporated herein by reference.
-;
-; ****************************************************************************
-
- absolute 0
-pspInt20: resw 1
-pspNextP: resw 1
- resb 124
-pspCmdLen: resb 1
-pspCmdArg: resb 127
-
- section .text
- org 0x100
-
-_start:
- mov ax,5300h ; APM Installation Check (00h)
- xor bx,bx ; APM BIOS (0000h)
- int 15h
- jnc check_sig
-
- mov bx, msg_notpresent
- jmp error
-
-check_sig:
- cmp bx,504Dh ; signature 'PM'
- je check_ver
-
- mov bx, msg_notpresent
- jmp error
-
-check_ver:
- cmp ax,0101h ; Need version 1.1+
- jae check_state
-
- mov bx, msg_notsup
- jmp error
-
-check_state:
- test cx,8 ; bit 3 APM BIOS Power Management disabled
- jz connect
-
- mov bx, msg_pmdisabled
- jmp error
-
-connect:
- mov ax,5301h ; APM Real Mode Interface Connect (01h)
- xor bx,bx ; APM BIOS (0000h)
- int 15h
- jnc connect_ok
-
- mov bx, msg_connect
- jmp error
-
-connect_ok:
- mov ax,530Eh ; APM Driver Version (0Eh)
- xor bx,bx ; APM BIOS (0000h)
- mov cx,0101h ; APM Driver version 1.1
- int 15h
- jnc apm0101_check
-
- mov bx, msg_notsup
- jmp error
-
-apm0101_check:
- cmp cx,0101h ; APM Connection version
- jae apm0101_ok
-
- mov bx, msg_notsup
- jmp error
-
-apm0101_ok:
- mov ax,5307h ; Set Power State (07h)
- mov bx,0001h ; All devices power managed by the APM BIOS
- mov cx,0003h ; Power state off
- int 15h
- jnc off
-
- mov bx, msg_failed
-
-error:
- mov ax,2
- int 22h
-off:
- ret
-
-msg_notpresent: db 'APM not present.',0dh,0ah,0
-msg_notsup: db 'APM 1.1+ not supported.',0dh,0ah,0
-msg_pmdisabled: db 'Power management disabled.',0dh,0ah,0
-msg_connect: db 'APM RM interface connect failed.',0dh,0ah,0
-msg_failed: db 'Power off failed.',0dh,0ah,0
diff --git a/modules/pxechain.asm b/modules/pxechain.asm
deleted file mode 100644
index 35c19691..00000000
--- a/modules/pxechain.asm
+++ /dev/null
@@ -1,558 +0,0 @@
-; "$Id: pxechain.asm,v 1.2 2007/12/16 08:15:39 jhutz Exp $"
-; -*- fundamental -*- (asm-mode sucks) vim:noet:com=\:;
-; ****************************************************************************
-;
-; pxechain.asm
-;
-; A comboot program to chain from PXELINUX to another PXE network
-; bootstrap program (NBP). This improves on PXELINUX's built-in PXE
-; chaining support by arranging for the server address and boot filename
-; reported by the PXE stack to be those from which the new NBP was
-; loaded, allowing PXELINUX to be used to select from multiple NBP's,
-; such as gPXE, another PXELINUX(*), Windows RIS, and so on.
-;
-; (*) This seems unnecessary at first, but it is very helpful when
-; selecting from among self-contained network boot images.
-;
-; Copyright (c) 2007 Carnegie Mellon University
-; Copyright (C) 1994-2007 H. Peter Anvin
-;
-; 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, Inc., 53 Temple Place Ste 330,
-; Boston MA 02111-1307, USA; either version 2 of the License, or
-; (at your option) any later version; incorporated herein by reference.
-;
-; ****************************************************************************
-
-;%define DEBUG
-;%define NO_RUN
-
- absolute 0
-pspInt20: resw 1
-pspNextP: resw 1
- resb 124
-pspCmdLen: resb 1
-pspCmdArg: resb 127
-
- section .text
- org 0x100
-
-%ifdef DEBUG
-%macro MARK 1.nolist
- mov ah,0x02
- mov dl,%1&0xff
- int 0x21
-%if (%1 >> 8) & 0xff
- mov dl,(%1 >> 8) & 0xff
- int 0x21
-%if (%1 >> 16) & 0xff
- mov dl,(%1 >> 16) & 0xff
- int 0x21
-%if (%1 >> 24) & 0xff
- mov dl,(%1 >> 24) & 0xff
- int 0x21
-%endif
-%endif
-%endif
- mov dl,' '
- int 0x21
-%endmacro
-%macro SHOWD 1.nolist
- mov al,%1
- call print_dec
- mov ah,0x02
- mov dl,' '
- int 0x21
-%endmacro
-%macro SHOWX 1.nolist
- mov bx,%1
- call print_hex
- mov ah,0x02
- mov dl,' '
- int 0x21
-%endmacro
-%else
-%macro MARK 1.nolist
-%endmacro
-%macro SHOWD 1.nolist
-%endmacro
-%macro SHOWX 1.nolist
-%endmacro
-%endif
-
-_start:
- MARK 'INIT'
-
-; There should be exactly one command-line argument, which is of the form
-; [[ipaddress]::]tftp_filename, just like filenames given to PXELINUX.
-; Too few or too many arguments is an error.
-;
-; This code is based on mangle_name in pxelinux.asm
-parse_args:
- cld
- xor cx,cx
- mov cl,[pspCmdLen]
- dec cx
- mov si,pspCmdArg+1
- and cx,cx
- je near usage ; no args is bad
- add si,cx
- dec si
- std
-.chomp: lodsb
- cmp al,' '
- loopz .chomp
- inc cx
- cld
- mov [pspCmdLen],cl
- mov si,pspCmdArg+1
- cmp word [si],'::' ; Leading ::?
- je near gotprefix
- dec cx
- jz noip
- MARK 'SCAN'
-
-.more:
- inc si
- cmp byte [si],' '
- je near usage
- cmp word [si],'::'
- je near parse_ip
- loop .more
-
-noip:
- MARK 'NOIP'
- mov ax,0x0e ; get config file name
- int 0x22
- mov si,bx
-%ifdef DEBUG
- mov ah,0x02
- mov dl,'['
- int 0x21
- mov ax,0x02
- int 0x22
- mov ah,0x02
- mov dl,']'
- int 0x21
- mov dl,' '
- int 0x21
-%endif
- push ds
- push es
- pop ds
- pop es
- push es
-.find_prefix:
- lodsb
- and al,al
- jnz .find_prefix
- dec si
-
- mov cx,si
- sub cx,bx
- MARK 'LEN'
- SHOWD cl ; assume it's <256 for debugging
- dec si
- std
-.find_slash:
- lodsb
- cmp al,'/'
- je .slash
- loop .find_slash
-.slash:
- cmp cx,127
- cld
- jna .copy_prefix
- pop ds
- jmp too_long
-
-.copy_prefix:
- SHOWD cl
- MARK 'PFX'
- mov si,bx
- mov di,tftp_filename
- mov bx,128
- sub bx,cx
- rep movsb
- pop ds
-
- mov cl,[pspCmdLen]
- mov si,pspCmdArg+1
- jmp prefix_done
-
-usage:
- xor cx,cx
- mov si,msg_usage
- jmp fail
-
-too_long:
- xor cx,cx
- mov si,msg_too_long
- jmp fail
-
-parse_ip:
- MARK 'PIP'
- mov di,si
- mov si,pspCmdArg+1
- call parse_dotquad
- jc .notdq
- cmp si,di ; is it the same place?
- jne .notdq
- mov [tftp_siaddr],eax
- jmp gotprefix
-.notdq:
- MARK 'NDQ'
- mov si,di
- mov bx,pspCmdArg+1
- mov ax,0x0010 ; DNS resolve
- int 0x22
- and eax,eax
- jz noip
- mov [tftp_siaddr],eax
-gotprefix:
- MARK 'GOTP'
- dec cx ; skip the ::
- dec cx
- inc si
- inc si
- mov di,tftp_filename
- mov bx,128
-
-prefix_done:
- SHOWD bl
- MARK 'LEFT'
-
-; SI points at the filename, plus remaining arguments,
-; CX contains their combined length.
-; DI points to where the filename should be stored
-; BX says how much space is left for the filename and NUL
-
- and cx,cx
- jz usage ; no args is bad
-.copy_filename:
- lodsb
-%ifdef DEBUG
- mov dl,al
- mov ah,0x2
- int 0x21
-%endif
- cmp al,' '
- je usage
- dec bx
- jz too_long
- stosb
- loop .copy_filename
- xor eax,eax
- stosb
-
-; get PXE cached data
- MARK 'GCI'
- mov ax,0x0009 ; call PXE stack
- mov bx,0x0071 ; PXENV_GET_CACHED_INFO
- mov di,PXECacheParms
- int 0x22
- and eax,eax
- jz .fix_siaddr
- mov cx,[gci_status]
- mov si,msg_get_cache
- jmp fail
-
-.fix_siaddr:
- mov bx,[gci_bufferseg]
- mov es,bx
- mov bx,[gci_buffer]
- mov eax,[es:bx+12] ; save our address (ciaddr)
- mov [open_ciaddr],eax ; ... in case we have to do UDP open
- mov eax,[tftp_siaddr]
- and eax,eax
- jnz .replace_addr
- MARK 'ADDR'
- mov eax,[es:bx+20] ; siaddr
- mov [tftp_siaddr],eax
- jmp .addr_done
-.replace_addr:
- mov [es:bx+20],eax
-.addr_done:
- mov si,tftp_filename ; copy the new filename...
- lea di,[es:bx+108] ; to the "cached DHCP response"
- mov cx,128
- rep movsb
- mov bx,ds ; restore es before proceeding
- mov es,bx
-
-; print out what we are doing
-%ifdef DEBUG
- mov ah,0x02 ; write character
- mov dl,0x0d ; print a CRLF first
- int 0x21
- mov dl,0x0a
- int 0x21
-%endif
- mov ax,0x0002 ; write string
- mov bx,msg_booting
- int 0x22
- mov ebx,[tftp_siaddr]
- call print_dotquad
- mov ah,0x02 ; write character
- mov dl,' '
- int 0x21
- mov ax,0x0002 ; write string
- mov bx,tftp_filename
- int 0x22
- mov ah,0x02 ; write character
- mov dl,0x0d
- int 0x21
- mov dl,0x0a
- int 0x21
-
-%ifndef NO_RUN
- mov ax,0x0009 ; call PXE stack
- mov bx,0x0031 ; PXENV_UDP_CLOSE
- mov di,PXECloseParms
- int 0x22
- mov cx,[close_status]
- mov si,msg_udp_close
- and ax,ax
- jnz fail
-
- mov ax,0x0009 ; call PXE stack
- mov bx,0x0073 ; PXENV_RESTART_TFTP
- mov di,PXERestartTFTPParms
- int 0x22
- mov cx,[tftp_status]
- mov si,msg_rst_tftp
- call fail
-
- mov ax,0x0009 ; call PXE stack
- mov bx,0x0030 ; PXENV_UDP_OPEN
- mov di,PXEOpenParms
- int 0x22
- mov cx,[open_status]
- mov si,msg_udp_open
- and ax,ax
- jnz fail
- ret
-%endif
-
-fail:
- MARK 'FAIL'
- SHOWX cs
- SHOWX ds
- SHOWX es
- SHOWX si
-%ifdef DEBUG
- mov ah,0x02 ; write character
- mov dl,0x0d ; print a CRLF first
- int 0x21
- mov dl,0x0a
- int 0x21
-%endif
- mov ax,0x0002 ; write string
- mov bx,msg_progname ; print our name
- int 0x22
- mov bx,si ; ... the error message
- int 0x22
- mov ah,0x02 ; write character
- jcxz .done
- mov dl,' ' ; ... and the error code, in []
- int 0x21
- mov dl,'['
- int 0x21
- mov bx,cx
- call print_hex
- mov ah,0x02 ; write character
- mov dl,']'
- int 0x21
-.done:
- mov dl,0x0d ; and finally a CRLF
- int 0x21
- mov dl,0x0a
- int 0x21
- ret
-
-
-; print_hex
-;
-; Take a 16-bit integer in BX and print it as 2 hex digits.
-; Destroys AX and DL.
-;
-print_hex:
- mov al,bh
- aam 16
- cmp ah,10
- jb .lt_a000
- add ah,'A'-'0'-10
-.lt_a000: add ah,'0'
- mov dl,ah
- mov ah,0x02 ; write character
- int 0x21
-
- cmp al,10
- jb .lt_a00
- add al,'A'-'0'-10
-.lt_a00: add al,'0'
- mov dl,al
- mov ah,0x02 ; write character
- int 0x21
-
- mov al,bl
- aam 16
- cmp ah,10
- jb .lt_a0
- add ah,'A'-'0'-10
-.lt_a0: add ah,'0'
- mov dl,ah
- mov ah,0x02 ; write character
- int 0x21
-
- cmp al,10
- jb .lt_a
- add al,'A'-'0'-10
-.lt_a: add al,'0'
- mov dl,al
- mov ah,0x02 ; write character
- int 0x21
- ret
-
-
-; print_dec
-;
-; Take an 8-bit integer in AL and print it in decimal.
-; Destroys AX and DL.
-;
-print_dec:
- cmp al,10 ; < 10?
- jb .lt10 ; If so, skip first 2 digits
-
- cmp al,100 ; < 100
- jb .lt100 ; If so, skip first digit
-
- aam 100
- ; Now AH = 100-digit; AL = remainder
- add ah,'0'
- mov dl,ah
- mov ah,0x02
- int 0x21
-
-.lt100:
- aam 10
- ; Now AH = 10-digit; AL = remainder
- add ah,'0'
- mov dl,ah
- mov ah,0x02
- int 0x21
-
-.lt10:
- add al,'0'
- mov dl,al
- mov ah,0x02
- int 0x21
- ret
-
-
-; print_dotquad
-;
-; Take an IP address (in network byte order) in EBX and print it
-; as a dotted quad.
-; Destroys EAX, EBX, ECX, EDX
-;
-print_dotquad:
- mov cx,3
-.octet:
- mov al,bl
- call print_dec
- jcxz .done
- mov ah,0x02
- mov dl,'.'
- int 0x21
- ror ebx,8 ; Move next char into LSB
- dec cx
- jmp .octet
-.done:
- ret
-
-
-; parse_dotquad:
-; Read a dot-quad pathname in DS:SI and output an IP
-; address in EAX, with SI pointing to the first
-; nonmatching character.
-;
-; Return CF=1 on error.
-;
-; No segment assumptions permitted.
-;
-parse_dotquad:
- push cx
- mov cx,4
- xor eax,eax
-.parseloop:
- mov ch,ah
- mov ah,al
- lodsb
- sub al,'0'
- jb .notnumeric
- cmp al,9
- ja .notnumeric
- aad ; AL += 10 * AH; AH = 0;
- xchg ah,ch
- jmp .parseloop
-.notnumeric:
- cmp al,'.'-'0'
- pushf
- mov al,ah
- mov ah,ch
- xor ch,ch
- ror eax,8
- popf
- jne .error
- loop .parseloop
- jmp .done
-.error:
- loop .realerror ; If CX := 1 then we're done
- clc
- jmp .done
-.realerror:
- stc
-.done:
- dec si ; CF unchanged!
- pop cx
- ret
-
- section .data
-msg_booting: db 'TFTP boot: ',0
-msg_progname: db 'pxechain: ',0
-msg_usage: db 'usage: pxechain.cbt [[ipaddress]::]filename',0dh,0ah,0
-msg_too_long: db 'pxechain: filename is too long (max 127)',0dh,0ah,0
-msg_get_cache: db 'PXENV_GET_CACHED_INFO',0
-msg_rst_tftp: db 'PXENV_RESTART_TFTP',0
-msg_udp_close: db 'PXENV_UDP_CLOSE',0
-msg_udp_open: db 'PXENV_UDP_OPEN',0
-
-PXECacheParms:
-gci_status: dw 0
-gci_packettype: dw 3 ; PXENV_PACKET_TYPE_CACHED_REPLY
-gci_buffersize: dw 0
-gci_buffer: dw 0
-gci_bufferseg: dw 0
-gci_bufferlim: dw 0
-
-PXERestartTFTPParms:
-tftp_status: dw 0
-tftp_filename: times 128 db 0
-tftp_bufsize: dd 0x00090000 ; available memory for NBP
-tftp_bufaddr: dd 0x00007c00 ; PXE NBP load address
-tftp_siaddr: dd 0
-tftp_giaddr: dd 0
-tftp_mcaddr: dd 0
-tftp_mcport: dw 0
-tftp_msport: dw 0
-tftp_timeout: dw 0
-tftp_reopendly: dw 0
-
-PXECloseParms:
-close_status: dw 0
-
-PXEOpenParms:
-open_status: dw 0
-open_ciaddr: dd 0
diff --git a/modules/ver.asm b/modules/ver.asm
deleted file mode 100644
index 600def02..00000000
--- a/modules/ver.asm
+++ /dev/null
@@ -1,606 +0,0 @@
-; ****************************************************************************
-;
-; ver.asm
-;
-; A COMBOOT/DOS COM program to display the version of the system
-; (Syslinux, DOS, or DRMK)
-;
-; Copyright (C) 2009-2010 Gene Cumm
-;
-; 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, Inc., 53 Temple Place Ste 330,
-; Boston MA 02111-1307, USA; either version 2 of the License, or
-; (at your option) any later version; incorporated herein by reference.
-;
-; ****************************************************************************
-
-; %define DEBUG
-
- section .text
- org 0x100
-
-_start:
- call crlf
- mov si,info_str
- call writestr
- call getdosver
- call chkprn_dosver
- jnz .end
- call chkprn_syslinux
- call crlf
-.end:
-; pop ds
- ret
-
-
-; chkprn_syslinux
-chkprn_syslinux:
-%ifdef DEBUG
- mov si,may_sysl_str
- call writestr
-%endif
- cmp eax,59530000h
- jne .end
- cmp ebx,4C530000h
- jne .end
- cmp ecx,4E490000h
- jne .end
- cmp edx,58550000h
- jne .end
-.is_syslinux:
- pushad
-%ifdef DEBUG
- mov si,is_sysl_str
- call writestr
-%endif
-.get_sysl_ver:
- mov ax,0001h
- int 22h
-; AX=0001h [2.00] Get Version
-;
-; Input: AX 0001h
-; Output: AX number of INT 22h API functions available
-; CH Syslinux major version number
-; CL Syslinux minor version number
-; DL Syslinux derivative ID (e.g. 32h = PXELINUX)
-; ES:SI Syslinux version string
-; ES:DI Syslinux copyright string
-%ifdef DEBUG
- push si
- push cs
- pop ds
- mov si,gotver_str
- call writestr
- pop si
-%endif
-
-.prn_ver_str:
- mov si,syslban_str
- call writestr
- push ds
- push es
- pop ds
- call writestr
- call crlf
- pop ds
-.prn_var:
- cmp dl,31h
- je .var_sysl
- cmp dl,32h
- je .var_pxel
- cmp dl,33h
- je .var_isol
- cmp dl,34h
- je .var_extl
- jmp .var_unk
-.var_sysl:
- mov si,sysl_str
- call writestr
- jmp .prn_lnxsp
-.var_pxel:
- mov si,pxel_str
- call writestr
- jmp .prn_lnxsp
-.var_isol:
- mov si,isol_str
- call writestr
- jmp .prn_lnxsp
-.var_extl:
- mov si,extl_str
- call writestr
-; jmp .prn_lnxsp
-.prn_lnxsp:
- mov si,linsp_str
- call writestr
- jmp .prn_ver
-.var_unk:
- mov si,unkvar_str
- call writestr
-.prn_ver:
-%ifdef DEBUG
- push si
- push cs
- pop ds
- mov si,prn_ver_str
- call writestr
- pop si
-%endif
-.prn_ver_maj:
- mov al,ch
- call writedecb
- mov dl,'.'
- call writechr_dl
-.prn_ver_min:
- mov al,cl
-; cmp al,10
-; jae .min_wri
-; mov al,'0'
-; call writechr
-; mov al,cl
-; .min_wri:
-; call writedecb
- call writedecb2
-
-.end_prn:
- popad
-.end:
- ret
-
-; chkprn_dosver Check and print DOS version;
-; Input Data from INT21 AH=30h
-; AH Major version of DOS or 0
-; AL Minor Version
-; BH DOS type
-; BL:CX 24-bit OEM serial number
-; Return
-; ZF Unset if DOS, Set if not DOS (AX=0)
-chkprn_dosver:
- and ax,ax ; cmp ax,0
- jz .end
-.is_dos:
- push eax
- push edx
- push si
-%ifdef DEBUG
- mov si,is_dos_str
- call writestr
- call crlf
- call prnreg_gp_l
- call crlf
-%endif
-.var_prn:
- cmp bh,0
- je .var_pcdos
- cmp bh,0FFh
- je .var_msdos
- cmp bh,0FDh
- je .var_freedos
- cmp bh,0DEh
- je .var_drmk
- jmp .var_unk
-.var_pcdos:
- mov si,pcdos_str
- call writestr
- jmp .var_end
-.var_msdos:
- mov si,msdos_str
- call writestr
- jmp .var_end
-.var_freedos:
- mov si,freedos_str
- call writestr
- jmp .var_end
-.var_drmk:
- mov si,drmk_str
- call writestr
- jmp .var_end
-.var_unk:
- mov si,unkdos_str
- call writestr
- mov si,spparen_str
- call writestr
- push eax
- mov al,bh
- call writehex2
- pop eax
- mov si,parensp_str
- call writestr
-; jmp .var_end
-.var_end:
- call prn_dosver_num
- call crlf
-.subver:
- pop si
- pop edx
- pop eax
- cmp bh,0FFh
- je .msdos_ver
- cmp bh,0DEh
- jne .end_ver
-.drmk_ver:
- call getprn_drmkver
-; jmp .end_ver ; DRMK returns Extended/True DOS
-.msdos_ver:
- cmp al,5
- jb .end_ver
- call getprn_msdosver
-.end_ver:
- and ax,ax ; Unset ZF
-.end:
- ret
-
-; prn_dosver_num Print the numerical DOS version
-; Input Data from INT21 AH=30h
-; AH Major version of DOS or 0
-; AL Minor Version
-; BH DOS type
-; BL:CX 24-bit OEM serial number
-prn_dosver_num:
- push eax
- push edx
- push si
- pushfd
-.vmaj_prn:
- call writedecb
-; call writehex2
- mov dl,'.'
- call writechr_dl
-.vmin_prn:
- mov al,ah
- call writedecb
-; call writehex2
-.serial: ; Skip if 0
- cmp bl,0
- jne .ser_start
- cmp cx,0
- je .end
-.ser_start:
- mov si,spparen_str
- call writestr
- mov si,zerox_str
- call writestr
-.ser_bl:
- mov al,bl
- call writehex2
-.ser_cx:
- mov ax,cx
- call writehex4
-.serial_end:
- mov si,parensp_str
- call writestr
-.end:
- popfd
- pop si
- pop edx
- pop eax
- ret
-
-; getdosver Get the DOS version
-; Return Version or 0 + SYSLINUX message
-; EAX Part 1
-; EBX Part 2
-; ECX Part 3
-; EDX Part 4
-getdosver:
- mov ecx,0
- mov edx,0
- mov ebx,0
- mov eax,3000h
- int 21h
- ret
-
-; getmsdosver Get the Extended MS-DOS version
-; Returns Version
-; EAX Part 1
-; EBX Part 2
-; ECX Part 3
-; EDX Part 4
-getmsdosver:
- mov ecx,0
- mov edx,0
- mov ebx,0
- mov eax,3306h
- int 21h
- ret
-
-; getprn_msdosver
-getprn_msdosver:
- pushad
- pushfd
- call getmsdosver
-%ifdef DEBUG
- call prnreg_gp_l
- call crlf
-%endif
- mov si,dosext_str
- call writestr
- mov eax,ebx
- mov ebx,0
- mov ecx,edx
- call prn_dosver_num
-.end:
- popfd
- popad
- ret
-
-; getdrmkver: Get the DRMK-specifc OS version
-; Returns Version
-; AX OS Version
-; DX Patch Version
-getdrmkver:
- mov ax,4452h
- int 21h
- ret
-
-; getdrmkver: Get the DRMK-specifc Kernel build info
-; Returns Kernel build info
-; AX Kernel build date in DOS 16-bit format
-; [ES:BX] Kernel private data
-getdrmkbld:
- mov ax,4458h
- int 21h
- ret
-
-; getprn_drmkver: Get/Print DRMK-specific Version info
-getprn_drmkver:
- pushad
- pushfd
-.getver:
- call getdrmkver
-.prnosver: ; "OS Version"
- mov si,osver_str
- call writestr
- mov si,zerox_str
- call writestr
-; mov ax,0
- call writehex4
- call crlf
-.prnpatchver: ; "Patch Version"
- mov si,patchver_str
- call writestr
- mov si,zerox_str
- call writestr
- mov ax,dx
- call writehex4
- call crlf
-.getbld:
- call getdrmkbld
-.prnkernbld: ; "Kernel Build Date"
- mov si,kernbld_str
- call writestr
- call writedate_ax
- call crlf
-.prnkernprvaddr:
- mov si,prvdat_str
- call writestr
- mov ax,es
- call writehex4
- mov dl,':'
- call writechr_dl
- mov ax,bx
- call writehex4
- call crlf
-%ifdef DEBUG
-.prnkernprv:
- mov di,[es:bx]
- mov ax,di
- call writehex4
- call crlf
- mov si,2
- mov cx,8
-.prnkernprv2:
- push cx
- mov cx,8
-.prnkernprv1:
- mov eax,[es:bx+si]
- call writehex8
- cmp cx,1
- jbe .prnkern0dash
- mov ax,'-'
- call writechr
-.prnkern0dash:
- add si,4
- sub di,4
- cmp di,0
- jbe .prnkernprvend
- loop .prnkernprv1
- call crlf
- pop cx
- loop .prnkernprv2
- jmp .end
-.prnkernprvend:
- pop cx
-%endif
-.end:
- popfd
- popad
- ret
-
-;writedate_ax Write a date in AX in ISO8601 big endian format
-; Input
-; AX Date in 16-bit DOS format
-; 2006-01-11
-; 0011010 0001 01011
-writedate_ax:
- pushad
- pushfd
- mov dx,ax
-%ifdef DEBUG
- call writehex4
- call crlf
-%endif
-.year:
- shr ax,9
- add ax,1980
- call writedecw
- mov al,'-'
- call writechr
- mov ax,dx
-.month:
- shr ax,5
- and ax,0Fh
-; cmp ax,10
-; jae .month_wri
-; mov cx,ax
-; mov ax,'0'
-; call writechr
-; mov ax,cx
-; .month_wri:
-; call writedecb
- call writedecb2
- mov al,'-'
- call writechr
- mov ax,dx
-.day:
- and ax,1Fh
-; cmp ax,10
-; jae .day_wri
-; mov cx,ax
-; mov ax,'0'
-; call writechr
-; mov ax,cx
-; .day_wri:
-; call writedecb
- call writedecb2
-.end:
- popfd
- popad
- ret
-
-; writechr_dl Write a character to the console saving AX
-; Input
-; DL character to write
-writechr_dl:
- push ax
- mov ah,02h
- int 21h
-.end:
- pop ax
- ret
-
-; writechr_al Write a character to the console saving AX
-; Input
-; AL character to write
-writechr:
-writechr_al:
- push dx
- mov dl,al
- call writechr_dl
-.end: pop dx
- ret
-
-; writedecb[23] Print byte as fixed width
-; Input
-; AL number to write
-writedecb3:
- pushfd
- cmp al,100
- jae .skip
- push ax
- mov ax,'0'
- call writechr
- pop ax
-.skip: popfd
-writedecb2:
- pushfd
- cmp al,10
- jae .skip
- push ax
- mov ax,'0'
- call writechr
- pop ax
-.skip: popfd
- call writedecb
- ret
-
-
-; prnreg_gp_l Dump GP registers (Long)
-prnreg_gp_l:
- push eax
- push si
- call crlf
- mov si,sp2_str
- call writestr
- mov si,eax_str
- call writestr
- call writehex8
- mov si,sp2_str
- call writestr
- mov si,ecx_str
- call writestr
- mov eax,ecx
- call writehex8
- mov si,sp2_str
- call writestr
- mov si,edx_str
- call writestr
- mov eax,edx
- call writehex8
- mov si,sp2_str
- call writestr
- mov si,ebx_str
- call writestr
- mov eax,ebx
- call writehex8
- call crlf
- pop si
- pop eax
-.end:
- ret
-
-; is_zf
-is_zf:
- push si
- jz .true
-.false:
- mov si,zero_not_str
- call writestr
- jmp .end
-.true:
- mov si,zero_is_str
- call writestr
-.end:
- pop si
- ret
-
-%include "../core/macros.inc" ; CR/LF
-%include "writestr.inc" ; String output
-%include "../core/writehex.inc" ; Hexadecimal output
-%include "../core/writedec.inc" ; Decimal output
-
- section .data
-info_str db 'Ver.com b026', CR, LF, 0
-is_dos_str db 'Found DOS', CR, LF, 0
-is_sysl_str db 'Found a Syslinux variant', CR, LF, 0
-is_drmk_str db 'Found DRMK', CR, LF, 0
-may_sysl_str db 'Maybe Syslinux variant', CR, LF, 0
-gotver_str db 'Got the version back', CR, LF, 0
-prn_ver_str db 'Printing version number', CR, LF, 0
-syslban_str db 'Syslinux banner: ',0
-sysl_str db 'SYS', 0
-pxel_str db 'PXE', 0
-isol_str db 'ISO', 0
-extl_str db 'EXT', 0
-linsp_str db 'LINUX ', 0
-unkvar_str db 'Unkown-Variant ', 0
-pcdos_str db 'PC-DOS ', 0
-msdos_str db 'MS-DOS ', 0
-freedos_str db 'FreeDOS ', 0
-unkdos_str db 'Unknown-DOS ', 0
-drmk_str db 'DRMK ', 0
-dosext_str db ' Extended DOS version: ', 0
-osver_str db ' OS Version: ', 0
-patchver_str db ' Patch Version: ', 0
-kernbld_str db ' Kernel Build Date: ', 0
-prvdat_str db ' Private Data Ptr: ', 0
-spparen_str db ' (', 0
-zerox_str db '0x', 0
-parensp_str db ') ', 0
-eax_str db 'EAX=', 0
-ebx_str db 'EBX=', 0
-ecx_str db 'ECX=', 0
-edx_str db 'EDX=', 0
-sp2_str db ' ', 0
-zero_not_str db ' NOT_Zero ',0
-zero_is_str db ' IS_Zero ',0
diff --git a/modules/writestr.inc b/modules/writestr.inc
deleted file mode 100644
index 9c11b320..00000000
--- a/modules/writestr.inc
+++ /dev/null
@@ -1,47 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
-;;
-;; 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, Inc., 53 Temple Place Ste 330,
-;; Boston MA 02111-1307, USA; either version 2 of the License, or
-;; (at your option) any later version; incorporated herein by reference.
-;;
-;; -----------------------------------------------------------------------
-
-;;
-;; writestr.inc
-;;
-;; Code to write a simple string.
-;;
-
-;
-; crlf: Print a newline
-;
-crlf: push ax
- mov al,CR
- call writechr
- mov al,LF
- call writechr
- pop ax
- ret
-
-;
-; writestr: write a null-terminated string to the console, saving
-; registers on entry.
-;
-; Note: writestr_early and writestr are distinct in
-; SYSLINUX and EXTLINUX, but not PXELINUX and ISOLINUX
-;
-writestr:
- pushfd
- pushad
-.top: lodsb
- and al,al
- jz .end
- call writechr
- jmp short .top
-.end: popad
- popfd
- ret