From 9a2bcc0b92b392f1f21cd26927515e4d49bc128e Mon Sep 17 00:00:00 2001 From: lefranc Date: Fri, 1 Aug 2008 09:25:43 +0000 Subject: - import of buildroot original sources (20080729 version) git-svn-id: svn+ssh://pessac/svn/cesar/trunk@2704 017c9cb6-072f-447c-8318-d5b54f68fe89 --- .../buildroot/toolchain/kernel-headers/Config.in | 138 + .../linux-2.6.20.4-ipmisensors-20070314-1214.patch | 1914 ++ ...ux-2.6.21.5-007-ipmisensors-20070314-1214.patch | 1914 ++ ...ux-2.6.22.1-007-ipmisensors-20070314-1214.patch | 1914 ++ ...ux-2.6.22.9-007-ipmisensors-20070314-1214.patch | 1914 ++ .../kernel-headers/kernel-headers-new.makefile | 91 + .../kernel-headers-old-versions.makefile | 103 + .../kernel-headers/kernel-headers-old.makefile | 87 + .../toolchain/kernel-headers/kernel-headers.mk | 48 + .../linux-2.6.20.4-dwmw2-combined.01.diff | 460 + .../linux-2.6.21.5-001-add-linkage-header.patch | 18 + ...-006-wait-for-async-scanned-block-devices.patch | 55 + .../kernel-headers/linux-2.6.23-nios2nommu.patch | 26567 ++++++++++++++++++ .../linux-2.6.25.9-export-linux-aout.patch | 24 + ...ibc-headers-2.6.11-nios2nommu.patch.conditional | 13527 ++++++++++ .../linux-libc-headers-2.6.11.0-mips-nptl.patch | 75 + .../linux-libc-headers-2.6.11.0.patch | 18 + .../linux-libc-headers-2.6.12.0-arm-eabi.patch | 166 + ...x-libc-headers-2.6.12.0-config-base-small.patch | 30 + .../linux-libc-headers-2.6.12.0-i2c_msg.patch | 12 + .../linux-libc-headers-2.6.12.0-mips-nptl.patch | 90 + .../linux-libc-headers-2.6.8-cleanup.patch | 8153 ++++++ ...libc-headers-2.6.9-nios2nommu.patch.conditional | 12925 +++++++++ .../lzma/linux-2.6.21.5-001-lzma-vmlinuz.00.patch | 27017 +++++++++++++++++++ .../lzma/linux-2.6.21.5-002-lzma-vmlinuz.01.patch | 54 + .../lzma/linux-2.6.22.1-001-lzma-vmlinuz.00.patch | 26856 ++++++++++++++++++ .../lzma/linux-2.6.22.1-002-lzma-vmlinuz.01.patch | 54 + .../lzma/linux-2.6.22.1-003-lzma-vmlinuz.patch | 44 + 28 files changed, 124268 insertions(+) create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/Config.in create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.20.4-ipmisensors-20070314-1214.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.21.5-007-ipmisensors-20070314-1214.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.22.1-007-ipmisensors-20070314-1214.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.22.9-007-ipmisensors-20070314-1214.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-new.makefile create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-old-versions.makefile create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-old.makefile create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/kernel-headers.mk create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.20.4-dwmw2-combined.01.diff create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.21.5-001-add-linkage-header.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.21.5-006-wait-for-async-scanned-block-devices.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.23-nios2nommu.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.25.9-export-linux-aout.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11-nios2nommu.patch.conditional create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11.0-mips-nptl.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11.0.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-arm-eabi.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-config-base-small.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-i2c_msg.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-mips-nptl.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.8-cleanup.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.9-nios2nommu.patch.conditional create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.21.5-001-lzma-vmlinuz.00.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.21.5-002-lzma-vmlinuz.01.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-001-lzma-vmlinuz.00.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-002-lzma-vmlinuz.01.patch create mode 100644 cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-003-lzma-vmlinuz.patch (limited to 'cleopatre/buildroot/toolchain/kernel-headers') diff --git a/cleopatre/buildroot/toolchain/kernel-headers/Config.in b/cleopatre/buildroot/toolchain/kernel-headers/Config.in new file mode 100644 index 0000000000..c512ae22bb --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/Config.in @@ -0,0 +1,138 @@ +# Choose the kernel headers to use for kernel-headers target. This is +# ignored if you are building your own kernel or using the system kernel. +# + +comment "Kernel Header Options" + +choice + prompt "Kernel Headers" + default BR2_KERNEL_HEADERS_2_6_25 + + help + Select the version of kernel header files you wish to use. + You must select the correct set of header files to match + the kernel you intend to use on your target system. + + For the snapshot, you have to provide the + linux-2.6.tar.bz2 tarball in your download dir. + + config BR2_KERNEL_HEADERS_2_4_25 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.4.25 kernel headers" + + config BR2_KERNEL_HEADERS_2_4_27 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.4.27 kernel headers" + + config BR2_KERNEL_HEADERS_2_4_29 + depends on !BR2_avr32 && !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.4.29 kernel headers" + + config BR2_KERNEL_HEADERS_2_4_31 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.4.31 kernel headers" + + config BR2_KERNEL_HEADERS_2_6_9 + depends on !BR2_avr32 && BR2_DEPRECATED + bool "Linux 2.6.9 kernel headers" + + config BR2_KERNEL_HEADERS_2_6_11 + depends on !BR2_avr32 && BR2_DEPRECATED + bool "Linux 2.6.11 kernel headers" + + config BR2_KERNEL_HEADERS_2_6_12 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.6.12 kernel headers" + + config BR2_KERNEL_HEADERS_2_6_20_4 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.6.20.4 kernel headers" + + config BR2_KERNEL_HEADERS_2_6_20 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.6.20.x kernel headers" + + config BR2_KERNEL_HEADERS_2_6_21_5 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.6.21.5 kernel headers" + + config BR2_KERNEL_HEADERS_2_6_21 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.6.21.x kernel headers" + + config BR2_KERNEL_HEADERS_2_6_22_1 + depends on !BR2_avr32 && !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.6.22.1 kernel headers" + + config BR2_KERNEL_HEADERS_2_6_22_10 + depends on !BR2_nios2 && BR2_DEPRECATED + bool "Linux 2.6.22.10 kernel headers" + + config BR2_KERNEL_HEADERS_2_6_22 + depends on BR2_DEPRECATED + bool "Linux 2.6.22.x kernel headers" + + config BR2_KERNEL_HEADERS_2_6_23 + depends on BR2_DEPRECATED + bool "Linux 2.6.23.x kernel headers" + + config BR2_KERNEL_HEADERS_2_6_24 + depends on BR2_RECENT + bool "Linux 2.6.24.x kernel headers" + + config BR2_KERNEL_HEADERS_2_6_25 + bool "Linux 2.6.25.x kernel headers" + + config BR2_KERNEL_HEADERS_SNAP + bool "Linux 2.6 snapshot" + +endchoice + +config BR2_KERNEL_HEADERS_IPMI + bool "use ipmi kernel patches" + depends on BR2_KERNEL_HEADERS_2_6_20_4 || BR2_KERNEL_HEADERS_2_6_21_5 || BR2_KERNEL_HEADERS_2_6_22_1 + help + Apply patches which add IPMI sensor support. + +config BR2_KERNEL_HEADERS_LZMA + bool "use lzma initramfs kernel patches" + depends on BR2_KERNEL_HEADERS_2_6_21_5 || BR2_KERNEL_HEADERS_2_6_22_1 + help + Apply patches which allow for lzma compressed + initramfs filesystems. This requires the lzma + program in your development environment. + +config BR2_KERNEL_HEADERS_RT + bool "use realtime (-rt) kernel patches" + depends on BR2_KERNEL_HEADERS_2_6_21_5 || BR2_KERNEL_HEADERS_2_6_22_1 + help + Apply Ingo's realtime extensions to linux + +config BR2_KERNEL_HEADERS_PATCH_DIR + bool "Add additional headers from $(KERNEL_HEADERS_PATCH_DIR)" + depends on BR2_KERNEL_HEADERS_2_6_20_4 || BR2_KERNEL_HEADERS_2_6_21_5 || BR2_KERNEL_HEADERS_2_6_22_1 || BR2_KERNEL_HEADERS_2_6_22_10 + help + Apply additional kernel patches defined by KERNEL_HEADERS_PATCH_DIR + in your board directory. + +config BR2_DEFAULT_KERNEL_HEADERS + string + default "2.4.25" if BR2_KERNEL_HEADERS_2_4_25 + default "2.4.27" if BR2_KERNEL_HEADERS_2_4_27 + default "2.4.29" if BR2_KERNEL_HEADERS_2_4_29 + default "2.4.31" if BR2_KERNEL_HEADERS_2_4_31 + default "2.6.9" if BR2_KERNEL_HEADERS_2_6_9 + default "2.6.11" if BR2_KERNEL_HEADERS_2_6_11 + default "2.6.12" if BR2_KERNEL_HEADERS_2_6_12 + default "2.6.20.4" if BR2_KERNEL_HEADERS_2_6_20_4 + default "2.6.20.20" if BR2_KERNEL_HEADERS_2_6_20 + default "2.6.21.5" if BR2_KERNEL_HEADERS_2_6_21_5 + default "2.6.21.7" if BR2_KERNEL_HEADERS_2_6_21 + default "2.6.22.1" if BR2_KERNEL_HEADERS_2_6_22_1 + default "2.6.22.10" if BR2_KERNEL_HEADERS_2_6_22_10 + default "2.6.22.10" if BR2_KERNEL_HEADERS_2_6_22 + default "2.6.23" if BR2_KERNEL_HEADERS_2_6_23 + default "2.6.24.7" if BR2_KERNEL_HEADERS_2_6_24 + default "2.6.25.10" if BR2_KERNEL_HEADERS_2_6_25 + default "2.6" if BR2_KERNEL_HEADERS_SNAP + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.20.4-ipmisensors-20070314-1214.patch b/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.20.4-ipmisensors-20070314-1214.patch new file mode 100644 index 0000000000..aca57c37b0 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.20.4-ipmisensors-20070314-1214.patch @@ -0,0 +1,1914 @@ +diff -rduNp linux-2.6.20.3.orig/drivers/char/ipmi/ipmi_msghandler.c linux-2.6.20.3/drivers/char/ipmi/ipmi_msghandler.c +--- linux-2.6.20.3.orig/drivers/char/ipmi/ipmi_msghandler.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/drivers/char/ipmi/ipmi_msghandler.c 2007-03-14 14:23:02.000000000 +0100 +@@ -1954,6 +1954,24 @@ static void remove_proc_entries(ipmi_smi + #endif /* CONFIG_PROC_FS */ + } + ++/* ++ * Retrieves the bmc_device struct for a given ipmi interface number (or NULL if none). ++ */ ++struct device *ipmi_get_bmcdevice(int if_num) ++{ ++ ipmi_smi_t intf; ++ mutex_lock(&ipmi_interfaces_mutex); ++ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { ++ if (intf->intf_num == if_num){ ++ mutex_unlock(&ipmi_interfaces_mutex); ++ return &intf->bmc->dev->dev; ++ } ++ } ++ mutex_unlock(&ipmi_interfaces_mutex); ++ ++ return NULL; ++} ++ + static int __find_bmc_guid(struct device *dev, void *data) + { + unsigned char *id = data; +@@ -4183,3 +4201,4 @@ EXPORT_SYMBOL(ipmi_get_my_LUN); + EXPORT_SYMBOL(ipmi_smi_add_proc_entry); + EXPORT_SYMBOL(ipmi_user_set_run_to_completion); + EXPORT_SYMBOL(ipmi_free_recv_msg); ++EXPORT_SYMBOL(ipmi_get_bmcdevice); +diff -rduNp linux-2.6.20.3.orig/drivers/hwmon/Kconfig linux-2.6.20.3/drivers/hwmon/Kconfig +--- linux-2.6.20.3.orig/drivers/hwmon/Kconfig 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/drivers/hwmon/Kconfig 2007-03-14 14:23:02.000000000 +0100 +@@ -218,6 +218,16 @@ config SENSORS_GL520SM + This driver can also be built as a module. If so, the module + will be called gl520sm. + ++config SENSORS_IPMI ++ tristate "IPMI Hardware Monitoring Support" ++ depends on HWMON && IPMI_HANDLER && EXPERIMENTAL ++ help ++ If you say yes here you get support for sensors monitored by ++ an IPMI baseboard management controller (BMC). ++ ++ This driver can also be built as a module. If so, the module ++ will be called ipmisensors. ++ + config SENSORS_IT87 + tristate "ITE IT87xx and compatibles" + depends on HWMON && I2C +diff -rduNp linux-2.6.20.3.orig/drivers/hwmon/Makefile linux-2.6.20.3/drivers/hwmon/Makefile +--- linux-2.6.20.3.orig/drivers/hwmon/Makefile 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/drivers/hwmon/Makefile 2007-03-14 14:23:02.000000000 +0100 +@@ -28,6 +28,7 @@ obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o + obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o + obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o + obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o ++obj-$(CONFIG_SENSORS_IPMI) += ipmisensors.o + obj-$(CONFIG_SENSORS_IT87) += it87.o + obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o + obj-$(CONFIG_SENSORS_LM63) += lm63.o +diff -rduNp linux-2.6.20.3.orig/drivers/hwmon/ipmisensors.c linux-2.6.20.3/drivers/hwmon/ipmisensors.c +--- linux-2.6.20.3.orig/drivers/hwmon/ipmisensors.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.20.3/drivers/hwmon/ipmisensors.c 2007-03-14 14:44:42.000000000 +0100 +@@ -0,0 +1,1552 @@ ++/* ++ * ipmisensors.c - lm-sensors/hwmon interface to IPMI sensors. ++ * ++ * Copyright (C) 2004-2006 Yani Ioannou ++ * ++ * Adapted from bmcsensors (lm-sensors for linux 2.4) ++ * bmcsensors (C) Mark D. Studebaker ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ipmisensors.h" ++ ++/****** Function Prototypes ******/ ++static void ipmisensors_send_message(struct ipmisensors_bmc_data *bmc, ++ long msgid, struct kernel_ipmi_msg *msg); ++static void ipmisensors_reserve_sdr(struct ipmisensors_bmc_data *bmc); ++static void ipmisensors_get_sdr(struct ipmisensors_bmc_data *bmc, u16 res_id, ++ u16 record, u8 offset); ++static void ipmisensors_set_sensor_threshold(struct ipmisensors_bmc_data *bmc, ++ u8 number, int value, ++ int lim_index); ++static void ipmisensors_get_reading(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr); ++static void ipmisensors_msg_handler(struct ipmi_recv_msg *msg, ++ void *user_msg_data); ++static int ipmisensors_intf_registered(int ipmi_intf); ++static int ipmisensors_bmc_registered(struct device *bmc); ++static void ipmisensors_register_bmc(int ipmi_intf, struct ipmi_addr *address); ++static void ipmisensors_unregister_bmc(int ipmi_intf); ++static void ipmisensors_unregister_bmc_all(void); ++static void ipmisensors_new_smi(int if_num, struct device *dev); ++static void ipmisensors_smi_gone(int if_num); ++static void ipmisensors_update_bmc(struct work_struct *); ++static void ipmisensors_cleanup(void); ++ ++/****** Static Vars ******/ ++ ++/* set when module is being removed */ ++static int cleanup = 0; ++ ++/* ipmisensors driver data */ ++static struct ipmisensors_data driver_data = { ++ .driver_name = "bmc", ++ .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data), ++ .interfaces = 0, ++ .smi_watcher = { ++ .owner = THIS_MODULE, ++ .new_smi = ipmisensors_new_smi, ++ .smi_gone = ipmisensors_smi_gone, ++ }, ++ .ipmi_hndlrs = { ++ .ipmi_recv_hndl = ipmisensors_msg_handler, ++ }, ++}; ++ ++/* sensor refresh workqueue */ ++static struct workqueue_struct *ipmisensors_workqueue; ++ ++/****** SDR List Functions ******/ ++/** ++ * Creates a new sdrdata struct, or returns NULL if insufficient memory. ++ */ ++static struct sdrdata *ipmisensors_new_sdr(void) ++{ ++ struct sdrdata *sdr; ++ ++ sdr = kmem_cache_alloc(driver_data.sdrdata_cache, GFP_ATOMIC); ++ if (sdr) { ++ memset(sdr, 0, sizeof(struct sdrdata)); ++ } else { ++ printk(KERN_ERR ++ "ipmisensors: Couldn't allocate memory for new SDR\n"); ++ } ++ ++ return sdr; ++} ++ ++/** ++ * Adds the given sdrdata struct to the given bmc's SDR list. ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static inline void ipmisensors_add_sdr(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr) ++{ ++ list_add(&sdr->list, &bmc->sdrs); ++ printk(KERN_DEBUG ++ "ipmisensors: SDR %d: type 0x%02x (%s)\n", ++ bmc->sdr_count, sdr->stype, sdr->id); ++ bmc->sdr_count++; ++} ++ ++/** ++ * Cleanup the sdr list for the given BMC. ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static void ipmisensors_sdr_cleanup(struct ipmisensors_bmc_data *bmc) ++{ ++ struct sdrdata *cursor, *next; ++ ++ /* find and free each sdr data struct */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ device_remove_file(bmc->dev, &cursor->attr.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_min.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_max.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_label.dev_attr); ++ ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ ++ list_del(&cursor->list); ++ kmem_cache_free(driver_data.sdrdata_cache, cursor); ++ } ++} ++ ++/* worker function for workqueue ipmisensors_workqueue */ ++static void ipmisensors_update_bmc(struct work_struct *work) ++{ ++ struct ipmisensors_bmc_data *bmc = container_of(work, struct ipmisensors_bmc_data, update_work.work); ++ ++ /* don't start an update cycle if one already in progress */ ++ if (bmc->state != STATE_READING) { ++ struct sdrdata *cursor, *next; ++ bmc->state = STATE_READING; ++ printk(KERN_DEBUG "ipmisensors: starting update\n"); ++ ++ /* init semaphore to 1 for update cycle */ ++ sema_init(&bmc->update_semaphore, 1); ++ ++ /* update each sdr reading */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ ipmisensors_get_reading(bmc, cursor); ++ } ++ } ++ ++ /* wait for readings (need timeout?) */ ++ down_interruptible(&bmc->update_semaphore); ++ ++ printk(KERN_DEBUG "ipmisensors: update complete\n"); ++ ++ bmc->state = STATE_DONE; ++ ++ /* if the module isn't cleaning up, schedule another update */ ++ if (!cleanup) ++ queue_delayed_work(ipmisensors_workqueue, &bmc->update_work, ++ bmc->update_period * HZ); ++} ++ ++/****** IPMI Message Sending ******/ ++ ++/** ++ * Send a message to the IPMI BMC ++ * ++ * @bmc: the bmc to send the message to. ++ * @msgid: the message id to use. ++ * @msg: the ipmi message structure. ++ */ ++static void ipmisensors_send_message(struct ipmisensors_bmc_data *bmc, ++ long msgid, struct kernel_ipmi_msg *msg) ++{ ++ if (msg->data == NULL) ++ printk(KERN_DEBUG "ipmisensors: Send 0x%x\n", msg->cmd); ++ else ++ printk(KERN_DEBUG "ipmisensors: Send 0x%x 0x%x 0x%x\n", ++ msg->cmd, msg->data[0], msg->data[1]); ++ ++ /* This should be ipmi_request, but Corey had to remove ++ * that due to it being unused at the moment, as soon as ++ * this makes it into the kernel we should request it be re-instated. ++ */ ++ ipmi_request_settime(bmc->user, &bmc->address, msgid, msg, bmc, 0, ++ -1, 0); ++} ++ ++/** ++ * Compose and send a "reserve SDR" message ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static void ipmisensors_reserve_sdr(struct ipmisensors_bmc_data *bmc) ++{ ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_RESERVE_SDR; ++ bmc->tx_message.data_len = 0; ++ bmc->tx_message.data = NULL; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Componse and send a "get SDR" message ++ * ++ * @bmc: the bmc to send the message to. ++ * @res_id: ++ * @record: ++ * @offset: ++ */ ++static void ipmisensors_get_sdr(struct ipmisensors_bmc_data *bmc, u16 res_id, ++ u16 record, u8 offset) ++{ ++ printk(KERN_DEBUG "ipmisensors: Get SDR 0x%x 0x%x 0x%x\n", ++ res_id, record, offset); ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_GET_SDR; ++ bmc->tx_message.data_len = 6; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = res_id & 0xff; ++ bmc->tx_msg_data[1] = res_id >> 8; ++ bmc->tx_msg_data[2] = record & 0xff; ++ bmc->tx_msg_data[3] = record >> 8; ++ bmc->tx_msg_data[4] = offset; ++ bmc->tx_msg_data[5] = bmc->ipmi_sdr_partial_size; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Compose and send a "set sensor threshold" message ++ * ++ * @bmc: the bmc to send the message to. ++ * @id: the ipmi id number of the sensor. ++ * @value: the new value for the threshold. ++ * @lim_index: the index in the lim[] array for which this value applies. ++ */ ++static void ipmisensors_set_sensor_threshold(struct ipmisensors_bmc_data *bmc, ++ u8 number, int value, ++ int lim_index) ++{ ++ int i; ++ ++ printk(KERN_DEBUG "ipmisensors: Set SDR Threshold %d %d %d\n", ++ number, value, lim_index); ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_SET_SENSOR_THRESHOLD; ++ bmc->tx_message.data_len = 8; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = number & 0xff; ++ bmc->tx_msg_data[1] = 0x01 << lim_index; ++ ++ if (lim_index > 5 || lim_index < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Error - ipmisensors_set_sensor_threshold given invalid lim_index\n"); ++ return; ++ } ++ ++ for (i = 2; i < 8; i++) ++ bmc->tx_msg_data[i] = 0x00; ++ ++ bmc->tx_msg_data[lim_index] = value && 0xff; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Compose and send a "get sensor reading" message for the given sdr. ++ * ++ * @bmc: the bmc to send the message to. ++ * @sdr: the sdr of the sensor to get the reading for. ++ */ ++static void ipmisensors_get_reading(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr) ++{ ++ bmc->tx_message.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST; ++ bmc->tx_message.cmd = IPMI_GET_SENSOR_STATE_READING; ++ bmc->tx_message.data_len = 1; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = sdr->number; ++ bmc->current_sdr = sdr; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++ down_interruptible(&bmc->update_semaphore); ++} ++ ++/****** IPMI Message Receiving ******/ ++ ++/** ++ * Process an sensor reading response message. ++ * ++ * @bmc: the bmc the message is from ++ * @msg: the IPMI SDR response message ++ */ ++static void ipmisensors_rcv_reading_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ struct sdrdata *sdr = bmc->current_sdr; ++ ++ if (sdr == NULL) { ++ printk(KERN_ERR ++ "ipmisensors: Error ipmisensors_rcv_reading with NULL sdr\n"); ++ return; ++ } ++ ++ sdr->reading = msg->data[1]; ++ sdr->status = msg->data[2]; ++ sdr->thresholds = msg->data[3]; ++ ++ printk(KERN_DEBUG "ipmisensors: sensor %d (type %d) reading %d\n", ++ sdr->number, sdr->stype, msg->data[1]); ++ ++ up(&bmc->update_semaphore); ++} ++ ++/** ++ * Unpack based on string type, convert to normal, null terminate. ++ */ ++static void ipmisensors_sprintf(u8 * to, u8 * from, u8 type, u8 length) ++{ ++ static const u8 *bcdplus = "0123456789 -.:,_"; ++ int i; ++ ++ switch (type) { ++ case 0: /* unicode */ ++ for (i = 0; i < length; i++) ++ *to++ = (*from++ & 0x7f); ++ *to = 0; ++ break; ++ case 1: /* BCD Plus */ ++ for (i = 0; i < length; i++) ++ *to++ = bcdplus[*from++ & 0x0f]; ++ *to = 0; ++ break; ++ case 2: /* packed ascii *//* if not a mult. of 3 this will run over */ ++ for (i = 0; i < length; i += 3) { ++ *to++ = *from & 0x3f; ++ *to++ = *from >> 6 | ((*(from+1) & 0xf) << 2); ++ from++; ++ *to++ = *from >> 4 | ((*(from+1) & 0x3) << 4); ++ from++; ++ *to++ = (*from++ >> 2) & 0x3f; ++ } ++ *to = 0; ++ break; ++ case 3: /* normal */ ++ if (length > 1) ++ memcpy(to, from, length); ++ to[length] = 0; ++ break; ++ } ++} ++ ++/* IPMI V1.5 Section 30 */ ++static const int exps[] = ++ { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; ++ ++/* Return 0 for fan, 2 for temp, 3 for voltage ++ We could make it variable based on the accuracy (= log10(m * 10**k2)); ++ this would work for /proc output, however libsensors resolution ++ is statically set in lib/chips.c */ ++static int decplaces(struct sdrdata *sd) ++{ ++ switch (sd->stype) { ++ case STYPE_TEMP: ++ return 2; ++ case STYPE_CURR: ++ case STYPE_VOLT: ++ return 3; ++ case STYPE_FAN: ++ default: ++ return 0; ++ } ++} ++ ++/* convert a raw value to a reading. IMPI V1.5 Section 30 */ ++static long conv_val(int value, struct sdrdata *sd) ++{ ++ u8 k1, k2; ++ long r; ++ ++ r = value * sd->m; ++ k1 = sd->k & 0x0f; ++ k2 = sd->k >> 4; ++ if (k1 < 8) ++ r += sd->b * exps[k1]; ++ else ++ r += sd->b / exps[16 - k1]; ++ r *= exps[decplaces(sd)]; ++ if (k2 < 8) { ++ if (sd->linear != 7) ++ r *= exps[k2]; ++ else ++ /* this will always truncate to 0: r = 1 / (exps[k2] * r); */ ++ r = 0; ++ } else { ++ if (sd->linear != 7) ++ r /= exps[16 - k2]; ++ else { ++ if (r != 0) ++ /* 1 / x * 10 ** (-m) == 10 ** m / x */ ++ r = exps[16 - k2] / r; ++ else ++ r = 0; ++ } ++ } ++ ++ return r; ++} ++ ++static const char *threshold_text[] = { ++ "upper non-recoverable threshold", ++ "upper critical threshold", ++ "upper non-critical threshold", ++ "lower non-recoverable threshold", ++ "lower critical threshold", ++ "lower non-critical threshold", ++ "positive-going hysteresis", ++ "negative-going hysteresis" /* unused */ ++}; ++ ++/* select two out of the 8 possible readable thresholds, and place indexes into the limits ++ array into lim1 and lim2. Set writable flags */ ++static void ipmisensors_select_thresholds(struct sdrdata *sd) ++{ ++ u8 capab = sd->capab; ++ u16 mask = sd->thresh_mask; ++ int tmp; ++ ++ sd->lim1 = -1; ++ sd->lim2 = -1; ++ sd->lim1_write = 0; ++ sd->lim2_write = 0; ++ ++ if (((capab & 0x0c) == 0x04) || /* readable thresholds ? */ ++ ((capab & 0x0c) == 0x08)) { ++ /* select upper threshold */ ++ if (mask & 0x10) { /* upper crit */ ++ sd->lim1 = 1; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x1000)) ++ sd->lim1_write = 1; ++ } else if (mask & 0x20) { /* upper non-recov */ ++ sd->lim1 = 0; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x2000)) ++ sd->lim1_write = 1; ++ } else if (mask & 0x08) { /* upper non-crit */ ++ sd->lim1 = 2; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0800)) ++ sd->lim1_write = 1; ++ } ++ ++ /* select lower threshold */ ++ if ((((capab & 0x30) == 0x10) || /* readable ? */ ++ ((capab & 0x30) == 0x20)) && /* pos hyst */ ++ sd->stype == STYPE_TEMP) ++ sd->lim2 = 6; ++ else if (mask & 0x02) { /* lower crit */ ++ sd->lim2 = 4; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0200)) ++ sd->lim2_write = 1; ++ } else if (mask & 0x04) { /* lower non-recov */ ++ sd->lim2 = 3; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0400)) ++ sd->lim2_write = 1; ++ } else if (mask & 0x01) { /* lower non-crit */ ++ sd->lim2 = 5; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0100)) ++ sd->lim2_write = 1; ++ } ++ } ++ ++ /* swap lim1/lim2 if m < 0 or function is 1/x (but not both!) */ ++ if ((sd->m < 0 && sd->linear != 7) || (sd->m >= 0 && sd->linear == 7)) { ++ tmp = sd->lim1; ++ sd->lim1 = sd->lim2; ++ sd->lim2 = tmp; ++ } ++ ++ if (sd->lim1 >= 0) ++ printk(KERN_INFO "ipmisensors: using %s for upper limit\n", ++ threshold_text[sd->lim1]); ++ else ++ printk(KERN_DEBUG "ipmisensors: no readable upper limit\n"); ++ ++ if (sd->lim2 >= 0) ++ printk(KERN_INFO "ipmisensors: using %s for lower limit\n", ++ threshold_text[sd->lim2]); ++ else ++ printk(KERN_DEBUG "ipmisensors: no readable lower limit\n"); ++} ++ ++/************* sysfs callback functions *********/ ++static ssize_t show_update_period(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ ++ return snprintf(buf, 20, "%d\n", aattr->bmc->update_period); ++} ++ ++static ssize_t store_update_period(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ ++ aattr->bmc->update_period = simple_strtoul(buf, NULL, 10);; ++ return count; ++}; ++ ++static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ return snprintf(buf, 20, "%ld\n", ++ conv_val(sattr->sdr->reading, sattr->sdr)); ++} ++ ++static ssize_t show_sensor_max(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ long max = 0; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ if (sattr->sdr->lim1 >= 0) ++ max = conv_val(sattr->sdr->limits[sattr->sdr->lim1], ++ sattr->sdr); ++ return snprintf(buf, 20, "%ld\n", max); ++} ++ ++static ssize_t show_sensor_min(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ long min = 0; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ if (sattr->sdr->lim2 >= 0) ++ min = conv_val(sattr->sdr->limits[sattr->sdr->lim2], ++ sattr->sdr); ++ return snprintf(buf, 20, "%ld\n", min); ++}; ++ ++static ssize_t show_sensor_label(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ u8 label[SDR_MAX_UNPACKED_ID_LENGTH]; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ ipmisensors_sprintf(label, sattr->sdr->id, sattr->sdr->string_type, ++ sattr->sdr->id_length); ++ return snprintf(buf, 20, "%s\n", label); ++}; ++ ++static ssize_t store_sensor_max(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ long val = simple_strtoul(buf, NULL, 10); ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ printk(KERN_DEBUG "ipmisensors: set max on sensor #%d to %ld", ++ sattr->sdr->number, val); ++ ipmisensors_set_sensor_threshold(sattr->sdr->bmc, sattr->sdr->number, ++ val, sattr->sdr->lim1); ++ return count; ++}; ++ ++static ssize_t store_sensor_min(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ long val = simple_strtoul(buf, NULL, 10); ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ printk(KERN_DEBUG "ipmisensors: set min on sensor #%d to %ld", ++ sattr->sdr->number, val); ++ ipmisensors_set_sensor_threshold(sattr->sdr->bmc, sattr->sdr->number, ++ val, sattr->sdr->lim2); ++ return count; ++}; ++ ++static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ return snprintf(buf, 20, "%d\n", aattr->bmc->alarms); ++}; ++ ++static ssize_t show_name(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ return snprintf(buf, 20, "%s\n", driver_data.driver_name); ++}; ++ ++/* work function to build the sysfs entries using the ipmi sdrs */ ++static void ipmisensors_build_sysfs(struct work_struct *work) ++{ ++ int temps = 0, volts = 0, currs = 0, fans = 0; ++ struct sdrdata *cursor, *next; ++ struct ipmisensors_bmc_data *bmc = container_of(work, struct ipmisensors_bmc_data, sysfs_work); ++ ++ /* find and create entries for each sdr data struct */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; ++ ++ cursor->attr_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ cursor->attr_max_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ cursor->attr_min_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ ++ if (cursor->id_length > 0) { ++ cursor->attr_label_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ ++ if (cursor->attr_label_name == NULL) { ++ printk(KERN_INFO ++ "ipmisensors: Out of memory (kmalloc failed)"); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ return; ++ } ++ } ++ ++ if (cursor->attr_name == NULL || cursor->attr_max_name == NULL ++ || cursor->attr_min_name == NULL ++ || cursor->attr_label_name == NULL) { ++ printk(KERN_INFO ++ "ipmisensors: Out of memory (kmalloc failed)"); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ return; ++ } ++ ++ switch (cursor->stype) { ++ case (STYPE_TEMP): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "temp%d_input", ++temps); ++ /* create min, max attributes */ ++ snprintf(cursor->attr_max_name, MAX_FILENAME_LENGTH, ++ "temp%d_max", temps); ++ snprintf(cursor->attr_min_name, MAX_FILENAME_LENGTH, ++ "temp%d_min", temps); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "temp%d_label", temps); ++ break; ++ case (STYPE_VOLT): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "in%d_input", ++volts); ++ /* create min, max attributes */ ++ snprintf(cursor->attr_max_name, MAX_FILENAME_LENGTH, ++ "in%d_max", volts); ++ snprintf(cursor->attr_min_name, MAX_FILENAME_LENGTH, ++ "in%d_min", volts); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "in%d_label", volts); ++ break; ++ case (STYPE_CURR): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "curr%d_input", ++currs); ++ /* create min, max attributes */ ++ sprintf(cursor->attr_max_name, "curr%d_max", currs); ++ sprintf(cursor->attr_min_name, "curr%d_min", currs); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "curr%d_label", currs); ++ break; ++ case (STYPE_FAN): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "fan%d_input", ++fans); ++ /* create min, max attributes */ ++ sprintf(cursor->attr_max_name, "fan%d_max", fans); ++ sprintf(cursor->attr_min_name, "fan%d_min", fans); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "fan%d_label", fans); ++ break; ++ default: ++ printk(KERN_INFO "ipmisensors: unkown sensor type\n"); ++ continue; ++ } ++ ++ cursor->attr.dev_attr.attr.name = cursor->attr_name; ++ cursor->attr.dev_attr.attr.mode = S_IRUGO; ++ cursor->attr.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr.dev_attr.show = show_sensor; ++ cursor->attr.dev_attr.store = NULL; ++ cursor->attr.sdr = cursor; ++ ++ cursor->attr_min.dev_attr.attr.name = cursor->attr_min_name; ++ cursor->attr_min.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_min.dev_attr.show = show_sensor_min; ++ cursor->attr_min.sdr = cursor; ++ ++ if (cursor->lim2_write) { ++ printk(KERN_INFO ++ "ipmisensors: You have a writable sensor threshold! Send me an e-mail at .\n"); ++ cursor->attr_min.dev_attr.store = store_sensor_min; ++ cursor->attr_min.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ } else { ++ cursor->attr_min.dev_attr.store = NULL; ++ cursor->attr_min.dev_attr.attr.mode = S_IRUGO; ++ } ++ ++ cursor->attr_max.dev_attr.attr.name = cursor->attr_max_name; ++ cursor->attr_max.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_max.dev_attr.show = show_sensor_max; ++ cursor->attr_max.sdr = cursor; ++ ++ if (cursor->lim1_write) { ++ printk(KERN_INFO ++ "ipmisensors: You have a writable sensor threshold! Send me an e-mail at .\n"); ++ cursor->attr_max.dev_attr.store = store_sensor_max; ++ cursor->attr_max.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ } else { ++ cursor->attr_max.dev_attr.store = NULL; ++ cursor->attr_max.dev_attr.attr.mode = S_IRUGO; ++ } ++ ++ if (cursor->id_length > 0) { ++ cursor->attr_label.dev_attr.attr.name = ++ cursor->attr_label_name; ++ cursor->attr_label.dev_attr.attr.mode = S_IRUGO; ++ cursor->attr_label.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_label.dev_attr.show = show_sensor_label; ++ cursor->attr_label.dev_attr.store = NULL; ++ cursor->attr_label.sdr = cursor; ++ } ++ ++ printk(KERN_INFO ++ "ipmisensors: registering sensor %d: (type 0x%.2x) " ++ "(fmt=%d; m=%d; b=%d; k1=%d; k2=%d; cap=0x%.2x; mask=0x%.4x)\n", ++ cursor->number, cursor->stype, cursor->format, cursor->m, ++ cursor->b, cursor->k & 0xf, cursor->k >> 4, ++ cursor->capab, cursor->thresh_mask); ++ ++ if (cursor->id_length > 0) { ++ ipmisensors_sprintf(id, cursor->id, cursor->string_type, ++ cursor->id_length); ++ switch (cursor->stype) { ++ case (STYPE_TEMP): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label temp%d \"%s\"\n", ++ temps, id); ++ break; ++ case (STYPE_VOLT): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label in%d \"%s\"\n", ++ volts, id); ++ break; ++ case (STYPE_CURR): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label curr%d \"%s\"\n", ++ currs, id); ++ break; ++ case (STYPE_FAN): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label fan%d \"%s\"\n", ++ fans, id); ++ break; ++ } ++ } ++ ++ ipmisensors_select_thresholds(cursor); ++ ++ if (cursor->linear != 0 && cursor->linear != 7) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: nonlinear function 0x%.2x unsupported, expect bad results\n", ++ cursor->number, cursor->linear); ++ } ++ ++ if ((cursor->format & 0x03) == 0x02) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: 1's complement format unsupported, expect bad results\n", ++ cursor->number); ++ } else if ((cursor->format & 0x03) == 0x03) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: threshold sensor only, no readings available", ++ cursor->number); ++ } ++ ++ if (cursor->lim1_write || cursor->lim2_write) ++ cursor->attr.dev_attr.attr.mode = 0644; ++ else ++ cursor->attr.dev_attr.attr.mode = 0444; ++ ++ if (device_create_file(bmc->dev, &cursor->attr.dev_attr) < 0 ++ || device_create_file(bmc->dev, ++ &cursor->attr_min.dev_attr) < 0 ++ || device_create_file(bmc->dev, ++ &cursor->attr_max.dev_attr) < 0 ++ || (cursor->id_length > ++ 0 ? device_create_file(bmc->dev, ++ &cursor->attr_label.dev_attr) < ++ 0 : 0) ++ ) { ++ printk(KERN_INFO ++ "ipmisensors: sysfs file creation failed for SDR %d (%s).\n", ++ cursor->number, cursor->id); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ return; ++ } ++ } ++ ++ bmc->alarms_attr.dev_attr.attr.name = "alarms"; ++ bmc->alarms_attr.dev_attr.attr.mode = S_IRUGO; ++ bmc->alarms_attr.dev_attr.attr.owner = THIS_MODULE; ++ bmc->alarms_attr.dev_attr.show = show_alarms; ++ bmc->alarms_attr.dev_attr.store = NULL; ++ bmc->alarms_attr.bmc = bmc; ++ ++ if (device_create_file(bmc->dev, &bmc->alarms_attr.dev_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'alarms'"); ++ return; ++ } ++ ++ bmc->name_attr.attr.name = "name"; ++ bmc->name_attr.attr.mode = S_IRUGO; ++ bmc->name_attr.attr.owner = THIS_MODULE; ++ bmc->name_attr.show = show_name; ++ ++ if (device_create_file(bmc->dev, &bmc->name_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'name'"); ++ return; ++ } ++ ++ bmc->update_attr.dev_attr.attr.name = "update_period"; ++ bmc->update_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ bmc->update_attr.dev_attr.attr.owner = THIS_MODULE; ++ bmc->update_attr.dev_attr.show = show_update_period; ++ bmc->update_attr.dev_attr.store = store_update_period; ++ bmc->update_attr.bmc = bmc; ++ ++ if (device_create_file(bmc->dev, &bmc->update_attr.dev_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'update_period'"); ++ return; ++ } ++ ++ printk(KERN_INFO ++ "ipmisensors: registered %d temp, %d volt, %d current, %d fan sensors\n", ++ temps, volts, currs, fans); ++ ++ /* This completes the initialization. We can now kickoff the ++ * periodic update of the bmc sensor's values by scheduling ++ * the first work. ++ */ ++ queue_work(ipmisensors_workqueue, &bmc->update_work.work); ++ ++} ++ ++/** ++ * Process an SDR response message, save the SDRs we like in the sdr ++ * list for the given BMC. ++ * ++ * @bmc: the bmc the message is from ++ * @msg: the IPMI SDR response message ++ */ ++static void ipmisensors_rcv_sdr_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ u16 record; ++ int type; ++ int stype; ++ int id_length; ++ int i; ++ int ipmi_ver = 0; ++ unsigned char *data; ++ u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; ++ struct sdrdata *sdr; ++ ++ if (msg->data[0] != 0) { ++ /* cut request in half and try again */ ++ bmc->ipmi_sdr_partial_size /= 2; ++ if (bmc->ipmi_sdr_partial_size < 8) { ++ printk(KERN_INFO ++ "ipmisensors: IPMI buffers too small, giving up\n"); ++ bmc->state = STATE_DONE; ++ return; ++ } ++ printk(KERN_DEBUG ++ "ipmisensors: Reducing SDR request size to %d\n", ++ bmc->ipmi_sdr_partial_size); ++ ++ ipmisensors_get_sdr(bmc, 0, 0, 0); ++ bmc->state = STATE_SDR; ++ return; ++ } ++ if (bmc->ipmi_sdr_partial_size < IPMI_SDR_SIZE) { ++ if (bmc->rx_msg_data_offset == 0) { ++ memcpy(bmc->rx_msg_data, msg->data, ++ bmc->ipmi_sdr_partial_size + 3); ++ bmc->rx_msg_data_offset = ++ bmc->ipmi_sdr_partial_size + 3; ++ } else { ++ memcpy(bmc->rx_msg_data + bmc->rx_msg_data_offset, ++ msg->data + 3, bmc->ipmi_sdr_partial_size); ++ bmc->rx_msg_data_offset += bmc->ipmi_sdr_partial_size; ++ } ++ if (bmc->rx_msg_data_offset > bmc->rx_msg_data[7] + 7) { ++ /* got last chunk */ ++ bmc->rx_msg_data_offset = 0; ++ data = bmc->rx_msg_data; ++ } else { ++ /* get more */ ++ record = ++ (bmc->rx_msg_data[4] << 8) | bmc->rx_msg_data[3]; ++ ipmisensors_get_sdr(bmc, bmc->resid, record, ++ bmc->rx_msg_data_offset - 3); ++ bmc->state = STATE_SDR; ++ return; ++ } ++ } else { ++ /* got it in one chunk */ ++ data = msg->data; ++ } ++ ++ bmc->nextrecord = (data[2] << 8) | data[1]; ++ ++ /* If the ipmi version is 0.9 we have to remap some things. ++ * Yes this is very ugly, but we aren't the ones who ++ * implemented an incomplete spec! ++ */ ++ ipmi_ver = data[5]; ++ ++ type = data[6]; ++ /* known SDR type */ ++ if (type == 1 || type == 2) { ++ stype = data[(ipmi_ver == 0x90 ? 16 : 15)]; ++ /* known sensor type */ ++ if (stype <= STYPE_MAX) { ++ if (data[(ipmi_ver == 0x90 ? 17 : 16)] != 0x01) { ++ if (type == 1) ++ ipmisensors_sprintf(id, &data[51], ++ data[50] >> 6, ++ data[50] & 0x1f); ++ else ++ ipmisensors_sprintf(id, ++ &data[(ipmi_ver == ++ 0x90 ? 30 : ++ 35)], ++ data[(ipmi_ver == ++ 0x90 ? 29 : ++ 34)] >> 6, ++ data[(ipmi_ver == ++ 0x90 ? 29 : ++ 34)] & 0x1f); ++ printk(KERN_INFO ++ "ipmisensors: skipping non-threshold sensor \"%s\"\n", ++ id); ++ } else { ++ /* add entry to sdrd table */ ++ sdr = ipmisensors_new_sdr(); ++ if (!sdr) { ++ printk(KERN_ERR ++ "ipmisensors: could not allocate memory for new SDR"); ++ return; ++ } ++ sdr->bmc = bmc; ++ sdr->stype = stype; ++ sdr->number = data[10]; ++ sdr->capab = data[(ipmi_ver == 0x90 ? 15 : 14)]; ++ sdr->thresh_mask = ++ (((u16) data[(ipmi_ver == 0x90 ? 21 : 22)]) ++ << 8) | data[21]; ++ if (type == 1) { ++ sdr->format = ++ data[(ipmi_ver == ++ 0x90 ? 22 : 24)] >> 6; ++ sdr->linear = ++ data[(ipmi_ver == ++ 0x90 ? 25 : 26)] & 0x7f; ++ sdr->m = ++ data[(ipmi_ver == 0x90 ? 26 : 27)]; ++ sdr->m |= ((u16) ++ (data ++ [(ipmi_ver == ++ 0x90 ? 27 : 28)] ++ & 0xc0)) << 2; ++ if (sdr->m & 0x0200) { ++ /* sign extend */ ++ sdr->m |= 0xfc00; ++ } ++ sdr->b = ++ data[(ipmi_ver == 0x90 ? 28 : 29)]; ++ sdr->b |= ((u16) ++ (data ++ [(ipmi_ver == ++ 0x90 ? 29 : 30)] ++ & 0xc0)) << 2; ++ if (sdr->b & 0x0200) { ++ /* sign extend */ ++ sdr->b |= 0xfc00; ++ } ++ sdr->k = ++ data[(ipmi_ver == 0x90 ? 31 : 32)]; ++ sdr->nominal = ++ data[(ipmi_ver == 0x90 ? 33 : 34)]; ++ for (i = 0; i < SDR_LIMITS; i++) { ++ /* assume readable */ ++ sdr->limits[i] = ++ data[(ipmi_ver == ++ 0x90 ? 40 : 39) + i]; ++ } ++ sdr->string_type = data[50] >> 6; ++ id_length = data[50] & 0x1f; ++ memcpy(sdr->id, &data[51], id_length); ++ sdr->id_length = id_length; ++ } else { ++ sdr->m = 1; ++ sdr->b = 0; ++ sdr->k = 0; ++ sdr->string_type = ++ data[(ipmi_ver == ++ 0x90 ? 29 : 34)] >> 6; ++ id_length = data[34] & 0x1f; ++ if (id_length > 0) { ++ memcpy(sdr->id, ++ &data[(ipmi_ver == ++ 0x90 ? 30 : 35)], ++ id_length); ++ } ++ sdr->id_length = id_length; ++ /* limits?? */ ++ if (ipmi_ver == 0x90) { ++ memcpy(sdr->id, ++ &data[30], id_length); ++ sdr->id_length = id_length; ++ } ++ } ++ ipmisensors_add_sdr(bmc, sdr); ++ } ++ } ++ /* peek at the other SDR types */ ++ } else if (type == 0x10 || type == 0x11 || type == 0x12) { ++ ipmisensors_sprintf(id, data + 19, data[18] >> 6, ++ data[18] & 0x1f); ++ if (type == 0x10) { ++ printk(KERN_INFO ++ "ipmisensors: Generic Device acc=0x%x; slv=0x%x; lun=0x%x; type=0x%x; \"%s\"\n", ++ data[8], data[9], data[10], data[13], id); ++ } else if (type == 0x11) { ++ printk(KERN_INFO ++ "ipmisensors: FRU Device acc=0x%x; slv=0x%x; log=0x%x; ch=0x%x; type=0x%x; \"%s\"\n", ++ data[8], data[9], data[10], data[11], data[13], ++ id); ++ } else { ++ printk(KERN_INFO ++ "ipmisensors: Mgmt Ctllr Device slv=0x%x; \"%s\"\n", ++ data[8], id); ++ } ++ } else if (type == 0x14) { ++ printk(KERN_INFO ++ "ipmisensors: Message Channel Info Records:\n"); ++ for (i = 0; i < 8; i++) { ++ printk(KERN_INFO "ipmisensors: Channel %d info 0x%x\n", ++ i, data[9 + i]); ++ } ++ } else { ++ printk(KERN_INFO "ipmisensors: Skipping SDR type 0x%x\n", type); ++ } ++ if (ipmi_ver != 0x90) { ++ if (bmc->nextrecord >= 6224) { ++ /*YJ stop sensor scan on poweredge 1750 */ ++ bmc->nextrecord = 0xffff; ++ } ++ } ++ ++ if (bmc->nextrecord == 0xFFFF) { ++ if (bmc->sdr_count == 0) { ++ printk(KERN_INFO ++ "ipmisensors: No recognized sensors found.\n"); ++ bmc->state = STATE_DONE; ++ } else { ++ printk(KERN_INFO "ipmisensors: all sensors detected\n"); ++ bmc->state = STATE_SYSTABLE; ++ ++ /* Schedule sysfs build/registration work */ ++ INIT_WORK(&bmc->sysfs_work, ipmisensors_build_sysfs); ++ queue_work(ipmisensors_workqueue, &bmc->sysfs_work); ++ } ++ } else { ++ ipmisensors_get_sdr(bmc, 0, bmc->nextrecord, 0); ++ bmc->state = STATE_SDR; ++ } ++} ++ ++/** ++ * Process incoming messages based on internal state ++ * ++ * @bmc: the bmc the message is from. ++ * @msg: the ipmi message to process. ++ */ ++static void ipmisensors_rcv_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ switch (bmc->state) { ++ case STATE_INIT: ++ case STATE_RESERVE: ++ bmc->resid = (((u16) msg->data[2]) << 8) | msg->data[1]; ++ ++ printk(KERN_DEBUG "ipmisensors: Got first resid 0x%.4x\n", ++ bmc->resid); ++ ++ ipmisensors_get_sdr(bmc, 0, 0, 0); ++ bmc->state = STATE_SDR; ++ break; ++ ++ case STATE_SDR: ++ case STATE_SDRPARTIAL: ++ ipmisensors_rcv_sdr_msg(bmc, msg); ++ break; ++ ++ case STATE_READING: ++ ipmisensors_rcv_reading_msg(bmc, msg); ++ break; ++ ++ case STATE_UNCANCEL: ++ bmc->resid = (((u16) msg->data[2]) << 8) | msg->data[1]; ++ ++ printk(KERN_DEBUG "ipmisensors: Got new resid 0x%.4x\n", ++ bmc->resid); ++ ++ bmc->rx_msg_data_offset = 0; ++ ipmisensors_get_sdr(bmc, 0, bmc->nextrecord, 0); ++ bmc->state = STATE_SDR; ++ break; ++ ++ case STATE_DONE: ++ case STATE_SYSTABLE: ++ break; ++ default: ++ bmc->state = STATE_INIT; ++ } ++} ++ ++/** ++ * Callback to handle a received IPMI message from a given BMC. ++ * ++ * @msg: the received message. ++ * @handler_data: a pointer to the particular bmc ipmisensors_bmc_data struct. ++ */ ++static void ipmisensors_msg_handler(struct ipmi_recv_msg *msg, ++ void *user_msg_data) ++{ ++ struct ipmisensors_bmc_data *bmc = ++ (struct ipmisensors_bmc_data *)user_msg_data; ++ ++ if (msg->msg.data[0] != 0) ++ printk(KERN_WARNING ++ "ipmisensors: Error 0x%x on cmd 0x%x/0x%x\n", ++ msg->msg.data[0], msg->msg.netfn, msg->msg.cmd); ++ ++ if (bmc != NULL && ipmisensors_intf_registered(bmc->interface_id)) { ++ if (bmc->state == STATE_SDR && ++ msg->msg.data[0] == IPMI_INVALID_RESERVATION_ID) { ++ /* reservation cancelled, get new resid */ ++ if (++bmc->errorcount > 275) { ++ printk(KERN_ERR ++ "ipmisensors: Too many reservations cancelled, giving up\n"); ++ bmc->state = STATE_DONE; ++ } else { ++ printk(KERN_DEBUG ++ "ipmisensors: resid 0x%04x cancelled, getting new one\n", ++ bmc->resid); ++ ++ ipmisensors_reserve_sdr(bmc); ++ bmc->state = STATE_UNCANCEL; ++ } ++ } else if (msg->msg.data[0] != IPMI_CC_NO_ERROR && ++ msg->msg.data[0] != IPMI_ERR_RETURNING_REQ_BYTES && ++ msg->msg.data[0] != IPMI_ERR_PROVIDING_RESPONSE) { ++ printk(KERN_ERR ++ "ipmisensors: Error 0x%x on cmd 0x%x/0x%x; state = %d; probably fatal.\n", ++ msg->msg.data[0], msg->msg.netfn & 0xfe, ++ msg->msg.cmd, bmc->state); ++ } else { ++ printk(KERN_DEBUG "ipmisensors: received message\n"); ++ ipmisensors_rcv_msg(bmc, &msg->msg); ++ } ++ ++ } else { ++ printk(KERN_WARNING ++ "ipmisensors: Response for non-registered BMC\n"); ++ if (bmc != NULL) ++ printk(KERN_DEBUG "ipmisensors: BMC ID: %d\n", ++ bmc->interface_id); ++ else ++ printk(KERN_DEBUG "ipmisensors: BMC NULL!\n"); ++ } ++ ++ ipmi_free_recv_msg(msg); ++} ++ ++/****** IPMI Interface Initialization ******/ ++ ++/** ++ * Return true if the given ipmi interface has been registered. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static int ipmisensors_intf_registered(int ipmi_intf) ++{ ++ int found = 0; ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->interface_id == ipmi_intf) { ++ found++; ++ } ++ } ++ ++ return found; ++} ++ ++/** ++ * Return true if the given BMC has been registered. ++ * ++ * @bmc: The BMC device. ++ */ ++static int ipmisensors_bmc_registered(struct device *bmc) ++{ ++ int found = 0; ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->dev == bmc) { ++ found++; ++ } ++ } ++ ++ return found; ++} ++ ++/** ++ * Register new IPMI BMC interface. Interface indpendent callback created ++ * for flexibility in adding new types of interface callbacks in future. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static void ipmisensors_register_bmc(int ipmi_intf, struct ipmi_addr *address) ++{ ++ int error; ++ ++ /* allocate a new ipmisensors_bmc_data struct */ ++ ++ struct ipmisensors_bmc_data *bmc = (struct ipmisensors_bmc_data *) ++ kmalloc(sizeof(struct ipmisensors_bmc_data), GFP_KERNEL); ++ ++ /* initialize members */ ++ INIT_LIST_HEAD(&bmc->sdrs); ++ bmc->interface_id = ipmi_intf; ++ ++ bmc->address = *address; ++ ++ bmc->sdr_count = 0; ++ bmc->msgid = 0; ++ bmc->ipmi_sdr_partial_size = IPMI_CHUNK_SIZE; ++ bmc->state = STATE_INIT; ++ bmc->errorcount = 0; ++ bmc->rx_msg_data_offset = 0; ++ bmc->dev = ipmi_get_bmcdevice(ipmi_intf); ++ ++ /* default to 3 second min update interval */ ++ bmc->update_period = 3; ++ ++ if (bmc->dev == NULL) { ++ printk(KERN_ERR ++ "ipmisensors: Error, couldn't get BMC device for interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Create IPMI messaging interface user */ ++ error = ipmi_create_user(bmc->interface_id, &driver_data.ipmi_hndlrs, ++ bmc, &bmc->user); ++ if (error < 0) { ++ printk(KERN_ERR ++ "ipmisensors: Error, unable to register user with ipmi interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Register the BMC as a HWMON class device */ ++ bmc->class_dev = hwmon_device_register(bmc->dev); ++ ++ if (IS_ERR(bmc->class_dev)) { ++ printk(KERN_ERR ++ "ipmisensors: Error, unable to register hwmon class device for interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Register the BMC in the driver */ ++ if (ipmisensors_bmc_registered(bmc->dev)) { ++ printk(KERN_ERR ++ "ipmisensors: BMC on interface %d already registered\n", ++ bmc->interface_id); ++ hwmon_device_unregister(bmc->class_dev); ++ kfree(bmc); ++ return; ++ } ++ ++ ipmi_get_version(bmc->user, &bmc->ipmi_version_major, ++ &bmc->ipmi_version_minor); ++ ++ /* finally add the new bmc data to the bmc data list */ ++ list_add_tail(&bmc->list, &driver_data.bmc_data); ++ driver_data.interfaces++; ++ ++ printk(KERN_INFO ++ "ipmisensors: Registered IPMI %d.%d BMC over interface %d\n", ++ bmc->ipmi_version_major, ++ bmc->ipmi_version_minor, bmc->interface_id); ++ ++ /* Send a reserve SDR command to the bmc */ ++ ipmisensors_reserve_sdr(bmc); ++ ++ /* initialize the bmc's update work struct */ ++ INIT_DELAYED_WORK(&bmc->update_work, ipmisensors_update_bmc); ++} ++ ++/** ++ * Callback for when an IPMI BMC is gone. Interface indpendent callback created ++ * for flexibility in adding new types of interface callbacks in future. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static void ipmisensors_unregister_bmc(int ipmi_intf) ++{ ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->interface_id == ipmi_intf) { ++ list_del(&cursor->list); ++ printk(KERN_DEBUG ++ "ipmisensors: cancelling queued work\n"); ++ /* cancel update work queued for this bmc */ ++ cancel_delayed_work(&cursor->update_work); ++ printk(KERN_DEBUG ++ "ipmisensors: waiting for update to finish\n"); ++ /* wait for readings to finish */ ++ while (cursor->state != STATE_DONE) ; ++ ++ device_remove_file(cursor->dev, ++ &cursor->alarms_attr.dev_attr); ++ device_remove_file(cursor->dev, ++ &cursor->update_attr.dev_attr); ++ hwmon_device_unregister(cursor->class_dev); ++ ipmisensors_sdr_cleanup(cursor); ++ ipmi_destroy_user(cursor->user); ++ ++ printk(KERN_INFO ++ "ipmisensors: Unegistered IPMI interface %d\n", ++ cursor->interface_id); ++ ++ kfree(cursor); ++ driver_data.interfaces--; ++ } ++ } ++ ++} ++ ++/** ++ * Unregister all registered bmcs. ++ */ ++static void ipmisensors_unregister_bmc_all(void) ++{ ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ list_del(&cursor->list); ++ ++ /* cancel update work queued for this bmc */ ++ printk(KERN_DEBUG "ipmisensors: cancelling queued work\n"); ++ cancel_delayed_work(&cursor->update_work); ++ ++ printk(KERN_DEBUG ++ "ipmisensors: waiting for update to finish\n"); ++ /* wait for readings to finish */ ++ while (cursor->state != STATE_DONE) ; ++ ++ device_remove_file(cursor->dev, &cursor->alarms_attr.dev_attr); ++ device_remove_file(cursor->dev, &cursor->update_attr.dev_attr); ++ hwmon_device_unregister(cursor->class_dev); ++ ipmisensors_sdr_cleanup(cursor); ++ ipmi_destroy_user(cursor->user); ++ ++ printk(KERN_INFO ++ "ipmisensors: Unegistered IPMI interface %d\n", ++ cursor->interface_id); ++ ++ kfree(cursor); ++ } ++ ++ driver_data.interfaces = 0; ++} ++ ++/** ++ * Callback for when a new IPMI SMI type interface is found. ++ * ++ * @if_num: The IPMI interface number. ++ */ ++static void ipmisensors_new_smi(int if_num, struct device *dev) ++{ ++ struct ipmi_addr smi_address = { ++ IPMI_SYSTEM_INTERFACE_ADDR_TYPE, ++ IPMI_BMC_CHANNEL, ++ {0}, ++ }; ++ ++ /* calls the generic new interface function */ ++ ipmisensors_register_bmc(if_num, &smi_address); ++} ++ ++/** ++ * Callback for when an exisiting IPMI SMI type interface is gone. ++ * ++ * @if_num: The IPMI interface number. ++ */ ++static void ipmisensors_smi_gone(int if_num) ++{ ++ if (driver_data.interfaces > 0) { ++ ipmisensors_unregister_bmc(if_num); ++ } ++} ++ ++/** ++ * Initialize the module. ++ */ ++static int __init ipmisensors_init(void) ++{ ++ int error; ++ printk(KERN_INFO "ipmisensors - IPMI BMC sensors interface\n"); ++ ++ /* init cache managers */ ++ driver_data.sdrdata_cache = ++ kmem_cache_create("ipmisensors_sdrdata", sizeof(struct sdrdata), 0, ++ 0, NULL, NULL); ++ driver_data.sysfsattr_cache = ++ kmem_cache_create("ipmisensors_sysfsattr", ++ sizeof(struct ipmisensors_device_attribute), 0, 0, ++ NULL, NULL); ++ ++ if (!driver_data.sdrdata_cache || !driver_data.sysfsattr_cache) { ++ if (driver_data.sdrdata_cache) ++ kmem_cache_destroy(driver_data.sdrdata_cache); ++ if (driver_data.sysfsattr_cache) ++ kmem_cache_destroy(driver_data.sysfsattr_cache); ++ return -ENOMEM; ++ } ++ ++ /* register IPMI interface callback(s) */ ++ error = ipmi_smi_watcher_register(&driver_data.smi_watcher); ++ if (error) { ++ printk(KERN_WARNING ++ "ipmisensors: can't register smi watcher\n"); ++ return error; ++ } ++ ++ /* create work queue, keep it simple, single-threaded */ ++ ipmisensors_workqueue = ++ create_singlethread_workqueue("ipmisensors_workqueue"); ++ ++ return 0; ++} ++ ++/** ++ * Cleanup ++ */ ++static void ipmisensors_cleanup(void) ++{ ++ /* start cleanup */ ++ cleanup = 1; ++ ++ /* unregister bmcs */ ++ printk(KERN_DEBUG "ipmisensors: unregister bmcs\n"); ++ ipmi_smi_watcher_unregister(&driver_data.smi_watcher); ++ ipmisensors_unregister_bmc_all(); ++ ++ /* flush & destroy work queue */ ++ printk(KERN_DEBUG "ipmisensors: destroy workqueue\n"); ++ flush_workqueue(ipmisensors_workqueue); ++ destroy_workqueue(ipmisensors_workqueue); ++ ++ /* remove cache managers */ ++ if (driver_data.sdrdata_cache) ++ kmem_cache_destroy(driver_data.sdrdata_cache); ++ if (driver_data.sysfsattr_cache) ++ kmem_cache_destroy(driver_data.sysfsattr_cache); ++} ++ ++/** ++ * Cleanup and exit the module ++ */ ++static void __exit ipmisensors_exit(void) ++{ ++ ipmisensors_cleanup(); ++ printk(KERN_DEBUG "ipmisensors: cleanup finished\n"); ++} ++ ++MODULE_AUTHOR("Yani Ioannou "); ++MODULE_DESCRIPTION("IPMI BMC sensors"); ++MODULE_LICENSE("GPL"); ++ ++module_init(ipmisensors_init); ++module_exit(ipmisensors_exit); +diff -rduNp linux-2.6.20.3.orig/drivers/hwmon/ipmisensors.h linux-2.6.20.3/drivers/hwmon/ipmisensors.h +--- linux-2.6.20.3.orig/drivers/hwmon/ipmisensors.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.20.3/drivers/hwmon/ipmisensors.h 2007-03-14 14:41:23.000000000 +0100 +@@ -0,0 +1,240 @@ ++/* ++ * ipmisensors.h - lm_sensors interface to IPMI sensors. ++ * ++ * Copyright (C) 2004-2006 Yani Ioannou ++ * ++ * Adapted from bmcsensors (lm-sensors for linux 2.4) ++ * bmcsensors (C) Mark D. Studebaker ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* SDR defs */ ++#define STYPE_TEMP 0x01 ++#define STYPE_VOLT 0x02 ++#define STYPE_CURR 0x03 ++#define STYPE_FAN 0x04 ++ ++#define SDR_LIMITS 8 ++#define SDR_MAX_ID_LENGTH 16 ++#define SDR_MAX_UNPACKED_ID_LENGTH ((SDR_MAX_ID_LENGTH * 4 / 3) + 2) ++ ++/* the last sensor type we are interested in */ ++#define STYPE_MAX 4 ++ ++#define IPMI_SDR_SIZE 67 ++#define IPMI_CHUNK_SIZE 16 ++ ++#define MAX_FILENAME_LENGTH 30 ++ ++struct ipmisensors_device_attribute { ++ struct device_attribute dev_attr; ++ struct sdrdata *sdr; ++}; ++#define to_ipmisensors_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct ipmisensors_device_attribute, dev_attr) ++ ++#define IPMISENSORS_DEVICE_ATTR(_name,_mode,_show,_store,_index) \ ++struct ipmisensors_attribute sensor_dev_attr_##_name = { \ ++ .dev_attr = __ATTR(_name,_mode,_show,_store), \ ++ .index = _index, \ ++} ++ ++struct ipmisensors_bmc_device_attribute { ++ struct device_attribute dev_attr; ++ struct ipmisensors_bmc_data *bmc; ++}; ++#define to_ipmisensors_bmc_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct ipmisensors_bmc_device_attribute, dev_attr) ++ ++/** ++ * &struct_sdrdata stores the IPMI Sensor Data Record (SDR) data, as recieved from the BMC, along with the corresponding sysfs attributes ++ */ ++struct sdrdata { ++ struct list_head list; ++ /* retrieved from SDR, not expected to change */ ++ /* Sensor Type Code */ ++ u8 stype; ++ u8 number; ++ /* Sensor Capability Code */ ++ u8 capab; ++ u16 thresh_mask; ++ u8 format; ++ u8 linear; ++ s16 m; ++ s16 b; ++ u8 k; ++ u8 nominal; ++ u8 limits[SDR_LIMITS]; ++ /* index into limits for reported upper and lower limit */ ++ int lim1, lim2; ++ u8 lim1_write, lim2_write; ++ u8 string_type; ++ u8 id_length; ++ u8 id[SDR_MAX_ID_LENGTH]; ++ /* retrieved from reading */ ++ u8 reading; ++ u8 status; ++ u8 thresholds; ++ /* sensor's bmc */ ++ struct ipmisensors_bmc_data *bmc; ++ /* sysfs entries */ ++ struct ipmisensors_device_attribute attr; ++ char *attr_name; ++ struct ipmisensors_device_attribute attr_min; ++ char *attr_min_name; ++ struct ipmisensors_device_attribute attr_max; ++ char *attr_max_name; ++ struct ipmisensors_device_attribute attr_label; ++ char *attr_label_name; ++ ++}; ++ ++/** ++ * &struct_ipmisensors_data stores the data for the ipmisensors driver. ++ */ ++struct ipmisensors_data { ++ /* Driver struct */ ++ char *driver_name; ++ ++ /* Linked list of ipmisensors_bmc_data structs, one for each BMC */ ++ struct list_head bmc_data; ++ ++ /* Number of ipmi interfaces (and hence ipmisensors_data structs). */ ++ int interfaces; ++ ++ /* IPMI kernel interface - SMI watcher */ ++ struct ipmi_smi_watcher smi_watcher; ++ ++ /* IPMI kernel interface - user handlers */ ++ struct ipmi_user_hndl ipmi_hndlrs; ++ ++ /* Cache manager for sdrdata cache */ ++ struct kmem_cache *sdrdata_cache; ++ ++ /* Cache manager for ipmi_sensor_device_attribute cache */ ++ struct kmem_cache *sysfsattr_cache; ++}; ++ ++/** ++ * &states: enumeration of state codes for a bmc specific ipmisensors ++ */ ++enum states { ++ STATE_INIT, ++ STATE_RESERVE, ++ STATE_SDR, ++ STATE_SDRPARTIAL, ++ STATE_READING, ++ STATE_UNCANCEL, ++ STATE_SYSTABLE, ++ STATE_DONE ++}; ++ ++/** ++ * &struct_ipmisensors_bmc_data stores the data for a particular IPMI BMC. ++ */ ++struct ipmisensors_bmc_data { ++ struct list_head list; ++ ++ /* The IPMI interface number */ ++ int interface_id; ++ ++ /* The IPMI address */ ++ struct ipmi_addr address; ++ ++ /* List of sdrdata structs (sdrs) recieved from the BMC */ ++ struct list_head sdrs; ++ ++ /* Count of the number of sdrs stored in the sdr list */ ++ int sdr_count; ++ ++ /* next message id */ ++ int msgid; ++ ++ /* The ipmi interface 'user' used to access this particular bmc */ ++ ipmi_user_t user; ++ ++ /* BMC IPMI Version (major) */ ++ unsigned char ipmi_version_major; ++ ++ /* BMC IPMI Version (minor) */ ++ unsigned char ipmi_version_minor; ++ ++ /* The size of the SDR request message */ ++ int ipmi_sdr_partial_size; ++ ++ /* transmit message buffer */ ++ struct kernel_ipmi_msg tx_message; ++ ++ /* ipmi transmited data buffer */ ++ unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* why the +50 in bmcsensors? */ ++ ++ /* ipmi recieved data buffer */ ++ unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; ++ ++ /* current recieve buffer offset */ ++ int rx_msg_data_offset; ++ ++ /* The id of then next SDR record to read during update cycle */ ++ u16 nextrecord; ++ ++ /* BMC SDR Reservation ID */ ++ u16 resid; ++ ++ /* Alarm status */ ++ u8 alarms; ++ ++ /* The cumalative error count for this bmc */ ++ int errorcount; ++ ++ /* The current state of this bmc w.r.t. ipmisensors (see enum states) */ ++ int state; ++ ++ /* The current sdr for which a reading is pending */ ++ struct sdrdata *current_sdr; ++ ++ /* The BMC's device struct */ ++ struct device *dev; ++ ++ /* hwmon class device */ ++ struct class_device *class_dev; ++ ++ /* hwmon device name */ ++ struct device_attribute name_attr; ++ ++ /* alarms attribute */ ++ struct ipmisensors_bmc_device_attribute alarms_attr; ++ ++ /* update_period attribute */ ++ struct ipmisensors_bmc_device_attribute update_attr; ++ ++ /* lower bound on time between updates (in seconds) */ ++ unsigned int update_period; ++ ++ /* semaphore used to do a headcount of the SDR readings we are waiting ++ * on in a given bmc update */ ++ struct semaphore update_semaphore; ++ ++ /* bmc's work struct for updating sensors */ ++ struct delayed_work update_work; ++ ++ /* bmc's work struct for building the sysfs workqueue */ ++ struct work_struct sysfs_work; ++}; +diff -rduNp linux-2.6.20.3.orig/include/linux/ipmi.h linux-2.6.20.3/include/linux/ipmi.h +--- linux-2.6.20.3.orig/include/linux/ipmi.h 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/include/linux/ipmi.h 2007-03-14 14:23:02.000000000 +0100 +@@ -300,6 +300,9 @@ int ipmi_create_user(unsigned int + safe, too. */ + int ipmi_destroy_user(ipmi_user_t user); + ++/* Get the IPMI BMC's device struct */ ++struct device *ipmi_get_bmcdevice(int ipmi_intf); ++ + /* Get the IPMI version of the BMC we are talking to. */ + void ipmi_get_version(ipmi_user_t user, + unsigned char *major, +diff -rduNp linux-2.6.20.3.orig/include/linux/ipmi_msgdefs.h linux-2.6.20.3/include/linux/ipmi_msgdefs.h +--- linux-2.6.20.3.orig/include/linux/ipmi_msgdefs.h 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/include/linux/ipmi_msgdefs.h 2007-03-14 14:23:02.000000000 +0100 +@@ -45,6 +45,7 @@ + + #define IPMI_NETFN_APP_REQUEST 0x06 + #define IPMI_NETFN_APP_RESPONSE 0x07 ++#define IPMI_GET_DEVICE_GUID_CMD 0x08 + #define IPMI_GET_DEVICE_ID_CMD 0x01 + #define IPMI_COLD_RESET_CMD 0x02 + #define IPMI_WARM_RESET_CMD 0x03 +@@ -57,6 +58,11 @@ + #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD 0x2f + #define IPMI_READ_EVENT_MSG_BUFFER_CMD 0x35 + #define IPMI_GET_CHANNEL_INFO_CMD 0x42 ++#define IPMI_RESERVE_SDR 0x22 ++#define IPMI_GET_SDR 0x23 ++#define IPMI_GET_SENSOR_STATE_READING 0x2D ++#define IPMI_SET_SENSOR_HYSTERESIS 0x24 ++#define IPMI_SET_SENSOR_THRESHOLD 0x26 + + #define IPMI_NETFN_STORAGE_REQUEST 0x0a + #define IPMI_NETFN_STORAGE_RESPONSE 0x0b +@@ -79,10 +85,13 @@ + #define IPMI_NODE_BUSY_ERR 0xc0 + #define IPMI_INVALID_COMMAND_ERR 0xc1 + #define IPMI_TIMEOUT_ERR 0xc3 ++#define IPMI_INVALID_RESERVATION_ID 0xc5 + #define IPMI_ERR_MSG_TRUNCATED 0xc6 + #define IPMI_REQ_LEN_INVALID_ERR 0xc7 + #define IPMI_REQ_LEN_EXCEEDED_ERR 0xc8 + #define IPMI_NOT_IN_MY_STATE_ERR 0xd5 /* IPMI 2.0 */ ++#define IPMI_ERR_RETURNING_REQ_BYTES 0xca ++#define IPMI_ERR_PROVIDING_RESPONSE 0xce + #define IPMI_LOST_ARBITRATION_ERR 0x81 + #define IPMI_BUS_ERR 0x82 + #define IPMI_NAK_ON_WRITE_ERR 0x83 diff --git a/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.21.5-007-ipmisensors-20070314-1214.patch b/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.21.5-007-ipmisensors-20070314-1214.patch new file mode 100644 index 0000000000..aca57c37b0 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.21.5-007-ipmisensors-20070314-1214.patch @@ -0,0 +1,1914 @@ +diff -rduNp linux-2.6.20.3.orig/drivers/char/ipmi/ipmi_msghandler.c linux-2.6.20.3/drivers/char/ipmi/ipmi_msghandler.c +--- linux-2.6.20.3.orig/drivers/char/ipmi/ipmi_msghandler.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/drivers/char/ipmi/ipmi_msghandler.c 2007-03-14 14:23:02.000000000 +0100 +@@ -1954,6 +1954,24 @@ static void remove_proc_entries(ipmi_smi + #endif /* CONFIG_PROC_FS */ + } + ++/* ++ * Retrieves the bmc_device struct for a given ipmi interface number (or NULL if none). ++ */ ++struct device *ipmi_get_bmcdevice(int if_num) ++{ ++ ipmi_smi_t intf; ++ mutex_lock(&ipmi_interfaces_mutex); ++ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { ++ if (intf->intf_num == if_num){ ++ mutex_unlock(&ipmi_interfaces_mutex); ++ return &intf->bmc->dev->dev; ++ } ++ } ++ mutex_unlock(&ipmi_interfaces_mutex); ++ ++ return NULL; ++} ++ + static int __find_bmc_guid(struct device *dev, void *data) + { + unsigned char *id = data; +@@ -4183,3 +4201,4 @@ EXPORT_SYMBOL(ipmi_get_my_LUN); + EXPORT_SYMBOL(ipmi_smi_add_proc_entry); + EXPORT_SYMBOL(ipmi_user_set_run_to_completion); + EXPORT_SYMBOL(ipmi_free_recv_msg); ++EXPORT_SYMBOL(ipmi_get_bmcdevice); +diff -rduNp linux-2.6.20.3.orig/drivers/hwmon/Kconfig linux-2.6.20.3/drivers/hwmon/Kconfig +--- linux-2.6.20.3.orig/drivers/hwmon/Kconfig 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/drivers/hwmon/Kconfig 2007-03-14 14:23:02.000000000 +0100 +@@ -218,6 +218,16 @@ config SENSORS_GL520SM + This driver can also be built as a module. If so, the module + will be called gl520sm. + ++config SENSORS_IPMI ++ tristate "IPMI Hardware Monitoring Support" ++ depends on HWMON && IPMI_HANDLER && EXPERIMENTAL ++ help ++ If you say yes here you get support for sensors monitored by ++ an IPMI baseboard management controller (BMC). ++ ++ This driver can also be built as a module. If so, the module ++ will be called ipmisensors. ++ + config SENSORS_IT87 + tristate "ITE IT87xx and compatibles" + depends on HWMON && I2C +diff -rduNp linux-2.6.20.3.orig/drivers/hwmon/Makefile linux-2.6.20.3/drivers/hwmon/Makefile +--- linux-2.6.20.3.orig/drivers/hwmon/Makefile 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/drivers/hwmon/Makefile 2007-03-14 14:23:02.000000000 +0100 +@@ -28,6 +28,7 @@ obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o + obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o + obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o + obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o ++obj-$(CONFIG_SENSORS_IPMI) += ipmisensors.o + obj-$(CONFIG_SENSORS_IT87) += it87.o + obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o + obj-$(CONFIG_SENSORS_LM63) += lm63.o +diff -rduNp linux-2.6.20.3.orig/drivers/hwmon/ipmisensors.c linux-2.6.20.3/drivers/hwmon/ipmisensors.c +--- linux-2.6.20.3.orig/drivers/hwmon/ipmisensors.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.20.3/drivers/hwmon/ipmisensors.c 2007-03-14 14:44:42.000000000 +0100 +@@ -0,0 +1,1552 @@ ++/* ++ * ipmisensors.c - lm-sensors/hwmon interface to IPMI sensors. ++ * ++ * Copyright (C) 2004-2006 Yani Ioannou ++ * ++ * Adapted from bmcsensors (lm-sensors for linux 2.4) ++ * bmcsensors (C) Mark D. Studebaker ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ipmisensors.h" ++ ++/****** Function Prototypes ******/ ++static void ipmisensors_send_message(struct ipmisensors_bmc_data *bmc, ++ long msgid, struct kernel_ipmi_msg *msg); ++static void ipmisensors_reserve_sdr(struct ipmisensors_bmc_data *bmc); ++static void ipmisensors_get_sdr(struct ipmisensors_bmc_data *bmc, u16 res_id, ++ u16 record, u8 offset); ++static void ipmisensors_set_sensor_threshold(struct ipmisensors_bmc_data *bmc, ++ u8 number, int value, ++ int lim_index); ++static void ipmisensors_get_reading(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr); ++static void ipmisensors_msg_handler(struct ipmi_recv_msg *msg, ++ void *user_msg_data); ++static int ipmisensors_intf_registered(int ipmi_intf); ++static int ipmisensors_bmc_registered(struct device *bmc); ++static void ipmisensors_register_bmc(int ipmi_intf, struct ipmi_addr *address); ++static void ipmisensors_unregister_bmc(int ipmi_intf); ++static void ipmisensors_unregister_bmc_all(void); ++static void ipmisensors_new_smi(int if_num, struct device *dev); ++static void ipmisensors_smi_gone(int if_num); ++static void ipmisensors_update_bmc(struct work_struct *); ++static void ipmisensors_cleanup(void); ++ ++/****** Static Vars ******/ ++ ++/* set when module is being removed */ ++static int cleanup = 0; ++ ++/* ipmisensors driver data */ ++static struct ipmisensors_data driver_data = { ++ .driver_name = "bmc", ++ .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data), ++ .interfaces = 0, ++ .smi_watcher = { ++ .owner = THIS_MODULE, ++ .new_smi = ipmisensors_new_smi, ++ .smi_gone = ipmisensors_smi_gone, ++ }, ++ .ipmi_hndlrs = { ++ .ipmi_recv_hndl = ipmisensors_msg_handler, ++ }, ++}; ++ ++/* sensor refresh workqueue */ ++static struct workqueue_struct *ipmisensors_workqueue; ++ ++/****** SDR List Functions ******/ ++/** ++ * Creates a new sdrdata struct, or returns NULL if insufficient memory. ++ */ ++static struct sdrdata *ipmisensors_new_sdr(void) ++{ ++ struct sdrdata *sdr; ++ ++ sdr = kmem_cache_alloc(driver_data.sdrdata_cache, GFP_ATOMIC); ++ if (sdr) { ++ memset(sdr, 0, sizeof(struct sdrdata)); ++ } else { ++ printk(KERN_ERR ++ "ipmisensors: Couldn't allocate memory for new SDR\n"); ++ } ++ ++ return sdr; ++} ++ ++/** ++ * Adds the given sdrdata struct to the given bmc's SDR list. ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static inline void ipmisensors_add_sdr(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr) ++{ ++ list_add(&sdr->list, &bmc->sdrs); ++ printk(KERN_DEBUG ++ "ipmisensors: SDR %d: type 0x%02x (%s)\n", ++ bmc->sdr_count, sdr->stype, sdr->id); ++ bmc->sdr_count++; ++} ++ ++/** ++ * Cleanup the sdr list for the given BMC. ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static void ipmisensors_sdr_cleanup(struct ipmisensors_bmc_data *bmc) ++{ ++ struct sdrdata *cursor, *next; ++ ++ /* find and free each sdr data struct */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ device_remove_file(bmc->dev, &cursor->attr.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_min.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_max.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_label.dev_attr); ++ ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ ++ list_del(&cursor->list); ++ kmem_cache_free(driver_data.sdrdata_cache, cursor); ++ } ++} ++ ++/* worker function for workqueue ipmisensors_workqueue */ ++static void ipmisensors_update_bmc(struct work_struct *work) ++{ ++ struct ipmisensors_bmc_data *bmc = container_of(work, struct ipmisensors_bmc_data, update_work.work); ++ ++ /* don't start an update cycle if one already in progress */ ++ if (bmc->state != STATE_READING) { ++ struct sdrdata *cursor, *next; ++ bmc->state = STATE_READING; ++ printk(KERN_DEBUG "ipmisensors: starting update\n"); ++ ++ /* init semaphore to 1 for update cycle */ ++ sema_init(&bmc->update_semaphore, 1); ++ ++ /* update each sdr reading */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ ipmisensors_get_reading(bmc, cursor); ++ } ++ } ++ ++ /* wait for readings (need timeout?) */ ++ down_interruptible(&bmc->update_semaphore); ++ ++ printk(KERN_DEBUG "ipmisensors: update complete\n"); ++ ++ bmc->state = STATE_DONE; ++ ++ /* if the module isn't cleaning up, schedule another update */ ++ if (!cleanup) ++ queue_delayed_work(ipmisensors_workqueue, &bmc->update_work, ++ bmc->update_period * HZ); ++} ++ ++/****** IPMI Message Sending ******/ ++ ++/** ++ * Send a message to the IPMI BMC ++ * ++ * @bmc: the bmc to send the message to. ++ * @msgid: the message id to use. ++ * @msg: the ipmi message structure. ++ */ ++static void ipmisensors_send_message(struct ipmisensors_bmc_data *bmc, ++ long msgid, struct kernel_ipmi_msg *msg) ++{ ++ if (msg->data == NULL) ++ printk(KERN_DEBUG "ipmisensors: Send 0x%x\n", msg->cmd); ++ else ++ printk(KERN_DEBUG "ipmisensors: Send 0x%x 0x%x 0x%x\n", ++ msg->cmd, msg->data[0], msg->data[1]); ++ ++ /* This should be ipmi_request, but Corey had to remove ++ * that due to it being unused at the moment, as soon as ++ * this makes it into the kernel we should request it be re-instated. ++ */ ++ ipmi_request_settime(bmc->user, &bmc->address, msgid, msg, bmc, 0, ++ -1, 0); ++} ++ ++/** ++ * Compose and send a "reserve SDR" message ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static void ipmisensors_reserve_sdr(struct ipmisensors_bmc_data *bmc) ++{ ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_RESERVE_SDR; ++ bmc->tx_message.data_len = 0; ++ bmc->tx_message.data = NULL; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Componse and send a "get SDR" message ++ * ++ * @bmc: the bmc to send the message to. ++ * @res_id: ++ * @record: ++ * @offset: ++ */ ++static void ipmisensors_get_sdr(struct ipmisensors_bmc_data *bmc, u16 res_id, ++ u16 record, u8 offset) ++{ ++ printk(KERN_DEBUG "ipmisensors: Get SDR 0x%x 0x%x 0x%x\n", ++ res_id, record, offset); ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_GET_SDR; ++ bmc->tx_message.data_len = 6; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = res_id & 0xff; ++ bmc->tx_msg_data[1] = res_id >> 8; ++ bmc->tx_msg_data[2] = record & 0xff; ++ bmc->tx_msg_data[3] = record >> 8; ++ bmc->tx_msg_data[4] = offset; ++ bmc->tx_msg_data[5] = bmc->ipmi_sdr_partial_size; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Compose and send a "set sensor threshold" message ++ * ++ * @bmc: the bmc to send the message to. ++ * @id: the ipmi id number of the sensor. ++ * @value: the new value for the threshold. ++ * @lim_index: the index in the lim[] array for which this value applies. ++ */ ++static void ipmisensors_set_sensor_threshold(struct ipmisensors_bmc_data *bmc, ++ u8 number, int value, ++ int lim_index) ++{ ++ int i; ++ ++ printk(KERN_DEBUG "ipmisensors: Set SDR Threshold %d %d %d\n", ++ number, value, lim_index); ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_SET_SENSOR_THRESHOLD; ++ bmc->tx_message.data_len = 8; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = number & 0xff; ++ bmc->tx_msg_data[1] = 0x01 << lim_index; ++ ++ if (lim_index > 5 || lim_index < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Error - ipmisensors_set_sensor_threshold given invalid lim_index\n"); ++ return; ++ } ++ ++ for (i = 2; i < 8; i++) ++ bmc->tx_msg_data[i] = 0x00; ++ ++ bmc->tx_msg_data[lim_index] = value && 0xff; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Compose and send a "get sensor reading" message for the given sdr. ++ * ++ * @bmc: the bmc to send the message to. ++ * @sdr: the sdr of the sensor to get the reading for. ++ */ ++static void ipmisensors_get_reading(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr) ++{ ++ bmc->tx_message.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST; ++ bmc->tx_message.cmd = IPMI_GET_SENSOR_STATE_READING; ++ bmc->tx_message.data_len = 1; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = sdr->number; ++ bmc->current_sdr = sdr; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++ down_interruptible(&bmc->update_semaphore); ++} ++ ++/****** IPMI Message Receiving ******/ ++ ++/** ++ * Process an sensor reading response message. ++ * ++ * @bmc: the bmc the message is from ++ * @msg: the IPMI SDR response message ++ */ ++static void ipmisensors_rcv_reading_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ struct sdrdata *sdr = bmc->current_sdr; ++ ++ if (sdr == NULL) { ++ printk(KERN_ERR ++ "ipmisensors: Error ipmisensors_rcv_reading with NULL sdr\n"); ++ return; ++ } ++ ++ sdr->reading = msg->data[1]; ++ sdr->status = msg->data[2]; ++ sdr->thresholds = msg->data[3]; ++ ++ printk(KERN_DEBUG "ipmisensors: sensor %d (type %d) reading %d\n", ++ sdr->number, sdr->stype, msg->data[1]); ++ ++ up(&bmc->update_semaphore); ++} ++ ++/** ++ * Unpack based on string type, convert to normal, null terminate. ++ */ ++static void ipmisensors_sprintf(u8 * to, u8 * from, u8 type, u8 length) ++{ ++ static const u8 *bcdplus = "0123456789 -.:,_"; ++ int i; ++ ++ switch (type) { ++ case 0: /* unicode */ ++ for (i = 0; i < length; i++) ++ *to++ = (*from++ & 0x7f); ++ *to = 0; ++ break; ++ case 1: /* BCD Plus */ ++ for (i = 0; i < length; i++) ++ *to++ = bcdplus[*from++ & 0x0f]; ++ *to = 0; ++ break; ++ case 2: /* packed ascii *//* if not a mult. of 3 this will run over */ ++ for (i = 0; i < length; i += 3) { ++ *to++ = *from & 0x3f; ++ *to++ = *from >> 6 | ((*(from+1) & 0xf) << 2); ++ from++; ++ *to++ = *from >> 4 | ((*(from+1) & 0x3) << 4); ++ from++; ++ *to++ = (*from++ >> 2) & 0x3f; ++ } ++ *to = 0; ++ break; ++ case 3: /* normal */ ++ if (length > 1) ++ memcpy(to, from, length); ++ to[length] = 0; ++ break; ++ } ++} ++ ++/* IPMI V1.5 Section 30 */ ++static const int exps[] = ++ { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; ++ ++/* Return 0 for fan, 2 for temp, 3 for voltage ++ We could make it variable based on the accuracy (= log10(m * 10**k2)); ++ this would work for /proc output, however libsensors resolution ++ is statically set in lib/chips.c */ ++static int decplaces(struct sdrdata *sd) ++{ ++ switch (sd->stype) { ++ case STYPE_TEMP: ++ return 2; ++ case STYPE_CURR: ++ case STYPE_VOLT: ++ return 3; ++ case STYPE_FAN: ++ default: ++ return 0; ++ } ++} ++ ++/* convert a raw value to a reading. IMPI V1.5 Section 30 */ ++static long conv_val(int value, struct sdrdata *sd) ++{ ++ u8 k1, k2; ++ long r; ++ ++ r = value * sd->m; ++ k1 = sd->k & 0x0f; ++ k2 = sd->k >> 4; ++ if (k1 < 8) ++ r += sd->b * exps[k1]; ++ else ++ r += sd->b / exps[16 - k1]; ++ r *= exps[decplaces(sd)]; ++ if (k2 < 8) { ++ if (sd->linear != 7) ++ r *= exps[k2]; ++ else ++ /* this will always truncate to 0: r = 1 / (exps[k2] * r); */ ++ r = 0; ++ } else { ++ if (sd->linear != 7) ++ r /= exps[16 - k2]; ++ else { ++ if (r != 0) ++ /* 1 / x * 10 ** (-m) == 10 ** m / x */ ++ r = exps[16 - k2] / r; ++ else ++ r = 0; ++ } ++ } ++ ++ return r; ++} ++ ++static const char *threshold_text[] = { ++ "upper non-recoverable threshold", ++ "upper critical threshold", ++ "upper non-critical threshold", ++ "lower non-recoverable threshold", ++ "lower critical threshold", ++ "lower non-critical threshold", ++ "positive-going hysteresis", ++ "negative-going hysteresis" /* unused */ ++}; ++ ++/* select two out of the 8 possible readable thresholds, and place indexes into the limits ++ array into lim1 and lim2. Set writable flags */ ++static void ipmisensors_select_thresholds(struct sdrdata *sd) ++{ ++ u8 capab = sd->capab; ++ u16 mask = sd->thresh_mask; ++ int tmp; ++ ++ sd->lim1 = -1; ++ sd->lim2 = -1; ++ sd->lim1_write = 0; ++ sd->lim2_write = 0; ++ ++ if (((capab & 0x0c) == 0x04) || /* readable thresholds ? */ ++ ((capab & 0x0c) == 0x08)) { ++ /* select upper threshold */ ++ if (mask & 0x10) { /* upper crit */ ++ sd->lim1 = 1; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x1000)) ++ sd->lim1_write = 1; ++ } else if (mask & 0x20) { /* upper non-recov */ ++ sd->lim1 = 0; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x2000)) ++ sd->lim1_write = 1; ++ } else if (mask & 0x08) { /* upper non-crit */ ++ sd->lim1 = 2; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0800)) ++ sd->lim1_write = 1; ++ } ++ ++ /* select lower threshold */ ++ if ((((capab & 0x30) == 0x10) || /* readable ? */ ++ ((capab & 0x30) == 0x20)) && /* pos hyst */ ++ sd->stype == STYPE_TEMP) ++ sd->lim2 = 6; ++ else if (mask & 0x02) { /* lower crit */ ++ sd->lim2 = 4; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0200)) ++ sd->lim2_write = 1; ++ } else if (mask & 0x04) { /* lower non-recov */ ++ sd->lim2 = 3; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0400)) ++ sd->lim2_write = 1; ++ } else if (mask & 0x01) { /* lower non-crit */ ++ sd->lim2 = 5; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0100)) ++ sd->lim2_write = 1; ++ } ++ } ++ ++ /* swap lim1/lim2 if m < 0 or function is 1/x (but not both!) */ ++ if ((sd->m < 0 && sd->linear != 7) || (sd->m >= 0 && sd->linear == 7)) { ++ tmp = sd->lim1; ++ sd->lim1 = sd->lim2; ++ sd->lim2 = tmp; ++ } ++ ++ if (sd->lim1 >= 0) ++ printk(KERN_INFO "ipmisensors: using %s for upper limit\n", ++ threshold_text[sd->lim1]); ++ else ++ printk(KERN_DEBUG "ipmisensors: no readable upper limit\n"); ++ ++ if (sd->lim2 >= 0) ++ printk(KERN_INFO "ipmisensors: using %s for lower limit\n", ++ threshold_text[sd->lim2]); ++ else ++ printk(KERN_DEBUG "ipmisensors: no readable lower limit\n"); ++} ++ ++/************* sysfs callback functions *********/ ++static ssize_t show_update_period(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ ++ return snprintf(buf, 20, "%d\n", aattr->bmc->update_period); ++} ++ ++static ssize_t store_update_period(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ ++ aattr->bmc->update_period = simple_strtoul(buf, NULL, 10);; ++ return count; ++}; ++ ++static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ return snprintf(buf, 20, "%ld\n", ++ conv_val(sattr->sdr->reading, sattr->sdr)); ++} ++ ++static ssize_t show_sensor_max(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ long max = 0; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ if (sattr->sdr->lim1 >= 0) ++ max = conv_val(sattr->sdr->limits[sattr->sdr->lim1], ++ sattr->sdr); ++ return snprintf(buf, 20, "%ld\n", max); ++} ++ ++static ssize_t show_sensor_min(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ long min = 0; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ if (sattr->sdr->lim2 >= 0) ++ min = conv_val(sattr->sdr->limits[sattr->sdr->lim2], ++ sattr->sdr); ++ return snprintf(buf, 20, "%ld\n", min); ++}; ++ ++static ssize_t show_sensor_label(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ u8 label[SDR_MAX_UNPACKED_ID_LENGTH]; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ ipmisensors_sprintf(label, sattr->sdr->id, sattr->sdr->string_type, ++ sattr->sdr->id_length); ++ return snprintf(buf, 20, "%s\n", label); ++}; ++ ++static ssize_t store_sensor_max(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ long val = simple_strtoul(buf, NULL, 10); ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ printk(KERN_DEBUG "ipmisensors: set max on sensor #%d to %ld", ++ sattr->sdr->number, val); ++ ipmisensors_set_sensor_threshold(sattr->sdr->bmc, sattr->sdr->number, ++ val, sattr->sdr->lim1); ++ return count; ++}; ++ ++static ssize_t store_sensor_min(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ long val = simple_strtoul(buf, NULL, 10); ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ printk(KERN_DEBUG "ipmisensors: set min on sensor #%d to %ld", ++ sattr->sdr->number, val); ++ ipmisensors_set_sensor_threshold(sattr->sdr->bmc, sattr->sdr->number, ++ val, sattr->sdr->lim2); ++ return count; ++}; ++ ++static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ return snprintf(buf, 20, "%d\n", aattr->bmc->alarms); ++}; ++ ++static ssize_t show_name(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ return snprintf(buf, 20, "%s\n", driver_data.driver_name); ++}; ++ ++/* work function to build the sysfs entries using the ipmi sdrs */ ++static void ipmisensors_build_sysfs(struct work_struct *work) ++{ ++ int temps = 0, volts = 0, currs = 0, fans = 0; ++ struct sdrdata *cursor, *next; ++ struct ipmisensors_bmc_data *bmc = container_of(work, struct ipmisensors_bmc_data, sysfs_work); ++ ++ /* find and create entries for each sdr data struct */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; ++ ++ cursor->attr_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ cursor->attr_max_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ cursor->attr_min_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ ++ if (cursor->id_length > 0) { ++ cursor->attr_label_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ ++ if (cursor->attr_label_name == NULL) { ++ printk(KERN_INFO ++ "ipmisensors: Out of memory (kmalloc failed)"); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ return; ++ } ++ } ++ ++ if (cursor->attr_name == NULL || cursor->attr_max_name == NULL ++ || cursor->attr_min_name == NULL ++ || cursor->attr_label_name == NULL) { ++ printk(KERN_INFO ++ "ipmisensors: Out of memory (kmalloc failed)"); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ return; ++ } ++ ++ switch (cursor->stype) { ++ case (STYPE_TEMP): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "temp%d_input", ++temps); ++ /* create min, max attributes */ ++ snprintf(cursor->attr_max_name, MAX_FILENAME_LENGTH, ++ "temp%d_max", temps); ++ snprintf(cursor->attr_min_name, MAX_FILENAME_LENGTH, ++ "temp%d_min", temps); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "temp%d_label", temps); ++ break; ++ case (STYPE_VOLT): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "in%d_input", ++volts); ++ /* create min, max attributes */ ++ snprintf(cursor->attr_max_name, MAX_FILENAME_LENGTH, ++ "in%d_max", volts); ++ snprintf(cursor->attr_min_name, MAX_FILENAME_LENGTH, ++ "in%d_min", volts); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "in%d_label", volts); ++ break; ++ case (STYPE_CURR): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "curr%d_input", ++currs); ++ /* create min, max attributes */ ++ sprintf(cursor->attr_max_name, "curr%d_max", currs); ++ sprintf(cursor->attr_min_name, "curr%d_min", currs); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "curr%d_label", currs); ++ break; ++ case (STYPE_FAN): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "fan%d_input", ++fans); ++ /* create min, max attributes */ ++ sprintf(cursor->attr_max_name, "fan%d_max", fans); ++ sprintf(cursor->attr_min_name, "fan%d_min", fans); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "fan%d_label", fans); ++ break; ++ default: ++ printk(KERN_INFO "ipmisensors: unkown sensor type\n"); ++ continue; ++ } ++ ++ cursor->attr.dev_attr.attr.name = cursor->attr_name; ++ cursor->attr.dev_attr.attr.mode = S_IRUGO; ++ cursor->attr.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr.dev_attr.show = show_sensor; ++ cursor->attr.dev_attr.store = NULL; ++ cursor->attr.sdr = cursor; ++ ++ cursor->attr_min.dev_attr.attr.name = cursor->attr_min_name; ++ cursor->attr_min.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_min.dev_attr.show = show_sensor_min; ++ cursor->attr_min.sdr = cursor; ++ ++ if (cursor->lim2_write) { ++ printk(KERN_INFO ++ "ipmisensors: You have a writable sensor threshold! Send me an e-mail at .\n"); ++ cursor->attr_min.dev_attr.store = store_sensor_min; ++ cursor->attr_min.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ } else { ++ cursor->attr_min.dev_attr.store = NULL; ++ cursor->attr_min.dev_attr.attr.mode = S_IRUGO; ++ } ++ ++ cursor->attr_max.dev_attr.attr.name = cursor->attr_max_name; ++ cursor->attr_max.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_max.dev_attr.show = show_sensor_max; ++ cursor->attr_max.sdr = cursor; ++ ++ if (cursor->lim1_write) { ++ printk(KERN_INFO ++ "ipmisensors: You have a writable sensor threshold! Send me an e-mail at .\n"); ++ cursor->attr_max.dev_attr.store = store_sensor_max; ++ cursor->attr_max.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ } else { ++ cursor->attr_max.dev_attr.store = NULL; ++ cursor->attr_max.dev_attr.attr.mode = S_IRUGO; ++ } ++ ++ if (cursor->id_length > 0) { ++ cursor->attr_label.dev_attr.attr.name = ++ cursor->attr_label_name; ++ cursor->attr_label.dev_attr.attr.mode = S_IRUGO; ++ cursor->attr_label.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_label.dev_attr.show = show_sensor_label; ++ cursor->attr_label.dev_attr.store = NULL; ++ cursor->attr_label.sdr = cursor; ++ } ++ ++ printk(KERN_INFO ++ "ipmisensors: registering sensor %d: (type 0x%.2x) " ++ "(fmt=%d; m=%d; b=%d; k1=%d; k2=%d; cap=0x%.2x; mask=0x%.4x)\n", ++ cursor->number, cursor->stype, cursor->format, cursor->m, ++ cursor->b, cursor->k & 0xf, cursor->k >> 4, ++ cursor->capab, cursor->thresh_mask); ++ ++ if (cursor->id_length > 0) { ++ ipmisensors_sprintf(id, cursor->id, cursor->string_type, ++ cursor->id_length); ++ switch (cursor->stype) { ++ case (STYPE_TEMP): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label temp%d \"%s\"\n", ++ temps, id); ++ break; ++ case (STYPE_VOLT): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label in%d \"%s\"\n", ++ volts, id); ++ break; ++ case (STYPE_CURR): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label curr%d \"%s\"\n", ++ currs, id); ++ break; ++ case (STYPE_FAN): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label fan%d \"%s\"\n", ++ fans, id); ++ break; ++ } ++ } ++ ++ ipmisensors_select_thresholds(cursor); ++ ++ if (cursor->linear != 0 && cursor->linear != 7) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: nonlinear function 0x%.2x unsupported, expect bad results\n", ++ cursor->number, cursor->linear); ++ } ++ ++ if ((cursor->format & 0x03) == 0x02) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: 1's complement format unsupported, expect bad results\n", ++ cursor->number); ++ } else if ((cursor->format & 0x03) == 0x03) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: threshold sensor only, no readings available", ++ cursor->number); ++ } ++ ++ if (cursor->lim1_write || cursor->lim2_write) ++ cursor->attr.dev_attr.attr.mode = 0644; ++ else ++ cursor->attr.dev_attr.attr.mode = 0444; ++ ++ if (device_create_file(bmc->dev, &cursor->attr.dev_attr) < 0 ++ || device_create_file(bmc->dev, ++ &cursor->attr_min.dev_attr) < 0 ++ || device_create_file(bmc->dev, ++ &cursor->attr_max.dev_attr) < 0 ++ || (cursor->id_length > ++ 0 ? device_create_file(bmc->dev, ++ &cursor->attr_label.dev_attr) < ++ 0 : 0) ++ ) { ++ printk(KERN_INFO ++ "ipmisensors: sysfs file creation failed for SDR %d (%s).\n", ++ cursor->number, cursor->id); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ return; ++ } ++ } ++ ++ bmc->alarms_attr.dev_attr.attr.name = "alarms"; ++ bmc->alarms_attr.dev_attr.attr.mode = S_IRUGO; ++ bmc->alarms_attr.dev_attr.attr.owner = THIS_MODULE; ++ bmc->alarms_attr.dev_attr.show = show_alarms; ++ bmc->alarms_attr.dev_attr.store = NULL; ++ bmc->alarms_attr.bmc = bmc; ++ ++ if (device_create_file(bmc->dev, &bmc->alarms_attr.dev_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'alarms'"); ++ return; ++ } ++ ++ bmc->name_attr.attr.name = "name"; ++ bmc->name_attr.attr.mode = S_IRUGO; ++ bmc->name_attr.attr.owner = THIS_MODULE; ++ bmc->name_attr.show = show_name; ++ ++ if (device_create_file(bmc->dev, &bmc->name_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'name'"); ++ return; ++ } ++ ++ bmc->update_attr.dev_attr.attr.name = "update_period"; ++ bmc->update_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ bmc->update_attr.dev_attr.attr.owner = THIS_MODULE; ++ bmc->update_attr.dev_attr.show = show_update_period; ++ bmc->update_attr.dev_attr.store = store_update_period; ++ bmc->update_attr.bmc = bmc; ++ ++ if (device_create_file(bmc->dev, &bmc->update_attr.dev_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'update_period'"); ++ return; ++ } ++ ++ printk(KERN_INFO ++ "ipmisensors: registered %d temp, %d volt, %d current, %d fan sensors\n", ++ temps, volts, currs, fans); ++ ++ /* This completes the initialization. We can now kickoff the ++ * periodic update of the bmc sensor's values by scheduling ++ * the first work. ++ */ ++ queue_work(ipmisensors_workqueue, &bmc->update_work.work); ++ ++} ++ ++/** ++ * Process an SDR response message, save the SDRs we like in the sdr ++ * list for the given BMC. ++ * ++ * @bmc: the bmc the message is from ++ * @msg: the IPMI SDR response message ++ */ ++static void ipmisensors_rcv_sdr_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ u16 record; ++ int type; ++ int stype; ++ int id_length; ++ int i; ++ int ipmi_ver = 0; ++ unsigned char *data; ++ u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; ++ struct sdrdata *sdr; ++ ++ if (msg->data[0] != 0) { ++ /* cut request in half and try again */ ++ bmc->ipmi_sdr_partial_size /= 2; ++ if (bmc->ipmi_sdr_partial_size < 8) { ++ printk(KERN_INFO ++ "ipmisensors: IPMI buffers too small, giving up\n"); ++ bmc->state = STATE_DONE; ++ return; ++ } ++ printk(KERN_DEBUG ++ "ipmisensors: Reducing SDR request size to %d\n", ++ bmc->ipmi_sdr_partial_size); ++ ++ ipmisensors_get_sdr(bmc, 0, 0, 0); ++ bmc->state = STATE_SDR; ++ return; ++ } ++ if (bmc->ipmi_sdr_partial_size < IPMI_SDR_SIZE) { ++ if (bmc->rx_msg_data_offset == 0) { ++ memcpy(bmc->rx_msg_data, msg->data, ++ bmc->ipmi_sdr_partial_size + 3); ++ bmc->rx_msg_data_offset = ++ bmc->ipmi_sdr_partial_size + 3; ++ } else { ++ memcpy(bmc->rx_msg_data + bmc->rx_msg_data_offset, ++ msg->data + 3, bmc->ipmi_sdr_partial_size); ++ bmc->rx_msg_data_offset += bmc->ipmi_sdr_partial_size; ++ } ++ if (bmc->rx_msg_data_offset > bmc->rx_msg_data[7] + 7) { ++ /* got last chunk */ ++ bmc->rx_msg_data_offset = 0; ++ data = bmc->rx_msg_data; ++ } else { ++ /* get more */ ++ record = ++ (bmc->rx_msg_data[4] << 8) | bmc->rx_msg_data[3]; ++ ipmisensors_get_sdr(bmc, bmc->resid, record, ++ bmc->rx_msg_data_offset - 3); ++ bmc->state = STATE_SDR; ++ return; ++ } ++ } else { ++ /* got it in one chunk */ ++ data = msg->data; ++ } ++ ++ bmc->nextrecord = (data[2] << 8) | data[1]; ++ ++ /* If the ipmi version is 0.9 we have to remap some things. ++ * Yes this is very ugly, but we aren't the ones who ++ * implemented an incomplete spec! ++ */ ++ ipmi_ver = data[5]; ++ ++ type = data[6]; ++ /* known SDR type */ ++ if (type == 1 || type == 2) { ++ stype = data[(ipmi_ver == 0x90 ? 16 : 15)]; ++ /* known sensor type */ ++ if (stype <= STYPE_MAX) { ++ if (data[(ipmi_ver == 0x90 ? 17 : 16)] != 0x01) { ++ if (type == 1) ++ ipmisensors_sprintf(id, &data[51], ++ data[50] >> 6, ++ data[50] & 0x1f); ++ else ++ ipmisensors_sprintf(id, ++ &data[(ipmi_ver == ++ 0x90 ? 30 : ++ 35)], ++ data[(ipmi_ver == ++ 0x90 ? 29 : ++ 34)] >> 6, ++ data[(ipmi_ver == ++ 0x90 ? 29 : ++ 34)] & 0x1f); ++ printk(KERN_INFO ++ "ipmisensors: skipping non-threshold sensor \"%s\"\n", ++ id); ++ } else { ++ /* add entry to sdrd table */ ++ sdr = ipmisensors_new_sdr(); ++ if (!sdr) { ++ printk(KERN_ERR ++ "ipmisensors: could not allocate memory for new SDR"); ++ return; ++ } ++ sdr->bmc = bmc; ++ sdr->stype = stype; ++ sdr->number = data[10]; ++ sdr->capab = data[(ipmi_ver == 0x90 ? 15 : 14)]; ++ sdr->thresh_mask = ++ (((u16) data[(ipmi_ver == 0x90 ? 21 : 22)]) ++ << 8) | data[21]; ++ if (type == 1) { ++ sdr->format = ++ data[(ipmi_ver == ++ 0x90 ? 22 : 24)] >> 6; ++ sdr->linear = ++ data[(ipmi_ver == ++ 0x90 ? 25 : 26)] & 0x7f; ++ sdr->m = ++ data[(ipmi_ver == 0x90 ? 26 : 27)]; ++ sdr->m |= ((u16) ++ (data ++ [(ipmi_ver == ++ 0x90 ? 27 : 28)] ++ & 0xc0)) << 2; ++ if (sdr->m & 0x0200) { ++ /* sign extend */ ++ sdr->m |= 0xfc00; ++ } ++ sdr->b = ++ data[(ipmi_ver == 0x90 ? 28 : 29)]; ++ sdr->b |= ((u16) ++ (data ++ [(ipmi_ver == ++ 0x90 ? 29 : 30)] ++ & 0xc0)) << 2; ++ if (sdr->b & 0x0200) { ++ /* sign extend */ ++ sdr->b |= 0xfc00; ++ } ++ sdr->k = ++ data[(ipmi_ver == 0x90 ? 31 : 32)]; ++ sdr->nominal = ++ data[(ipmi_ver == 0x90 ? 33 : 34)]; ++ for (i = 0; i < SDR_LIMITS; i++) { ++ /* assume readable */ ++ sdr->limits[i] = ++ data[(ipmi_ver == ++ 0x90 ? 40 : 39) + i]; ++ } ++ sdr->string_type = data[50] >> 6; ++ id_length = data[50] & 0x1f; ++ memcpy(sdr->id, &data[51], id_length); ++ sdr->id_length = id_length; ++ } else { ++ sdr->m = 1; ++ sdr->b = 0; ++ sdr->k = 0; ++ sdr->string_type = ++ data[(ipmi_ver == ++ 0x90 ? 29 : 34)] >> 6; ++ id_length = data[34] & 0x1f; ++ if (id_length > 0) { ++ memcpy(sdr->id, ++ &data[(ipmi_ver == ++ 0x90 ? 30 : 35)], ++ id_length); ++ } ++ sdr->id_length = id_length; ++ /* limits?? */ ++ if (ipmi_ver == 0x90) { ++ memcpy(sdr->id, ++ &data[30], id_length); ++ sdr->id_length = id_length; ++ } ++ } ++ ipmisensors_add_sdr(bmc, sdr); ++ } ++ } ++ /* peek at the other SDR types */ ++ } else if (type == 0x10 || type == 0x11 || type == 0x12) { ++ ipmisensors_sprintf(id, data + 19, data[18] >> 6, ++ data[18] & 0x1f); ++ if (type == 0x10) { ++ printk(KERN_INFO ++ "ipmisensors: Generic Device acc=0x%x; slv=0x%x; lun=0x%x; type=0x%x; \"%s\"\n", ++ data[8], data[9], data[10], data[13], id); ++ } else if (type == 0x11) { ++ printk(KERN_INFO ++ "ipmisensors: FRU Device acc=0x%x; slv=0x%x; log=0x%x; ch=0x%x; type=0x%x; \"%s\"\n", ++ data[8], data[9], data[10], data[11], data[13], ++ id); ++ } else { ++ printk(KERN_INFO ++ "ipmisensors: Mgmt Ctllr Device slv=0x%x; \"%s\"\n", ++ data[8], id); ++ } ++ } else if (type == 0x14) { ++ printk(KERN_INFO ++ "ipmisensors: Message Channel Info Records:\n"); ++ for (i = 0; i < 8; i++) { ++ printk(KERN_INFO "ipmisensors: Channel %d info 0x%x\n", ++ i, data[9 + i]); ++ } ++ } else { ++ printk(KERN_INFO "ipmisensors: Skipping SDR type 0x%x\n", type); ++ } ++ if (ipmi_ver != 0x90) { ++ if (bmc->nextrecord >= 6224) { ++ /*YJ stop sensor scan on poweredge 1750 */ ++ bmc->nextrecord = 0xffff; ++ } ++ } ++ ++ if (bmc->nextrecord == 0xFFFF) { ++ if (bmc->sdr_count == 0) { ++ printk(KERN_INFO ++ "ipmisensors: No recognized sensors found.\n"); ++ bmc->state = STATE_DONE; ++ } else { ++ printk(KERN_INFO "ipmisensors: all sensors detected\n"); ++ bmc->state = STATE_SYSTABLE; ++ ++ /* Schedule sysfs build/registration work */ ++ INIT_WORK(&bmc->sysfs_work, ipmisensors_build_sysfs); ++ queue_work(ipmisensors_workqueue, &bmc->sysfs_work); ++ } ++ } else { ++ ipmisensors_get_sdr(bmc, 0, bmc->nextrecord, 0); ++ bmc->state = STATE_SDR; ++ } ++} ++ ++/** ++ * Process incoming messages based on internal state ++ * ++ * @bmc: the bmc the message is from. ++ * @msg: the ipmi message to process. ++ */ ++static void ipmisensors_rcv_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ switch (bmc->state) { ++ case STATE_INIT: ++ case STATE_RESERVE: ++ bmc->resid = (((u16) msg->data[2]) << 8) | msg->data[1]; ++ ++ printk(KERN_DEBUG "ipmisensors: Got first resid 0x%.4x\n", ++ bmc->resid); ++ ++ ipmisensors_get_sdr(bmc, 0, 0, 0); ++ bmc->state = STATE_SDR; ++ break; ++ ++ case STATE_SDR: ++ case STATE_SDRPARTIAL: ++ ipmisensors_rcv_sdr_msg(bmc, msg); ++ break; ++ ++ case STATE_READING: ++ ipmisensors_rcv_reading_msg(bmc, msg); ++ break; ++ ++ case STATE_UNCANCEL: ++ bmc->resid = (((u16) msg->data[2]) << 8) | msg->data[1]; ++ ++ printk(KERN_DEBUG "ipmisensors: Got new resid 0x%.4x\n", ++ bmc->resid); ++ ++ bmc->rx_msg_data_offset = 0; ++ ipmisensors_get_sdr(bmc, 0, bmc->nextrecord, 0); ++ bmc->state = STATE_SDR; ++ break; ++ ++ case STATE_DONE: ++ case STATE_SYSTABLE: ++ break; ++ default: ++ bmc->state = STATE_INIT; ++ } ++} ++ ++/** ++ * Callback to handle a received IPMI message from a given BMC. ++ * ++ * @msg: the received message. ++ * @handler_data: a pointer to the particular bmc ipmisensors_bmc_data struct. ++ */ ++static void ipmisensors_msg_handler(struct ipmi_recv_msg *msg, ++ void *user_msg_data) ++{ ++ struct ipmisensors_bmc_data *bmc = ++ (struct ipmisensors_bmc_data *)user_msg_data; ++ ++ if (msg->msg.data[0] != 0) ++ printk(KERN_WARNING ++ "ipmisensors: Error 0x%x on cmd 0x%x/0x%x\n", ++ msg->msg.data[0], msg->msg.netfn, msg->msg.cmd); ++ ++ if (bmc != NULL && ipmisensors_intf_registered(bmc->interface_id)) { ++ if (bmc->state == STATE_SDR && ++ msg->msg.data[0] == IPMI_INVALID_RESERVATION_ID) { ++ /* reservation cancelled, get new resid */ ++ if (++bmc->errorcount > 275) { ++ printk(KERN_ERR ++ "ipmisensors: Too many reservations cancelled, giving up\n"); ++ bmc->state = STATE_DONE; ++ } else { ++ printk(KERN_DEBUG ++ "ipmisensors: resid 0x%04x cancelled, getting new one\n", ++ bmc->resid); ++ ++ ipmisensors_reserve_sdr(bmc); ++ bmc->state = STATE_UNCANCEL; ++ } ++ } else if (msg->msg.data[0] != IPMI_CC_NO_ERROR && ++ msg->msg.data[0] != IPMI_ERR_RETURNING_REQ_BYTES && ++ msg->msg.data[0] != IPMI_ERR_PROVIDING_RESPONSE) { ++ printk(KERN_ERR ++ "ipmisensors: Error 0x%x on cmd 0x%x/0x%x; state = %d; probably fatal.\n", ++ msg->msg.data[0], msg->msg.netfn & 0xfe, ++ msg->msg.cmd, bmc->state); ++ } else { ++ printk(KERN_DEBUG "ipmisensors: received message\n"); ++ ipmisensors_rcv_msg(bmc, &msg->msg); ++ } ++ ++ } else { ++ printk(KERN_WARNING ++ "ipmisensors: Response for non-registered BMC\n"); ++ if (bmc != NULL) ++ printk(KERN_DEBUG "ipmisensors: BMC ID: %d\n", ++ bmc->interface_id); ++ else ++ printk(KERN_DEBUG "ipmisensors: BMC NULL!\n"); ++ } ++ ++ ipmi_free_recv_msg(msg); ++} ++ ++/****** IPMI Interface Initialization ******/ ++ ++/** ++ * Return true if the given ipmi interface has been registered. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static int ipmisensors_intf_registered(int ipmi_intf) ++{ ++ int found = 0; ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->interface_id == ipmi_intf) { ++ found++; ++ } ++ } ++ ++ return found; ++} ++ ++/** ++ * Return true if the given BMC has been registered. ++ * ++ * @bmc: The BMC device. ++ */ ++static int ipmisensors_bmc_registered(struct device *bmc) ++{ ++ int found = 0; ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->dev == bmc) { ++ found++; ++ } ++ } ++ ++ return found; ++} ++ ++/** ++ * Register new IPMI BMC interface. Interface indpendent callback created ++ * for flexibility in adding new types of interface callbacks in future. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static void ipmisensors_register_bmc(int ipmi_intf, struct ipmi_addr *address) ++{ ++ int error; ++ ++ /* allocate a new ipmisensors_bmc_data struct */ ++ ++ struct ipmisensors_bmc_data *bmc = (struct ipmisensors_bmc_data *) ++ kmalloc(sizeof(struct ipmisensors_bmc_data), GFP_KERNEL); ++ ++ /* initialize members */ ++ INIT_LIST_HEAD(&bmc->sdrs); ++ bmc->interface_id = ipmi_intf; ++ ++ bmc->address = *address; ++ ++ bmc->sdr_count = 0; ++ bmc->msgid = 0; ++ bmc->ipmi_sdr_partial_size = IPMI_CHUNK_SIZE; ++ bmc->state = STATE_INIT; ++ bmc->errorcount = 0; ++ bmc->rx_msg_data_offset = 0; ++ bmc->dev = ipmi_get_bmcdevice(ipmi_intf); ++ ++ /* default to 3 second min update interval */ ++ bmc->update_period = 3; ++ ++ if (bmc->dev == NULL) { ++ printk(KERN_ERR ++ "ipmisensors: Error, couldn't get BMC device for interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Create IPMI messaging interface user */ ++ error = ipmi_create_user(bmc->interface_id, &driver_data.ipmi_hndlrs, ++ bmc, &bmc->user); ++ if (error < 0) { ++ printk(KERN_ERR ++ "ipmisensors: Error, unable to register user with ipmi interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Register the BMC as a HWMON class device */ ++ bmc->class_dev = hwmon_device_register(bmc->dev); ++ ++ if (IS_ERR(bmc->class_dev)) { ++ printk(KERN_ERR ++ "ipmisensors: Error, unable to register hwmon class device for interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Register the BMC in the driver */ ++ if (ipmisensors_bmc_registered(bmc->dev)) { ++ printk(KERN_ERR ++ "ipmisensors: BMC on interface %d already registered\n", ++ bmc->interface_id); ++ hwmon_device_unregister(bmc->class_dev); ++ kfree(bmc); ++ return; ++ } ++ ++ ipmi_get_version(bmc->user, &bmc->ipmi_version_major, ++ &bmc->ipmi_version_minor); ++ ++ /* finally add the new bmc data to the bmc data list */ ++ list_add_tail(&bmc->list, &driver_data.bmc_data); ++ driver_data.interfaces++; ++ ++ printk(KERN_INFO ++ "ipmisensors: Registered IPMI %d.%d BMC over interface %d\n", ++ bmc->ipmi_version_major, ++ bmc->ipmi_version_minor, bmc->interface_id); ++ ++ /* Send a reserve SDR command to the bmc */ ++ ipmisensors_reserve_sdr(bmc); ++ ++ /* initialize the bmc's update work struct */ ++ INIT_DELAYED_WORK(&bmc->update_work, ipmisensors_update_bmc); ++} ++ ++/** ++ * Callback for when an IPMI BMC is gone. Interface indpendent callback created ++ * for flexibility in adding new types of interface callbacks in future. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static void ipmisensors_unregister_bmc(int ipmi_intf) ++{ ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->interface_id == ipmi_intf) { ++ list_del(&cursor->list); ++ printk(KERN_DEBUG ++ "ipmisensors: cancelling queued work\n"); ++ /* cancel update work queued for this bmc */ ++ cancel_delayed_work(&cursor->update_work); ++ printk(KERN_DEBUG ++ "ipmisensors: waiting for update to finish\n"); ++ /* wait for readings to finish */ ++ while (cursor->state != STATE_DONE) ; ++ ++ device_remove_file(cursor->dev, ++ &cursor->alarms_attr.dev_attr); ++ device_remove_file(cursor->dev, ++ &cursor->update_attr.dev_attr); ++ hwmon_device_unregister(cursor->class_dev); ++ ipmisensors_sdr_cleanup(cursor); ++ ipmi_destroy_user(cursor->user); ++ ++ printk(KERN_INFO ++ "ipmisensors: Unegistered IPMI interface %d\n", ++ cursor->interface_id); ++ ++ kfree(cursor); ++ driver_data.interfaces--; ++ } ++ } ++ ++} ++ ++/** ++ * Unregister all registered bmcs. ++ */ ++static void ipmisensors_unregister_bmc_all(void) ++{ ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ list_del(&cursor->list); ++ ++ /* cancel update work queued for this bmc */ ++ printk(KERN_DEBUG "ipmisensors: cancelling queued work\n"); ++ cancel_delayed_work(&cursor->update_work); ++ ++ printk(KERN_DEBUG ++ "ipmisensors: waiting for update to finish\n"); ++ /* wait for readings to finish */ ++ while (cursor->state != STATE_DONE) ; ++ ++ device_remove_file(cursor->dev, &cursor->alarms_attr.dev_attr); ++ device_remove_file(cursor->dev, &cursor->update_attr.dev_attr); ++ hwmon_device_unregister(cursor->class_dev); ++ ipmisensors_sdr_cleanup(cursor); ++ ipmi_destroy_user(cursor->user); ++ ++ printk(KERN_INFO ++ "ipmisensors: Unegistered IPMI interface %d\n", ++ cursor->interface_id); ++ ++ kfree(cursor); ++ } ++ ++ driver_data.interfaces = 0; ++} ++ ++/** ++ * Callback for when a new IPMI SMI type interface is found. ++ * ++ * @if_num: The IPMI interface number. ++ */ ++static void ipmisensors_new_smi(int if_num, struct device *dev) ++{ ++ struct ipmi_addr smi_address = { ++ IPMI_SYSTEM_INTERFACE_ADDR_TYPE, ++ IPMI_BMC_CHANNEL, ++ {0}, ++ }; ++ ++ /* calls the generic new interface function */ ++ ipmisensors_register_bmc(if_num, &smi_address); ++} ++ ++/** ++ * Callback for when an exisiting IPMI SMI type interface is gone. ++ * ++ * @if_num: The IPMI interface number. ++ */ ++static void ipmisensors_smi_gone(int if_num) ++{ ++ if (driver_data.interfaces > 0) { ++ ipmisensors_unregister_bmc(if_num); ++ } ++} ++ ++/** ++ * Initialize the module. ++ */ ++static int __init ipmisensors_init(void) ++{ ++ int error; ++ printk(KERN_INFO "ipmisensors - IPMI BMC sensors interface\n"); ++ ++ /* init cache managers */ ++ driver_data.sdrdata_cache = ++ kmem_cache_create("ipmisensors_sdrdata", sizeof(struct sdrdata), 0, ++ 0, NULL, NULL); ++ driver_data.sysfsattr_cache = ++ kmem_cache_create("ipmisensors_sysfsattr", ++ sizeof(struct ipmisensors_device_attribute), 0, 0, ++ NULL, NULL); ++ ++ if (!driver_data.sdrdata_cache || !driver_data.sysfsattr_cache) { ++ if (driver_data.sdrdata_cache) ++ kmem_cache_destroy(driver_data.sdrdata_cache); ++ if (driver_data.sysfsattr_cache) ++ kmem_cache_destroy(driver_data.sysfsattr_cache); ++ return -ENOMEM; ++ } ++ ++ /* register IPMI interface callback(s) */ ++ error = ipmi_smi_watcher_register(&driver_data.smi_watcher); ++ if (error) { ++ printk(KERN_WARNING ++ "ipmisensors: can't register smi watcher\n"); ++ return error; ++ } ++ ++ /* create work queue, keep it simple, single-threaded */ ++ ipmisensors_workqueue = ++ create_singlethread_workqueue("ipmisensors_workqueue"); ++ ++ return 0; ++} ++ ++/** ++ * Cleanup ++ */ ++static void ipmisensors_cleanup(void) ++{ ++ /* start cleanup */ ++ cleanup = 1; ++ ++ /* unregister bmcs */ ++ printk(KERN_DEBUG "ipmisensors: unregister bmcs\n"); ++ ipmi_smi_watcher_unregister(&driver_data.smi_watcher); ++ ipmisensors_unregister_bmc_all(); ++ ++ /* flush & destroy work queue */ ++ printk(KERN_DEBUG "ipmisensors: destroy workqueue\n"); ++ flush_workqueue(ipmisensors_workqueue); ++ destroy_workqueue(ipmisensors_workqueue); ++ ++ /* remove cache managers */ ++ if (driver_data.sdrdata_cache) ++ kmem_cache_destroy(driver_data.sdrdata_cache); ++ if (driver_data.sysfsattr_cache) ++ kmem_cache_destroy(driver_data.sysfsattr_cache); ++} ++ ++/** ++ * Cleanup and exit the module ++ */ ++static void __exit ipmisensors_exit(void) ++{ ++ ipmisensors_cleanup(); ++ printk(KERN_DEBUG "ipmisensors: cleanup finished\n"); ++} ++ ++MODULE_AUTHOR("Yani Ioannou "); ++MODULE_DESCRIPTION("IPMI BMC sensors"); ++MODULE_LICENSE("GPL"); ++ ++module_init(ipmisensors_init); ++module_exit(ipmisensors_exit); +diff -rduNp linux-2.6.20.3.orig/drivers/hwmon/ipmisensors.h linux-2.6.20.3/drivers/hwmon/ipmisensors.h +--- linux-2.6.20.3.orig/drivers/hwmon/ipmisensors.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.20.3/drivers/hwmon/ipmisensors.h 2007-03-14 14:41:23.000000000 +0100 +@@ -0,0 +1,240 @@ ++/* ++ * ipmisensors.h - lm_sensors interface to IPMI sensors. ++ * ++ * Copyright (C) 2004-2006 Yani Ioannou ++ * ++ * Adapted from bmcsensors (lm-sensors for linux 2.4) ++ * bmcsensors (C) Mark D. Studebaker ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* SDR defs */ ++#define STYPE_TEMP 0x01 ++#define STYPE_VOLT 0x02 ++#define STYPE_CURR 0x03 ++#define STYPE_FAN 0x04 ++ ++#define SDR_LIMITS 8 ++#define SDR_MAX_ID_LENGTH 16 ++#define SDR_MAX_UNPACKED_ID_LENGTH ((SDR_MAX_ID_LENGTH * 4 / 3) + 2) ++ ++/* the last sensor type we are interested in */ ++#define STYPE_MAX 4 ++ ++#define IPMI_SDR_SIZE 67 ++#define IPMI_CHUNK_SIZE 16 ++ ++#define MAX_FILENAME_LENGTH 30 ++ ++struct ipmisensors_device_attribute { ++ struct device_attribute dev_attr; ++ struct sdrdata *sdr; ++}; ++#define to_ipmisensors_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct ipmisensors_device_attribute, dev_attr) ++ ++#define IPMISENSORS_DEVICE_ATTR(_name,_mode,_show,_store,_index) \ ++struct ipmisensors_attribute sensor_dev_attr_##_name = { \ ++ .dev_attr = __ATTR(_name,_mode,_show,_store), \ ++ .index = _index, \ ++} ++ ++struct ipmisensors_bmc_device_attribute { ++ struct device_attribute dev_attr; ++ struct ipmisensors_bmc_data *bmc; ++}; ++#define to_ipmisensors_bmc_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct ipmisensors_bmc_device_attribute, dev_attr) ++ ++/** ++ * &struct_sdrdata stores the IPMI Sensor Data Record (SDR) data, as recieved from the BMC, along with the corresponding sysfs attributes ++ */ ++struct sdrdata { ++ struct list_head list; ++ /* retrieved from SDR, not expected to change */ ++ /* Sensor Type Code */ ++ u8 stype; ++ u8 number; ++ /* Sensor Capability Code */ ++ u8 capab; ++ u16 thresh_mask; ++ u8 format; ++ u8 linear; ++ s16 m; ++ s16 b; ++ u8 k; ++ u8 nominal; ++ u8 limits[SDR_LIMITS]; ++ /* index into limits for reported upper and lower limit */ ++ int lim1, lim2; ++ u8 lim1_write, lim2_write; ++ u8 string_type; ++ u8 id_length; ++ u8 id[SDR_MAX_ID_LENGTH]; ++ /* retrieved from reading */ ++ u8 reading; ++ u8 status; ++ u8 thresholds; ++ /* sensor's bmc */ ++ struct ipmisensors_bmc_data *bmc; ++ /* sysfs entries */ ++ struct ipmisensors_device_attribute attr; ++ char *attr_name; ++ struct ipmisensors_device_attribute attr_min; ++ char *attr_min_name; ++ struct ipmisensors_device_attribute attr_max; ++ char *attr_max_name; ++ struct ipmisensors_device_attribute attr_label; ++ char *attr_label_name; ++ ++}; ++ ++/** ++ * &struct_ipmisensors_data stores the data for the ipmisensors driver. ++ */ ++struct ipmisensors_data { ++ /* Driver struct */ ++ char *driver_name; ++ ++ /* Linked list of ipmisensors_bmc_data structs, one for each BMC */ ++ struct list_head bmc_data; ++ ++ /* Number of ipmi interfaces (and hence ipmisensors_data structs). */ ++ int interfaces; ++ ++ /* IPMI kernel interface - SMI watcher */ ++ struct ipmi_smi_watcher smi_watcher; ++ ++ /* IPMI kernel interface - user handlers */ ++ struct ipmi_user_hndl ipmi_hndlrs; ++ ++ /* Cache manager for sdrdata cache */ ++ struct kmem_cache *sdrdata_cache; ++ ++ /* Cache manager for ipmi_sensor_device_attribute cache */ ++ struct kmem_cache *sysfsattr_cache; ++}; ++ ++/** ++ * &states: enumeration of state codes for a bmc specific ipmisensors ++ */ ++enum states { ++ STATE_INIT, ++ STATE_RESERVE, ++ STATE_SDR, ++ STATE_SDRPARTIAL, ++ STATE_READING, ++ STATE_UNCANCEL, ++ STATE_SYSTABLE, ++ STATE_DONE ++}; ++ ++/** ++ * &struct_ipmisensors_bmc_data stores the data for a particular IPMI BMC. ++ */ ++struct ipmisensors_bmc_data { ++ struct list_head list; ++ ++ /* The IPMI interface number */ ++ int interface_id; ++ ++ /* The IPMI address */ ++ struct ipmi_addr address; ++ ++ /* List of sdrdata structs (sdrs) recieved from the BMC */ ++ struct list_head sdrs; ++ ++ /* Count of the number of sdrs stored in the sdr list */ ++ int sdr_count; ++ ++ /* next message id */ ++ int msgid; ++ ++ /* The ipmi interface 'user' used to access this particular bmc */ ++ ipmi_user_t user; ++ ++ /* BMC IPMI Version (major) */ ++ unsigned char ipmi_version_major; ++ ++ /* BMC IPMI Version (minor) */ ++ unsigned char ipmi_version_minor; ++ ++ /* The size of the SDR request message */ ++ int ipmi_sdr_partial_size; ++ ++ /* transmit message buffer */ ++ struct kernel_ipmi_msg tx_message; ++ ++ /* ipmi transmited data buffer */ ++ unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* why the +50 in bmcsensors? */ ++ ++ /* ipmi recieved data buffer */ ++ unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; ++ ++ /* current recieve buffer offset */ ++ int rx_msg_data_offset; ++ ++ /* The id of then next SDR record to read during update cycle */ ++ u16 nextrecord; ++ ++ /* BMC SDR Reservation ID */ ++ u16 resid; ++ ++ /* Alarm status */ ++ u8 alarms; ++ ++ /* The cumalative error count for this bmc */ ++ int errorcount; ++ ++ /* The current state of this bmc w.r.t. ipmisensors (see enum states) */ ++ int state; ++ ++ /* The current sdr for which a reading is pending */ ++ struct sdrdata *current_sdr; ++ ++ /* The BMC's device struct */ ++ struct device *dev; ++ ++ /* hwmon class device */ ++ struct class_device *class_dev; ++ ++ /* hwmon device name */ ++ struct device_attribute name_attr; ++ ++ /* alarms attribute */ ++ struct ipmisensors_bmc_device_attribute alarms_attr; ++ ++ /* update_period attribute */ ++ struct ipmisensors_bmc_device_attribute update_attr; ++ ++ /* lower bound on time between updates (in seconds) */ ++ unsigned int update_period; ++ ++ /* semaphore used to do a headcount of the SDR readings we are waiting ++ * on in a given bmc update */ ++ struct semaphore update_semaphore; ++ ++ /* bmc's work struct for updating sensors */ ++ struct delayed_work update_work; ++ ++ /* bmc's work struct for building the sysfs workqueue */ ++ struct work_struct sysfs_work; ++}; +diff -rduNp linux-2.6.20.3.orig/include/linux/ipmi.h linux-2.6.20.3/include/linux/ipmi.h +--- linux-2.6.20.3.orig/include/linux/ipmi.h 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/include/linux/ipmi.h 2007-03-14 14:23:02.000000000 +0100 +@@ -300,6 +300,9 @@ int ipmi_create_user(unsigned int + safe, too. */ + int ipmi_destroy_user(ipmi_user_t user); + ++/* Get the IPMI BMC's device struct */ ++struct device *ipmi_get_bmcdevice(int ipmi_intf); ++ + /* Get the IPMI version of the BMC we are talking to. */ + void ipmi_get_version(ipmi_user_t user, + unsigned char *major, +diff -rduNp linux-2.6.20.3.orig/include/linux/ipmi_msgdefs.h linux-2.6.20.3/include/linux/ipmi_msgdefs.h +--- linux-2.6.20.3.orig/include/linux/ipmi_msgdefs.h 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.3/include/linux/ipmi_msgdefs.h 2007-03-14 14:23:02.000000000 +0100 +@@ -45,6 +45,7 @@ + + #define IPMI_NETFN_APP_REQUEST 0x06 + #define IPMI_NETFN_APP_RESPONSE 0x07 ++#define IPMI_GET_DEVICE_GUID_CMD 0x08 + #define IPMI_GET_DEVICE_ID_CMD 0x01 + #define IPMI_COLD_RESET_CMD 0x02 + #define IPMI_WARM_RESET_CMD 0x03 +@@ -57,6 +58,11 @@ + #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD 0x2f + #define IPMI_READ_EVENT_MSG_BUFFER_CMD 0x35 + #define IPMI_GET_CHANNEL_INFO_CMD 0x42 ++#define IPMI_RESERVE_SDR 0x22 ++#define IPMI_GET_SDR 0x23 ++#define IPMI_GET_SENSOR_STATE_READING 0x2D ++#define IPMI_SET_SENSOR_HYSTERESIS 0x24 ++#define IPMI_SET_SENSOR_THRESHOLD 0x26 + + #define IPMI_NETFN_STORAGE_REQUEST 0x0a + #define IPMI_NETFN_STORAGE_RESPONSE 0x0b +@@ -79,10 +85,13 @@ + #define IPMI_NODE_BUSY_ERR 0xc0 + #define IPMI_INVALID_COMMAND_ERR 0xc1 + #define IPMI_TIMEOUT_ERR 0xc3 ++#define IPMI_INVALID_RESERVATION_ID 0xc5 + #define IPMI_ERR_MSG_TRUNCATED 0xc6 + #define IPMI_REQ_LEN_INVALID_ERR 0xc7 + #define IPMI_REQ_LEN_EXCEEDED_ERR 0xc8 + #define IPMI_NOT_IN_MY_STATE_ERR 0xd5 /* IPMI 2.0 */ ++#define IPMI_ERR_RETURNING_REQ_BYTES 0xca ++#define IPMI_ERR_PROVIDING_RESPONSE 0xce + #define IPMI_LOST_ARBITRATION_ERR 0x81 + #define IPMI_BUS_ERR 0x82 + #define IPMI_NAK_ON_WRITE_ERR 0x83 diff --git a/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.22.1-007-ipmisensors-20070314-1214.patch b/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.22.1-007-ipmisensors-20070314-1214.patch new file mode 100644 index 0000000000..5fe74954f3 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.22.1-007-ipmisensors-20070314-1214.patch @@ -0,0 +1,1914 @@ +diff -rduNp linux-2.6.22.1.oorig2/drivers/char/ipmi/ipmi_msghandler.c linux-2.6.22.1/drivers/char/ipmi/ipmi_msghandler.c +--- linux-2.6.22.1.oorig2/drivers/char/ipmi/ipmi_msghandler.c 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/drivers/char/ipmi/ipmi_msghandler.c 2007-07-24 14:22:26.000000000 +0200 +@@ -1953,6 +1953,24 @@ static void remove_proc_entries(ipmi_smi + #endif /* CONFIG_PROC_FS */ + } + ++/* ++ * Retrieves the bmc_device struct for a given ipmi interface number (or NULL if none). ++ */ ++struct device *ipmi_get_bmcdevice(int if_num) ++{ ++ ipmi_smi_t intf; ++ mutex_lock(&ipmi_interfaces_mutex); ++ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { ++ if (intf->intf_num == if_num){ ++ mutex_unlock(&ipmi_interfaces_mutex); ++ return &intf->bmc->dev->dev; ++ } ++ } ++ mutex_unlock(&ipmi_interfaces_mutex); ++ ++ return NULL; ++} ++ + static int __find_bmc_guid(struct device *dev, void *data) + { + unsigned char *id = data; +@@ -4196,3 +4214,4 @@ EXPORT_SYMBOL(ipmi_get_my_LUN); + EXPORT_SYMBOL(ipmi_smi_add_proc_entry); + EXPORT_SYMBOL(ipmi_user_set_run_to_completion); + EXPORT_SYMBOL(ipmi_free_recv_msg); ++EXPORT_SYMBOL(ipmi_get_bmcdevice); +diff -rduNp linux-2.6.22.1.oorig2/drivers/hwmon/Kconfig linux-2.6.22.1/drivers/hwmon/Kconfig +--- linux-2.6.22.1.oorig2/drivers/hwmon/Kconfig 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/drivers/hwmon/Kconfig 2007-07-24 14:22:26.000000000 +0200 +@@ -248,6 +248,16 @@ config SENSORS_CORETEMP + sensor inside your CPU. Supported all are all known variants + of Intel Core family. + ++config SENSORS_IPMI ++ tristate "IPMI Hardware Monitoring Support" ++ depends on HWMON && IPMI_HANDLER && EXPERIMENTAL ++ help ++ If you say yes here you get support for sensors monitored by ++ an IPMI baseboard management controller (BMC). ++ ++ This driver can also be built as a module. If so, the module ++ will be called ipmisensors. ++ + config SENSORS_IT87 + tristate "ITE IT87xx and compatibles" + depends on I2C +diff -rduNp linux-2.6.22.1.oorig2/drivers/hwmon/Makefile linux-2.6.22.1/drivers/hwmon/Makefile +--- linux-2.6.22.1.oorig2/drivers/hwmon/Makefile 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/drivers/hwmon/Makefile 2007-07-24 14:22:26.000000000 +0200 +@@ -32,6 +32,7 @@ obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o + obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o + obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o + obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o ++obj-$(CONFIG_SENSORS_IPMI) += ipmisensors.o + obj-$(CONFIG_SENSORS_IT87) += it87.o + obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o + obj-$(CONFIG_SENSORS_LM63) += lm63.o +diff -rduNp linux-2.6.22.1.oorig2/drivers/hwmon/ipmisensors.c linux-2.6.22.1/drivers/hwmon/ipmisensors.c +--- linux-2.6.22.1.oorig2/drivers/hwmon/ipmisensors.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/drivers/hwmon/ipmisensors.c 2007-07-24 14:22:26.000000000 +0200 +@@ -0,0 +1,1552 @@ ++/* ++ * ipmisensors.c - lm-sensors/hwmon interface to IPMI sensors. ++ * ++ * Copyright (C) 2004-2006 Yani Ioannou ++ * ++ * Adapted from bmcsensors (lm-sensors for linux 2.4) ++ * bmcsensors (C) Mark D. Studebaker ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ipmisensors.h" ++ ++/****** Function Prototypes ******/ ++static void ipmisensors_send_message(struct ipmisensors_bmc_data *bmc, ++ long msgid, struct kernel_ipmi_msg *msg); ++static void ipmisensors_reserve_sdr(struct ipmisensors_bmc_data *bmc); ++static void ipmisensors_get_sdr(struct ipmisensors_bmc_data *bmc, u16 res_id, ++ u16 record, u8 offset); ++static void ipmisensors_set_sensor_threshold(struct ipmisensors_bmc_data *bmc, ++ u8 number, int value, ++ int lim_index); ++static void ipmisensors_get_reading(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr); ++static void ipmisensors_msg_handler(struct ipmi_recv_msg *msg, ++ void *user_msg_data); ++static int ipmisensors_intf_registered(int ipmi_intf); ++static int ipmisensors_bmc_registered(struct device *bmc); ++static void ipmisensors_register_bmc(int ipmi_intf, struct ipmi_addr *address); ++static void ipmisensors_unregister_bmc(int ipmi_intf); ++static void ipmisensors_unregister_bmc_all(void); ++static void ipmisensors_new_smi(int if_num, struct device *dev); ++static void ipmisensors_smi_gone(int if_num); ++static void ipmisensors_update_bmc(struct work_struct *); ++static void ipmisensors_cleanup(void); ++ ++/****** Static Vars ******/ ++ ++/* set when module is being removed */ ++static int cleanup = 0; ++ ++/* ipmisensors driver data */ ++static struct ipmisensors_data driver_data = { ++ .driver_name = "bmc", ++ .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data), ++ .interfaces = 0, ++ .smi_watcher = { ++ .owner = THIS_MODULE, ++ .new_smi = ipmisensors_new_smi, ++ .smi_gone = ipmisensors_smi_gone, ++ }, ++ .ipmi_hndlrs = { ++ .ipmi_recv_hndl = ipmisensors_msg_handler, ++ }, ++}; ++ ++/* sensor refresh workqueue */ ++static struct workqueue_struct *ipmisensors_workqueue; ++ ++/****** SDR List Functions ******/ ++/** ++ * Creates a new sdrdata struct, or returns NULL if insufficient memory. ++ */ ++static struct sdrdata *ipmisensors_new_sdr(void) ++{ ++ struct sdrdata *sdr; ++ ++ sdr = kmem_cache_alloc(driver_data.sdrdata_cache, GFP_ATOMIC); ++ if (sdr) { ++ memset(sdr, 0, sizeof(struct sdrdata)); ++ } else { ++ printk(KERN_ERR ++ "ipmisensors: Couldn't allocate memory for new SDR\n"); ++ } ++ ++ return sdr; ++} ++ ++/** ++ * Adds the given sdrdata struct to the given bmc's SDR list. ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static inline void ipmisensors_add_sdr(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr) ++{ ++ list_add(&sdr->list, &bmc->sdrs); ++ printk(KERN_DEBUG ++ "ipmisensors: SDR %d: type 0x%02x (%s)\n", ++ bmc->sdr_count, sdr->stype, sdr->id); ++ bmc->sdr_count++; ++} ++ ++/** ++ * Cleanup the sdr list for the given BMC. ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static void ipmisensors_sdr_cleanup(struct ipmisensors_bmc_data *bmc) ++{ ++ struct sdrdata *cursor, *next; ++ ++ /* find and free each sdr data struct */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ device_remove_file(bmc->dev, &cursor->attr.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_min.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_max.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_label.dev_attr); ++ ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ ++ list_del(&cursor->list); ++ kmem_cache_free(driver_data.sdrdata_cache, cursor); ++ } ++} ++ ++/* worker function for workqueue ipmisensors_workqueue */ ++static void ipmisensors_update_bmc(struct work_struct *work) ++{ ++ struct ipmisensors_bmc_data *bmc = container_of(work, struct ipmisensors_bmc_data, update_work.work); ++ ++ /* don't start an update cycle if one already in progress */ ++ if (bmc->state != STATE_READING) { ++ struct sdrdata *cursor, *next; ++ bmc->state = STATE_READING; ++ printk(KERN_DEBUG "ipmisensors: starting update\n"); ++ ++ /* init semaphore to 1 for update cycle */ ++ sema_init(&bmc->update_semaphore, 1); ++ ++ /* update each sdr reading */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ ipmisensors_get_reading(bmc, cursor); ++ } ++ } ++ ++ /* wait for readings (need timeout?) */ ++ down_interruptible(&bmc->update_semaphore); ++ ++ printk(KERN_DEBUG "ipmisensors: update complete\n"); ++ ++ bmc->state = STATE_DONE; ++ ++ /* if the module isn't cleaning up, schedule another update */ ++ if (!cleanup) ++ queue_delayed_work(ipmisensors_workqueue, &bmc->update_work, ++ bmc->update_period * HZ); ++} ++ ++/****** IPMI Message Sending ******/ ++ ++/** ++ * Send a message to the IPMI BMC ++ * ++ * @bmc: the bmc to send the message to. ++ * @msgid: the message id to use. ++ * @msg: the ipmi message structure. ++ */ ++static void ipmisensors_send_message(struct ipmisensors_bmc_data *bmc, ++ long msgid, struct kernel_ipmi_msg *msg) ++{ ++ if (msg->data == NULL) ++ printk(KERN_DEBUG "ipmisensors: Send 0x%x\n", msg->cmd); ++ else ++ printk(KERN_DEBUG "ipmisensors: Send 0x%x 0x%x 0x%x\n", ++ msg->cmd, msg->data[0], msg->data[1]); ++ ++ /* This should be ipmi_request, but Corey had to remove ++ * that due to it being unused at the moment, as soon as ++ * this makes it into the kernel we should request it be re-instated. ++ */ ++ ipmi_request_settime(bmc->user, &bmc->address, msgid, msg, bmc, 0, ++ -1, 0); ++} ++ ++/** ++ * Compose and send a "reserve SDR" message ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static void ipmisensors_reserve_sdr(struct ipmisensors_bmc_data *bmc) ++{ ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_RESERVE_SDR; ++ bmc->tx_message.data_len = 0; ++ bmc->tx_message.data = NULL; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Componse and send a "get SDR" message ++ * ++ * @bmc: the bmc to send the message to. ++ * @res_id: ++ * @record: ++ * @offset: ++ */ ++static void ipmisensors_get_sdr(struct ipmisensors_bmc_data *bmc, u16 res_id, ++ u16 record, u8 offset) ++{ ++ printk(KERN_DEBUG "ipmisensors: Get SDR 0x%x 0x%x 0x%x\n", ++ res_id, record, offset); ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_GET_SDR; ++ bmc->tx_message.data_len = 6; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = res_id & 0xff; ++ bmc->tx_msg_data[1] = res_id >> 8; ++ bmc->tx_msg_data[2] = record & 0xff; ++ bmc->tx_msg_data[3] = record >> 8; ++ bmc->tx_msg_data[4] = offset; ++ bmc->tx_msg_data[5] = bmc->ipmi_sdr_partial_size; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Compose and send a "set sensor threshold" message ++ * ++ * @bmc: the bmc to send the message to. ++ * @id: the ipmi id number of the sensor. ++ * @value: the new value for the threshold. ++ * @lim_index: the index in the lim[] array for which this value applies. ++ */ ++static void ipmisensors_set_sensor_threshold(struct ipmisensors_bmc_data *bmc, ++ u8 number, int value, ++ int lim_index) ++{ ++ int i; ++ ++ printk(KERN_DEBUG "ipmisensors: Set SDR Threshold %d %d %d\n", ++ number, value, lim_index); ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_SET_SENSOR_THRESHOLD; ++ bmc->tx_message.data_len = 8; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = number & 0xff; ++ bmc->tx_msg_data[1] = 0x01 << lim_index; ++ ++ if (lim_index > 5 || lim_index < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Error - ipmisensors_set_sensor_threshold given invalid lim_index\n"); ++ return; ++ } ++ ++ for (i = 2; i < 8; i++) ++ bmc->tx_msg_data[i] = 0x00; ++ ++ bmc->tx_msg_data[lim_index] = value && 0xff; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Compose and send a "get sensor reading" message for the given sdr. ++ * ++ * @bmc: the bmc to send the message to. ++ * @sdr: the sdr of the sensor to get the reading for. ++ */ ++static void ipmisensors_get_reading(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr) ++{ ++ bmc->tx_message.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST; ++ bmc->tx_message.cmd = IPMI_GET_SENSOR_STATE_READING; ++ bmc->tx_message.data_len = 1; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = sdr->number; ++ bmc->current_sdr = sdr; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++ down_interruptible(&bmc->update_semaphore); ++} ++ ++/****** IPMI Message Receiving ******/ ++ ++/** ++ * Process an sensor reading response message. ++ * ++ * @bmc: the bmc the message is from ++ * @msg: the IPMI SDR response message ++ */ ++static void ipmisensors_rcv_reading_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ struct sdrdata *sdr = bmc->current_sdr; ++ ++ if (sdr == NULL) { ++ printk(KERN_ERR ++ "ipmisensors: Error ipmisensors_rcv_reading with NULL sdr\n"); ++ return; ++ } ++ ++ sdr->reading = msg->data[1]; ++ sdr->status = msg->data[2]; ++ sdr->thresholds = msg->data[3]; ++ ++ printk(KERN_DEBUG "ipmisensors: sensor %d (type %d) reading %d\n", ++ sdr->number, sdr->stype, msg->data[1]); ++ ++ up(&bmc->update_semaphore); ++} ++ ++/** ++ * Unpack based on string type, convert to normal, null terminate. ++ */ ++static void ipmisensors_sprintf(u8 * to, u8 * from, u8 type, u8 length) ++{ ++ static const u8 *bcdplus = "0123456789 -.:,_"; ++ int i; ++ ++ switch (type) { ++ case 0: /* unicode */ ++ for (i = 0; i < length; i++) ++ *to++ = (*from++ & 0x7f); ++ *to = 0; ++ break; ++ case 1: /* BCD Plus */ ++ for (i = 0; i < length; i++) ++ *to++ = bcdplus[*from++ & 0x0f]; ++ *to = 0; ++ break; ++ case 2: /* packed ascii *//* if not a mult. of 3 this will run over */ ++ for (i = 0; i < length; i += 3) { ++ *to++ = *from & 0x3f; ++ *to++ = *from >> 6 | ((*(from+1) & 0xf) << 2); ++ from++; ++ *to++ = *from >> 4 | ((*(from+1) & 0x3) << 4); ++ from++; ++ *to++ = (*from++ >> 2) & 0x3f; ++ } ++ *to = 0; ++ break; ++ case 3: /* normal */ ++ if (length > 1) ++ memcpy(to, from, length); ++ to[length] = 0; ++ break; ++ } ++} ++ ++/* IPMI V1.5 Section 30 */ ++static const int exps[] = ++ { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; ++ ++/* Return 0 for fan, 2 for temp, 3 for voltage ++ We could make it variable based on the accuracy (= log10(m * 10**k2)); ++ this would work for /proc output, however libsensors resolution ++ is statically set in lib/chips.c */ ++static int decplaces(struct sdrdata *sd) ++{ ++ switch (sd->stype) { ++ case STYPE_TEMP: ++ return 2; ++ case STYPE_CURR: ++ case STYPE_VOLT: ++ return 3; ++ case STYPE_FAN: ++ default: ++ return 0; ++ } ++} ++ ++/* convert a raw value to a reading. IMPI V1.5 Section 30 */ ++static long conv_val(int value, struct sdrdata *sd) ++{ ++ u8 k1, k2; ++ long r; ++ ++ r = value * sd->m; ++ k1 = sd->k & 0x0f; ++ k2 = sd->k >> 4; ++ if (k1 < 8) ++ r += sd->b * exps[k1]; ++ else ++ r += sd->b / exps[16 - k1]; ++ r *= exps[decplaces(sd)]; ++ if (k2 < 8) { ++ if (sd->linear != 7) ++ r *= exps[k2]; ++ else ++ /* this will always truncate to 0: r = 1 / (exps[k2] * r); */ ++ r = 0; ++ } else { ++ if (sd->linear != 7) ++ r /= exps[16 - k2]; ++ else { ++ if (r != 0) ++ /* 1 / x * 10 ** (-m) == 10 ** m / x */ ++ r = exps[16 - k2] / r; ++ else ++ r = 0; ++ } ++ } ++ ++ return r; ++} ++ ++static const char *threshold_text[] = { ++ "upper non-recoverable threshold", ++ "upper critical threshold", ++ "upper non-critical threshold", ++ "lower non-recoverable threshold", ++ "lower critical threshold", ++ "lower non-critical threshold", ++ "positive-going hysteresis", ++ "negative-going hysteresis" /* unused */ ++}; ++ ++/* select two out of the 8 possible readable thresholds, and place indexes into the limits ++ array into lim1 and lim2. Set writable flags */ ++static void ipmisensors_select_thresholds(struct sdrdata *sd) ++{ ++ u8 capab = sd->capab; ++ u16 mask = sd->thresh_mask; ++ int tmp; ++ ++ sd->lim1 = -1; ++ sd->lim2 = -1; ++ sd->lim1_write = 0; ++ sd->lim2_write = 0; ++ ++ if (((capab & 0x0c) == 0x04) || /* readable thresholds ? */ ++ ((capab & 0x0c) == 0x08)) { ++ /* select upper threshold */ ++ if (mask & 0x10) { /* upper crit */ ++ sd->lim1 = 1; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x1000)) ++ sd->lim1_write = 1; ++ } else if (mask & 0x20) { /* upper non-recov */ ++ sd->lim1 = 0; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x2000)) ++ sd->lim1_write = 1; ++ } else if (mask & 0x08) { /* upper non-crit */ ++ sd->lim1 = 2; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0800)) ++ sd->lim1_write = 1; ++ } ++ ++ /* select lower threshold */ ++ if ((((capab & 0x30) == 0x10) || /* readable ? */ ++ ((capab & 0x30) == 0x20)) && /* pos hyst */ ++ sd->stype == STYPE_TEMP) ++ sd->lim2 = 6; ++ else if (mask & 0x02) { /* lower crit */ ++ sd->lim2 = 4; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0200)) ++ sd->lim2_write = 1; ++ } else if (mask & 0x04) { /* lower non-recov */ ++ sd->lim2 = 3; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0400)) ++ sd->lim2_write = 1; ++ } else if (mask & 0x01) { /* lower non-crit */ ++ sd->lim2 = 5; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0100)) ++ sd->lim2_write = 1; ++ } ++ } ++ ++ /* swap lim1/lim2 if m < 0 or function is 1/x (but not both!) */ ++ if ((sd->m < 0 && sd->linear != 7) || (sd->m >= 0 && sd->linear == 7)) { ++ tmp = sd->lim1; ++ sd->lim1 = sd->lim2; ++ sd->lim2 = tmp; ++ } ++ ++ if (sd->lim1 >= 0) ++ printk(KERN_INFO "ipmisensors: using %s for upper limit\n", ++ threshold_text[sd->lim1]); ++ else ++ printk(KERN_DEBUG "ipmisensors: no readable upper limit\n"); ++ ++ if (sd->lim2 >= 0) ++ printk(KERN_INFO "ipmisensors: using %s for lower limit\n", ++ threshold_text[sd->lim2]); ++ else ++ printk(KERN_DEBUG "ipmisensors: no readable lower limit\n"); ++} ++ ++/************* sysfs callback functions *********/ ++static ssize_t show_update_period(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ ++ return snprintf(buf, 20, "%d\n", aattr->bmc->update_period); ++} ++ ++static ssize_t store_update_period(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ ++ aattr->bmc->update_period = simple_strtoul(buf, NULL, 10);; ++ return count; ++}; ++ ++static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ return snprintf(buf, 20, "%ld\n", ++ conv_val(sattr->sdr->reading, sattr->sdr)); ++} ++ ++static ssize_t show_sensor_max(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ long max = 0; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ if (sattr->sdr->lim1 >= 0) ++ max = conv_val(sattr->sdr->limits[sattr->sdr->lim1], ++ sattr->sdr); ++ return snprintf(buf, 20, "%ld\n", max); ++} ++ ++static ssize_t show_sensor_min(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ long min = 0; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ if (sattr->sdr->lim2 >= 0) ++ min = conv_val(sattr->sdr->limits[sattr->sdr->lim2], ++ sattr->sdr); ++ return snprintf(buf, 20, "%ld\n", min); ++}; ++ ++static ssize_t show_sensor_label(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ u8 label[SDR_MAX_UNPACKED_ID_LENGTH]; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ ipmisensors_sprintf(label, sattr->sdr->id, sattr->sdr->string_type, ++ sattr->sdr->id_length); ++ return snprintf(buf, 20, "%s\n", label); ++}; ++ ++static ssize_t store_sensor_max(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ long val = simple_strtoul(buf, NULL, 10); ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ printk(KERN_DEBUG "ipmisensors: set max on sensor #%d to %ld", ++ sattr->sdr->number, val); ++ ipmisensors_set_sensor_threshold(sattr->sdr->bmc, sattr->sdr->number, ++ val, sattr->sdr->lim1); ++ return count; ++}; ++ ++static ssize_t store_sensor_min(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ long val = simple_strtoul(buf, NULL, 10); ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ printk(KERN_DEBUG "ipmisensors: set min on sensor #%d to %ld", ++ sattr->sdr->number, val); ++ ipmisensors_set_sensor_threshold(sattr->sdr->bmc, sattr->sdr->number, ++ val, sattr->sdr->lim2); ++ return count; ++}; ++ ++static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ return snprintf(buf, 20, "%d\n", aattr->bmc->alarms); ++}; ++ ++static ssize_t show_name(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ return snprintf(buf, 20, "%s\n", driver_data.driver_name); ++}; ++ ++/* work function to build the sysfs entries using the ipmi sdrs */ ++static void ipmisensors_build_sysfs(struct work_struct *work) ++{ ++ int temps = 0, volts = 0, currs = 0, fans = 0; ++ struct sdrdata *cursor, *next; ++ struct ipmisensors_bmc_data *bmc = container_of(work, struct ipmisensors_bmc_data, sysfs_work); ++ ++ /* find and create entries for each sdr data struct */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; ++ ++ cursor->attr_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ cursor->attr_max_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ cursor->attr_min_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ ++ if (cursor->id_length > 0) { ++ cursor->attr_label_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ ++ if (cursor->attr_label_name == NULL) { ++ printk(KERN_INFO ++ "ipmisensors: Out of memory (kmalloc failed)"); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ return; ++ } ++ } ++ ++ if (cursor->attr_name == NULL || cursor->attr_max_name == NULL ++ || cursor->attr_min_name == NULL ++ || cursor->attr_label_name == NULL) { ++ printk(KERN_INFO ++ "ipmisensors: Out of memory (kmalloc failed)"); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ return; ++ } ++ ++ switch (cursor->stype) { ++ case (STYPE_TEMP): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "temp%d_input", ++temps); ++ /* create min, max attributes */ ++ snprintf(cursor->attr_max_name, MAX_FILENAME_LENGTH, ++ "temp%d_max", temps); ++ snprintf(cursor->attr_min_name, MAX_FILENAME_LENGTH, ++ "temp%d_min", temps); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "temp%d_label", temps); ++ break; ++ case (STYPE_VOLT): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "in%d_input", ++volts); ++ /* create min, max attributes */ ++ snprintf(cursor->attr_max_name, MAX_FILENAME_LENGTH, ++ "in%d_max", volts); ++ snprintf(cursor->attr_min_name, MAX_FILENAME_LENGTH, ++ "in%d_min", volts); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "in%d_label", volts); ++ break; ++ case (STYPE_CURR): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "curr%d_input", ++currs); ++ /* create min, max attributes */ ++ sprintf(cursor->attr_max_name, "curr%d_max", currs); ++ sprintf(cursor->attr_min_name, "curr%d_min", currs); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "curr%d_label", currs); ++ break; ++ case (STYPE_FAN): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "fan%d_input", ++fans); ++ /* create min, max attributes */ ++ sprintf(cursor->attr_max_name, "fan%d_max", fans); ++ sprintf(cursor->attr_min_name, "fan%d_min", fans); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "fan%d_label", fans); ++ break; ++ default: ++ printk(KERN_INFO "ipmisensors: unkown sensor type\n"); ++ continue; ++ } ++ ++ cursor->attr.dev_attr.attr.name = cursor->attr_name; ++ cursor->attr.dev_attr.attr.mode = S_IRUGO; ++ cursor->attr.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr.dev_attr.show = show_sensor; ++ cursor->attr.dev_attr.store = NULL; ++ cursor->attr.sdr = cursor; ++ ++ cursor->attr_min.dev_attr.attr.name = cursor->attr_min_name; ++ cursor->attr_min.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_min.dev_attr.show = show_sensor_min; ++ cursor->attr_min.sdr = cursor; ++ ++ if (cursor->lim2_write) { ++ printk(KERN_INFO ++ "ipmisensors: You have a writable sensor threshold! Send me an e-mail at .\n"); ++ cursor->attr_min.dev_attr.store = store_sensor_min; ++ cursor->attr_min.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ } else { ++ cursor->attr_min.dev_attr.store = NULL; ++ cursor->attr_min.dev_attr.attr.mode = S_IRUGO; ++ } ++ ++ cursor->attr_max.dev_attr.attr.name = cursor->attr_max_name; ++ cursor->attr_max.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_max.dev_attr.show = show_sensor_max; ++ cursor->attr_max.sdr = cursor; ++ ++ if (cursor->lim1_write) { ++ printk(KERN_INFO ++ "ipmisensors: You have a writable sensor threshold! Send me an e-mail at .\n"); ++ cursor->attr_max.dev_attr.store = store_sensor_max; ++ cursor->attr_max.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ } else { ++ cursor->attr_max.dev_attr.store = NULL; ++ cursor->attr_max.dev_attr.attr.mode = S_IRUGO; ++ } ++ ++ if (cursor->id_length > 0) { ++ cursor->attr_label.dev_attr.attr.name = ++ cursor->attr_label_name; ++ cursor->attr_label.dev_attr.attr.mode = S_IRUGO; ++ cursor->attr_label.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_label.dev_attr.show = show_sensor_label; ++ cursor->attr_label.dev_attr.store = NULL; ++ cursor->attr_label.sdr = cursor; ++ } ++ ++ printk(KERN_INFO ++ "ipmisensors: registering sensor %d: (type 0x%.2x) " ++ "(fmt=%d; m=%d; b=%d; k1=%d; k2=%d; cap=0x%.2x; mask=0x%.4x)\n", ++ cursor->number, cursor->stype, cursor->format, cursor->m, ++ cursor->b, cursor->k & 0xf, cursor->k >> 4, ++ cursor->capab, cursor->thresh_mask); ++ ++ if (cursor->id_length > 0) { ++ ipmisensors_sprintf(id, cursor->id, cursor->string_type, ++ cursor->id_length); ++ switch (cursor->stype) { ++ case (STYPE_TEMP): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label temp%d \"%s\"\n", ++ temps, id); ++ break; ++ case (STYPE_VOLT): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label in%d \"%s\"\n", ++ volts, id); ++ break; ++ case (STYPE_CURR): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label curr%d \"%s\"\n", ++ currs, id); ++ break; ++ case (STYPE_FAN): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label fan%d \"%s\"\n", ++ fans, id); ++ break; ++ } ++ } ++ ++ ipmisensors_select_thresholds(cursor); ++ ++ if (cursor->linear != 0 && cursor->linear != 7) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: nonlinear function 0x%.2x unsupported, expect bad results\n", ++ cursor->number, cursor->linear); ++ } ++ ++ if ((cursor->format & 0x03) == 0x02) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: 1's complement format unsupported, expect bad results\n", ++ cursor->number); ++ } else if ((cursor->format & 0x03) == 0x03) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: threshold sensor only, no readings available", ++ cursor->number); ++ } ++ ++ if (cursor->lim1_write || cursor->lim2_write) ++ cursor->attr.dev_attr.attr.mode = 0644; ++ else ++ cursor->attr.dev_attr.attr.mode = 0444; ++ ++ if (device_create_file(bmc->dev, &cursor->attr.dev_attr) < 0 ++ || device_create_file(bmc->dev, ++ &cursor->attr_min.dev_attr) < 0 ++ || device_create_file(bmc->dev, ++ &cursor->attr_max.dev_attr) < 0 ++ || (cursor->id_length > ++ 0 ? device_create_file(bmc->dev, ++ &cursor->attr_label.dev_attr) < ++ 0 : 0) ++ ) { ++ printk(KERN_INFO ++ "ipmisensors: sysfs file creation failed for SDR %d (%s).\n", ++ cursor->number, cursor->id); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ return; ++ } ++ } ++ ++ bmc->alarms_attr.dev_attr.attr.name = "alarms"; ++ bmc->alarms_attr.dev_attr.attr.mode = S_IRUGO; ++ bmc->alarms_attr.dev_attr.attr.owner = THIS_MODULE; ++ bmc->alarms_attr.dev_attr.show = show_alarms; ++ bmc->alarms_attr.dev_attr.store = NULL; ++ bmc->alarms_attr.bmc = bmc; ++ ++ if (device_create_file(bmc->dev, &bmc->alarms_attr.dev_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'alarms'"); ++ return; ++ } ++ ++ bmc->name_attr.attr.name = "name"; ++ bmc->name_attr.attr.mode = S_IRUGO; ++ bmc->name_attr.attr.owner = THIS_MODULE; ++ bmc->name_attr.show = show_name; ++ ++ if (device_create_file(bmc->dev, &bmc->name_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'name'"); ++ return; ++ } ++ ++ bmc->update_attr.dev_attr.attr.name = "update_period"; ++ bmc->update_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ bmc->update_attr.dev_attr.attr.owner = THIS_MODULE; ++ bmc->update_attr.dev_attr.show = show_update_period; ++ bmc->update_attr.dev_attr.store = store_update_period; ++ bmc->update_attr.bmc = bmc; ++ ++ if (device_create_file(bmc->dev, &bmc->update_attr.dev_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'update_period'"); ++ return; ++ } ++ ++ printk(KERN_INFO ++ "ipmisensors: registered %d temp, %d volt, %d current, %d fan sensors\n", ++ temps, volts, currs, fans); ++ ++ /* This completes the initialization. We can now kickoff the ++ * periodic update of the bmc sensor's values by scheduling ++ * the first work. ++ */ ++ queue_work(ipmisensors_workqueue, &bmc->update_work.work); ++ ++} ++ ++/** ++ * Process an SDR response message, save the SDRs we like in the sdr ++ * list for the given BMC. ++ * ++ * @bmc: the bmc the message is from ++ * @msg: the IPMI SDR response message ++ */ ++static void ipmisensors_rcv_sdr_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ u16 record; ++ int type; ++ int stype; ++ int id_length; ++ int i; ++ int ipmi_ver = 0; ++ unsigned char *data; ++ u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; ++ struct sdrdata *sdr; ++ ++ if (msg->data[0] != 0) { ++ /* cut request in half and try again */ ++ bmc->ipmi_sdr_partial_size /= 2; ++ if (bmc->ipmi_sdr_partial_size < 8) { ++ printk(KERN_INFO ++ "ipmisensors: IPMI buffers too small, giving up\n"); ++ bmc->state = STATE_DONE; ++ return; ++ } ++ printk(KERN_DEBUG ++ "ipmisensors: Reducing SDR request size to %d\n", ++ bmc->ipmi_sdr_partial_size); ++ ++ ipmisensors_get_sdr(bmc, 0, 0, 0); ++ bmc->state = STATE_SDR; ++ return; ++ } ++ if (bmc->ipmi_sdr_partial_size < IPMI_SDR_SIZE) { ++ if (bmc->rx_msg_data_offset == 0) { ++ memcpy(bmc->rx_msg_data, msg->data, ++ bmc->ipmi_sdr_partial_size + 3); ++ bmc->rx_msg_data_offset = ++ bmc->ipmi_sdr_partial_size + 3; ++ } else { ++ memcpy(bmc->rx_msg_data + bmc->rx_msg_data_offset, ++ msg->data + 3, bmc->ipmi_sdr_partial_size); ++ bmc->rx_msg_data_offset += bmc->ipmi_sdr_partial_size; ++ } ++ if (bmc->rx_msg_data_offset > bmc->rx_msg_data[7] + 7) { ++ /* got last chunk */ ++ bmc->rx_msg_data_offset = 0; ++ data = bmc->rx_msg_data; ++ } else { ++ /* get more */ ++ record = ++ (bmc->rx_msg_data[4] << 8) | bmc->rx_msg_data[3]; ++ ipmisensors_get_sdr(bmc, bmc->resid, record, ++ bmc->rx_msg_data_offset - 3); ++ bmc->state = STATE_SDR; ++ return; ++ } ++ } else { ++ /* got it in one chunk */ ++ data = msg->data; ++ } ++ ++ bmc->nextrecord = (data[2] << 8) | data[1]; ++ ++ /* If the ipmi version is 0.9 we have to remap some things. ++ * Yes this is very ugly, but we aren't the ones who ++ * implemented an incomplete spec! ++ */ ++ ipmi_ver = data[5]; ++ ++ type = data[6]; ++ /* known SDR type */ ++ if (type == 1 || type == 2) { ++ stype = data[(ipmi_ver == 0x90 ? 16 : 15)]; ++ /* known sensor type */ ++ if (stype <= STYPE_MAX) { ++ if (data[(ipmi_ver == 0x90 ? 17 : 16)] != 0x01) { ++ if (type == 1) ++ ipmisensors_sprintf(id, &data[51], ++ data[50] >> 6, ++ data[50] & 0x1f); ++ else ++ ipmisensors_sprintf(id, ++ &data[(ipmi_ver == ++ 0x90 ? 30 : ++ 35)], ++ data[(ipmi_ver == ++ 0x90 ? 29 : ++ 34)] >> 6, ++ data[(ipmi_ver == ++ 0x90 ? 29 : ++ 34)] & 0x1f); ++ printk(KERN_INFO ++ "ipmisensors: skipping non-threshold sensor \"%s\"\n", ++ id); ++ } else { ++ /* add entry to sdrd table */ ++ sdr = ipmisensors_new_sdr(); ++ if (!sdr) { ++ printk(KERN_ERR ++ "ipmisensors: could not allocate memory for new SDR"); ++ return; ++ } ++ sdr->bmc = bmc; ++ sdr->stype = stype; ++ sdr->number = data[10]; ++ sdr->capab = data[(ipmi_ver == 0x90 ? 15 : 14)]; ++ sdr->thresh_mask = ++ (((u16) data[(ipmi_ver == 0x90 ? 21 : 22)]) ++ << 8) | data[21]; ++ if (type == 1) { ++ sdr->format = ++ data[(ipmi_ver == ++ 0x90 ? 22 : 24)] >> 6; ++ sdr->linear = ++ data[(ipmi_ver == ++ 0x90 ? 25 : 26)] & 0x7f; ++ sdr->m = ++ data[(ipmi_ver == 0x90 ? 26 : 27)]; ++ sdr->m |= ((u16) ++ (data ++ [(ipmi_ver == ++ 0x90 ? 27 : 28)] ++ & 0xc0)) << 2; ++ if (sdr->m & 0x0200) { ++ /* sign extend */ ++ sdr->m |= 0xfc00; ++ } ++ sdr->b = ++ data[(ipmi_ver == 0x90 ? 28 : 29)]; ++ sdr->b |= ((u16) ++ (data ++ [(ipmi_ver == ++ 0x90 ? 29 : 30)] ++ & 0xc0)) << 2; ++ if (sdr->b & 0x0200) { ++ /* sign extend */ ++ sdr->b |= 0xfc00; ++ } ++ sdr->k = ++ data[(ipmi_ver == 0x90 ? 31 : 32)]; ++ sdr->nominal = ++ data[(ipmi_ver == 0x90 ? 33 : 34)]; ++ for (i = 0; i < SDR_LIMITS; i++) { ++ /* assume readable */ ++ sdr->limits[i] = ++ data[(ipmi_ver == ++ 0x90 ? 40 : 39) + i]; ++ } ++ sdr->string_type = data[50] >> 6; ++ id_length = data[50] & 0x1f; ++ memcpy(sdr->id, &data[51], id_length); ++ sdr->id_length = id_length; ++ } else { ++ sdr->m = 1; ++ sdr->b = 0; ++ sdr->k = 0; ++ sdr->string_type = ++ data[(ipmi_ver == ++ 0x90 ? 29 : 34)] >> 6; ++ id_length = data[34] & 0x1f; ++ if (id_length > 0) { ++ memcpy(sdr->id, ++ &data[(ipmi_ver == ++ 0x90 ? 30 : 35)], ++ id_length); ++ } ++ sdr->id_length = id_length; ++ /* limits?? */ ++ if (ipmi_ver == 0x90) { ++ memcpy(sdr->id, ++ &data[30], id_length); ++ sdr->id_length = id_length; ++ } ++ } ++ ipmisensors_add_sdr(bmc, sdr); ++ } ++ } ++ /* peek at the other SDR types */ ++ } else if (type == 0x10 || type == 0x11 || type == 0x12) { ++ ipmisensors_sprintf(id, data + 19, data[18] >> 6, ++ data[18] & 0x1f); ++ if (type == 0x10) { ++ printk(KERN_INFO ++ "ipmisensors: Generic Device acc=0x%x; slv=0x%x; lun=0x%x; type=0x%x; \"%s\"\n", ++ data[8], data[9], data[10], data[13], id); ++ } else if (type == 0x11) { ++ printk(KERN_INFO ++ "ipmisensors: FRU Device acc=0x%x; slv=0x%x; log=0x%x; ch=0x%x; type=0x%x; \"%s\"\n", ++ data[8], data[9], data[10], data[11], data[13], ++ id); ++ } else { ++ printk(KERN_INFO ++ "ipmisensors: Mgmt Ctllr Device slv=0x%x; \"%s\"\n", ++ data[8], id); ++ } ++ } else if (type == 0x14) { ++ printk(KERN_INFO ++ "ipmisensors: Message Channel Info Records:\n"); ++ for (i = 0; i < 8; i++) { ++ printk(KERN_INFO "ipmisensors: Channel %d info 0x%x\n", ++ i, data[9 + i]); ++ } ++ } else { ++ printk(KERN_INFO "ipmisensors: Skipping SDR type 0x%x\n", type); ++ } ++ if (ipmi_ver != 0x90) { ++ if (bmc->nextrecord >= 6224) { ++ /*YJ stop sensor scan on poweredge 1750 */ ++ bmc->nextrecord = 0xffff; ++ } ++ } ++ ++ if (bmc->nextrecord == 0xFFFF) { ++ if (bmc->sdr_count == 0) { ++ printk(KERN_INFO ++ "ipmisensors: No recognized sensors found.\n"); ++ bmc->state = STATE_DONE; ++ } else { ++ printk(KERN_INFO "ipmisensors: all sensors detected\n"); ++ bmc->state = STATE_SYSTABLE; ++ ++ /* Schedule sysfs build/registration work */ ++ INIT_WORK(&bmc->sysfs_work, ipmisensors_build_sysfs); ++ queue_work(ipmisensors_workqueue, &bmc->sysfs_work); ++ } ++ } else { ++ ipmisensors_get_sdr(bmc, 0, bmc->nextrecord, 0); ++ bmc->state = STATE_SDR; ++ } ++} ++ ++/** ++ * Process incoming messages based on internal state ++ * ++ * @bmc: the bmc the message is from. ++ * @msg: the ipmi message to process. ++ */ ++static void ipmisensors_rcv_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ switch (bmc->state) { ++ case STATE_INIT: ++ case STATE_RESERVE: ++ bmc->resid = (((u16) msg->data[2]) << 8) | msg->data[1]; ++ ++ printk(KERN_DEBUG "ipmisensors: Got first resid 0x%.4x\n", ++ bmc->resid); ++ ++ ipmisensors_get_sdr(bmc, 0, 0, 0); ++ bmc->state = STATE_SDR; ++ break; ++ ++ case STATE_SDR: ++ case STATE_SDRPARTIAL: ++ ipmisensors_rcv_sdr_msg(bmc, msg); ++ break; ++ ++ case STATE_READING: ++ ipmisensors_rcv_reading_msg(bmc, msg); ++ break; ++ ++ case STATE_UNCANCEL: ++ bmc->resid = (((u16) msg->data[2]) << 8) | msg->data[1]; ++ ++ printk(KERN_DEBUG "ipmisensors: Got new resid 0x%.4x\n", ++ bmc->resid); ++ ++ bmc->rx_msg_data_offset = 0; ++ ipmisensors_get_sdr(bmc, 0, bmc->nextrecord, 0); ++ bmc->state = STATE_SDR; ++ break; ++ ++ case STATE_DONE: ++ case STATE_SYSTABLE: ++ break; ++ default: ++ bmc->state = STATE_INIT; ++ } ++} ++ ++/** ++ * Callback to handle a received IPMI message from a given BMC. ++ * ++ * @msg: the received message. ++ * @handler_data: a pointer to the particular bmc ipmisensors_bmc_data struct. ++ */ ++static void ipmisensors_msg_handler(struct ipmi_recv_msg *msg, ++ void *user_msg_data) ++{ ++ struct ipmisensors_bmc_data *bmc = ++ (struct ipmisensors_bmc_data *)user_msg_data; ++ ++ if (msg->msg.data[0] != 0) ++ printk(KERN_WARNING ++ "ipmisensors: Error 0x%x on cmd 0x%x/0x%x\n", ++ msg->msg.data[0], msg->msg.netfn, msg->msg.cmd); ++ ++ if (bmc != NULL && ipmisensors_intf_registered(bmc->interface_id)) { ++ if (bmc->state == STATE_SDR && ++ msg->msg.data[0] == IPMI_INVALID_RESERVATION_ID) { ++ /* reservation cancelled, get new resid */ ++ if (++bmc->errorcount > 275) { ++ printk(KERN_ERR ++ "ipmisensors: Too many reservations cancelled, giving up\n"); ++ bmc->state = STATE_DONE; ++ } else { ++ printk(KERN_DEBUG ++ "ipmisensors: resid 0x%04x cancelled, getting new one\n", ++ bmc->resid); ++ ++ ipmisensors_reserve_sdr(bmc); ++ bmc->state = STATE_UNCANCEL; ++ } ++ } else if (msg->msg.data[0] != IPMI_CC_NO_ERROR && ++ msg->msg.data[0] != IPMI_ERR_RETURNING_REQ_BYTES && ++ msg->msg.data[0] != IPMI_ERR_PROVIDING_RESPONSE) { ++ printk(KERN_ERR ++ "ipmisensors: Error 0x%x on cmd 0x%x/0x%x; state = %d; probably fatal.\n", ++ msg->msg.data[0], msg->msg.netfn & 0xfe, ++ msg->msg.cmd, bmc->state); ++ } else { ++ printk(KERN_DEBUG "ipmisensors: received message\n"); ++ ipmisensors_rcv_msg(bmc, &msg->msg); ++ } ++ ++ } else { ++ printk(KERN_WARNING ++ "ipmisensors: Response for non-registered BMC\n"); ++ if (bmc != NULL) ++ printk(KERN_DEBUG "ipmisensors: BMC ID: %d\n", ++ bmc->interface_id); ++ else ++ printk(KERN_DEBUG "ipmisensors: BMC NULL!\n"); ++ } ++ ++ ipmi_free_recv_msg(msg); ++} ++ ++/****** IPMI Interface Initialization ******/ ++ ++/** ++ * Return true if the given ipmi interface has been registered. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static int ipmisensors_intf_registered(int ipmi_intf) ++{ ++ int found = 0; ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->interface_id == ipmi_intf) { ++ found++; ++ } ++ } ++ ++ return found; ++} ++ ++/** ++ * Return true if the given BMC has been registered. ++ * ++ * @bmc: The BMC device. ++ */ ++static int ipmisensors_bmc_registered(struct device *bmc) ++{ ++ int found = 0; ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->dev == bmc) { ++ found++; ++ } ++ } ++ ++ return found; ++} ++ ++/** ++ * Register new IPMI BMC interface. Interface indpendent callback created ++ * for flexibility in adding new types of interface callbacks in future. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static void ipmisensors_register_bmc(int ipmi_intf, struct ipmi_addr *address) ++{ ++ int error; ++ ++ /* allocate a new ipmisensors_bmc_data struct */ ++ ++ struct ipmisensors_bmc_data *bmc = (struct ipmisensors_bmc_data *) ++ kmalloc(sizeof(struct ipmisensors_bmc_data), GFP_KERNEL); ++ ++ /* initialize members */ ++ INIT_LIST_HEAD(&bmc->sdrs); ++ bmc->interface_id = ipmi_intf; ++ ++ bmc->address = *address; ++ ++ bmc->sdr_count = 0; ++ bmc->msgid = 0; ++ bmc->ipmi_sdr_partial_size = IPMI_CHUNK_SIZE; ++ bmc->state = STATE_INIT; ++ bmc->errorcount = 0; ++ bmc->rx_msg_data_offset = 0; ++ bmc->dev = ipmi_get_bmcdevice(ipmi_intf); ++ ++ /* default to 3 second min update interval */ ++ bmc->update_period = 3; ++ ++ if (bmc->dev == NULL) { ++ printk(KERN_ERR ++ "ipmisensors: Error, couldn't get BMC device for interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Create IPMI messaging interface user */ ++ error = ipmi_create_user(bmc->interface_id, &driver_data.ipmi_hndlrs, ++ bmc, &bmc->user); ++ if (error < 0) { ++ printk(KERN_ERR ++ "ipmisensors: Error, unable to register user with ipmi interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Register the BMC as a HWMON class device */ ++ bmc->class_dev = hwmon_device_register(bmc->dev); ++ ++ if (IS_ERR(bmc->class_dev)) { ++ printk(KERN_ERR ++ "ipmisensors: Error, unable to register hwmon class device for interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Register the BMC in the driver */ ++ if (ipmisensors_bmc_registered(bmc->dev)) { ++ printk(KERN_ERR ++ "ipmisensors: BMC on interface %d already registered\n", ++ bmc->interface_id); ++ hwmon_device_unregister(bmc->class_dev); ++ kfree(bmc); ++ return; ++ } ++ ++ ipmi_get_version(bmc->user, &bmc->ipmi_version_major, ++ &bmc->ipmi_version_minor); ++ ++ /* finally add the new bmc data to the bmc data list */ ++ list_add_tail(&bmc->list, &driver_data.bmc_data); ++ driver_data.interfaces++; ++ ++ printk(KERN_INFO ++ "ipmisensors: Registered IPMI %d.%d BMC over interface %d\n", ++ bmc->ipmi_version_major, ++ bmc->ipmi_version_minor, bmc->interface_id); ++ ++ /* Send a reserve SDR command to the bmc */ ++ ipmisensors_reserve_sdr(bmc); ++ ++ /* initialize the bmc's update work struct */ ++ INIT_DELAYED_WORK(&bmc->update_work, ipmisensors_update_bmc); ++} ++ ++/** ++ * Callback for when an IPMI BMC is gone. Interface indpendent callback created ++ * for flexibility in adding new types of interface callbacks in future. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static void ipmisensors_unregister_bmc(int ipmi_intf) ++{ ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->interface_id == ipmi_intf) { ++ list_del(&cursor->list); ++ printk(KERN_DEBUG ++ "ipmisensors: cancelling queued work\n"); ++ /* cancel update work queued for this bmc */ ++ cancel_delayed_work(&cursor->update_work); ++ printk(KERN_DEBUG ++ "ipmisensors: waiting for update to finish\n"); ++ /* wait for readings to finish */ ++ while (cursor->state != STATE_DONE) ; ++ ++ device_remove_file(cursor->dev, ++ &cursor->alarms_attr.dev_attr); ++ device_remove_file(cursor->dev, ++ &cursor->update_attr.dev_attr); ++ hwmon_device_unregister(cursor->class_dev); ++ ipmisensors_sdr_cleanup(cursor); ++ ipmi_destroy_user(cursor->user); ++ ++ printk(KERN_INFO ++ "ipmisensors: Unegistered IPMI interface %d\n", ++ cursor->interface_id); ++ ++ kfree(cursor); ++ driver_data.interfaces--; ++ } ++ } ++ ++} ++ ++/** ++ * Unregister all registered bmcs. ++ */ ++static void ipmisensors_unregister_bmc_all(void) ++{ ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ list_del(&cursor->list); ++ ++ /* cancel update work queued for this bmc */ ++ printk(KERN_DEBUG "ipmisensors: cancelling queued work\n"); ++ cancel_delayed_work(&cursor->update_work); ++ ++ printk(KERN_DEBUG ++ "ipmisensors: waiting for update to finish\n"); ++ /* wait for readings to finish */ ++ while (cursor->state != STATE_DONE) ; ++ ++ device_remove_file(cursor->dev, &cursor->alarms_attr.dev_attr); ++ device_remove_file(cursor->dev, &cursor->update_attr.dev_attr); ++ hwmon_device_unregister(cursor->class_dev); ++ ipmisensors_sdr_cleanup(cursor); ++ ipmi_destroy_user(cursor->user); ++ ++ printk(KERN_INFO ++ "ipmisensors: Unegistered IPMI interface %d\n", ++ cursor->interface_id); ++ ++ kfree(cursor); ++ } ++ ++ driver_data.interfaces = 0; ++} ++ ++/** ++ * Callback for when a new IPMI SMI type interface is found. ++ * ++ * @if_num: The IPMI interface number. ++ */ ++static void ipmisensors_new_smi(int if_num, struct device *dev) ++{ ++ struct ipmi_addr smi_address = { ++ IPMI_SYSTEM_INTERFACE_ADDR_TYPE, ++ IPMI_BMC_CHANNEL, ++ {0}, ++ }; ++ ++ /* calls the generic new interface function */ ++ ipmisensors_register_bmc(if_num, &smi_address); ++} ++ ++/** ++ * Callback for when an exisiting IPMI SMI type interface is gone. ++ * ++ * @if_num: The IPMI interface number. ++ */ ++static void ipmisensors_smi_gone(int if_num) ++{ ++ if (driver_data.interfaces > 0) { ++ ipmisensors_unregister_bmc(if_num); ++ } ++} ++ ++/** ++ * Initialize the module. ++ */ ++static int __init ipmisensors_init(void) ++{ ++ int error; ++ printk(KERN_INFO "ipmisensors - IPMI BMC sensors interface\n"); ++ ++ /* init cache managers */ ++ driver_data.sdrdata_cache = ++ kmem_cache_create("ipmisensors_sdrdata", sizeof(struct sdrdata), 0, ++ 0, NULL, NULL); ++ driver_data.sysfsattr_cache = ++ kmem_cache_create("ipmisensors_sysfsattr", ++ sizeof(struct ipmisensors_device_attribute), 0, 0, ++ NULL, NULL); ++ ++ if (!driver_data.sdrdata_cache || !driver_data.sysfsattr_cache) { ++ if (driver_data.sdrdata_cache) ++ kmem_cache_destroy(driver_data.sdrdata_cache); ++ if (driver_data.sysfsattr_cache) ++ kmem_cache_destroy(driver_data.sysfsattr_cache); ++ return -ENOMEM; ++ } ++ ++ /* register IPMI interface callback(s) */ ++ error = ipmi_smi_watcher_register(&driver_data.smi_watcher); ++ if (error) { ++ printk(KERN_WARNING ++ "ipmisensors: can't register smi watcher\n"); ++ return error; ++ } ++ ++ /* create work queue, keep it simple, single-threaded */ ++ ipmisensors_workqueue = ++ create_singlethread_workqueue("ipmisensors_workqueue"); ++ ++ return 0; ++} ++ ++/** ++ * Cleanup ++ */ ++static void ipmisensors_cleanup(void) ++{ ++ /* start cleanup */ ++ cleanup = 1; ++ ++ /* unregister bmcs */ ++ printk(KERN_DEBUG "ipmisensors: unregister bmcs\n"); ++ ipmi_smi_watcher_unregister(&driver_data.smi_watcher); ++ ipmisensors_unregister_bmc_all(); ++ ++ /* flush & destroy work queue */ ++ printk(KERN_DEBUG "ipmisensors: destroy workqueue\n"); ++ flush_workqueue(ipmisensors_workqueue); ++ destroy_workqueue(ipmisensors_workqueue); ++ ++ /* remove cache managers */ ++ if (driver_data.sdrdata_cache) ++ kmem_cache_destroy(driver_data.sdrdata_cache); ++ if (driver_data.sysfsattr_cache) ++ kmem_cache_destroy(driver_data.sysfsattr_cache); ++} ++ ++/** ++ * Cleanup and exit the module ++ */ ++static void __exit ipmisensors_exit(void) ++{ ++ ipmisensors_cleanup(); ++ printk(KERN_DEBUG "ipmisensors: cleanup finished\n"); ++} ++ ++MODULE_AUTHOR("Yani Ioannou "); ++MODULE_DESCRIPTION("IPMI BMC sensors"); ++MODULE_LICENSE("GPL"); ++ ++module_init(ipmisensors_init); ++module_exit(ipmisensors_exit); +diff -rduNp linux-2.6.22.1.oorig2/drivers/hwmon/ipmisensors.h linux-2.6.22.1/drivers/hwmon/ipmisensors.h +--- linux-2.6.22.1.oorig2/drivers/hwmon/ipmisensors.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/drivers/hwmon/ipmisensors.h 2007-07-24 14:22:26.000000000 +0200 +@@ -0,0 +1,240 @@ ++/* ++ * ipmisensors.h - lm_sensors interface to IPMI sensors. ++ * ++ * Copyright (C) 2004-2006 Yani Ioannou ++ * ++ * Adapted from bmcsensors (lm-sensors for linux 2.4) ++ * bmcsensors (C) Mark D. Studebaker ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* SDR defs */ ++#define STYPE_TEMP 0x01 ++#define STYPE_VOLT 0x02 ++#define STYPE_CURR 0x03 ++#define STYPE_FAN 0x04 ++ ++#define SDR_LIMITS 8 ++#define SDR_MAX_ID_LENGTH 16 ++#define SDR_MAX_UNPACKED_ID_LENGTH ((SDR_MAX_ID_LENGTH * 4 / 3) + 2) ++ ++/* the last sensor type we are interested in */ ++#define STYPE_MAX 4 ++ ++#define IPMI_SDR_SIZE 67 ++#define IPMI_CHUNK_SIZE 16 ++ ++#define MAX_FILENAME_LENGTH 30 ++ ++struct ipmisensors_device_attribute { ++ struct device_attribute dev_attr; ++ struct sdrdata *sdr; ++}; ++#define to_ipmisensors_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct ipmisensors_device_attribute, dev_attr) ++ ++#define IPMISENSORS_DEVICE_ATTR(_name,_mode,_show,_store,_index) \ ++struct ipmisensors_attribute sensor_dev_attr_##_name = { \ ++ .dev_attr = __ATTR(_name,_mode,_show,_store), \ ++ .index = _index, \ ++} ++ ++struct ipmisensors_bmc_device_attribute { ++ struct device_attribute dev_attr; ++ struct ipmisensors_bmc_data *bmc; ++}; ++#define to_ipmisensors_bmc_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct ipmisensors_bmc_device_attribute, dev_attr) ++ ++/** ++ * &struct_sdrdata stores the IPMI Sensor Data Record (SDR) data, as recieved from the BMC, along with the corresponding sysfs attributes ++ */ ++struct sdrdata { ++ struct list_head list; ++ /* retrieved from SDR, not expected to change */ ++ /* Sensor Type Code */ ++ u8 stype; ++ u8 number; ++ /* Sensor Capability Code */ ++ u8 capab; ++ u16 thresh_mask; ++ u8 format; ++ u8 linear; ++ s16 m; ++ s16 b; ++ u8 k; ++ u8 nominal; ++ u8 limits[SDR_LIMITS]; ++ /* index into limits for reported upper and lower limit */ ++ int lim1, lim2; ++ u8 lim1_write, lim2_write; ++ u8 string_type; ++ u8 id_length; ++ u8 id[SDR_MAX_ID_LENGTH]; ++ /* retrieved from reading */ ++ u8 reading; ++ u8 status; ++ u8 thresholds; ++ /* sensor's bmc */ ++ struct ipmisensors_bmc_data *bmc; ++ /* sysfs entries */ ++ struct ipmisensors_device_attribute attr; ++ char *attr_name; ++ struct ipmisensors_device_attribute attr_min; ++ char *attr_min_name; ++ struct ipmisensors_device_attribute attr_max; ++ char *attr_max_name; ++ struct ipmisensors_device_attribute attr_label; ++ char *attr_label_name; ++ ++}; ++ ++/** ++ * &struct_ipmisensors_data stores the data for the ipmisensors driver. ++ */ ++struct ipmisensors_data { ++ /* Driver struct */ ++ char *driver_name; ++ ++ /* Linked list of ipmisensors_bmc_data structs, one for each BMC */ ++ struct list_head bmc_data; ++ ++ /* Number of ipmi interfaces (and hence ipmisensors_data structs). */ ++ int interfaces; ++ ++ /* IPMI kernel interface - SMI watcher */ ++ struct ipmi_smi_watcher smi_watcher; ++ ++ /* IPMI kernel interface - user handlers */ ++ struct ipmi_user_hndl ipmi_hndlrs; ++ ++ /* Cache manager for sdrdata cache */ ++ struct kmem_cache *sdrdata_cache; ++ ++ /* Cache manager for ipmi_sensor_device_attribute cache */ ++ struct kmem_cache *sysfsattr_cache; ++}; ++ ++/** ++ * &states: enumeration of state codes for a bmc specific ipmisensors ++ */ ++enum states { ++ STATE_INIT, ++ STATE_RESERVE, ++ STATE_SDR, ++ STATE_SDRPARTIAL, ++ STATE_READING, ++ STATE_UNCANCEL, ++ STATE_SYSTABLE, ++ STATE_DONE ++}; ++ ++/** ++ * &struct_ipmisensors_bmc_data stores the data for a particular IPMI BMC. ++ */ ++struct ipmisensors_bmc_data { ++ struct list_head list; ++ ++ /* The IPMI interface number */ ++ int interface_id; ++ ++ /* The IPMI address */ ++ struct ipmi_addr address; ++ ++ /* List of sdrdata structs (sdrs) recieved from the BMC */ ++ struct list_head sdrs; ++ ++ /* Count of the number of sdrs stored in the sdr list */ ++ int sdr_count; ++ ++ /* next message id */ ++ int msgid; ++ ++ /* The ipmi interface 'user' used to access this particular bmc */ ++ ipmi_user_t user; ++ ++ /* BMC IPMI Version (major) */ ++ unsigned char ipmi_version_major; ++ ++ /* BMC IPMI Version (minor) */ ++ unsigned char ipmi_version_minor; ++ ++ /* The size of the SDR request message */ ++ int ipmi_sdr_partial_size; ++ ++ /* transmit message buffer */ ++ struct kernel_ipmi_msg tx_message; ++ ++ /* ipmi transmited data buffer */ ++ unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* why the +50 in bmcsensors? */ ++ ++ /* ipmi recieved data buffer */ ++ unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; ++ ++ /* current recieve buffer offset */ ++ int rx_msg_data_offset; ++ ++ /* The id of then next SDR record to read during update cycle */ ++ u16 nextrecord; ++ ++ /* BMC SDR Reservation ID */ ++ u16 resid; ++ ++ /* Alarm status */ ++ u8 alarms; ++ ++ /* The cumalative error count for this bmc */ ++ int errorcount; ++ ++ /* The current state of this bmc w.r.t. ipmisensors (see enum states) */ ++ int state; ++ ++ /* The current sdr for which a reading is pending */ ++ struct sdrdata *current_sdr; ++ ++ /* The BMC's device struct */ ++ struct device *dev; ++ ++ /* hwmon class device */ ++ struct class_device *class_dev; ++ ++ /* hwmon device name */ ++ struct device_attribute name_attr; ++ ++ /* alarms attribute */ ++ struct ipmisensors_bmc_device_attribute alarms_attr; ++ ++ /* update_period attribute */ ++ struct ipmisensors_bmc_device_attribute update_attr; ++ ++ /* lower bound on time between updates (in seconds) */ ++ unsigned int update_period; ++ ++ /* semaphore used to do a headcount of the SDR readings we are waiting ++ * on in a given bmc update */ ++ struct semaphore update_semaphore; ++ ++ /* bmc's work struct for updating sensors */ ++ struct delayed_work update_work; ++ ++ /* bmc's work struct for building the sysfs workqueue */ ++ struct work_struct sysfs_work; ++}; +diff -rduNp linux-2.6.22.1.oorig2/include/linux/ipmi.h linux-2.6.22.1/include/linux/ipmi.h +--- linux-2.6.22.1.oorig2/include/linux/ipmi.h 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/include/linux/ipmi.h 2007-07-24 14:22:26.000000000 +0200 +@@ -300,6 +300,9 @@ int ipmi_create_user(unsigned int + safe, too. */ + int ipmi_destroy_user(ipmi_user_t user); + ++/* Get the IPMI BMC's device struct */ ++struct device *ipmi_get_bmcdevice(int ipmi_intf); ++ + /* Get the IPMI version of the BMC we are talking to. */ + void ipmi_get_version(ipmi_user_t user, + unsigned char *major, +diff -rduNp linux-2.6.22.1.oorig2/include/linux/ipmi_msgdefs.h linux-2.6.22.1/include/linux/ipmi_msgdefs.h +--- linux-2.6.22.1.oorig2/include/linux/ipmi_msgdefs.h 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/include/linux/ipmi_msgdefs.h 2007-07-24 14:22:26.000000000 +0200 +@@ -45,6 +45,7 @@ + + #define IPMI_NETFN_APP_REQUEST 0x06 + #define IPMI_NETFN_APP_RESPONSE 0x07 ++#define IPMI_GET_DEVICE_GUID_CMD 0x08 + #define IPMI_GET_DEVICE_ID_CMD 0x01 + #define IPMI_COLD_RESET_CMD 0x02 + #define IPMI_WARM_RESET_CMD 0x03 +@@ -57,6 +58,11 @@ + #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD 0x2f + #define IPMI_READ_EVENT_MSG_BUFFER_CMD 0x35 + #define IPMI_GET_CHANNEL_INFO_CMD 0x42 ++#define IPMI_RESERVE_SDR 0x22 ++#define IPMI_GET_SDR 0x23 ++#define IPMI_GET_SENSOR_STATE_READING 0x2D ++#define IPMI_SET_SENSOR_HYSTERESIS 0x24 ++#define IPMI_SET_SENSOR_THRESHOLD 0x26 + + #define IPMI_NETFN_STORAGE_REQUEST 0x0a + #define IPMI_NETFN_STORAGE_RESPONSE 0x0b +@@ -79,10 +85,13 @@ + #define IPMI_NODE_BUSY_ERR 0xc0 + #define IPMI_INVALID_COMMAND_ERR 0xc1 + #define IPMI_TIMEOUT_ERR 0xc3 ++#define IPMI_INVALID_RESERVATION_ID 0xc5 + #define IPMI_ERR_MSG_TRUNCATED 0xc6 + #define IPMI_REQ_LEN_INVALID_ERR 0xc7 + #define IPMI_REQ_LEN_EXCEEDED_ERR 0xc8 + #define IPMI_NOT_IN_MY_STATE_ERR 0xd5 /* IPMI 2.0 */ ++#define IPMI_ERR_RETURNING_REQ_BYTES 0xca ++#define IPMI_ERR_PROVIDING_RESPONSE 0xce + #define IPMI_LOST_ARBITRATION_ERR 0x81 + #define IPMI_BUS_ERR 0x82 + #define IPMI_NAK_ON_WRITE_ERR 0x83 diff --git a/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.22.9-007-ipmisensors-20070314-1214.patch b/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.22.9-007-ipmisensors-20070314-1214.patch new file mode 100644 index 0000000000..5fe74954f3 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/ipmi/linux-2.6.22.9-007-ipmisensors-20070314-1214.patch @@ -0,0 +1,1914 @@ +diff -rduNp linux-2.6.22.1.oorig2/drivers/char/ipmi/ipmi_msghandler.c linux-2.6.22.1/drivers/char/ipmi/ipmi_msghandler.c +--- linux-2.6.22.1.oorig2/drivers/char/ipmi/ipmi_msghandler.c 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/drivers/char/ipmi/ipmi_msghandler.c 2007-07-24 14:22:26.000000000 +0200 +@@ -1953,6 +1953,24 @@ static void remove_proc_entries(ipmi_smi + #endif /* CONFIG_PROC_FS */ + } + ++/* ++ * Retrieves the bmc_device struct for a given ipmi interface number (or NULL if none). ++ */ ++struct device *ipmi_get_bmcdevice(int if_num) ++{ ++ ipmi_smi_t intf; ++ mutex_lock(&ipmi_interfaces_mutex); ++ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { ++ if (intf->intf_num == if_num){ ++ mutex_unlock(&ipmi_interfaces_mutex); ++ return &intf->bmc->dev->dev; ++ } ++ } ++ mutex_unlock(&ipmi_interfaces_mutex); ++ ++ return NULL; ++} ++ + static int __find_bmc_guid(struct device *dev, void *data) + { + unsigned char *id = data; +@@ -4196,3 +4214,4 @@ EXPORT_SYMBOL(ipmi_get_my_LUN); + EXPORT_SYMBOL(ipmi_smi_add_proc_entry); + EXPORT_SYMBOL(ipmi_user_set_run_to_completion); + EXPORT_SYMBOL(ipmi_free_recv_msg); ++EXPORT_SYMBOL(ipmi_get_bmcdevice); +diff -rduNp linux-2.6.22.1.oorig2/drivers/hwmon/Kconfig linux-2.6.22.1/drivers/hwmon/Kconfig +--- linux-2.6.22.1.oorig2/drivers/hwmon/Kconfig 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/drivers/hwmon/Kconfig 2007-07-24 14:22:26.000000000 +0200 +@@ -248,6 +248,16 @@ config SENSORS_CORETEMP + sensor inside your CPU. Supported all are all known variants + of Intel Core family. + ++config SENSORS_IPMI ++ tristate "IPMI Hardware Monitoring Support" ++ depends on HWMON && IPMI_HANDLER && EXPERIMENTAL ++ help ++ If you say yes here you get support for sensors monitored by ++ an IPMI baseboard management controller (BMC). ++ ++ This driver can also be built as a module. If so, the module ++ will be called ipmisensors. ++ + config SENSORS_IT87 + tristate "ITE IT87xx and compatibles" + depends on I2C +diff -rduNp linux-2.6.22.1.oorig2/drivers/hwmon/Makefile linux-2.6.22.1/drivers/hwmon/Makefile +--- linux-2.6.22.1.oorig2/drivers/hwmon/Makefile 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/drivers/hwmon/Makefile 2007-07-24 14:22:26.000000000 +0200 +@@ -32,6 +32,7 @@ obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o + obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o + obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o + obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o ++obj-$(CONFIG_SENSORS_IPMI) += ipmisensors.o + obj-$(CONFIG_SENSORS_IT87) += it87.o + obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o + obj-$(CONFIG_SENSORS_LM63) += lm63.o +diff -rduNp linux-2.6.22.1.oorig2/drivers/hwmon/ipmisensors.c linux-2.6.22.1/drivers/hwmon/ipmisensors.c +--- linux-2.6.22.1.oorig2/drivers/hwmon/ipmisensors.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/drivers/hwmon/ipmisensors.c 2007-07-24 14:22:26.000000000 +0200 +@@ -0,0 +1,1552 @@ ++/* ++ * ipmisensors.c - lm-sensors/hwmon interface to IPMI sensors. ++ * ++ * Copyright (C) 2004-2006 Yani Ioannou ++ * ++ * Adapted from bmcsensors (lm-sensors for linux 2.4) ++ * bmcsensors (C) Mark D. Studebaker ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ipmisensors.h" ++ ++/****** Function Prototypes ******/ ++static void ipmisensors_send_message(struct ipmisensors_bmc_data *bmc, ++ long msgid, struct kernel_ipmi_msg *msg); ++static void ipmisensors_reserve_sdr(struct ipmisensors_bmc_data *bmc); ++static void ipmisensors_get_sdr(struct ipmisensors_bmc_data *bmc, u16 res_id, ++ u16 record, u8 offset); ++static void ipmisensors_set_sensor_threshold(struct ipmisensors_bmc_data *bmc, ++ u8 number, int value, ++ int lim_index); ++static void ipmisensors_get_reading(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr); ++static void ipmisensors_msg_handler(struct ipmi_recv_msg *msg, ++ void *user_msg_data); ++static int ipmisensors_intf_registered(int ipmi_intf); ++static int ipmisensors_bmc_registered(struct device *bmc); ++static void ipmisensors_register_bmc(int ipmi_intf, struct ipmi_addr *address); ++static void ipmisensors_unregister_bmc(int ipmi_intf); ++static void ipmisensors_unregister_bmc_all(void); ++static void ipmisensors_new_smi(int if_num, struct device *dev); ++static void ipmisensors_smi_gone(int if_num); ++static void ipmisensors_update_bmc(struct work_struct *); ++static void ipmisensors_cleanup(void); ++ ++/****** Static Vars ******/ ++ ++/* set when module is being removed */ ++static int cleanup = 0; ++ ++/* ipmisensors driver data */ ++static struct ipmisensors_data driver_data = { ++ .driver_name = "bmc", ++ .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data), ++ .interfaces = 0, ++ .smi_watcher = { ++ .owner = THIS_MODULE, ++ .new_smi = ipmisensors_new_smi, ++ .smi_gone = ipmisensors_smi_gone, ++ }, ++ .ipmi_hndlrs = { ++ .ipmi_recv_hndl = ipmisensors_msg_handler, ++ }, ++}; ++ ++/* sensor refresh workqueue */ ++static struct workqueue_struct *ipmisensors_workqueue; ++ ++/****** SDR List Functions ******/ ++/** ++ * Creates a new sdrdata struct, or returns NULL if insufficient memory. ++ */ ++static struct sdrdata *ipmisensors_new_sdr(void) ++{ ++ struct sdrdata *sdr; ++ ++ sdr = kmem_cache_alloc(driver_data.sdrdata_cache, GFP_ATOMIC); ++ if (sdr) { ++ memset(sdr, 0, sizeof(struct sdrdata)); ++ } else { ++ printk(KERN_ERR ++ "ipmisensors: Couldn't allocate memory for new SDR\n"); ++ } ++ ++ return sdr; ++} ++ ++/** ++ * Adds the given sdrdata struct to the given bmc's SDR list. ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static inline void ipmisensors_add_sdr(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr) ++{ ++ list_add(&sdr->list, &bmc->sdrs); ++ printk(KERN_DEBUG ++ "ipmisensors: SDR %d: type 0x%02x (%s)\n", ++ bmc->sdr_count, sdr->stype, sdr->id); ++ bmc->sdr_count++; ++} ++ ++/** ++ * Cleanup the sdr list for the given BMC. ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static void ipmisensors_sdr_cleanup(struct ipmisensors_bmc_data *bmc) ++{ ++ struct sdrdata *cursor, *next; ++ ++ /* find and free each sdr data struct */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ device_remove_file(bmc->dev, &cursor->attr.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_min.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_max.dev_attr); ++ device_remove_file(bmc->dev, &cursor->attr_label.dev_attr); ++ ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ ++ list_del(&cursor->list); ++ kmem_cache_free(driver_data.sdrdata_cache, cursor); ++ } ++} ++ ++/* worker function for workqueue ipmisensors_workqueue */ ++static void ipmisensors_update_bmc(struct work_struct *work) ++{ ++ struct ipmisensors_bmc_data *bmc = container_of(work, struct ipmisensors_bmc_data, update_work.work); ++ ++ /* don't start an update cycle if one already in progress */ ++ if (bmc->state != STATE_READING) { ++ struct sdrdata *cursor, *next; ++ bmc->state = STATE_READING; ++ printk(KERN_DEBUG "ipmisensors: starting update\n"); ++ ++ /* init semaphore to 1 for update cycle */ ++ sema_init(&bmc->update_semaphore, 1); ++ ++ /* update each sdr reading */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ ipmisensors_get_reading(bmc, cursor); ++ } ++ } ++ ++ /* wait for readings (need timeout?) */ ++ down_interruptible(&bmc->update_semaphore); ++ ++ printk(KERN_DEBUG "ipmisensors: update complete\n"); ++ ++ bmc->state = STATE_DONE; ++ ++ /* if the module isn't cleaning up, schedule another update */ ++ if (!cleanup) ++ queue_delayed_work(ipmisensors_workqueue, &bmc->update_work, ++ bmc->update_period * HZ); ++} ++ ++/****** IPMI Message Sending ******/ ++ ++/** ++ * Send a message to the IPMI BMC ++ * ++ * @bmc: the bmc to send the message to. ++ * @msgid: the message id to use. ++ * @msg: the ipmi message structure. ++ */ ++static void ipmisensors_send_message(struct ipmisensors_bmc_data *bmc, ++ long msgid, struct kernel_ipmi_msg *msg) ++{ ++ if (msg->data == NULL) ++ printk(KERN_DEBUG "ipmisensors: Send 0x%x\n", msg->cmd); ++ else ++ printk(KERN_DEBUG "ipmisensors: Send 0x%x 0x%x 0x%x\n", ++ msg->cmd, msg->data[0], msg->data[1]); ++ ++ /* This should be ipmi_request, but Corey had to remove ++ * that due to it being unused at the moment, as soon as ++ * this makes it into the kernel we should request it be re-instated. ++ */ ++ ipmi_request_settime(bmc->user, &bmc->address, msgid, msg, bmc, 0, ++ -1, 0); ++} ++ ++/** ++ * Compose and send a "reserve SDR" message ++ * ++ * @bmc: the bmc to send the message to. ++ */ ++static void ipmisensors_reserve_sdr(struct ipmisensors_bmc_data *bmc) ++{ ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_RESERVE_SDR; ++ bmc->tx_message.data_len = 0; ++ bmc->tx_message.data = NULL; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Componse and send a "get SDR" message ++ * ++ * @bmc: the bmc to send the message to. ++ * @res_id: ++ * @record: ++ * @offset: ++ */ ++static void ipmisensors_get_sdr(struct ipmisensors_bmc_data *bmc, u16 res_id, ++ u16 record, u8 offset) ++{ ++ printk(KERN_DEBUG "ipmisensors: Get SDR 0x%x 0x%x 0x%x\n", ++ res_id, record, offset); ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_GET_SDR; ++ bmc->tx_message.data_len = 6; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = res_id & 0xff; ++ bmc->tx_msg_data[1] = res_id >> 8; ++ bmc->tx_msg_data[2] = record & 0xff; ++ bmc->tx_msg_data[3] = record >> 8; ++ bmc->tx_msg_data[4] = offset; ++ bmc->tx_msg_data[5] = bmc->ipmi_sdr_partial_size; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Compose and send a "set sensor threshold" message ++ * ++ * @bmc: the bmc to send the message to. ++ * @id: the ipmi id number of the sensor. ++ * @value: the new value for the threshold. ++ * @lim_index: the index in the lim[] array for which this value applies. ++ */ ++static void ipmisensors_set_sensor_threshold(struct ipmisensors_bmc_data *bmc, ++ u8 number, int value, ++ int lim_index) ++{ ++ int i; ++ ++ printk(KERN_DEBUG "ipmisensors: Set SDR Threshold %d %d %d\n", ++ number, value, lim_index); ++ bmc->tx_message.netfn = IPMI_NETFN_STORAGE_REQUEST; ++ bmc->tx_message.cmd = IPMI_SET_SENSOR_THRESHOLD; ++ bmc->tx_message.data_len = 8; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = number & 0xff; ++ bmc->tx_msg_data[1] = 0x01 << lim_index; ++ ++ if (lim_index > 5 || lim_index < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Error - ipmisensors_set_sensor_threshold given invalid lim_index\n"); ++ return; ++ } ++ ++ for (i = 2; i < 8; i++) ++ bmc->tx_msg_data[i] = 0x00; ++ ++ bmc->tx_msg_data[lim_index] = value && 0xff; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++} ++ ++/** ++ * Compose and send a "get sensor reading" message for the given sdr. ++ * ++ * @bmc: the bmc to send the message to. ++ * @sdr: the sdr of the sensor to get the reading for. ++ */ ++static void ipmisensors_get_reading(struct ipmisensors_bmc_data *bmc, ++ struct sdrdata *sdr) ++{ ++ bmc->tx_message.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST; ++ bmc->tx_message.cmd = IPMI_GET_SENSOR_STATE_READING; ++ bmc->tx_message.data_len = 1; ++ bmc->tx_message.data = bmc->tx_msg_data; ++ bmc->tx_msg_data[0] = sdr->number; ++ bmc->current_sdr = sdr; ++ ++ ipmisensors_send_message(bmc, bmc->msgid++, &bmc->tx_message); ++ down_interruptible(&bmc->update_semaphore); ++} ++ ++/****** IPMI Message Receiving ******/ ++ ++/** ++ * Process an sensor reading response message. ++ * ++ * @bmc: the bmc the message is from ++ * @msg: the IPMI SDR response message ++ */ ++static void ipmisensors_rcv_reading_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ struct sdrdata *sdr = bmc->current_sdr; ++ ++ if (sdr == NULL) { ++ printk(KERN_ERR ++ "ipmisensors: Error ipmisensors_rcv_reading with NULL sdr\n"); ++ return; ++ } ++ ++ sdr->reading = msg->data[1]; ++ sdr->status = msg->data[2]; ++ sdr->thresholds = msg->data[3]; ++ ++ printk(KERN_DEBUG "ipmisensors: sensor %d (type %d) reading %d\n", ++ sdr->number, sdr->stype, msg->data[1]); ++ ++ up(&bmc->update_semaphore); ++} ++ ++/** ++ * Unpack based on string type, convert to normal, null terminate. ++ */ ++static void ipmisensors_sprintf(u8 * to, u8 * from, u8 type, u8 length) ++{ ++ static const u8 *bcdplus = "0123456789 -.:,_"; ++ int i; ++ ++ switch (type) { ++ case 0: /* unicode */ ++ for (i = 0; i < length; i++) ++ *to++ = (*from++ & 0x7f); ++ *to = 0; ++ break; ++ case 1: /* BCD Plus */ ++ for (i = 0; i < length; i++) ++ *to++ = bcdplus[*from++ & 0x0f]; ++ *to = 0; ++ break; ++ case 2: /* packed ascii *//* if not a mult. of 3 this will run over */ ++ for (i = 0; i < length; i += 3) { ++ *to++ = *from & 0x3f; ++ *to++ = *from >> 6 | ((*(from+1) & 0xf) << 2); ++ from++; ++ *to++ = *from >> 4 | ((*(from+1) & 0x3) << 4); ++ from++; ++ *to++ = (*from++ >> 2) & 0x3f; ++ } ++ *to = 0; ++ break; ++ case 3: /* normal */ ++ if (length > 1) ++ memcpy(to, from, length); ++ to[length] = 0; ++ break; ++ } ++} ++ ++/* IPMI V1.5 Section 30 */ ++static const int exps[] = ++ { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; ++ ++/* Return 0 for fan, 2 for temp, 3 for voltage ++ We could make it variable based on the accuracy (= log10(m * 10**k2)); ++ this would work for /proc output, however libsensors resolution ++ is statically set in lib/chips.c */ ++static int decplaces(struct sdrdata *sd) ++{ ++ switch (sd->stype) { ++ case STYPE_TEMP: ++ return 2; ++ case STYPE_CURR: ++ case STYPE_VOLT: ++ return 3; ++ case STYPE_FAN: ++ default: ++ return 0; ++ } ++} ++ ++/* convert a raw value to a reading. IMPI V1.5 Section 30 */ ++static long conv_val(int value, struct sdrdata *sd) ++{ ++ u8 k1, k2; ++ long r; ++ ++ r = value * sd->m; ++ k1 = sd->k & 0x0f; ++ k2 = sd->k >> 4; ++ if (k1 < 8) ++ r += sd->b * exps[k1]; ++ else ++ r += sd->b / exps[16 - k1]; ++ r *= exps[decplaces(sd)]; ++ if (k2 < 8) { ++ if (sd->linear != 7) ++ r *= exps[k2]; ++ else ++ /* this will always truncate to 0: r = 1 / (exps[k2] * r); */ ++ r = 0; ++ } else { ++ if (sd->linear != 7) ++ r /= exps[16 - k2]; ++ else { ++ if (r != 0) ++ /* 1 / x * 10 ** (-m) == 10 ** m / x */ ++ r = exps[16 - k2] / r; ++ else ++ r = 0; ++ } ++ } ++ ++ return r; ++} ++ ++static const char *threshold_text[] = { ++ "upper non-recoverable threshold", ++ "upper critical threshold", ++ "upper non-critical threshold", ++ "lower non-recoverable threshold", ++ "lower critical threshold", ++ "lower non-critical threshold", ++ "positive-going hysteresis", ++ "negative-going hysteresis" /* unused */ ++}; ++ ++/* select two out of the 8 possible readable thresholds, and place indexes into the limits ++ array into lim1 and lim2. Set writable flags */ ++static void ipmisensors_select_thresholds(struct sdrdata *sd) ++{ ++ u8 capab = sd->capab; ++ u16 mask = sd->thresh_mask; ++ int tmp; ++ ++ sd->lim1 = -1; ++ sd->lim2 = -1; ++ sd->lim1_write = 0; ++ sd->lim2_write = 0; ++ ++ if (((capab & 0x0c) == 0x04) || /* readable thresholds ? */ ++ ((capab & 0x0c) == 0x08)) { ++ /* select upper threshold */ ++ if (mask & 0x10) { /* upper crit */ ++ sd->lim1 = 1; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x1000)) ++ sd->lim1_write = 1; ++ } else if (mask & 0x20) { /* upper non-recov */ ++ sd->lim1 = 0; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x2000)) ++ sd->lim1_write = 1; ++ } else if (mask & 0x08) { /* upper non-crit */ ++ sd->lim1 = 2; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0800)) ++ sd->lim1_write = 1; ++ } ++ ++ /* select lower threshold */ ++ if ((((capab & 0x30) == 0x10) || /* readable ? */ ++ ((capab & 0x30) == 0x20)) && /* pos hyst */ ++ sd->stype == STYPE_TEMP) ++ sd->lim2 = 6; ++ else if (mask & 0x02) { /* lower crit */ ++ sd->lim2 = 4; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0200)) ++ sd->lim2_write = 1; ++ } else if (mask & 0x04) { /* lower non-recov */ ++ sd->lim2 = 3; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0400)) ++ sd->lim2_write = 1; ++ } else if (mask & 0x01) { /* lower non-crit */ ++ sd->lim2 = 5; ++ if ((capab & 0x0c) == 0x08 && (mask & 0x0100)) ++ sd->lim2_write = 1; ++ } ++ } ++ ++ /* swap lim1/lim2 if m < 0 or function is 1/x (but not both!) */ ++ if ((sd->m < 0 && sd->linear != 7) || (sd->m >= 0 && sd->linear == 7)) { ++ tmp = sd->lim1; ++ sd->lim1 = sd->lim2; ++ sd->lim2 = tmp; ++ } ++ ++ if (sd->lim1 >= 0) ++ printk(KERN_INFO "ipmisensors: using %s for upper limit\n", ++ threshold_text[sd->lim1]); ++ else ++ printk(KERN_DEBUG "ipmisensors: no readable upper limit\n"); ++ ++ if (sd->lim2 >= 0) ++ printk(KERN_INFO "ipmisensors: using %s for lower limit\n", ++ threshold_text[sd->lim2]); ++ else ++ printk(KERN_DEBUG "ipmisensors: no readable lower limit\n"); ++} ++ ++/************* sysfs callback functions *********/ ++static ssize_t show_update_period(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ ++ return snprintf(buf, 20, "%d\n", aattr->bmc->update_period); ++} ++ ++static ssize_t store_update_period(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ ++ aattr->bmc->update_period = simple_strtoul(buf, NULL, 10);; ++ return count; ++}; ++ ++static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ return snprintf(buf, 20, "%ld\n", ++ conv_val(sattr->sdr->reading, sattr->sdr)); ++} ++ ++static ssize_t show_sensor_max(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ long max = 0; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ if (sattr->sdr->lim1 >= 0) ++ max = conv_val(sattr->sdr->limits[sattr->sdr->lim1], ++ sattr->sdr); ++ return snprintf(buf, 20, "%ld\n", max); ++} ++ ++static ssize_t show_sensor_min(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ long min = 0; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ if (sattr->sdr->lim2 >= 0) ++ min = conv_val(sattr->sdr->limits[sattr->sdr->lim2], ++ sattr->sdr); ++ return snprintf(buf, 20, "%ld\n", min); ++}; ++ ++static ssize_t show_sensor_label(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ u8 label[SDR_MAX_UNPACKED_ID_LENGTH]; ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ ++ ipmisensors_sprintf(label, sattr->sdr->id, sattr->sdr->string_type, ++ sattr->sdr->id_length); ++ return snprintf(buf, 20, "%s\n", label); ++}; ++ ++static ssize_t store_sensor_max(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ long val = simple_strtoul(buf, NULL, 10); ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ printk(KERN_DEBUG "ipmisensors: set max on sensor #%d to %ld", ++ sattr->sdr->number, val); ++ ipmisensors_set_sensor_threshold(sattr->sdr->bmc, sattr->sdr->number, ++ val, sattr->sdr->lim1); ++ return count; ++}; ++ ++static ssize_t store_sensor_min(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ long val = simple_strtoul(buf, NULL, 10); ++ struct ipmisensors_device_attribute *sattr = ++ to_ipmisensors_dev_attr(attr); ++ printk(KERN_DEBUG "ipmisensors: set min on sensor #%d to %ld", ++ sattr->sdr->number, val); ++ ipmisensors_set_sensor_threshold(sattr->sdr->bmc, sattr->sdr->number, ++ val, sattr->sdr->lim2); ++ return count; ++}; ++ ++static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ipmisensors_bmc_device_attribute *aattr = ++ to_ipmisensors_bmc_dev_attr(attr); ++ return snprintf(buf, 20, "%d\n", aattr->bmc->alarms); ++}; ++ ++static ssize_t show_name(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ return snprintf(buf, 20, "%s\n", driver_data.driver_name); ++}; ++ ++/* work function to build the sysfs entries using the ipmi sdrs */ ++static void ipmisensors_build_sysfs(struct work_struct *work) ++{ ++ int temps = 0, volts = 0, currs = 0, fans = 0; ++ struct sdrdata *cursor, *next; ++ struct ipmisensors_bmc_data *bmc = container_of(work, struct ipmisensors_bmc_data, sysfs_work); ++ ++ /* find and create entries for each sdr data struct */ ++ list_for_each_entry_safe(cursor, next, &bmc->sdrs, list) { ++ u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; ++ ++ cursor->attr_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ cursor->attr_max_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ cursor->attr_min_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ ++ if (cursor->id_length > 0) { ++ cursor->attr_label_name = ++ (char *)kmalloc(sizeof(char) * MAX_FILENAME_LENGTH, ++ GFP_KERNEL); ++ ++ if (cursor->attr_label_name == NULL) { ++ printk(KERN_INFO ++ "ipmisensors: Out of memory (kmalloc failed)"); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ return; ++ } ++ } ++ ++ if (cursor->attr_name == NULL || cursor->attr_max_name == NULL ++ || cursor->attr_min_name == NULL ++ || cursor->attr_label_name == NULL) { ++ printk(KERN_INFO ++ "ipmisensors: Out of memory (kmalloc failed)"); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ return; ++ } ++ ++ switch (cursor->stype) { ++ case (STYPE_TEMP): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "temp%d_input", ++temps); ++ /* create min, max attributes */ ++ snprintf(cursor->attr_max_name, MAX_FILENAME_LENGTH, ++ "temp%d_max", temps); ++ snprintf(cursor->attr_min_name, MAX_FILENAME_LENGTH, ++ "temp%d_min", temps); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "temp%d_label", temps); ++ break; ++ case (STYPE_VOLT): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "in%d_input", ++volts); ++ /* create min, max attributes */ ++ snprintf(cursor->attr_max_name, MAX_FILENAME_LENGTH, ++ "in%d_max", volts); ++ snprintf(cursor->attr_min_name, MAX_FILENAME_LENGTH, ++ "in%d_min", volts); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "in%d_label", volts); ++ break; ++ case (STYPE_CURR): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "curr%d_input", ++currs); ++ /* create min, max attributes */ ++ sprintf(cursor->attr_max_name, "curr%d_max", currs); ++ sprintf(cursor->attr_min_name, "curr%d_min", currs); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "curr%d_label", currs); ++ break; ++ case (STYPE_FAN): ++ /* create the name of the sensor */ ++ snprintf(cursor->attr_name, MAX_FILENAME_LENGTH, ++ "fan%d_input", ++fans); ++ /* create min, max attributes */ ++ sprintf(cursor->attr_max_name, "fan%d_max", fans); ++ sprintf(cursor->attr_min_name, "fan%d_min", fans); ++ /* create the label of the sensor */ ++ snprintf(cursor->attr_label_name, MAX_FILENAME_LENGTH, ++ "fan%d_label", fans); ++ break; ++ default: ++ printk(KERN_INFO "ipmisensors: unkown sensor type\n"); ++ continue; ++ } ++ ++ cursor->attr.dev_attr.attr.name = cursor->attr_name; ++ cursor->attr.dev_attr.attr.mode = S_IRUGO; ++ cursor->attr.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr.dev_attr.show = show_sensor; ++ cursor->attr.dev_attr.store = NULL; ++ cursor->attr.sdr = cursor; ++ ++ cursor->attr_min.dev_attr.attr.name = cursor->attr_min_name; ++ cursor->attr_min.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_min.dev_attr.show = show_sensor_min; ++ cursor->attr_min.sdr = cursor; ++ ++ if (cursor->lim2_write) { ++ printk(KERN_INFO ++ "ipmisensors: You have a writable sensor threshold! Send me an e-mail at .\n"); ++ cursor->attr_min.dev_attr.store = store_sensor_min; ++ cursor->attr_min.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ } else { ++ cursor->attr_min.dev_attr.store = NULL; ++ cursor->attr_min.dev_attr.attr.mode = S_IRUGO; ++ } ++ ++ cursor->attr_max.dev_attr.attr.name = cursor->attr_max_name; ++ cursor->attr_max.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_max.dev_attr.show = show_sensor_max; ++ cursor->attr_max.sdr = cursor; ++ ++ if (cursor->lim1_write) { ++ printk(KERN_INFO ++ "ipmisensors: You have a writable sensor threshold! Send me an e-mail at .\n"); ++ cursor->attr_max.dev_attr.store = store_sensor_max; ++ cursor->attr_max.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ } else { ++ cursor->attr_max.dev_attr.store = NULL; ++ cursor->attr_max.dev_attr.attr.mode = S_IRUGO; ++ } ++ ++ if (cursor->id_length > 0) { ++ cursor->attr_label.dev_attr.attr.name = ++ cursor->attr_label_name; ++ cursor->attr_label.dev_attr.attr.mode = S_IRUGO; ++ cursor->attr_label.dev_attr.attr.owner = THIS_MODULE; ++ cursor->attr_label.dev_attr.show = show_sensor_label; ++ cursor->attr_label.dev_attr.store = NULL; ++ cursor->attr_label.sdr = cursor; ++ } ++ ++ printk(KERN_INFO ++ "ipmisensors: registering sensor %d: (type 0x%.2x) " ++ "(fmt=%d; m=%d; b=%d; k1=%d; k2=%d; cap=0x%.2x; mask=0x%.4x)\n", ++ cursor->number, cursor->stype, cursor->format, cursor->m, ++ cursor->b, cursor->k & 0xf, cursor->k >> 4, ++ cursor->capab, cursor->thresh_mask); ++ ++ if (cursor->id_length > 0) { ++ ipmisensors_sprintf(id, cursor->id, cursor->string_type, ++ cursor->id_length); ++ switch (cursor->stype) { ++ case (STYPE_TEMP): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label temp%d \"%s\"\n", ++ temps, id); ++ break; ++ case (STYPE_VOLT): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label in%d \"%s\"\n", ++ volts, id); ++ break; ++ case (STYPE_CURR): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label curr%d \"%s\"\n", ++ currs, id); ++ break; ++ case (STYPE_FAN): ++ printk(KERN_INFO ++ "ipmisensors: sensors.conf: label fan%d \"%s\"\n", ++ fans, id); ++ break; ++ } ++ } ++ ++ ipmisensors_select_thresholds(cursor); ++ ++ if (cursor->linear != 0 && cursor->linear != 7) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: nonlinear function 0x%.2x unsupported, expect bad results\n", ++ cursor->number, cursor->linear); ++ } ++ ++ if ((cursor->format & 0x03) == 0x02) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: 1's complement format unsupported, expect bad results\n", ++ cursor->number); ++ } else if ((cursor->format & 0x03) == 0x03) { ++ printk(KERN_INFO ++ "ipmisensors: sensor %d: threshold sensor only, no readings available", ++ cursor->number); ++ } ++ ++ if (cursor->lim1_write || cursor->lim2_write) ++ cursor->attr.dev_attr.attr.mode = 0644; ++ else ++ cursor->attr.dev_attr.attr.mode = 0444; ++ ++ if (device_create_file(bmc->dev, &cursor->attr.dev_attr) < 0 ++ || device_create_file(bmc->dev, ++ &cursor->attr_min.dev_attr) < 0 ++ || device_create_file(bmc->dev, ++ &cursor->attr_max.dev_attr) < 0 ++ || (cursor->id_length > ++ 0 ? device_create_file(bmc->dev, ++ &cursor->attr_label.dev_attr) < ++ 0 : 0) ++ ) { ++ printk(KERN_INFO ++ "ipmisensors: sysfs file creation failed for SDR %d (%s).\n", ++ cursor->number, cursor->id); ++ kfree(cursor->attr_name); ++ kfree(cursor->attr_max_name); ++ kfree(cursor->attr_min_name); ++ kfree(cursor->attr_label_name); ++ return; ++ } ++ } ++ ++ bmc->alarms_attr.dev_attr.attr.name = "alarms"; ++ bmc->alarms_attr.dev_attr.attr.mode = S_IRUGO; ++ bmc->alarms_attr.dev_attr.attr.owner = THIS_MODULE; ++ bmc->alarms_attr.dev_attr.show = show_alarms; ++ bmc->alarms_attr.dev_attr.store = NULL; ++ bmc->alarms_attr.bmc = bmc; ++ ++ if (device_create_file(bmc->dev, &bmc->alarms_attr.dev_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'alarms'"); ++ return; ++ } ++ ++ bmc->name_attr.attr.name = "name"; ++ bmc->name_attr.attr.mode = S_IRUGO; ++ bmc->name_attr.attr.owner = THIS_MODULE; ++ bmc->name_attr.show = show_name; ++ ++ if (device_create_file(bmc->dev, &bmc->name_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'name'"); ++ return; ++ } ++ ++ bmc->update_attr.dev_attr.attr.name = "update_period"; ++ bmc->update_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO; ++ bmc->update_attr.dev_attr.attr.owner = THIS_MODULE; ++ bmc->update_attr.dev_attr.show = show_update_period; ++ bmc->update_attr.dev_attr.store = store_update_period; ++ bmc->update_attr.bmc = bmc; ++ ++ if (device_create_file(bmc->dev, &bmc->update_attr.dev_attr) < 0) { ++ printk(KERN_INFO ++ "ipmisensors: Failed to create sysfs entry 'update_period'"); ++ return; ++ } ++ ++ printk(KERN_INFO ++ "ipmisensors: registered %d temp, %d volt, %d current, %d fan sensors\n", ++ temps, volts, currs, fans); ++ ++ /* This completes the initialization. We can now kickoff the ++ * periodic update of the bmc sensor's values by scheduling ++ * the first work. ++ */ ++ queue_work(ipmisensors_workqueue, &bmc->update_work.work); ++ ++} ++ ++/** ++ * Process an SDR response message, save the SDRs we like in the sdr ++ * list for the given BMC. ++ * ++ * @bmc: the bmc the message is from ++ * @msg: the IPMI SDR response message ++ */ ++static void ipmisensors_rcv_sdr_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ u16 record; ++ int type; ++ int stype; ++ int id_length; ++ int i; ++ int ipmi_ver = 0; ++ unsigned char *data; ++ u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; ++ struct sdrdata *sdr; ++ ++ if (msg->data[0] != 0) { ++ /* cut request in half and try again */ ++ bmc->ipmi_sdr_partial_size /= 2; ++ if (bmc->ipmi_sdr_partial_size < 8) { ++ printk(KERN_INFO ++ "ipmisensors: IPMI buffers too small, giving up\n"); ++ bmc->state = STATE_DONE; ++ return; ++ } ++ printk(KERN_DEBUG ++ "ipmisensors: Reducing SDR request size to %d\n", ++ bmc->ipmi_sdr_partial_size); ++ ++ ipmisensors_get_sdr(bmc, 0, 0, 0); ++ bmc->state = STATE_SDR; ++ return; ++ } ++ if (bmc->ipmi_sdr_partial_size < IPMI_SDR_SIZE) { ++ if (bmc->rx_msg_data_offset == 0) { ++ memcpy(bmc->rx_msg_data, msg->data, ++ bmc->ipmi_sdr_partial_size + 3); ++ bmc->rx_msg_data_offset = ++ bmc->ipmi_sdr_partial_size + 3; ++ } else { ++ memcpy(bmc->rx_msg_data + bmc->rx_msg_data_offset, ++ msg->data + 3, bmc->ipmi_sdr_partial_size); ++ bmc->rx_msg_data_offset += bmc->ipmi_sdr_partial_size; ++ } ++ if (bmc->rx_msg_data_offset > bmc->rx_msg_data[7] + 7) { ++ /* got last chunk */ ++ bmc->rx_msg_data_offset = 0; ++ data = bmc->rx_msg_data; ++ } else { ++ /* get more */ ++ record = ++ (bmc->rx_msg_data[4] << 8) | bmc->rx_msg_data[3]; ++ ipmisensors_get_sdr(bmc, bmc->resid, record, ++ bmc->rx_msg_data_offset - 3); ++ bmc->state = STATE_SDR; ++ return; ++ } ++ } else { ++ /* got it in one chunk */ ++ data = msg->data; ++ } ++ ++ bmc->nextrecord = (data[2] << 8) | data[1]; ++ ++ /* If the ipmi version is 0.9 we have to remap some things. ++ * Yes this is very ugly, but we aren't the ones who ++ * implemented an incomplete spec! ++ */ ++ ipmi_ver = data[5]; ++ ++ type = data[6]; ++ /* known SDR type */ ++ if (type == 1 || type == 2) { ++ stype = data[(ipmi_ver == 0x90 ? 16 : 15)]; ++ /* known sensor type */ ++ if (stype <= STYPE_MAX) { ++ if (data[(ipmi_ver == 0x90 ? 17 : 16)] != 0x01) { ++ if (type == 1) ++ ipmisensors_sprintf(id, &data[51], ++ data[50] >> 6, ++ data[50] & 0x1f); ++ else ++ ipmisensors_sprintf(id, ++ &data[(ipmi_ver == ++ 0x90 ? 30 : ++ 35)], ++ data[(ipmi_ver == ++ 0x90 ? 29 : ++ 34)] >> 6, ++ data[(ipmi_ver == ++ 0x90 ? 29 : ++ 34)] & 0x1f); ++ printk(KERN_INFO ++ "ipmisensors: skipping non-threshold sensor \"%s\"\n", ++ id); ++ } else { ++ /* add entry to sdrd table */ ++ sdr = ipmisensors_new_sdr(); ++ if (!sdr) { ++ printk(KERN_ERR ++ "ipmisensors: could not allocate memory for new SDR"); ++ return; ++ } ++ sdr->bmc = bmc; ++ sdr->stype = stype; ++ sdr->number = data[10]; ++ sdr->capab = data[(ipmi_ver == 0x90 ? 15 : 14)]; ++ sdr->thresh_mask = ++ (((u16) data[(ipmi_ver == 0x90 ? 21 : 22)]) ++ << 8) | data[21]; ++ if (type == 1) { ++ sdr->format = ++ data[(ipmi_ver == ++ 0x90 ? 22 : 24)] >> 6; ++ sdr->linear = ++ data[(ipmi_ver == ++ 0x90 ? 25 : 26)] & 0x7f; ++ sdr->m = ++ data[(ipmi_ver == 0x90 ? 26 : 27)]; ++ sdr->m |= ((u16) ++ (data ++ [(ipmi_ver == ++ 0x90 ? 27 : 28)] ++ & 0xc0)) << 2; ++ if (sdr->m & 0x0200) { ++ /* sign extend */ ++ sdr->m |= 0xfc00; ++ } ++ sdr->b = ++ data[(ipmi_ver == 0x90 ? 28 : 29)]; ++ sdr->b |= ((u16) ++ (data ++ [(ipmi_ver == ++ 0x90 ? 29 : 30)] ++ & 0xc0)) << 2; ++ if (sdr->b & 0x0200) { ++ /* sign extend */ ++ sdr->b |= 0xfc00; ++ } ++ sdr->k = ++ data[(ipmi_ver == 0x90 ? 31 : 32)]; ++ sdr->nominal = ++ data[(ipmi_ver == 0x90 ? 33 : 34)]; ++ for (i = 0; i < SDR_LIMITS; i++) { ++ /* assume readable */ ++ sdr->limits[i] = ++ data[(ipmi_ver == ++ 0x90 ? 40 : 39) + i]; ++ } ++ sdr->string_type = data[50] >> 6; ++ id_length = data[50] & 0x1f; ++ memcpy(sdr->id, &data[51], id_length); ++ sdr->id_length = id_length; ++ } else { ++ sdr->m = 1; ++ sdr->b = 0; ++ sdr->k = 0; ++ sdr->string_type = ++ data[(ipmi_ver == ++ 0x90 ? 29 : 34)] >> 6; ++ id_length = data[34] & 0x1f; ++ if (id_length > 0) { ++ memcpy(sdr->id, ++ &data[(ipmi_ver == ++ 0x90 ? 30 : 35)], ++ id_length); ++ } ++ sdr->id_length = id_length; ++ /* limits?? */ ++ if (ipmi_ver == 0x90) { ++ memcpy(sdr->id, ++ &data[30], id_length); ++ sdr->id_length = id_length; ++ } ++ } ++ ipmisensors_add_sdr(bmc, sdr); ++ } ++ } ++ /* peek at the other SDR types */ ++ } else if (type == 0x10 || type == 0x11 || type == 0x12) { ++ ipmisensors_sprintf(id, data + 19, data[18] >> 6, ++ data[18] & 0x1f); ++ if (type == 0x10) { ++ printk(KERN_INFO ++ "ipmisensors: Generic Device acc=0x%x; slv=0x%x; lun=0x%x; type=0x%x; \"%s\"\n", ++ data[8], data[9], data[10], data[13], id); ++ } else if (type == 0x11) { ++ printk(KERN_INFO ++ "ipmisensors: FRU Device acc=0x%x; slv=0x%x; log=0x%x; ch=0x%x; type=0x%x; \"%s\"\n", ++ data[8], data[9], data[10], data[11], data[13], ++ id); ++ } else { ++ printk(KERN_INFO ++ "ipmisensors: Mgmt Ctllr Device slv=0x%x; \"%s\"\n", ++ data[8], id); ++ } ++ } else if (type == 0x14) { ++ printk(KERN_INFO ++ "ipmisensors: Message Channel Info Records:\n"); ++ for (i = 0; i < 8; i++) { ++ printk(KERN_INFO "ipmisensors: Channel %d info 0x%x\n", ++ i, data[9 + i]); ++ } ++ } else { ++ printk(KERN_INFO "ipmisensors: Skipping SDR type 0x%x\n", type); ++ } ++ if (ipmi_ver != 0x90) { ++ if (bmc->nextrecord >= 6224) { ++ /*YJ stop sensor scan on poweredge 1750 */ ++ bmc->nextrecord = 0xffff; ++ } ++ } ++ ++ if (bmc->nextrecord == 0xFFFF) { ++ if (bmc->sdr_count == 0) { ++ printk(KERN_INFO ++ "ipmisensors: No recognized sensors found.\n"); ++ bmc->state = STATE_DONE; ++ } else { ++ printk(KERN_INFO "ipmisensors: all sensors detected\n"); ++ bmc->state = STATE_SYSTABLE; ++ ++ /* Schedule sysfs build/registration work */ ++ INIT_WORK(&bmc->sysfs_work, ipmisensors_build_sysfs); ++ queue_work(ipmisensors_workqueue, &bmc->sysfs_work); ++ } ++ } else { ++ ipmisensors_get_sdr(bmc, 0, bmc->nextrecord, 0); ++ bmc->state = STATE_SDR; ++ } ++} ++ ++/** ++ * Process incoming messages based on internal state ++ * ++ * @bmc: the bmc the message is from. ++ * @msg: the ipmi message to process. ++ */ ++static void ipmisensors_rcv_msg(struct ipmisensors_bmc_data *bmc, ++ struct kernel_ipmi_msg *msg) ++{ ++ switch (bmc->state) { ++ case STATE_INIT: ++ case STATE_RESERVE: ++ bmc->resid = (((u16) msg->data[2]) << 8) | msg->data[1]; ++ ++ printk(KERN_DEBUG "ipmisensors: Got first resid 0x%.4x\n", ++ bmc->resid); ++ ++ ipmisensors_get_sdr(bmc, 0, 0, 0); ++ bmc->state = STATE_SDR; ++ break; ++ ++ case STATE_SDR: ++ case STATE_SDRPARTIAL: ++ ipmisensors_rcv_sdr_msg(bmc, msg); ++ break; ++ ++ case STATE_READING: ++ ipmisensors_rcv_reading_msg(bmc, msg); ++ break; ++ ++ case STATE_UNCANCEL: ++ bmc->resid = (((u16) msg->data[2]) << 8) | msg->data[1]; ++ ++ printk(KERN_DEBUG "ipmisensors: Got new resid 0x%.4x\n", ++ bmc->resid); ++ ++ bmc->rx_msg_data_offset = 0; ++ ipmisensors_get_sdr(bmc, 0, bmc->nextrecord, 0); ++ bmc->state = STATE_SDR; ++ break; ++ ++ case STATE_DONE: ++ case STATE_SYSTABLE: ++ break; ++ default: ++ bmc->state = STATE_INIT; ++ } ++} ++ ++/** ++ * Callback to handle a received IPMI message from a given BMC. ++ * ++ * @msg: the received message. ++ * @handler_data: a pointer to the particular bmc ipmisensors_bmc_data struct. ++ */ ++static void ipmisensors_msg_handler(struct ipmi_recv_msg *msg, ++ void *user_msg_data) ++{ ++ struct ipmisensors_bmc_data *bmc = ++ (struct ipmisensors_bmc_data *)user_msg_data; ++ ++ if (msg->msg.data[0] != 0) ++ printk(KERN_WARNING ++ "ipmisensors: Error 0x%x on cmd 0x%x/0x%x\n", ++ msg->msg.data[0], msg->msg.netfn, msg->msg.cmd); ++ ++ if (bmc != NULL && ipmisensors_intf_registered(bmc->interface_id)) { ++ if (bmc->state == STATE_SDR && ++ msg->msg.data[0] == IPMI_INVALID_RESERVATION_ID) { ++ /* reservation cancelled, get new resid */ ++ if (++bmc->errorcount > 275) { ++ printk(KERN_ERR ++ "ipmisensors: Too many reservations cancelled, giving up\n"); ++ bmc->state = STATE_DONE; ++ } else { ++ printk(KERN_DEBUG ++ "ipmisensors: resid 0x%04x cancelled, getting new one\n", ++ bmc->resid); ++ ++ ipmisensors_reserve_sdr(bmc); ++ bmc->state = STATE_UNCANCEL; ++ } ++ } else if (msg->msg.data[0] != IPMI_CC_NO_ERROR && ++ msg->msg.data[0] != IPMI_ERR_RETURNING_REQ_BYTES && ++ msg->msg.data[0] != IPMI_ERR_PROVIDING_RESPONSE) { ++ printk(KERN_ERR ++ "ipmisensors: Error 0x%x on cmd 0x%x/0x%x; state = %d; probably fatal.\n", ++ msg->msg.data[0], msg->msg.netfn & 0xfe, ++ msg->msg.cmd, bmc->state); ++ } else { ++ printk(KERN_DEBUG "ipmisensors: received message\n"); ++ ipmisensors_rcv_msg(bmc, &msg->msg); ++ } ++ ++ } else { ++ printk(KERN_WARNING ++ "ipmisensors: Response for non-registered BMC\n"); ++ if (bmc != NULL) ++ printk(KERN_DEBUG "ipmisensors: BMC ID: %d\n", ++ bmc->interface_id); ++ else ++ printk(KERN_DEBUG "ipmisensors: BMC NULL!\n"); ++ } ++ ++ ipmi_free_recv_msg(msg); ++} ++ ++/****** IPMI Interface Initialization ******/ ++ ++/** ++ * Return true if the given ipmi interface has been registered. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static int ipmisensors_intf_registered(int ipmi_intf) ++{ ++ int found = 0; ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->interface_id == ipmi_intf) { ++ found++; ++ } ++ } ++ ++ return found; ++} ++ ++/** ++ * Return true if the given BMC has been registered. ++ * ++ * @bmc: The BMC device. ++ */ ++static int ipmisensors_bmc_registered(struct device *bmc) ++{ ++ int found = 0; ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->dev == bmc) { ++ found++; ++ } ++ } ++ ++ return found; ++} ++ ++/** ++ * Register new IPMI BMC interface. Interface indpendent callback created ++ * for flexibility in adding new types of interface callbacks in future. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static void ipmisensors_register_bmc(int ipmi_intf, struct ipmi_addr *address) ++{ ++ int error; ++ ++ /* allocate a new ipmisensors_bmc_data struct */ ++ ++ struct ipmisensors_bmc_data *bmc = (struct ipmisensors_bmc_data *) ++ kmalloc(sizeof(struct ipmisensors_bmc_data), GFP_KERNEL); ++ ++ /* initialize members */ ++ INIT_LIST_HEAD(&bmc->sdrs); ++ bmc->interface_id = ipmi_intf; ++ ++ bmc->address = *address; ++ ++ bmc->sdr_count = 0; ++ bmc->msgid = 0; ++ bmc->ipmi_sdr_partial_size = IPMI_CHUNK_SIZE; ++ bmc->state = STATE_INIT; ++ bmc->errorcount = 0; ++ bmc->rx_msg_data_offset = 0; ++ bmc->dev = ipmi_get_bmcdevice(ipmi_intf); ++ ++ /* default to 3 second min update interval */ ++ bmc->update_period = 3; ++ ++ if (bmc->dev == NULL) { ++ printk(KERN_ERR ++ "ipmisensors: Error, couldn't get BMC device for interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Create IPMI messaging interface user */ ++ error = ipmi_create_user(bmc->interface_id, &driver_data.ipmi_hndlrs, ++ bmc, &bmc->user); ++ if (error < 0) { ++ printk(KERN_ERR ++ "ipmisensors: Error, unable to register user with ipmi interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Register the BMC as a HWMON class device */ ++ bmc->class_dev = hwmon_device_register(bmc->dev); ++ ++ if (IS_ERR(bmc->class_dev)) { ++ printk(KERN_ERR ++ "ipmisensors: Error, unable to register hwmon class device for interface %d\n", ++ bmc->interface_id); ++ kfree(bmc); ++ return; ++ } ++ ++ /* Register the BMC in the driver */ ++ if (ipmisensors_bmc_registered(bmc->dev)) { ++ printk(KERN_ERR ++ "ipmisensors: BMC on interface %d already registered\n", ++ bmc->interface_id); ++ hwmon_device_unregister(bmc->class_dev); ++ kfree(bmc); ++ return; ++ } ++ ++ ipmi_get_version(bmc->user, &bmc->ipmi_version_major, ++ &bmc->ipmi_version_minor); ++ ++ /* finally add the new bmc data to the bmc data list */ ++ list_add_tail(&bmc->list, &driver_data.bmc_data); ++ driver_data.interfaces++; ++ ++ printk(KERN_INFO ++ "ipmisensors: Registered IPMI %d.%d BMC over interface %d\n", ++ bmc->ipmi_version_major, ++ bmc->ipmi_version_minor, bmc->interface_id); ++ ++ /* Send a reserve SDR command to the bmc */ ++ ipmisensors_reserve_sdr(bmc); ++ ++ /* initialize the bmc's update work struct */ ++ INIT_DELAYED_WORK(&bmc->update_work, ipmisensors_update_bmc); ++} ++ ++/** ++ * Callback for when an IPMI BMC is gone. Interface indpendent callback created ++ * for flexibility in adding new types of interface callbacks in future. ++ * ++ * @ipmi_intf: The IPMI interface number. ++ */ ++static void ipmisensors_unregister_bmc(int ipmi_intf) ++{ ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ if (cursor->interface_id == ipmi_intf) { ++ list_del(&cursor->list); ++ printk(KERN_DEBUG ++ "ipmisensors: cancelling queued work\n"); ++ /* cancel update work queued for this bmc */ ++ cancel_delayed_work(&cursor->update_work); ++ printk(KERN_DEBUG ++ "ipmisensors: waiting for update to finish\n"); ++ /* wait for readings to finish */ ++ while (cursor->state != STATE_DONE) ; ++ ++ device_remove_file(cursor->dev, ++ &cursor->alarms_attr.dev_attr); ++ device_remove_file(cursor->dev, ++ &cursor->update_attr.dev_attr); ++ hwmon_device_unregister(cursor->class_dev); ++ ipmisensors_sdr_cleanup(cursor); ++ ipmi_destroy_user(cursor->user); ++ ++ printk(KERN_INFO ++ "ipmisensors: Unegistered IPMI interface %d\n", ++ cursor->interface_id); ++ ++ kfree(cursor); ++ driver_data.interfaces--; ++ } ++ } ++ ++} ++ ++/** ++ * Unregister all registered bmcs. ++ */ ++static void ipmisensors_unregister_bmc_all(void) ++{ ++ struct ipmisensors_bmc_data *cursor, *next; ++ ++ /* find and free the ipmisensors_bmc_data struct */ ++ list_for_each_entry_safe(cursor, next, &driver_data.bmc_data, list) { ++ list_del(&cursor->list); ++ ++ /* cancel update work queued for this bmc */ ++ printk(KERN_DEBUG "ipmisensors: cancelling queued work\n"); ++ cancel_delayed_work(&cursor->update_work); ++ ++ printk(KERN_DEBUG ++ "ipmisensors: waiting for update to finish\n"); ++ /* wait for readings to finish */ ++ while (cursor->state != STATE_DONE) ; ++ ++ device_remove_file(cursor->dev, &cursor->alarms_attr.dev_attr); ++ device_remove_file(cursor->dev, &cursor->update_attr.dev_attr); ++ hwmon_device_unregister(cursor->class_dev); ++ ipmisensors_sdr_cleanup(cursor); ++ ipmi_destroy_user(cursor->user); ++ ++ printk(KERN_INFO ++ "ipmisensors: Unegistered IPMI interface %d\n", ++ cursor->interface_id); ++ ++ kfree(cursor); ++ } ++ ++ driver_data.interfaces = 0; ++} ++ ++/** ++ * Callback for when a new IPMI SMI type interface is found. ++ * ++ * @if_num: The IPMI interface number. ++ */ ++static void ipmisensors_new_smi(int if_num, struct device *dev) ++{ ++ struct ipmi_addr smi_address = { ++ IPMI_SYSTEM_INTERFACE_ADDR_TYPE, ++ IPMI_BMC_CHANNEL, ++ {0}, ++ }; ++ ++ /* calls the generic new interface function */ ++ ipmisensors_register_bmc(if_num, &smi_address); ++} ++ ++/** ++ * Callback for when an exisiting IPMI SMI type interface is gone. ++ * ++ * @if_num: The IPMI interface number. ++ */ ++static void ipmisensors_smi_gone(int if_num) ++{ ++ if (driver_data.interfaces > 0) { ++ ipmisensors_unregister_bmc(if_num); ++ } ++} ++ ++/** ++ * Initialize the module. ++ */ ++static int __init ipmisensors_init(void) ++{ ++ int error; ++ printk(KERN_INFO "ipmisensors - IPMI BMC sensors interface\n"); ++ ++ /* init cache managers */ ++ driver_data.sdrdata_cache = ++ kmem_cache_create("ipmisensors_sdrdata", sizeof(struct sdrdata), 0, ++ 0, NULL, NULL); ++ driver_data.sysfsattr_cache = ++ kmem_cache_create("ipmisensors_sysfsattr", ++ sizeof(struct ipmisensors_device_attribute), 0, 0, ++ NULL, NULL); ++ ++ if (!driver_data.sdrdata_cache || !driver_data.sysfsattr_cache) { ++ if (driver_data.sdrdata_cache) ++ kmem_cache_destroy(driver_data.sdrdata_cache); ++ if (driver_data.sysfsattr_cache) ++ kmem_cache_destroy(driver_data.sysfsattr_cache); ++ return -ENOMEM; ++ } ++ ++ /* register IPMI interface callback(s) */ ++ error = ipmi_smi_watcher_register(&driver_data.smi_watcher); ++ if (error) { ++ printk(KERN_WARNING ++ "ipmisensors: can't register smi watcher\n"); ++ return error; ++ } ++ ++ /* create work queue, keep it simple, single-threaded */ ++ ipmisensors_workqueue = ++ create_singlethread_workqueue("ipmisensors_workqueue"); ++ ++ return 0; ++} ++ ++/** ++ * Cleanup ++ */ ++static void ipmisensors_cleanup(void) ++{ ++ /* start cleanup */ ++ cleanup = 1; ++ ++ /* unregister bmcs */ ++ printk(KERN_DEBUG "ipmisensors: unregister bmcs\n"); ++ ipmi_smi_watcher_unregister(&driver_data.smi_watcher); ++ ipmisensors_unregister_bmc_all(); ++ ++ /* flush & destroy work queue */ ++ printk(KERN_DEBUG "ipmisensors: destroy workqueue\n"); ++ flush_workqueue(ipmisensors_workqueue); ++ destroy_workqueue(ipmisensors_workqueue); ++ ++ /* remove cache managers */ ++ if (driver_data.sdrdata_cache) ++ kmem_cache_destroy(driver_data.sdrdata_cache); ++ if (driver_data.sysfsattr_cache) ++ kmem_cache_destroy(driver_data.sysfsattr_cache); ++} ++ ++/** ++ * Cleanup and exit the module ++ */ ++static void __exit ipmisensors_exit(void) ++{ ++ ipmisensors_cleanup(); ++ printk(KERN_DEBUG "ipmisensors: cleanup finished\n"); ++} ++ ++MODULE_AUTHOR("Yani Ioannou "); ++MODULE_DESCRIPTION("IPMI BMC sensors"); ++MODULE_LICENSE("GPL"); ++ ++module_init(ipmisensors_init); ++module_exit(ipmisensors_exit); +diff -rduNp linux-2.6.22.1.oorig2/drivers/hwmon/ipmisensors.h linux-2.6.22.1/drivers/hwmon/ipmisensors.h +--- linux-2.6.22.1.oorig2/drivers/hwmon/ipmisensors.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/drivers/hwmon/ipmisensors.h 2007-07-24 14:22:26.000000000 +0200 +@@ -0,0 +1,240 @@ ++/* ++ * ipmisensors.h - lm_sensors interface to IPMI sensors. ++ * ++ * Copyright (C) 2004-2006 Yani Ioannou ++ * ++ * Adapted from bmcsensors (lm-sensors for linux 2.4) ++ * bmcsensors (C) Mark D. Studebaker ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* SDR defs */ ++#define STYPE_TEMP 0x01 ++#define STYPE_VOLT 0x02 ++#define STYPE_CURR 0x03 ++#define STYPE_FAN 0x04 ++ ++#define SDR_LIMITS 8 ++#define SDR_MAX_ID_LENGTH 16 ++#define SDR_MAX_UNPACKED_ID_LENGTH ((SDR_MAX_ID_LENGTH * 4 / 3) + 2) ++ ++/* the last sensor type we are interested in */ ++#define STYPE_MAX 4 ++ ++#define IPMI_SDR_SIZE 67 ++#define IPMI_CHUNK_SIZE 16 ++ ++#define MAX_FILENAME_LENGTH 30 ++ ++struct ipmisensors_device_attribute { ++ struct device_attribute dev_attr; ++ struct sdrdata *sdr; ++}; ++#define to_ipmisensors_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct ipmisensors_device_attribute, dev_attr) ++ ++#define IPMISENSORS_DEVICE_ATTR(_name,_mode,_show,_store,_index) \ ++struct ipmisensors_attribute sensor_dev_attr_##_name = { \ ++ .dev_attr = __ATTR(_name,_mode,_show,_store), \ ++ .index = _index, \ ++} ++ ++struct ipmisensors_bmc_device_attribute { ++ struct device_attribute dev_attr; ++ struct ipmisensors_bmc_data *bmc; ++}; ++#define to_ipmisensors_bmc_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct ipmisensors_bmc_device_attribute, dev_attr) ++ ++/** ++ * &struct_sdrdata stores the IPMI Sensor Data Record (SDR) data, as recieved from the BMC, along with the corresponding sysfs attributes ++ */ ++struct sdrdata { ++ struct list_head list; ++ /* retrieved from SDR, not expected to change */ ++ /* Sensor Type Code */ ++ u8 stype; ++ u8 number; ++ /* Sensor Capability Code */ ++ u8 capab; ++ u16 thresh_mask; ++ u8 format; ++ u8 linear; ++ s16 m; ++ s16 b; ++ u8 k; ++ u8 nominal; ++ u8 limits[SDR_LIMITS]; ++ /* index into limits for reported upper and lower limit */ ++ int lim1, lim2; ++ u8 lim1_write, lim2_write; ++ u8 string_type; ++ u8 id_length; ++ u8 id[SDR_MAX_ID_LENGTH]; ++ /* retrieved from reading */ ++ u8 reading; ++ u8 status; ++ u8 thresholds; ++ /* sensor's bmc */ ++ struct ipmisensors_bmc_data *bmc; ++ /* sysfs entries */ ++ struct ipmisensors_device_attribute attr; ++ char *attr_name; ++ struct ipmisensors_device_attribute attr_min; ++ char *attr_min_name; ++ struct ipmisensors_device_attribute attr_max; ++ char *attr_max_name; ++ struct ipmisensors_device_attribute attr_label; ++ char *attr_label_name; ++ ++}; ++ ++/** ++ * &struct_ipmisensors_data stores the data for the ipmisensors driver. ++ */ ++struct ipmisensors_data { ++ /* Driver struct */ ++ char *driver_name; ++ ++ /* Linked list of ipmisensors_bmc_data structs, one for each BMC */ ++ struct list_head bmc_data; ++ ++ /* Number of ipmi interfaces (and hence ipmisensors_data structs). */ ++ int interfaces; ++ ++ /* IPMI kernel interface - SMI watcher */ ++ struct ipmi_smi_watcher smi_watcher; ++ ++ /* IPMI kernel interface - user handlers */ ++ struct ipmi_user_hndl ipmi_hndlrs; ++ ++ /* Cache manager for sdrdata cache */ ++ struct kmem_cache *sdrdata_cache; ++ ++ /* Cache manager for ipmi_sensor_device_attribute cache */ ++ struct kmem_cache *sysfsattr_cache; ++}; ++ ++/** ++ * &states: enumeration of state codes for a bmc specific ipmisensors ++ */ ++enum states { ++ STATE_INIT, ++ STATE_RESERVE, ++ STATE_SDR, ++ STATE_SDRPARTIAL, ++ STATE_READING, ++ STATE_UNCANCEL, ++ STATE_SYSTABLE, ++ STATE_DONE ++}; ++ ++/** ++ * &struct_ipmisensors_bmc_data stores the data for a particular IPMI BMC. ++ */ ++struct ipmisensors_bmc_data { ++ struct list_head list; ++ ++ /* The IPMI interface number */ ++ int interface_id; ++ ++ /* The IPMI address */ ++ struct ipmi_addr address; ++ ++ /* List of sdrdata structs (sdrs) recieved from the BMC */ ++ struct list_head sdrs; ++ ++ /* Count of the number of sdrs stored in the sdr list */ ++ int sdr_count; ++ ++ /* next message id */ ++ int msgid; ++ ++ /* The ipmi interface 'user' used to access this particular bmc */ ++ ipmi_user_t user; ++ ++ /* BMC IPMI Version (major) */ ++ unsigned char ipmi_version_major; ++ ++ /* BMC IPMI Version (minor) */ ++ unsigned char ipmi_version_minor; ++ ++ /* The size of the SDR request message */ ++ int ipmi_sdr_partial_size; ++ ++ /* transmit message buffer */ ++ struct kernel_ipmi_msg tx_message; ++ ++ /* ipmi transmited data buffer */ ++ unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* why the +50 in bmcsensors? */ ++ ++ /* ipmi recieved data buffer */ ++ unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; ++ ++ /* current recieve buffer offset */ ++ int rx_msg_data_offset; ++ ++ /* The id of then next SDR record to read during update cycle */ ++ u16 nextrecord; ++ ++ /* BMC SDR Reservation ID */ ++ u16 resid; ++ ++ /* Alarm status */ ++ u8 alarms; ++ ++ /* The cumalative error count for this bmc */ ++ int errorcount; ++ ++ /* The current state of this bmc w.r.t. ipmisensors (see enum states) */ ++ int state; ++ ++ /* The current sdr for which a reading is pending */ ++ struct sdrdata *current_sdr; ++ ++ /* The BMC's device struct */ ++ struct device *dev; ++ ++ /* hwmon class device */ ++ struct class_device *class_dev; ++ ++ /* hwmon device name */ ++ struct device_attribute name_attr; ++ ++ /* alarms attribute */ ++ struct ipmisensors_bmc_device_attribute alarms_attr; ++ ++ /* update_period attribute */ ++ struct ipmisensors_bmc_device_attribute update_attr; ++ ++ /* lower bound on time between updates (in seconds) */ ++ unsigned int update_period; ++ ++ /* semaphore used to do a headcount of the SDR readings we are waiting ++ * on in a given bmc update */ ++ struct semaphore update_semaphore; ++ ++ /* bmc's work struct for updating sensors */ ++ struct delayed_work update_work; ++ ++ /* bmc's work struct for building the sysfs workqueue */ ++ struct work_struct sysfs_work; ++}; +diff -rduNp linux-2.6.22.1.oorig2/include/linux/ipmi.h linux-2.6.22.1/include/linux/ipmi.h +--- linux-2.6.22.1.oorig2/include/linux/ipmi.h 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/include/linux/ipmi.h 2007-07-24 14:22:26.000000000 +0200 +@@ -300,6 +300,9 @@ int ipmi_create_user(unsigned int + safe, too. */ + int ipmi_destroy_user(ipmi_user_t user); + ++/* Get the IPMI BMC's device struct */ ++struct device *ipmi_get_bmcdevice(int ipmi_intf); ++ + /* Get the IPMI version of the BMC we are talking to. */ + void ipmi_get_version(ipmi_user_t user, + unsigned char *major, +diff -rduNp linux-2.6.22.1.oorig2/include/linux/ipmi_msgdefs.h linux-2.6.22.1/include/linux/ipmi_msgdefs.h +--- linux-2.6.22.1.oorig2/include/linux/ipmi_msgdefs.h 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/include/linux/ipmi_msgdefs.h 2007-07-24 14:22:26.000000000 +0200 +@@ -45,6 +45,7 @@ + + #define IPMI_NETFN_APP_REQUEST 0x06 + #define IPMI_NETFN_APP_RESPONSE 0x07 ++#define IPMI_GET_DEVICE_GUID_CMD 0x08 + #define IPMI_GET_DEVICE_ID_CMD 0x01 + #define IPMI_COLD_RESET_CMD 0x02 + #define IPMI_WARM_RESET_CMD 0x03 +@@ -57,6 +58,11 @@ + #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD 0x2f + #define IPMI_READ_EVENT_MSG_BUFFER_CMD 0x35 + #define IPMI_GET_CHANNEL_INFO_CMD 0x42 ++#define IPMI_RESERVE_SDR 0x22 ++#define IPMI_GET_SDR 0x23 ++#define IPMI_GET_SENSOR_STATE_READING 0x2D ++#define IPMI_SET_SENSOR_HYSTERESIS 0x24 ++#define IPMI_SET_SENSOR_THRESHOLD 0x26 + + #define IPMI_NETFN_STORAGE_REQUEST 0x0a + #define IPMI_NETFN_STORAGE_RESPONSE 0x0b +@@ -79,10 +85,13 @@ + #define IPMI_NODE_BUSY_ERR 0xc0 + #define IPMI_INVALID_COMMAND_ERR 0xc1 + #define IPMI_TIMEOUT_ERR 0xc3 ++#define IPMI_INVALID_RESERVATION_ID 0xc5 + #define IPMI_ERR_MSG_TRUNCATED 0xc6 + #define IPMI_REQ_LEN_INVALID_ERR 0xc7 + #define IPMI_REQ_LEN_EXCEEDED_ERR 0xc8 + #define IPMI_NOT_IN_MY_STATE_ERR 0xd5 /* IPMI 2.0 */ ++#define IPMI_ERR_RETURNING_REQ_BYTES 0xca ++#define IPMI_ERR_PROVIDING_RESPONSE 0xce + #define IPMI_LOST_ARBITRATION_ERR 0x81 + #define IPMI_BUS_ERR 0x82 + #define IPMI_NAK_ON_WRITE_ERR 0x83 diff --git a/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-new.makefile b/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-new.makefile new file mode 100644 index 0000000000..7852c04bcc --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-new.makefile @@ -0,0 +1,91 @@ +############################################################# +# +# full kernel tarballs >= 2.6.19.1 +# +############################################################# + +# new-style kernels? +ifeq ($(LINUX_HEADERS_VERSION),) +# parse linux version string +LNXVER:=$(subst ., , $(strip $(DEFAULT_KERNEL_HEADERS))) +VERSION:=$(word 1, $(LNXVER)) +PATCHLEVEL:=$(word 2, $(LNXVER)) +SUBLEVEL:=$(word 3, $(LNXVER)) +EXTRAVERSION:=$(word 4, $(LNXVER)) +LOCALVERSION:= + +# should contain prepended dot +EXTRAVERSION:=$(if $(EXTRAVERSION),.$(EXTRAVERSION),) + +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=$(BR2_KERNEL_MIRROR)/linux/kernel/v2.6/ +LINUX_HEADERS_SOURCE:=linux-$(LINUX_HEADERS_VERSION).tar.bz2 +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-$(LINUX_HEADERS_VERSION) +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_IS_KERNEL=y +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.6.22.1") +LINUX_RT_VERSION:=rt9 +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.6.21.5") +LINUX_RT_VERSION:=rt20 +endif + +ifeq ($(LINUX_HEADERS_IS_KERNEL),y) +# Need to redefine KERNEL_HEADERS_PATCH_DIR if you want +# board specific kernel headers +KERNEL_HEADERS_PATCH_DIR:=toolchain/kernel-headers/empty +LINUX_HEADERS_DEPENDS:= + +ifeq ($(BR2_KERNEL_HEADERS_RT),y) +LINUX_RT_SOURCE:=patch-$(LINUX_HEADERS_VERSION)-$(LINUX_RT_VERSION) +LINUX_RT_SITE:=$(BR2_KERNEL_MIRROR)/linux/kernel/projects/rt/older/ +LINUX_HEADERS_DEPENDS+=$(DL_DIR)/$(LINUX_RT_SOURCE) +$(DL_DIR)/$(LINUX_RT_SOURCE): + $(WGET) -P $(DL_DIR) $(LINUX_RT_SITE)/$(LINUX_RT_SOURCE) +endif + +$(LINUX_HEADERS_UNPACK_DIR)/.unpacked: $(DL_DIR)/$(LINUX_HEADERS_SOURCE) + @echo "*** Using kernel-headers generated from kernel source" + rm -rf $(LINUX_HEADERS_DIR) + [ -d $(TOOL_BUILD_DIR) ] || $(INSTALL) -d $(TOOL_BUILD_DIR) + $(LINUX_HEADERS_CAT) $(DL_DIR)/$(LINUX_HEADERS_SOURCE) | tar -C $(TOOL_BUILD_DIR) $(TAR_OPTIONS) - + touch $@ + +$(LINUX_HEADERS_UNPACK_DIR)/.patched: $(LINUX_HEADERS_UNPACK_DIR)/.unpacked $(LINUX_HEADERS_DEPENDS) + toolchain/patch-kernel.sh $(LINUX_HEADERS_UNPACK_DIR) toolchain/kernel-headers \ + linux-$(LINUX_HEADERS_VERSION)-\*.patch{,.gz,.bz2} +ifeq ($(BR2_KERNEL_HEADERS_IPMI),y) + toolchain/patch-kernel.sh $(LINUX_HEADERS_UNPACK_DIR) toolchain/kernel-headers/ipmi \ + linux-$(LINUX_HEADERS_VERSION)-\*.patch{,.gz,.bz2} +endif +ifeq ($(BR2_KERNEL_HEADERS_LZMA),y) + toolchain/patch-kernel.sh $(LINUX_HEADERS_UNPACK_DIR) toolchain/kernel-headers/lzma \ + linux-$(LINUX_HEADERS_VERSION)-\*.patch{,.gz,.bz2} +endif +ifeq ($(BR2_KERNEL_HEADERS_RT),y) + toolchain/patch-kernel.sh $(LINUX_HEADERS_UNPACK_DIR) $(DL_DIR) $(LINUX_RT_SOURCE) +endif +ifeq ($(BR2_KERNEL_HEADERS_PATCH_DIR),y) + toolchain/patch-kernel.sh $(LINUX_HEADERS_UNPACK_DIR) $(KERNEL_HEADERS_PATCH_DIR) \ + \*.patch{,.gz,.bz2} +endif +ifeq ($(BR2_PACKAGE_OPENSWAN),y) + toolchain/patch-kernel.sh $(LINUX_HEADERS_UNPACK_DIR) package/openswan \ + linux-$(LINUX_HEADERS_VERSION)-\*.patch{,.gz,.bz2} +endif + touch $@ + +$(LINUX_HEADERS_DIR)/.configured: $(LINUX_HEADERS_UNPACK_DIR)/.patched + (cd $(LINUX_HEADERS_UNPACK_DIR); \ + $(MAKE) ARCH=$(KERNEL_ARCH) \ + HOSTCC="$(HOSTCC)" HOSTCFLAGS="$(HOSTCFLAGS)" \ + HOSTCXX="$(HOSTCXX)" \ + INSTALL_HDR_PATH=$(LINUX_HEADERS_DIR) headers_install; \ + ) + touch $@ + +endif diff --git a/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-old-versions.makefile b/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-old-versions.makefile new file mode 100644 index 0000000000..01e530084f --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-old-versions.makefile @@ -0,0 +1,103 @@ +############################################################# +# +# Setup the kernel headers. I include a generic package of +# kernel headers here, so you shouldn't need to include your +# own. Be aware these kernel headers _will_ get blown away +# by a 'make clean' so don't put anything sacred in here... +# +############################################################# +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.4.25") +VERSION:=2 +PATCHLEVEL:=4 +SUBLEVEL:=25 +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=http://www.uclibc.org/downloads/toolchain +LINUX_HEADERS_SOURCE:=linux-libc-headers-2.4.25.tar.bz2 +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-2.4.25 +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.4.27") +VERSION:=2 +PATCHLEVEL:=4 +SUBLEVEL:=27 +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=http://www.uclibc.org/downloads/toolchain +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_SOURCE:=linux-libc-headers-2.4.27.tar.bz2 +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-2.4.27 +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.4.29") +VERSION:=2 +PATCHLEVEL:=4 +SUBLEVEL:=29 +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=http://www.uclibc.org/downloads/toolchain +LINUX_HEADERS_SOURCE:=linux-libc-headers-2.4.29.tar.bz2 +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-2.4.29 +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.4.31") +VERSION:=2 +PATCHLEVEL:=4 +SUBLEVEL:=31 +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=http://www.uclibc.org/downloads/toolchain +LINUX_HEADERS_SOURCE:=linux-libc-headers-2.4.31.tar.bz2 +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-2.4.31 +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.6.9") +VERSION:=2 +PATCHLEVEL:=6 +SUBLEVEL:=9 +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=http://ep09.pld-linux.org/~mmazur/linux-libc-headers/ +LINUX_HEADERS_SOURCE:=linux-libc-headers-2.6.9.1.tar.bz2 +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-2.6.9.1 +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.6.10") +VERSION:=2 +PATCHLEVEL:=6 +SUBLEVEL:=10 +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=http://ep09.pld-linux.org/~mmazur/linux-libc-headers/ +LINUX_HEADERS_SOURCE:=linux-libc-headers-2.6.10.0.tar.bz2 +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-2.6.10.0 +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.6.11") +VERSION:=2 +PATCHLEVEL:=6 +SUBLEVEL:=11 +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=http://ep09.pld-linux.org/~mmazur/linux-libc-headers/ +LINUX_HEADERS_SOURCE:=linux-libc-headers-2.6.11.0.tar.bz2 +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-2.6.11.0 +endif + +ifeq ("$(DEFAULT_KERNEL_HEADERS)","2.6.12") +VERSION:=2 +PATCHLEVEL:=6 +SUBLEVEL:=12 +LINUX_HEADERS_VERSION:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +LINUX_HEADERS_SITE:=http://ep09.pld-linux.org/~mmazur/linux-libc-headers/ +LINUX_HEADERS_SOURCE:=linux-libc-headers-2.6.12.0.tar.bz2 +LINUX_HEADERS_CAT:=$(BZCAT) +LINUX_HEADERS_DIR:=$(TOOL_BUILD_DIR)/linux +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-2.6.12.0 +endif diff --git a/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-old.makefile b/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-old.makefile new file mode 100644 index 0000000000..52fa68e6f3 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers-old.makefile @@ -0,0 +1,87 @@ +############################################################# +# +# Setup the kernel headers. I include a generic package of +# kernel headers here, so you shouldn't need to include your +# own. Be aware these kernel headers _will_ get blown away +# by a 'make clean' so don't put anything sacred in here... +# +############################################################# + +# the old sanitized kernel-headers +ifeq ($(LINUX_HEADERS_IS_KERNEL),n) + +$(LINUX_HEADERS_UNPACK_DIR)/.unpacked: $(DL_DIR)/$(LINUX_HEADERS_SOURCE) + @echo "Using old sanitized kernel-headers" + rm -rf $(LINUX_HEADERS_DIR) + $(LINUX_HEADERS_CAT) $(DL_DIR)/$(LINUX_HEADERS_SOURCE) | tar -C $(TOOL_BUILD_DIR) $(TAR_OPTIONS) - +ifneq ($(LINUX_HEADERS_UNPACK_DIR),$(LINUX_HEADERS_DIR)) + ln -fs $(LINUX_HEADERS_UNPACK_DIR) $(LINUX_HEADERS_DIR) +endif + touch $(LINUX_HEADERS_UNPACK_DIR)/.unpacked + +$(LINUX_HEADERS_DIR)/.patched: $(LINUX_HEADERS_UNPACK_DIR)/.unpacked + toolchain/patch-kernel.sh $(LINUX_HEADERS_DIR) toolchain/kernel-headers \ + linux-libc-headers-$(LINUX_HEADERS_VERSION)\*.patch +ifeq ($(strip $(ARCH)),nios2) + toolchain/patch-kernel.sh $(LINUX_HEADERS_DIR) toolchain/kernel-headers \ + linux-libc-headers-$(LINUX_HEADERS_VERSION)-nios2nommu.patch.conditional +endif + touch $(LINUX_HEADERS_DIR)/.patched + +$(LINUX_HEADERS_DIR)/.configured: $(LINUX_HEADERS_DIR)/.patched + rm -f $(LINUX_HEADERS_DIR)/include/asm + @if [ ! -f $(LINUX_HEADERS_DIR)/Makefile ] ; then \ + /bin/echo -e "VERSION = $(VERSION)\nPATCHLEVEL = $(PATCHLEVEL)\n" > \ + $(LINUX_HEADERS_DIR)/Makefile; \ + /bin/echo -e "SUBLEVEL = $(SUBLEVEL)\nEXTRAVERSION =\n" >> \ + $(LINUX_HEADERS_DIR)/Makefile; \ + /bin/echo -e "KERNELRELEASE=\$$(VERSION).\$$(PATCHLEVEL).\$$(SUBLEVEL)\$$(EXTRAVERSION)" >> \ + $(LINUX_HEADERS_DIR)/Makefile; \ + fi + @if [ "$(ARCH)" = "powerpc" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-ppc$(NOMMU) asm;) \ + elif [ "$(ARCH)" = "mips" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-mips$(NOMMU) asm;) \ + elif [ "$(ARCH)" = "mipsel" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-mips$(NOMMU) asm;) \ + elif [ "$(ARCH)" = "nios2" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-nios2nommu asm;) \ + elif [ "$(ARCH)" = "arm" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-arm$(NOMMU) asm; \ + cd asm; \ + if [ ! -L proc ] ; then \ + ln -fs proc-armv proc; \ + ln -fs arch-ebsa285 arch; fi); \ + elif [ "$(ARCH)" = "armeb" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-arm$(NOMMU) asm; \ + cd asm; \ + if [ ! -L proc ] ; then \ + ln -fs proc-armv proc; \ + ln -fs arch-ebsa285 arch; fi); \ + elif [ "$(ARCH)" = "cris" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-cris asm;) \ + elif [ "$(ARCH)" = "sh3" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-sh asm; \ + cd asm; \ + ln -s cpu-sh3 cpu) \ + elif [ "$(ARCH)" = "sh3eb" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-sh asm; \ + cd asm; \ + ln -s cpu-sh3 cpu) \ + elif [ "$(ARCH)" = "sh4" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-sh asm; \ + cd asm; \ + ln -s cpu-sh4 cpu) \ + elif [ "$(ARCH)" = "sh4eb" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-sh asm; \ + cd asm; \ + ln -s cpu-sh4 cpu) \ + elif [ "$(ARCH)" = "i386" -o "$(ARCH)" = "i486" -o "$(ARCH)" = "i586" -o "$(ARCH)" = "i686" ];then \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-i386$(NOMMU) asm;) \ + else \ + (cd $(LINUX_HEADERS_DIR)/include; ln -fs asm-$(ARCH)$(NOMMU) asm;) \ + fi + touch $(LINUX_HEADERS_DIR)/include/linux/autoconf.h + touch $(LINUX_HEADERS_DIR)/.configured + +endif diff --git a/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers.mk b/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers.mk new file mode 100644 index 0000000000..fc8acda051 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/kernel-headers.mk @@ -0,0 +1,48 @@ +############################################################# +# +# Setup the kernel headers. I include a generic package of +# kernel headers here, so you shouldn't need to include your +# own. Be aware these kernel headers _will_ get blown away +# by a 'make clean' so don't put anything sacred in here... +# +############################################################# + +DEFAULT_KERNEL_HEADERS:=$(strip $(subst ",, $(BR2_DEFAULT_KERNEL_HEADERS))) +#")) + +LINUX_HEADERS_SITE:=127.0.0.1 +LINUX_HEADERS_SOURCE:=unspecified-kernel-headers +LINUX_HEADERS_UNPACK_DIR:=$(TOOL_BUILD_DIR)/linux-libc-headers-null + +KERNEL_ARCH:=$(shell $(SHELL) -c "echo \"$(ARCH)\" | sed -e \"s/-.*//\" \ + -e s/i.86/i386/ -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ -e s/sa110/arm/ \ + -e s/s390x/s390/ -e s/parisc64/parisc/ \ + -e s/powerpc64/powerpc/ \ + -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ + -e s/sh2.*/sh/ -e s/sh3.*/sh/ -e s/sh4.*/sh/ \ + -e s/nios2.*/nios2nommu/") + +# assume old manually sanitized kernel-headers +LINUX_HEADERS_IS_KERNEL=n + +# this needs to be included before kernel-headers-new to set old-style mode +include toolchain/kernel-headers/kernel-headers-old-versions.makefile +include toolchain/kernel-headers/kernel-headers-new.makefile +include toolchain/kernel-headers/kernel-headers-old.makefile + +$(DL_DIR)/$(LINUX_HEADERS_SOURCE): + $(WGET) -P $(DL_DIR) $(LINUX_HEADERS_SITE)/$(LINUX_HEADERS_SOURCE) + +kernel-headers: $(LINUX_HEADERS_DIR)/.configured + +kernel-headers-source: $(DL_DIR)/$(LINUX_HEADERS_SOURCE) + +kernel-headers-clean: clean + rm -rf $(LINUX_HEADERS_DIR) + +kernel-headers-dirclean: + rm -rf $(LINUX_HEADERS_DIR) + rm -rf $(LINUX_HEADERS_UNPACK_DIR) + +.PHONY: kernel-headers diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.20.4-dwmw2-combined.01.diff b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.20.4-dwmw2-combined.01.diff new file mode 100644 index 0000000000..d07dd33d2b --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.20.4-dwmw2-combined.01.diff @@ -0,0 +1,460 @@ +\\\\ dwmw2's --combine -fwhole-program patch for the kernel +\\ original of this incarnation was here: +\\ http://david.woodhou.se/linux-combine-build.patch +diff -rduNp linux-2.6.20.4.orig/drivers/md/md.c linux-2.6.20.4/drivers/md/md.c +--- linux-2.6.20.4.orig/drivers/md/md.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/drivers/md/md.c 2007-03-24 20:14:10.000000000 +0100 +@@ -2944,6 +2944,7 @@ static struct kobj_type md_ktype = { + }; + + int mdp_major = 0; ++__internal_export(mdp_major); + + static struct kobject *md_probe(dev_t dev, int *part, void *data) + { +@@ -5602,7 +5603,7 @@ void md_autodetect_dev(dev_t dev) + if (dev_cnt >= 0 && dev_cnt < 127) + detected_devices[dev_cnt++] = dev; + } +- ++__internal_export(md_autodetect_dev); + + static void autostart_arrays(int part) + { +diff -rduNp linux-2.6.20.4.orig/drivers/video/fbcvt.c linux-2.6.20.4/drivers/video/fbcvt.c +--- linux-2.6.20.4.orig/drivers/video/fbcvt.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/drivers/video/fbcvt.c 2007-03-24 20:14:10.000000000 +0100 +@@ -376,3 +376,4 @@ int fb_find_mode_cvt(struct fb_videomode + + return 0; + } ++__internal_export(fb_find_mode_cvt); +diff -rduNp linux-2.6.20.4.orig/fs/debugfs/inode.c linux-2.6.20.4/fs/debugfs/inode.c +--- linux-2.6.20.4.orig/fs/debugfs/inode.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/debugfs/inode.c 2007-03-24 20:14:10.000000000 +0100 +@@ -29,7 +29,7 @@ + #define DEBUGFS_MAGIC 0x64626720 + + /* declared over in file.c */ +-extern struct file_operations debugfs_file_operations; ++extern const struct file_operations debugfs_file_operations; + + static struct vfsmount *debugfs_mount; + static int debugfs_mount_count; +diff -rduNp linux-2.6.20.4.orig/fs/devpts/inode.c linux-2.6.20.4/fs/devpts/inode.c +--- linux-2.6.20.4.orig/fs/devpts/inode.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/devpts/inode.c 2007-03-24 20:14:10.000000000 +0100 +@@ -185,6 +185,7 @@ int devpts_pty_new(struct tty_struct *tt + + return 0; + } ++__internal_export(devpts_pty_new); + + struct tty_struct *devpts_get_tty(int number) + { +@@ -202,6 +203,7 @@ struct tty_struct *devpts_get_tty(int nu + + return tty; + } ++__internal_export(devpts_get_tty); + + void devpts_pty_kill(int number) + { +@@ -218,6 +220,7 @@ void devpts_pty_kill(int number) + } + mutex_unlock(&devpts_root->d_inode->i_mutex); + } ++__internal_export(devpts_pty_kill); + + static int __init init_devpts_fs(void) + { +diff -rduNp linux-2.6.20.4.orig/fs/hfsplus/inode.c linux-2.6.20.4/fs/hfsplus/inode.c +--- linux-2.6.20.4.orig/fs/hfsplus/inode.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/hfsplus/inode.c 2007-03-24 20:14:10.000000000 +0100 +@@ -269,7 +269,7 @@ static int hfsplus_file_release(struct i + } + + extern struct inode_operations hfsplus_dir_inode_operations; +-extern struct file_operations hfsplus_dir_operations; ++extern const struct file_operations hfsplus_dir_operations; + + static struct inode_operations hfsplus_file_inode_operations = { + .lookup = hfsplus_file_lookup, +diff -rduNp linux-2.6.20.4.orig/fs/hugetlbfs/inode.c linux-2.6.20.4/fs/hugetlbfs/inode.c +--- linux-2.6.20.4.orig/fs/hugetlbfs/inode.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/hugetlbfs/inode.c 2007-03-24 20:14:10.000000000 +0100 +@@ -45,6 +45,7 @@ static struct backing_dev_info hugetlbfs + }; + + int sysctl_hugetlb_shm_group; ++__internal_export(sysctl_hugetlb_shm_group); + + static void huge_pagevec_release(struct pagevec *pvec) + { +@@ -562,6 +563,7 @@ const struct file_operations hugetlbfs_f + .fsync = simple_sync_file, + .get_unmapped_area = hugetlb_get_unmapped_area, + }; ++__internal_export(hugetlbfs_file_operations); + + static struct inode_operations hugetlbfs_dir_inode_operations = { + .create = hugetlbfs_create, +@@ -701,6 +703,7 @@ int hugetlb_get_quota(struct address_spa + + return ret; + } ++__internal_export(hugetlb_get_quota); + + void hugetlb_put_quota(struct address_space *mapping) + { +@@ -712,6 +715,7 @@ void hugetlb_put_quota(struct address_sp + spin_unlock(&sbinfo->stat_lock); + } + } ++__internal_export(hugetlb_put_quota); + + static int hugetlbfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) +@@ -794,6 +798,7 @@ out_shm_unlock: + user_shm_unlock(size, current->user); + return ERR_PTR(error); + } ++__internal_export(hugetlb_zero_setup); + + static int __init init_hugetlbfs_fs(void) + { +diff -rduNp linux-2.6.20.4.orig/fs/proc/base.c linux-2.6.20.4/fs/proc/base.c +--- linux-2.6.20.4.orig/fs/proc/base.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/proc/base.c 2007-03-24 20:18:09.000000000 +0100 +@@ -71,6 +71,7 @@ + #include + #include + #include ++#include + #include + #include + #include "internal.h" +@@ -2030,6 +2031,7 @@ struct dentry *proc_pid_lookup(struct in + out: + return result; + } ++__internal_export(proc_flush_task); + + /* + * Find the first task with tgid >= tgid +diff -rduNp linux-2.6.20.4.orig/fs/proc/generic.c linux-2.6.20.4/fs/proc/generic.c +--- linux-2.6.20.4.orig/fs/proc/generic.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/proc/generic.c 2007-03-24 20:14:10.000000000 +0100 +@@ -20,8 +20,8 @@ + #include + #include + #include ++#include + #include +- + #include "internal.h" + + static ssize_t proc_file_read(struct file *file, char __user *buf, +@@ -38,6 +38,7 @@ int proc_match(int len, const char *name + return 0; + return !memcmp(name, de->name, len); + } ++__internal_export(proc_match); + + static struct file_operations proc_file_operations = { + .llseek = proc_file_lseek, +diff -rduNp linux-2.6.20.4.orig/fs/proc/kcore.c linux-2.6.20.4/fs/proc/kcore.c +--- linux-2.6.20.4.orig/fs/proc/kcore.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/proc/kcore.c 2007-03-24 20:14:10.000000000 +0100 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -66,6 +67,7 @@ kclist_add(struct kcore_list *new, void + kclist = new; + write_unlock(&kclist_lock); + } ++__internal_export(kclist_add); + + static size_t get_kcore_size(int *nphdr, size_t *elf_buflen) + { +diff -rduNp linux-2.6.20.4.orig/fs/proc/proc_tty.c linux-2.6.20.4/fs/proc/proc_tty.c +--- linux-2.6.20.4.orig/fs/proc/proc_tty.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/proc/proc_tty.c 2007-03-24 20:14:10.000000000 +0100 +@@ -201,6 +201,7 @@ void proc_tty_register_driver(struct tty + + driver->proc_entry = ent; + } ++__internal_export(proc_tty_register_driver); + + /* + * This function is called by tty_unregister_driver() +@@ -217,6 +218,7 @@ void proc_tty_unregister_driver(struct t + + driver->proc_entry = NULL; + } ++__internal_export(proc_tty_unregister_driver); + + /* + * Called by proc_root_init() to initialize the /proc/tty subtree +diff -rduNp linux-2.6.20.4.orig/fs/proc/root.c linux-2.6.20.4/fs/proc/root.c +--- linux-2.6.20.4.orig/fs/proc/root.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/proc/root.c 2007-03-24 20:14:10.000000000 +0100 +@@ -21,7 +21,9 @@ + + #include "internal.h" + +-struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; ++struct proc_dir_entry *proc_net; ++ ++struct proc_dir_entry *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; + + #ifdef CONFIG_SYSCTL + struct proc_dir_entry *proc_sys_root; +@@ -91,6 +93,7 @@ void __init proc_root_init(void) + #endif + proc_bus = proc_mkdir("bus", NULL); + } ++__internal_export(proc_root_init); + + static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat + ) +@@ -163,6 +166,7 @@ struct proc_dir_entry proc_root = { + .parent = &proc_root, + }; + ++__internal_export(proc_sys_root); + EXPORT_SYMBOL(proc_symlink); + EXPORT_SYMBOL(proc_mkdir); + EXPORT_SYMBOL(create_proc_entry); +diff -rduNp linux-2.6.20.4.orig/fs/ramfs/inode.c linux-2.6.20.4/fs/ramfs/inode.c +--- linux-2.6.20.4.orig/fs/ramfs/inode.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/ramfs/inode.c 2007-03-24 20:14:10.000000000 +0100 +@@ -225,5 +225,6 @@ int __init init_rootfs(void) + { + return register_filesystem(&rootfs_fs_type); + } ++__internal_export(init_rootfs); + + MODULE_LICENSE("GPL"); +diff -rduNp linux-2.6.20.4.orig/fs/reiserfs/dir.c linux-2.6.20.4/fs/reiserfs/dir.c +--- linux-2.6.20.4.orig/fs/reiserfs/dir.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/fs/reiserfs/dir.c 2007-03-24 20:14:10.000000000 +0100 +@@ -11,7 +11,7 @@ + #include + #include + +-extern struct reiserfs_key MIN_KEY; ++extern const struct reiserfs_key MIN_KEY; + + static int reiserfs_readdir(struct file *, void *, filldir_t); + static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, +diff -rduNp linux-2.6.20.4.orig/include/linux/module.h linux-2.6.20.4/include/linux/module.h +--- linux-2.6.20.4.orig/include/linux/module.h 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/include/linux/module.h 2007-03-24 20:14:10.000000000 +0100 +@@ -20,6 +20,15 @@ + + #include + ++ ++#ifdef CONFIG_COMBINED_COMPILE ++#define __externally_visible__ __attribute__((externally_visible,used)) ++#define __internal_export(sym) extern typeof(sym) sym __externally_visible__ ++#else ++#define __externally_visible__ ++#define __internal_export(sym) ++#endif ++ + /* Not Yet Implemented */ + #define MODULE_SUPPORTED_DEVICE(name) + +@@ -188,7 +197,7 @@ void *__symbol_get_gpl(const char *symbo + + /* For every exported symbol, place a struct in the __ksymtab section */ + #define __EXPORT_SYMBOL(sym, sec) \ +- extern typeof(sym) sym; \ ++ extern typeof(sym) sym __externally_visible__; \ + __CRC_SYMBOL(sym, sec) \ + static const char __kstrtab_##sym[] \ + __attribute__((section("__ksymtab_strings"))) \ +@@ -212,8 +221,8 @@ void *__symbol_get_gpl(const char *symbo + #define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused") + #define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl") + #else +-#define EXPORT_UNUSED_SYMBOL(sym) +-#define EXPORT_UNUSED_SYMBOL_GPL(sym) ++#define EXPORT_UNUSED_SYMBOL(sym) __internal_export(sym) ++#define EXPORT_UNUSED_SYMBOL_GPL(sym) __internal_export(sym) + #endif + + #endif +@@ -471,11 +480,12 @@ void module_add_driver(struct module *, + void module_remove_driver(struct device_driver *); + + #else /* !CONFIG_MODULES... */ +-#define EXPORT_SYMBOL(sym) +-#define EXPORT_SYMBOL_GPL(sym) +-#define EXPORT_SYMBOL_GPL_FUTURE(sym) +-#define EXPORT_UNUSED_SYMBOL(sym) +-#define EXPORT_UNUSED_SYMBOL_GPL(sym) ++ ++#define EXPORT_SYMBOL(sym) __internal_export(sym) ++#define EXPORT_SYMBOL_GPL(sym) __internal_export(sym) ++#define EXPORT_SYMBOL_GPL_FUTURE(sym) __internal_export(sym) ++#define EXPORT_UNUSED_SYMBOL(sym) __internal_export(sym) ++#define EXPORT_UNUSED_SYMBOL_GPL(sym) __internal_export(sym) + + /* Given an address, look for it in the exception tables. */ + static inline const struct exception_table_entry * +diff -rduNp linux-2.6.20.4.orig/init/do_mounts.c linux-2.6.20.4/init/do_mounts.c +--- linux-2.6.20.4.orig/init/do_mounts.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/init/do_mounts.c 2007-03-24 20:14:10.000000000 +0100 +@@ -26,6 +26,10 @@ static char __initdata saved_root_name[6 + + dev_t ROOT_DEV; + ++__internal_export(root_mountflags); ++__internal_export(rd_doload); ++__internal_export(ROOT_DEV); ++ + static int __init load_ramdisk(char *str) + { + rd_doload = simple_strtol(str,NULL,0) & 3; +@@ -205,6 +209,7 @@ fail: + res = 0; + goto done; + } ++__internal_export(name_to_dev_t); + + static int __init root_dev_setup(char *line) + { +@@ -446,4 +451,4 @@ out: + sys_chroot("."); + security_sb_post_mountroot(); + } +- ++__internal_export(prepare_namespace); +diff -rduNp linux-2.6.20.4.orig/init/do_mounts_initrd.c linux-2.6.20.4/init/do_mounts_initrd.c +--- linux-2.6.20.4.orig/init/do_mounts_initrd.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/init/do_mounts_initrd.c 2007-03-24 20:18:32.000000000 +0100 +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + + #include "do_mounts.h" +@@ -16,6 +17,11 @@ unsigned int real_root_dev; /* do_proc_d + static int __initdata old_fd, root_fd; + static int __initdata mount_initrd = 1; + ++__internal_export(initrd_start); ++__internal_export(initrd_end); ++__internal_export(initrd_below_start_ok); ++__internal_export(real_root_dev); ++ + static int __init no_initrd(char *str) + { + mount_initrd = 0; +diff -rduNp linux-2.6.20.4.orig/init/do_mounts_rd.c linux-2.6.20.4/init/do_mounts_rd.c +--- linux-2.6.20.4.orig/init/do_mounts_rd.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/init/do_mounts_rd.c 2007-03-24 20:14:10.000000000 +0100 +@@ -7,12 +7,14 @@ + #include + #include + #include ++#include + + #include "do_mounts.h" + + #define BUILD_CRAMDISK + + int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */ ++__internal_export(rd_prompt); + + static int __init prompt_ramdisk(char *str) + { +@@ -22,6 +24,7 @@ static int __init prompt_ramdisk(char *s + __setup("prompt_ramdisk=", prompt_ramdisk); + + int __initdata rd_image_start; /* starting block # of image */ ++__internal_export(rd_image_start); + + static int __init ramdisk_start_setup(char *str) + { +diff -rduNp linux-2.6.20.4.orig/init/Kconfig linux-2.6.20.4/init/Kconfig +--- linux-2.6.20.4.orig/init/Kconfig 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/init/Kconfig 2007-03-24 20:14:10.000000000 +0100 +@@ -526,6 +526,11 @@ config MODULE_FORCE_UNLOAD + rmmod). This is mainly for kernel developers and desperate users. + If unsure, say N. + ++config COMBINED_COMPILE ++ bool "Use combined compilation (gcc --combine)" ++ help ++ fish ++ + config MODVERSIONS + bool "Module versioning support" + depends on MODULES +diff -rduNp linux-2.6.20.4.orig/net/netfilter/core.c linux-2.6.20.4/net/netfilter/core.c +--- linux-2.6.20.4.orig/net/netfilter/core.c 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/net/netfilter/core.c 2007-03-24 20:14:10.000000000 +0100 +@@ -279,3 +279,5 @@ void __init netfilter_init(void) + if (netfilter_log_init() < 0) + panic("cannot initialize nf_log"); + } ++__internal_export(netfilter_init); ++ +diff -rduNp linux-2.6.20.4.orig/scripts/Makefile.build linux-2.6.20.4/scripts/Makefile.build +--- linux-2.6.20.4.orig/scripts/Makefile.build 2007-03-13 19:27:08.000000000 +0100 ++++ linux-2.6.20.4/scripts/Makefile.build 2007-03-24 20:14:10.000000000 +0100 +@@ -128,6 +128,11 @@ $(multi-objs-y:.o=.i) : modname = $(mo + $(multi-objs-y:.o=.s) : modname = $(modname-multi) + $(multi-objs-y:.o=.lst) : modname = $(modname-multi) + ++ifdef CONFIG_COMBINED_COMPILE ++$(multi-used-m) : CFLAGS += -fwhole-program --combine $(sort $(addprefix $(srctree)/$(obj)/,$($(subst $(obj)/,,$(@:.o=-y)):.o=.c) $($(subst $(obj)/,,$(@:.o=-objs)):.o=.c))) ++$(multi-used-y) : CFLAGS += -fwhole-program --combine $(sort $(addprefix $(srctree)/$(obj)/,$($(subst $(obj)/,,$(@:.o=-y)):.o=.c) $($(subst $(obj)/,,$(@:.o=-objs)):.o=.c))) ++endif ++ + quiet_cmd_cc_s_c = CC $(quiet_modtag) $@ + cmd_cc_s_c = $(CC) $(c_flags) -fverbose-asm -S -o $@ $< + +@@ -284,6 +289,22 @@ $(lib-target): $(lib-y) FORCE + targets += $(lib-target) + endif + ++ifdef CONFIG_COMBINED_COMPILE ++# We would rather have a list of rules like ++# foo.o: $(foo-objs) ++# but that's not so easy, so we rather make all composite objects depend ++# on the set of all their parts ++ ++$(multi-used-y) : %.o: $(srctree)/dummy.c $(multi-objs-y:.o=.c) FORCE ++ $(call cmd,force_checksrc) ++ $(call if_changed_rule,cc_o_c) ++ ++$(multi-used-m) : %.o: $(srctree)/dummy.c $(multi-objs-m:.o=.c) FORCE ++ $(call cmd,force_checksrc) ++ $(call if_changed_rule,cc_o_c) ++ ++targets += $(multi-used-y) $(multi-used-m) ++else + # + # Rule to link composite objects + # +@@ -314,7 +335,7 @@ $(multi-used-m) : %.o: $(multi-objs-m) F + @{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod) + + targets += $(multi-used-y) $(multi-used-m) +- ++endif + + # Descending + # --------------------------------------------------------------------------- diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.21.5-001-add-linkage-header.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.21.5-001-add-linkage-header.patch new file mode 100644 index 0000000000..dd89d4a893 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.21.5-001-add-linkage-header.patch @@ -0,0 +1,18 @@ +diff -ur linux-2.6.21.5/include/asm-arm/Kbuild linux-2.6.21.5-patched/include/asm-arm/Kbuild +--- linux-2.6.21.5/include/asm-arm/Kbuild 2007-06-11 13:37:06.000000000 -0500 ++++ linux-2.6.21.5-patched/include/asm-arm/Kbuild 2008-02-27 18:17:46.999128276 -0600 +@@ -1 +1,3 @@ + include include/asm-generic/Kbuild.asm ++ ++header-y += linkage.h +diff -ur linux-2.6.21.5/include/linux/Kbuild linux-2.6.21.5-patched/include/linux/Kbuild +--- linux-2.6.21.5/include/linux/Kbuild 2007-06-11 13:37:06.000000000 -0500 ++++ linux-2.6.21.5-patched/include/linux/Kbuild 2008-02-27 18:15:05.921149678 -0600 +@@ -100,6 +100,7 @@ + header-y += jffs2.h + header-y += keyctl.h + header-y += limits.h ++header-y += linkage.h + header-y += lock_dlm_plock.h + header-y += magic.h + header-y += major.h diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.21.5-006-wait-for-async-scanned-block-devices.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.21.5-006-wait-for-async-scanned-block-devices.patch new file mode 100644 index 0000000000..910b43ad9b --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.21.5-006-wait-for-async-scanned-block-devices.patch @@ -0,0 +1,55 @@ +diff --git a/init/do_mounts.c b/init/do_mounts.c +index 46fe407..efc134c 100644 +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -25,6 +25,7 @@ int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ + int root_mountflags = MS_RDONLY | MS_SILENT; + char * __initdata root_device_name; + static char __initdata saved_root_name[64]; ++int __initdata root_wait; + + dev_t ROOT_DEV; + +@@ -216,6 +217,14 @@ static int __init root_dev_setup(char *line) + + __setup("root=", root_dev_setup); + ++static int __init rootwait_setup(char *line) ++{ ++ root_wait = simple_strtol(line,NULL,0); ++ return 1; ++} ++ ++__setup("rootwait=", rootwait_setup); ++ + static char * __initdata root_mount_data; + static int __init root_data_setup(char *str) + { +@@ -438,11 +447,24 @@ void __init prepare_namespace(void) + root_device_name += 5; + } + +- is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; +- + if (initrd_load()) + goto out; + ++ /* wait for any asynchronous scanning to complete */ ++ if ((ROOT_DEV == 0) && root_wait) { ++ printk(KERN_INFO "Waiting for root device %s...\n", ++ saved_root_name); ++ do { ++ while (driver_probe_done() != 0) ++ msleep(100); ++ ROOT_DEV = name_to_dev_t(saved_root_name); ++ if (ROOT_DEV == 0) ++ msleep(100); ++ } while (ROOT_DEV == 0); ++ } ++ ++ is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; ++ + if (is_floppy && rd_doload && rd_load_disk(0)) + ROOT_DEV = Root_RAM0; + + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.23-nios2nommu.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.23-nios2nommu.patch new file mode 100644 index 0000000000..6e558fd66c --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.23-nios2nommu.patch @@ -0,0 +1,26567 @@ +diff --git a/arch/nios2nommu/ChangeLog b/arch/nios2nommu/ChangeLog +new file mode 100644 +index 0000000..039c010 +--- /dev/null ++++ b/arch/nios2nommu/ChangeLog +@@ -0,0 +1,4 @@ ++2004-06-15 Ken Hill ++ ++ * Kconfig: Add Microtronix uKit support. ++ +diff --git a/arch/nios2nommu/Kconfig b/arch/nios2nommu/Kconfig +new file mode 100644 +index 0000000..525c77b +--- /dev/null ++++ b/arch/nios2nommu/Kconfig +@@ -0,0 +1,403 @@ ++# ++# For a description of the syntax of this configuration file, ++# see the Configure script. ++# ++mainmenu 'uClinux/Nios2 (w/o MMU) Kernel Configuration' ++ ++config MMU ++ bool ++ default n ++ ++config FPU ++ bool ++ default n ++ ++config ZONE_DMA ++ bool ++ default y ++ ++config UID16 ++ bool ++ default y ++ ++config RWSEM_GENERIC_SPINLOCK ++ bool ++ default y ++ ++config RWSEM_XCHGADD_ALGORITHM ++ bool ++ default n ++ ++config GENERIC_FIND_NEXT_BIT ++ bool ++ default y ++ ++config GENERIC_HWEIGHT ++ bool ++ default y ++ ++config GENERIC_CALIBRATE_DELAY ++ bool ++ default y ++ ++source "init/Kconfig" ++ ++menu "Processor type and features" ++ ++comment 'Platform dependant setup' ++ ++choice ++ prompt "CPU" ++ default NIOS2 ++ ++config NIOS2 ++ bool "NIOS2" ++ help ++ Altera Nios2 softcore processor. ++ ++endchoice ++ ++choice ++ prompt "Platform" ++ default ALTERA_STRATIX ++ ++config MICROTRONIX_UKIT ++ bool "Microtronix uKit board support" ++ depends on NIOS2 ++ help ++ Support for the Microtronix uKit development board. Includes support ++ for Sodimm SDRAM/FLASH, soft ethernet MAC & PHY. ++ ++config MICROTRONIX_STRATIX ++ bool "Microtronix Stratix board support" ++ depends on NIOS2 ++ help ++ Support for the Microtronix Stratix board. Includes support ++ for Sodimm SDRAM/FLASH, soft ethernet MAC & PHY, USB, LVDS ++ & analog/digital converters. ++ ++config MICROTRONIX_CYCLONE ++ bool "Microtronix Cyclone board support" ++ depends on NIOS2 ++ help ++ Support for the Microtronix Cyclone board. Includes support ++ for SDRAM, FLASH, soft ethernet MAC & PHY, USB, ++ & analog/digital converters. ++ ++config MICROTRONIX_PSK ++ bool "Microtronix PSK (Product Starter Kit) support" ++ depends on NIOS2 ++ help ++ Support for the Microtronix PSK (Product Starter Kit), which ++ features firefly module (EP1C4 or EP1C12). Includes support ++ for SDRAM, FLASH, and a variety of product expansion kits such ++ as USB, Ethernet etc. ++ ++config ALTERA_STRATIX ++ bool "Altera Stratix Development board support" ++ depends on NIOS2 ++ help ++ Support for the Altera Stratix Development board. Includes ++ support for 10/100 ethernet, FLASH, SDRAM, compact flash. ++ ++config ALTERA_STRATIX_PRO ++ bool "Altera Stratix Pro Development board support" ++ depends on NIOS2 ++ help ++ Support for the Altera Stratix 1s40 Development board. Includes ++ support for 10/100 ethernet, FLASH, SDRAM, compact flash. ++ ++config ALTERA_STRATIX_II ++ bool "Altera Stratix II Development board support" ++ depends on NIOS2 ++ help ++ Support for the Altera Stratix II Development board. Includes ++ support for 10/100 ethernet, FLASH, SDRAM, compact flash. ++ ++config ALTERA_CYCLONE ++ bool "Altera Cyclone Development board support" ++ depends on NIOS2 ++ help ++ Support for the Altera Cyclone Development board. Includes ++ support for 10/100 ethernet, FLASH, SDRAM, compact flash. ++ ++config ALTERA_CYCLONE_1C12_EVAL ++ bool "Altera Cyclone 1C12 Evaluation board support" ++ depends on NIOS2 ++ help ++ Support for the Altera Cyclone 1C12 Evaluation board (with the ++ embedded processor module). ++ ++config ALTERA_DE2 ++ bool "Altera DE2 Development board support" ++ depends on NIOS2 ++ help ++ Support for the Altera Cyclone Development board. Includes ++ support for 10/100 ethernet, FLASH, SDRAM, VGA, I2C. ++ ++endchoice ++ ++choice ++ prompt "Nios II Hardware Multiply Support" ++ default NIOS2_HW_MULX ++ help ++ This option enables various assembler instructions based on your ++ selection. The choice depends on what target hardware you'll be ++ running your applications on. The default is ++ "Enable mulx instruction". ++ ++ Here is an explanation of each option: ++ None = -mno-hw-mul -mno-hw-mulx ++ (no mul or mulx instructions used) ++ Enable mul instruction = -mhw-mul -mno-hw-mulx ++ (use mul instructions) ++ Enable mul and mulx instructions = -mhw-mul -mhw-mulx ++ (use mul and mulx instructions) ++ ++ If you don't know what to choose, select "Enable mulx instruction". ++ ++config NIOS2_HW_MUL_OFF ++ bool "None" ++ ++config NIOS2_HW_MUL ++ bool "Enable mul instruction" ++ ++config NIOS2_HW_MULX ++ bool "Enable mul and mulx instructions" ++ ++endchoice ++ ++comment 'Platform drivers Options' ++ ++config AVALON_DMA ++ bool "Support of DMA controller with Avalon interface" ++ default y ++ help ++ This enables support of Altera's DMA controller with Avalon ++ interface, so that drivers of DMA-able device can use this ++ interface. ++ ++config PIO_DEVICES ++ bool "Enable leds, seven segment display" ++ default y ++ depends on (ALTERA_STRATIX || ALTERA_STRATIX_PRO || ALTERA_CYCLONE) ++ help ++ This enables example code to support leds, and seven segment ++ display as PIO devices. Once enabled, the kernel will show a ++ counter (increas once a second) on these devices. ++ ++source "arch/nios2nommu/drivers/Kconfig" ++ ++comment 'Miscellaneous Options' ++ ++config EXCALIBUR ++ bool ++ default y ++ depends on (NIOS2) ++ ++config BREAK_ON_START ++ bool "Include breakpoint trap on kernel startup" ++ help ++ Configures the kernel to trap to the GDB client on startup ++ before the kernel starts initialization. This allows you to ++ debug the kernel startup. ++ ++config LARGE_ALLOCS ++ bool "Allow allocating large blocks (> 1MB) of memory" ++ help ++ Allow the slab memory allocator to keep chains for very large ++ memory sizes - upto 32MB. You may need this if your system has ++ a lot of RAM, and you need to able to allocate very large ++ contiguous chunks. If unsure, say N. ++ ++choice ++ prompt "Kernel executes from" ++ ---help--- ++ Choose the memory type that the kernel will be running in. ++ ++config RAMKERNEL ++ bool "RAM" ++ help ++ The kernel will be resident in RAM when running. ++ ++#config ROMKERNEL ++# bool "ROM" ++# help ++# The kernel will be resident in FLASH/ROM when running. ++ ++#config HIMEMKERNEL ++# bool "HIMEM" ++# help ++# The kernel will be resident in high memory when running. ++ ++endchoice ++ ++config PREEMPT ++ bool "Preemptible Kernel" ++ help ++ This option reduces the latency of the kernel when reacting to ++ real-time or interactive events by allowing a low priority process to ++ be preempted even if it is in kernel mode executing a system call. ++ This allows applications to run more reliably even when the system is ++ under load. ++ ++ Say Y here if you are building a kernel for a desktop, embedded ++ or real-time system. Say N if you are unsure. ++ ++config PREEMPT_TIMES ++ bool "Collect preemption latency times" ++ depends on PREEMPT ++ help ++ Allow collection for preemption latency times. ++ ++config CMDLINE ++ string "Default kernel command string" ++ default "CONSOLE=/dev/ttyS0 root=/dev/rom0 ro" ++ help ++ On some architectures, there is currently no way ++ for the boot loader to pass arguments to the kernel. For these ++ architectures, you should supply some command-line options at build ++ time by entering them here. As a minimum, you should specify the ++ memory size and the root device (e.g., mem=64M root=/dev/nfs). ++ ++config PASS_CMDLINE ++ bool "Passed kernel command line from u-boot" ++ default n ++ help ++ Use bootargs env variable from u-boot for kernel command line. ++ will override "Default kernel command string". ++ Say N if you are unsure. ++ ++source "mm/Kconfig" ++ ++config BOOT_LINK_OFFSET ++ hex "Link address offset for booting" ++ default "0x00800000" ++ help ++ This option allows you to set the link address offset of the zImage. ++ This can be useful if you are on a board which has a small amount of ++ memory. ++ ++endmenu ++ ++menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" ++ ++config PCI ++ bool "PCI support" ++ help ++ Support for PCI bus. ++ ++source "drivers/pci/Kconfig" ++ ++config HOTPLUG ++ bool "Support for hot-pluggable device" ++ ---help--- ++ Say Y here if you want to plug devices into your computer while ++ the system is running, and be able to use them quickly. In many ++ cases, the devices can likewise be unplugged at any time too. ++ ++ One well known example of this is PCMCIA- or PC-cards, credit-card ++ size devices such as network cards, modems or hard drives which are ++ plugged into slots found on all modern laptop computers. Another ++ example, used on modern desktops as well as laptops, is USB. ++ ++ Enable HOTPLUG and KMOD, and build a modular kernel. Get agent ++ software (at ) and install it. ++ Then your kernel will automatically call out to a user mode "policy ++ agent" (/sbin/hotplug) to load modules and set up software needed ++ to use devices as you hotplug them. ++ ++source "drivers/pcmcia/Kconfig" ++ ++source "drivers/pci/hotplug/Kconfig" ++ ++endmenu ++ ++menu "Executable file formats" ++ ++config KCORE_AOUT ++ bool ++ default y ++ ++config KCORE_ELF ++ bool ++ default y ++ ++source "fs/Kconfig.binfmt" ++ ++endmenu ++ ++menu "Power management options" ++ ++config PM ++ bool "Power Management support" ++ help ++ Support processor power management modes ++ ++endmenu ++ ++ ++source "net/Kconfig" ++ ++source "drivers/Kconfig" ++ ++source "fs/Kconfig" ++ ++source "arch/nios2nommu/Kconfig.debug" ++ ++menu "Kernel hacking" ++ ++config FULLDEBUG ++ bool "Full Symbolic/Source Debugging support" ++ help ++ Enable debuging symbols on kernel build. ++ ++config FRAME_POINTER ++ bool "Compile the kernel with frame pointers" ++ help ++ If you say Y here the resulting kernel image will be slightly larger ++ and slower, but it will give very useful debugging information. ++ If you don't debug the kernel, you can say N, but we may not be able ++ to solve problems without frame pointers. ++ ++config MAGIC_SYSRQ ++ bool "Magic SysRq key" ++ help ++ Enables console device to interpret special characters as ++ commands to dump state information. ++ ++config HIGHPROFILE ++ bool "Use fast second timer for profiling" ++ depends on COLDFIRE ++ help ++ Use a fast secondary clock to produce profiling information. ++ ++config NO_KERNEL_MSG ++ bool "Suppress Kernel BUG Messages" ++ help ++ Do not output any debug BUG messages within the kernel. ++ ++config LOG_BUF_SHIFT ++ int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL ++ range 12 21 ++ default 17 if ARCH_S390 ++ default 16 if X86_NUMAQ || IA64 ++ default 15 if SMP ++ default 14 ++ help ++ Select kernel log buffer size as a power of 2. ++ Defaults and Examples: ++ 17 => 128 KB for S/390 ++ 16 => 64 KB for x86 NUMAQ or IA-64 ++ 15 => 32 KB for SMP ++ 14 => 16 KB for uniprocessor ++ 13 => 8 KB ++ 12 => 4 KB ++ ++endmenu ++ ++source "security/Kconfig" ++ ++source "crypto/Kconfig" ++ ++source "lib/Kconfig" +diff --git a/arch/nios2nommu/Kconfig.debug b/arch/nios2nommu/Kconfig.debug +new file mode 100644 +index 0000000..b188c4a +--- /dev/null ++++ b/arch/nios2nommu/Kconfig.debug +@@ -0,0 +1,35 @@ ++menu "Kernel hacking" ++ ++source "lib/Kconfig.debug" ++ ++config FULLDEBUG ++ bool "Full Symbolic/Source Debugging support" ++ help ++ Enable debuging symbols on kernel build. ++ ++config FRAME_POINTER ++ bool "Compile the kernel with frame pointers" ++ help ++ If you say Y here the resulting kernel image will be slightly larger ++ and slower, but it will give very useful debugging information. ++ If you don't debug the kernel, you can say N, but we may not be able ++ to solve problems without frame pointers. ++ ++config MAGIC_SYSRQ ++ bool "Magic SysRq key" ++ help ++ Enables console device to interpret special characters as ++ commands to dump state information. ++ ++config HIGHPROFILE ++ bool "Use fast second timer for profiling" ++ depends on COLDFIRE ++ help ++ Use a fast secondary clock to produce profiling information. ++ ++config NO_KERNEL_MSG ++ bool "Suppress Kernel BUG Messages" ++ help ++ Do not output any debug BUG messages within the kernel. ++ ++endmenu +diff --git a/arch/nios2nommu/Makefile b/arch/nios2nommu/Makefile +new file mode 100644 +index 0000000..ca139b6 +--- /dev/null ++++ b/arch/nios2nommu/Makefile +@@ -0,0 +1,181 @@ ++# arch/niosnommu/Makefile ++# ++# Makefile for the architecture dependent flags and dependencies on the ++# nios. ++# ++# Copyright (C) 2001 Vic Phillips (vic@microtronix.com) ++# ++# based on sparcnommu/Makefile: ++# ++# Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) ++# ++KERNELLOAD = ${shell echo `grep "nasys_program_mem " include/asm/nios.h | sed 's/^.*\*)//' | sed 's/)//'`} ++ ++HARDWARE_MK = arch/$(ARCH)/hardware.mk ++ ++platform-$(CONFIG_NIOS) := NIOS2 ++PLATFORM := $(platform-y) ++ ++board-$(CONFIG_ALTERA_STRATIX) := altera_stratix ++board-$(CONFIG_ALTERA_STRATIX_PRO) := altera_stratix_pro ++board-$(CONFIG_ALTERA_STRATIX_II) := altera_stratix_ii ++board-$(CONFIG_ALTERA_CYCLONE) := altera_cyclone ++board-$(CONFIG_ALTERA_CYCLONE_1C12_EVAL) := altera_cyclone_1c12_eval ++board-$(CONFIG_MICROTRONIX_STRATIX) := microtronix_stratix ++board-$(CONFIG_MICROTRONIX_CYCLONE) := microtronix_cyclone ++board-$(CONFIG_MICROTRONIX_UKIT) := microtronix_ukit ++board-$(CONFIG_MICROTRONIX_PSK) := microtronix_psk ++BOARD := $(board-y) ++ ++model-$(CONFIG_RAMKERNEL) := ram ++model-$(CONFIG_ROMKERNEL) := rom ++model-$(CONFIG_HIMEMKERNEL) := himem ++MODEL := $(model-y) ++ ++export PLATFORM BOARD MODEL ++ ++CFLAGS += -DNO_MM -pipe -D__linux__ -D__ELF__ ++#CFLAGS += -DNO_MM -save-temps -D__linux__ -D__ELF__ ++ ++# Uncomment this if you are doing gdb source level ++# debugging of the kernel to get the proper debugging information. ++# ++#CFLAGS += -DDEBUG ++ ++# Turn on/off various hardware multiply options ++cpu-cflags-$(CONFIG_NIOS2_HW_MUL_OFF) += -mno-hw-mul -mno-hw-mulx ++cpu-cflags-$(CONFIG_NIOS2_HW_MUL) += -mhw-mul -mno-hw-mulx ++cpu-cflags-$(CONFIG_NIOS2_HW_MULX) += -mhw-mul -mhw-mulx ++CFLAGS += $(cpu-cflags-y) ++ ++# mulx flags currently cause older version of nios2-elf-gcc to fail ++# The following line ensures that all mulx flags are removed before ++# it is passed to the compiler. ++mulx_help_text:= $(shell $(CC) --target-help | grep mulx) ++ifeq "$(mulx_help_text)" "" ++CFLAGS := $(filter-out -mhw-mulx -mno-hw-mulx, $(CFLAGS)) ++endif ++ ++# Temporary workaround for nios2-elf-gcc bug ++# First noticed in v3.4.1 (Altera Nios II 1.1 b131) ++# To be removed at a later date when bug is resolved. ++CFLAGS += -fno-optimize-sibling-calls ++ ++# This undefines the "__init" type used in defining initialization ++# procedures. When defined, the procedures are put into an 'init' data ++# section that GDB doesn't recognize as source. ++# ++CFLAGS += -DNO_TEXT_SECTIONS ++CFLAGS += -fno-builtin ++CFLAGS += -O2 -g -G 0 ++CFLAGS += -DUTS_SYSNAME=\"uClinux\" ++ ++CFLAGS_GCC_INC := $(shell $(CC) -print-file-name=include) ++CFLAGS += -I$(CFLAGS_GCC_INC) ++ ++AFLAGS += -DNO_MM -g ++#AFLAGS += -DNO_MM -g -save-temps ++ ++# vic - add this to get name of nios gcc library ++LIBGCC_CFLAGS = $(if $(CONFIG_NIOS2_HW_MUL_OFF),-mno-hw-mul) ++LIBGCC := `$(CC) --print-libgcc-file-name $(LIBGCC_CFLAGS)` ++ ++# add this to avoid multiple '_stack' and '_vecbase' definition errors ++# ++ifdef niosgnu ++# Include the path to the lib directory where the ldscripts are found to fix ++# a problem with the cygwin/bash environment. ++ ++#cygwhack: kenw - this following section could be a possible problem ++# due to the O= option on the command line. ++LDSCRIPTS:=$(shell nios2-elf-gcc -print-file-name=ldscripts) ++LDFLAGS += -mnios2elf -L $(LDSCRIPTS)/.. ++else ++LDFLAGS += -mnios2elf ++LDLIBS := -L `$(CC) -print-file-name=m32` -l gcc ++endif ++ ++head-y := arch/nios2nommu/kernel/head.o arch/nios2nommu/kernel/init_task.o ++ ++CLEAN_FILES := include/asm-$(ARCH)/asm-offsets.h \ ++ $(HARDWARE_MK) \ ++ arch/$(ARCH)/kernel/asm-offsets.s \ ++ linux.srec \ ++ linux.flash \ ++ linux.bin \ ++ linux.bin.srec ++ ++core-y += arch/nios2nommu/kernel/ \ ++ arch/nios2nommu/mm/ \ ++ arch/nios2nommu/drivers/ ++ ++libs-y += arch/nios2nommu/lib/ ++ ++libs-y += $(LIBGCC) ++####;dgt2;tmp; ++ ++# force user to configure hardware before building kernel ++ ++pardoned_targets = clean mrproper sgmldocs psdocs pdfdocs \ ++ htmldocs mandocs headers_install ++ ++-include $(HARDWARE_MK) ++build_targets = $(filter-out $(pardoned_targets), $(MAKECMDGOALS)) ++ifneq '$(strip $(build_targets))' '' ++ ifndef SYSPTF ++ ifneq '$(firstword $(MAKECMDGOALS))' 'hwselect' ++ $(error Run "make hwselect SYSPTF=" first) ++ endif ++ endif ++endif ++ ++quiet_cmd_gen_mk = ' RUNNING $@' ++define cmd_gen_mk ++ mkdir -p $(dir $(objtree)/$(HARDWARE_MK)); \ ++ perl -I$(TOPDIR)/arch/$(ARCH)/scripts \ ++ $(srctree)/arch/$(ARCH)/scripts/hwselect.pl $(SYSPTF) \ ++ $(objtree)/$(HARDWARE_MK) ++endef ++ ++.PHONY: hwselect ++hwselect: ++ @echo $($(quiet)cmd_gen_mk); ++ @$(cmd_gen_mk) ++ ++prepare: include/nios2_system.h ++ ++archclean: ++ $(call descend arch/$(ARCH)/boot, subdirclean) ++ ++define filechk_nios2_system.h ++ # call perl script that will build nios2_system.h file ++ perl -I$(TOPDIR)/arch/$(ARCH)/scripts \ ++ $(TOPDIR)/arch/$(ARCH)/scripts/gen_nios2_system.h.pl $(CPU) $(EXEMEM) $(UPLMEM) ++endef ++ ++include/nios2_system.h: $(SYSPTF) FORCE ++ $(call filechk,nios2_system.h) ++ ++quiet_cmd_touch = ' TOUCH $@' ++ cmd_touch = touch $(TOPDIR)/$@ ++ ++arch/$(ARCH)/kernel/vmlinux.lds.S: FORCE ++ @echo $($(quiet)cmd_touch); ++ @$(cmd_touch) ++ ++linuxsrec: linux ++ $(OBJCOPY) -O srec $(LINUX) linux.srec ++ ++boot := arch/nios2nommu/boot ++ ++zImage: vmlinux ++ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ ++ ++compressed: zImage ++ ++CLEAN_FILES += include/nios2_system.h ++ ++archmrproper: ++ ++archdep: ++ +diff --git a/arch/nios2nommu/boot/Makefile b/arch/nios2nommu/boot/Makefile +new file mode 100644 +index 0000000..fd25b72 +--- /dev/null ++++ b/arch/nios2nommu/boot/Makefile +@@ -0,0 +1,17 @@ ++# ++# arch/nios2nommu/boot/Makefile ++# ++# This file is subject to the terms and conditions of the GNU General Public ++# License. See the file "COPYING" in the main directory of this archive ++# for more details. ++ ++targets := zImage ++subdir- := compressed ++ ++$(obj)/zImage: $(obj)/compressed/vmlinux FORCE ++ $(call if_changed,objcopy) ++ @echo 'Kernel: $@ is ready' ++ ++$(obj)/compressed/vmlinux: FORCE ++ $(Q)$(MAKE) $(build)=$(obj)/compressed $@ ++ +diff --git a/arch/nios2nommu/boot/compressed/Makefile b/arch/nios2nommu/boot/compressed/Makefile +new file mode 100644 +index 0000000..2002471 +--- /dev/null ++++ b/arch/nios2nommu/boot/compressed/Makefile +@@ -0,0 +1,36 @@ ++# ++# linux/arch/sh/boot/compressed/Makefile ++# ++# create a compressed vmlinux image from the original vmlinux ++# ++ ++targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o \ ++ piggy.o vmlinux.lds ++EXTRA_AFLAGS := ++ ++OBJECTS = $(obj)/head.o $(obj)/misc.o ++ ++# ++# IMAGE_OFFSET is the load offset of the compression loader ++# ++#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x2000]) ++#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x00400000]) ++ ++LDFLAGS_vmlinux := -T ++ ++$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(obj)/piggy.o FORCE ++ $(call if_changed,ld) ++ @: ++ ++$(obj)/vmlinux.bin: vmlinux FORCE ++ $(call if_changed,objcopy) ++ ++$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE ++ $(call if_changed,gzip) ++ ++LDFLAGS_piggy.o := -r --format binary --oformat elf32-littlenios2 -T ++ ++OBJCOPYFLAGS += -O binary ++ ++$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE ++ $(call if_changed,ld) +diff --git a/arch/nios2nommu/boot/compressed/head.S b/arch/nios2nommu/boot/compressed/head.S +new file mode 100644 +index 0000000..accadd0 +--- /dev/null ++++ b/arch/nios2nommu/boot/compressed/head.S +@@ -0,0 +1,100 @@ ++/* ++ * linux/arch/nios2nommu/boot/compressed/head.S ++ * ++ */ ++ ++ .text ++ .set noat ++#include ++#include ++ ++ /* ++ * This code can be loaded anywhere, as long as output will not ++ * overlap it. ++ * ++ */ ++ ++ .global _start ++_start: ++ // disable interrupt ++ wrctl status, r0 ++ // flush the instruction cache ++ movia r1,NIOS2_ICACHE_SIZE ++ movi r2,NIOS2_ICACHE_LINE_SIZE ++text_init: ++ initi r1 ++ sub r1, r1, r2 ++ bgt r1, zero, text_init ++ // then flush the pipeline ++ flushp ++ // flush the data cache ++ movia r1,NIOS2_DCACHE_SIZE ++ movi r2,NIOS2_DCACHE_LINE_SIZE ++data_init: ++ initd (r1) ++ sub r1, r1, r2 ++ bgt r1, zero, data_init ++ //------------------------------------------------------ ++ // Zero out the .bss segment (uninitialized common data) ++ // ++ movia r2,__bss_start // presume nothing is between ++ movia r1,_end // the .bss and _end. ++1: ++ stb r0,0(r2) ++ addi r2,r2,1 ++ bne r1,r2,1b ++ // set up the stack pointer, some where higher than _end. The stack space must be greater than 32K for decompress. ++ movia sp, 0x10000 ++ add sp,sp,r1 ++ // save args passed from u-boot ++ addi sp,sp,-16 ++ stw r4,0(sp) ++ stw r5,4(sp) ++ stw r6,8(sp) ++ stw r7,12(sp) ++/* ++ * decompress the kernel ++ */ ++ call decompress_kernel ++ ++flush_cache: ++ // flush all cache after loading ++ // flush the data cache ++ movia r1,NIOS2_DCACHE_SIZE ++ movi r2,NIOS2_DCACHE_LINE_SIZE ++data_flush: ++ flushd (r1) ++ sub r1, r1, r2 ++ bgt r1, zero, data_flush ++ // flush the instruction cache ++ movia r1,NIOS2_ICACHE_SIZE ++ movi r2,NIOS2_ICACHE_LINE_SIZE ++text_flush: ++ flushi r1 ++ sub r1, r1, r2 ++ bgt r1, zero, text_flush ++ // then flush the pipeline ++ flushp ++ // pass saved args to kernel ++ ldw r4,0(sp) ++ ldw r5,4(sp) ++ ldw r6,8(sp) ++ ldw r7,12(sp) ++ movia r1,LINUX_SDRAM_START ++ jmp r1 ++ ++ .balign 512 ++fake_headers_as_bzImage: ++ .short 0 ++ .ascii "HdrS" ++ .short 0x0202 ++ .short 0 ++ .short 0 ++ .byte 0x00, 0x10 ++ .short 0 ++ .byte 0 ++ .byte 1 ++ .byte 0x00, 0x80 ++ .long 0 ++ .long 0 ++ +diff --git a/arch/nios2nommu/boot/compressed/install.sh b/arch/nios2nommu/boot/compressed/install.sh +new file mode 100644 +index 0000000..6d72e9e +--- /dev/null ++++ b/arch/nios2nommu/boot/compressed/install.sh +@@ -0,0 +1,57 @@ ++#!/bin/sh ++# ++# arch/sh/boot/install.sh ++# ++# This file is subject to the terms and conditions of the GNU General Public ++# License. See the file "COPYING" in the main directory of this archive ++# for more details. ++# ++# Copyright (C) 1995 by Linus Torvalds ++# ++# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin ++# Adapted from code in arch/i386/boot/install.sh by Russell King ++# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy ++# Adapted from code in arch/sh/boot/install.sh by Takeo Takahashi ++# ++# "make install" script for sh architecture ++# ++# Arguments: ++# $1 - kernel version ++# $2 - kernel image file ++# $3 - kernel map file ++# $4 - default install path (blank if root directory) ++# ++ ++# User may have a custom install script ++ ++if [ -x /sbin/installkernel ]; then ++ exec /sbin/installkernel "$@" ++fi ++ ++if [ "$2" = "zImage" ]; then ++# Compressed install ++ echo "Installing compressed kernel" ++ if [ -f $4/vmlinuz-$1 ]; then ++ mv $4/vmlinuz-$1 $4/vmlinuz.old ++ fi ++ ++ if [ -f $4/System.map-$1 ]; then ++ mv $4/System.map-$1 $4/System.old ++ fi ++ ++ cat $2 > $4/vmlinuz-$1 ++ cp $3 $4/System.map-$1 ++else ++# Normal install ++ echo "Installing normal kernel" ++ if [ -f $4/vmlinux-$1 ]; then ++ mv $4/vmlinux-$1 $4/vmlinux.old ++ fi ++ ++ if [ -f $4/System.map ]; then ++ mv $4/System.map $4/System.old ++ fi ++ ++ cat $2 > $4/vmlinux-$1 ++ cp $3 $4/System.map ++fi +diff --git a/arch/nios2nommu/boot/compressed/misc.c b/arch/nios2nommu/boot/compressed/misc.c +new file mode 100644 +index 0000000..c513e6e +--- /dev/null ++++ b/arch/nios2nommu/boot/compressed/misc.c +@@ -0,0 +1,208 @@ ++/* ++ * arch/nios2nommu/boot/compressed/misc.c ++ * ++ * This is a collection of several routines from gzip-1.0.3 ++ * adapted for Linux. ++ * ++ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 ++ * ++ * Adapted for SH by Stuart Menefy, Aug 1999 ++ * ++ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000 ++ */ ++ ++#include ++ ++/* ++ * gzip declarations ++ */ ++ ++#define OF(args) args ++#define STATIC static ++ ++#undef memset ++#undef memcpy ++#define memzero(s, n) memset ((s), 0, (n)) ++ ++typedef unsigned char uch; ++typedef unsigned short ush; ++typedef unsigned long ulg; ++ ++#define WSIZE 0x8000 /* Window size must be at least 32k, */ ++ /* and a power of two */ ++ ++static uch *inbuf; /* input buffer */ ++static uch window[WSIZE]; /* Sliding window buffer */ ++ ++static unsigned insize = 0; /* valid bytes in inbuf */ ++static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ ++static unsigned outcnt = 0; /* bytes in output buffer */ ++ ++/* gzip flag byte */ ++#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ ++#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ ++#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ ++#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ ++#define COMMENT 0x10 /* bit 4 set: file comment present */ ++#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ ++#define RESERVED 0xC0 /* bit 6,7: reserved */ ++ ++#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) ++ ++/* Diagnostic functions */ ++#ifdef DEBUG ++# define Assert(cond,msg) {if(!(cond)) error(msg);} ++# define Trace(x) fprintf x ++# define Tracev(x) {if (verbose) fprintf x ;} ++# define Tracevv(x) {if (verbose>1) fprintf x ;} ++# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} ++# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} ++#else ++# define Assert(cond,msg) ++# define Trace(x) ++# define Tracev(x) ++# define Tracevv(x) ++# define Tracec(c,x) ++# define Tracecv(c,x) ++#endif ++ ++static int fill_inbuf(void); ++static void flush_window(void); ++static void error(char *m); ++static void gzip_mark(void **); ++static void gzip_release(void **); ++ ++extern char input_data[]; ++extern int input_len; ++ ++static long bytes_out = 0; ++static uch *output_data; ++static unsigned long output_ptr = 0; ++ ++#include "nios2_sio.c" ++ ++static void *malloc(int size); ++static void free(void *where); ++static void error(char *m); ++static void gzip_mark(void **); ++static void gzip_release(void **); ++ ++int puts(const char *); ++ ++extern int _end; ++static unsigned long free_mem_ptr; ++static unsigned long free_mem_end_ptr; ++ ++#define HEAP_SIZE 0x10000 ++ ++#include "../../../../lib/inflate.c" ++ ++static void *malloc(int size) ++{ ++ void *p; ++ ++ if (size <0) error("Malloc error"); ++ if (free_mem_ptr == 0) error("Memory error"); ++ ++ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ ++ ++ p = (void *)free_mem_ptr; ++ free_mem_ptr += size; ++ ++ if (free_mem_ptr >= free_mem_end_ptr) ++ error("Out of memory"); ++ ++ return p; ++} ++ ++static void free(void *where) ++{ /* Don't care */ ++} ++ ++static void gzip_mark(void **ptr) ++{ ++ *ptr = (void *) free_mem_ptr; ++} ++ ++static void gzip_release(void **ptr) ++{ ++ free_mem_ptr = (long) *ptr; ++} ++ ++void* memset(void* s, int c, size_t n) ++{ ++ int i; ++ char *ss = (char*)s; ++ ++ for (i=0;i> 8); ++ } ++ crc = c; ++ bytes_out += (ulg)outcnt; ++ output_ptr += (ulg)outcnt; ++ outcnt = 0; ++} ++ ++static void error(char *x) ++{ ++ puts("\nERROR\n"); ++ puts(x); ++ puts("\n\n -- System halted"); ++ ++ while(1); /* Halt */ ++} ++ ++void decompress_kernel(void) ++{ ++ output_data = (void *)nasys_program_mem; ++ output_ptr = 0; ++ free_mem_ptr = (unsigned long)&_end; ++ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; ++ ++ makecrc(); ++ puts("Uncompressing Linux... "); ++ gunzip(); ++ puts("Ok, booting the kernel.\n"); ++} +diff --git a/arch/nios2nommu/boot/compressed/nios2_sio.c b/arch/nios2nommu/boot/compressed/nios2_sio.c +new file mode 100644 +index 0000000..8630c8f +--- /dev/null ++++ b/arch/nios2nommu/boot/compressed/nios2_sio.c +@@ -0,0 +1,57 @@ ++ ++static int putchar(int ch); ++ ++static int puts(const char *s) ++ { ++ while(*s) ++ putchar(*s++); ++ return 0; ++ } ++ ++#include ++#include ++ ++#if defined(CONFIG_SERIAL_AJUART_CONSOLE) ++ ++#define IORD_ALTERA_AVALON_JTAG_UART_DATA(base) inl(base) ++#define IOWR_ALTERA_AVALON_JTAG_UART_DATA(base, data) outl(data, base) ++#define IORD_ALTERA_AVALON_JTAG_UART_CONTROL(base) inl(base+4) ++#define IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(base, data) outl(data, base+4) ++#define ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK (0xFFFF0000u) ++#define ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_OFST (16) ++ ++static void jtag_putc(int ch) ++{ ++ unsigned base = na_jtag_uart; ++ while ((IORD_ALTERA_AVALON_JTAG_UART_CONTROL(base) & ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK) == 0); ++ IOWR_ALTERA_AVALON_JTAG_UART_DATA(base, ch); ++} ++ ++static int putchar(int ch) ++{ ++ jtag_putc( ch ); ++ return ch; ++} ++ ++#elif defined(CONFIG_NIOS_SERIAL_CONSOLE) ++ ++static void nr_txchar(int ch) ++{ ++ while ((na_uart0->np_uartstatus & np_uartstatus_trdy_mask) == 0); ++ na_uart0->np_uarttxdata = ch; ++} ++ ++static int putchar(int ch) ++{ ++ nr_txchar( ch ); if (ch=='\n') nr_txchar( '\r' ); ++ return ch; ++} ++ ++#else ++ ++static int putchar(int ch) ++{ ++ return ch; ++} ++ ++#endif +diff --git a/arch/nios2nommu/boot/compressed/vmlinux.lds.S b/arch/nios2nommu/boot/compressed/vmlinux.lds.S +new file mode 100644 +index 0000000..08bb3e2 +--- /dev/null ++++ b/arch/nios2nommu/boot/compressed/vmlinux.lds.S +@@ -0,0 +1,34 @@ ++#include ++#include ++ ++OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") ++ ++OUTPUT_ARCH(nios) ++ENTRY(_start) /* Defined in head.S */ ++ ++SECTIONS ++{ ++ . =nasys_program_mem + CONFIG_BOOT_LINK_OFFSET; ++ ++ _text = .; ++ .text : { *(.text) } = 0 ++ .rodata : { *(.rodata) *(.rodata.*) } ++ _etext = .; ++ ++ . = ALIGN(32 / 8); ++ .data : { *(.data) } ++ . = ALIGN(32 / 8); ++ _got = .; ++ .got : { *(.got) _egot = .; *(.got.*) } ++ _edata = .; ++ ++ . = ALIGN(32 / 8); ++ __bss_start = .; ++ .bss : { *(.bss) *(.sbss) } ++ . = ALIGN(32 / 8); ++ _ebss = .; ++ end = . ; ++ _end = . ; ++ ++ got_len = (_egot - _got); ++} +diff --git a/arch/nios2nommu/defconfig b/arch/nios2nommu/defconfig +new file mode 100644 +index 0000000..40629cb +--- /dev/null ++++ b/arch/nios2nommu/defconfig +@@ -0,0 +1,690 @@ ++# ++# Automatically generated make config: don't edit ++# Linux kernel version: 2.6.19-uc1 ++# ++# CONFIG_MMU is not set ++# CONFIG_FPU is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++CONFIG_GENERIC_FIND_NEXT_BIT=y ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_BROKEN_ON_SMP=y ++CONFIG_LOCK_KERNEL=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++ ++# ++# General setup ++# ++CONFIG_LOCALVERSION="" ++CONFIG_LOCALVERSION_AUTO=y ++# CONFIG_SYSVIPC is not set ++# CONFIG_POSIX_MQUEUE is not set ++# CONFIG_BSD_PROCESS_ACCT is not set ++# CONFIG_TASKSTATS is not set ++# CONFIG_UTS_NS is not set ++# CONFIG_AUDIT is not set ++# CONFIG_IKCONFIG is not set ++# CONFIG_RELAY is not set ++CONFIG_INITRAMFS_SOURCE="../romfs ../vendors/Altera/nios2nommu/romfs_list" ++CONFIG_INITRAMFS_ROOT_UID=500 ++CONFIG_INITRAMFS_ROOT_GID=500 ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_EMBEDDED=y ++# CONFIG_SYSCTL_SYSCALL is not set ++# CONFIG_KALLSYMS is not set ++# CONFIG_HOTPLUG is not set ++CONFIG_PRINTK=y ++CONFIG_BUG=y ++# CONFIG_ELF_CORE is not set ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++# CONFIG_EPOLL is not set ++CONFIG_SLAB=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_RT_MUTEXES=y ++CONFIG_TINY_SHMEM=y ++CONFIG_BASE_SMALL=0 ++# CONFIG_SLOB is not set ++ ++# ++# Loadable module support ++# ++# CONFIG_MODULES is not set ++ ++# ++# Block layer ++# ++CONFIG_BLOCK=y ++# CONFIG_BLK_DEV_IO_TRACE is not set ++ ++# ++# IO Schedulers ++# ++CONFIG_IOSCHED_NOOP=y ++# CONFIG_IOSCHED_AS is not set ++CONFIG_IOSCHED_DEADLINE=y ++# CONFIG_IOSCHED_CFQ is not set ++# CONFIG_DEFAULT_AS is not set ++CONFIG_DEFAULT_DEADLINE=y ++# CONFIG_DEFAULT_CFQ is not set ++# CONFIG_DEFAULT_NOOP is not set ++CONFIG_DEFAULT_IOSCHED="deadline" ++ ++# ++# Processor type and features ++# ++ ++# ++# Platform dependant setup ++# ++CONFIG_NIOS2=y ++# CONFIG_MICROTRONIX_UKIT is not set ++# CONFIG_MICROTRONIX_STRATIX is not set ++# CONFIG_MICROTRONIX_CYCLONE is not set ++# CONFIG_MICROTRONIX_PSK is not set ++CONFIG_ALTERA_STRATIX=y ++# CONFIG_ALTERA_STRATIX_PRO is not set ++# CONFIG_ALTERA_STRATIX_II is not set ++# CONFIG_ALTERA_CYCLONE is not set ++# CONFIG_ALTERA_CYCLONE_1C12_EVAL is not set ++# CONFIG_ALTERA_DE2 is not set ++# CONFIG_NIOS2_HW_MUL_OFF is not set ++CONFIG_NIOS2_HW_MUL=y ++# CONFIG_NIOS2_HW_MULX is not set ++ ++# ++# Platform drivers Options ++# ++# CONFIG_AVALON_DMA is not set ++# CONFIG_PIO_DEVICES is not set ++# CONFIG_PCI is not set ++# CONFIG_FB_ALTERA is not set ++# CONFIG_SERIO_ALTPS2 is not set ++# CONFIG_I2C_GPIO is not set ++ ++# ++# Miscellaneous Options ++# ++CONFIG_EXCALIBUR=y ++# CONFIG_BREAK_ON_START is not set ++CONFIG_LARGE_ALLOCS=y ++CONFIG_RAMKERNEL=y ++CONFIG_PREEMPT=y ++# CONFIG_PREEMPT_TIMES is not set ++CONFIG_CMDLINE="" ++# CONFIG_PASS_CMDLINE is not set ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++# CONFIG_DISCONTIGMEM_MANUAL is not set ++# CONFIG_SPARSEMEM_MANUAL is not set ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++# CONFIG_SPARSEMEM_STATIC is not set ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++# CONFIG_RESOURCES_64BIT is not set ++CONFIG_BOOT_LINK_OFFSET=0x00500000 ++ ++# ++# Bus options (PCI, PCMCIA, EISA, MCA, ISA) ++# ++ ++# ++# PCCARD (PCMCIA/CardBus) support ++# ++ ++# ++# PCI Hotplug Support ++# ++ ++# ++# Executable file formats ++# ++CONFIG_KCORE_AOUT=y ++CONFIG_KCORE_ELF=y ++CONFIG_BINFMT_FLAT=y ++CONFIG_BINFMT_ZFLAT=y ++# CONFIG_BINFMT_SHARED_FLAT is not set ++# CONFIG_BINFMT_MISC is not set ++ ++# ++# Power management options ++# ++# CONFIG_PM is not set ++ ++# ++# Networking ++# ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++# CONFIG_NETDEBUG is not set ++CONFIG_PACKET=y ++# CONFIG_PACKET_MMAP is not set ++CONFIG_UNIX=y ++# CONFIG_NET_KEY is not set ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_FIB_HASH=y ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++# CONFIG_INET_XFRM_TUNNEL is not set ++# CONFIG_INET_TUNNEL is not set ++# CONFIG_IPSEC_NAT_TRAVERSAL is not set ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_DIAG is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_IPV6 is not set ++# CONFIG_INET6_XFRM_TUNNEL is not set ++# CONFIG_INET6_TUNNEL is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETFILTER is not set ++ ++# ++# DCCP Configuration (EXPERIMENTAL) ++# ++# CONFIG_IP_DCCP is not set ++ ++# ++# SCTP Configuration (EXPERIMENTAL) ++# ++# CONFIG_IP_SCTP is not set ++ ++# ++# TIPC Configuration (EXPERIMENTAL) ++# ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_DECNET is not set ++# CONFIG_LLC2 is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_HAMRADIO is not set ++# CONFIG_IRDA is not set ++# CONFIG_BT is not set ++# CONFIG_KLIPS is not set ++# CONFIG_IEEE80211 is not set ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_STANDALONE=y ++CONFIG_PREVENT_FIRMWARE_BUILD=y ++# CONFIG_SYS_HYPERVISOR is not set ++ ++# ++# Connector - unified userspace <-> kernelspace linker ++# ++# CONFIG_CONNECTOR is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++# CONFIG_MTD is not set ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Plug and Play support ++# ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_COW_COMMON is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++ ++# ++# Misc devices ++# ++# CONFIG_TIFM_CORE is not set ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++# CONFIG_RAID_ATTRS is not set ++# CONFIG_SCSI is not set ++# CONFIG_SCSI_NETLINK is not set ++ ++# ++# Serial ATA (prod) and Parallel ATA (experimental) drivers ++# ++# CONFIG_ATA is not set ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++ ++# ++# Fusion MPT device support ++# ++# CONFIG_FUSION is not set ++ ++# ++# IEEE 1394 (FireWire) support ++# ++ ++# ++# I2O device support ++# ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++ ++# ++# PHY device support ++# ++# CONFIG_PHYLIB is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++CONFIG_MII=y ++# CONFIG_NET_VENDOR_SMC is not set ++# CONFIG_OPEN_ETH is not set ++# CONFIG_MTIP1000_ETH is not set ++# CONFIG_NE2000 is not set ++# CONFIG_NET_PCI is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++ ++# ++# Ethernet (10000 Mbit) ++# ++ ++# ++# Token Ring devices ++# ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++# CONFIG_SHAPER is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Telephony Support ++# ++# CONFIG_PHONE is not set ++ ++# ++# Input device support ++# ++# CONFIG_INPUT is not set ++ ++# ++# Hardware I/O ports ++# ++# CONFIG_SERIO is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++# CONFIG_VT is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++# CONFIG_NIOS_LCD_16207 is not set ++# CONFIG_NIOS_BUTTON is not set ++# CONFIG_LEDMAN is not set ++# CONFIG_SNAPDOG is not set ++# CONFIG_FAST_TIMER is not set ++# CONFIG_RESETSWITCH is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_8250 is not set ++ ++# ++# Non-8250 serial port support ++# ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++# CONFIG_NIOS_SERIAL is not set ++CONFIG_SERIAL_AJUART=y ++CONFIG_SERIAL_AJUART_CONSOLE=y ++# CONFIG_UNIX98_PTYS is not set ++CONFIG_LEGACY_PTYS=y ++CONFIG_LEGACY_PTY_COUNT=10 ++ ++# ++# IPMI ++# ++# CONFIG_IPMI_HANDLER is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_HW_RANDOM is not set ++# CONFIG_RTC is not set ++# CONFIG_GEN_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_RAW_DRIVER is not set ++ ++# ++# TPM devices ++# ++# CONFIG_TCG_TPM is not set ++# CONFIG_M41T11M6 is not set ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# SPI support ++# ++# CONFIG_SPI is not set ++# CONFIG_SPI_MASTER is not set ++ ++# ++# Dallas's 1-wire bus ++# ++# CONFIG_W1 is not set ++ ++# ++# Hardware Monitoring support ++# ++CONFIG_HWMON=y ++# CONFIG_HWMON_VID is not set ++# CONFIG_SENSORS_ABITUGURU is not set ++# CONFIG_SENSORS_F71805F is not set ++# CONFIG_SENSORS_VT1211 is not set ++# CONFIG_HWMON_DEBUG_CHIP is not set ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# Digital Video Broadcasting Devices ++# ++# CONFIG_DVB is not set ++ ++# ++# Graphics support ++# ++# CONFIG_FIRMWARE_EDID is not set ++# CONFIG_FB is not set ++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++ ++# ++# Sound ++# ++# CONFIG_SOUND is not set ++ ++# ++# USB support ++# ++# CONFIG_USB_ARCH_HAS_HCD is not set ++# CONFIG_USB_ARCH_HAS_OHCI is not set ++# CONFIG_USB_ARCH_HAS_EHCI is not set ++ ++# ++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' ++# ++ ++# ++# USB Gadget Support ++# ++# CONFIG_USB_GADGET is not set ++ ++# ++# MMC/SD Card support ++# ++# CONFIG_MMC is not set ++ ++# ++# LED devices ++# ++# CONFIG_NEW_LEDS is not set ++ ++# ++# LED drivers ++# ++ ++# ++# LED Triggers ++# ++ ++# ++# InfiniBand support ++# ++ ++# ++# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) ++# ++ ++# ++# Real Time Clock ++# ++# CONFIG_RTC_CLASS is not set ++ ++# ++# DMA Engine support ++# ++# CONFIG_DMA_ENGINE is not set ++ ++# ++# DMA Clients ++# ++ ++# ++# DMA Devices ++# ++ ++# ++# File systems ++# ++# CONFIG_EXT2_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_EXT4DEV_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_FS_POSIX_ACL is not set ++# CONFIG_XFS_FS is not set ++# CONFIG_GFS2_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_INOTIFY is not set ++# CONFIG_QUOTA is not set ++# CONFIG_DNOTIFY is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_FUSE_FS is not set ++# CONFIG_DIRECTIO is not set ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# DOS/FAT/NT Filesystems ++# ++# CONFIG_MSDOS_FS is not set ++# CONFIG_VFAT_FS is not set ++# CONFIG_NTFS_FS is not set ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++# CONFIG_PROC_SYSCTL is not set ++CONFIG_SYSFS=y ++# CONFIG_TMPFS is not set ++# CONFIG_HUGETLB_PAGE is not set ++CONFIG_RAMFS=y ++# CONFIG_CONFIGFS_FS is not set ++ ++# ++# Miscellaneous filesystems ++# ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_SQUASHFS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++ ++# ++# Network File Systems ++# ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++# CONFIG_NFS_V3_ACL is not set ++# CONFIG_NFS_V4 is not set ++# CONFIG_NFSD is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++# CONFIG_RPCSEC_GSS_KRB5 is not set ++# CONFIG_RPCSEC_GSS_SPKM3 is not set ++# CONFIG_SMB_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++# CONFIG_9P_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++ ++# ++# Native Language Support ++# ++# CONFIG_NLS is not set ++ ++# ++# Debug ++# ++# CONFIG_COREDUMP_PRINTK is not set ++ ++# ++# Kernel hacking ++# ++# CONFIG_FULLDEBUG is not set ++# CONFIG_FRAME_POINTER is not set ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_NO_KERNEL_MSG is not set ++CONFIG_LOG_BUF_SHIFT=14 ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY is not set ++ ++# ++# Cryptographic options ++# ++# CONFIG_CRYPTO is not set ++ ++# ++# Library routines ++# ++# CONFIG_CRC_CCITT is not set ++# CONFIG_CRC16 is not set ++CONFIG_CRC32=y ++# CONFIG_LIBCRC32C is not set ++CONFIG_ZLIB_INFLATE=y ++CONFIG_PLIST=y +diff --git a/arch/nios2nommu/drivers/Kconfig b/arch/nios2nommu/drivers/Kconfig +new file mode 100644 +index 0000000..2fde3a8 +--- /dev/null ++++ b/arch/nios2nommu/drivers/Kconfig +@@ -0,0 +1,45 @@ ++# Platfrom drivers configuration ++ ++source "arch/nios2nommu/drivers/pci/Kconfig" ++ ++config FB_ALTERA ++ tristate "Avalon VGA controller support" ++ default N ++ select FB ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ This is the frame buffer device driver for the VGA controller ++ in SOPC Builder. ++ ++config SERIO_ALTPS2 ++ tristate "PS2 controller" ++ select VT ++ default N ++ select SERIO ++ ++config I2C_NIOS2_GPIO ++ tristate "GPIO-Based I2C Interface" ++ default N ++ select I2C ++ select I2C_ALGOBIT ++ help ++ Say Y here if you use GPIO lines for an I2C bus. ++ ++config BLK_DEV_ALTCF ++ tristate "Altera CF (IDE mode) interface (Avalon bus) support" ++ select IDE ++ select BLK_DEV_IDE ++ default N ++ help ++ This driver provides support for the Altera Compact flash core (with ++ Avalon interface) support. If you have an Altera or Microtronix ++ development board you can build support into the FPGA device for this. ++ ++config NIOS_SPI ++ bool "Nios SPI device support" ++ depends on NIOS || NIOS2 ++ help ++ This driver supports the Nios softcore SPI device. ++ +diff --git a/arch/nios2nommu/drivers/Makefile b/arch/nios2nommu/drivers/Makefile +new file mode 100644 +index 0000000..f6a273e +--- /dev/null ++++ b/arch/nios2nommu/drivers/Makefile +@@ -0,0 +1,10 @@ ++# ++# Makefile for the Linux nios2-specific device drivers. ++# ++ ++obj-$(CONFIG_PCI) += pci/ ++obj-$(CONFIG_FB_ALTERA) += altfb.o ++obj-$(CONFIG_SERIO_ALTPS2) += altps2.o ++obj-$(CONFIG_I2C_NIOS2_GPIO) += i2c-gpio.o ++obj-$(CONFIG_BLK_DEV_ALTCF) += altcf.o ++obj-$(CONFIG_NIOS_SPI) += spi.o +diff --git a/arch/nios2nommu/drivers/altcf.c b/arch/nios2nommu/drivers/altcf.c +new file mode 100644 +index 0000000..80275c6 +--- /dev/null ++++ b/arch/nios2nommu/drivers/altcf.c +@@ -0,0 +1,266 @@ ++/* ++ * linux/drivers/ide/altcf.c ++ * Support for Altera CompactFlash core with Avalon interface. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Written by Wentao Xu ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Microtronix Datacom Ltd."); ++MODULE_DESCRIPTION("Driver of Altera CompactFlash core with Avalon interface"); ++MODULE_LICENSE("GPL"); ++ ++#define PDEBUG printk ++/* Altera Avalon Compact Flash core registers */ ++#define REG_CFCTL 0 ++#define REG_IDECTL 4 ++ ++/* CFCTL bits */ ++#define CFCTL_DET 1 /* detect status */ ++#define CFCTL_PWR 2 /* Power */ ++#define CFCTL_RST 4 /* Reset */ ++#define CFCTL_IDET 8 /* Detect int enable*/ ++ ++/* IDECTL bits */ ++#define IDECTL_IIDE 1 /* IDE int enable */ ++ ++struct cf_dev { ++ int base; ++ int irq; ++ int ide_base; ++ int ide_irq; ++ int configured; ++ ide_hwif_t *hwif; ++ struct delayed_work wcf; ++}; ++ ++static struct cf_dev cf_devices[MAX_HWIFS] = { ++#if MAX_HWIFS > 0 ++ {na_ide_ctl, na_ide_ctl_irq, na_ide_ide, na_ide_ide_irq, 0, NULL}, ++#endif ++#if MAX_HWIFS > 1 ++ {na_ctl_base1, na_ctl_irq1, na_ide_base1, na_ide_irq1, 0, NULL}, ++#endif ++#if MAX_HWIFS > 2 ++ {na_ctl_base2, na_ctl_irq2, na_ide_base2, na_ide_irq2, 0, NULL}, ++#endif ++#if MAX_HWIFS > 3 ++ {na_ctl_base3, na_ctl_irq3, na_ide_base3, na_ide_irq3, 0, NULL}, ++#endif ++}; ++ ++static inline void cf_init_hwif_ports(hw_regs_t *hw, ++ unsigned long io_addr, ++ unsigned long ctl_addr, ++ int *irq) ++{ ++ unsigned int i; ++ ++ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) ++ hw->io_ports[i] = io_addr + 4*(i-IDE_DATA_OFFSET); ++ ++ hw->io_ports[IDE_CONTROL_OFFSET] = ctl_addr; ++ ++ if (irq) ++ *irq = 0; ++ ++ hw->io_ports[IDE_IRQ_OFFSET] = 0; ++ ++} ++ ++static int cf_release(struct cf_dev* dev) ++{ ++ if (dev) { ++ if ((dev->configured) && (dev->hwif)) { ++ /* disable IDE interrupts */ ++ outl(0, dev->base + REG_IDECTL); ++ /* power off the card */ ++ //outl(0, dev->base + REG_CFCTL); ++ ++ ide_unregister(dev->hwif->index); ++ dev->configured = 0; ++ dev->hwif = NULL; ++ PDEBUG("CF released\n"); ++ return 0; ++ } ++ } ++ return -1; ++} ++ ++static int cf_config(struct cf_dev* dev) ++{ ++ hw_regs_t hw; ++ int index; ++ ide_hwif_t *hwif; ++ ++ if (!dev) ++ return -1; ++ ++ if (!dev->configured) { ++ int i; ++ for (i=1; i<=10; i++) { ++ cf_init_hwif_ports(&hw, dev->ide_base, 0, NULL); ++ hw.irq = dev->ide_irq; ++ hw.chipset = ide_generic; ++ outl(IDECTL_IIDE, dev->base + REG_IDECTL); ++ index = ide_register_hw(&hw, 1, &hwif); ++ if (index >=0) { ++ dev->configured = 1; ++ dev->hwif = hwif; ++ return index; ++ } ++ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(HZ/10); ++ } ++ /* register fails */ ++ PDEBUG("CF:fail to register\n"); ++ /* disable IDE interrupt */ ++ outl(0, dev->base + REG_IDECTL); ++ return -1; ++ } ++ return -2; /* already configured */ ++} ++ ++static irqreturn_t cf_intr(int irq, void *dev_id) ++{ ++ unsigned int cfctl; ++ struct cf_dev* dev = (struct cf_dev *)dev_id; ++ ++ if (!dev) ++ return IRQ_NONE; ++ ++ cfctl=inl(dev->base + REG_CFCTL); ++ /* unpower the card */ ++ outl((cfctl & ~(CFCTL_PWR)), dev->base + REG_CFCTL); ++ ++ if ((cfctl & CFCTL_DET)) ++ schedule_delayed_work(&dev->wcf, HZ/2); ++ else ++ schedule_work(&dev->wcf.work); ++ return IRQ_HANDLED; ++} ++ ++static void cf_event(struct work_struct *work) ++{ ++ struct cf_dev* dev = container_of(work, struct cf_dev, wcf.work); ++ ++ if (dev) { ++ unsigned int cfctl; ++ ++ cfctl=inl(dev->base + REG_CFCTL); ++ if ((cfctl & CFCTL_DET)) { ++ /* a CF card is inserted, power on the card */ ++ outl(((cfctl | CFCTL_PWR) & ~(CFCTL_RST) ), dev->base + REG_CFCTL); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(HZ); ++ cf_config(dev); ++ } ++ else { ++ /* a CF card is removed */ ++ cf_release(dev); ++ } ++ } ++} ++ ++int __init altcf_init(void) ++{ ++ unsigned int cfctl; ++ int i; ++ ide_hwif_t *hwif; ++ hw_regs_t hw; ++ extern ide_hwif_t ide_hwifs[]; ++ ++ for (i=0; i=0) { ++ cf_devices[i].configured = 1; ++ cf_devices[i].hwif = hwif; ++ } ++ else ++ printk("CF register fails\n"); ++ } ++ else printk("Unable to initialize compact flash card. Please re-insert\n"); ++ } ++ ++ /* register the detection interrupt */ ++ if (request_irq(cf_devices[i].irq, cf_intr, IRQF_DISABLED, "cf", &cf_devices[i])) { ++ PDEBUG("CF: unable to get interrupt %d for detecting inf %d\n", ++ cf_devices[i].irq, i ); ++ } else { ++ INIT_DELAYED_WORK(&cf_devices[i].wcf, cf_event); ++ /* enable the detection interrupt */ ++ cfctl=inl(cf_devices[i].base + REG_CFCTL); ++ outl(cfctl | CFCTL_IDET, cf_devices[i].base + REG_CFCTL); ++ } ++ } ++ ++ return 0; ++} ++ ++#ifdef MODULE ++static void __exit altcf_exit(void) ++{ ++ unsigned int cfctl; ++ for (i=0; i ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define vgabase na_vga_controller_0 ++#define XRES 640 ++#define YRES 480 ++#define BPX 16 ++ ++ /* ++ * RAM we reserve for the frame buffer. This defines the maximum screen ++ * size ++ * ++ * The default can be overridden if the driver is compiled as a module ++ */ ++ ++#define VIDEOMEMSIZE (XRES * YRES * (BPX>>3)) ++ ++static void *videomemory; ++static u_long videomemorysize = VIDEOMEMSIZE; ++module_param(videomemorysize, ulong, 0); ++ ++static struct fb_var_screeninfo altfb_default __initdata = { ++ .xres = XRES, ++ .yres = YRES, ++ .xres_virtual = XRES, ++ .yres_virtual = YRES, ++ .bits_per_pixel = BPX, ++#if (BPX == 16) ++ .red = { 11, 5, 0 }, ++ .green = { 5, 6, 0 }, ++ .blue = { 0, 5, 0 }, ++#else // BPX == 24 ++ .red = { 16, 8, 0 }, ++ .green = { 8, 8, 0 }, ++ .blue = { 0, 8, 0 }, ++#endif ++ .activate = FB_ACTIVATE_NOW, ++ .height = -1, ++ .width = -1, ++ // timing useless ? ++ .pixclock = 20000, ++ .left_margin = 64, ++ .right_margin = 64, ++ .upper_margin = 32, ++ .lower_margin = 32, ++ .hsync_len = 64, ++ .vsync_len = 2, ++ .vmode = FB_VMODE_NONINTERLACED, ++}; ++ ++static struct fb_fix_screeninfo altfb_fix __initdata = { ++ .id = "Altera FB", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .line_length = (XRES * (BPX>>3)), ++ .xpanstep = 0, ++ .ypanstep = 0, ++ .ywrapstep = 0, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++static int altfb_mmap(struct fb_info *info, ++ struct vm_area_struct *vma); ++ ++static struct fb_ops altfb_ops = { ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_mmap = altfb_mmap, ++}; ++ ++ ++ /* ++ * Most drivers don't need their own mmap function ++ */ ++ ++static int altfb_mmap(struct fb_info *info, ++ struct vm_area_struct *vma) ++{ ++ /* this is uClinux (no MMU) specific code */ ++ vma->vm_flags |= (VM_RESERVED | VM_MAYSHARE); ++ vma->vm_start = (unsigned) videomemory; ++ return 0; ++} ++ ++ /* ++ * Initialisation ++ */ ++ ++static void altfb_platform_release(struct device *device) ++{ ++ // This is called when the reference count goes to zero. ++ dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n"); ++} ++ ++static int __init altfb_probe(struct platform_device *dev) ++{ ++ struct fb_info *info; ++ int retval = -ENOMEM; ++ dma_addr_t handle; ++ ++ /* ++ * For real video cards we use ioremap. ++ */ ++ if (!(videomemory = dma_alloc_coherent(&dev->dev, PAGE_ALIGN(videomemorysize), &handle, GFP_KERNEL))) { ++ printk(KERN_ERR "altfb: unable to allocate screen memory\n"); ++ return retval; ++ } ++ altfb_fix.smem_start = handle; ++ altfb_fix.smem_len = videomemorysize; ++ ++ info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); ++ if (!info) ++ goto err; ++ ++ info->screen_base = (char __iomem *)videomemory; ++ info->fbops = &altfb_ops; ++ info->var = altfb_default; ++ info->fix = altfb_fix; ++ info->pseudo_palette = info->par; ++ info->par = NULL; ++ info->flags = FBINFO_FLAG_DEFAULT; ++ ++ retval = fb_alloc_cmap(&info->cmap, 256, 0); ++ if (retval < 0) ++ goto err1; ++ ++ retval = register_framebuffer(info); ++ if (retval < 0) ++ goto err2; ++ platform_set_drvdata(dev, info); ++ ++ outl(0x0,vgabase+0); // Reset the VGA controller ++ outl(videomemory,vgabase+4); // Where our frame buffer starts ++ outl(videomemorysize,vgabase+8); // amount of memory needed ++ outl(0x1,vgabase+0); // Set the go bit ++ ++ printk(KERN_INFO ++ "fb%d: Altera frame buffer device, using %ldK of video memory\n", ++ info->node, videomemorysize >> 10); ++ // printk("vga %08x, video %08x+%08x\n",vgabase,videomemory,videomemorysize); ++ return 0; ++err2: ++ fb_dealloc_cmap(&info->cmap); ++err1: ++ framebuffer_release(info); ++err: ++ dma_free_noncoherent(&dev->dev, videomemorysize, videomemory, handle); ++ return retval; ++} ++ ++static int altfb_remove(struct platform_device *dev) ++{ ++ struct fb_info *info = platform_get_drvdata(dev); ++ ++ if (info) { ++ unregister_framebuffer(info); ++ dma_free_noncoherent(&dev->dev, videomemorysize, videomemory, altfb_fix.smem_start); ++ framebuffer_release(info); ++ } ++ return 0; ++} ++ ++static struct platform_driver altfb_driver = { ++ .probe = altfb_probe, ++ .remove = altfb_remove, ++ .driver = { ++ .name = "altfb", ++ }, ++}; ++ ++static struct platform_device altfb_device = { ++ .name = "altfb", ++ .id = 0, ++ .dev = { ++ .release = altfb_platform_release, ++ } ++}; ++ ++static int __init altfb_init(void) ++{ ++ int ret = 0; ++ ++ ret = platform_driver_register(&altfb_driver); ++ ++ if (!ret) { ++ ret = platform_device_register(&altfb_device); ++ if (ret) ++ platform_driver_unregister(&altfb_driver); ++ } ++ return ret; ++} ++ ++module_init(altfb_init); ++ ++#ifdef MODULE ++static void __exit altfb_exit(void) ++{ ++ platform_device_unregister(&altfb_device); ++ platform_driver_unregister(&altfb_driver); ++} ++ ++module_exit(altfb_exit); ++ ++MODULE_LICENSE("GPL"); ++#endif /* MODULE */ +diff --git a/arch/nios2nommu/drivers/altps2.c b/arch/nios2nommu/drivers/altps2.c +new file mode 100644 +index 0000000..4a6523c +--- /dev/null ++++ b/arch/nios2nommu/drivers/altps2.c +@@ -0,0 +1,193 @@ ++/* ++ * altera DE2 PS/2 ++ * ++ * linux/drivers/input/serio/sa1111ps2.c ++ * ++ * Copyright (C) 2002 Russell King ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++struct ps2if { ++ struct serio *io; ++ struct platform_device *dev; ++ unsigned base; ++ unsigned irq; ++}; ++ ++/* ++ * Read all bytes waiting in the PS2 port. There should be ++ * at the most one, but we loop for safety. If there was a ++ * framing error, we have to manually clear the status. ++ */ ++static irqreturn_t ps2_rxint(int irq, void *dev_id) ++{ ++ struct ps2if *ps2if = dev_id; ++ unsigned int status; ++ int handled = IRQ_NONE; ++ ++ while ((status = inl(ps2if->base)) & 0xffff0000) { ++ serio_interrupt(ps2if->io, status & 0xff, 0); ++ handled = IRQ_HANDLED; ++ } ++ return handled; ++} ++ ++/* ++ * Write a byte to the PS2 port. We have to wait for the ++ * port to indicate that the transmitter is empty. ++ */ ++static int ps2_write(struct serio *io, unsigned char val) ++{ ++ struct ps2if *ps2if = io->port_data; ++ outl(val,ps2if->base); ++ // should check command send error ++ if (inl(ps2if->base+4) & (1<<10)) ++ { ++ // printk("ps2 write error %02x\n",val); ++ } ++ return 0; ++} ++ ++static int ps2_open(struct serio *io) ++{ ++ struct ps2if *ps2if = io->port_data; ++ int ret; ++ ++ ret = request_irq(ps2if->irq, ps2_rxint, 0, ++ "altps2", ps2if); ++ if (ret) { ++ printk(KERN_ERR "altps2: could not allocate IRQ%d: %d\n", ++ ps2if->irq, ret); ++ return ret; ++ } ++ outl(1,ps2if->base+4); // enable rx irq ++ return 0; ++} ++ ++static void ps2_close(struct serio *io) ++{ ++ struct ps2if *ps2if = io->port_data; ++ outl(0,ps2if->base); // disable rx irq ++ free_irq(ps2if->irq, ps2if); ++} ++ ++/* ++ * Add one device to this driver. ++ */ ++static int ps2_probe(struct platform_device *dev) ++{ ++ struct ps2if *ps2if; ++ struct serio *serio; ++ unsigned int status; ++ int ret; ++ ++ ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); ++ serio = kmalloc(sizeof(struct serio), GFP_KERNEL); ++ if (!ps2if || !serio) { ++ ret = -ENOMEM; ++ goto free; ++ } ++ ++ memset(ps2if, 0, sizeof(struct ps2if)); ++ memset(serio, 0, sizeof(struct serio)); ++ ++ serio->id.type = SERIO_8042; ++ serio->write = ps2_write; ++ serio->open = ps2_open; ++ serio->close = ps2_close; ++ strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); ++ strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); ++ serio->port_data = ps2if; ++ serio->dev.parent = &dev->dev; ++ ps2if->io = serio; ++ ps2if->dev = dev; ++ platform_set_drvdata(dev, ps2if); ++ ++ /* ++ * Request the physical region for this PS2 port. ++ */ ++ if (dev->num_resources < 2) { ++ ret = -ENODEV; ++ goto out; ++ } ++ if (!request_mem_region(dev->resource[0].start, ++ 4, ++ "altps2")) { ++ ret = -EBUSY; ++ goto free; ++ } ++ ps2if->base = dev->resource[0].start; ++ ps2if->irq = dev->resource[1].start; ++ printk("altps2 : base %08x irq %d\n",ps2if->base,ps2if->irq); ++ // clear fifo ++ while ((status = inl(ps2if->base)) & 0xffff0000) { ++ } ++ ++ serio_register_port(ps2if->io); ++ return 0; ++ ++ out: ++ release_mem_region(dev->resource[0].start,4); ++ free: ++ platform_set_drvdata(dev, NULL); ++ kfree(ps2if); ++ kfree(serio); ++ return ret; ++} ++ ++/* ++ * Remove one device from this driver. ++ */ ++static int ps2_remove(struct platform_device *dev) ++{ ++ struct ps2if *ps2if = platform_get_drvdata(dev); ++ ++ platform_set_drvdata(dev, NULL); ++ serio_unregister_port(ps2if->io); ++ release_mem_region(dev->resource[0].start,4); ++ ++ kfree(ps2if); ++ ++ return 0; ++} ++ ++/* ++ * Our device driver structure ++ */ ++static struct platform_driver ps2_driver = { ++ .probe = ps2_probe, ++ .remove = ps2_remove, ++ .driver = { ++ .name = "altps2", ++ }, ++}; ++ ++static int __init ps2_init(void) ++{ ++ return platform_driver_register(&ps2_driver); ++} ++ ++static void __exit ps2_exit(void) ++{ ++ platform_driver_unregister(&ps2_driver); ++} ++ ++module_init(ps2_init); ++module_exit(ps2_exit); +diff --git a/arch/nios2nommu/drivers/i2c-gpio.c b/arch/nios2nommu/drivers/i2c-gpio.c +new file mode 100644 +index 0000000..3f5e51a +--- /dev/null ++++ b/arch/nios2nommu/drivers/i2c-gpio.c +@@ -0,0 +1,166 @@ ++/* ++ * drivers/i2c/busses/i2c-gpio.c for Nios2 ++ * ++ * drivers/i2c/busses/i2c-ixp2000.c ++ * ++ * I2C adapter for IXP2000 systems using GPIOs for I2C bus ++ * ++ * Author: Deepak Saxena ++ * Based on IXDP2400 code by: Naeem M. Afzal ++ * Made generic by: Jeff Daly ++ * ++ * Copyright (c) 2003-2004 MontaVista Software Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ * ++ * From Jeff Daly: ++ * ++ * I2C adapter driver for Intel IXDP2xxx platforms. This should work for any ++ * IXP2000 platform if it uses the HW GPIO in the same manner. Basically, ++ * SDA and SCL GPIOs have external pullups. Setting the respective GPIO to ++ * an input will make the signal a '1' via the pullup. Setting them to ++ * outputs will pull them down. ++ * ++ * The GPIOs are open drain signals and are used as configuration strap inputs ++ * during power-up so there's generally a buffer on the board that needs to be ++ * 'enabled' to drive the GPIOs. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++static inline int gpio_scl_pin(void *data) ++{ ++ return ((struct gpio_i2c_pins*)data)->scl_pin; ++} ++ ++static inline int gpio_sda_pin(void *data) ++{ ++ return ((struct gpio_i2c_pins*)data)->sda_pin; ++} ++ ++ ++static void gpio_bit_setscl(void *data, int val) ++{ ++ int i = 5000; ++ ++ if (val) { ++ outl(3,gpio_scl_pin(data)); ++ while(!(inl(gpio_scl_pin(data)) & 1) && i--); ++ } else { ++ outl(2,gpio_scl_pin(data)); ++ } ++} ++ ++static void gpio_bit_setsda(void *data, int val) ++{ ++ if (val) { ++ outl(1,gpio_sda_pin(data)); ++ } else { ++ outl(0,gpio_sda_pin(data)); ++ } ++} ++ ++static int gpio_bit_getscl(void *data) ++{ ++ return inl(gpio_scl_pin(data)) & 1; ++} ++ ++static int gpio_bit_getsda(void *data) ++{ ++ return inl(gpio_sda_pin(data)) & 1; ++} ++ ++struct gpio_i2c_data { ++ struct gpio_i2c_pins *gpio_pins; ++ struct i2c_adapter adapter; ++ struct i2c_algo_bit_data algo_data; ++}; ++ ++static int gpio_i2c_remove(struct platform_device *plat_dev) ++{ ++ struct gpio_i2c_data *drv_data = platform_get_drvdata(plat_dev); ++ ++ platform_set_drvdata(plat_dev, NULL); ++ ++ i2c_del_adapter(&drv_data->adapter); ++ ++ kfree(drv_data); ++ ++ return 0; ++} ++ ++static int gpio_i2c_probe(struct platform_device *plat_dev) ++{ ++ int err; ++ struct gpio_i2c_pins *gpio = plat_dev->dev.platform_data; ++ struct gpio_i2c_data *drv_data = ++ kzalloc(sizeof(struct gpio_i2c_data), GFP_KERNEL); ++ ++ if (!drv_data) ++ return -ENOMEM; ++ drv_data->gpio_pins = gpio; ++ ++ drv_data->algo_data.data = gpio; ++ drv_data->algo_data.setsda = gpio_bit_setsda; ++ drv_data->algo_data.setscl = gpio_bit_setscl; ++ drv_data->algo_data.getsda = gpio_bit_getsda; ++ drv_data->algo_data.getscl = gpio_bit_getscl; ++ drv_data->algo_data.udelay = 6; ++ drv_data->algo_data.timeout = 100; ++ ++ drv_data->adapter.id = I2C_HW_B_IXP2000, // borrowed, ++ strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, ++ I2C_NAME_SIZE); ++ drv_data->adapter.algo_data = &drv_data->algo_data, ++ ++ drv_data->adapter.dev.parent = &plat_dev->dev; ++ drv_data->adapter.class = I2C_CLASS_ALL; ++ ++ outl(1,gpio->sda_pin); ++ outl(1,gpio->scl_pin); ++ ++ if ((err = i2c_bit_add_bus(&drv_data->adapter)) != 0) { ++ dev_err(&plat_dev->dev, "Could not install, error %d\n", err); ++ kfree(drv_data); ++ return err; ++ } ++ ++ platform_set_drvdata(plat_dev, drv_data); ++ printk("i2c-gpio driver at %08x\n",gpio->sda_pin); ++ ++ return 0; ++} ++ ++static struct platform_driver gpio_i2c_driver = { ++ .probe = gpio_i2c_probe, ++ .remove = gpio_i2c_remove, ++ .driver = { ++ .name = "GPIO-I2C", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init gpio_i2c_init(void) ++{ ++ return platform_driver_register(&gpio_i2c_driver); ++} ++ ++static void __exit gpio_i2c_exit(void) ++{ ++ platform_driver_unregister(&gpio_i2c_driver); ++} ++ ++module_init(gpio_i2c_init); ++module_exit(gpio_i2c_exit); ++ +diff --git a/arch/nios2nommu/drivers/pci/Kconfig b/arch/nios2nommu/drivers/pci/Kconfig +new file mode 100644 +index 0000000..6c3b175 +--- /dev/null ++++ b/arch/nios2nommu/drivers/pci/Kconfig +@@ -0,0 +1,4 @@ ++config PCI_ALTPCI ++ bool "Altera PCI host bridge" ++ select PCI ++ default n +diff --git a/arch/nios2nommu/drivers/pci/Makefile b/arch/nios2nommu/drivers/pci/Makefile +new file mode 100644 +index 0000000..b027e1e +--- /dev/null ++++ b/arch/nios2nommu/drivers/pci/Makefile +@@ -0,0 +1,6 @@ ++# ++# Makefile for the PCI specific kernel interface routines under Linux. ++# ++ ++obj-y += pci.o ++obj-$(CONFIG_PCI_ALTPCI) += altpci.o setup-irq.o pci-auto.o +diff --git a/arch/nios2nommu/drivers/pci/altpci.c b/arch/nios2nommu/drivers/pci/altpci.c +new file mode 100644 +index 0000000..85959ea +--- /dev/null ++++ b/arch/nios2nommu/drivers/pci/altpci.c +@@ -0,0 +1,204 @@ ++/* arch/sh/kernel/pci.c ++ * $Id: altpci.c,v 1.1 2006/07/05 06:23:17 gerg Exp $ ++ * ++ * Copyright (c) 2002 M. R. Brown ++ * ++ * ++ * These functions are collected here to reduce duplication of common ++ * code amongst the many platform-specific PCI support code files. ++ * ++ * These routines require the following board-specific routines: ++ * void pcibios_fixup_irqs(); ++ * ++ * See include/asm-sh/pci.h for more information. ++ */ ++ ++#include ++#include ++#include ++ ++/* ++ * Direct access to PCI hardware... ++ */ ++#define pcicfg_space (na_pci_compiler_0_PCI_Bus_Access) // avalon space ++#define pciio (pcicfg_space+0x100000) // pci io device base in avalon space ++#define pcimm (pcicfg_space+0x200000) // pci mem device base in avalon space ++ // idsel of ad11=dev0,ad12=dev1 , using type 0 config request ++#define pcicfg(dev,fun,reg) (pcicfg_space | ((dev)<<11) | ((fun)<<8) | (reg)) // cfg space ++ ++// FIX ME for your board, dram device for external pci masters access ++static int __init alt_pci_init(void) ++{ ++ unsigned dev,fun; ++ // setup dram bar ++ dev=0; fun=0; ++ outl(nasys_program_mem,pcicfg(dev,fun,0x10)); // mem space ++ outw(0x0006,pcicfg(dev,fun,0x04)); // enable master, mem space ++ return 0; ++} ++ ++subsys_initcall(alt_pci_init); ++ ++#define PCICFG(bus, devfn, where) (pcicfg_space | (bus->number << 16) | (devfn << 8) | (where & ~3)) ++#define ALT_PCI_IO_BASE (pciio) ++#define ALT_PCI_IO_SIZE 0x100000 ++#define ALT_PCI_MEMORY_BASE (pcimm) ++#define ALT_PCI_MEM_SIZE 0x100000 ++ ++/* ++ * Functions for accessing PCI configuration space with type 1 accesses ++ */ ++ ++// FIX ME for your board, number of pci bus, and number of devices ++static inline int pci_range_ck(struct pci_bus *bus, unsigned int devfn) ++{ ++ if (bus->number > 0 || PCI_SLOT(devfn) == 0 || PCI_SLOT(devfn) > 2) ++ return -1; ++ ++ return 0; ++} ++ ++static int alt_pci_read(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 *val) ++{ ++ u32 data; ++ ++ if (pci_range_ck(bus, devfn)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ // local_irq_save(flags); ++ data = inl(PCICFG(bus, devfn, where)); ++ // local_irq_restore(flags); ++ ++ switch (size) { ++ case 1: ++ *val = (data >> ((where & 3) << 3)) & 0xff; ++ break; ++ case 2: ++ *val = (data >> ((where & 2) << 3)) & 0xffff; ++ break; ++ case 4: ++ *val = data; ++ break; ++ default: ++ return PCIBIOS_FUNC_NOT_SUPPORTED; ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++/* ++ * we'll do a read, ++ * mask,write operation. ++ * We'll allow an odd byte offset, though it should be illegal. ++ */ ++static int alt_pci_write(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ int shift; ++ u32 data; ++ ++ if (pci_range_ck(bus, devfn)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ // local_irq_save(flags); ++ data = inl(PCICFG(bus, devfn, where)); ++ // local_irq_restore(flags); ++ ++ switch (size) { ++ case 1: ++ shift = (where & 3) << 3; ++ data &= ~(0xff << shift); ++ data |= ((val & 0xff) << shift); ++ break; ++ case 2: ++ shift = (where & 2) << 3; ++ data &= ~(0xffff << shift); ++ data |= ((val & 0xffff) << shift); ++ break; ++ case 4: ++ data = val; ++ break; ++ default: ++ return PCIBIOS_FUNC_NOT_SUPPORTED; ++ } ++ ++ outl(data, PCICFG(bus, devfn, where)); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++struct pci_ops alt_pci_ops = { ++ .read = alt_pci_read, ++ .write = alt_pci_write, ++}; ++ ++static struct resource alt_io_resource = { ++ .name = "ALTPCI IO", ++ .start = ALT_PCI_IO_BASE, ++ .end = ALT_PCI_IO_BASE + ALT_PCI_IO_SIZE - 1, ++ .flags = IORESOURCE_IO ++}; ++ ++static struct resource alt_mem_resource = { ++ .name = "ALTPCI mem", ++ .start = ALT_PCI_MEMORY_BASE, ++ .end = ALT_PCI_MEMORY_BASE + ALT_PCI_MEM_SIZE - 1, ++ .flags = IORESOURCE_MEM ++}; ++ ++extern struct pci_ops alt_pci_ops; ++ ++struct pci_channel board_pci_channels[] = { ++ { &alt_pci_ops, &alt_io_resource, &alt_mem_resource, 0, 0xff }, ++ { NULL, NULL, NULL, 0, 0 }, ++}; ++ ++char *pcibios_setup(char *option) ++{ ++ /* Nothing for us to handle. */ ++ return(option); ++} ++ ++void pcibios_fixup_bus(struct pci_bus *b) ++{ ++} ++ ++/* ++ * IRQ functions ++ */ ++static u8 __init altpci_no_swizzle(struct pci_dev *dev, u8 *pin) ++{ ++ /* no swizzling */ ++ return PCI_SLOT(dev->devfn); ++} ++ ++// FIX ME for your board, nios2 irqn mapping ++int __init pcibios_map_platform_irq(u8 slot, u8 pin) ++{ ++ int irq = na_irqn_0_irq + ((slot-1)*4) + (pin-1); ++ // printk("map slot %d pin %d irq %d\n",slot,pin,irq); ++ return irq; ++} ++ ++static int altpci_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ int irq = -1; ++ ++ /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ ++ irq = pcibios_map_platform_irq(slot,pin); ++ if( irq < 0 ) { ++ // printk("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); ++ return irq; ++ } ++ ++ // printk("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); ++ ++ return irq; ++} ++ ++void __init pcibios_fixup_irqs(void) ++{ ++ pci_fixup_irqs(altpci_no_swizzle, altpci_pci_lookup_irq); ++} ++ +diff --git a/arch/nios2nommu/drivers/pci/pci-auto.c b/arch/nios2nommu/drivers/pci/pci-auto.c +new file mode 100644 +index 0000000..e1cdfdc +--- /dev/null ++++ b/arch/nios2nommu/drivers/pci/pci-auto.c +@@ -0,0 +1,559 @@ ++/* ++ * PCI autoconfiguration library ++ * ++ * Author: Matt Porter ++ * ++ * Copyright 2000, 2001 MontaVista Software Inc. ++ * Copyright 2001 Bradley D. LaRonde ++ * Copyright 2003 Paul Mundt ++ * ++ * 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. ++ */ ++ ++/* ++ * Modified for MIPS by Jun Sun, jsun@mvista.com ++ * ++ * . Simplify the interface between pci_auto and the rest: a single function. ++ * . Assign resources from low address to upper address. ++ * . change most int to u32. ++ * ++ * Further modified to include it as mips generic code, ppopov@mvista.com. ++ * ++ * 2001-10-26 Bradley D. LaRonde ++ * - Add a top_bus argument to the "early config" functions so that ++ * they can set a fake parent bus pointer to convince the underlying ++ * pci ops to use type 1 configuration for sub busses. ++ * - Set bridge base and limit registers correctly. ++ * - Align io and memory base properly before and after bridge setup. ++ * - Don't fall through to pci_setup_bars for bridge. ++ * - Reformat the debug output to look more like lspci's output. ++ * ++ * Cloned for SuperH by M. R. Brown, mrbrown@0xd6.org ++ * ++ * 2003-08-05 Paul Mundt ++ * - Don't update the BAR values on systems that already have valid addresses ++ * and don't want these updated for whatever reason, by way of a new config ++ * option check. However, we still read in the old BAR values so that they ++ * can still be reported through the debug output. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#undef DEBUG ++#define DEBUG // you can remove debug message here ++ ++#ifdef DEBUG ++#define DBG(x...) printk(x) ++#else ++#define DBG(x...) ++#endif ++ ++/* ++ * These functions are used early on before PCI scanning is done ++ * and all of the pci_dev and pci_bus structures have been created. ++ */ ++static struct pci_dev *fake_pci_dev(struct pci_channel *hose, ++ int top_bus, int busnr, int devfn) ++{ ++ static struct pci_dev dev; ++ static struct pci_bus bus; ++ ++ dev.bus = &bus; ++ dev.sysdata = hose; ++ dev.devfn = devfn; ++ bus.number = busnr; ++ bus.ops = hose->pci_ops; ++ ++ if(busnr != top_bus) ++ /* Fake a parent bus structure. */ ++ bus.parent = &bus; ++ else ++ bus.parent = NULL; ++ ++ return &dev; ++} ++ ++#define EARLY_PCI_OP(rw, size, type) \ ++int early_##rw##_config_##size(struct pci_channel *hose, \ ++ int top_bus, int bus, int devfn, int offset, type value) \ ++{ \ ++ return pci_##rw##_config_##size( \ ++ fake_pci_dev(hose, top_bus, bus, devfn), \ ++ offset, value); \ ++} ++ ++EARLY_PCI_OP(read, byte, u8 *) ++EARLY_PCI_OP(read, word, u16 *) ++EARLY_PCI_OP(read, dword, u32 *) ++EARLY_PCI_OP(write, byte, u8) ++EARLY_PCI_OP(write, word, u16) ++EARLY_PCI_OP(write, dword, u32) ++ ++static struct resource *io_resource_inuse; ++static struct resource *mem_resource_inuse; ++ ++static u32 pciauto_lower_iospc; ++static u32 pciauto_upper_iospc; ++ ++static u32 pciauto_lower_memspc; ++static u32 pciauto_upper_memspc; ++ ++static void __init ++pciauto_setup_bars(struct pci_channel *hose, ++ int top_bus, ++ int current_bus, ++ int pci_devfn, ++ int bar_limit) ++{ ++ u32 bar_response, bar_size, bar_value; ++ u32 bar, addr_mask, bar_nr = 0; ++ u32 * upper_limit; ++ u32 * lower_limit; ++ int found_mem64 = 0; ++ ++ for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) { ++#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) ++ u32 bar_addr; ++ ++ /* Read the old BAR value */ ++ early_read_config_dword(hose, top_bus, ++ current_bus, ++ pci_devfn, ++ bar, ++ &bar_addr); ++#endif ++ ++ /* Tickle the BAR and get the response */ ++ early_write_config_dword(hose, top_bus, ++ current_bus, ++ pci_devfn, ++ bar, ++ 0xffffffff); ++ ++ early_read_config_dword(hose, top_bus, ++ current_bus, ++ pci_devfn, ++ bar, ++ &bar_response); ++ ++#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) ++ /* ++ * Write the old BAR value back out, only update the BAR ++ * if we implicitly want resources to be updated, which ++ * is done by the generic code further down. -- PFM. ++ */ ++ early_write_config_dword(hose, top_bus, ++ current_bus, ++ pci_devfn, ++ bar, ++ bar_addr); ++#endif ++ ++ /* If BAR is not implemented go to the next BAR */ ++ if (!bar_response) ++ continue; ++ ++ /* ++ * Workaround for a BAR that doesn't use its upper word, ++ * like the ALi 1535D+ PCI DC-97 Controller Modem (M5457). ++ * bdl ++ */ ++ if (!(bar_response & 0xffff0000)) ++ bar_response |= 0xffff0000; ++ ++retry: ++ /* Check the BAR type and set our address mask */ ++ if (bar_response & PCI_BASE_ADDRESS_SPACE) { ++ addr_mask = PCI_BASE_ADDRESS_IO_MASK; ++ upper_limit = &pciauto_upper_iospc; ++ lower_limit = &pciauto_lower_iospc; ++ DBG(" I/O"); ++ } else { ++ if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == ++ PCI_BASE_ADDRESS_MEM_TYPE_64) ++ found_mem64 = 1; ++ ++ addr_mask = PCI_BASE_ADDRESS_MEM_MASK; ++ upper_limit = &pciauto_upper_memspc; ++ lower_limit = &pciauto_lower_memspc; ++ DBG(" Mem"); ++ } ++ ++ ++ /* Calculate requested size */ ++ bar_size = ~(bar_response & addr_mask) + 1; ++ ++ /* Allocate a base address */ ++ bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size; ++ ++ if ((bar_value + bar_size) > *upper_limit) { ++ if (bar_response & PCI_BASE_ADDRESS_SPACE) { ++ if (io_resource_inuse->child) { ++ io_resource_inuse = ++ io_resource_inuse->child; ++ pciauto_lower_iospc = ++ io_resource_inuse->start; ++ pciauto_upper_iospc = ++ io_resource_inuse->end + 1; ++ goto retry; ++ } ++ ++ } else { ++ if (mem_resource_inuse->child) { ++ mem_resource_inuse = ++ mem_resource_inuse->child; ++ pciauto_lower_memspc = ++ mem_resource_inuse->start; ++ pciauto_upper_memspc = ++ mem_resource_inuse->end + 1; ++ goto retry; ++ } ++ } ++ DBG(" unavailable -- skipping, value %x size %x\n", ++ bar_value, bar_size); ++ continue; ++ } ++ ++#if 1 ++ /* Write it out and update our limit */ ++ early_write_config_dword(hose, top_bus, current_bus, pci_devfn, ++ bar, bar_value); ++#endif ++ ++ *lower_limit = bar_value + bar_size; ++ ++ /* ++ * If we are a 64-bit decoder then increment to the ++ * upper 32 bits of the bar and force it to locate ++ * in the lower 4GB of memory. ++ */ ++ if (found_mem64) { ++ bar += 4; ++ early_write_config_dword(hose, top_bus, ++ current_bus, ++ pci_devfn, ++ bar, ++ 0x00000000); ++ } ++ ++ DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size); ++ ++ bar_nr++; ++ } ++ ++} ++ ++static void __init ++pciauto_prescan_setup_bridge(struct pci_channel *hose, ++ int top_bus, ++ int current_bus, ++ int pci_devfn, ++ int sub_bus) ++{ ++ /* Configure bus number registers */ ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_PRIMARY_BUS, current_bus); ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_SECONDARY_BUS, sub_bus + 1); ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_SUBORDINATE_BUS, 0xff); ++ ++ /* Align memory and I/O to 1MB and 4KB boundaries. */ ++ pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) ++ & ~(0x100000 - 1); ++ pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) ++ & ~(0x1000 - 1); ++ ++ /* Set base (lower limit) of address range behind bridge. */ ++ early_write_config_word(hose, top_bus, current_bus, pci_devfn, ++ PCI_MEMORY_BASE, pciauto_lower_memspc >> 16); ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_IO_BASE, (pciauto_lower_iospc & 0x0000f000) >> 8); ++ early_write_config_word(hose, top_bus, current_bus, pci_devfn, ++ PCI_IO_BASE_UPPER16, pciauto_lower_iospc >> 16); ++ ++ /* We don't support prefetchable memory for now, so disable */ ++ early_write_config_word(hose, top_bus, current_bus, pci_devfn, ++ PCI_PREF_MEMORY_BASE, 0); ++ early_write_config_word(hose, top_bus, current_bus, pci_devfn, ++ PCI_PREF_MEMORY_LIMIT, 0); ++} ++ ++static void __init ++pciauto_postscan_setup_bridge(struct pci_channel *hose, ++ int top_bus, ++ int current_bus, ++ int pci_devfn, ++ int sub_bus) ++{ ++ u32 temp; ++ ++ /* ++ * [jsun] we always bump up baselines a little, so that if there ++ * nothing behind P2P bridge, we don't wind up overlapping IO/MEM ++ * spaces. ++ */ ++ pciauto_lower_memspc += 1; ++ pciauto_lower_iospc += 1; ++ ++ /* Configure bus number registers */ ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_SUBORDINATE_BUS, sub_bus); ++ ++ /* Set upper limit of address range behind bridge. */ ++ early_write_config_word(hose, top_bus, current_bus, pci_devfn, ++ PCI_MEMORY_LIMIT, pciauto_lower_memspc >> 16); ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_IO_LIMIT, (pciauto_lower_iospc & 0x0000f000) >> 8); ++ early_write_config_word(hose, top_bus, current_bus, pci_devfn, ++ PCI_IO_LIMIT_UPPER16, pciauto_lower_iospc >> 16); ++ ++ /* Align memory and I/O to 1MB and 4KB boundaries. */ ++ pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) ++ & ~(0x100000 - 1); ++ pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) ++ & ~(0x1000 - 1); ++ ++ /* Enable memory and I/O accesses, enable bus master */ ++ early_read_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_COMMAND, &temp); ++ early_write_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY ++ | PCI_COMMAND_MASTER); ++} ++ ++static void __init ++pciauto_prescan_setup_cardbus_bridge(struct pci_channel *hose, ++ int top_bus, ++ int current_bus, ++ int pci_devfn, ++ int sub_bus) ++{ ++ /* Configure bus number registers */ ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_PRIMARY_BUS, current_bus); ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_SECONDARY_BUS, sub_bus + 1); ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_SUBORDINATE_BUS, 0xff); ++ ++ /* Align memory and I/O to 4KB and 4 byte boundaries. */ ++ pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) ++ & ~(0x1000 - 1); ++ pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1)) ++ & ~(0x4 - 1); ++ ++ early_write_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_CB_MEMORY_BASE_0, pciauto_lower_memspc); ++ early_write_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_CB_IO_BASE_0, pciauto_lower_iospc); ++} ++ ++static void __init ++pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, ++ int top_bus, ++ int current_bus, ++ int pci_devfn, ++ int sub_bus) ++{ ++ u32 temp; ++ ++#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) ++ /* ++ * [jsun] we always bump up baselines a little, so that if there ++ * nothing behind P2P bridge, we don't wind up overlapping IO/MEM ++ * spaces. ++ */ ++ pciauto_lower_memspc += 1; ++ pciauto_lower_iospc += 1; ++#endif ++ ++ /* ++ * Configure subordinate bus number. The PCI subsystem ++ * bus scan will renumber buses (reserving three additional ++ * for this PCI<->CardBus bridge for the case where a CardBus ++ * adapter contains a P2P or CB2CB bridge. ++ */ ++ ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_SUBORDINATE_BUS, sub_bus); ++ ++ /* ++ * Reserve an additional 4MB for mem space and 16KB for ++ * I/O space. This should cover any additional space ++ * requirement of unusual CardBus devices with ++ * additional bridges that can consume more address space. ++ * ++ * Although pcmcia-cs currently will reprogram bridge ++ * windows, the goal is to add an option to leave them ++ * alone and use the bridge window ranges as the regions ++ * that are searched for free resources upon hot-insertion ++ * of a device. This will allow a PCI<->CardBus bridge ++ * configured by this routine to happily live behind a ++ * P2P bridge in a system. ++ */ ++#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) ++ pciauto_lower_memspc += 0x00400000; ++ pciauto_lower_iospc += 0x00004000; ++#endif ++ ++ /* Align memory and I/O to 4KB and 4 byte boundaries. */ ++ pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) ++ & ~(0x1000 - 1); ++ pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1)) ++ & ~(0x4 - 1); ++ /* Set up memory and I/O filter limits, assume 32-bit I/O space */ ++ early_write_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_CB_MEMORY_LIMIT_0, pciauto_lower_memspc - 1); ++ early_write_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_CB_IO_LIMIT_0, pciauto_lower_iospc - 1); ++ ++ /* Enable memory and I/O accesses, enable bus master */ ++ early_read_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_COMMAND, &temp); ++ early_write_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | ++ PCI_COMMAND_MASTER); ++} ++ ++#define PCIAUTO_IDE_MODE_MASK 0x05 ++ ++static int __init ++pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) ++{ ++ int sub_bus; ++ u32 pci_devfn, pci_class, cmdstat, found_multi=0; ++ unsigned short vid, did; ++ unsigned char header_type; ++ int devfn_start = 0; ++ int devfn_stop = 0xff; ++ ++ sub_bus = current_bus; ++ ++ if (hose->first_devfn) ++ devfn_start = hose->first_devfn; ++ if (hose->last_devfn) ++ devfn_stop = hose->last_devfn; ++ ++ for (pci_devfn=devfn_start; pci_devfn> 16, vid, did); ++ if (pci_class & 0xff) ++ DBG(" (rev %.2x)", pci_class & 0xff); ++ DBG("\n"); ++ ++ if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) { ++ DBG(" Bridge: primary=%.2x, secondary=%.2x\n", ++ current_bus, sub_bus + 1); ++#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) ++ pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1); ++#endif ++ pciauto_prescan_setup_bridge(hose, top_bus, current_bus, ++ pci_devfn, sub_bus); ++ DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", ++ sub_bus + 1, ++ pciauto_lower_iospc, pciauto_lower_memspc); ++ sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); ++ DBG("Back to bus %.2x\n", current_bus); ++ pciauto_postscan_setup_bridge(hose, top_bus, current_bus, ++ pci_devfn, sub_bus); ++ continue; ++ } else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) { ++ DBG(" CARDBUS Bridge: primary=%.2x, secondary=%.2x\n", ++ current_bus, sub_bus + 1); ++ DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn)); ++ /* Place CardBus Socket/ExCA registers */ ++ pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0); ++ ++ pciauto_prescan_setup_cardbus_bridge(hose, top_bus, ++ current_bus, pci_devfn, sub_bus); ++ ++ DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", ++ sub_bus + 1, ++ pciauto_lower_iospc, pciauto_lower_memspc); ++ sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); ++ DBG("Back to bus %.2x, sub_bus is %x\n", current_bus, sub_bus); ++ pciauto_postscan_setup_cardbus_bridge(hose, top_bus, ++ current_bus, pci_devfn, sub_bus); ++ continue; ++ } else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) { ++ ++ unsigned char prg_iface; ++ ++ early_read_config_byte(hose, top_bus, current_bus, ++ pci_devfn, PCI_CLASS_PROG, &prg_iface); ++ if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { ++ DBG("Skipping legacy mode IDE controller\n"); ++ continue; ++ } ++ } ++ ++ /* ++ * Found a peripheral, enable some standard ++ * settings ++ */ ++ early_read_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_COMMAND, &cmdstat); ++ early_write_config_dword(hose, top_bus, current_bus, pci_devfn, ++ PCI_COMMAND, cmdstat | PCI_COMMAND_IO | ++ PCI_COMMAND_MEMORY | ++ PCI_COMMAND_MASTER); ++#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) ++ early_write_config_byte(hose, top_bus, current_bus, pci_devfn, ++ PCI_LATENCY_TIMER, 0x80); ++#endif ++ ++ /* Allocate PCI I/O and/or memory space */ ++ pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5); ++ } ++ return sub_bus; ++} ++ ++int __init ++pciauto_assign_resources(int busno, struct pci_channel *hose) ++{ ++ /* setup resource limits */ ++ io_resource_inuse = hose->io_resource; ++ mem_resource_inuse = hose->mem_resource; ++ ++ pciauto_lower_iospc = io_resource_inuse->start; ++ pciauto_upper_iospc = io_resource_inuse->end + 1; ++ pciauto_lower_memspc = mem_resource_inuse->start; ++ pciauto_upper_memspc = mem_resource_inuse->end + 1; ++ DBG("Autoconfig PCI channel 0x%p\n", hose); ++ DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n", ++ busno, pciauto_lower_iospc, pciauto_upper_iospc, ++ pciauto_lower_memspc, pciauto_upper_memspc); ++ ++ return pciauto_bus_scan(hose, busno, busno); ++} +diff --git a/arch/nios2nommu/drivers/pci/pci.c b/arch/nios2nommu/drivers/pci/pci.c +new file mode 100644 +index 0000000..83436df +--- /dev/null ++++ b/arch/nios2nommu/drivers/pci/pci.c +@@ -0,0 +1,151 @@ ++/* arch/sh/kernel/pci.c ++ * $Id: pci.c,v 1.2 2007/01/25 01:26:48 gerg Exp $ ++ * ++ * Copyright (c) 2002 M. R. Brown ++ * ++ * ++ * These functions are collected here to reduce duplication of common ++ * code amongst the many platform-specific PCI support code files. ++ * ++ * These routines require the following board-specific routines: ++ * void pcibios_fixup_irqs(); ++ * ++ * See include/asm-sh/pci.h for more information. ++ */ ++ ++#include ++#include ++#include ++ ++static int __init pcibios_init(void) ++{ ++ struct pci_channel *p; ++ struct pci_bus *bus; ++ int busno; ++ ++#if 1 ++ /* assign resources */ ++ busno = 0; ++ for (p = board_pci_channels; p->pci_ops != NULL; p++) { ++ busno = pciauto_assign_resources(busno, p) + 1; ++ } ++#endif ++ ++ /* scan the buses */ ++ busno = 0; ++ for (p= board_pci_channels; p->pci_ops != NULL; p++) { ++ bus = pci_scan_bus(busno, p->pci_ops, p); ++ busno = bus->subordinate+1; ++ } ++ ++ /* board-specific fixups */ ++ pcibios_fixup_irqs(); ++ ++ return 0; ++} ++ ++subsys_initcall(pcibios_init); ++ ++void ++pcibios_update_resource(struct pci_dev *dev, struct resource *root, ++ struct resource *res, int resource) ++{ ++ u32 new, check; ++ int reg; ++ ++ new = res->start | (res->flags & PCI_REGION_FLAG_MASK); ++ if (resource < 6) { ++ reg = PCI_BASE_ADDRESS_0 + 4*resource; ++ } else if (resource == PCI_ROM_RESOURCE) { ++ res->flags |= IORESOURCE_ROM_ENABLE; ++ new |= PCI_ROM_ADDRESS_ENABLE; ++ reg = dev->rom_base_reg; ++ } else { ++ /* Somebody might have asked allocation of a non-standard resource */ ++ return; ++ } ++ ++ pci_write_config_dword(dev, reg, new); ++ pci_read_config_dword(dev, reg, &check); ++ if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { ++ printk(KERN_ERR "PCI: Error while updating region " ++ "%s/%d (%08x != %08x)\n", pci_name(dev), resource, ++ new, check); ++ } ++} ++ ++/* ++ * We need to avoid collisions with `mirrored' VGA ports ++ * and other strange ISA hardware, so we always want the ++ * addresses to be allocated in the 0x000-0x0ff region ++ * modulo 0x400. ++ */ ++void pcibios_align_resource(void *data, struct resource *res, ++ resource_size_t size, resource_size_t align) ++{ ++ if (res->flags & IORESOURCE_IO) { ++ unsigned long start = res->start; ++ ++ if (start & 0x300) { ++ start = (start + 0x3ff) & ~0x3ff; ++ res->start = start; ++ } ++ } ++} ++ ++int pcibios_enable_device(struct pci_dev *dev, int mask) ++{ ++ u16 cmd, old_cmd; ++ int idx; ++ struct resource *r; ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ old_cmd = cmd; ++ for(idx=0; idx<6; idx++) { ++ if (!(mask & (1 << idx))) ++ continue; ++ r = &dev->resource[idx]; ++ if (!r->start && r->end) { ++ printk(KERN_ERR "PCI: Device %s not available because " ++ "of resource collisions\n", pci_name(dev)); ++ return -EINVAL; ++ } ++ if (r->flags & IORESOURCE_IO) ++ cmd |= PCI_COMMAND_IO; ++ if (r->flags & IORESOURCE_MEM) ++ cmd |= PCI_COMMAND_MEMORY; ++ } ++ if (dev->resource[PCI_ROM_RESOURCE].start) ++ cmd |= PCI_COMMAND_MEMORY; ++ if (cmd != old_cmd) { ++ printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", ++ pci_name(dev), old_cmd, cmd); ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ } ++ return 0; ++} ++ ++/* ++ * If we set up a device for bus mastering, we need to check and set ++ * the latency timer as it may not be properly set. ++ */ ++unsigned int pcibios_max_latency = 255; ++ ++void pcibios_set_master(struct pci_dev *dev) ++{ ++ u8 lat; ++ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); ++ if (lat < 16) ++ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; ++ else if (lat > pcibios_max_latency) ++ lat = pcibios_max_latency; ++ else ++ return; ++ printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); ++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); ++} ++ ++void __init pcibios_update_irq(struct pci_dev *dev, int irq) ++{ ++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); ++} +diff --git a/arch/nios2nommu/drivers/pci/setup-irq.c b/arch/nios2nommu/drivers/pci/setup-irq.c +new file mode 100644 +index 0000000..0fa8f98 +--- /dev/null ++++ b/arch/nios2nommu/drivers/pci/setup-irq.c +@@ -0,0 +1 @@ ++#include "../../../../drivers/pci/setup-irq.c" +diff --git a/arch/nios2nommu/drivers/spi.c b/arch/nios2nommu/drivers/spi.c +new file mode 100644 +index 0000000..72a2519 +--- /dev/null ++++ b/arch/nios2nommu/drivers/spi.c +@@ -0,0 +1,315 @@ ++#ifdef MODULE ++#include ++#include ++#else ++#define MOD_INC_USE_COUNT ++#define MOD_DEC_USE_COUNT ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++#include ++ ++#if !defined(SEEK_SET) ++#define SEEK_SET 0 ++#endif ++ ++ ++static unsigned int spi_major = 60; /* a local major, can be overwritten */ ++static int openflag = 0; ++static np_spi * const spi_ptr = na_spi; ++ ++ /*******************************/ ++ /* SPI data transfer routines. */ ++ /*******************************/ ++ ++#define SPI_XMIT_READY np_spistatus_trdy_mask ++#define SPI_RECV_READY np_spistatus_rrdy_mask ++ ++#define SPI_BUSYPOLL_TIMEOUT 1000 ++ ++// returns -1 if there is no data present, otherwise returns ++// the value ++inline int SPI_Recv_Byte(char *pdata ) ++{ ++ if (spi_ptr->np_spistatus & SPI_RECV_READY){ ++ *pdata = spi_ptr->np_spirxdata & 0xff; ++ return 0; ++ } ++ return -1; ++} ++ ++ ++// Sends the 16 bit address+data ++inline int SPI_Send_Byte( unsigned char address, char data ) ++{ ++ u16 value = ((address & 0xFF) << 8) | (data & 0xFF); ++ ++ if ( spi_ptr->np_spistatus & SPI_XMIT_READY ) { ++ spi_ptr->np_spitxdata = value; ++ return 0; ++ } ++ ++ return -1; ++} ++ ++ ++ ++ /*************************/ ++ /* SPI Driver functions. */ ++ /*************************/ ++ ++int spi_reset( void ) ++{ ++ // Nothing to do: The Nios does _not_ ++ // support burst xfers. Chip Enables ++ // (Selects) are inactive after each xfer. ++ return 0; ++} ++ ++ ++/***************************************************/ ++/* The SPI Write routine. The first 16 bits are */ ++/* the device register, and the rest of the buffer */ ++/* is data. */ ++/***************************************************/ ++ ++ssize_t spi_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) ++{ ++ int i; ++ unsigned char addr; ++ int timeout; ++ char temp; ++ ++ if ( count < 3 ) ++ return -EINVAL; /* Address is 2 bytes: Must have _something_ to send */ ++ ++ addr = buf[0]; /* chip register address. */ ++ spi_ptr->np_spistatus=0; ++ ++ for ( i = sizeof(u16); inp_spistatus=0; ++ ++ /* empty the np_spirxdata register */ ++ SPI_Recv_Byte(&temp); ++ ++ for ( i = sizeof(u16); i 1 ) ++ { ++ errno = -EINVAL; ++ return -1; ++ } ++ } ++ } ++#endif ++ spi_ptr->np_spislaveselect = offset; ++ return 0; ++} ++ ++int spi_open(struct inode *inode, struct file *filp) ++{ ++ preempt_disable(); ++ if (openflag) { ++ preempt_enable(); ++ return -EBUSY; ++ } ++ ++ MOD_INC_USE_COUNT; ++ openflag = 1; ++ preempt_enable(); ++ ++ return 0; ++} ++ ++int spi_release(struct inode *inode, struct file *filp) ++{ ++ openflag = 0; ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++ ++/* static struct file_operations spi_fops */ ++ ++static struct file_operations spi_fops = { ++ llseek: spi_lseek, /* Set chip-select line. The offset is used as an address. */ ++ read: spi_read, ++ write: spi_write, ++ open: spi_open, ++ release: spi_release, ++}; ++ ++ ++int register_NIOS_SPI( void ) ++{ ++ int result = register_chrdev( spi_major, "spi", &spi_fops ); ++ if ( result < 0 ) ++ { ++ printk( "SPI: unable to get major %d for SPI bus \n", spi_major ); ++ return result; ++ }/*end-if*/ ++ ++ if ( spi_major == 0 ) ++ spi_major = result; /* here we got our major dynamically */ ++ ++ /* reserve our port, but check first if free */ ++ if ( check_region( (unsigned int)na_spi, sizeof(np_spi) ) ) ++ { ++ printk( "SPI: port at adr 0x%08x already occupied\n", (unsigned int)na_spi ); ++ unregister_chrdev( spi_major, "spi" ); ++ ++ return result; ++ }/*end-if*/ ++ ++ return 0; ++} ++ ++void unregister_NIOS_SPI( void ) ++{ ++ if ( spi_major > 0 ) ++ unregister_chrdev( spi_major, "spi" ); ++ ++ release_region( (unsigned int)na_spi, sizeof(np_spi) ); ++} ++ ++ ++#ifdef MODULE ++void cleanup_module( void ) ++{ ++ unregister_NIOS_SPI(); ++} ++ ++ ++ ++int init_module( void ) ++{ ++ return register_NIOS_SPI(); ++} ++#endif ++ ++ ++static int __init nios_spi_init(void) ++{ ++ printk("SPI: Nios SPI bus device version 0.1\n"); ++ return register_NIOS_SPI(); ++// if ( register_NIOS_SPI() ) ++// printk("*** Cannot initialize SPI device.\n"); ++} ++ ++__initcall(nios_spi_init); +diff --git a/arch/nios2nommu/kernel/ChangeLog b/arch/nios2nommu/kernel/ChangeLog +new file mode 100644 +index 0000000..7f1449d +--- /dev/null ++++ b/arch/nios2nommu/kernel/ChangeLog +@@ -0,0 +1,27 @@ ++2004-06-17 Ken Hill ++ ++ * process.c (machine_restart): Add code to disable interrups and ++ jump to the cpu reset address. ++ (machine_halt): Add code to disable interrupts and spinlock. ++ (machine_power_off): Add code to disable interrupts and spinlock. ++ ++2004-06-16 Ken Hill ++ ++ * nios2_ksyms.c: Remove hard_reset_now. ++ ++2004-06-10 Ken Hill ++ ++ * nios2_ksyms.c: Add EXPORT_SYMBOL_NOVERS(__down) to solve insmod for ++ some modules. ++ ++2004-06-02 Ken Hill ++ ++ * entry.S (software_exception): Add a safety catch for old applications that may ++ have been linked against an older library. This does not add any overhead to ++ system call processing. ++ ++2004-04-15 Ken Hill ++ ++ * setup.c (setup_arch): Remove ROMFS message from debug printk kernel message. ++ Add copyright and GNU license notice. ++ +diff --git a/arch/nios2nommu/kernel/Makefile b/arch/nios2nommu/kernel/Makefile +new file mode 100644 +index 0000000..a056ff1 +--- /dev/null ++++ b/arch/nios2nommu/kernel/Makefile +@@ -0,0 +1,22 @@ ++# ++# Makefile for the linux kernel. ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definitions are now in the main makefile... ++ ++extra-y := head.o init_task.o vmlinux.lds ++ ++obj-y := entry.o traps.o irq.o syscalltable.o \ ++ process.o signal.o setup.o sys_nios2.o \ ++ semaphore.o io.o usb.o\ ++ time.o ptrace.o start.o nios2_ksyms.o ++ ++obj-$(CONFIG_MODULES) += module.o ++obj-$(CONFIG_CONSOLE) += console.o ++obj-$(CONFIG_PIO_DEVICES) += pio.o ++obj-$(CONFIG_AVALON_DMA) += dma.o ++ ++ +diff --git a/arch/nios2nommu/kernel/asm-offsets.c b/arch/nios2nommu/kernel/asm-offsets.c +new file mode 100644 +index 0000000..4877eba +--- /dev/null ++++ b/arch/nios2nommu/kernel/asm-offsets.c +@@ -0,0 +1,201 @@ ++/* ++ * This program is used to generate definitions needed by ++ * assembly language modules. ++ * ++ * We use the technique used in the OSF Mach kernel code: ++ * generate asm statements containing #defines, ++ * compile this file to assembler, and then extract the ++ * #defines from the assembly-language output. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEFINE(sym, val) \ ++ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) ++ ++#define BLANK() asm volatile("\n->" : : ) ++ ++int main(void) ++{ ++ ++ /* offsets into the task struct */ ++ DEFINE(TASK_STATE, offsetof(struct task_struct, state)); ++ DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); ++ DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); ++ DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); ++ DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); ++ DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack)); ++ DEFINE(TASK_MM, offsetof(struct task_struct, mm)); ++ DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); ++ ++ /* offsets into the kernel_stat struct */ ++ DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); ++ ++ /* offsets into the irq_cpustat_t struct */ ++ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); ++ ++ /* offsets into the irq_node struct */ ++ DEFINE(IRQ_HANDLER, offsetof(struct irq_hand, handler)); ++ DEFINE(IRQ_FLAGS, offsetof(struct irq_hand, flags)); ++ DEFINE(IRQ_DEV_ID, offsetof(struct irq_hand, dev_id)); ++ DEFINE(IRQ_DEVNAME, offsetof(struct irq_hand, devname)); ++ ++ /* offsets into the thread struct */ ++ DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); ++ DEFINE(THREAD_KPSR, offsetof(struct thread_struct, kpsr)); ++ DEFINE(THREAD_KESR, offsetof(struct thread_struct, kesr)); ++ DEFINE(THREAD_FLAGS, offsetof(struct thread_struct, flags)); ++ ++ /* offsets into the pt_regs */ ++ DEFINE(PT_ORIG_R2, offsetof(struct pt_regs, orig_r2)); ++ DEFINE(PT_R1, offsetof(struct pt_regs, r1)); ++ DEFINE(PT_R2, offsetof(struct pt_regs, r2)); ++ DEFINE(PT_R3, offsetof(struct pt_regs, r3)); ++ DEFINE(PT_R4, offsetof(struct pt_regs, r4)); ++ DEFINE(PT_R5, offsetof(struct pt_regs, r5)); ++ DEFINE(PT_R6, offsetof(struct pt_regs, r6)); ++ DEFINE(PT_R7, offsetof(struct pt_regs, r7)); ++ DEFINE(PT_R8, offsetof(struct pt_regs, r8)); ++ DEFINE(PT_R9, offsetof(struct pt_regs, r9)); ++ DEFINE(PT_R10, offsetof(struct pt_regs, r10)); ++ DEFINE(PT_R11, offsetof(struct pt_regs, r11)); ++ DEFINE(PT_R12, offsetof(struct pt_regs, r12)); ++ DEFINE(PT_R13, offsetof(struct pt_regs, r13)); ++ DEFINE(PT_R14, offsetof(struct pt_regs, r14)); ++ DEFINE(PT_R15, offsetof(struct pt_regs, r15)); ++ DEFINE(PT_EA, offsetof(struct pt_regs, ea)); ++ DEFINE(PT_RA, offsetof(struct pt_regs, ra)); ++ DEFINE(PT_FP, offsetof(struct pt_regs, fp)); ++ DEFINE(PT_SP, offsetof(struct pt_regs, sp)); ++ DEFINE(PT_GP, offsetof(struct pt_regs, gp)); ++ DEFINE(PT_ESTATUS, offsetof(struct pt_regs, estatus)); ++ DEFINE(PT_STATUS_EXTENSION, offsetof(struct pt_regs, status_extension)); ++ DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); ++ ++ /* offsets into the switch_stack */ ++ DEFINE(SW_R16, offsetof(struct switch_stack, r16)); ++ DEFINE(SW_R17, offsetof(struct switch_stack, r17)); ++ DEFINE(SW_R18, offsetof(struct switch_stack, r18)); ++ DEFINE(SW_R19, offsetof(struct switch_stack, r19)); ++ DEFINE(SW_R20, offsetof(struct switch_stack, r20)); ++ DEFINE(SW_R21, offsetof(struct switch_stack, r21)); ++ DEFINE(SW_R22, offsetof(struct switch_stack, r22)); ++ DEFINE(SW_R23, offsetof(struct switch_stack, r23)); ++ DEFINE(SW_FP, offsetof(struct switch_stack, fp)); ++ DEFINE(SW_GP, offsetof(struct switch_stack, gp)); ++ DEFINE(SW_RA, offsetof(struct switch_stack, ra)); ++ DEFINE(SWITCH_STACK_SIZE, sizeof(struct switch_stack)); ++ ++ DEFINE(PS_S_ASM, PS_S); ++ ++ DEFINE(NIOS2_STATUS_PIE_MSK_ASM, NIOS2_STATUS_PIE_MSK); ++ DEFINE(NIOS2_STATUS_PIE_OFST_ASM, NIOS2_STATUS_PIE_OFST); ++ DEFINE(NIOS2_STATUS_U_MSK_ASM, NIOS2_STATUS_U_MSK); ++ DEFINE(NIOS2_STATUS_U_OFST_ASM, NIOS2_STATUS_U_OFST); ++ ++ /* offsets into the kernel_stat struct */ ++ DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); ++ ++ /* Offsets in thread_info structure, used in assembly code */ ++ DEFINE(TI_TASK, offsetof(struct thread_info, task)); ++ DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); ++ DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); ++ DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); ++ DEFINE(TI_PREEMPT_COUNT, offsetof(struct thread_info, preempt_count)); ++ ++ DEFINE(PREEMPT_ACTIVE_ASM, PREEMPT_ACTIVE); ++ ++ DEFINE(THREAD_SIZE_ASM, THREAD_SIZE); ++ ++ DEFINE(TIF_SYSCALL_TRACE_ASM, TIF_SYSCALL_TRACE); ++ DEFINE(TIF_NOTIFY_RESUME_ASM, TIF_NOTIFY_RESUME); ++ DEFINE(TIF_SIGPENDING_ASM, TIF_SIGPENDING); ++ DEFINE(TIF_NEED_RESCHED_ASM, TIF_NEED_RESCHED); ++ DEFINE(TIF_POLLING_NRFLAG_ASM, TIF_POLLING_NRFLAG); ++ ++ DEFINE(_TIF_SYSCALL_TRACE_ASM, _TIF_SYSCALL_TRACE); ++ DEFINE(_TIF_NOTIFY_RESUME_ASM, _TIF_NOTIFY_RESUME); ++ DEFINE(_TIF_SIGPENDING_ASM, _TIF_SIGPENDING); ++ DEFINE(_TIF_NEED_RESCHED_ASM, _TIF_NEED_RESCHED); ++ DEFINE(_TIF_POLLING_NRFLAG_ASM, _TIF_POLLING_NRFLAG); ++ ++ DEFINE(_TIF_WORK_MASK_ASM, _TIF_WORK_MASK); ++ ++#if defined(na_flash_kernel) && defined(na_flash_kernel_end) ++ /* the flash chip */ ++ DEFINE(NIOS_FLASH_START, na_flash_kernel); ++ DEFINE(NIOS_FLASH_END, na_flash_kernel_end); ++ ++ /* the kernel placement in the flash*/ ++ DEFINE(KERNEL_FLASH_START, na_flash_kernel); ++ DEFINE(KERNEL_FLASH_LEN, 0x200000); ++ ++ /* the romdisk placement in the flash */ ++ DEFINE(LINUX_ROMFS_START, na_flash_kernel+0x200000); ++ DEFINE(LINUX_ROMFS_END, na_flash_kernel_end); ++#else ++#error Sorry,you dont have na_flash_kernel or na_flash_kernel_end defined in the core. ++#endif ++ ++#if defined(nasys_program_mem) && defined(nasys_program_mem_end) ++ /* the sdram */ ++ DEFINE(LINUX_SDRAM_START, nasys_program_mem); ++ DEFINE(LINUX_SDRAM_END, nasys_program_mem_end); ++#else ++#error Sorry,you dont have nasys_program_mem or nasys_program_mem_end defined in the core. ++#endif ++ ++ DEFINE(NIOS2_ICACHE_SIZE, nasys_icache_size); ++ DEFINE(NIOS2_ICACHE_LINE_SIZE, nasys_icache_line_size); ++ DEFINE(NIOS2_DCACHE_SIZE, nasys_dcache_size); ++ DEFINE(NIOS2_DCACHE_LINE_SIZE, nasys_dcache_line_size); ++ ++#if defined(na_enet) ++ DEFINE(NA_ENET_ASM, na_enet); ++#endif ++ ++#if defined(na_enet_reset) ++ DEFINE(NA_ENET_RESET_ASM, na_enet_reset); ++#endif ++ ++#if defined(na_enet_reset_n) ++ DEFINE(NA_ENET_RESET_N_ASM, na_enet_reset_n); ++#endif ++ ++#if defined(na_ide_interface) ++ DEFINE(NA_IDE_INTERFACE_ASM, na_ide_interface); ++#endif ++ ++#if defined(na_timer0) ++ DEFINE(NA_TIMER0_ASM, na_timer0); ++ DEFINE(NP_TIMERCONTROL_ASM, offsetof(np_timer, np_timercontrol)); ++ DEFINE(NP_TIMERSTATUS_ASM, offsetof(np_timer, np_timerstatus)); ++#endif ++ ++#if defined(na_uart0) ++ DEFINE(NA_UART0_ASM, na_uart0); ++ DEFINE(NP_UARTCONTROL_ASM, offsetof(np_uart, np_uartcontrol)); ++ DEFINE(NP_UARTSTATUS_ASM, offsetof(np_uart, np_uartstatus)); ++#endif ++ ++#if defined(na_uart1) ++ DEFINE(NA_UART1_ASM, na_uart1); ++#endif ++ ++#if defined(na_uart2) ++ DEFINE(NA_UART2_ASM, na_uart2); ++#endif ++ ++#if defined(na_uart3) ++ DEFINE(NA_UART3_ASM, na_uart3); ++#endif ++ ++ return 0; ++} +diff --git a/arch/nios2nommu/kernel/dma.c b/arch/nios2nommu/kernel/dma.c +new file mode 100644 +index 0000000..f23323b +--- /dev/null ++++ b/arch/nios2nommu/kernel/dma.c +@@ -0,0 +1,342 @@ ++/* ++ * arch/nios2nommu/kernel/dma.c ++ * ++ * Copyright (C) 2005 Microtronix Datacom Ltd ++ * ++ * PC like DMA API for Nios's DMAC. ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Written by Wentao Xu ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* nios2 dma controller register map */ ++#define REG_DMA_STATUS 0 ++#define REG_DMA_READADDR 4 ++#define REG_DMA_WRITEADDR 8 ++#define REG_DMA_LENGTH 12 ++#define REG_DMA_CONTROL 24 ++ ++/* status register bits definition */ ++#define ST_DONE 0x01 ++#define ST_BUSY 0x02 ++#define ST_REOP 0x04 ++#define ST_WROP 0x08 ++#define ST_LEN 0x10 ++ ++/* control register bits definition */ ++#define CT_BYTE 0x01 ++#define CT_HW 0x02 ++#define CT_WORD 0x04 ++#define CT_GO 0x08 ++#define CT_IEEN 0x10 ++#define CT_REEN 0x20 ++#define CT_WEEN 0x40 ++#define CT_LEEN 0x80 ++#define CT_RCON 0x100 ++#define CT_WCON 0x200 ++#define CT_DOUBLE 0x400 ++#define CT_QUAD 0x800 ++ ++struct dma_channel { ++ unsigned int addr; /* control address */ ++ unsigned int irq; /* interrupt number */ ++ atomic_t idle; ++ unsigned int mode; /* dma mode: width, stream etc */ ++ int (*handler)(void*, int ); ++ void* user; ++ ++ char id[16]; ++ char dev_id[16]; ++}; ++static struct dma_channel dma_channels[]={ ++#ifdef na_dma_0 ++ { ++ .addr = na_dma_0, ++ .irq = na_dma_0_irq, ++ .idle = ATOMIC_INIT(1), ++ }, ++#endif ++#ifdef na_dma_1 ++ { ++ .addr = na_dma_1, ++ .irq = na_dma_1_irq, ++ .idle = ATOMIC_INIT(1), ++ }, ++#endif ++}; ++#define MAX_DMA_CHANNELS sizeof(dma_channels)/sizeof(struct dma_channel) ++ ++void enable_dma(unsigned int dmanr) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ unsigned int ctl = dma_channels[dmanr].mode; ++ ctl |= CT_GO | CT_IEEN; ++ outl(ctl, dma_channels[dmanr].addr+REG_DMA_CONTROL); ++ } ++} ++ ++void disable_dma(unsigned int dmanr) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ unsigned int ctl = dma_channels[dmanr].mode; ++ ctl &= ~(CT_GO | CT_IEEN); ++ outl(ctl, dma_channels[dmanr].addr+REG_DMA_CONTROL); ++ } ++} ++ ++void set_dma_count(unsigned int dmanr, unsigned int count) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ dma_channels[dmanr].mode |= CT_LEEN; ++ outl(count, dma_channels[dmanr].addr+REG_DMA_LENGTH); ++ } ++} ++ ++int get_dma_residue(unsigned int dmanr) ++{ ++ int result =-1; ++ if (dmanr < MAX_DMA_CHANNELS) { ++ result = inl(dma_channels[dmanr].addr+REG_DMA_LENGTH); ++ } ++ return result; ++} ++ ++int request_dma(unsigned int chan, const char *dev_id) ++{ ++ struct dma_channel *channel; ++ ++ if ( chan >= MAX_DMA_CHANNELS) { ++ return -EINVAL; ++ } ++ ++ channel = &dma_channels[chan]; ++ ++ if (!atomic_dec_and_test(&channel->idle)) { ++ return -EBUSY; ++ } ++ ++ strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); ++ channel->handler=NULL; ++ channel->user=NULL; ++ channel->mode =0; ++ ++ return 0; ++} ++ ++void free_dma(unsigned int chan) ++{ ++ if ( chan < MAX_DMA_CHANNELS) { ++ dma_channels[chan].handler=NULL; ++ dma_channels[chan].user=NULL; ++ atomic_set(&dma_channels[chan].idle, 1); ++ } ++} ++ ++int nios2_request_dma(const char *dev_id) ++{ ++ int chann; ++ ++ for ( chann=0; chann < MAX_DMA_CHANNELS; chann++) { ++ if (request_dma(chann, dev_id)==0) ++ return chann; ++ } ++ ++ return -EINVAL; ++} ++void nios2_set_dma_handler(unsigned int dmanr, int (*handler)(void*, int), void* user) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ dma_channels[dmanr].handler=handler; ++ dma_channels[dmanr].user=user; ++ } ++} ++#define NIOS2_DMA_WIDTH_MASK (CT_BYTE | CT_HW | CT_WORD | CT_DOUBLE | CT_QUAD) ++#define NIOS2_MODE_MASK (NIOS2_DMA_WIDTH_MASK | CT_REEN | CT_WEEN | CT_LEEN | CT_RCON | CT_WCON) ++void nios2_set_dma_data_width(unsigned int dmanr, unsigned int width) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ dma_channels[dmanr].mode &= ~NIOS2_DMA_WIDTH_MASK; ++ switch (width) { ++ case 1: ++ dma_channels[dmanr].mode |= CT_BYTE; ++ break; ++ case 2: ++ dma_channels[dmanr].mode |= CT_HW; ++ break; ++ case 8: ++ dma_channels[dmanr].mode |= CT_DOUBLE; ++ break; ++ case 16: ++ dma_channels[dmanr].mode |= CT_QUAD; ++ break; ++ case 4: ++ default: ++ dma_channels[dmanr].mode |= CT_WORD; ++ break; ++ } ++ } ++} ++ ++void nios2_set_dma_rcon(unsigned int dmanr,unsigned int set) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ dma_channels[dmanr].mode &= ~(CT_REEN | CT_RCON); ++ if (set) ++ dma_channels[dmanr].mode |= (CT_REEN | CT_RCON); ++ } ++} ++void nios2_set_dma_wcon(unsigned int dmanr,unsigned int set) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ dma_channels[dmanr].mode &= ~(CT_WEEN | CT_WCON); ++ if (set) ++ dma_channels[dmanr].mode |= (CT_WEEN | CT_WCON); ++ } ++} ++void nios2_set_dma_mode(unsigned int dmanr, unsigned int mode) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ /* set_dma_mode is only allowed to change the bus width, ++ stream setting, etc. ++ */ ++ mode &= NIOS2_MODE_MASK; ++ dma_channels[dmanr].mode &= ~NIOS2_MODE_MASK; ++ dma_channels[dmanr].mode |= mode; ++ } ++} ++ ++void nios2_set_dma_raddr(unsigned int dmanr, unsigned int a) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ outl(a, dma_channels[dmanr].addr+REG_DMA_READADDR); ++ } ++} ++void nios2_set_dma_waddr(unsigned int dmanr, unsigned int a) ++{ ++ if (dmanr < MAX_DMA_CHANNELS) { ++ outl(a, dma_channels[dmanr].addr+REG_DMA_WRITEADDR); ++ } ++} ++ ++ ++static irqreturn_t dma_isr(int irq, void *dev_id) ++{ ++ struct dma_channel *chann=(struct dma_channel*)dev_id; ++ ++ if (chann) { ++ int status = inl(chann->addr+REG_DMA_STATUS); ++ /* ack the interrupt, and clear the DONE bit */ ++ outl(0, chann->addr+REG_DMA_STATUS); ++ /* call the peripheral callback */ ++ if (chann->handler) ++ chann->handler(chann->user, status); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++ ++ ++#ifdef CONFIG_PROC_FS ++static int proc_dma_show(struct seq_file *m, void *v) ++{ ++ int i; ++ ++ for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) { ++ if (!atomic_read(&dma_channels[i].idle)) { ++ seq_printf(m, "%2d: %s\n", i, ++ dma_channels[i].dev_id); ++ } ++ } ++ return 0; ++} ++ ++static int proc_dma_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, proc_dma_show, NULL); ++} ++static struct file_operations proc_dma_operations = { ++ .open = proc_dma_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int __init proc_dma_init(void) ++{ ++ struct proc_dir_entry *e; ++ ++ e = create_proc_entry("dma", 0, NULL); ++ if (e) ++ e->proc_fops = &proc_dma_operations; ++ ++ return 0; ++} ++ ++__initcall(proc_dma_init); ++ ++#endif /* CONFIG_PROC_FS */ ++ ++int __init init_dma(void) ++{ ++ int i; ++ ++ for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) { ++ sprintf(dma_channels[i].id, "dmac-%d", i); ++ /* disable the dmac channel */ ++ disable_dma(i); ++ /* request irq*/ ++ if (request_irq(dma_channels[i].irq, dma_isr, 0, dma_channels[i].id, (void*)&dma_channels[i])){ ++ printk("DMA controller %d failed to get irq %d\n", i, dma_channels[i].irq); ++ atomic_set(&dma_channels[i].idle, 0); ++ } ++ } ++ return 0; ++} ++ ++static void __exit exit_dma(void) ++{ ++ int i; ++ ++ for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) { ++ /* disable the dmac channel */ ++ disable_dma(i); ++ free_irq(dma_channels[i].irq, dma_channels[i].id); ++ } ++} ++ ++module_init(init_dma); ++module_exit(exit_dma); ++ ++MODULE_LICENSE("GPL"); ++ ++//EXPORT_SYMBOL(claim_dma_lock); ++//EXPORT_SYMBOL(release_dma_lock); ++EXPORT_SYMBOL(enable_dma); ++EXPORT_SYMBOL(disable_dma); ++EXPORT_SYMBOL(set_dma_count); ++EXPORT_SYMBOL(get_dma_residue); ++EXPORT_SYMBOL(request_dma); ++EXPORT_SYMBOL(free_dma); ++EXPORT_SYMBOL(nios2_request_dma); ++EXPORT_SYMBOL(nios2_set_dma_handler); ++EXPORT_SYMBOL(nios2_set_dma_data_width); ++EXPORT_SYMBOL(nios2_set_dma_rcon); ++EXPORT_SYMBOL(nios2_set_dma_wcon); ++EXPORT_SYMBOL(nios2_set_dma_mode); ++EXPORT_SYMBOL(nios2_set_dma_raddr); ++EXPORT_SYMBOL(nios2_set_dma_waddr); ++ +diff --git a/arch/nios2nommu/kernel/entry.S b/arch/nios2nommu/kernel/entry.S +new file mode 100644 +index 0000000..7f71a01 +--- /dev/null ++++ b/arch/nios2nommu/kernel/entry.S +@@ -0,0 +1,898 @@ ++/* ++ * linux/arch/nios2nommu/kernel/entry.S ++ * ++ * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) ++ * Copyright (C) 1998 D. Jeff Dionne , ++ * Kenneth Albanowski , ++ * Copyright (C) 2000 Lineo Inc. (www.lineo.com) ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * Based on: ++ * ++ * linux/arch/m68knommu/kernel/entry.S ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file README.legal in the main directory of this archive ++ * for more details. ++ * ++ * Linux/m68k support by Hamish Macdonald ++ * ++ * 68060 fixes by Jesper Skov ++ * ColdFire support by Greg Ungerer (gerg@snapgear.com) ++ * 5307 fixes by David W. Miller ++ * linux 2.4 support David McCullough ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++.text ++.set noat ++.set nobreak ++ ++ENTRY(system_call) ++/* SAVE_ALL */ ++ rdctl r10,status /* enable intrs again */ ++ ori r10,r10,0x0001 ++ wrctl status,r10 ++ ++ movi r2,-LENOSYS ++ stw r2,PT_R2(sp) /* default return value in r2 */ ++ /* original r2 is in orig_r2 */ ++ ++ movui r1,NR_syscalls ++ bgtu r3,r1,ret_from_exception ++ slli r1,r3,2 ++ movhi r11,%hiadj(sys_call_table) ++ add r1,r1,r11 ++ ldw r1,%lo(sys_call_table)(r1) ++ beq r1,r0,ret_from_exception ++ ++ movi r11,%lo(0xffffe000) /* Get thread info pointer */ ++ and r11,sp,r11 ++ ldw r11,TI_FLAGS(r11) ++ BTBNZ r11,r11,TIF_SYSCALL_TRACE_ASM,1f ++ ++ callr r1 ++ stw r2,PT_R2(sp) /* save the return value */ ++ br ret_from_exception ++1: ++ SAVE_SWITCH_STACK ++ call syscall_trace ++ RESTORE_SWITCH_STACK ++ /* wentao: restore r4-9, since they are trashed by syscall_trace */ ++ ldw r4,PT_R4(sp) ++ ldw r5,PT_R5(sp) ++ ldw r6,PT_R6(sp) ++ ldw r7,PT_R7(sp) ++ ldw r8,PT_R8(sp) ++ ldw r9,PT_R9(sp) ++ callr r1 ++ stw r2,PT_R2(sp) /* save the return value */ ++ SAVE_SWITCH_STACK ++ call syscall_trace ++ RESTORE_SWITCH_STACK ++ ++ret_from_exception: ++ ldw r1,PT_STATUS_EXTENSION(sp) /* check if returning to kernel */ ++ TSTBZ r1,r1,PS_S_ASM,Luser_return /* if so, skip resched, signals */ ++ ++restore_all: ++ rdctl r10,status /* disable intrs */ ++ andi r10,r10,0xfffe ++ wrctl status, r10 ++ RESTORE_ALL ++ eret ++ ++Luser_return: ++ GET_THREAD_INFO r24 /* get thread_info pointer */ ++ ldw r10,TI_FLAGS(r24) /* get thread_info->flags */ ++ ANDI32 r11,r10,_TIF_WORK_MASK_ASM ++ beq r11,r0,restore_all /* Nothing to do */ ++ BTBZ r1,r10,TIF_NEED_RESCHED_ASM,Lsignal_return ++ ++Lwork_resched: ++ call schedule ++ br ret_from_exception ++ ++Lsignal_return: ++ BTBZ r1,r10,TIF_SIGPENDING_ASM,restore_all ++ mov r5,sp /* pt_regs */ ++ SAVE_SWITCH_STACK ++ CLR r4 /* oldset = 0 */ ++ call do_signal ++ RESTORE_SWITCH_STACK ++ br restore_all ++ ++/* ++ * Handle software exceptions. Put here so external interrupts ++ * can fall throught to ret_from_interrupt. ++ */ ++ ++software_exception: ++ ldw r24,-4(ea) // instruction that caused the exception ++ xorhi r24,r24,0x003b // upper half of trap opcode ++ xori r24,r24,0x683a // lower half of trap opcode ++ bne r24,r0,instruction_trap /* N - check for instruction trap */ ++ cmpeqi r11,r2,TRAP_ID_SYSCALL /* ? Is this a syscall */ ++ bne r11,r0,system_call /* Y - handle syscall */ ++ cmpeqi r11,r2,TRAP_ID_APPDEBUG /* ? Is this an application debug */ ++ bne r11,r0,app_debug /* Y - handle app_debug */ ++ cmpeqi r11,r2,63 /* ? Is this the old syscall number */ ++ bne r11,r0,system_call /* Y - handle syscall to catch older apps*/ ++ br restore_all /* N - everything else is ignored for now */ ++ ++app_debug: ++ GET_THREAD_INFO r24 /* get thread_info */ ++ ldw r1,TI_TASK(r24) /* get thread_info->task */ ++ ldw r24,(TASK_THREAD + THREAD_FLAGS)(r1) /* get thread_info->task->thread.flags */ ++ ORI32 r24, r24, NIOS2_FLAG_DEBUG /* set the debug flag */ ++ stw r24,(TASK_THREAD + THREAD_FLAGS)(r1) /* save thread_info->task->thread.flags */ ++ br restore_all ++ ++/* ++ * This is the generic interrupt handler (for all hardware interrupt ++ * sources). It figures out the vector number and calls the appropriate ++ * interrupt service routine directly. ++ */ ++ENTRY(inthandler) ++ SAVE_ALL ++ /* ++ * Test to see if the exception was a software exception or caused by an ++ * external interrupt, and vector accordingly. ++ */ ++ ++ rdctl r24,estatus ++ andi r24,r24,1 ++ beq r24,r0,software_exception ++ rdctl r12,ipending ++ beq r12,r0,software_exception ++ ++ movi r24,-1 ++ stw r24,PT_ORIG_R2(sp) ++ ++ /* ++ * Process an external hardware interrupt. ++ */ ++ ++ addi ea,ea,-4 /* re-issue the interrupted instruction */ ++ stw ea,PT_EA(sp) ++ rdctl r9,ienable /* Isolate possible interrupts */ ++ and r12,r12,r9 ++ beq r12,r0,ret_from_interrupt /* No one to service done */ ++ movi r4,%lo(-1) /* Start from bit position 0, highest priority */ ++ /* This is the IRQ # for handler call */ ++1: addi r4,r4,1 ++ srl r10,r12,r4 ++ andi r10,r10,1 /* Isolate bit we are interested in */ ++ cmpeqi r11,r4,32 /* ? End of the register */ ++ bne r11,r0,ret_from_interrupt /* Y - out of here */ ++ beq r10,r0,1b ++ mov r5,sp /* Setup pt_regs pointer for handler call */ ++ PUSH r4 /* Save state for return */ ++ PUSH r12 ++ call process_int ++ POP r12 ++ POP r4 ++ br 1b /* Check for other interrupts while here */ ++ ++ENTRY(ret_from_interrupt) ++ ldw r4,PT_STATUS_EXTENSION(sp) ++ TSTBZ r4,r4,PS_S_ASM,Luser_return // Returning to user ++ ++#ifdef CONFIG_PREEMPT ++ GET_THREAD_INFO r1 ++ ldw r4,TI_PREEMPT_COUNT(r1) ++ bne r4,r0,restore_all ++ ++need_resched: ++ ldw r4,TI_FLAGS(r1) // ? Need resched set ++ BTBZ r10,r4,TIF_NEED_RESCHED_ASM,restore_all ++ ldw r4,PT_ESTATUS(sp) // ? Interrupts off ++ BTBZ r10,r4,NIOS2_STATUS_PIE_OFST_ASM,restore_all ++ movia r4,PREEMPT_ACTIVE_ASM ++ stw r4,TI_PREEMPT_COUNT(r1) ++ rdctl r10,status /* enable intrs again */ ++ ori r10,r10,0x0001 ++ wrctl status,r10 ++ PUSH r1 ++ call schedule ++ POP r1 ++ mov r4,r0 ++ stw r4,TI_PREEMPT_COUNT(r1) ++ rdctl r10,status /* disable intrs */ ++ andi r10,r10,0xfffe ++ wrctl status, r10 ++ br need_resched ++#else ++ br restore_all ++#endif ++ ++ ++/* ++ * Beware - when entering resume, prev (the current task) is ++ * in r4, next (the new task) is in r5, don't change these ++ * registers. ++ */ ++ENTRY(resume) ++ ++ rdctl r7,status /* save thread status reg */ ++ stw r7,TASK_THREAD+THREAD_KPSR(r4) ++ ++ andi r7,r7,0x0fffe /* disable interrupts */ ++ wrctl status,r7 ++ ++ movia r8,status_extension /* save status extension */ ++ ldw r7,0(r8) ++ stw r7,TASK_THREAD+THREAD_KESR(r4) ++ ++ SAVE_SWITCH_STACK ++ stw sp,TASK_THREAD+THREAD_KSP(r4) /* save kernel stack pointer */ ++ ldw sp,TASK_THREAD+THREAD_KSP(r5) /* restore new thread stack */ ++ movia r24,_current_thread /* save thread */ ++ GET_THREAD_INFO r1 ++ stw r1,0(r24) ++ RESTORE_SWITCH_STACK ++ ++ ldw r7,TASK_THREAD+THREAD_KESR(r5) /* restore extended status reg */ ++ stw r7,0(r8) ++ ++ ldw r7,TASK_THREAD+THREAD_KPSR(r5) /* restore thread status reg */ ++ wrctl status,r7 ++ ret ++ ++ENTRY(ret_from_fork) ++ call schedule_tail ++ br ret_from_exception ++ ++ENTRY(sys_fork) ++ mov r4,sp ++ SAVE_SWITCH_STACK ++ call nios2_vfork ++ RESTORE_SWITCH_STACK ++ ret ++ ++ENTRY(sys_vfork) ++ mov r4,sp ++ SAVE_SWITCH_STACK ++ call nios2_vfork ++ RESTORE_SWITCH_STACK ++ ret ++ ++ENTRY(sys_execve) ++ mov r4,sp ++ SAVE_SWITCH_STACK ++ call nios2_execve ++ RESTORE_SWITCH_STACK ++ ret ++ ++ENTRY(sys_clone) ++ mov r4,sp ++ SAVE_SWITCH_STACK ++ call nios2_clone ++ RESTORE_SWITCH_STACK ++ ret ++ ++ENTRY(sys_sigsuspend) ++ mov r4,sp ++ SAVE_SWITCH_STACK ++ call do_sigsuspend ++ RESTORE_SWITCH_STACK ++ ret ++ ++ENTRY(sys_rt_sigsuspend) ++ mov r4,sp ++ SAVE_SWITCH_STACK ++ call do_rt_sigsuspend ++ RESTORE_SWITCH_STACK ++ ret ++ ++ENTRY(sys_sigreturn) ++ mov r4,sp ++ SAVE_SWITCH_STACK ++ call do_sigreturn ++ RESTORE_SWITCH_STACK ++ ret ++ ++ENTRY(sys_sigaltstack) ++ ldw r4,PT_R4(sp) ++ ldw r5,PT_R5(sp) ++ ldw r6,PT_SP(sp) ++ SAVE_SWITCH_STACK ++ call do_sigaltstack ++ RESTORE_SWITCH_STACK ++ ret ++ ++ENTRY(sys_rt_sigreturn) ++ SAVE_SWITCH_STACK ++ call do_rt_sigreturn ++ RESTORE_SWITCH_STACK ++ ret ++ ++/****************************************************************************** ++* * ++* License Agreement * ++* * ++* Copyright (c) 2003 Altera Corporation, San Jose, California, USA. * ++* 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. * ++* * ++* This agreement shall be governed in all respects by the laws of the State * ++* of California and by the laws of the United States of America. * ++* * ++******************************************************************************/ ++ ++ /* ++ * This is the software exception handler for Nios2. ++ */ ++ ++ /* ++ * Explicitly allow the use of r1 (the assembler temporary register) ++ * within this code. This register is normally reserved for the use of ++ * the compiler. ++ */ ++ ++ENTRY(instruction_trap) ++ RESTORE_ALL // Clean off our save & setup for emulation ++ ++ /* INSTRUCTION EMULATION ++ * --------------------- ++ * ++ * Nios II processors generate exceptions for unimplemented instructions. ++ * The routines below emulate these instructions. Depending on the ++ * processor core, the only instructions that might need to be emulated ++ * are div, divu, mul, muli, mulxss, mulxsu, and mulxuu. ++ * ++ * The emulations match the instructions, except for the following ++ * limitations: ++ * ++ * 1) The emulation routines do not emulate the use of the exception ++ * temporary register (et) as a source operand because the exception ++ * handler already has modified it. ++ * ++ * 2) The routines do not emulate the use of the stack pointer (sp) or the ++ * exception return address register (ea) as a destination because ++ * modifying these registers crashes the exception handler or the ++ * interrupted routine. ++ * ++ * Detailed Design ++ * --------------- ++ * ++ * The emulation routines expect the contents of integer registers r0-r31 ++ * to be on the stack at addresses sp, 4(sp), 8(sp), ... 124(sp). The ++ * routines retrieve source operands from the stack and modify the ++ * destination register's value on the stack prior to the end of the ++ * exception handler. Then all registers except the destination register ++ * are restored to their previous values. ++ * ++ * The instruction that causes the exception is found at address -4(ea). ++ * The instruction's OP and OPX fields identify the operation to be ++ * performed. ++ * ++ * One instruction, muli, is an I-type instruction that is identified by ++ * an OP field of 0x24. ++ * ++ * muli AAAAA,BBBBB,IIIIIIIIIIIIIIII,-0x24- ++ * 27 22 6 0 <-- LSB of field ++ * ++ * The remaining emulated instructions are R-type and have an OP field ++ * of 0x3a. Their OPX fields identify them. ++ * ++ * R-type AAAAA,BBBBB,CCCCC,XXXXXX,NNNNN,-0x3a- ++ * 27 22 17 11 6 0 <-- LSB of field ++ * ++ * ++ * Opcode Encoding. muli is identified by its OP value. Then OPX & 0x02 ++ * is used to differentiate between the division opcodes and the remaining ++ * multiplication opcodes. ++ * ++ * Instruction OP OPX OPX & 0x02 ++ * ----------- ---- ---- ---------- ++ * muli 0x24 ++ * divu 0x3a 0x24 0 ++ * div 0x3a 0x25 0 ++ * mul 0x3a 0x27 != 0 ++ * mulxuu 0x3a 0x07 != 0 ++ * mulxsu 0x3a 0x17 != 0 ++ * mulxss 0x3a 0x1f != 0 ++ */ ++ ++ ++ /* ++ * Save everything on the stack to make it easy for the emulation routines ++ * to retrieve the source register operands. ++ */ ++ ++ addi sp, sp, -128 ++ stw zero, 0(sp) // Save zero on stack to avoid special case for r0. ++ stw r1, 4(sp) ++ stw r2, 8(sp) ++ stw r3, 12(sp) ++ stw r4, 16(sp) ++ stw r5, 20(sp) ++ stw r6, 24(sp) ++ stw r7, 28(sp) ++ stw r8, 32(sp) ++ stw r9, 36(sp) ++ stw r10, 40(sp) ++ stw r11, 44(sp) ++ stw r12, 48(sp) ++ stw r13, 52(sp) ++ stw r14, 56(sp) ++ stw r15, 60(sp) ++ stw r16, 64(sp) ++ stw r17, 68(sp) ++ stw r18, 72(sp) ++ stw r19, 76(sp) ++ stw r20, 80(sp) ++ stw r21, 84(sp) ++ stw r22, 88(sp) ++ stw r23, 92(sp) ++ // Don't bother to save et. It's already been changed. ++ stw bt, 100(sp) ++ stw gp, 104(sp) ++ stw sp, 108(sp) ++ stw fp, 112(sp) ++ // Don't bother to save ea. It's already been changed. ++ stw ba, 120(sp) ++ stw ra, 124(sp) ++ ++ ++ /* ++ * Split the instruction into its fields. We need 4*A, 4*B, and 4*C as ++ * offsets to the stack pointer for access to the stored register values. ++ */ ++ ldw r2,-4(ea) // r2 = AAAAA,BBBBB,IIIIIIIIIIIIIIII,PPPPPP ++ roli r3,r2,7 // r3 = BBB,IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BB ++ roli r4,r3,3 // r4 = IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB ++ roli r5,r4,2 // r5 = IIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB,II ++ srai r4,r4,16 // r4 = (sign-extended) IMM16 ++ roli r6,r5,5 // r6 = XXXX,NNNNN,PPPPPP,AAAAA,BBBBB,CCCCC,XX ++ andi r2,r2,0x3f // r2 = 00000000000000000000000000,PPPPPP ++ andi r3,r3,0x7c // r3 = 0000000000000000000000000,AAAAA,00 ++ andi r5,r5,0x7c // r5 = 0000000000000000000000000,BBBBB,00 ++ andi r6,r6,0x7c // r6 = 0000000000000000000000000,CCCCC,00 ++ ++ /* Now ++ * r2 = OP ++ * r3 = 4*A ++ * r4 = IMM16 (sign extended) ++ * r5 = 4*B ++ * r6 = 4*C ++ */ ++ ++ ++ /* ++ * Get the operands. ++ * ++ * It is necessary to check for muli because it uses an I-type instruction ++ * format, while the other instructions are have an R-type format. ++ * ++ * Prepare for either multiplication or division loop. ++ * They both loop 32 times. ++ */ ++ movi r14,32 ++ ++ add r3,r3,sp // r3 = address of A-operand. ++ ldw r3,0(r3) // r3 = A-operand. ++ movi r7,0x24 // muli opcode (I-type instruction format) ++ beq r2,r7,mul_immed // muli doesn't use the B register as a source ++ ++ add r5,r5,sp // r5 = address of B-operand. ++ ldw r5,0(r5) // r5 = B-operand. ++ // r4 = SSSSSSSSSSSSSSSS,-----IMM16------ ++ // IMM16 not needed, align OPX portion ++ // r4 = SSSSSSSSSSSSSSSS,CCCCC,-OPX--,00000 ++ srli r4,r4,5 // r4 = 00000,SSSSSSSSSSSSSSSS,CCCCC,-OPX-- ++ andi r4,r4,0x3f // r4 = 00000000000000000000000000,-OPX-- ++ ++ /* Now ++ * r2 = OP ++ * r3 = src1 ++ * r5 = src2 ++ * r4 = OPX (no longer can be muli) ++ * r6 = 4*C ++ */ ++ ++ ++ ++ /* ++ * Multiply or Divide? ++ */ ++ andi r7,r4,0x02 // For R-type multiply instructions, OPX & 0x02 != 0 ++ bne r7,zero,multiply ++ ++ ++ /* DIVISION ++ * ++ * Divide an unsigned dividend by an unsigned divisor using ++ * a shift-and-subtract algorithm. The example below shows ++ * 43 div 7 = 6 for 8-bit integers. This classic algorithm uses a ++ * single register to store both the dividend and the quotient, ++ * allowing both values to be shifted with a single instruction. ++ * ++ * remainder dividend:quotient ++ * --------- ----------------- ++ * initialize 00000000 00101011: ++ * shift 00000000 0101011:_ ++ * remainder >= divisor? no 00000000 0101011:0 ++ * shift 00000000 101011:0_ ++ * remainder >= divisor? no 00000000 101011:00 ++ * shift 00000001 01011:00_ ++ * remainder >= divisor? no 00000001 01011:000 ++ * shift 00000010 1011:000_ ++ * remainder >= divisor? no 00000010 1011:0000 ++ * shift 00000101 011:0000_ ++ * remainder >= divisor? no 00000101 011:00000 ++ * shift 00001010 11:00000_ ++ * remainder >= divisor? yes 00001010 11:000001 ++ * remainder -= divisor - 00000111 ++ * ---------- ++ * 00000011 11:000001 ++ * shift 00000111 1:000001_ ++ * remainder >= divisor? yes 00000111 1:0000011 ++ * remainder -= divisor - 00000111 ++ * ---------- ++ * 00000000 1:0000011 ++ * shift 00000001 :0000011_ ++ * remainder >= divisor? no 00000001 :00000110 ++ * ++ * The quotient is 00000110. ++ */ ++ ++divide: ++ /* ++ * Prepare for division by assuming the result ++ * is unsigned, and storing its "sign" as 0. ++ */ ++ movi r17,0 ++ ++ ++ // Which division opcode? ++ xori r7,r4,0x25 // OPX of div ++ bne r7,zero,unsigned_division ++ ++ ++ /* ++ * OPX is div. Determine and store the sign of the quotient. ++ * Then take the absolute value of both operands. ++ */ ++ xor r17,r3,r5 // MSB contains sign of quotient ++ bge r3,zero,dividend_is_nonnegative ++ sub r3,zero,r3 // -r3 ++dividend_is_nonnegative: ++ bge r5,zero,divisor_is_nonnegative ++ sub r5,zero,r5 // -r5 ++divisor_is_nonnegative: ++ ++ ++unsigned_division: ++ // Initialize the unsigned-division loop. ++ movi r13,0 // remainder = 0 ++ ++ /* Now ++ * r3 = dividend : quotient ++ * r4 = 0x25 for div, 0x24 for divu ++ * r5 = divisor ++ * r13 = remainder ++ * r14 = loop counter (already initialized to 32) ++ * r17 = MSB contains sign of quotient ++ */ ++ ++ ++ /* ++ * for (count = 32; count > 0; --count) ++ * { ++ */ ++divide_loop: ++ ++ /* ++ * Division: ++ * ++ * (remainder:dividend:quotient) <<= 1; ++ */ ++ slli r13,r13,1 ++ cmplt r7,r3,zero // r7 = MSB of r3 ++ or r13,r13,r7 ++ slli r3,r3,1 ++ ++ ++ /* ++ * if (remainder >= divisor) ++ * { ++ * set LSB of quotient ++ * remainder -= divisor; ++ * } ++ */ ++ bltu r13,r5,div_skip ++ ori r3,r3,1 ++ sub r13,r13,r5 ++div_skip: ++ ++ /* ++ * } ++ */ ++ subi r14,r14,1 ++ bne r14,zero,divide_loop ++ ++ ++ /* Now ++ * r3 = quotient ++ * r4 = 0x25 for div, 0x24 for divu ++ * r6 = 4*C ++ * r17 = MSB contains sign of quotient ++ */ ++ ++ ++ /* ++ * Conditionally negate signed quotient. If quotient is unsigned, ++ * the sign already is initialized to 0. ++ */ ++ bge r17,zero,quotient_is_nonnegative ++ sub r3,zero,r3 // -r3 ++quotient_is_nonnegative: ++ ++ ++ /* ++ * Final quotient is in r3. ++ */ ++ add r6,r6,sp ++ stw r3,0(r6) // write quotient to stack ++ br restore_registers ++ ++ ++ ++ ++ /* MULTIPLICATION ++ * ++ * A "product" is the number that one gets by summing a "multiplicand" ++ * several times. The "multiplier" specifies the number of copies of the ++ * multiplicand that are summed. ++ * ++ * Actual multiplication algorithms don't use repeated addition, however. ++ * Shift-and-add algorithms get the same answer as repeated addition, and ++ * they are faster. To compute the lower half of a product (pppp below) ++ * one shifts the product left before adding in each of the partial products ++ * (a * mmmm) through (d * mmmm). ++ * ++ * To compute the upper half of a product (PPPP below), one adds in the ++ * partial products (d * mmmm) through (a * mmmm), each time following the ++ * add by a right shift of the product. ++ * ++ * mmmm ++ * * abcd ++ * ------ ++ * #### = d * mmmm ++ * #### = c * mmmm ++ * #### = b * mmmm ++ * #### = a * mmmm ++ * -------- ++ * PPPPpppp ++ * ++ * The example above shows 4 partial products. Computing actual Nios II ++ * products requires 32 partials. ++ * ++ * It is possible to compute the result of mulxsu from the result of mulxuu ++ * because the only difference between the results of these two opcodes is ++ * the value of the partial product associated with the sign bit of rA. ++ * ++ * mulxsu = mulxuu - (rA < 0) ? rB : 0; ++ * ++ * It is possible to compute the result of mulxss from the result of mulxsu ++ * because the only difference between the results of these two opcodes is ++ * the value of the partial product associated with the sign bit of rB. ++ * ++ * mulxss = mulxsu - (rB < 0) ? rA : 0; ++ * ++ */ ++ ++mul_immed: ++ // Opcode is muli. Change it into mul for remainder of algorithm. ++ mov r6,r5 // Field B is dest register, not field C. ++ mov r5,r4 // Field IMM16 is src2, not field B. ++ movi r4,0x27 // OPX of mul is 0x27 ++ ++multiply: ++ // Initialize the multiplication loop. ++ movi r9,0 // mul_product = 0 ++ movi r10,0 // mulxuu_product = 0 ++ mov r11,r5 // save original multiplier for mulxsu and mulxss ++ mov r12,r5 // mulxuu_multiplier (will be shifted) ++ movi r16,1 // used to create "rori B,A,1" from "ror B,A,r16" ++ ++ /* Now ++ * r3 = multiplicand ++ * r5 = mul_multiplier ++ * r6 = 4 * dest_register (used later as offset to sp) ++ * r7 = temp ++ * r9 = mul_product ++ * r10 = mulxuu_product ++ * r11 = original multiplier ++ * r12 = mulxuu_multiplier ++ * r14 = loop counter (already initialized) ++ * r16 = 1 ++ */ ++ ++ ++ /* ++ * for (count = 32; count > 0; --count) ++ * { ++ */ ++multiply_loop: ++ ++ /* ++ * mul_product <<= 1; ++ * lsb = multiplier & 1; ++ */ ++ slli r9,r9,1 ++ andi r7,r12,1 ++ ++ /* ++ * if (lsb == 1) ++ * { ++ * mulxuu_product += multiplicand; ++ * } ++ */ ++ beq r7,zero,mulx_skip ++ add r10,r10,r3 ++ cmpltu r7,r10,r3 // Save the carry from the MSB of mulxuu_product. ++ ror r7,r7,r16 // r7 = 0x80000000 on carry, or else 0x00000000 ++mulx_skip: ++ ++ /* ++ * if (MSB of mul_multiplier == 1) ++ * { ++ * mul_product += multiplicand; ++ * } ++ */ ++ bge r5,zero,mul_skip ++ add r9,r9,r3 ++mul_skip: ++ ++ /* ++ * mulxuu_product >>= 1; logical shift ++ * mul_multiplier <<= 1; done with MSB ++ * mulx_multiplier >>= 1; done with LSB ++ */ ++ srli r10,r10,1 ++ or r10,r10,r7 // OR in the saved carry bit. ++ slli r5,r5,1 ++ srli r12,r12,1 ++ ++ ++ /* ++ * } ++ */ ++ subi r14,r14,1 ++ bne r14,zero,multiply_loop ++ ++ ++ /* ++ * Multiply emulation loop done. ++ */ ++ ++ /* Now ++ * r3 = multiplicand ++ * r4 = OPX ++ * r6 = 4 * dest_register (used later as offset to sp) ++ * r7 = temp ++ * r9 = mul_product ++ * r10 = mulxuu_product ++ * r11 = original multiplier ++ */ ++ ++ ++ // Calculate address for result from 4 * dest_register ++ add r6,r6,sp ++ ++ ++ /* ++ * Select/compute the result based on OPX. ++ */ ++ ++ ++ // OPX == mul? Then store. ++ xori r7,r4,0x27 ++ beq r7,zero,store_product ++ ++ // It's one of the mulx.. opcodes. Move over the result. ++ mov r9,r10 ++ ++ // OPX == mulxuu? Then store. ++ xori r7,r4,0x07 ++ beq r7,zero,store_product ++ ++ // Compute mulxsu ++ // ++ // mulxsu = mulxuu - (rA < 0) ? rB : 0; ++ // ++ bge r3,zero,mulxsu_skip ++ sub r9,r9,r11 ++mulxsu_skip: ++ ++ // OPX == mulxsu? Then store. ++ xori r7,r4,0x17 ++ beq r7,zero,store_product ++ ++ // Compute mulxss ++ // ++ // mulxss = mulxsu - (rB < 0) ? rA : 0; ++ // ++ bge r11,zero,mulxss_skip ++ sub r9,r9,r3 ++mulxss_skip: ++ // At this point, assume that OPX is mulxss, so store ++ ++ ++store_product: ++ stw r9,0(r6) ++ ++ ++restore_registers: ++ // No need to restore r0. ++ ldw r1, 4(sp) ++ ldw r2, 8(sp) ++ ldw r3, 12(sp) ++ ldw r4, 16(sp) ++ ldw r5, 20(sp) ++ ldw r6, 24(sp) ++ ldw r7, 28(sp) ++ ldw r8, 32(sp) ++ ldw r9, 36(sp) ++ ldw r10, 40(sp) ++ ldw r11, 44(sp) ++ ldw r12, 48(sp) ++ ldw r13, 52(sp) ++ ldw r14, 56(sp) ++ ldw r15, 60(sp) ++ ldw r16, 64(sp) ++ ldw r17, 68(sp) ++ ldw r18, 72(sp) ++ ldw r19, 76(sp) ++ ldw r20, 80(sp) ++ ldw r21, 84(sp) ++ ldw r22, 88(sp) ++ ldw r23, 92(sp) ++ ldw et, 96(sp) ++ ldw bt, 100(sp) ++ ldw gp, 104(sp) ++ // Don't corrupt sp. ++ ldw fp, 112(sp) ++ // Don't corrupt ea. ++ ldw ba, 120(sp) ++ ldw ra, 124(sp) ++ addi sp, sp, 128 ++ eret ++ ++.set at ++.set break ++ +diff --git a/arch/nios2nommu/kernel/head.S b/arch/nios2nommu/kernel/head.S +new file mode 100644 +index 0000000..f1cba65 +--- /dev/null ++++ b/arch/nios2nommu/kernel/head.S +@@ -0,0 +1,228 @@ ++/* ++ * head.S for Altera's Excalibur development board with nios processor ++ * ++ * (c) Vic Phillips, Microtronix Datacom Ltd., 2001 ++ * (C) Copyright 2004 Microtronix Datacom Ltd ++ * ++ * Based on the following from the Excalibur sdk distribution: ++ * NA_MemoryMap.s, NR_JumpToStart.s, NR_Setup.s, NR_CWPManager.s ++ * ++ * 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., 675 ++ * Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++ ++ ++#ifdef CONFIG_CRC_CHECK ++/**********************************************/ ++/* Define where the CRC table lives in flash. */ ++/* The __CRC_Sector_Size is the flash sector */ ++/* size for the address range. */ ++/**********************************************/ ++ ++ GEQU __CRC_Table_Begin,(na_flash)+0x4000 /* Second sector of main board flash */ ++ GEQU __CRC_Sector_Size,0x2000 ++#endif ++ ++/* ++ * This global variable is used as an extension to the nios' ++ * STATUS register to emulate a user/supervisor mode. ++ */ ++ .data ++ .align 2 ++ .set noat ++ .global status_extension ++status_extension: ++ .long 0 ++ ++ .global _current_thread ++_current_thread: ++ .long 0 ++/* ++ * Input(s): passed from u-boot ++ * r4 - Optional pointer to a board information structure. ++ * r5 - Optional pointer to the physical starting address of the init RAM ++ * disk. ++ * r6 - Optional pointer to the physical ending address of the init RAM ++ * disk. ++ * r7 - Optional pointer to the physical starting address of any kernel ++ * command-line parameters. ++ */ ++ ++/* ++ * First executable code - detected and jumped to by the ROM bootstrap ++ * if the code resides in flash (looks for "Nios" at offset 0x0c from ++ * the potential executable image). ++ */ ++ .text ++ .global _start ++_start: ++ wrctl status,r0 /* Disable interrupts */ ++ ++ /* Flush all cache lines within the instruction cache */ ++ ++ movia r1,NIOS2_ICACHE_SIZE ++ movui r2,NIOS2_ICACHE_LINE_SIZE ++ ++text_flush: ++ flushi r1 ++ sub r1,r1,r2 ++ bgt r1,r0,text_flush ++ br 1f ++ ++ /* This is the default location for the exception ++ * handler. Code in jump to our handler ++ */ ++ ++ movia r24,inthandler ++ jmp r24 ++1: ++ /* ++ * After flushing the instruction cache, we must flush the data ++ * cache. ++ */ ++ ++ movia r1,NIOS2_DCACHE_SIZE ++ movi r2,NIOS2_DCACHE_LINE_SIZE ++ ++data_flush: ++ flushd 0(r1) ++ sub r1,r1,r2 ++ bgt r1,r0,data_flush ++ ++NR_MoveStart: ++#ifdef CONFIG_BREAK_ON_START ++ break ++#endif //CONFIG_BREAK_ON_START ++ nextpc r1 /* Find out where we are */ ++chkadr: ++ movia r2,chkadr ++ beq r1,r2,finish_move /* We are running in RAM done */ ++ addi r1,r1,(_start - chkadr) /* Source */ ++ movia r2,_start /* Destination */ ++ movia r3,__bss_start /* End of copy */ ++ ++loop_move: // r1: src, r2: dest, r3: last dest ++ ldw r8,0(r1) // load a word from [r1] ++ stw r8,0(r2) // stort a word to dest [r2] ++ flushd 0(r2) // Flush cache for safty ++ addi r1,r1,4 // inc the src addr ++ addi r2,r2,4 // inc the dest addr ++ blt r2,r3,loop_move ++ ++ movia r1,finish_move // VMA(_start)->l1 ++ jmp r1 // jmp to _start ++ ++finish_move: ++ ++ //------------------------------------ ++ // Disable interrupts on known devices ++ // ++#ifdef NA_ENET_ASM ++#ifdef NA_ENET_RESET_ASM ++ movia r1,NA_ENET_RESET_ASM // ethernet reset address ++ stwio r0,0(r1) // reset ++#endif ++#ifdef NA_ENET_RESET_N_ASM ++ movia r1,NA_ENET_RESET_N_ASM // ethernet reset address ++ stwio r0,0(r1) // reset ++#endif ++ nop // give it some time ++ nop // ++ nop // ++ nop // ++#endif ++#ifdef NA_TIMER0_ASM ++ movia r1,NA_TIMER0_ASM // get timer address ++ stwio r0,NP_TIMERCONTROL_ASM(r1) // clear interrupt enable ++ stwio r0,NP_TIMERSTATUS_ASM(r1) // clear interrupt condition ++#endif ++#ifdef NA_UART0_ASM ++ movia r1,NA_UART0_ASM ++ stwio r0,NP_UARTCONTROL_ASM(r1) // clear interrupt enable ++ stwio r0,NP_UARTSTATUS_ASM(r1) // clear interrupt status ++#endif ++#ifdef NA_UART1_ASM ++ movia r1,NA_UART1_ASM ++ stwio r0,NP_UARTCONTROL_ASM(r1) // clear interrupt enable ++ stwio r0,NP_UARTSTATUS_ASM(r1) // clear interrupt status ++#endif ++#ifdef NA_UART2_ASM ++ movia r1,NA_UART2_ASM ++ stwio r0,NP_UARTCONTROL_ASM(r1) // clear interrupt enable ++ stwio r0,NP_UARTSTATUS_ASM(r1) // clear interrupt status ++#endif ++#ifdef NA_UART3_ASM ++ movia r1,NA_UART3_ASM ++ stwio r0,NP_UARTCONTROL_ASM(r1) // clear interrupt enable ++ stwio r0,NP_UARTSTATUS_ASM(r1) // clear interrupt status ++#endif ++#ifdef NA_IDE_INTERFACE_ASM ++ movia r1,NA_IDE_INTERFACE_ASM // ATA reset ++ stwio r0,0(r1) // write to control register ++#endif ++#ifdef NA_ENET_ASM ++#ifdef NA_ENET_RESET_ASM ++ movia r1,NA_ENET_RESET_ASM // ethernet reset address ++ movui r2,1 // reset ++ stwio r2,0(r1) // ++#endif ++#ifdef NA_ENET_RESET_N_ASM ++ movia r1,NA_ENET_RESET_N_ASM // ethernet reset address ++ movui r2,1 // reset ++ stwio r2,0(r1) // ++#endif ++#endif ++ wrctl ienable,r0 // Mask off all possible interrupts ++ ++ //------------------------------------------------------ ++ // Zero out the .bss segment (uninitialized common data) ++ // ++ movia r2,__bss_start // presume nothing is between ++ movia r1,_end // the .bss and _end. ++1: ++ stb r0,0(r2) ++ addi r2,r2,1 ++ bne r1,r2,1b ++ ++ //------------------------------------------------------ ++ // Call main() with interrupts disabled ++ // ++ movia r1,status_extension // get the STATUS extension address ++ movi r2,PS_S_ASM // set initial mode = supervisor ++ stw r2,0(r1) ++ ++ movia r1,init_thread_union // set stack at top of the task union ++ addi sp,r1,THREAD_SIZE_ASM ++ movia r2,_current_thread // Remember current thread ++ stw r1,0(r2) ++ ++ movia r1,nios2_boot_init // save args r4-r7 passed from u-boot ++ callr r1 ++ ++ movia r1,main // call main as a subroutine ++ callr r1 ++ ++ //------------------------------------------------------------------ ++ // If we return from main, break to the oci debugger and buggered we are ++ // ++ break ++ ++ /* End of startup code */ ++.set at ++ ++ +diff --git a/arch/nios2nommu/kernel/init_task.c b/arch/nios2nommu/kernel/init_task.c +new file mode 100644 +index 0000000..867e8fb +--- /dev/null ++++ b/arch/nios2nommu/kernel/init_task.c +@@ -0,0 +1,69 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/kernel/init_task.c ++ * ++ * Ported from arch/m68knommu/kernel/init_task.c ++ * ++ * Copyright (C) 2003, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++static struct fs_struct init_fs = INIT_FS; ++static struct files_struct init_files = INIT_FILES; ++static struct signal_struct init_signals = INIT_SIGNALS(init_signals); ++static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); ++struct mm_struct init_mm = INIT_MM(init_mm); ++ ++EXPORT_SYMBOL(init_mm); ++ ++/* ++ * Initial task structure. ++ * ++ * All other task structs will be allocated on slabs in fork.c ++ */ ++__asm__(".align 2"); ++struct task_struct init_task = INIT_TASK(init_task); ++ ++ ++/* ++ * Initial thread structure. ++ * ++ * We need to make sure that this is 8192-byte aligned due to the ++ * way process stacks are handled. This is done by having a special ++ * "init_task" linker map entry.. ++ */ ++union thread_union init_thread_union ++ __attribute__((__section__(".data.init_task"))) = ++ { INIT_THREAD_INFO(init_task) }; ++ +diff --git a/arch/nios2nommu/kernel/io.c b/arch/nios2nommu/kernel/io.c +new file mode 100644 +index 0000000..e1b0b12 +--- /dev/null ++++ b/arch/nios2nommu/kernel/io.c +@@ -0,0 +1,143 @@ ++/*-------------------------------------------------------------------- ++ * ++ * Optimized IO string functions. ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++void insl(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned long read32; ++ ++ if ((unsigned long)dst & 2){ ++ /* Unaligned destination pointer, need to do ++ * two 16 bit writes for each read. ++ */ ++ unsigned short *p=(unsigned short*)dst; ++ while (count--){ ++ read32 = inl(port); ++ *p++ = read32 & 0xFFFF; ++ *p++ = read32 >> 16; ++ } ++ } ++ else { ++ unsigned long *p=(unsigned long*)dst; ++ while (count--) ++ *p++ = inl(port); ++ } ++} ++ ++void insw(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned long dst1=(unsigned long)dst; ++ if (count > 8) { ++ /* Long word align buffer ptr */ ++ if (dst1 & 2) { ++ *(unsigned short*)dst1 = inw(port); ++ dst1 += sizeof(unsigned short); ++ count--; ++ } ++ ++ /* Input pairs of short and store as longs */ ++ while (count >= 8) { ++ *((unsigned long *)dst1) = inw(port) + (inw(port) << 16); dst1+=sizeof(unsigned long); ++ *((unsigned long *)dst1) = inw(port) + (inw(port) << 16); dst1+=sizeof(unsigned long); ++ *((unsigned long *)dst1) = inw(port) + (inw(port) << 16); dst1+=sizeof(unsigned long); ++ *((unsigned long *)dst1) = inw(port) + (inw(port) << 16); dst1+=sizeof(unsigned long); ++ count -= 8; ++ } ++ } ++ ++ /* Input remaining shorts */ ++ while (count--) { ++ *((unsigned short *)dst1) = inw(port); ++ dst1 += sizeof(unsigned short); ++ } ++} ++ ++ ++void outsl(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned long src1=(unsigned long)src; ++ unsigned long write32; ++ ++ if (src1 & 2){ ++ /* Unaligned source pointer, need to read ++ * two 16 bit shorts before writing to register. ++ */ ++ while (count--){ ++ write32 = *(unsigned short *)src1; ++ src1+=sizeof(unsigned short); ++ write32 |= *((unsigned short *)src1) << 16; ++ src1+=sizeof(unsigned short); ++ outl(write32,port); ++ } ++ } ++ else { ++ while (count--) { ++ outl(*(unsigned long *)src1,port); ++ src1+=sizeof(unsigned long); ++ } ++ } ++} ++ ++void outsw(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned int lw; ++ unsigned long src1=(unsigned long)src; ++ ++ if (count > 8) { ++ /* Long word align buffer ptr */ ++ if (src1 & 2) { ++ outw( *(unsigned short *)src1, port ); ++ count--; ++ src1 += sizeof(unsigned short); ++ } ++ ++ /* Read long words and output as pairs of short */ ++ while (count >= 8) { ++ lw = *(unsigned long *)src1; ++ src1+=sizeof(unsigned long); ++ outw(lw, port); ++ outw((lw >> 16), port); ++ lw = *(unsigned long *)src1; ++ src1+=sizeof(unsigned long); ++ outw(lw, port); ++ outw((lw >> 16), port); ++ lw = *(unsigned long *)src1; ++ src1+=sizeof(unsigned long); ++ outw(lw, port); ++ outw((lw >> 16), port); ++ lw = *(unsigned long *)src1; ++ src1+=sizeof(unsigned long); ++ outw(lw, port); ++ outw((lw >> 16), port); ++ count -= 8; ++ } ++ } ++ ++ /* Output remaining shorts */ ++ while (count--) { ++ outw( *(unsigned short *)src1, port ); ++ src1 += sizeof(unsigned short); ++ } ++} +diff --git a/arch/nios2nommu/kernel/irq.c b/arch/nios2nommu/kernel/irq.c +new file mode 100644 +index 0000000..f1b2347 +--- /dev/null ++++ b/arch/nios2nommu/kernel/irq.c +@@ -0,0 +1,245 @@ ++/* ++ * linux/arch/$(ARCH)/irq.c -- general exception handling code ++ * ++ * Cloned from Linux/m68k. ++ * ++ * No original Copyright holder listed, ++ * Probabily original (C) Roman Zippel (assigned DJD, 1999) ++ * ++ * Copyright 1999-2000 D. Jeff Dionne, ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* table for system interrupt handlers */ ++irq_hand_t irq_list[NR_IRQS]; ++ ++/* The number of spurious interrupts */ ++volatile unsigned int num_spurious; ++ ++#define NUM_IRQ_NODES 16 ++static irq_node_t nodes[NUM_IRQ_NODES]; ++ ++void __init init_irq_proc(void) ++{ ++ /* Insert /proc/irq driver here */ ++} ++ ++static irqreturn_t default_irq_handler(int irq, void *ptr) ++{ ++#if 1 ++ printk(KERN_INFO "%s(%d): default irq handler vec=%d [0x%x]\n", ++ __FILE__, __LINE__, irq, irq); ++#endif ++ disable_irq(irq); ++ return(IRQ_NONE); ++} ++ ++/* ++ * void init_IRQ(void) ++ * ++ * Parameters: None ++ * ++ * Returns: Nothing ++ * ++ * This function should be called during kernel startup to initialize ++ * the IRQ handling routines. ++ */ ++ ++void __init init_IRQ(void) ++{ ++ int i; ++ ++ for (i = 0; i < NR_IRQS; i++) { ++ irq_list[i].handler = default_irq_handler; ++ irq_list[i].flags = IRQ_FLG_STD; ++ irq_list[i].dev_id = NULL; ++ irq_list[i].devname = NULL; ++ } ++ ++ for (i = 0; i < NUM_IRQ_NODES; i++) ++ nodes[i].handler = NULL; ++ ++ /* turn off all interrupts */ ++ clrimr(0); ++ ++#ifdef DEBUG ++ printk("init_IRQ done\n"); ++#endif ++} ++ ++irq_node_t *new_irq_node(void) ++{ ++ irq_node_t *node; ++ short i; ++ ++ for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) ++ if (!node->handler) ++ return node; ++ ++ printk (KERN_INFO "new_irq_node: out of nodes\n"); ++ return NULL; ++} ++ ++int request_irq(unsigned int irq, ++ irq_handler_t handler, ++ unsigned long flags, ++ const char *devname, ++ void *dev_id) ++{ ++ if (irq >= NR_IRQS) { ++ printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); ++ return -ENXIO; ++ } ++ ++ if (!(irq_list[irq].flags & IRQ_FLG_STD)) { ++ if (irq_list[irq].flags & IRQ_FLG_LOCK) { ++ printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n", ++ __FUNCTION__, irq, irq_list[irq].devname); ++ return -EBUSY; ++ } ++ if (flags & IRQ_FLG_REPLACE) { ++ printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n", ++ __FUNCTION__, devname, irq, irq_list[irq].devname); ++ return -EBUSY; ++ } ++ } ++ irq_list[irq].handler = handler; ++ irq_list[irq].flags = flags; ++ irq_list[irq].dev_id = dev_id; ++ irq_list[irq].devname = devname; ++ ++ setimr(1<= NR_IRQS) { ++ printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq); ++ return; ++ } ++ ++ if (irq_list[irq].dev_id != dev_id) ++ printk(KERN_ERR "%s: Removing probably wrong IRQ %d from %s\n", ++ __FUNCTION__, irq, irq_list[irq].devname); ++ ++ irq_list[irq].handler = default_irq_handler; ++ irq_list[irq].flags = IRQ_FLG_STD; ++ irq_list[irq].dev_id = NULL; ++ irq_list[irq].devname = NULL; ++ ++ clrimr(~(1< ++*/ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(fmt , ...) ++#endif ++ ++void *module_alloc(unsigned long size) ++{ ++ if (size == 0) ++ return NULL; ++ return vmalloc(size); ++} ++ ++ ++/* Free memory returned from module_alloc */ ++void module_free(struct module *mod, void *module_region) ++{ ++ vfree(module_region); ++ /* FIXME: If module_region == mod->init_region, trim exception ++ table entries. */ ++} ++ ++/* We don't need anything special. */ ++int module_frob_arch_sections(Elf_Ehdr *hdr, ++ Elf_Shdr *sechdrs, ++ char *secstrings, ++ struct module *mod) ++{ ++ return 0; ++} ++ ++int apply_relocate(Elf32_Shdr *sechdrs, ++ const char *strtab, ++ unsigned int symindex, ++ unsigned int relsec, ++ struct module *me) ++{ ++ printk(KERN_ERR "module %s: NO-ADD RELOCATION unsupported\n", ++ me->name); ++ return -ENOEXEC; ++} ++ ++ ++int apply_relocate_add (Elf32_Shdr *sechdrs, const char *strtab, ++ unsigned int symindex, unsigned int relsec, ++ struct module *mod) ++{ ++ unsigned int i; ++ Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; ++ ++ DEBUGP ("Applying relocate section %u to %u\n", relsec, ++ sechdrs[relsec].sh_info); ++ ++ for (i = 0; i < sechdrs[relsec].sh_size / sizeof (*rela); i++) { ++ /* This is where to make the change */ ++ uint32_t word; ++ uint32_t *loc ++ = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr ++ + rela[i].r_offset); ++ /* This is the symbol it is referring to. Note that all ++ undefined symbols have been resolved. */ ++ Elf32_Sym *sym ++ = ((Elf32_Sym *)sechdrs[symindex].sh_addr ++ + ELF32_R_SYM (rela[i].r_info)); ++ uint32_t v = sym->st_value + rela[i].r_addend; ++ ++ switch (ELF32_R_TYPE (rela[i].r_info)) { ++ case R_NIOS2_NONE: ++ break; ++ ++ case R_NIOS2_BFD_RELOC_32: ++ *loc += v; ++ break; ++ ++ case R_NIOS2_PCREL16: ++ v -= (uint32_t)loc + 4; ++ if ((int32_t)v > 0x7fff || ++ (int32_t)v < -(int32_t)0x8000) { ++ printk(KERN_ERR ++ "module %s: relocation overflow\n", ++ mod->name); ++ return -ENOEXEC; ++ } ++ word = *loc; ++ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f); ++ break; ++ ++ case R_NIOS2_CALL26: ++ if (v & 3) { ++ printk(KERN_ERR ++ "module %s: dangerous relocation\n", ++ mod->name); ++ return -ENOEXEC; ++ } ++ if ((v >> 28) != ((uint32_t)loc >> 28)) { ++ printk(KERN_ERR ++ "module %s: relocation overflow\n", ++ mod->name); ++ return -ENOEXEC; ++ } ++ *loc = (*loc & 0x3f) | ((v >> 2) << 6); ++ break; ++ ++ case R_NIOS2_HI16: ++ word = *loc; ++ *loc = ((((word >> 22) << 16) | ((v >>16) & 0xffff)) << 6) | ++ (word & 0x3f); ++ break; ++ ++ case R_NIOS2_LO16: ++ word = *loc; ++ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | ++ (word & 0x3f); ++ break; ++ ++ case R_NIOS2_HIADJ16: ++ { ++ Elf32_Addr word2; ++ ++ word = *loc; ++ word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff; ++ *loc = ((((word >> 22) << 16) | word2) << 6) | ++ (word & 0x3f); ++ } ++ break; ++ ++ default: ++ printk (KERN_ERR "module %s: Unknown reloc: %u\n", ++ mod->name, ELF32_R_TYPE (rela[i].r_info)); ++ return -ENOEXEC; ++ } ++ } ++ ++ return 0; ++} ++ ++int module_finalize(const Elf_Ehdr *hdr, ++ const Elf_Shdr *sechdrs, ++ struct module *me) ++{ ++ return 0; ++} ++ ++void module_arch_cleanup(struct module *mod) ++{ ++} +diff --git a/arch/nios2nommu/kernel/nios2_ksyms.c b/arch/nios2nommu/kernel/nios2_ksyms.c +new file mode 100644 +index 0000000..720f007 +--- /dev/null ++++ b/arch/nios2nommu/kernel/nios2_ksyms.c +@@ -0,0 +1,113 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/kernel/nios_ksyms.c ++ * ++ * Derived from Nios1 ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * vic - copied from v850 ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++//;dgt2;tmp; ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern void dump_thread(struct pt_regs *, struct user *); ++/* platform dependent support */ ++ ++EXPORT_SYMBOL(__ioremap); ++EXPORT_SYMBOL(iounmap); ++EXPORT_SYMBOL(dump_fpu); ++EXPORT_SYMBOL(dump_thread); ++ ++EXPORT_SYMBOL(kernel_thread); ++ ++/* Networking helper routines. */ ++EXPORT_SYMBOL(csum_partial_copy); ++ ++EXPORT_SYMBOL(memcpy); ++EXPORT_SYMBOL(memset); ++EXPORT_SYMBOL(memmove); ++ ++EXPORT_SYMBOL(__down); ++EXPORT_SYMBOL(__down_interruptible); ++EXPORT_SYMBOL(__down_trylock); ++EXPORT_SYMBOL(__up); ++ ++EXPORT_SYMBOL(get_wchan); ++ ++/* ++ * libgcc functions - functions that are used internally by the ++ * compiler... (prototypes are not correct though, but that ++ * doesn't really matter since they're not versioned). ++ */ ++extern void __gcc_bcmp(void); ++extern void __ashldi3(void); ++extern void __ashrdi3(void); ++extern void __cmpdi2(void); ++extern void __divdi3(void); ++extern void __divsi3(void); ++extern void __lshrdi3(void); ++extern void __moddi3(void); ++extern void __modsi3(void); ++extern void __muldi3(void); ++extern void __mulsi3(void); ++extern void __negdi2(void); ++extern void __ucmpdi2(void); ++extern void __udivdi3(void); ++extern void __udivmoddi4(void); ++extern void __udivsi3(void); ++extern void __umoddi3(void); ++extern void __umodsi3(void); ++ ++ /* gcc lib functions */ ++EXPORT_SYMBOL(__gcc_bcmp); ++EXPORT_SYMBOL(__ashldi3); ++EXPORT_SYMBOL(__ashrdi3); ++EXPORT_SYMBOL(__cmpdi2); ++EXPORT_SYMBOL(__divdi3); ++EXPORT_SYMBOL(__divsi3); ++EXPORT_SYMBOL(__lshrdi3); ++EXPORT_SYMBOL(__moddi3); ++EXPORT_SYMBOL(__modsi3); ++EXPORT_SYMBOL(__muldi3); ++EXPORT_SYMBOL(__mulsi3); ++EXPORT_SYMBOL(__negdi2); ++EXPORT_SYMBOL(__ucmpdi2); ++EXPORT_SYMBOL(__udivdi3); ++EXPORT_SYMBOL(__udivmoddi4); ++EXPORT_SYMBOL(__udivsi3); ++EXPORT_SYMBOL(__umoddi3); ++EXPORT_SYMBOL(__umodsi3); +diff --git a/arch/nios2nommu/kernel/nios_gdb_stub.c b/arch/nios2nommu/kernel/nios_gdb_stub.c +new file mode 100644 +index 0000000..103925b +--- /dev/null ++++ b/arch/nios2nommu/kernel/nios_gdb_stub.c +@@ -0,0 +1,1456 @@ ++// Modified for uClinux - Vic - Apr 2002 ++// From: ++ ++// File: nios_gdb_stub.c ++// Date: 2000 June 20 ++// Author dvb \ Altera Santa Cruz ++ ++#ifndef __KERNEL__ ++#include "nios.h" ++#else ++#include ++#include ++#include ++#endif ++ ++#include "nios_gdb_stub.h" ++ ++#define na_debug_peripheral_irq 8 ++ ++enum ++{ ++ na_BreakpointTrap = 3, ++ na_SingleStepTrap = 4, ++ na_StartGDBTrap = 5 ++}; ++ ++ ++#ifdef __KERNEL__ ++ ++extern int _etext; ++ ++static void puts( unsigned char *s ) ++{ ++ while(*s) { ++ while (!(nasys_printf_uart->np_uartstatus & np_uartstatus_trdy_mask)); ++ nasys_printf_uart->np_uarttxdata = *s++; ++ } ++} ++ ++#endif // __KERNEL__ ++ ++// -------------------------------- ++// Local Prototypes ++ ++#if GDB_DEBUG_PRINT ++ ++static void StringFit(char *s,int w); ++ ++// -------------------------------- ++// Debugging The Debugger ++ ++void GDB_RawMessage(char *s) ++ { ++ StringFit(s,32); ++ nr_pio_lcdwritescreen(s); ++ } ++#else ++ #define GDB_RawMessage(a,b,c) // define away to nothing ++#endif ++ ++#if GDB_DEBUG_PRINT ++void GDB_Print2(char *s,int n1,int n2) ++ { ++ char st[1000]; ++ ++ sprintf(st,s,n1,n2); ++ GDB_RawMessage(st); ++ } ++#else ++ #define GDB_Print2(a,b,c) // define away to nothing ++#endif ++ ++// If string is longer than w, cut out the middle. ++ ++#if GDB_DEBUG_PRINT ++int StringLen(char *s) ++ { ++ int l = 0; ++ ++ while(*s++) ++ l++; ++ return l; ++ } ++ ++static void StringFit(char *s,int w) ++ { ++ if(StringLen(s) > w) ++ { ++ int i; ++ ++ ++ w = w / 2; ++ ++ for(i = 0; i < w; i++) ++ { ++ s[i + w] = s[StringLen(s) - w + i]; ++ } ++ s[w + w] = 0; ++ } ++ } ++#endif ++ ++// --------------------------------------------- ++// Generic routines for dealing with ++// hex input, output, and parsing ++// (Adapted from other stubs.) ++ ++NiosGDBGlobals gdb = {0}; // not static: the ISR uses it! ++ ++static char dHexChars[16] = "0123456789abcdef"; ++ ++/* ++ * HexCharToValue -- convert a characters ++ * to its hex value, or -1 if not. ++ */ ++char HexCharToValue(char c) ++{ ++ char result=0; ++ ++ if(c >= '0' && c <= '9') ++ result = c - '0'; ++ else if(c >= 'a' && c <= 'f') ++ result = c - 'a' + 10; ++ else if(c >= 'A' && c <= 'F') ++ result = c - 'A' + 10; ++ else ++ result = -1; ++ return result; ++} ++ ++/* ++ * HexStringToValue -- convert a 2*byte_width string of characters ++ * to its little endian hex value, ++ * or -1 if not. ++ * This routine is for strings of hex values ++ */ ++unsigned long HexStringToValue(char *c, int byte_width) ++{ ++ unsigned long result=0; ++ unsigned char a,b; ++ int i=0; ++ ++ while (i < byte_width) ++ { ++ a = HexCharToValue(*c++); ++ if (a & 0x80) return a; ++ b = HexCharToValue(*c++); ++ if (b & 0x80) return b; ++ b = (a<<4) | (b&0x0f); ++ result |= b << (i*8); ++ i++; ++ } ++ return result; ++} ++ ++/* ++ * Hex2Value -- convert a non-hex char delimited string ++ * to its big endian hex value. ++ * This routine is for address and byte count values ++ */ ++ ++char *Hex2Value(char *hexIn, int *valueOut) ++ { ++ char c; ++ int digitValue; ++ int value = 0; ++ ++ while(1) ++ { ++ c = *hexIn; ++ digitValue = HexCharToValue(c); ++ if(digitValue < 0) ++ { ++ *valueOut = value; ++ return hexIn; ++ } ++ hexIn++; ++ value = (value << 4) + digitValue; ++ } ++ } ++ ++/* ++ * HexToMem -- convert a string to a specified ++ * number of bytes in memory. ++ * ++ * JMB -- make this thing a bit smarter so ++ * that it selects the byte width to ++ * write based on the number of bytes ++ * and the destination address alignment. ++ * This is to support writes to non-byte enabled ++ * peripheral registers...I don't like it. ++ * Beware! there are cases where it wont work ++ */ ++char *HexToMem(char *hexIn, char *memOut, int memByteCount) ++{ ++ int i; ++ unsigned long x; ++ short *memOutS=0; ++ long *memOutL=0; ++ int byte_width; ++ ++ //determine maximum byte width ++ if (((memByteCount%2) != 0) || (((unsigned int)memOut%2) != 0)) ++ byte_width = 1; ++ else if (((memByteCount % 4) != 0) || (((unsigned int)memOut % 4) != 0)) ++ { ++ byte_width = 2; ++ memOutS = (short *)memOut; ++ } ++ else ++ { ++ byte_width = 4; ++ memOutL = (long *)memOut; ++ } ++ for(i = 0; i < memByteCount; i+=byte_width) ++ { ++ x = HexStringToValue(hexIn,byte_width); ++ hexIn += byte_width*2; ++ switch (byte_width) ++ { ++ case 1: ++ *memOut++ = (unsigned char) 0x000000ff & x; ++ break; ++ case 2: ++ *memOutS++ = (unsigned short) 0x0000ffff & x; ++ break; ++ case 4: ++ *memOutL++ = x; ++ break; ++ default: ++ //How could this ever happen??? ++ break; ++ } ++ } ++ ++ return hexIn; ++} ++ ++char *MemToHex(char *memIn, char *hexOut, int memByteCount) ++{ ++ int i,j; ++ int byte_width; ++ unsigned long x=0; ++ unsigned short *memInS=0; ++ unsigned long *memInL=0; ++ ++ //determine maximum byte width ++ if (((memByteCount % 2) != 0) || (((unsigned int)memIn % 2) != 0)) ++ byte_width = 1; ++ else if (((memByteCount % 4) != 0) || (((unsigned int)memIn % 4) != 0)) ++ { ++ byte_width = 2; ++ memInS = (short *)memIn; ++ } ++ else ++ { ++ byte_width = 4; ++ memInL = (long *)memIn; ++ } ++ ++ for(i = 0; i < memByteCount; i+=byte_width) ++ { ++ switch (byte_width) ++ { ++ case 1: ++ x = *memIn++; ++ break; ++ case 2: ++ x = *memInS++; ++ break; ++ case 4: ++ x = *memInL++; ++ break; ++ default: ++ //How would we get here? ++ break; ++ } ++ ++ for (j=0; j>4]; ++ *hexOut++ = dHexChars[x&0x0000000f]; ++ x = x>>8; ++ } ++ } ++ ++ *hexOut = 0; ++ ++ return hexOut; ++} ++ ++//Send just the + or - to indicate ++//ACK or NACK ++void GDBPutAck (char ack) ++{ ++ if (gdb.comlink == ne_gdb_serial) ++ GDBPutChar (ack); ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++ else ++ { ++ if (gdb.host_ip_address != 0) ++ nr_plugs_send_to (gdb.gdb_eth_plug, &ack, 1, 0, ++ gdb.host_ip_address, ++ gdb.host_port_number); ++ } ++#endif ++#endif ++} ++ ++/* ++ * Once a $ comes in, use GetGDBPacket to ++ * retrieve a full gdb packet, and verify ++ * checksum, and reply + or -. ++ */ ++int GetGDBPacket(char *aBuffer) ++{ ++ int checksum=0; ++ int length=0; ++ char c; ++ int x=0; ++ ++ if (gdb.comlink == ne_gdb_serial) ++ { ++ while ((c = GDBGetChar ()) != '$') ; ++ ++startPacket: ++ length = 0; ++ checksum = 0; ++ while(((c = GDBGetChar()) != '#') && (length < kTextBufferSize)) ++ { ++ if(c == '$') ++ goto startPacket; ++ checksum += c; ++ aBuffer[length++] = c; ++ aBuffer[length] = 0; ++ } ++ ++ c = GDBGetChar(); ++ x = HexCharToValue(c) << 4; ++ c = GDBGetChar(); ++ x += HexCharToValue(c); ++ ++ ++ checksum &= 0xff; ++ ++ GDB_Print2("GetPacket %d",length,0); ++ } ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++ else ++ { ++ int srcidx; ++ // wait till beginning of packet ++ while (gdb.textBuffer[0] != '$') nr_plugs_idle(); ++startEPacket: ++ length = 0; ++ checksum = 0; ++ srcidx = 1; ++ ++ //loop until packet terminator ++ //leave enough room for the checksum at the end ++ while (((c = gdb.textBuffer[srcidx++]) != '#') && (srcidx < kTextBufferSize-2)) ++ { ++ if (c == '$') ++ goto startEPacket; ++ ++ checksum += c; ++ aBuffer[length++] = c; ++ } ++ ++ c = gdb.textBuffer[srcidx++]; ++ x = HexCharToValue(c) << 4; ++ c = gdb.textBuffer[srcidx++]; ++ x += HexCharToValue (c); ++ ++ aBuffer[length++] = 0; ++ ++ checksum &= 0xff; ++ ++ GDB_Print2("GetPacket %d",length,0); ++ } ++#endif ++#endif ++ ++ if(checksum != x) ++ { ++ GDBPutAck('-'); ++ length = 0; ++ } ++ else ++ { ++ GDBPutAck('+'); ++ } ++ return length; ++} ++ ++//Wait for acknowledgement ++//Should we have some way of timing out??? ++//return TRUE if ACK ++//return FALSE if NACK ++int GDBGetACK (void) ++{ ++ char c; ++ if (gdb.comlink == ne_gdb_serial) ++ { ++ while (1) ++ { ++ c = GDBGetChar (); ++ if (c == '+') return (1); ++ else if (c == '-') return (0); ++ } ++ ++ } ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++ else ++ { ++ gdb.ACKstatus = ne_gdb_ack_waiting; ++ while (1) ++ { ++ nr_plugs_idle (); ++ if (gdb.ACKstatus == ne_gdb_ack_acked) ++ { ++ gdb.ACKstatus = ne_gdb_ack_notwaiting; ++ return (1); ++ } ++ else if (gdb.ACKstatus == ne_gdb_ack_nacked) ++ { ++ gdb.ACKstatus = ne_gdb_ack_notwaiting; ++ return (0); ++ } ++ } ++ } ++#endif ++#endif ++ return(0); ++} ++ ++/* ++ * Send a packet, preceded by $, ++ * and followed by #checksum. ++ */ ++void PutGDBPacket(char *aBuffer) ++{ ++ int checksum; ++ char c; ++ char *origPtr; ++ int cnt=0; ++ ++ origPtr = aBuffer; // Remember in case we get a NACK ++ if (gdb.comlink == ne_gdb_serial) ++ { ++startPutSerial: ++ GDBPutChar('$'); ++ checksum = 0; ++ while((c = *aBuffer++) != 0) ++ { ++ checksum += c; ++ GDBPutChar(c); ++ } ++ GDBPutChar('#'); ++ GDBPutChar(dHexChars[(checksum >> 4) & 15]); ++ GDBPutChar(dHexChars[checksum & 15]); ++ ++ if (!GDBGetACK ()) ++ { ++ aBuffer = origPtr; ++ if (++cnt < GDB_RETRY_CNT) goto startPutSerial; ++ } ++ } ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++ else ++ { ++ if (gdb.host_ip_address != 0) ++ { ++ int i; ++ int result; ++ char c1; ++ ++ i = 0; ++ c = aBuffer[i]; ++ if (c==0) return; //there is no data in packet, so why bother sending ++ aBuffer[i++] = '$'; ++ checksum = 0; ++ do ++ { ++ checksum += c; ++ c1 = aBuffer[i]; ++ aBuffer[i++] = c; ++ c = c1; ++ } while (c != 0); ++ ++ aBuffer[i++] = '#'; ++ aBuffer[i++] = dHexChars[(checksum >> 4) & 15]; ++ aBuffer[i++] = dHexChars[checksum & 15]; ++ aBuffer[i++] = 0; ++startPutEth: ++ result = nr_plugs_send_to (gdb.gdb_eth_plug, aBuffer, i, 0, ++ gdb.host_ip_address, ++ gdb.host_port_number); ++ ++ if (!GDBGetACK ()) ++ { ++ if (++cnt < GDB_RETRY_CNT) goto startPutEth; ++ } ++ aBuffer[0] = 0; //clear packet to ++ } ++ } ++#endif ++#endif ++} ++ ++int PutTracePacket(char *aBuffer, int size) ++{ ++ int checksum; ++#ifdef ethernet_exists ++ char c; ++#endif ++ int i; ++ int cnt=0; ++ ++ if (gdb.comlink == ne_gdb_serial) ++ { ++startPutSerial: ++ GDBPutChar('$'); ++ checksum = 0; ++ for (i=0; i> 4) & 15]); ++ GDBPutChar(dHexChars[checksum & 15]); ++ ++ if (!GDBGetACK ()) ++ { ++ if (++cnt < GDB_RETRY_CNT) goto startPutSerial; ++ } ++ } ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++ else ++ { ++ int result; ++ char c1; ++ ++ checksum = 0; ++ c = '$'; ++ for (i=0; i> 4) & 15]; ++ aBuffer[i++] = dHexChars[checksum & 15]; ++ aBuffer[i++] = 0; ++ethResend: ++ if (gdb.host_ip_address != 0) ++ { ++ result = nr_plugs_send_to (gdb.gdb_eth_plug, aBuffer, i, 0, ++ gdb.host_ip_address, ++ gdb.host_port_number); ++ } ++ if (!GDBGetACK ()) ++ { ++ if (++cnt < GDB_RETRY_CNT) goto ethResend; ++ } ++ aBuffer[0]=0; ++ } ++#endif ++#endif ++ if (cnt < GDB_RETRY_CNT) return 1; ++ else return 0; ++} ++ ++void PutGDBOKPacket(char *aBuffer) ++ { ++ aBuffer[0] = 'O'; ++ aBuffer[1] = 'K'; ++ aBuffer[2] = 0; ++ PutGDBPacket(aBuffer); ++ } ++ ++#if nasys_debug_core ++ ++//some defines used exclusively for TRACE data xfer ++//stepsize is the ascii hex step value i.e. twice the binary length ++#define stepsize (2*(2*sizeof(int) + sizeof (char))) ++#define MAX_TRACE_BYTES (((int)((2*MAX_DATA_SIZE-2)/stepsize))*stepsize) ++ ++int Trace_Read_Intercept (char *aBuffer) ++{ ++ int cnt=0; ++ unsigned int data; ++ unsigned char code; ++ int byteCount; ++ unsigned char *w; ++ unsigned short dataAccumulate; ++ int status; ++ ++ w = aBuffer; ++ w++; //skip past the m ++ if (*w++ == 't') //see if this is a special "memory trace" packet ++ { ++ w = Hex2Value(w,&byteCount); //get the number of bytes to transfer ++ ++ //turn byteCount to a multiple of stepsize ++ byteCount = ((int)(byteCount/stepsize))*stepsize; ++ ++ //wait until fifo empties ++ nm_debug_get_reg(status, np_debug_write_status); ++ while (status&np_debug_write_status_writing_mask) nm_debug_get_reg(status,np_debug_write_status); ++ ++ // loop through total size ++ while (byteCount > 0) ++ { ++ w=aBuffer; //reset w to beginning of buffer ++ ++ //calculate the number of bytes in this packet ++ if (byteCount > MAX_TRACE_BYTES) dataAccumulate = MAX_TRACE_BYTES; ++ else dataAccumulate = byteCount; ++ ++ //insert data size at beginning of packet ++ w = MemToHex((char *)&dataAccumulate, w, sizeof (dataAccumulate)); ++ ++ byteCount -= dataAccumulate; //decrement byteCount ++ ++ // accumulate a full buffer ++ for (cnt=0; cnt MAX_DATA_SIZE) byteCount = MAX_DATA_SIZE; ++ ++ // mA,L -- request memory ++ w = aBuffer; ++ w = MemToHex((char *)startAddr,w,byteCount); ++ PutGDBPacket(aBuffer); ++ } ++ ++void DoGDBCommand_M(char *aBuffer) ++ { ++ char *w; ++ int startAddr,byteCount; ++ ++ w = aBuffer; ++ w++; // past 'M' ++ w = Hex2Value(w,&startAddr); ++ w++; // past ',' ++ w = Hex2Value(w,&byteCount); ++ w++; // past ':' ++ ++ GDB_Print2("M from %x to %x",startAddr,byteCount); ++ ++ // MA,L:values -- write to memory ++ ++ w = HexToMem(w,(char *)startAddr,byteCount); ++ ++ // Send "OK" ++ PutGDBOKPacket(aBuffer); ++ } ++ ++int Debug_Read_Intercept (char *aBuffer) ++{ ++ unsigned int data; ++ int index; ++ unsigned char *w; ++ ++ w = aBuffer; ++ w++; //skip past the g ++ if (*w++ == 'g') //see if this is a special "register read" packet ++ { ++ w = Hex2Value(w,&index); //get the index of the register to be read ++ ++ nm_debug_get_reg (data, index); ++ ++ //assemble the output packet ++ w=aBuffer; //reset w to beginning of buffer ++ w = MemToHex((char *)&data, w, sizeof (data)); ++ *w++ = 0; ++ ++ //now send it ++ PutTracePacket (aBuffer,sizeof (data) * 2); ++ ++ return 1; ++ } ++ return 0; ++} ++ ++// Return the values of all the registers ++void DoGDBCommand_g(NiosGDBGlobals *g) ++ { ++ char *w; ++ ++ if (Debug_Read_Intercept (g->textBuffer)) return; ++ ++ w = g->textBuffer; ++ ++ w = MemToHex((char *)(&g->registers),w,sizeof(g->registers)); ++ PutGDBPacket(g->textBuffer); ++ GDB_Print2("Sent Registers",0,0); ++ } ++ ++int Debug_Write_Intercept (char *aBuffer) ++{ ++ unsigned int data; ++ int index; ++ unsigned char *w; ++ ++ w = aBuffer; ++ w++; //skip past the g ++ if (*w++ == 'g') //see if this is a special "register read" packet ++ { ++ w = Hex2Value(w,&index); //get the index of the register to be written ++ w++; // past ',' ++ w = Hex2Value(w,&data); ++ ++ nm_debug_set_reg (data, index); ++ ++ //now send it ++ // Send "OK" ++ PutGDBOKPacket(aBuffer); ++ ++ return 1; ++ } ++ return 0; ++} ++ ++void DoGDBCommand_G(NiosGDBGlobals *g) ++ { ++ char *w; ++ ++ if (Debug_Write_Intercept (g->textBuffer)) return; ++ ++ w = g->textBuffer; ++ w++; // skip past 'G' ++ w = HexToMem(w,(char *)(&g->registers), sizeof(g->registers) ); ++ ++ // Send "OK" ++ PutGDBOKPacket(g->textBuffer); ++ ++ GDB_Print2("Received Registers",0,0); ++ } ++ ++// Return last signal value ++void DoGDBCommand_qm(NiosGDBGlobals *g) ++ { ++ char *w; ++ ++ w = g->textBuffer; ++ ++ *w++ = 'S'; ++ *w++ = '2'; ++ *w++ = '3'; // make up a signal for now... ++ *w++ = 0; ++ PutGDBPacket(g->textBuffer); ++ } ++ ++void DoGDBCommand_q(NiosGDBGlobals *g) ++{ ++#ifdef na_ssram_detect_in ++ short int* ssram_exists; ++#endif ++ char *w; ++ w = g->textBuffer; ++ ++ w++; /* skip past the q */ ++ switch (*w) { ++ case ('A'): ++ w = g->textBuffer; ++ ++ /* handle intialization information */ ++ /* is nios_ocd available? */ ++#ifdef nasys_debug_core ++ *w++ = nasys_debug_core + '0'; ++#else ++ *w++ = '0'; ++#endif ++ *w++ = ','; ++ ++ /* determine if the SSRAM debugger board is ++ * physically present */ ++#ifdef na_ssram_detect_in ++ ssram_exists = (short int*) na_ssram_detect_in; ++ *w++ = !(*ssram_exists) + '0'; ++#else ++ *w++ = '0'; ++#endif ++ *w++ = ','; ++ ++ /* print out the max size of a trace packet */ ++#if nasys_debug_core ++ sprintf (w, "%04x", MAX_TRACE_BYTES); ++#else ++ sprintf (w, "0000"); ++#endif ++ ++ break; ++ case ('B'): ++ w = g->textBuffer; ++ ++ /* returns 1 if it was an OCD interrupt ++ * returns 0 if it was software breakpoint */ ++ if (gdb.trapNumber == nasys_debug_core_irq) { ++ *w++ = '1'; ++ } else { ++ *w++ = '0'; ++ } ++ ++ *w++ = 0; ++ break; ++ default: ++ w = g->textBuffer; ++ ++ *w = 0; ++ break; ++ } ++ ++ PutGDBPacket(g->textBuffer); ++} ++ ++ ++void GDBInsertBreakpoint(NiosGDBGlobals *g,short *address) ++ { ++ NiosGDBBreakpoint *b; ++ ++ GDB_Print2("breakpoint 0x%x",(int)address,0); ++ if(g->breakpointCount < kMaximumBreakpoints) ++ { ++ b = &g->breakpoint[g->breakpointCount++]; ++ b->address = address; ++ b->oldContents = *b->address; ++ *b->address = 0x7904; ++ } ++ } ++ ++void GDBRemoveBreakpoints(NiosGDBGlobals *g) ++ { ++ NiosGDBBreakpoint *b; ++ int i; ++ ++ for(i = 0; i < g->breakpointCount; i++) ++ { ++ b = &g->breakpoint[i]; ++ *b->address = b->oldContents; ++ b->address = 0; ++ } ++ ++ g->breakpointCount = 0; ++ } ++ ++int NiosInstructionIsTrap5(unsigned short instruction) ++ { ++ return instruction == 0x7905; ++ } ++ ++int NiosInstructionIsPrefix(unsigned short instruction) ++ { ++ return (instruction >> 11) == 0x13; ++ } ++ ++int NiosInstructionIsSkip(unsigned short instruction) ++ { ++ int op6; ++ int op11; ++ ++ op6 = (instruction >> 10); ++ op11 = (instruction >> 5); ++ ++ return (op6 == 0x14 // SKP0 ++ || op6 == 0x15 // SKP1 ++ || op11 == 0x3f6 // SKPRz ++ || op11 == 0x3f7 // SKPS ++ || op11 == 0x3fa); // SKPRnz ++ } ++ ++int NiosInstructionIsBranch(unsigned short instruction,short *pc,short **branchTargetOut) ++ { ++ int op4; ++ int op7; ++ int op10; ++ short *branchTarget = 0; ++ int result = 0; ++ ++ op4 = (instruction >> 12); ++ op7 = (instruction >> 9); ++ op10 = (instruction >> 6); ++ ++ if(op4 == 0x08) // BR, BSR ++ { ++ int offset; ++ ++ result = 1; ++ offset = instruction & 0x07ff; ++ if(offset & 0x400) // sign extend ++ offset |= 0xffffF800; ++ branchTarget = pc + offset + 1; // short * gets x2 scaling automatically ++ } ++ else if(op10 == 0x1ff) // JMP, CALL ++ { ++ result = 1; ++ branchTarget = (short *)(gdb.registers.r[instruction & 31] * 2); ++ } ++ else if(op7 == 0x3d) // JMPC, CALLC ++ { ++ result = 1; ++ branchTarget = pc + 1 + (instruction & 0x0ffff); ++#ifdef __nios32__ ++ branchTarget = (short *)((int)branchTarget & 0xffffFFFc); // align 32... ++#else ++ branchTarget = (short *)((int)branchTarget & 0xFFFe); // align 16... ++#endif ++ branchTarget = (short *)(*(int *)branchTarget); ++ } ++ ++ if(branchTargetOut) ++ *branchTargetOut = branchTarget; ++ ++ return result; ++ } ++ ++// ------------------------- ++// Step at address ++// ++// "stepping" involves inserting a ++// breakpoint at some reasonable ++// spot later than the current program ++// counter ++// ++// On the Nios processor, this is ++// nontrivial. For example, we should ++// not break up a PFX instruction. ++ ++void DoGDBCommand_s(NiosGDBGlobals *g) ++ { ++ char *w; ++ int x; ++ short *pc; ++ short *branchTarget; ++ unsigned short instruction; ++ int stepType; ++ ++ /* ++ * First, if there's an argument to the packet, ++ * set the new program-counter value ++ */ ++ ++ w = g->textBuffer; ++ w++; ++ if(HexCharToValue(*w) >= 0) ++ { ++ w = Hex2Value(w,&x); ++ g->registers.pc = x; ++ } ++ ++ /* ++ * Scan forward to see what the ++ * most appropriate location(s) for ++ * a breakpoint will be. ++ * ++ * The rules are: ++ * 1. If *pc == PFX, break after modified instruction. ++ * 2. If *pc == BR,BSR,JMP,CALL, break at destination ++ * 3. If *pc == SKIP, break right after SKIP AND after optional instruction, ++ which might, of course, be prefixed. ++ * 4. Anything else, just drop in the breakpoint. ++ */ ++ ++ pc = (short *)(int)g->registers.pc; ++ ++ instruction = *pc; ++ stepType = 0; ++ ++ if(NiosInstructionIsPrefix(instruction)) ++ { ++ /* ++ * PFX instruction: skip til after it ++ */ ++ while(NiosInstructionIsPrefix(instruction)) ++ { ++ pc++; ++ instruction = *pc; ++ } ++ ++ GDBInsertBreakpoint(g,pc + 1); ++ stepType = 1; ++ } ++ else if(NiosInstructionIsBranch(instruction,pc,&branchTarget)) ++ { ++ GDBInsertBreakpoint(g,branchTarget); ++ stepType = 2; ++ } ++ else if(NiosInstructionIsSkip(instruction)) ++ { ++ short *pc2; ++ stepType = 3; ++ ++ /* ++ * Skip gets to breaks: one after the skippable instruction, ++ * and the skippable instruction itself. ++ * ++ * Since Skips know how to skip over PFX's, we have to, too. ++ */ ++ pc2 = pc; // the Skip instruction ++ do ++ { ++ pc2++; ++ } while(NiosInstructionIsPrefix(*pc2)); ++ // pc2 now points to first non-PFX after Skip ++ GDBInsertBreakpoint(g,pc2+1); ++ GDBInsertBreakpoint(g,pc+1); ++ } ++ else ++ GDBInsertBreakpoint(g,pc+1); // the genericest case ++ ++ GDB_Print2("Program Steppingat 0x%x (%d)",g->registers.pc,stepType); ++ } ++ ++// ----------------------------- ++// Continue at address ++ ++void DoGDBCommand_c(NiosGDBGlobals *g) ++ { ++ char *w; ++ int x; ++ w = g->textBuffer; ++ ++ w++; // past command ++ ++ // Anything in the packet? if so, ++ // use it to set the PC value ++ ++ if(HexCharToValue(*w) >= 0) ++ { ++ w = Hex2Value(w,&x); ++ g->registers.pc = x; ++ } ++ ++ GDB_Print2("Program Running at 0x%x",g->registers.pc,0); ++ } ++ ++// ---------------------- ++// Kill ++ ++void DoGDBCommand_k(NiosGDBGlobals *g) ++ { ++ return; ++ } ++ ++ ++/* ++ * If we've somehow skidded ++ * to a stop just after a PFX instruction ++ * back up the program counter by one. ++ * ++ * That way, we can't end up with an accidentally-unprefixed ++ * instruction. ++ * ++ * We do this just before we begin running ++ * again, so that when the host queries our ++ * registers, we report the place we actually ++ * stopped. ++ */ ++ ++void MaybeAdjustProgramCounter(NiosGDBGlobals *g) ++ { ++ short instruction; ++ if(g->registers.pc) ++ { ++ instruction = *(short *)(int)(g->registers.pc - 2); ++ if(NiosInstructionIsPrefix(instruction)) ++ g->registers.pc -= 2; ++ else ++ { ++ // If the *current* instruction is Trap5, we must skip it! ++ instruction = *(short *)(int)(g->registers.pc); ++ if(NiosInstructionIsTrap5(instruction)) ++ g->registers.pc += 2; ++ } ++ } ++ } ++ ++/* ++ * GDBMainLoop - this is the main processing loop ++ * for the GDB stub. ++ */ ++void GDBMainLoop (void) ++{ ++ while(1) ++ { ++ if (GetGDBPacket(gdb.textBuffer) > 0) ++ { ++ ++ GDB_Print2(gdb.textBuffer,0,0); ++ switch(gdb.textBuffer[0]) ++ { ++ case 's': ++ DoGDBCommand_s(&gdb); ++ goto startRunning; ++ break; ++ ++ case 'c': // continue ++ DoGDBCommand_c(&gdb); ++ ++ // if the PC is something other than 0, it's ++ // probably ok to exit and go there ++ ++ startRunning: ++ if(gdb.registers.pc) ++ { ++ MaybeAdjustProgramCounter(&gdb); ++ return; ++ } ++ break; ++ ++ case 'm': // memory read ++ DoGDBCommand_m(gdb.textBuffer); ++ break; ++ ++ case 'M': // memory set ++ DoGDBCommand_M(gdb.textBuffer); ++ break; ++ ++ case 'g': // registers read ++ DoGDBCommand_g(&gdb); ++ break; ++ ++ case 'G': //registers set ++ DoGDBCommand_G(&gdb); ++ break; ++ ++ case 'k': //kill process ++ DoGDBCommand_k(&gdb); ++ break; ++ ++ case '?': // last exception value ++ DoGDBCommand_qm(&gdb); ++ break; ++ ++ case 'q': ++ DoGDBCommand_q(&gdb); ++ break; ++ ++ default: // return empty packet, means "yeah yeah". ++ gdb.textBuffer[0] = 0; ++ PutGDBPacket(gdb.textBuffer); ++ break; ++ } ++ } ++ } ++ ++} ++ ++// ----------main------------ ++void GDBMain(void) ++{ ++ int i; ++ ++ for(i = 0; i < kTextBufferSize; i++) ++ gdb.textBuffer[i] = i; ++ ++ GDBRemoveBreakpoints(&gdb); ++ ++#ifdef __KERNEL__ ++/* ++ * Inform the user that they need to add the symbol file for the application ++ * that is just starting up. Display the .text .data .bss regions. ++ */ ++ if (gdb.trapNumber == 5) { ++ extern struct task_struct *_current_task; ++ sprintf(gdb.textBuffer, ++ "\r\n\nGDB: trap 5 at 0x%08lX", gdb.registers.pc); ++ puts(gdb.textBuffer); ++ if (_current_task) { ++ if ( _current_task->mm->start_code > _etext ) ++ sprintf(gdb.textBuffer, ++ "\r\nGDB: Enter the following command in the nios-elf-gdb Console Window:" ++ "\r\nGDB: add-symbol-file %s.abself 0x%08lX 0x%08lX 0x%08lX\r\n\n", ++ _current_task->comm, ++ (unsigned long)_current_task->mm->start_code, ++ (unsigned long)_current_task->mm->start_data, ++ (unsigned long)_current_task->mm->end_data ); ++ else ++ sprintf(gdb.textBuffer, ++ ", kernel process: %s\r\n", _current_task->comm ); ++ } else ++ sprintf(gdb.textBuffer, ++ ", kernel process unknown\r\n" ); ++ puts(gdb.textBuffer); ++ } ++#endif ++ ++ // Send trapnumber for breakpoint encountered. No other signals. ++ ++ gdb.textBuffer[0] = 'S'; ++ gdb.textBuffer[1] = '0'; ++ ++#if nasys_debug_core ++ if (gdb.trapNumber == nasys_debug_core_irq) ++ { ++ /* gdb.textBuffer[2] = '8'; */ ++ gdb.textBuffer[2] = '5'; ++ } ++ else ++ { ++ gdb.textBuffer[2] = '5'; ++ } ++#else ++ gdb.textBuffer[2] = '5'; ++#endif ++ gdb.textBuffer[3] = 0; ++ PutGDBPacket(gdb.textBuffer); ++ ++ GDB_Print2("Trap %2d At 0x%x", ++ gdb.trapNumber,gdb.registers.pc); ++// printf ("Trap %d at 0x%x\n",gdb.trapNumber,gdb.registers.pc); ++// for (i=0;i<32;i++) printf (" register[%d] = 0x%x\n",i,gdb.registers.r[i]); ++ ++ GDBMainLoop (); ++} ++ ++// +---------------------------------- ++// | gdb_eth_proc -- gets called for udp packets ++// | from the host bound for gdb stub ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++int gdb_eth_proc(int plug_handle, ++ void *context, ++ ns_plugs_packet *p, ++ void *payload, ++ int payload_length) ++{ ++ int i; ++ char *buf = (char *)payload; ++ // if this is a stop request, set a flag to stop after nr_plugs_idle ++ // leave it up to the host to prevent stops from being sent while stub is running??? ++ ++ if (*buf == 3) gdb.stop = 1; ++ ++ // if we're waiting for an ack, check that here ++ if (gdb.ACKstatus == ne_gdb_ack_waiting) ++ { ++ if (buf[0] == '+') ++ { ++ gdb.ACKstatus = ne_gdb_ack_acked; ++ return 0; ++ } ++ else if (buf[0] == '-') ++ { ++ gdb.ACKstatus = ne_gdb_ack_nacked; ++ return 0; ++ } ++ } ++ strcpy (gdb.textBuffer, buf); //all commands should be zero terminated strings ++ ++ gdb.textBuffer[payload_length] = 0; //terminate string ++ ++ gdb.host_ip_address=((ns_plugs_ip_packet *)(p[ne_plugs_ip].header))->source_ip_address; ++ gdb.host_port_number=((ns_plugs_udp_packet *)(p[ne_plugs_udp].header))->source_port; ++ ++ return 0; ++} ++ ++int nr_dbg_plugs_idle (void) ++{ ++ int result; ++ ++ result = nr_plugs_idle (); ++ if (gdb.stop) ++ { ++ gdb.stop = 0; ++//;dgt2;tmp; asm ("TRAP #5"); ++ } ++ return result; ++} ++#endif ++#endif ++ ++ ++/* ++ * int main(void) ++ * ++ * All we really do here is install our trap # 3, ++ * and call it once, so that we're living down in ++ * the GDBMain, trap handler. ++ */ ++ ++extern int StubBreakpointHandler; ++extern int StubHarmlessHandler; ++#if nasys_debug_core ++extern int StubHWBreakpointHandler; ++#endif ++#ifdef nasys_debug_uart ++extern int StubUartHandler; ++#endif ++ ++void gdb_local_install(int active) ++{ ++ unsigned int *vectorTable; ++ unsigned int stubBreakpointHandler; ++ unsigned int stubHarmlessHandler; ++#if nasys_debug_core ++ unsigned int stubHWBreakpointHandler; ++#endif ++ ++ gdb.breakpointCount = 0; ++ gdb.textBuffer[0] = 0; ++ ++ vectorTable = (int *)nasys_vector_table; ++ stubBreakpointHandler = ( (unsigned int)(&StubBreakpointHandler) ) >> 1; ++ stubHarmlessHandler = ( (unsigned int)(&StubHarmlessHandler) ) >> 1; ++#if nasys_debug_core ++ stubHWBreakpointHandler = ( (unsigned int)(&StubHWBreakpointHandler) ) >> 1; ++#endif ++ ++ /* ++ * Breakpoint & single step both go here ++ */ ++ vectorTable[na_BreakpointTrap] = stubBreakpointHandler; ++ vectorTable[na_SingleStepTrap] = stubBreakpointHandler; ++ vectorTable[na_StartGDBTrap] = active ? stubBreakpointHandler : stubHarmlessHandler; ++ /* ++ * If it exists, Hardware Breakpoint has a different entry point ++ */ ++#if nasys_debug_core ++ vectorTable[na_debug_peripheral_irq] = stubHWBreakpointHandler; ++#endif ++ ++#ifndef __KERNEL__ ++#ifdef nasys_debug_uart ++ if (gdb.comlink == ne_gdb_serial) ++ { ++ np_uart *uart = (np_uart *)nasys_debug_uart; ++ unsigned int stubUartHandler = ((unsigned int)(&StubUartHandler)) >> 1; ++ ++ vectorTable[nasys_debug_uart_irq] = stubUartHandler; //set Uart int vector ++ uart->np_uartcontrol = np_uartcontrol_irrdy_mask; //enable Rx intr ++ } ++#endif ++#endif ++} ++ ++void nios_gdb_install(int active) ++{ ++ gdb.comlink = ne_gdb_serial; ++ gdb_local_install (active); ++} ++ ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++void nios_gdb_install_ethernet (int active) ++{ ++ int result; ++ host_16 host_port = GDB_ETH_PORT; ++ ++ gdb.comlink = ne_gdb_ethernet; ++ gdb_local_install (active); ++ ++ result = nr_plugs_create (&gdb.gdb_eth_plug, ne_plugs_udp, host_port, gdb_eth_proc, 0, 0); ++ //if unabled to open ethernet plug, switch back to default serial interface ++ if (result) ++ { ++ printf ("nr_plugs_create failed %d\n",result); ++ gdb.comlink = ne_gdb_serial; ++ return; ++ } ++ result = nr_plugs_connect (gdb.gdb_eth_plug, 0, -1, -1); ++ if (result) ++ { ++ printf ("nr_plugs_connect fialed %d\n",result); ++ gdb.comlink = ne_gdb_serial; ++ return; ++ } ++} ++#endif ++#endif ++ ++#ifdef nios_gdb_breakpoint ++ #undef nios_gdb_breakpoint ++#endif ++ ++void nios_gdb_breakpoint(void) ++ { ++ /* ++ * If you arrived here, you didn't include ++ * the file "nios_peripherals.h", which ++ * defines nios_gdb_breakpoint as a ++ * macro that expands to TRAP 5. ++ * ++ * (No problem, you can step out ++ * of this routine.) ++ */ ++//;dgt2;tmp; asm("TRAP 5"); ++ } ++ ++// end of file +diff --git a/arch/nios2nommu/kernel/nios_gdb_stub.h b/arch/nios2nommu/kernel/nios_gdb_stub.h +new file mode 100644 +index 0000000..3900109 +--- /dev/null ++++ b/arch/nios2nommu/kernel/nios_gdb_stub.h +@@ -0,0 +1,105 @@ ++// file: nios_gdb_stub.h ++// Author: Altera Santa Cruz \ 2000 ++// ++// You can modify this header file to ++// enable some features useful for ++// debugging the debugger. They're ++// good features also to just show ++// signs of life on your Nios board. ++// But they consume valuable peripherals! ++// ++// The 'GDB_DEBUG_PRINT' option ties ++// up the LCD living on the 5v port, ++// showing useful internals of the stub. ++// ++// dvb@altera.com ++// ++ ++#ifdef ETHER_DEBUG ++#ifdef na_enet ++#define ethernet_exists ++#endif ++#endif ++ ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++#include "plugs.h" ++#endif ++#endif ++ ++#define MAX_DATA_SIZE 650 ++#define kTextBufferSize ((2*MAX_DATA_SIZE)+4) ++#define kMaximumBreakpoints 4 ++#define GDB_ETH_PORT 7070 ++#define GDB_WHOLE_PACKET 0 ++#define GDB_SKIP_FIRST 1 ++#define GDB_RETRY_CNT 3 ++ ++/* ++ * This register structure must match ++ * its counterpart in the GDB host, since ++ * it is blasted across in byte notation. ++ */ ++typedef struct ++ { ++ int r[32]; ++ long pc; ++ short ctl0; ++ short ctl1; ++ short ctl2; ++ short ctl3; ++ } NiosGDBRegisters; ++ ++typedef struct ++ { ++ short *address; ++ short oldContents; ++ } NiosGDBBreakpoint; ++ ++typedef struct ++ { ++ NiosGDBRegisters registers; ++ int trapNumber; // stashed by ISR, to distinguish types ++ char textBuffer[kTextBufferSize]; ++ int breakpointCount; // breakpoints used for stepping ++ int comlink; ++ int stop; ++ int gdb_eth_plug; ++ NiosGDBBreakpoint breakpoint[kMaximumBreakpoints]; ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++ volatile int ACKstatus; ++ net_32 host_ip_address; ++ net_16 host_port_number; ++#endif ++#endif ++ } NiosGDBGlobals; ++ ++#ifdef ETHER_DEBUG ++#ifdef ethernet_exists ++enum ++{ ++ ne_gdb_ack_notwaiting, ++ ne_gdb_ack_waiting, ++ ne_gdb_ack_acked, ++ ne_gdb_ack_nacked ++}; ++#endif ++#endif ++ ++enum ++{ ++ ne_gdb_serial, ++ ne_gdb_ethernet ++}; ++ ++#ifndef GDB_DEBUG_PRINT ++ #define GDB_DEBUG_PRINT 0 ++#endif ++ ++void GDB_Main(void); // initialize gdb and begin. ++ ++char GDBGetChar(void); ++void GDBPutChar(char c); ++void GDB_Print2(char *s,int v1,int v2); ++ +diff --git a/arch/nios2nommu/kernel/nios_gdb_stub_io.c b/arch/nios2nommu/kernel/nios_gdb_stub_io.c +new file mode 100644 +index 0000000..e0d8f82 +--- /dev/null ++++ b/arch/nios2nommu/kernel/nios_gdb_stub_io.c +@@ -0,0 +1,39 @@ ++// Modified for uClinux - Vic - Apr 2002 ++// From: ++ ++// file: nios_gdb_stub_IO.c ++// ++// Single character I/O for Nios GDB Stub ++ ++#ifndef __KERNEL__ ++#include "nios.h" ++#else ++#include ++#endif ++ ++#include "nios_gdb_stub.h" ++ ++#ifdef nasys_debug_uart ++ #define GDB_UART nasys_debug_uart ++#endif ++ ++char GDBGetChar(void) ++{ ++ char c = 0; ++ ++#ifdef GDB_UART ++ while( (c = (char)nr_uart_rxchar(GDB_UART)) < 0 ) ++ ; ++#endif ++ ++ return c; ++} ++ ++void GDBPutChar(char c) ++{ ++#ifdef GDB_UART ++ nr_uart_txchar(c, GDB_UART); ++#endif ++} ++ ++// End of file +diff --git a/arch/nios2nommu/kernel/nios_gdb_stub_isr.S b/arch/nios2nommu/kernel/nios_gdb_stub_isr.S +new file mode 100644 +index 0000000..c4af09a +--- /dev/null ++++ b/arch/nios2nommu/kernel/nios_gdb_stub_isr.S +@@ -0,0 +1,99 @@ ++/*-------------------------------------------------------------------- ++ * ++ * Assembly language portions of Nios GDB Stub ++ * ++ * arch\nios2nommu\kernel\switch.S ++ * ++ * Derived from Nios1 ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Modified for uClinux - Vic - Apr 2002 ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++//;dgt2;tmp; ++ ++ .equ ethernet_exists, 1 ++ ++ ++ .equ gdbRegistersGeneral,0 ++ .equ gdbRegistersPC,32 ++ .equ gdbRegistersCtl0Ctl1,33 ++ .equ gdbRegistersCtl2Ctl3,34 ++ .equ gdbTrapNumber,35 ; ISR can report trap number here ++ ++ ++ .text ++ ++ .global StubBreakpointHandler ++ .global StubHarmlessHandler ++ .global StubButtonHandler ++ .global StubHWBreakpointHandler ++ .global GDBMain ++ ++ .comm _gdb_stub_stack,1024,4 ; Local stack, statically allocated. ++ .equ gdbStubStacktop,_gdb_stub_stack+992 ++ ++ ++StubHarmlessHandler: ++//;dgt2;tmp ++ ++ .equ gdbBreakChar,0x3 ++ .global StubUartHandler ++ ++StubUartHandler: ++//;dgt2;tmp ++ ++StubUartRx: ++//;dgt2;tmp ++ ++StubHWBreakpointHandler: ++//;dgt2;tmp ++ ++StubBreakpointHandler: ++//;dgt2;tmp ++ ++#ifdef __KERNEL__ ++;---------------------------------------- ++; Name: nr_uart_rxchar ++; Description: Read character if available ++; Input: %o0: UART base to use ++; Output: %o0 = character 0-0xff, or -1 if none present ++; Side Effects: %g0 & %g1 altered ++; CWP Depth: 0 ++; ++ ++ .global nr_uart_rxchar ++nr_uart_rxchar: ++//;dgt2;tmp ++ ++ ++;---------------------------------------- ++; Name: nr_uart_txchar ++; Description: Send a single byte out the UART ++; Input: %o0 = A character ++; %o1 = the UART to use, 0 for default ++; Output: none ++; Side Effects: %g0 & %g1 altered, CPU waits for UART ++; CWP Depth: 0 ++; ++ ++; nr_uart_txchar ++ .global nr_uart_txchar ++nr_uart_txchar: ++//;dgt2;tmp ++ ++#endif +diff --git a/arch/nios2nommu/kernel/pio.c b/arch/nios2nommu/kernel/pio.c +new file mode 100644 +index 0000000..013a64b +--- /dev/null ++++ b/arch/nios2nommu/kernel/pio.c +@@ -0,0 +1,154 @@ ++/* ++ * linux/arch/nios2nommu/kernel/pio.c ++ * "Example" drivers(LEDs and 7 seg displays) of the PIO interface ++ * on Nios Development Kit. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Written by Wentao Xu ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Microtronix Datacom Ltd."); ++MODULE_DESCRIPTION("Drivers of PIO devices (LEDs and 7 seg) on Nios kit"); ++MODULE_LICENSE("GPL"); ++ ++#undef CONFIG_PIO_SEG ++#ifdef na_seven_seg_pio ++#define CONFIG_PIO_SEG ++#define PIO_SEG_IO na_seven_seg_pio ++#endif ++ ++#undef CONFIG_PIO_LED ++#ifdef na_led_pio ++#define CONFIG_PIO_LED ++#define PIO_LED_IO na_led_pio ++#endif ++ ++#define PDEBUG printk ++ ++/* routines for 7-segment hex display */ ++#ifdef CONFIG_PIO_SEG ++static unsigned char _hex_digits_data[] = { ++ 0x01, 0x4f, 0x12, 0x06, 0x4c, /* 0-4 */ ++ 0x24, 0x20, 0x0f, 0x00, 0x04, /* 5-9 */ ++ 0x08, 0x60, 0x72, 0x42, 0x30, /* a-e */ ++ 0x38 /* f */ ++}; ++ ++void pio_seg_write(int value) ++{ ++ int led_value; ++ ++ /* Left Hand Digit, goes to PIO bits 8-14 */ ++ led_value = _hex_digits_data[value & 0xF]; ++ led_value |= (_hex_digits_data[(value >> 4) & 0xF]) << 8; ++ ++ outl(led_value, &(PIO_SEG_IO->np_piodata)); ++} ++ ++static void __init pio_seg_init(void) ++{ ++ pio_seg_write(0); ++} ++#endif ++ ++ ++/* routines for LED display */ ++#ifdef CONFIG_PIO_LED ++void pio_led_write(int value) ++{ ++ np_pio *pio=(np_pio *)(PIO_LED_IO); ++ ++ //outl(-1, &pio->np_piodirection); ++ outl(value, &pio->np_piodata); ++} ++ ++static void __init pio_led_init(void) ++{ ++ np_pio *pio=(np_pio *)(PIO_LED_IO); ++ ++ outl(-1, &pio->np_piodirection); ++ outl(0x0, &pio->np_piodata); ++} ++#endif ++ ++/* timing routines */ ++#if defined(CONFIG_PIO_SEG) || defined(CONFIG_PIO_LED) ++static struct timer_list display_timer; ++static int restart_timer=1; ++static int timer_counter=0; ++static void display_timeout(unsigned long unused) ++{ ++#ifdef CONFIG_PIO_SEG ++ pio_seg_write(++timer_counter); ++#endif ++ ++#ifdef CONFIG_PIO_LED ++ pio_led_write(timer_counter); ++#endif ++ if (restart_timer) { ++ display_timer.expires = jiffies + HZ; /* one second */ ++ add_timer(&display_timer); ++ } ++} ++#endif ++ ++int __init pio_init(void) ++{ ++#ifdef CONFIG_PIO_SEG ++ request_mem_region((unsigned long)PIO_SEG_IO, sizeof(np_pio), "pio_7seg"); ++ pio_seg_init(); ++#endif ++ ++#ifdef CONFIG_PIO_LED ++ request_mem_region((unsigned long)PIO_LED_IO, sizeof(np_pio), "pio_led"); ++ pio_led_init(); ++#endif ++ ++#if defined(CONFIG_PIO_SEG) || defined(CONFIG_PIO_LED) ++ /* init timer */ ++ init_timer(&display_timer); ++ display_timer.function = display_timeout; ++ display_timer.data = 0; ++ display_timer.expires = jiffies + HZ * 10; /* 10 seconds */ ++ add_timer(&display_timer); ++#endif ++ ++ return 0; ++} ++ ++static void __exit pio_exit(void) ++{ ++#ifdef CONFIG_PIO_SEG ++ pio_seg_write(0); ++ release_mem_region((unsigned long)PIO_SEG_IO, sizeof(np_pio)); ++#endif ++ ++#ifdef CONFIG_PIO_LED ++ pio_led_write(0); ++ release_mem_region((unsigned long)PIO_LED_IO, sizeof(np_pio)); ++#endif ++ ++#if defined(CONFIG_PIO_SEG) || defined(CONFIG_PIO_LED) ++ restart_timer=0; ++ del_timer_sync(&display_timer); ++#endif ++} ++module_init(pio_init); ++module_exit(pio_exit); ++ +diff --git a/arch/nios2nommu/kernel/process.c b/arch/nios2nommu/kernel/process.c +new file mode 100644 +index 0000000..4cd353c +--- /dev/null ++++ b/arch/nios2nommu/kernel/process.c +@@ -0,0 +1,578 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/kernel/process.c ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 1995 Hamish Macdonald ++ * Copyright (C) 2000-2002, David McCullough ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * 68060 fixes by Jesper Skov ++ * Jan/20/2004 dgt NiosII ++ * rdusp() === (pt_regs *) regs->sp ++ * Monday: ++ * asm-nios2nommu\processor.h now bears ++ * inline thread_saved_pc ++ * (struct thread_struct *t) ++ * Friday: it's back here now ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This file handles the architecture-dependent parts of process handling.. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++asmlinkage void ret_from_fork(void); ++ ++/* ++ * The following aren't currently used. ++ */ ++void (*pm_idle)(void) = NULL; ++EXPORT_SYMBOL(pm_idle); ++ ++void (*pm_power_off)(void) = NULL; ++EXPORT_SYMBOL(pm_power_off); ++ ++void default_idle(void) ++{ ++ local_irq_disable(); ++ if (!need_resched()) { ++ local_irq_enable(); ++ __asm__("nop"); // was asm sleep ++ } else ++ local_irq_enable(); ++} ++ ++void (*idle)(void) = default_idle; ++ ++/* ++ * The idle thread. There's no useful work to be ++ * done, so just try to conserve power and have a ++ * low exit latency (ie sit in a loop waiting for ++ * somebody to say that they'd like to reschedule) ++ */ ++void cpu_idle(void) ++{ ++ while (1) { ++ while (!need_resched()) ++ idle(); ++ preempt_enable_no_resched(); ++ schedule(); ++ preempt_disable(); ++ } ++} ++ ++/* ++ * The development boards have no way to pull a board ++ * reset. Just jump to the cpu reset address and let ++ * the code in head.S take care of disabling peripherals. ++ */ ++ ++void machine_restart(char * __unused) ++{ ++ local_irq_disable(); ++ __asm__ __volatile__ ( ++ "jmp %0\n\t" ++ : ++ : "r" (CPU_RESET_ADDRESS) ++ : "r4"); ++} ++ ++EXPORT_SYMBOL(machine_restart); ++ ++void machine_halt(void) ++{ ++ local_irq_disable(); ++ for (;;); ++} ++ ++EXPORT_SYMBOL(machine_halt); ++ ++void exit_thread(void) ++{ ++} ++ ++void release_thread(struct task_struct *dead_task) ++{ ++ /* nothing to do ... */ ++} ++ ++/* ++ * There is no way to power off the development ++ * boards. So just spin lock for now. If you have ++ * your own board with power down circuits add you ++ * specific code here. ++ */ ++ ++void machine_power_off(void) ++{ ++ local_irq_disable(); ++ for (;;); ++} ++ ++EXPORT_SYMBOL(machine_power_off); ++ ++void show_regs(struct pt_regs * regs) ++{ ++ printk(KERN_NOTICE "\n"); ++ ++ printk(KERN_NOTICE "r1: %08lx r2: %08lx r3: %08lx r4: %08lx\n", ++ regs->r1, regs->r2, regs->r3, regs->r4); ++ ++ printk(KERN_NOTICE "r5: %08lx r6: %08lx r7: %08lx r8: %08lx\n", ++ regs->r5, regs->r6, regs->r7, regs->r8); ++ ++ printk(KERN_NOTICE "r9: %08lx r10: %08lx r11: %08lx r12: %08lx\n", ++ regs->r9, regs->r10, regs->r11, regs->r12); ++ ++ printk(KERN_NOTICE "r13: %08lx r14: %08lx r15: %08lx\n", ++ regs->r13, regs->r14, regs->r15); ++ ++ printk(KERN_NOTICE "ra: %08lx fp: %08lx sp: %08lx gp: %08lx\n", ++ regs->ra, regs->fp, regs->sp, regs->gp); ++ ++ printk(KERN_NOTICE "ea: %08lx estatus: %08lx statusx: %08lx\n", ++ regs->ea, regs->estatus, regs->status_extension); ++} ++ ++/* ++ * Create a kernel thread ++ */ ++int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) ++{ ++ long retval; ++ long clone_arg = flags | CLONE_VM; ++ mm_segment_t fs; ++ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ __asm__ __volatile( ++ ++ " movi r2, %6\n\t" /* TRAP_ID_SYSCALL */ ++ " movi r3, %1\n\t" /* __NR_clone */ ++ " mov r4, %5\n\t" /* (clone_arg */ ++ /* (flags | CLONE_VM)) */ ++ " movia r5, -1\n\t" /* usp: -1 */ ++ " trap\n\t" /* sys_clone */ ++ "\n\t" ++ " cmpeq r4, r3, zero\n\t"/*2nd return valu in r3 */ ++ " bne r4, zero, 1f\n\t"/* 0: parent, just return. */ ++ /* See copy_thread, called */ ++ /* by do_fork, called by */ ++ /* nios2_clone, called by */ ++ /* sys_clone, called by */ ++ /* syscall trap handler. */ ++ ++ " mov r4, %4\n\t" /* fn's parameter (arg) */ ++ "\n\t" ++ "\n\t" ++ " callr %3\n\t" /* Call function (fn) */ ++ "\n\t" ++ " mov r4, r2\n\t" /* fn's rtn code//;dgt2;tmp;*/ ++ " movi r2, %6\n\t" /* TRAP_ID_SYSCALL */ ++ " movi r3, %2\n\t" /* __NR_exit */ ++ " trap\n\t" /* sys_exit() */ ++ ++ /* Not reached by child. */ ++ "1:\n\t" ++ " mov %0, r2\n\t" /* error rtn code (retval) */ ++ ++ : "=r" (retval) /* %0 */ ++ ++ : "i" (__NR_clone) /* %1 */ ++ , "i" (__NR_exit) /* %2 */ ++ , "r" (fn) /* %3 */ ++ , "r" (arg) /* %4 */ ++ , "r" (clone_arg) /* %5 (flags | CLONE_VM) */ ++ , "i" (TRAP_ID_SYSCALL) /* %6 */ ++ ++ : "r2" /* Clobbered */ ++ , "r3" /* Clobbered */ ++ , "r4" /* Clobbered */ ++ , "r5" /* Clobbered */ ++ , "ra" /* Clobbered //;mex1 */ ++ ); ++ ++ set_fs(fs); ++ return retval; ++} ++ ++void flush_thread(void) ++{ ++ /* Now, this task is no longer a kernel thread. */ ++ current->thread.flags &= ~NIOS2_FLAG_KTHREAD; ++ ++#ifdef CONFIG_FPU ++ unsigned long zero = 0; ++#endif ++ set_fs(USER_DS); ++#ifdef CONFIG_FPU ++ if (!FPU_IS_EMU) ++...;dgt2; ++ asm volatile (".chip 68k/68881\n\t" ++ "frestore %0@\n\t" ++ ".chip 68k" : : "a" (&zero)); ++#endif ++} ++ ++/* ++ * "nios2_fork()".. By the time we get here, the ++ * non-volatile registers have also been saved on the ++ * stack. We do some ugly pointer stuff here.. (see ++ * also copy_thread) ++ */ ++ ++asmlinkage int nios2_fork(struct pt_regs *regs) ++{ ++ /* fork almost works, enough to trick you into looking elsewhere :-( */ ++ return(-EINVAL); ++} ++ ++/* ++ * nios2_execve() executes a new program. ++ */ ++asmlinkage int nios2_execve(struct pt_regs *regs) ++{ ++ int error; ++ char * filename; ++ ++ lock_kernel(); ++ filename = getname((char *) regs->r4); ++ error = PTR_ERR(filename); ++ if (IS_ERR(filename)) ++ goto out; ++ error = do_execve(filename, ++ (char **) regs->r5, ++ (char **) regs->r6, ++ regs); ++ putname(filename); ++out: ++ unlock_kernel(); ++ return error; ++} ++ ++asmlinkage int nios2_vfork(struct pt_regs *regs) ++{ ++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL); ++} ++ ++asmlinkage int nios2_clone(struct pt_regs *regs) ++{ ++ /* r4: clone_flags, r5: child_stack (usp) */ ++ ++ unsigned long clone_flags; ++ unsigned long newsp; ++ ++ clone_flags = regs->r4; ++ newsp = regs->r5; ++ if (!newsp) ++ newsp = regs->sp; ++ return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); ++} ++ ++int copy_thread(int nr, unsigned long clone_flags, ++ unsigned long usp, unsigned long topstk, ++ struct task_struct * p, struct pt_regs * regs) ++{ ++ struct pt_regs * childregs; ++ struct switch_stack * childstack, *stack; ++ unsigned long stack_offset, *retp; ++ ++ stack_offset = THREAD_SIZE - sizeof(struct pt_regs); ++ childregs = (struct pt_regs *) ((unsigned long) p->stack + stack_offset); ++ p->thread.kregs = childregs; ++ ++ *childregs = *regs; ++ childregs->r2 = 0; //;dgt2;...redundant?...see "rtnvals" below ++ ++ retp = ((unsigned long *) regs); ++ stack = ((struct switch_stack *) retp) - 1; ++ ++ childstack = ((struct switch_stack *) childregs) - 1; ++ *childstack = *stack; ++ childstack->ra = (unsigned long)ret_from_fork; ++ ++ if (usp == -1) ++ p->thread.kregs->sp = (unsigned long) childstack; ++ else ++ p->thread.kregs->sp = usp; ++ ++ p->thread.ksp = (unsigned long)childstack; ++ ++#ifdef CONFIG_FPU ++ if (!FPU_IS_EMU) { ++ /* Copy the current fpu state */ ++...;dgt2; ++ asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); ++ ++ if (p->thread.fpstate[0]) ++ asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" ++ "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" ++ : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) ++ : "memory"); ++ /* Restore the state in case the fpu was busy */ ++ asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); ++ } ++#endif ++ ++ /* Set the return value for the child. */ ++ childregs->r2 = 0; //;dgt2;...redundant?...see childregs->r2 above ++ childregs->r3 = 1; //;dgt2;...eg: kernel_thread parent test ++ ++ /* Set the return value for the parent. */ ++ regs->r2 = p->pid; // Return child pid to parent ++ regs->r3 = 0; //;dgt2;...eg: kernel_thread parent test ++ ++ return 0; ++} ++ ++/* Fill in the fpu structure for a core dump. */ ++ ++int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu) ++{ ++#ifdef CONFIG_FPU ++ char fpustate[216]; ++ ++ if (FPU_IS_EMU) { ++ int i; ++ ++ memcpy(fpu->fpcntl, current->thread.fpcntl, 12); ++ memcpy(fpu->fpregs, current->thread.fp, 96); ++ /* Convert internal fpu reg representation ++ * into long double format ++ */ ++ for (i = 0; i < 24; i += 3) ++ fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | ++ ((fpu->fpregs[i] & 0x0000ffff) << 16); ++ return 1; ++ } ++ ++ /* First dump the fpu context to avoid protocol violation. */ ++...;dgt2;tmp; ++ asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); ++ if (!fpustate[0]) ++ return 0; ++ ++ asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" ++ :: "m" (fpu->fpcntl[0]) ++ : "memory"); ++ asm volatile ("fmovemx %/fp0-%/fp7,%0" ++ :: "m" (fpu->fpregs[0]) ++ : "memory"); ++#endif ++ return 1; ++} ++ ++/* ++ * fill in the user structure for a core dump.. ++ */ ++void dump_thread(struct pt_regs * regs, struct user * dump) ++{ ++ struct switch_stack *sw; ++ ++ /* changed the size calculations - should hopefully work better. lbt */ ++ dump->magic = CMAGIC; ++ dump->start_code = 0; ++ dump->start_stack = regs->sp & ~(PAGE_SIZE - 1); ++ dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; ++ dump->u_dsize = ((unsigned long) (current->mm->brk + ++ (PAGE_SIZE-1))) >> PAGE_SHIFT; ++ dump->u_dsize -= dump->u_tsize; ++ dump->u_ssize = 0; ++ ++ if (dump->start_stack < TASK_SIZE) ++ dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; ++ ++ dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); ++ sw = ((struct switch_stack *)regs) - 1; ++ dump->regs.r1 = regs->r1; ++ dump->regs.r2 = regs->r2; ++ dump->regs.r3 = regs->r3; ++ dump->regs.r4 = regs->r4; ++ dump->regs.r5 = regs->r5; ++ dump->regs.r6 = regs->r6; ++ dump->regs.r7 = regs->r7; ++ dump->regs.r8 = regs->r8; ++ dump->regs.r9 = regs->r9; ++ dump->regs.r10 = regs->r10; ++ dump->regs.r11 = regs->r11; ++ dump->regs.r12 = regs->r12; ++ dump->regs.r13 = regs->r13; ++ dump->regs.r14 = regs->r14; ++ dump->regs.r15 = regs->r15; ++ dump->regs.r16 = sw->r16; ++ dump->regs.r17 = sw->r17; ++ dump->regs.r18 = sw->r18; ++ dump->regs.r19 = sw->r19; ++ dump->regs.r20 = sw->r20; ++ dump->regs.r21 = sw->r21; ++ dump->regs.r22 = sw->r22; ++ dump->regs.r23 = sw->r23; ++ dump->regs.ra = sw->ra; ++ dump->regs.fp = sw->fp; ++ dump->regs.gp = sw->gp; ++ dump->regs.sp = regs->sp; ++ dump->regs.orig_r2 = regs->orig_r2; ++ dump->regs.estatus = regs->estatus; ++ dump->regs.ea = regs->ea; ++ /* dump floating point stuff */ ++ // dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp); ++} ++ ++/* ++ * Generic dumping code. Used for panic and debug. ++ */ ++void dump(struct pt_regs *fp) ++{ ++ unsigned long *sp; ++ unsigned char *tp; ++ int i; ++ ++ printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); ++ printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); ++ ++ if (current->mm) { ++ printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", ++ (int) current->mm->start_code, ++ (int) current->mm->end_code, ++ (int) current->mm->start_data, ++ (int) current->mm->end_data, ++ (int) current->mm->end_data, ++ (int) current->mm->brk); ++ printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", ++ (int) current->mm->start_stack, ++ (int)(((unsigned long) current) + THREAD_SIZE)); ++ } ++ ++ printk(KERN_EMERG "PC: %08lx\n", fp->ea); ++ printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->estatus, (long) fp); ++ printk(KERN_EMERG "r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", ++ fp->r4, fp->r5, fp->r6, fp->r7); ++ printk(KERN_EMERG "r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", ++ fp->r8, fp->r9, fp->r10, fp->r11); ++ printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) fp->sp, ++ (unsigned int) fp); ++ ++ printk(KERN_EMERG "\nCODE:"); ++ tp = ((unsigned char *) fp->ea) - 0x20; ++ for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { ++ if ((i % 0x10) == 0) ++ printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); ++ printk(KERN_EMERG "%08x ", (int) *sp++); ++ } ++ printk(KERN_EMERG "\n"); ++ ++ printk(KERN_EMERG "\nKERNEL STACK:"); ++ tp = ((unsigned char *) fp) - 0x40; ++ for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { ++ if ((i % 0x10) == 0) ++ printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); ++ printk(KERN_EMERG "%08x ", (int) *sp++); ++ } ++ printk(KERN_EMERG "\n"); ++ printk(KERN_EMERG "\n"); ++ ++ printk(KERN_EMERG "\nUSER STACK:"); ++ tp = (unsigned char *) (fp->sp - 0x10); ++ for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { ++ if ((i % 0x10) == 0) ++ printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); ++ printk(KERN_EMERG "%08x ", (int) *sp++); ++ } ++ printk(KERN_EMERG "\n\n"); ++} ++ ++/* ++ * These bracket the sleeping functions.. ++ */ ++extern void scheduling_functions_start_here(void); ++extern void scheduling_functions_end_here(void); ++#define first_sched ((unsigned long) scheduling_functions_start_here) ++#define last_sched ((unsigned long) scheduling_functions_end_here) ++ ++unsigned long get_wchan(struct task_struct *p) ++{ ++ unsigned long fp, pc; ++ unsigned long stack_page; ++ int count = 0; ++ if (!p || p == current || p->state == TASK_RUNNING) ++ return 0; ++ ++ stack_page = (unsigned long)p; ++ fp = ((struct switch_stack *)p->thread.ksp)->fp; //;dgt2 ++ do { ++ if (fp < stack_page+sizeof(struct task_struct) || ++ fp >= 8184+stack_page) //;dgt2;tmp ++ return 0; ++ pc = ((unsigned long *)fp)[1]; ++ if (!in_sched_functions(pc)) ++ return pc; ++ fp = *(unsigned long *) fp; ++ } while (count++ < 16); //;dgt2;tmp ++ return 0; ++} ++ ++/* Return saved PC of a blocked thread. */ ++unsigned long thread_saved_pc(struct task_struct *t) ++{ ++ return (t->thread.kregs->ea); ++} ++ ++/* ++ * Do necessary setup to start up a newly executed thread. ++ * Will statup in user mode (status_extension = 0). ++ */ ++void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) ++{ ++ memset((void *) regs, 0, sizeof(struct pt_regs)); ++ regs->estatus = NIOS2_STATUS_PIE_MSK; // No user mode setting, at least not for now ++ regs->ea = pc; ++ regs->sp = sp; ++ ++ /* check if debug flag is set */ ++ if (current->thread.flags & NIOS2_FLAG_DEBUG ) { ++ if ( *(u32*)pc == NIOS2_OP_NOP ) { ++ *(u32*)pc = NIOS2_OP_BREAK; ++ flush_icache_range(pc, pc+4); ++ } ++ } ++} +diff --git a/arch/nios2nommu/kernel/ptrace.c b/arch/nios2nommu/kernel/ptrace.c +new file mode 100644 +index 0000000..e6ff3b3 +--- /dev/null ++++ b/arch/nios2nommu/kernel/ptrace.c +@@ -0,0 +1,352 @@ ++/* ++ * linux/arch/m68knommu/kernel/ptrace.c ++ * ++ * Copyright (C) 1994 by Hamish Macdonald ++ * Taken from linux/kernel/ptrace.c and modified for M680x0. ++ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds ++ * ++ * This file is subject to the terms and conditions of the GNU General ++ * Public License. See the file COPYING in the main directory of ++ * this archive for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * does not yet catch signals sent when the child dies. ++ * in exit.c or in signal.c. ++ */ ++ ++/* determines which bits in the SR the user has access to. */ ++/* 1 = access 0 = no access */ ++#define SR_MASK 0x00000000 ++ ++/* Find the stack offset for a register, relative to thread.ksp. */ ++#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) ++#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ ++ - sizeof(struct switch_stack)) ++/* Mapping from PT_xxx to the stack offset at which the register is ++ saved. Notice that usp has no stack-slot and needs to be treated ++ specially (see get_reg/put_reg below). */ ++static int regoff[] = { ++ -1, PT_REG(r1), PT_REG(r2), PT_REG(r3), PT_REG(r4), ++ PT_REG(r5), PT_REG(r6), PT_REG(r7), PT_REG(r8), ++ PT_REG(r9), PT_REG(r10), PT_REG(r11), PT_REG(r12), ++ PT_REG(r13), PT_REG(r14), PT_REG(r15), SW_REG(r16), ++ SW_REG(r17), SW_REG(r18), SW_REG(r19), SW_REG(r20), ++ SW_REG(r21), SW_REG(r22), SW_REG(r23), -1, -1, ++ PT_REG(gp), PT_REG(sp), -1, -1, PT_REG(ra), -1, ++ PT_REG(estatus), -1, -1, -1 ++}; ++ ++/* ++ * Get contents of register REGNO in task TASK. ++ */ ++static inline long get_reg(struct task_struct *task, int regno) ++{ ++ unsigned long *addr; ++ ++ if (regno == PTR_R0) ++ return 0; ++ else if (regno == PTR_BA) ++ return 0; ++ else if (regno == PTR_STATUS) ++ return 0; ++ else if (regno == PTR_IENABLE) ++ return 0; ++ else if (regno == PTR_IPENDING) ++ return 0; ++ else if (regno < sizeof(regoff)/sizeof(regoff[0])) ++ addr = (unsigned long *)(task->thread.kregs + regoff[regno]); ++ else ++ return 0; ++ return *addr; ++} ++ ++/* ++ * Write contents of register REGNO in task TASK. ++ */ ++static inline int put_reg(struct task_struct *task, int regno, ++ unsigned long data) ++{ ++ unsigned long *addr; ++ ++ if (regno == PTR_R0) ++ return -1; ++ else if (regno == PTR_BA) ++ return -1; ++ else if (regno == PTR_STATUS) ++ return -1; ++ else if (regno == PTR_IENABLE) ++ return -1; ++ else if (regno == PTR_IPENDING) ++ return -1; ++ else if (regno < sizeof(regoff)/sizeof(regoff[0])) ++ addr = (unsigned long *) (task->thread.kregs + regoff[regno]); ++ else ++ return -1; ++ *addr = data; ++ return 0; ++} ++ ++/* ++ * Called by kernel/ptrace.c when detaching.. ++ * ++ * Nothing special to do here, no processor debug support. ++ */ ++void ptrace_disable(struct task_struct *child) ++{ ++} ++ ++long arch_ptrace(struct task_struct *child, long request, long addr, long data) ++{ ++ int ret; ++ ++ switch (request) { ++ /* when I and D space are separate, these will need to be fixed. */ ++ case PTRACE_PEEKTEXT: /* read word at location addr. */ ++ case PTRACE_PEEKDATA: { ++ unsigned long tmp; ++ int copied; ++ ++ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); ++ ret = -EIO; ++ if (copied != sizeof(tmp)) ++ break; ++ ret = put_user(tmp,(unsigned long *) data); ++ break; ++ } ++ ++ /* read the word at location addr in the USER area. */ ++ case PTRACE_PEEKUSR: { ++ unsigned long tmp; ++ ++ ret = -EIO; ++ if ((addr & 3) || addr < 0 || ++ addr > sizeof(struct user) - 3) ++ break; ++ ++ tmp = 0; /* Default return condition */ ++ addr = addr >> 2; /* temporary hack. */ ++ ret = -EIO; ++ if (addr < 19) { ++ tmp = get_reg(child, addr); ++#if 0 // No FPU stuff ++ } else if (addr >= 21 && addr < 49) { ++ tmp = child->thread.fp[addr - 21]; ++#ifdef CONFIG_M68KFPU_EMU ++ /* Convert internal fpu reg representation ++ * into long double format ++ */ ++ if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) ++ tmp = ((tmp & 0xffff0000) << 15) | ++ ((tmp & 0x0000ffff) << 16); ++#endif ++#endif ++ } else if (addr == 49) { ++ tmp = child->mm->start_code; ++ } else if (addr == 50) { ++ tmp = child->mm->start_data; ++ } else if (addr == 51) { ++ tmp = child->mm->end_code; ++ } else ++ break; ++ ret = put_user(tmp,(unsigned long *) data); ++ break; ++ } ++ ++ /* when I and D space are separate, this will have to be fixed. */ ++ case PTRACE_POKETEXT: /* write the word at location addr. */ ++ case PTRACE_POKEDATA: ++ ret = 0; ++ if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) ++ break; ++ ret = -EIO; ++ break; ++ ++ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ++ ret = -EIO; ++ if ((addr & 3) || addr < 0 || ++ addr > sizeof(struct user) - 3) ++ break; ++ ++ addr = addr >> 2; /* temporary hack. */ ++ ++ if (addr == PTR_ESTATUS) { ++ data &= SR_MASK; ++ data |= get_reg(child, PTR_ESTATUS) & ~(SR_MASK); ++ } ++ if (addr < 19) { ++ if (put_reg(child, addr, data)) ++ break; ++ ret = 0; ++ break; ++ } ++#if 0 // No FPU stuff ++ if (addr >= 21 && addr < 48) ++ { ++#ifdef CONFIG_M68KFPU_EMU ++ /* Convert long double format ++ * into internal fpu reg representation ++ */ ++ if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { ++ data = (unsigned long)data << 15; ++ data = (data & 0xffff0000) | ++ ((data & 0x0000ffff) >> 1); ++ } ++#endif ++ child->thread.fp[addr - 21] = data; ++ ret = 0; ++ } ++#endif ++ break; ++ ++ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ ++ case PTRACE_CONT: { /* restart after signal. */ ++ ++ ret = -EIO; ++ if ((unsigned long) data > _NSIG) ++ break; ++ if (request == PTRACE_SYSCALL) ++ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ++ else ++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ++ child->exit_code = data; ++ wake_up_process(child); ++ ret = 0; ++ break; ++ } ++ ++ /* ++ * make the child exit. Best I can do is send it a sigkill. ++ * perhaps it should be put in the status that it wants to ++ * exit. ++ */ ++ case PTRACE_KILL: { ++ ++ ret = 0; ++ if (child->state == EXIT_ZOMBIE) /* already dead */ ++ break; ++ child->exit_code = SIGKILL; ++ wake_up_process(child); ++ break; ++ } ++ ++ /* ++ * Single stepping requires placing break instructions in ++ * the code to break back. If you are stepping through a ++ * conditional branch you need to decode the test and put ++ * the break in the correct location. ++ */ ++ case PTRACE_SINGLESTEP: { /* set the trap flag. */ ++ ++ ret = -EIO; ++ if ((unsigned long) data > _NSIG) ++ break; ++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ++ ++ child->exit_code = data; ++ /* give it a chance to run. */ ++ wake_up_process(child); ++ ret = 0; ++ break; ++ } ++ ++ case PTRACE_DETACH: /* detach a process that was attached. */ ++ ret = ptrace_detach(child, data); ++ break; ++ ++ case PTRACE_GETREGS: { /* Get all gp regs from the child. */ ++ int i; ++ unsigned long tmp; ++ for (i = 0; i < 19; i++) { ++ tmp = get_reg(child, i); ++ if (put_user(tmp, (unsigned long *) data)) { ++ ret = -EFAULT; ++ break; ++ } ++ data += sizeof(long); ++ } ++ ret = 0; ++ break; ++ } ++ ++ case PTRACE_SETREGS: { /* Set all gp regs in the child. */ ++ int i; ++ unsigned long tmp; ++ for (i = 0; i < 19; i++) { ++ if (get_user(tmp, (unsigned long *) data)) { ++ ret = -EFAULT; ++ break; ++ } ++ if (i == PTR_ESTATUS) { ++ tmp &= SR_MASK; ++ tmp |= get_reg(child, PTR_ESTATUS) & ~(SR_MASK); ++ } ++ put_reg(child, i, tmp); ++ data += sizeof(long); ++ } ++ ret = 0; ++ break; ++ } ++ ++#ifdef PTRACE_GETFPREGS ++ case PTRACE_GETFPREGS: { /* Get the child FPU state. */ ++ ret = 0; ++ if (copy_to_user((void *)data, &child->thread.fp, ++ sizeof(struct user_m68kfp_struct))) ++ ret = -EFAULT; ++ break; ++ } ++#endif ++ ++#ifdef PTRACE_SETFPREGS ++ case PTRACE_SETFPREGS: { /* Set the child FPU state. */ ++ ret = 0; ++ if (copy_from_user(&child->thread.fp, (void *)data, ++ sizeof(struct user_m68kfp_struct))) ++ ret = -EFAULT; ++ break; ++ } ++#endif ++ ++ default: ++ ret = -EIO; ++ break; ++ } ++ return ret; ++} ++ ++asmlinkage void syscall_trace(void) ++{ ++ if (!test_thread_flag(TIF_SYSCALL_TRACE)) ++ return; ++ if (!(current->ptrace & PT_PTRACED)) ++ return; ++ current->exit_code = SIGTRAP; ++ current->state = TASK_STOPPED; ++ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ++ ? 0x80 : 0)); ++ /* ++ * this isn't the same as continuing with a signal, but it will do ++ * for normal use. strace only continues with a signal if the ++ * stopping signal is not SIGTRAP. -brl ++ */ ++ if (current->exit_code) { ++ send_sig(current->exit_code, current, 1); ++ current->exit_code = 0; ++ } ++} +diff --git a/arch/nios2nommu/kernel/semaphore.c b/arch/nios2nommu/kernel/semaphore.c +new file mode 100644 +index 0000000..0c7d11b +--- /dev/null ++++ b/arch/nios2nommu/kernel/semaphore.c +@@ -0,0 +1,155 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/kernel/semaphore.c ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++/* ++ * Generic semaphore code. Buyer beware. Do your own ++ * specific changes in ++ */ ++ ++#include ++#include ++#include ++ ++#ifndef CONFIG_RMW_INSNS ++spinlock_t semaphore_wake_lock; ++#endif ++ ++/* ++ * Semaphores are implemented using a two-way counter: ++ * The "count" variable is decremented for each process ++ * that tries to sleep, while the "waking" variable is ++ * incremented when the "up()" code goes to wake up waiting ++ * processes. ++ * ++ * Notably, the inline "up()" and "down()" functions can ++ * efficiently test if they need to do any extra work (up ++ * needs to do something only if count was negative before ++ * the increment operation. ++ * ++ * waking_non_zero() (from asm/semaphore.h) must execute ++ * atomically. ++ * ++ * When __up() is called, the count was negative before ++ * incrementing it, and we need to wake up somebody. ++ * ++ * This routine adds one to the count of processes that need to ++ * wake up and exit. ALL waiting processes actually wake up but ++ * only the one that gets to the "waking" field first will gate ++ * through and acquire the semaphore. The others will go back ++ * to sleep. ++ * ++ * Note that these functions are only called when there is ++ * contention on the lock, and as such all this is the ++ * "non-critical" part of the whole semaphore business. The ++ * critical part is the inline stuff in ++ * where we want to avoid any extra jumps and calls. ++ */ ++asmlinkage void __up(struct semaphore *sem) ++{ ++ wake_one_more(sem); ++ wake_up(&sem->wait); ++} ++ ++/* ++ * Perform the "down" function. Return zero for semaphore acquired, ++ * return negative for signalled out of the function. ++ * ++ * If called from __down, the return is ignored and the wait loop is ++ * not interruptible. This means that a task waiting on a semaphore ++ * using "down()" cannot be killed until someone does an "up()" on ++ * the semaphore. ++ * ++ * If called from __down_interruptible, the return value gets checked ++ * upon return. If the return value is negative then the task continues ++ * with the negative value in the return register (it can be tested by ++ * the caller). ++ * ++ * Either form may be used in conjunction with "up()". ++ * ++ */ ++ ++ ++#define DOWN_HEAD(task_state) \ ++ \ ++ \ ++ current->state = (task_state); \ ++ add_wait_queue(&sem->wait, &wait); \ ++ \ ++ /* \ ++ * Ok, we're set up. sem->count is known to be less than zero \ ++ * so we must wait. \ ++ * \ ++ * We can let go the lock for purposes of waiting. \ ++ * We re-acquire it after awaking so as to protect \ ++ * all semaphore operations. \ ++ * \ ++ * If "up()" is called before we call waking_non_zero() then \ ++ * we will catch it right away. If it is called later then \ ++ * we will have to go through a wakeup cycle to catch it. \ ++ * \ ++ * Multiple waiters contend for the semaphore lock to see \ ++ * who gets to gate through and who has to wait some more. \ ++ */ \ ++ for (;;) { ++ ++#define DOWN_TAIL(task_state) \ ++ current->state = (task_state); \ ++ } \ ++ current->state = TASK_RUNNING; \ ++ remove_wait_queue(&sem->wait, &wait); ++ ++void __sched __down(struct semaphore * sem) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ DOWN_HEAD(TASK_UNINTERRUPTIBLE) ++ if (waking_non_zero(sem)) ++ break; ++ schedule(); ++ DOWN_TAIL(TASK_UNINTERRUPTIBLE) ++} ++ ++int __sched __down_interruptible(struct semaphore * sem) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int ret = 0; ++ ++ DOWN_HEAD(TASK_INTERRUPTIBLE) ++ ++ ret = waking_non_zero_interruptible(sem, current); ++ if (ret) ++ { ++ if (ret == 1) ++ /* ret != 0 only if we get interrupted -arca */ ++ ret = 0; ++ break; ++ } ++ schedule(); ++ DOWN_TAIL(TASK_INTERRUPTIBLE) ++ return ret; ++} ++ ++int __down_trylock(struct semaphore * sem) ++{ ++ return waking_non_zero_trylock(sem); ++} +diff --git a/arch/nios2nommu/kernel/setup.c b/arch/nios2nommu/kernel/setup.c +new file mode 100644 +index 0000000..1f1627b +--- /dev/null ++++ b/arch/nios2nommu/kernel/setup.c +@@ -0,0 +1,663 @@ ++/* ++ 21Mar2001 1.1 dgt/microtronix: Altera Excalibur/Nios32 port ++ 30Jun2003 kenw/microtronix: Remove cmdline check in flash ++*/ ++ ++/* ++ * linux/arch/niosnommu/kernel/setup.c ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 2001 Vic Phillips {vic@microtronix.com} ++ * Copyleft (C) 2000 James D. Schettine {james@telos-systems.com} ++ * Copyright (C) 1999 Greg Ungerer (gerg@moreton.com.au) ++ * Copyright (C) 1998,2000 D. Jeff Dionne ++ * Copyright (C) 1998 Kenneth Albanowski ++ * Copyright (C) 1995 Hamish Macdonald ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++/* ++ * This file handles the architecture-dependent parts of system setup ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_BLK_DEV_INITRD ++#include ++#endif ++ ++#ifdef CONFIG_NIOS_SPI ++#include ++extern ssize_t spi_write(struct file *filp, const char *buf, size_t count, loff_t *ppos); ++extern ssize_t spi_read (struct file *filp, char *buf, size_t count, loff_t *ppos); ++extern loff_t spi_lseek (struct file *filp, loff_t offset, int origin); ++extern int spi_open (struct inode *inode, struct file *filp); ++extern int spi_release (struct inode *inode, struct file *filp); ++#endif ++ ++#ifdef CONFIG_CONSOLE ++extern struct consw *conswitchp; ++#endif ++ ++unsigned long rom_length; ++unsigned long memory_start; ++unsigned long memory_end; ++ ++EXPORT_SYMBOL(memory_start); ++EXPORT_SYMBOL(memory_end); ++ ++#ifndef CONFIG_CMDLINE ++#define CONFIG_CMDLINE "CONSOLE=/dev/ttyS0 root=/dev/rom0 ro" ++#endif ++ ++#ifndef CONFIG_PASS_CMDLINE ++static char default_command_line[] = CONFIG_CMDLINE; ++#endif ++static char __initdata command_line[COMMAND_LINE_SIZE] = { 0, }; ++ ++ ++/* r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11*/ ++/* r12 r13 r14 r15 or2 ra fp sp gp es ste ea*/ ++static struct pt_regs fake_regs = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\ ++ 0, 0, 0, 0, 0, (unsigned long)cpu_idle, 0, 0, 0, 0, 0, 0}; ++ ++#define CPU "NIOS2" ++ ++#if defined (CONFIG_CS89x0) || defined (CONFIG_SMC91111) || defined (CONFIG_OPEN_ETH) || defined (CONFIG_MTIP1000_ETH) || defined (CONFIG_DM9000_ETH) || defined (CONFIG_SMC91X) || defined (CONFIG_DM9000) || defined (CONFIG_DM9KS) ++ #if defined (CONFIG_MTIP1000_ETH) //;dgt3; ++ #include <../drivers/net/mtip1000.h> //;dgt3; ++ #endif //;dgt3; ++ ++ unsigned char *excalibur_enet_hwaddr; ++ unsigned char excalibur_enet_hwaddr_array[6]; ++#endif ++ ++// save args passed from u-boot, called from head.S ++void nios2_boot_init(unsigned r4,unsigned r5,unsigned r6,unsigned r7) ++{ ++#if defined(CONFIG_PASS_CMDLINE) ++ if (r4 == 0x534f494e) // r4 is magic NIOS, to become board info check in the future ++ { ++#if defined(CONFIG_BLK_DEV_INITRD) ++ /* ++ * If the init RAM disk has been configured in, and there's a valid ++ * starting address for it, set it up. ++ */ ++ if (r5) { ++ initrd_start = r5; ++ initrd_end = r6; ++ } ++#endif /* CONFIG_BLK_DEV_INITRD */ ++ if (r7) ++ strncpy(command_line, (char *)r7, COMMAND_LINE_SIZE); ++ } ++#endif ++} ++ ++inline void flash_command(int base, int offset, short data) ++{ ++ volatile unsigned short * ptr=(unsigned short*) (base); ++ ++ ptr[0x555]=0xaa; ++ ptr[0x2aa]=0x55; ++ ptr[offset]=data; ++} ++ ++inline void exit_se_flash(int base) ++{ ++ flash_command(base, 0x555, 0x90); ++ *(unsigned short*)base=0; ++} ++ ++void __init setup_arch(char **cmdline_p) ++{ ++ int bootmap_size; ++ extern int _stext, _etext; ++ extern int _edata, _end; ++#ifdef DEBUG ++ extern int _sdata, _sbss, _ebss; ++#ifdef CONFIG_BLK_DEV_BLKMEM ++ extern int *romarray; ++#endif ++#endif ++#if 0 // krh ++ unsigned char *psrc=(unsigned char *)((NIOS_FLASH_START + NIOS_FLASH_END)>>1); ++ int i=0; ++#endif // krh ++ ++ memory_start = PAGE_ALIGN((unsigned long)&_end); ++ memory_end = (unsigned long) nasys_program_mem_end; ++ ++#if 0 //;kenw; ++ /* copy the command line from booting paramter region */ ++ #if defined (nasys_am29lv065d_flash_0) //;dgt; ++ { //;dgt; ++ // ...TBA... //;dgt; ++ } //;dgt; ++ #else //;dgt; ++ flash_command((int)psrc, 0x555, 0x88); ++ while ((*psrc!=0xFF) && (i>1) ); ++ if (command_line[0]==0) ++ #endif //;dgt; ++#endif //;kenw; ++#ifndef CONFIG_PASS_CMDLINE ++ memcpy(command_line, default_command_line, sizeof(default_command_line)); ++#endif ++ ++ printk("\x0F\r\n\nuClinux/Nios II\n"); ++ printk("Altera Nios II support (C) 2004 Microtronix Datacom Ltd.\n"); ++ ++#ifdef DEBUG ++ printk("KERNEL -> TEXT=0x%08x-0x%08x DATA=0x%08x-0x%08x " ++ "BSS=0x%08x-0x%08x\n", (int) &_stext, (int) &_etext, ++ (int) &_sdata, (int) &_edata, ++ (int) &_sbss, (int) &_ebss); ++ printk("KERNEL -> MEM=0x%06x-0x%06x STACK=0x%06x-0x%06x\n", ++ (int) memory_start, (int) memory_end, ++ (int) memory_end, (int) nasys_program_mem_end); ++#endif ++ ++ init_mm.start_code = (unsigned long) &_stext; ++ init_mm.end_code = (unsigned long) &_etext; ++ init_mm.end_data = (unsigned long) &_edata; ++ init_mm.brk = (unsigned long) 0; ++ init_task.thread.kregs = &fake_regs; ++ ++#if 0 ++ ROOT_DEV = MKDEV(BLKMEM_MAJOR,0); ++#endif ++ ++ /* Keep a copy of command line */ ++ *cmdline_p = &command_line[0]; ++ ++ memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); ++ saved_command_line[COMMAND_LINE_SIZE-1] = 0; ++ ++#ifdef DEBUG ++ if (strlen(*cmdline_p)) ++ printk("Command line: '%s'\n", *cmdline_p); ++ else ++ printk("No Command line passed\n"); ++#endif ++ ++ ++#if defined (CONFIG_CS89x0) || defined (CONFIG_SMC91111) || defined (CONFIG_OPEN_ETH) || defined (CONFIG_MTIP1000_ETH) || defined (CONFIG_DM9000_ETH) || defined (CONFIG_SMC91X) || defined (CONFIG_DM9000) || defined (CONFIG_DM9KS) ++ ++ #if defined (CONFIG_MTIP1000_ETH) //;dgt3; ++ (*((np_mtip_mac *) //;dgt3; ++ (na_mtip_mac_control_port))). //;dgt3; ++ COMMAND_CONFIG = 0; //;dgt3; ++ #endif //;dgt3; ++ ++ /* now read the hwaddr of the ethernet --wentao*/ ++ ++ #if 1 //;dgt2; ++// #if defined (nasys_am29lv065d_flash_0) //;dgt; ++ { //;dgt; ++ unsigned char *flashptr = //;dgt; ++ ((unsigned char *) //;dgt; ++ (( //;dgt; ++ #if defined (na_flash_kernel_end) //;dgt2; ++ na_flash_kernel_end //;dgt2; ++ #else //;dgt2; ++ #if defined (na_flash_kernel_base) //;dgt2; ++ na_flash_kernel_base + //;dgt; ++ #else //;dgt2; ++ na_flash_kernel + //;dgt2; ++ #endif //;dgt2; ++ na_flash_kernel_size //;dgt2; ++ #endif //;dgt2; ++ - 0x00010000))); //;dgt; ++ // last 64K of Altera stratix/cyclone flash //;dgt; ++ //;dgt; ++ if((*((unsigned long *) flashptr)) == 0x00005AFE) //;dgt; ++ { //;dgt; ++ memcpy(excalibur_enet_hwaddr_array, //;dgt; ++ ((void*) (flashptr+4)),6); //;dgt; ++ } //;dgt; ++ else //;dgt; ++ { //;dgt; ++ printk("\nsetup_arch: No persistant network" //;dgt; ++ " settings signature at %08lX\n", //;dgt; ++ ((unsigned long) flashptr)); //;dgt; ++ *((unsigned long *) //;dgt; ++ (&(excalibur_enet_hwaddr_array[0]))) = //;dgt; ++ 0x00ED0700; //;dgt2; ++ /* 0x00-07-ED: Altera Corporation. //;dgt; */ ++ *((unsigned short *) //;dgt; ++ (&(excalibur_enet_hwaddr_array[4]))) = //;dgt; ++ 0x0000; //;dgt; ++ /* Should be: 0x-00-07-ED-0A-03-(Random# 0-256) //;dgt2; */ ++ /* 0x-00-07-ED-0A-xx-yy Vermont boards //;dgt2; */ ++ /* 0x-00-07-ED-0B-xx-yy Rhode Island boards //;dgt2; */ ++ /* 0x-00-07-ED-0C-xx-yy Delaware boards //;dgt2; */ ++ /* 00 Internal Altera //;dgt2; */ ++ /* 01 Beta, pre-production//;dgt2; */ ++ /* 02 Beta, pre-production//;dgt2; */ ++ /* 03 Customer use //;dgt2; */ ++ } //;dgt; ++ } //;dgt; ++ #else //;dgt; ++ flash_command(NIOS_FLASH_START, 0x555, 0x88); ++ memcpy(excalibur_enet_hwaddr_array,(void*)NIOS_FLASH_START,6); ++ exit_se_flash(NIOS_FLASH_START);; ++ #endif //;dgt; ++ ++ /* now do the checking, make sure we got a valid addr */ ++ if (excalibur_enet_hwaddr_array[0] & (unsigned char)1) ++ { ++ printk("Ethernet hardware address:Clearing invalid bit #0\n"); ++ excalibur_enet_hwaddr_array[0] ^= (unsigned char)1; ++ } ++ excalibur_enet_hwaddr=excalibur_enet_hwaddr_array; ++#ifdef DEBUG ++ printk("Setup the hardware addr for ethernet\n\t %02x %02x %02x %02x %02x %02x\n", ++ excalibur_enet_hwaddr[0],excalibur_enet_hwaddr[1], ++ excalibur_enet_hwaddr[2],excalibur_enet_hwaddr[3], ++ excalibur_enet_hwaddr[4],excalibur_enet_hwaddr[5]); ++#endif ++#endif ++ ++ ++ /* ++ * give all the memory to the bootmap allocator, tell it to put the ++ * boot mem_map at the start of memory ++ */ ++ bootmap_size = init_bootmem_node( ++ NODE_DATA(0), ++ memory_start >> PAGE_SHIFT, /* map goes here */ ++ PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */ ++ memory_end >> PAGE_SHIFT); ++ /* ++ * free the usable memory, we have to make sure we do not free ++ * the bootmem bitmap so we then reserve it after freeing it :-) ++ */ ++ free_bootmem(memory_start, memory_end - memory_start); ++ reserve_bootmem(memory_start, bootmap_size); ++#ifdef CONFIG_BLK_DEV_INITRD ++ if (initrd_start) reserve_bootmem(virt_to_phys((void *)initrd_start), initrd_end - initrd_start); ++#endif /* CONFIG_BLK_DEV_INITRD */ ++ /* ++ * get kmalloc into gear ++ */ ++ paging_init(); ++#ifdef CONFIG_VT ++#if defined(CONFIG_DUMMY_CONSOLE) ++ conswitchp = &dummy_con; ++#endif ++#endif ++ ++#ifdef DEBUG ++ printk("Done setup_arch\n"); ++#endif ++ ++} ++ ++int get_cpuinfo(char * buffer) ++{ ++ char *cpu, *mmu, *fpu; ++ u_long clockfreq; ++ ++ cpu = CPU; ++ mmu = "none"; ++ fpu = "none"; ++ ++ clockfreq = nasys_clock_freq; ++ ++ return(sprintf(buffer, "CPU:\t\t%s\n" ++ "MMU:\t\t%s\n" ++ "FPU:\t\t%s\n" ++ "Clocking:\t%lu.%1luMHz\n" ++ "BogoMips:\t%lu.%02lu\n" ++ "Calibration:\t%lu loops\n", ++ cpu, mmu, fpu, ++ clockfreq/1000000,(clockfreq/100000)%10, ++ (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100, ++ (loops_per_jiffy*HZ))); ++ ++} ++ ++/* ++ * Get CPU information for use by the procfs. ++ */ ++ ++static int show_cpuinfo(struct seq_file *m, void *v) ++{ ++ char *cpu, *mmu, *fpu; ++ u_long clockfreq; ++ ++ cpu = CPU; ++ mmu = "none"; ++ fpu = "none"; ++ ++ clockfreq = nasys_clock_freq; ++ ++ seq_printf(m, "CPU:\t\t%s\n" ++ "MMU:\t\t%s\n" ++ "FPU:\t\t%s\n" ++ "Clocking:\t%lu.%1luMHz\n" ++ "BogoMips:\t%lu.%02lu\n" ++ "Calibration:\t%lu loops\n", ++ cpu, mmu, fpu, ++ clockfreq/1000000,(clockfreq/100000)%10, ++ (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100, ++ (loops_per_jiffy*HZ)); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_NIOS_SPI ++ ++static int bcd2char( int x ) ++{ ++ if ( (x & 0xF) > 0x90 || (x & 0x0F) > 0x09 ) ++ return 99; ++ ++ return (((x & 0xF0) >> 4) * 10) + (x & 0x0F); ++} ++ ++#endif // CONFIG_NIOS_SPI ++ ++ ++void arch_gettod(int *year, int *month, int *date, int *hour, int *min, int *sec) ++{ ++#ifdef CONFIG_NIOS_SPI ++ /********************************************************************/ ++ /* Read the CMOS clock on the Microtronix Datacom O/S Support card. */ ++ /* Use the SPI driver code, but circumvent the file system by using */ ++ /* its internal functions. */ ++ /********************************************************************/ ++ int hr; ++ ++ struct /*********************************/ ++ { /* The SPI payload. Warning: the */ ++ unsigned short register_addr; /* sizeof() operator will return */ ++ unsigned char value; /* a length of 4 instead of 3! */ ++ } spi_data; /*********************************/ ++ ++ ++ if ( spi_open( NULL, NULL ) ) ++ { ++ printk( "Cannot open SPI driver to read system CMOS clock.\n" ); ++ *year = *month = *date = *hour = *min = *sec = 0; ++ return; ++ } ++ ++ spi_lseek( NULL, clockCS, 0 /* == SEEK_SET */ ); ++ ++ spi_data.register_addr = clock_write_control; ++ spi_data.value = 0x40; // Write protect ++ spi_write( NULL, (const char *)&spi_data, 3, NULL ); ++ ++ spi_data.register_addr = clock_read_sec; ++ spi_data.value = 0; ++ spi_read( NULL, (char *)&spi_data, 3, NULL ); ++ *sec = (int)bcd2char( spi_data.value ); ++ ++ spi_data.register_addr = clock_read_min; ++ spi_data.value = 0; ++ spi_read( NULL, (char *)&spi_data, 3, NULL ); ++ *min = (int)bcd2char( spi_data.value ); ++ ++ spi_data.register_addr = clock_read_hour; ++ spi_data.value = 0; ++ spi_read( NULL, (char *)&spi_data, 3, NULL ); ++ hr = (int)bcd2char( spi_data.value ); ++ if ( hr & 0x40 ) // Check 24-hr bit ++ hr = (hr & 0x3F) + 12; // Convert to 24-hr ++ ++ *hour = hr; ++ ++ ++ ++ spi_data.register_addr = clock_read_date; ++ spi_data.value = 0; ++ spi_read( NULL, (char *)&spi_data, 3, NULL ); ++ *date = (int)bcd2char( spi_data.value ); ++ ++ spi_data.register_addr = clock_read_month; ++ spi_data.value = 0; ++ spi_read( NULL, (char *)&spi_data, 3, NULL ); ++ *month = (int)bcd2char( spi_data.value ); ++ ++ spi_data.register_addr = clock_read_year; ++ spi_data.value = 0; ++ spi_read( NULL, (char *)&spi_data, 3, NULL ); ++ *year = (int)bcd2char( spi_data.value ); ++ ++ ++ spi_release( NULL, NULL ); ++#else ++ *year = *month = *date = *hour = *min = *sec = 0; ++ ++#endif ++} ++ ++static void *cpuinfo_start (struct seq_file *m, loff_t *pos) ++{ ++ return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL; ++} ++ ++static void *cpuinfo_next (struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return cpuinfo_start (m, pos); ++} ++ ++static void cpuinfo_stop (struct seq_file *m, void *v) ++{ ++} ++ ++struct seq_operations cpuinfo_op = { ++ start: cpuinfo_start, ++ next: cpuinfo_next, ++ stop: cpuinfo_stop, ++ show: show_cpuinfo ++}; ++ ++ ++// adapted from linux/arch/arm/mach-versatile/core.c and mach-bast ++// note, hardware MAC address is still undefined ++ ++#if defined(CONFIG_SMC91X) && defined(na_enet) ++ ++#ifndef LAN91C111_REGISTERS_OFFSET ++#define LAN91C111_REGISTERS_OFFSET 0x300 ++#endif ++ ++static struct resource smc91x_resources[] = { ++ [0] = { ++ .start = na_enet + LAN91C111_REGISTERS_OFFSET, ++ .end = na_enet + LAN91C111_REGISTERS_OFFSET + 0x100 - 1, // 32bits,64k, LAN91C111_REGISTERS_OFFSET 0x0300 ? ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = na_enet_irq, ++ .end = na_enet_irq, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++static struct platform_device smc91x_device = { ++ .name = "smc91x", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(smc91x_resources), ++ .resource = smc91x_resources, ++}; ++static int __init smc91x_device_init(void) ++{ ++ /* customizes platform devices, or adds new ones */ ++ platform_device_register(&smc91x_device); ++ return 0; ++} ++arch_initcall(smc91x_device_init); ++#endif // CONFIG_SMC91X ++ ++ ++#if defined(na_DM9000A) && !defined(na_dm9000) // defs for DE2 ++#define na_dm9000 na_DM9000A ++#define na_dm9000_irq na_DM9000A_irq ++#endif ++ ++#if defined(CONFIG_DM9000) && defined(na_dm9000) ++#include ++static struct resource dm9k_resource[] = { ++ [0] = { ++ .start = na_dm9000, ++ .end = na_dm9000 + 3, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = na_dm9000 + 4, ++ .end = na_dm9000 + 4 + 3, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = na_dm9000_irq, ++ .end = na_dm9000_irq, ++ .flags = IORESOURCE_IRQ, ++ } ++ ++}; ++static struct dm9000_plat_data dm9k_platdata = { ++ .flags = DM9000_PLATF_16BITONLY, ++}; ++static struct platform_device dm9k_device = { ++ .name = "dm9000", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(dm9k_resource), ++ .resource = dm9k_resource, ++ .dev = { ++ .platform_data = &dm9k_platdata, ++ } ++}; ++static int __init dm9k_device_init(void) ++{ ++ /* customizes platform devices, or adds new ones */ ++ platform_device_register(&dm9k_device); ++ return 0; ++} ++arch_initcall(dm9k_device_init); ++#endif // CONFIG_DM9000 ++ ++ ++#if defined(CONFIG_SERIO_ALTPS2) && defined(na_ps2_0) ++ ++static struct resource altps2_0_resources[] = { ++ [0] = { ++ .start = na_ps2_0, ++ .end = na_ps2_0 + 0x8 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = na_ps2_0_irq, ++ .end = na_ps2_0_irq, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++static struct platform_device altps2_0_device = { ++ .name = "altps2", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(altps2_0_resources), ++ .resource = altps2_0_resources, ++}; ++ ++#if defined(na_ps2_1) ++static struct resource altps2_1_resources[] = { ++ [0] = { ++ .start = na_ps2_1, ++ .end = na_ps2_1 + 0x8 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = na_ps2_1_irq, ++ .end = na_ps2_1_irq, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++static struct platform_device altps2_1_device = { ++ .name = "altps2", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(altps2_1_resources), ++ .resource = altps2_1_resources, ++}; ++#endif // na_ps2_1 ++ ++static int __init altps2_device_init(void) ++{ ++ /* customizes platform devices, or adds new ones */ ++ platform_device_register(&altps2_0_device); ++#if defined(na_ps2_1) ++ platform_device_register(&altps2_1_device); ++#endif // na_ps2_1 ++ return 0; ++} ++arch_initcall(altps2_device_init); ++#endif // CONFIG_SERIO_ALTPS2 ++ ++#if defined(CONFIG_I2C_NIOS2_GPIO) && defined(na_gpio_0) ++#include ++ ++static struct gpio_i2c_pins i2c_gpio_0_pins = { ++ .sda_pin = (na_gpio_0+(0<<2)), ++ .scl_pin = (na_gpio_0+(1<<2)), ++}; ++ ++static struct platform_device i2c_gpio_0_controller = { ++ .name = "GPIO-I2C", ++ .id = 0, ++ .dev = { ++ .platform_data = &i2c_gpio_0_pins, ++ }, ++ .num_resources = 0 ++}; ++ ++static int __init i2c_gpio_device_init(void) ++{ ++ /* customizes platform devices, or adds new ones */ ++ platform_device_register(&i2c_gpio_0_controller); ++ return 0; ++} ++arch_initcall(i2c_gpio_device_init); ++ ++#endif // CONFIG_I2C_NIOS2_GPIO +diff --git a/arch/nios2nommu/kernel/signal.c b/arch/nios2nommu/kernel/signal.c +new file mode 100644 +index 0000000..d8c30dc +--- /dev/null ++++ b/arch/nios2nommu/kernel/signal.c +@@ -0,0 +1,738 @@ ++/* ++ * linux/arch/nios2nommu/kernel/signal.c ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ * ++ * Linux/m68k support by Hamish Macdonald ++ * ++ * 68060 fixes by Jesper Skov ++ * ++ * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab ++ * ++ * mathemu support by Roman Zippel ++ * (Note: fpstate in the signal context is completely ignored for the emulator ++ * and the internal floating point format is put on stack) ++ * ++ * ++roman (07/09/96): implemented signal stacks (specially for tosemu on ++ * Atari :-) Current limitation: Only one sigstack can be active at one time. ++ * If a second signal with SA_ONSTACK set arrives while working on a sigstack, ++ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested ++ * signal handlers! ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) ++ ++asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options, ++ struct rusage * ru); ++asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); ++ ++/* ++ * Atomically swap in the new signal mask, and wait for a signal. ++ */ ++asmlinkage int do_sigsuspend(struct pt_regs *regs) ++{ ++ old_sigset_t mask = regs->r4; // Verify correct syscall reg ++ sigset_t saveset; ++ ++ mask &= _BLOCKABLE; ++ spin_lock_irq(¤t->sighand->siglock); ++ saveset = current->blocked; ++ siginitset(¤t->blocked, mask); ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ regs->r2 = -EINTR; ++ while (1) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ if (do_signal(&saveset, regs)) ++ return -EINTR; ++ } ++} ++ ++asmlinkage int ++do_rt_sigsuspend(struct pt_regs *regs) ++{ ++ sigset_t *unewset = (sigset_t *)regs->r4; ++ size_t sigsetsize = (size_t)regs->r5; ++ sigset_t saveset, newset; ++ ++ /* XXX: Don't preclude handling different sized sigset_t's. */ ++ if (sigsetsize != sizeof(sigset_t)) ++ return -EINVAL; ++ ++ if (copy_from_user(&newset, unewset, sizeof(newset))) ++ return -EFAULT; ++ sigdelsetmask(&newset, ~_BLOCKABLE); ++ ++ spin_lock_irq(¤t->sighand->siglock); ++ saveset = current->blocked; ++ current->blocked = newset; ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ regs->r2 = -EINTR; ++ while (1) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ if (do_signal(&saveset, regs)) ++ return -EINTR; ++ } ++} ++ ++asmlinkage int ++sys_sigaction(int sig, const struct old_sigaction *act, ++ struct old_sigaction *oact) ++{ ++ struct k_sigaction new_ka, old_ka; ++ int ret; ++ ++ if (act) { ++ old_sigset_t mask; ++ if (verify_area(VERIFY_READ, act, sizeof(*act)) || ++ __get_user(new_ka.sa.sa_handler, &act->sa_handler) || ++ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) ++ return -EFAULT; ++ __get_user(new_ka.sa.sa_flags, &act->sa_flags); ++ __get_user(mask, &act->sa_mask); ++ siginitset(&new_ka.sa.sa_mask, mask); ++ } ++ ++ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); ++ ++ if (!ret && oact) { ++ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || ++ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || ++ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) ++ return -EFAULT; ++ __put_user(old_ka.sa.sa_flags, &oact->sa_flags); ++ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Do a signal return; undo the signal stack. ++ * ++ * Keep the return code on the stack quadword aligned! ++ * That makes the cache flush below easier. ++ */ ++ ++ ++struct sigframe ++{ ++ char retcode[12]; ++ unsigned long extramask[_NSIG_WORDS-1]; ++ struct sigcontext sc; ++}; ++ ++struct rt_sigframe ++{ ++ char retcode[12]; ++ struct siginfo info; ++ struct ucontext uc; ++}; ++ ++#ifdef CONFIG_FPU ++ ++static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ ++ ++static inline int restore_fpu_state(struct sigcontext *sc) ++{ ++ int err = 1; ++ ++ if (FPU_IS_EMU) { ++ /* restore registers */ ++ memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); ++ memcpy(current->thread.fp, sc->sc_fpregs, 24); ++ return 0; ++ } ++ ++ if (sc->sc_fpstate[0]) { ++ /* Verify the frame format. */ ++ if (sc->sc_fpstate[0] != fpu_version) ++ goto out; ++ ++ __asm__ volatile ("Nios II FPU" ++ : /* no outputs */ ++ : ); ++ } ++ __asm__ volatile ("Nios II FPU" ++ : : ); ++ err = 0; ++ ++out: ++ return err; ++} ++ ++#define FPCONTEXT_SIZE 216 ++#define uc_fpstate uc_filler[0] ++#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] ++#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] ++ ++static inline int rt_restore_fpu_state(struct ucontext *uc) ++{ ++ unsigned char fpstate[FPCONTEXT_SIZE]; ++ int context_size = 0; ++ fpregset_t fpregs; ++ int err = 1; ++ ++ if (FPU_IS_EMU) { ++ /* restore fpu control register */ ++ if (__copy_from_user(current->thread.fpcntl, ++ &uc->uc_mcontext.fpregs.f_pcr, 12)) ++ goto out; ++ /* restore all other fpu register */ ++ if (__copy_from_user(current->thread.fp, ++ uc->uc_mcontext.fpregs.f_fpregs, 96)) ++ goto out; ++ return 0; ++ } ++ ++ if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) ++ goto out; ++ if (fpstate[0]) { ++ context_size = fpstate[1]; ++ ++ /* Verify the frame format. */ ++ if (fpstate[0] != fpu_version) ++ goto out; ++ if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, ++ sizeof(fpregs))) ++ goto out; ++ __asm__ volatile ("Nios II FPU" ++ : /* no outputs */ ++ : ); ++ } ++ if (context_size && ++ __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, ++ context_size)) ++ goto out; ++ __asm__ volatile ("Nios II FPU" ++ : : ); ++ err = 0; ++ ++out: ++ return err; ++} ++ ++#endif ++ ++static inline int ++restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, ++ int *pr2) ++{ ++ int err = 0; ++ int estatus; ++ ++ estatus = regs->estatus; ++ ++ /* get previous pt_regs */ ++ if (copy_from_user(regs, &usc->regs, sizeof(*regs))) ++ goto badframe; ++ ++ /* Prevent user from being able to change ++ * certain processor status bits. Currently nothing. ++ */ ++ regs->estatus = (estatus & 0xffffffff) | (regs->estatus & 0); ++ ++ *pr2 = regs->r2; ++ regs->orig_r2 = -1; /* disable syscall checks */ ++ ++#ifdef CONFIG_FPU ++ err |= restore_fpu_state(&context); ++#endif ++ ++ return err; ++ ++badframe: ++ return 1; ++} ++ ++static inline int ++rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, ++ struct ucontext *uc, int *pr2) ++{ ++ int temp; ++ greg_t *gregs = uc->uc_mcontext.gregs; ++ unsigned long usp; ++ int err; ++ ++ err = __get_user(temp, &uc->uc_mcontext.version); ++ if (temp != MCONTEXT_VERSION) ++ goto badframe; ++ /* restore passed registers */ ++ err |= __get_user(regs->r1, &gregs[0]); ++ err |= __get_user(regs->r2, &gregs[1]); ++ err |= __get_user(regs->r3, &gregs[2]); ++ err |= __get_user(regs->r4, &gregs[3]); ++ err |= __get_user(regs->r5, &gregs[4]); ++ err |= __get_user(regs->r6, &gregs[5]); ++ err |= __get_user(regs->r7, &gregs[6]); ++ err |= __get_user(regs->r8, &gregs[7]); ++ err |= __get_user(regs->r9, &gregs[8]); ++ err |= __get_user(regs->r10, &gregs[9]); ++ err |= __get_user(regs->r11, &gregs[10]); ++ err |= __get_user(regs->r12, &gregs[11]); ++ err |= __get_user(regs->r13, &gregs[12]); ++ err |= __get_user(regs->r14, &gregs[13]); ++ err |= __get_user(regs->r15, &gregs[14]); ++ err |= __get_user(sw->r16, &gregs[15]); ++ err |= __get_user(sw->r17, &gregs[16]); ++ err |= __get_user(sw->r18, &gregs[17]); ++ err |= __get_user(sw->r19, &gregs[18]); ++ err |= __get_user(sw->r20, &gregs[19]); ++ err |= __get_user(sw->r21, &gregs[20]); ++ err |= __get_user(sw->r22, &gregs[21]); ++ err |= __get_user(sw->r23, &gregs[22]); ++ err |= __get_user(usp, &gregs[23]); ++ err |= __get_user(sw->fp, &gregs[24]); // Verify, should this be settable ++ err |= __get_user(sw->gp, &gregs[25]); // Verify, should this be settable ++ ++ err |= __get_user(temp, &gregs[26]); // Not really necessary no user settable bits ++ regs->estatus = (regs->estatus & 0xffffffff) | (temp & 0x0); ++ err |= __get_user(regs->status_extension, ++ &uc->uc_mcontext.status_extension); ++ regs->orig_r2 = -1; /* disable syscall checks */ ++ ++ if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) ++ goto badframe; ++ ++ *pr2 = regs->r2; ++ return err; ++ ++badframe: ++ return 1; ++} ++ ++asmlinkage int do_sigreturn(struct pt_regs *regs) ++{ ++ struct sigframe *frame = (struct sigframe *) regs->sp; ++ sigset_t set; ++ int rval; ++ ++ if (verify_area(VERIFY_READ, frame, sizeof(*frame))) ++ goto badframe; ++ if (__get_user(set.sig[0], &frame->sc.sc_mask) || ++ (_NSIG_WORDS > 1 && ++ __copy_from_user(&set.sig[1], &frame->extramask, ++ sizeof(frame->extramask)))) ++ goto badframe; ++ ++ sigdelsetmask(&set, ~_BLOCKABLE); ++ spin_lock_irq(¤t->sighand->siglock); ++ current->blocked = set; ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ if (restore_sigcontext(regs, &frame->sc, frame + 1, &rval)) ++ goto badframe; ++ return rval; ++ ++badframe: ++ force_sig(SIGSEGV, current); ++ return 0; ++} ++ ++asmlinkage int do_rt_sigreturn(struct switch_stack *sw) ++{ ++ struct pt_regs *regs = (struct pt_regs *) sw + 1; ++ struct rt_sigframe *frame = (struct rt_sigframe *) regs->sp; // Verify, can we follow the stack back ++ sigset_t set; ++ int rval; ++ ++ if (verify_area(VERIFY_READ, frame, sizeof(*frame))) ++ goto badframe; ++ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) ++ goto badframe; ++ ++ sigdelsetmask(&set, ~_BLOCKABLE); ++ spin_lock_irq(¤t->sighand->siglock); ++ current->blocked = set; ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ if (rt_restore_ucontext(regs, sw, &frame->uc, &rval)) ++ goto badframe; ++ return rval; ++ ++badframe: ++ force_sig(SIGSEGV, current); ++ return 0; ++} ++ ++#ifdef CONFIG_FPU ++/* ++ * Set up a signal frame. ++ * ++ * Not converted, no FPU support at moment. ++ */ ++ ++static inline int save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) ++{ ++ int err = 0; ++ ++ if (FPU_IS_EMU) { ++ /* save registers */ ++ err |= copy_to_user(&sc->sc_fpcntl, current->thread.fpcntl, 12); ++ err |= copy_to_user(&sc->sc_fpregs, current->thread.fp, 24); ++ return err; ++ } ++ ++ __asm__ volatile ("Nios II FPUt" ++ : : ); ++ ++ if (sc->sc_fpstate[0]) { ++ fpu_version = sc->sc_fpstate[0]; ++ __asm__ volatile ("Nios II FPU" ++ : /* no outputs */ ++ : ++ : ); ++ } ++ return err; ++} ++ ++static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) ++{ ++ unsigned char fpstate[FPCONTEXT_SIZE]; ++ int context_size = 0; ++ int err = 0; ++ ++ if (FPU_IS_EMU) { ++ /* save fpu control register */ ++ err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, ++ current->thread.fpcntl, 12); ++ /* save all other fpu register */ ++ err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, ++ current->thread.fp, 96); ++ return err; ++ } ++ ++ __asm__ volatile ("Nios II FPU" ++ : : : ); ++ ++ err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); ++ if (fpstate[0]) { ++ fpregset_t fpregs; ++ context_size = fpstate[1]; ++ fpu_version = fpstate[0]; ++ __asm__ volatile ("Nios II FPU" ++ : /* no outputs */ ++ : ++ : ); ++ err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, ++ sizeof(fpregs)); ++ } ++ if (context_size) ++ err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, ++ context_size); ++ return err; ++} ++ ++#endif ++ ++static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, ++ unsigned long mask) ++{ ++ int err = 0; ++ ++ err |= __put_user(mask, &sc->sc_mask); ++ err |= copy_to_user(&sc->regs, regs, sizeof(*regs)); ++#ifdef CONFIG_FPU ++ err |= save_fpu_state(sc, regs); ++#endif ++ return err; ++} ++ ++static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) ++{ ++ struct switch_stack *sw = (struct switch_stack *)regs - 1; ++ greg_t *gregs = uc->uc_mcontext.gregs; ++ int err = 0; ++ ++ err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); ++ err |= __put_user(regs->status_extension, ++ &uc->uc_mcontext.status_extension); ++ err |= __put_user(regs->r1, &gregs[0]); ++ err |= __put_user(regs->r2, &gregs[1]); ++ err |= __put_user(regs->r3, &gregs[2]); ++ err |= __put_user(regs->r4, &gregs[3]); ++ err |= __put_user(regs->r5, &gregs[4]); ++ err |= __put_user(regs->r6, &gregs[5]); ++ err |= __put_user(regs->r7, &gregs[6]); ++ err |= __put_user(regs->r8, &gregs[7]); ++ err |= __put_user(regs->r9, &gregs[8]); ++ err |= __put_user(regs->r10, &gregs[9]); ++ err |= __put_user(regs->r11, &gregs[10]); ++ err |= __put_user(regs->r12, &gregs[11]); ++ err |= __put_user(regs->r13, &gregs[12]); ++ err |= __put_user(regs->r14, &gregs[13]); ++ err |= __put_user(regs->r15, &gregs[14]); ++ err |= __put_user(sw->r16, &gregs[15]); ++ err |= __put_user(sw->r17, &gregs[16]); ++ err |= __put_user(sw->r18, &gregs[17]); ++ err |= __put_user(sw->r19, &gregs[18]); ++ err |= __put_user(sw->r20, &gregs[19]); ++ err |= __put_user(sw->r21, &gregs[20]); ++ err |= __put_user(sw->r22, &gregs[21]); ++ err |= __put_user(sw->r23, &gregs[22]); ++ err |= __put_user(regs->sp, &gregs[23]); ++ err |= __put_user(sw->fp, &gregs[24]); ++ err |= __put_user(sw->gp, &gregs[25]); ++#ifdef CONFIG_FPU ++ err |= rt_save_fpu_state(uc, regs); ++#endif ++ return err; ++} ++ ++extern void cache_push_v (unsigned long vaddr, int len); ++ ++static inline void push_cache (unsigned long vaddr) ++{ ++ cache_push_v(vaddr,12); ++} ++ ++static inline void * ++get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) ++{ ++ unsigned long usp; ++ ++ /* Default to using normal stack. */ ++ usp = regs->sp; ++ ++ /* This is the X/Open sanctioned signal stack switching. */ ++ if (ka->sa.sa_flags & SA_ONSTACK) { ++ if (!on_sig_stack(usp)) ++ usp = current->sas_ss_sp + current->sas_ss_size; ++ } ++ return (void *)((usp - frame_size) & -8UL); // Verify, is it 32 or 64 bit aligned ++} ++ ++static void setup_frame (int sig, struct k_sigaction *ka, ++ sigset_t *set, struct pt_regs *regs) ++{ ++ struct sigframe *frame; ++ int err = 0; ++ ++ frame = get_sigframe(ka, regs, sizeof(*frame)); ++ ++ if (_NSIG_WORDS > 1) ++ err |= copy_to_user(frame->extramask, &set->sig[1], ++ sizeof(frame->extramask)); ++ ++ err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); ++ ++ /* Set up to return from userspace. */ ++ regs->ra = (unsigned long) &frame->retcode[0]; ++ /* movi r3,__NR_sigreturn */ ++ err |= __put_user(0x00c00004 + (__NR_sigreturn << 6), (long *)(frame->retcode)); ++ /* mov r2,r0 */ ++ err |= __put_user(0x0005883a, (long *)(frame->retcode + 4)); ++ /* trap */ ++ err |= __put_user(0x003b683a, (long *)(frame->retcode + 8)); ++ ++ if (err) ++ goto give_sigsegv; ++ ++ push_cache ((unsigned long) &frame->retcode); ++ ++ /* Set up registers for signal handler */ ++ regs->sp = (unsigned long) frame; ++ regs->r4 = (unsigned long) (current_thread_info()->exec_domain ++ && current_thread_info()->exec_domain->signal_invmap ++ && sig < 32 ++ ? current_thread_info()->exec_domain->signal_invmap[sig] ++ : sig); ++ regs->ea = (unsigned long) ka->sa.sa_handler; ++ return; ++ ++give_sigsegv: ++ if (sig == SIGSEGV) ++ ka->sa.sa_handler = SIG_DFL; ++ force_sig(SIGSEGV, current); ++} ++ ++static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, ++ sigset_t *set, struct pt_regs *regs) ++{ ++ struct rt_sigframe *frame; ++ int err = 0; ++ ++ frame = get_sigframe(ka, regs, sizeof(*frame)); ++ ++ err |= copy_siginfo_to_user(&frame->info, info); ++ ++ /* Create the ucontext. */ ++ err |= __put_user(0, &frame->uc.uc_flags); ++ err |= __put_user(0, &frame->uc.uc_link); ++ err |= __put_user((void *)current->sas_ss_sp, ++ &frame->uc.uc_stack.ss_sp); ++ err |= __put_user(sas_ss_flags(regs->sp), ++ &frame->uc.uc_stack.ss_flags); ++ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); ++ err |= rt_setup_ucontext(&frame->uc, regs); ++ err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); ++ ++ /* Set up to return from userspace. */ ++ regs->ra = (unsigned long) &frame->retcode[0]; ++ /* movi r3,__NR_rt_sigreturn */ ++ err |= __put_user(0x00c00004 + (__NR_rt_sigreturn << 6), (long *)(frame->retcode)); ++ /* mov r2,r0 */ ++ err |= __put_user(0x0005883a, (long *)(frame->retcode + 4)); ++ /* trap */ ++ err |= __put_user(0x003b683a, (long *)(frame->retcode + 8)); ++ ++ if (err) ++ goto give_sigsegv; ++ ++ push_cache ((unsigned long) &frame->retcode); ++ ++ /* Set up registers for signal handler */ ++ regs->sp = (unsigned long) frame; ++ regs->r4 = (unsigned long) (current_thread_info()->exec_domain ++ && current_thread_info()->exec_domain->signal_invmap ++ && sig < 32 ++ ? current_thread_info()->exec_domain->signal_invmap[sig] ++ : sig); ++ regs->r5 = (unsigned long) &frame->info; ++ regs->r6 = (unsigned long) &frame->uc; ++ regs->ea = (unsigned long) ka->sa.sa_handler; ++ return; ++ ++give_sigsegv: ++ if (sig == SIGSEGV) ++ ka->sa.sa_handler = SIG_DFL; ++ force_sig(SIGSEGV, current); ++} ++ ++static inline void ++handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) ++{ ++ switch (regs->r2) { ++ case -ERESTARTNOHAND: ++ if (!has_handler) ++ goto do_restart; ++ regs->r2 = -EINTR; ++ break; ++ ++ case -ERESTARTSYS: ++ if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { ++ regs->r2 = -EINTR; ++ break; ++ } ++ /* fallthrough */ ++ case -ERESTARTNOINTR: ++ do_restart: ++ regs->r2 = regs->orig_r2; ++ regs->ea -= 4; ++ break; ++ } ++} ++ ++/* ++ * OK, we're invoking a handler ++ */ ++static void ++handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, ++ sigset_t *oldset, struct pt_regs *regs) ++{ ++ /* are we from a system call? */ ++ if (regs->orig_r2 >= 0) ++ /* If so, check system call restarting.. */ ++ handle_restart(regs, ka, 1); ++ ++ /* set up the stack frame */ ++ if (ka->sa.sa_flags & SA_SIGINFO) ++ setup_rt_frame(sig, ka, info, oldset, regs); ++ else ++ setup_frame(sig, ka, oldset, regs); ++ ++ if (ka->sa.sa_flags & SA_ONESHOT) ++ ka->sa.sa_handler = SIG_DFL; ++ ++ if (!(ka->sa.sa_flags & SA_NODEFER)) { ++ spin_lock_irq(¤t->sighand->siglock); ++ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); ++ sigaddset(¤t->blocked,sig); ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ } ++} ++ ++/* ++ * Note that 'init' is a special process: it doesn't get signals it doesn't ++ * want to handle. Thus you cannot kill init even with a SIGKILL even by ++ * mistake. ++ */ ++asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) ++{ ++ struct k_sigaction ka; ++ siginfo_t info; ++ int signr; ++ ++ /* ++ * We want the common case to go fast, which ++ * is why we may in certain cases get here from ++ * kernel mode. Just return without doing anything ++ * if so. ++ */ ++ if (!user_mode(regs)) ++ return 1; ++ ++ /* FIXME - Do we still need to do this ? */ ++ current->thread.kregs = regs; ++ ++ if (!oldset) ++ oldset = ¤t->blocked; ++ ++ signr = get_signal_to_deliver(&info, &ka, regs, NULL); ++ if (signr > 0) { ++ /* Whee! Actually deliver the signal. */ ++ handle_signal(signr, &ka, &info, oldset, regs); ++ return 1; ++ } ++ ++ /* Did we come from a system call? */ ++ if (regs->orig_r2 >= 0){ ++ /* Restart the system call - no handlers present */ ++ if (regs->r2 == -ERESTARTNOHAND ++ || regs->r2 == -ERESTARTSYS ++ || regs->r2 == -ERESTARTNOINTR) { ++ regs->r2 = regs->orig_r2; ++ regs->ea -= 4; ++ } else if (regs->r2 == -ERESTART_RESTARTBLOCK) { ++ regs->r2 = __NR_restart_syscall; ++ regs->ea -= 4; ++ } ++ } ++ return 0; ++} +diff --git a/arch/nios2nommu/kernel/start.c b/arch/nios2nommu/kernel/start.c +new file mode 100644 +index 0000000..bca81fc +--- /dev/null ++++ b/arch/nios2nommu/kernel/start.c +@@ -0,0 +1,502 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/kernel/start.c ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * May/20/2005 dgt Altera NiosII Custom shift instr(s) ++ * possibly assumed by memcpy, etc; ensure ++ * "correct" core loaded therefore if so. ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ #ifdef CONFIG_SERIAL_AJUART //;dgt;20may05; ++ #ifdef CONFIG_SERIAL_AJUART_CONSOLE //;dgt;20may05; ++ ++ #include //;dgt;20may05; ++ #include //;dgt;20may05; ++ ++ extern struct console juart_console; //;dgt;20may05; ++ ++ #endif // CONFIG_SERIAL_AJUART //;dgt;20may05; ++ #endif // CONFIG_SERIAL_AJUART_CONSOLE //;dgt;20may05; ++ ++//;dgt;20may05; #ifdef CONFIG_CRC_CHECK ++ ++// #if defined(CONFIG_NIOS_SERIAL) //;dgt;20may05; ++// #if defined(CONFIG_NIOS_SERIAL_CONSOLE) //;dgt;20may05; ++ #if defined(nasys_printf_uart) //;dgt;20may05; ++ static void putsNoNewLine( unsigned char *s ) ++ { ++ while(*s) { ++ while (!(nasys_printf_uart->np_uartstatus & ++ np_uartstatus_trdy_mask)); ++ nasys_printf_uart->np_uarttxdata = *s++; ++ } ++ } ++ ++ #define NL "\r\n" ++ static void puts(unsigned char *s) ++ { ++ putsNoNewLine( s ); ++ putsNoNewLine( NL ); ++ } ++ #endif // nasys_printf_uart //;dgt;20may05; ++// #endif // CONFIG_NIOS_SERIAL_CONSOLE) //;dgt;20may05; ++// #endif // CONFIG_NIOS_SERIAL) //;dgt;20may05; ++ ++#ifdef CONFIG_CRC_CHECK //;dgt;20may05; ++ ++#if 1 ++#define outchar(X) { \ ++ while (!(nasys_printf_uart->np_uartstatus & np_uartstatus_trdy_mask)); \ ++ nasys_printf_uart->np_uarttxdata = (X); } ++#else ++#define outchar(X) putchar(X) ++#endif ++#define outhex(X,Y) { \ ++ unsigned long __w; \ ++ __w = ((X) >> (Y)) & 0xf; \ ++ __w = __w > 0x9 ? 'A' + __w - 0xa : '0' + __w; \ ++ outchar(__w); } ++#define outhex8(X) { \ ++ outhex(X,4); \ ++ outhex(X,0); } ++#define outhex16(X) { \ ++ outhex(X,12); \ ++ outhex(X,8); \ ++ outhex(X,4); \ ++ outhex(X,0); } ++#define outhex32(X) { \ ++ outhex(X,28); \ ++ outhex(X,24); \ ++ outhex(X,20); \ ++ outhex(X,16); \ ++ outhex(X,12); \ ++ outhex(X,8); \ ++ outhex(X,4); \ ++ outhex(X,0); } ++#endif ++ ++#if 0 ++static unsigned long testvar = 0xdeadbeef; ++#endif ++ ++#ifdef CONFIG_CRC_CHECK ++ ++ ++/******************************************************/ ++ ++ ++extern unsigned long __CRC_Table_Begin; ++ ++typedef unsigned char U8; ++typedef unsigned long U32; ++ ++/* Table of CRC-32's of all single byte values */ ++const U32 crc_32_tab[] = { ++ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, ++ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, ++ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, ++ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, ++ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, ++ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, ++ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, ++ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, ++ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, ++ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, ++ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, ++ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, ++ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, ++ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, ++ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, ++ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, ++ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, ++ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, ++ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, ++ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, ++ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, ++ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, ++ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, ++ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, ++ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, ++ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, ++ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, ++ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, ++ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, ++ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, ++ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, ++ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, ++ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, ++ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, ++ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, ++ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, ++ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, ++ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, ++ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, ++ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, ++ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, ++ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, ++ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, ++ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, ++ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, ++ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, ++ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, ++ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, ++ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, ++ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, ++ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, ++ 0x2d02ef8dL ++}; ++ ++U32 Calc_CRC( const U8 *p, U32 len ) ++{ ++ U32 crc = (U32)~0L; ++ while (len--) ++ crc = crc_32_tab[0xFF & (crc ^ *p++)] ^ (crc >> 8); ++ ++ return crc ^ (U32)~0L; ++} ++ ++ ++ ++/******************************************************/ ++ ++ ++/* hjz: Following time stuff is hacked and modified from uC-libc (various files), which in turn was... */ ++/* This is adapted from glibc */ ++/* Copyright (C) 1991, 1993 Free Software Foundation, Inc */ ++ ++#define SECS_PER_HOUR 3600L ++#define SECS_PER_DAY 86400L ++typedef unsigned long time_t; ++ ++ ++static const unsigned short int __mon_lengths[2][12] = { ++ /* Normal years. */ ++ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, ++ /* Leap years. */ ++ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} ++}; ++/* This global is exported to the wide world in keeping ++ * with the interface in time.h */ ++long int timezone = 0; ++ ++static const char *dayOfWeek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; ++static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", ++ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; ++ ++/* Nonzero if YEAR is a leap year (every 4 years, ++ except every 100th isn't, and every 400th is). */ ++# define __isleap(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) ++ ++struct tm ++{ ++ int tm_sec; /* Seconds. [0-60] (1 leap second) */ ++ int tm_min; /* Minutes. [0-59] */ ++ int tm_hour; /* Hours. [0-23] */ ++ int tm_mday; /* Day. [1-31] */ ++ int tm_mon; /* Month. [0-11] */ ++ int tm_year; /* Year - 1900. */ ++ int tm_wday; /* Day of week. [0-6] */ ++ int tm_yday; /* Days in year.[0-365] */ ++ int tm_isdst; /* DST. [-1/0/1]*/ ++ ++# ifdef __USE_BSD ++ long int tm_gmtoff; /* Seconds east of UTC. */ ++ __const char *tm_zone; /* Timezone abbreviation. */ ++# else ++ long int __tm_gmtoff; /* Seconds east of UTC. */ ++ __const char *__tm_zone; /* Timezone abbreviation. */ ++# endif ++}; ++ ++void __tm_conv(struct tm *tmbuf, time_t *t, time_t offset) ++{ ++ long days, rem; ++ register int y; ++ register const unsigned short int *ip; ++ ++ timezone = -offset; ++ ++ days = *t / SECS_PER_DAY; ++ rem = *t % SECS_PER_DAY; ++ rem += offset; ++ while (rem < 0) ++ { ++ rem += SECS_PER_DAY; ++ days--; ++ } ++ while (rem >= SECS_PER_DAY) ++ { ++ rem -= SECS_PER_DAY; ++ days++; ++ } ++ ++ tmbuf->tm_hour = rem / SECS_PER_HOUR; ++ rem %= SECS_PER_HOUR; ++ tmbuf->tm_min = rem / 60; ++ tmbuf->tm_sec = rem % 60; ++ ++ /* January 1, 1970 was a Thursday. */ ++ tmbuf->tm_wday = (4 + days) % 7; ++ if (tmbuf->tm_wday < 0) ++ tmbuf->tm_wday += 7; ++ ++ y = 1970; ++ while (days >= (rem = __isleap(y) ? 366 : 365)) ++ { ++ y++; ++ days -= rem; ++ } ++ ++ while (days < 0) ++ { ++ y--; ++ days += __isleap(y) ? 366 : 365; ++ } ++ ++ tmbuf->tm_year = y - 1900; ++ tmbuf->tm_yday = days; ++ ++ ip = __mon_lengths[__isleap(y)]; ++ for (y = 0; days >= ip[y]; ++y) ++ days -= ip[y]; ++ ++ tmbuf->tm_mon = y; ++ tmbuf->tm_mday = days + 1; ++ tmbuf->tm_isdst = -1; ++} ++ ++ ++ ++/* hjz: NOT your traditional ctime: This one includes timezone */ ++/* (UTC) and excludes the traditional trailing newline. */ ++char *CTime( time_t *t ) ++{ ++ static char theTime[29]; ++ struct tm tm; ++ ++ __tm_conv( &tm, t, 0 ); ++ sprintf( theTime, "%s %s %02d %02d:%02d:%02d UTC %04d", ++ dayOfWeek[tm.tm_wday], month[tm.tm_mon], tm.tm_mday, ++ tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900 ); ++ ++ return theTime; ++} ++ ++/******************************************************/ ++ ++ ++/* hjz: polled-I/O: Get a char if one is ready, or return -1 */ ++int getc( void ) ++{ ++ if ( nasys_printf_uart->np_uartstatus & np_uartstatus_rrdy_mask ) ++ return nasys_printf_uart->np_uartrxdata; ++ else ++ return -1; ++} ++ ++ ++typedef unsigned long off_t; ++typedef struct ++{ ++ U8 *startAddr; ++ U8 *endAddr; ++ U32 CRC; ++ time_t mtime; ++ off_t size; // File size ++ char id[44]; // Filename. If path exceeds available size, name is "..." + last 40 chars of given filename ++ char host[32]; // hostname. If name exceeds available size name is first 28 chars of hostname + "..." ++} FLASH_REGION_DESC; ++ ++ ++int Test_Flash_Regions(void) ++{ ++ FLASH_REGION_DESC *pRegion = (FLASH_REGION_DESC *)&__CRC_Table_Begin; ++ U32 crc; ++ char cBuff[256]; ++ int nrFailedRegions = 0; ++ int regionStatus; ++ int i; ++ unsigned int startAddr = (int) pRegion->startAddr; ++ unsigned int endAddr = (int) pRegion->endAddr; ++ ++ puts( "***Checking flash CRC's" ); ++ if ( (startAddr == -1) || (startAddr >= endAddr) ++ || !( ((startAddr >= (int) NIOS_FLASH_START) && (endAddr < (int) NIOS_FLASH_END)) ++ || ((startAddr >= (int) na_flash) && (endAddr < (int) na_flash_end)) ) ) ++ { ++ puts( " No Flash regions defined." ); ++ return -1; ++ } ++ ++ ++ for ( i = 0; pRegion->startAddr && pRegion->startAddr != (U8 *)~0L; pRegion++, i++ ) ++ { ++ crc = Calc_CRC( pRegion->startAddr, pRegion->endAddr - pRegion->startAddr ); ++ if ( crc != pRegion->CRC ) ++ { ++ regionStatus = 1; ++ nrFailedRegions++; ++ } ++ else ++ regionStatus = 0; ++ ++ sprintf( cBuff, " Region %d: 0x%08lX - 0x%08lX, CRC = 0x%08lX --> %s" NL ++ " From file `%s' on host `%s'" NL ++ " Dated %s, size = %lu bytes", ++ i, (U32)pRegion->startAddr, (U32)pRegion->endAddr, pRegion->CRC, ++ regionStatus ? "***Failed" : "Passed", ++ pRegion->id, pRegion->host, CTime( &pRegion->mtime ), pRegion->size ++ ); ++ puts( cBuff ); ++ } ++ ++ return nrFailedRegions; ++} ++#endif /* CONFIG_CRC_CHECK */ ++ ++ ++int main(void) { ++ ++#ifdef DEBUG ++ puts("MAIN: starting c\n"); ++#endif ++ ++#ifdef CONFIG_KGDB /* builtin GDB stub */ ++ ++/* Set up GDB stub, and make the first trap into it */ ++ nios_gdb_install(1); ++#ifdef CONFIG_BREAK_ON_START ++ puts( "MAIN: trapping to debugger - make sure nios-elf-gdb is running on host." ); ++ nios_gdb_breakpoint(); ++ nop(); ++#endif ++ ++#endif /* CONFIG_KGDB */ ++ ++#ifdef CONFIG_CRC_CHECK ++ #ifdef CONFIG_PROMPT_ON_MISSING_CRC_TABLES ++ if ( Test_Flash_Regions() ) ++ #else ++ if ( Test_Flash_Regions() > 0 ) ++ #endif ++ { ++ int c; ++ char tmp[3]; ++ while ( getc() != -1 ) // flush input ++ ; ++ ++ putsNoNewLine( " Do you wish to continue (Y/N) ? " ); ++ while ( 1 ) ++ { ++ c = getc(); ++ if ( c == -1 ) ++ continue; ++ ++ if ( !isprint( c ) ) ++ c = '?'; ++ ++ sprintf( tmp, "\b%c", c ); ++ putsNoNewLine( tmp ); ++ c = toupper( c ); ++ if ( c == 'Y' ) ++ { ++ puts( "" ); ++ break; ++ } ++ ++ if ( c == 'N' ) ++ { ++ puts( NL "***Trapping to monitor..." ); ++ return -1; ++ } ++ } ++ } ++ puts( "***Starting kernel..." ); ++ ++#endif ++ ++ // Altera NiosII Custom shift instr(s) possibly //;dgt; ++ // assumed by memcpy, etc; ensure "correct" core //;dgt; ++ // loaded therefore if so. //;dgt; ++ ++ #if defined(ALT_CI_ALIGN_32_N) //;dgt; ++ if(ALT_CI_ALIGN_32(1, 0xA9876543, //;dgt; ++ 0xB210FEDC) != 0x10FEDCA9) //;dgt; ++ { //;dgt; ++ goto badshiftci_label; //;dgt; ++ } //;dgt; ++ if(ALT_CI_ALIGN_32(2, 0xA9876543, //;dgt; ++ 0xB210FEDC) != 0xFEDCA987) //;dgt; ++ { //;dgt; ++ goto badshiftci_label; //;dgt; ++ } //;dgt; ++ if(ALT_CI_ALIGN_32(3, 0xA9876543, //;dgt; ++ 0xB210FEDC) != 0xDCA98765) //;dgt; ++ { //;dgt; ++ goto badshiftci_label; //;dgt; ++ } //;dgt; ++ #endif //;dgt; ++ goto gudshiftci_label; //;dgt; ++badshiftci_label: //;dgt; ++ { //;dgt; ++ unsigned char BadCImsg[] = //;dgt; ++ "?...ALT_CI_ALIGNn_321() NOT expected" //;dgt; ++ " NiosII custom instruction\n"; //;dgt; ++ unsigned char CIabortMsg[] = //;dgt; ++ " ...aborting uClinux startup..."; //;dgt; ++ ++ #ifdef CONFIG_SERIAL_AJUART //;dgt; ++ #ifdef CONFIG_SERIAL_AJUART_CONSOLE //;dgt; ++ juart_console.index = 0; //;dgt; ++ jtaguart_console_write(&(juart_console), //;dgt; ++ BadCImsg, //;dgt; ++ strlen(BadCImsg)); //;dgt; ++ jtaguart_console_write(&(juart_console), //;dgt; ++ CIabortMsg, //;dgt; ++ strlen(CIabortMsg)); //;dgt; ++ #endif // CONFIG_SERIAL_AJUART //;dgt; ++ #endif // CONFIG_SERIAL_AJUART_CONSOLE //;dgt; ++ ++// #if defined(CONFIG_NIOS_SERIAL) //;dgt; ++// #if defined(CONFIG_NIOS_SERIAL_CONSOLE) //;dgt; ++ #if defined(nasys_printf_uart) //;dgt; ++ puts(BadCImsg); //;dgt; ++ puts(CIabortMsg); //;dgt; ++ #endif // nasys_printf_uart //;dgt; ++// #endif // CONFIG_NIOS_SERIAL_CONSOLE) //;dgt; ++// #endif // CONFIG_NIOS_SERIAL) //;dgt; ++ ++ panic(" ...wrong fpga core?..."); //;dgt; ++ } //;dgt; ++ ++gudshiftci_label: //;dgt; ++ ++ start_kernel(); ++ return 0; ++} +diff --git a/arch/nios2nommu/kernel/sys_nios2.c b/arch/nios2nommu/kernel/sys_nios2.c +new file mode 100644 +index 0000000..8018fb0 +--- /dev/null ++++ b/arch/nios2nommu/kernel/sys_nios2.c +@@ -0,0 +1,248 @@ ++/* ++ * linux/arch/nios2nommu/kernel/sys_nios2.c ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * This file contains various random system calls that ++ * have a non-standard calling sequence on the Linux/nios2nommu ++ * platform. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * sys_pipe() is the normal C calling standard for creating ++ * a pipe. It's not the way unix traditionally does this, though. ++ */ ++asmlinkage int sys_pipe(unsigned long * fildes) ++{ ++ int fd[2]; ++ int error; ++ ++ error = do_pipe(fd); ++ if (!error) { ++ if (copy_to_user(fildes, fd, 2*sizeof(int))) ++ error = -EFAULT; ++ } ++ return error; ++} ++ ++/* common code for old and new mmaps */ ++static inline long do_mmap2( ++ unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long pgoff) ++{ ++ int error = -EBADF; ++ struct file * file = NULL; ++ ++ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); ++ if (!(flags & MAP_ANONYMOUS)) { ++ file = fget(fd); ++ if (!file) ++ goto out; ++ } ++ ++ down_write(¤t->mm->mmap_sem); ++ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); ++ up_write(¤t->mm->mmap_sem); ++ ++ if (file) ++ fput(file); ++out: ++ return error; ++} ++ ++asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long pgoff) ++{ ++ return do_mmap2(addr, len, prot, flags, fd, pgoff); ++} ++ ++/* ++ * Perform the select(nd, in, out, ex, tv) and mmap() system ++ * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to ++ * handle more than 4 system call parameters, so these system calls ++ * used a memory block for parameter passing.. ++ */ ++ ++struct mmap_arg_struct { ++ unsigned long addr; ++ unsigned long len; ++ unsigned long prot; ++ unsigned long flags; ++ unsigned long fd; ++ unsigned long offset; ++}; ++ ++asmlinkage int old_mmap(struct mmap_arg_struct *arg) ++{ ++ struct mmap_arg_struct a; ++ int error = -EFAULT; ++ ++ if (copy_from_user(&a, arg, sizeof(a))) ++ goto out; ++ ++ error = -EINVAL; ++ if (a.offset & ~PAGE_MASK) ++ goto out; ++ ++ a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); ++ ++ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); ++out: ++ return error; ++} ++ ++struct sel_arg_struct { ++ unsigned long n; ++ fd_set *inp, *outp, *exp; ++ struct timeval *tvp; ++}; ++ ++asmlinkage int old_select(struct sel_arg_struct *arg) ++{ ++ struct sel_arg_struct a; ++ ++ if (copy_from_user(&a, arg, sizeof(a))) ++ return -EFAULT; ++ /* sys_select() does the appropriate kernel locking */ ++ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); ++} ++ ++/* ++ * sys_ipc() is the de-multiplexer for the SysV IPC calls.. ++ * ++ * This is really horribly ugly. ++ */ ++asmlinkage int sys_ipc (uint call, int first, int second, ++ int third, void *ptr, long fifth) ++{ ++ int version; ++ ++ version = call >> 16; /* hack for backward compatibility */ ++ call &= 0xffff; ++ ++ if (call <= SEMCTL) ++ switch (call) { ++ case SEMOP: ++ return sys_semop (first, (struct sembuf *)ptr, second); ++ case SEMGET: ++ return sys_semget (first, second, third); ++ case SEMCTL: { ++ union semun fourth; ++ if (!ptr) ++ return -EINVAL; ++ if (get_user(fourth.__pad, (void **) ptr)) ++ return -EFAULT; ++ return sys_semctl (first, second, third, fourth); ++ } ++ default: ++ return -EINVAL; ++ } ++ if (call <= MSGCTL) ++ switch (call) { ++ case MSGSND: ++ return sys_msgsnd (first, (struct msgbuf *) ptr, ++ second, third); ++ case MSGRCV: ++ switch (version) { ++ case 0: { ++ struct ipc_kludge tmp; ++ if (!ptr) ++ return -EINVAL; ++ if (copy_from_user (&tmp, ++ (struct ipc_kludge *)ptr, ++ sizeof (tmp))) ++ return -EFAULT; ++ return sys_msgrcv (first, tmp.msgp, second, ++ tmp.msgtyp, third); ++ } ++ default: ++ return sys_msgrcv (first, ++ (struct msgbuf *) ptr, ++ second, fifth, third); ++ } ++ case MSGGET: ++ return sys_msgget ((key_t) first, second); ++ case MSGCTL: ++ return sys_msgctl (first, second, ++ (struct msqid_ds *) ptr); ++ default: ++ return -EINVAL; ++ } ++ ++ return -EINVAL; ++} ++ ++/* sys_cacheflush -- flush the processor cache. */ ++asmlinkage int ++sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) ++{ ++ flush_cache_all(); ++ return(0); ++} ++ ++asmlinkage int sys_getpagesize(void) ++{ ++ return PAGE_SIZE; ++} ++ ++/* ++ * Do a system call from kernel instead of calling sys_execve so we ++ * end up with proper pt_regs. ++ */ ++int kernel_execve(const char *filename, char *const argv[], char *const envp[]) ++{ ++ register long __res __asm__ ("r2") = TRAP_ID_SYSCALL; ++ register long __sc __asm__ ("r3") = __NR_execve; ++ register long __a __asm__ ("r4") = (long) filename; ++ register long __b __asm__ ("r5") = (long) argv; ++ register long __c __asm__ ("r6") = (long) envp; ++ __asm__ __volatile__ ("trap" : "=r" (__res) ++ : "0" (__res), "r" (__sc), "r" (__a), "r" (__b), "r" (__c) ++ : "memory"); ++ ++ return __res; ++} +diff --git a/arch/nios2nommu/kernel/syscalltable.S b/arch/nios2nommu/kernel/syscalltable.S +new file mode 100644 +index 0000000..3507e24 +--- /dev/null ++++ b/arch/nios2nommu/kernel/syscalltable.S +@@ -0,0 +1,362 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/kernel/syscalltable.S ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) ++ * Copyright (C) 2000 Lineo Inc. (www.lineo.com) ++ * Copyright (C) 1998 D. Jeff Dionne , ++ * Kenneth Albanowski , ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++ ++.text ++ALIGN ++ENTRY(sys_call_table) ++ .long sys_ni_syscall /* 0 - old "setup()" system call*/ ++ .long sys_exit ++ .long sys_fork ++ .long sys_read ++ .long sys_write ++ .long sys_open /* 5 */ ++ .long sys_close ++ .long sys_waitpid ++ .long sys_creat ++ .long sys_link ++ .long sys_unlink /* 10 */ ++ .long sys_execve ++ .long sys_chdir ++ .long sys_time ++ .long sys_mknod ++ .long sys_chmod /* 15 */ ++ .long sys_chown16 ++ .long sys_ni_syscall /* old break syscall holder */ ++ .long sys_stat ++ .long sys_lseek ++ .long sys_getpid /* 20 */ ++ .long sys_mount ++ .long sys_oldumount ++ .long sys_setuid16 ++ .long sys_getuid16 ++ .long sys_stime /* 25 */ ++ .long sys_ptrace ++ .long sys_alarm ++ .long sys_fstat ++ .long sys_pause ++ .long sys_utime /* 30 */ ++ .long sys_ni_syscall /* old stty syscall holder */ ++ .long sys_ni_syscall /* old gtty syscall holder */ ++ .long sys_access ++ .long sys_nice ++ .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ ++ .long sys_sync ++ .long sys_kill ++ .long sys_rename ++ .long sys_mkdir ++ .long sys_rmdir /* 40 */ ++ .long sys_dup ++ .long sys_pipe ++ .long sys_times ++ .long sys_ni_syscall /* old prof syscall holder */ ++ .long sys_brk /* 45 */ ++ .long sys_setgid16 ++ .long sys_getgid16 ++ .long sys_signal ++ .long sys_geteuid16 ++ .long sys_getegid16 /* 50 */ ++ .long sys_acct ++ .long sys_umount /* recycled never used phys() */ ++ .long sys_ni_syscall /* old lock syscall holder */ ++ .long sys_ioctl ++ .long sys_fcntl /* 55 */ ++ .long sys_ni_syscall /* old mpx syscall holder */ ++ .long sys_setpgid ++ .long sys_ni_syscall /* old ulimit syscall holder */ ++ .long sys_ni_syscall ++ .long sys_umask /* 60 */ ++ .long sys_chroot ++ .long sys_ustat ++ .long sys_dup2 ++ .long sys_getppid ++ .long sys_getpgrp /* 65 */ ++ .long sys_setsid ++ .long sys_sigaction ++ .long sys_sgetmask ++ .long sys_ssetmask ++ .long sys_setreuid16 /* 70 */ ++ .long sys_setregid16 ++ .long sys_sigsuspend ++ .long sys_sigpending ++ .long sys_sethostname ++ .long sys_setrlimit /* 75 */ ++ .long sys_old_getrlimit ++ .long sys_getrusage ++ .long sys_gettimeofday ++ .long sys_settimeofday ++ .long sys_getgroups16 /* 80 */ ++ .long sys_setgroups16 ++ .long old_select ++ .long sys_symlink ++ .long sys_lstat ++ .long sys_readlink /* 85 */ ++ .long sys_uselib ++ .long sys_ni_syscall /* sys_swapon */ ++ .long sys_reboot ++ .long old_readdir ++ .long old_mmap /* 90 */ ++ .long sys_munmap ++ .long sys_truncate ++ .long sys_ftruncate ++ .long sys_fchmod ++ .long sys_fchown16 /* 95 */ ++ .long sys_getpriority ++ .long sys_setpriority ++ .long sys_ni_syscall /* old profil syscall holder */ ++ .long sys_statfs ++ .long sys_fstatfs /* 100 */ ++ .long sys_ni_syscall /* was ioperm */ ++ .long sys_socketcall ++ .long sys_syslog ++ .long sys_setitimer ++ .long sys_getitimer /* 105 */ ++ .long sys_newstat ++ .long sys_newlstat ++ .long sys_newfstat ++ .long sys_ni_syscall ++ .long sys_ni_syscall /* iopl for i386 */ /* 110 */ ++ .long sys_vhangup ++ .long sys_ni_syscall /* obsolete idle() syscall */ ++ .long sys_ni_syscall /* vm86old for i386 */ ++ .long sys_wait4 ++ .long sys_ni_syscall /* 115 */ /* sys_swapoff */ ++ .long sys_sysinfo ++ .long sys_ipc ++ .long sys_fsync ++ .long sys_sigreturn ++ .long sys_clone /* 120 */ ++ .long sys_setdomainname ++ .long sys_newuname ++ .long sys_cacheflush /* modify_ldt for i386 */ ++ .long sys_adjtimex ++ .long sys_ni_syscall /* 125 */ /* sys_mprotect */ ++ .long sys_sigprocmask ++ .long sys_ni_syscall /* old "creat_module" */ ++ .long sys_init_module ++ .long sys_delete_module ++ .long sys_ni_syscall /* 130: old "get_kernel_syms" */ ++ .long sys_quotactl ++ .long sys_getpgid ++ .long sys_fchdir ++ .long sys_bdflush ++ .long sys_sysfs /* 135 */ ++ .long sys_personality ++ .long sys_ni_syscall /* for afs_syscall */ ++ .long sys_setfsuid16 ++ .long sys_setfsgid16 ++ .long sys_llseek /* 140 */ ++ .long sys_getdents ++ .long sys_select ++ .long sys_flock ++ .long sys_ni_syscall /* sys_msync */ ++ .long sys_readv /* 145 */ ++ .long sys_writev ++ .long sys_getsid ++ .long sys_fdatasync ++ .long sys_sysctl ++ .long sys_ni_syscall /* 150 */ /* sys_mlock */ ++ .long sys_ni_syscall /* sys_munlock */ ++ .long sys_ni_syscall /* sys_mlockall */ ++ .long sys_ni_syscall /* sys_munlockall */ ++ .long sys_sched_setparam ++ .long sys_sched_getparam /* 155 */ ++ .long sys_sched_setscheduler ++ .long sys_sched_getscheduler ++ .long sys_sched_yield ++ .long sys_sched_get_priority_max ++ .long sys_sched_get_priority_min /* 160 */ ++ .long sys_sched_rr_get_interval ++ .long sys_nanosleep ++ .long sys_ni_syscall /* sys_mremap */ ++ .long sys_setresuid16 ++ .long sys_getresuid16 /* 165 */ ++ .long sys_getpagesize /* sys_getpagesize */ ++ .long sys_ni_syscall /* old "query_module" */ ++ .long sys_poll ++ .long sys_ni_syscall /* sys_nfsservctl */ ++ .long sys_setresgid16 /* 170 */ ++ .long sys_getresgid16 ++ .long sys_prctl ++ .long sys_rt_sigreturn ++ .long sys_rt_sigaction ++ .long sys_rt_sigprocmask /* 175 */ ++ .long sys_rt_sigpending ++ .long sys_rt_sigtimedwait ++ .long sys_rt_sigqueueinfo ++ .long sys_rt_sigsuspend ++ .long sys_pread64 /* 180 */ ++ .long sys_pwrite64 ++ .long sys_lchown16 ++ .long sys_getcwd ++ .long sys_capget ++ .long sys_capset /* 185 */ ++ .long sys_sigaltstack ++ .long sys_sendfile ++ .long sys_ni_syscall /* streams1 */ ++ .long sys_ni_syscall /* streams2 */ ++ .long sys_vfork /* 190 */ ++ .long sys_getrlimit ++ .long sys_mmap2 ++ .long sys_truncate64 ++ .long sys_ftruncate64 ++ .long sys_stat64 /* 195 */ ++ .long sys_lstat64 ++ .long sys_fstat64 ++ .long sys_chown ++ .long sys_getuid ++ .long sys_getgid /* 200 */ ++ .long sys_geteuid ++ .long sys_getegid ++ .long sys_setreuid ++ .long sys_setregid ++ .long sys_getgroups /* 205 */ ++ .long sys_setgroups ++ .long sys_fchown ++ .long sys_setresuid ++ .long sys_getresuid ++ .long sys_setresgid /* 210 */ ++ .long sys_getresgid ++ .long sys_lchown ++ .long sys_setuid ++ .long sys_setgid ++ .long sys_setfsuid /* 215 */ ++ .long sys_setfsgid ++ .long sys_pivot_root ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_getdents64 /* 220 */ ++ .long sys_gettid ++ .long sys_tkill ++ .long sys_setxattr ++ .long sys_lsetxattr ++ .long sys_fsetxattr /* 225 */ ++ .long sys_getxattr ++ .long sys_lgetxattr ++ .long sys_fgetxattr ++ .long sys_listxattr ++ .long sys_llistxattr /* 230 */ ++ .long sys_flistxattr ++ .long sys_removexattr ++ .long sys_lremovexattr ++ .long sys_fremovexattr ++ .long sys_futex /* 235 */ ++ .long sys_sendfile64 ++ .long sys_ni_syscall /* sys_mincore */ ++ .long sys_ni_syscall /* sys_madvise */ ++ .long sys_fcntl64 ++ .long sys_readahead /* 240 */ ++ .long sys_io_setup ++ .long sys_io_destroy ++ .long sys_io_getevents ++ .long sys_io_submit ++ .long sys_io_cancel /* 245 */ ++ .long sys_fadvise64 ++ .long sys_exit_group ++ .long sys_lookup_dcookie ++ .long sys_epoll_create ++ .long sys_epoll_ctl /* 250 */ ++ .long sys_epoll_wait ++ .long sys_ni_syscall /* sys_remap_file_pages */ ++ .long sys_set_tid_address ++ .long sys_timer_create ++ .long sys_timer_settime /* 255 */ ++ .long sys_timer_gettime ++ .long sys_timer_getoverrun ++ .long sys_timer_delete ++ .long sys_clock_settime ++ .long sys_clock_gettime /* 260 */ ++ .long sys_clock_getres ++ .long sys_clock_nanosleep ++ .long sys_statfs64 ++ .long sys_fstatfs64 ++ .long sys_tgkill /* 265 */ ++ .long sys_utimes ++ .long sys_fadvise64_64 ++ .long sys_mbind ++ .long sys_get_mempolicy ++ .long sys_set_mempolicy /* 270 */ ++ .long sys_mq_open ++ .long sys_mq_unlink ++ .long sys_mq_timedsend ++ .long sys_mq_timedreceive ++ .long sys_mq_notify /* 275 */ ++ .long sys_mq_getsetattr ++ .long sys_waitid ++ .long sys_ni_syscall /* sys_setaltroot */ ++ .long sys_ni_syscall /* sys_add_key */ ++ .long sys_ni_syscall /* 280 */ /* sys_request_key */ ++ .long sys_ni_syscall /* sys_keyctl */ ++ .long sys_ioprio_set ++ .long sys_ioprio_get ++ .long sys_inotify_init ++ .long sys_inotify_add_watch /* 285 */ ++ .long sys_inotify_rm_watch ++ .long sys_migrate_pages ++ .long sys_openat ++ .long sys_mkdirat ++ .long sys_mknodat /* 290 */ ++ .long sys_fchownat ++ .long sys_futimesat ++ .long sys_fstatat64 ++ .long sys_unlinkat ++ .long sys_renameat /* 295 */ ++ .long sys_linkat ++ .long sys_symlinkat ++ .long sys_readlinkat ++ .long sys_fchmodat ++ .long sys_faccessat /* 300 */ ++ .long sys_ni_syscall /* Reserved for pselect6 */ ++ .long sys_ni_syscall /* Reserved for ppoll */ ++ .long sys_unshare ++ .long sys_set_robust_list ++ .long sys_get_robust_list /* 305 */ ++ .long sys_splice ++ .long sys_sync_file_range ++ .long sys_tee ++ .long sys_vmsplice ++ .long sys_move_pages /* 310 */ ++ .long sys_sched_setaffinity ++ .long sys_sched_getaffinity ++ .long sys_kexec_load ++ .long sys_getcpu ++ .long sys_epoll_pwait /* 315 */ ++ .long sys_utimensat ++ .long sys_signalfd ++ .long sys_timerfd ++ .long sys_eventfd ++ .long sys_pread64 ++ .long sys_pwrite64 /* 321 */ ++ ++ .rept NR_syscalls - 322 ++ .long sys_ni_syscall ++ .endr ++ +diff --git a/arch/nios2nommu/kernel/time.c b/arch/nios2nommu/kernel/time.c +new file mode 100644 +index 0000000..3b536fe +--- /dev/null ++++ b/arch/nios2nommu/kernel/time.c +@@ -0,0 +1,219 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/kernel/time.c ++ * ++ * Architecture specific time handling details. ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Most of the stuff is located in the machine specific files. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * Copyright (C) 1998-2000 D. Jeff Dionne , ++ * Kenneth Albanowski , ++ * Copyright (C) 1991, 1992, 1995 Linus Torvalds ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define TICK_SIZE (tick_nsec / 1000) ++ ++unsigned long cpu_khz; ++static inline int set_rtc_mmss(unsigned long nowtime) ++{ ++ return 0; ++} ++ ++/* Timer timeout status */ ++#define nios2_timer_TO (inw(&na_timer0->np_timerstatus) & np_timerstatus_to_mask) ++ ++/* Timer snapshot */ ++static inline unsigned long nios2_read_timercount(void) ++{ ++ unsigned long count; ++ ++ outw(0, &na_timer0->np_timersnapl); ++ count = inw(&na_timer0->np_timersnaph) << 16 | inw(&na_timer0->np_timersnapl); ++ ++ return count; ++} ++ ++/* ++ * Should return useconds since last timer tick ++ */ ++static unsigned long gettimeoffset(void) ++{ ++ unsigned long offset; ++ unsigned long count; ++ ++ count = nios2_read_timercount(); ++ offset = ((nasys_clock_freq/HZ)-1 - nios2_read_timercount()) \ ++ / (nasys_clock_freq / USEC_PER_SEC); ++ ++ /* Check if we just wrapped the counters and maybe missed a tick */ ++ if (nios2_timer_TO && (offset < (100000 / HZ / 2))) ++ offset += (USEC_PER_SEC / HZ); ++ ++ return offset; ++} ++ ++/* ++ * timer_interrupt() needs to keep up the real-time clock, ++ * as well as call the "do_timer()" routine every clocktick ++ */ ++irqreturn_t timer_interrupt(int irq, void *dummy) ++{ ++ /* last time the cmos clock got updated */ ++ static long last_rtc_update=0; ++ ++ write_seqlock(&xtime_lock); ++ na_timer0->np_timerstatus = 0; /* Clear the interrupt condition */ ++ ++ do_timer(1); ++#ifndef CONFIG_SMP ++ update_process_times(user_mode(get_irq_regs())); ++#endif ++ profile_tick(CPU_PROFILING); ++ /* ++ * If we have an externally synchronized Linux clock, then update ++ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be ++ * called as close as possible to 500 ms before the new second starts. ++ */ ++ if (ntp_synced() && ++ xtime.tv_sec > last_rtc_update + 660 && ++ (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && ++ (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { ++ if (set_rtc_mmss(xtime.tv_sec) == 0) ++ last_rtc_update = xtime.tv_sec; ++ else ++ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ ++ } ++ ++ write_sequnlock(&xtime_lock); ++ return(IRQ_HANDLED); ++} ++ ++void __init time_init(void) ++{ ++ unsigned int year, mon, day, hour, min, sec; ++ int err; ++ ++ extern void arch_gettod(int *year, int *mon, int *day, int *hour, ++ int *min, int *sec); ++ ++ cpu_khz=nasys_clock_freq_1000; ++ arch_gettod(&year, &mon, &day, &hour, &min, &sec); ++ ++ if ((year += 1900) < 1970) ++ year += 100; ++ xtime.tv_sec = mktime(year, mon, day, hour, min, sec); ++ xtime.tv_nsec = 0; ++ wall_to_monotonic.tv_sec = -xtime.tv_sec; ++ ++ err = request_irq(na_timer0_irq, timer_interrupt, IRQ_FLG_LOCK, "timer", NULL); ++ if(err) ++ printk(KERN_ERR "%s() failed - errno = %d\n", __FUNCTION__, -err); ++ na_timer0->np_timerperiodl = (nasys_clock_freq/HZ)-1; ++ na_timer0->np_timerperiodh = ((nasys_clock_freq/HZ)-1) >> 16; ++ ++ /* interrupt enable + continuous + start */ ++ na_timer0->np_timercontrol = np_timercontrol_start_mask ++ + np_timercontrol_cont_mask ++ + np_timercontrol_ito_mask; ++} ++ ++/* ++ * This version of gettimeofday has near microsecond resolution. ++ */ ++void do_gettimeofday(struct timeval *tv) ++{ ++ unsigned long flags; ++ unsigned long seq; ++ unsigned long usec, sec; ++ ++ do { ++ seq = read_seqbegin_irqsave(&xtime_lock, flags); ++ usec = gettimeoffset(); ++ sec = xtime.tv_sec; ++ usec += (xtime.tv_nsec / 1000); ++ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); ++ ++ while (usec >= 1000000) { ++ usec -= 1000000; ++ sec++; ++ } ++ ++ tv->tv_sec = sec; ++ tv->tv_usec = usec; ++} ++EXPORT_SYMBOL(do_gettimeofday); ++ ++int do_settimeofday(struct timespec *tv) ++{ ++ time_t wtm_sec, sec = tv->tv_sec; ++ long wtm_nsec, nsec = tv->tv_nsec; ++ ++ if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) ++ return -EINVAL; ++ ++ write_seqlock_irq(&xtime_lock); ++ /* ++ * This is revolting. We need to set "xtime" correctly. However, the ++ * value in this location is the value at the last tick. ++ * Discover what correction gettimeofday() would have ++ * made, and then undo it! ++ */ ++ nsec -= gettimeoffset() * NSEC_PER_USEC; ++ ++ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); ++ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); ++ ++ set_normalized_timespec(&xtime, sec, nsec); ++ set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); ++ ++ ntp_clear(); ++ ++ write_sequnlock_irq(&xtime_lock); ++ clock_was_set(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(do_settimeofday); ++ ++/* ++ * Scheduler clock - returns current time in nanosec units. ++ */ ++unsigned long long sched_clock(void) ++{ ++ return (unsigned long long)jiffies * (1000000000 / HZ); ++} +diff --git a/arch/nios2nommu/kernel/traps.c b/arch/nios2nommu/kernel/traps.c +new file mode 100644 +index 0000000..14b7e4c +--- /dev/null ++++ b/arch/nios2nommu/kernel/traps.c +@@ -0,0 +1,178 @@ ++/* ++ * arch/niosnommu/kernel/traps.c ++ * ++ * Copyright 2004 Microtronix Datacom Ltd. ++ * Copyright 2001 Vic Phillips ++ * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) ++ * ++ * hacked from: ++ * ++ * arch/sparcnommu/kernel/traps.c ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include /* for jiffies */ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* #define TRAP_DEBUG */ ++ ++#if 0 ++void dumpit(unsigned long l1, unsigned long l2) ++{ ++ printk("0x%08x l1 0x%08x l2\n"); ++ while(1); ++} ++ ++struct trap_trace_entry { ++ unsigned long pc; ++ unsigned long type; ++}; ++ ++int trap_curbuf = 0; ++struct trap_trace_entry trapbuf[1024]; ++ ++void syscall_trace_entry(struct pt_regs *regs) ++{ ++ printk("%s[%d]: ", current->comm, current->pid); ++ printk("scall<%d> (could be %d)\n", (int) regs->r3, ++ (int) regs->r4); ++} ++ ++void syscall_trace_exit(struct pt_regs *regs) ++{ ++} ++#endif ++ ++/* ++ * The architecture-independent backtrace generator ++ */ ++void dump_stack(void) ++{ ++ unsigned long stack; ++ ++ show_stack(current, &stack); ++} ++ ++EXPORT_SYMBOL(dump_stack); ++ ++/* ++ * The show_stack is an external API which we do not use ourselves. ++ * The oops is printed in die_if_kernel. ++ */ ++ ++int kstack_depth_to_print = 48; ++ ++void show_stack(struct task_struct *task, unsigned long *stack) ++{ ++ unsigned long *endstack, addr; ++ extern char _start, _etext; ++ int i; ++ ++ if (!stack) { ++ if (task) ++ stack = (unsigned long *)task->thread.ksp; ++ else ++ stack = (unsigned long *)&stack; ++ } ++ ++ addr = (unsigned long) stack; ++ endstack = (unsigned long *) PAGE_ALIGN(addr); ++ ++ printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); ++ for (i = 0; i < kstack_depth_to_print; i++) { ++ if (stack + 1 > endstack) ++ break; ++ if (i % 8 == 0) ++ printk(KERN_EMERG "\n "); ++ printk(KERN_EMERG " %08lx", *stack++); ++ } ++ ++ printk(KERN_EMERG "\nCall Trace:"); ++ i = 0; ++ while (stack + 1 <= endstack) { ++ addr = *stack++; ++ /* ++ * If the address is either in the text segment of the ++ * kernel, or in the region which contains vmalloc'ed ++ * memory, it *may* be the address of a calling ++ * routine; if so, print it so that someone tracing ++ * down the cause of the crash will be able to figure ++ * out the call path that was taken. ++ */ ++ if (((addr >= (unsigned long) &_start) && ++ (addr <= (unsigned long) &_etext))) { ++ if (i % 4 == 0) ++ printk(KERN_EMERG "\n "); ++ printk(KERN_EMERG " [<%08lx>]", addr); ++ i++; ++ } ++ } ++ printk(KERN_EMERG "\n"); ++} ++ ++void die_if_kernel(char *str, struct pt_regs *pregs) ++{ ++ unsigned long pc; ++ ++ pc = pregs->ra; ++ printk("0x%08lx\n trapped to die_if_kernel\n",pregs->ra); ++ show_regs(pregs); ++ if(pregs->status_extension & PS_S) ++ do_exit(SIGKILL); ++ do_exit(SIGSEGV); ++} ++ ++void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc) ++{ ++ if(type < 0x10) { ++ printk("Unimplemented Nios2 TRAP, type = %02lx\n", type); ++ die_if_kernel("Whee... Hello Mr. Penguin", current->thread.kregs); ++ } ++} ++ ++#if 0 ++void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long psr) ++{ ++#ifdef TRAP_DEBUG ++ printk("Watchpoint detected at PC %08lx PSR %08lx\n", pc, psr); ++#endif ++ if(psr & PSR_SUPERVISOR) ++ panic("Tell me what a watchpoint trap is, and I'll then deal " ++ "with such a beast..."); ++} ++#endif ++ ++void trap_init(void) ++{ ++#ifdef DEBUG ++ printk("trap_init reached\n"); ++#endif ++} +diff --git a/arch/nios2nommu/kernel/usb.c b/arch/nios2nommu/kernel/usb.c +new file mode 100644 +index 0000000..65655b6 +--- /dev/null ++++ b/arch/nios2nommu/kernel/usb.c +@@ -0,0 +1,341 @@ ++/* ++ * arch/nios2nommu/kernel/usb.c -- platform level USB initialization ++ * ++ * 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 ++ */ ++ ++#undef DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if defined(CONFIG_USB_SL811_HCD) || defined (CONFIG_USB_SL811_HCD_MODULE) ++#if defined(CONFIG_MICROTRONIX_STRATIX) || defined (CONFIG_MICROTRONIX_CYCLONE) ++ ++#include ++#define SL811_ADDR ((unsigned int)na_usb) ++#define SL811_IRQ na_usb_irq ++ ++static void sl811_port_power(struct device *dev, int is_on) ++{ ++} ++ ++static void sl811_port_reset(struct device *dev) ++{ ++ writeb(0xA, (SL811_ADDR+8)); ++ mdelay(10); ++ writeb(4, (SL811_ADDR+8)); ++} ++ ++static struct resource sl811hs_resources[] = { ++ { ++ .start = (SL811_ADDR), ++ .end = (SL811_ADDR + 3), ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = (SL811_ADDR + 4), ++ .end = (SL811_ADDR + 7), ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = SL811_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct sl811_platform_data sl811_data = { ++ .can_wakeup = 0, ++ .potpg = 0, ++ .power = 250, ++ .port_power = sl811_port_power, ++ .reset = sl811_port_reset, ++}; ++ ++static struct platform_device sl811hs_device = { ++ .name = "sl811-hcd", ++ .id = -1, ++ .dev = { ++ //.release = usb_release, ++ //.dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = 0x0fffffff, ++ .platform_data = &sl811_data, ++ }, ++ .num_resources = ARRAY_SIZE(sl811hs_resources), ++ .resource = sl811hs_resources, ++}; ++ ++ ++static int __init mtx_kit_usb_init(void) ++{ ++ int status; ++ ++ status = platform_device_register(&sl811hs_device); ++ if (status) { ++ pr_debug("can't register sl811hs device, %d\n", status); ++ return -1; ++ } ++ ++ writeb(4, (SL811_ADDR+8)); ++ return 0; ++} ++ ++subsys_initcall(mtx_kit_usb_init); ++#endif /* (CONFIG_MICROTRONIX_STRATIX) || (CONFIG_MICROTRONIX_CYCLONE)*/ ++#endif /*(CONFIG_USB_SL811_HCD) ||(CONFIG_USB_SL811_HCD_MODULE) */ ++ ++#if defined(CONFIG_USB_ISP116X_HCD) || defined (CONFIG_USB_ISP116X_HCD_MODULE) ++ ++#include ++ ++#define ISP116X_HCD_ADDR ((unsigned int)na_usb) ++#define ISP116X_HCD_IRQ na_usb_irq ++ ++static void isp116x_delay(struct device *dev, int delay) ++{ ++ ndelay(delay); ++} ++ ++static struct resource isp116x_hcd_resources[] = { ++ { ++ .start = (ISP116X_HCD_ADDR), ++ .end = (ISP116X_HCD_ADDR + 3), ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = (ISP116X_HCD_ADDR + 4), ++ .end = (ISP116X_HCD_ADDR + 7), ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = ISP116X_HCD_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct isp116x_platform_data isp116x_data = { ++ // Enable internal resistors on downstream ports ++ .sel15Kres = 1, ++ // On-chip overcurrent protection ++ .oc_enable = 1, ++ // INT output polarity ++ .int_act_high = 0, ++ // INT edge or level triggered ++ .int_edge_triggered = 0, ++ // Wakeup by devices on usb bus enabled ++ .remote_wakeup_enable = 0, ++ .delay = isp116x_delay, ++}; ++ ++static struct platform_device isp116x_hcd = { ++ .name = "isp116x-hcd", ++ .id = -1, ++ .dev = { ++ //.release = usb_release, ++ //.dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = 0x0fffffff, ++ .platform_data = &isp116x_data, ++ }, ++ .num_resources = ARRAY_SIZE(isp116x_hcd_resources), ++ .resource = isp116x_hcd_resources, ++}; ++ ++static int __init usb_hcd_init(void) ++{ ++ int status; ++ ++ status = platform_device_register(&isp116x_hcd); ++ if (status) { ++ pr_debug("can't register isp116x host controller, %d\n", status); ++ return -1; ++ } ++ ++ return 0; ++} ++subsys_initcall(usb_hcd_init); ++#endif /*(CONFIG_USB_ISP116X_HCD) ||(CONFIG_USB_ISP116X_HCD_MODULE) */ ++ ++#if defined(CONFIG_USB_ISP1161X) || defined(CONFIG_USB_ISP1161X_MODULE) ++#include ++ ++#define ISP116X_UDC_ADDR ((unsigned int)na_usb+8) ++#define ISP116X_UDC_IRQ na_int2_usb_irq ++ ++static struct resource isp116x_udc_resources[] = { ++ { ++ .start = (ISP116X_UDC_ADDR), ++ .end = (ISP116X_UDC_ADDR + 3), ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = (ISP116X_UDC_ADDR + 4), ++ .end = (ISP116X_UDC_ADDR + 7), ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = ISP116X_UDC_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++static void isp116x_udc_delay() ++{ ++ __asm__ __volatile__( ++ "1: \n\t" ++ " beq %0,zero,2f\n\t" ++ " addi %0, %0, -1\n\t" ++ " br 1b\n\t" ++ "2: \n\t" ++ : ++ : "r" (nasys_clock_freq_1000 * 180 / 2000000) ++ ); ++ ++} ++struct isp116x_dc_platform_data isp116x_udc_data = { ++ .ext_pullup_enable =0, ++ .no_lazy =1, ++ .eot_act_high =0, ++ .remote_wakeup_enable=1, ++ .power_off_enable =1, ++ .int_edge_triggered =0, ++ .int_act_high =0, ++ .clkout_freq =12, ++ .delay = isp116x_udc_delay ++}; ++ ++static struct platform_device isp116x_udc = { ++ .name = "isp1161a_udc", ++ .id = -1, ++ .dev = { ++ //.release = usb_release, ++ //.dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = 0x0fffffff, ++ .platform_data = &isp116x_udc_data, ++ }, ++ .num_resources = ARRAY_SIZE(isp116x_udc_resources), ++ .resource = isp116x_udc_resources, ++}; ++ ++static int __init usb_udc_init(void) ++{ ++ int status; ++ np_pio* pio; ++ ++ status = platform_device_register(&isp116x_udc); ++ if (status) { ++ pr_debug("can't register isp116x device controller, %d\n", status); ++ return -1; ++ } ++ ++ /* enable interrupts */ ++ pio = (np_pio*)na_int2_usb; ++ //outw(0, &pio->np_piodata); ++ //outw(0, &pio->np_pioedgecapture); ++ outw(1, &pio->np_piointerruptmask); ++ ++ return 0; ++} ++subsys_initcall(usb_udc_init); ++#endif ++ ++#if defined(na_ISP1362_avalonS) // for DE2 dev board, FIX ME otehrwise ++#define na_usb na_ISP1362_avalonS ++#define na_usb_irq na_ISP1362_avalonS_irq ++#endif ++ ++#if defined(na_ISP1362_avalon_slave_0) // for DE2 dev board, FIX ME otehrwise ++#define na_usb na_ISP1362_avalon_slave_0 ++#define na_usb_irq na_ISP1362_avalon_slave_0_irq ++#endif ++ ++#if defined(CONFIG_USB_ISP1362_HCD) && defined(na_usb) ++ ++#include ++#define ISP1362_HCD_ADDR ((unsigned int)na_usb) ++#define ISP1362_HCD_IRQ na_usb_irq ++ ++static struct resource isp1362_hcd_resources[] = { ++ { ++ .start = (ISP1362_HCD_ADDR), ++ .end = (ISP1362_HCD_ADDR + 3), ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = (ISP1362_HCD_ADDR + 4), ++ .end = (ISP1362_HCD_ADDR + 7), ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = ISP1362_HCD_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct isp1362_platform_data isp1362_data = { ++ // Enable internal resistors on downstream ports ++ .sel15Kres = 1, ++ // Clock cannot be stopped ++ .clknotstop = 0, ++ // On-chip overcurrent protection ++ .oc_enable = 0, ++ // INT output polarity ++ .int_act_high = 0, ++ // INT edge or level triggered ++ .int_edge_triggered = 0, ++ // WAKEUP pin connected ++ .remote_wakeup_connected = 0, ++ // Switch or not to switch (keep always powered) ++ .no_power_switching = 1, ++ // Ganged port power switching (0) or individual port power switching (1) ++ .power_switching_mode = 0, ++}; ++ ++static struct platform_device isp1362_hcd = { ++ .name = "isp1362-hcd", ++ .id = -1, ++ .dev = { ++ //.release = usb_release, ++ //.dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = 0x0fffffff, ++ .platform_data = &isp1362_data, ++ }, ++ .num_resources = ARRAY_SIZE(isp1362_hcd_resources), ++ .resource = isp1362_hcd_resources, ++}; ++ ++static int __init usb_hcd_init(void) ++{ ++ int status; ++ ++ status = platform_device_register(&isp1362_hcd); ++ if (status) { ++ pr_debug("can't register isp1362 host controller, %d\n", status); ++ return -1; ++ } ++ ++ return 0; ++} ++subsys_initcall(usb_hcd_init); ++#endif ++ +diff --git a/arch/nios2nommu/kernel/vmlinux.lds.S b/arch/nios2nommu/kernel/vmlinux.lds.S +new file mode 100644 +index 0000000..491901c +--- /dev/null ++++ b/arch/nios2nommu/kernel/vmlinux.lds.S +@@ -0,0 +1,141 @@ ++#include ++#include ++ ++OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") ++ ++OUTPUT_ARCH(nios) ++ENTRY(_start) /* Defined in head.S */ ++ ++jiffies = jiffies_64; ++ ++SECTIONS ++{ ++ . = nasys_program_mem; ++ /* read-only */ ++ _stext = . ; ++ _text = .; /* Text and read-only data */ ++ .text : { ++ TEXT_TEXT ++ SCHED_TEXT ++ LOCK_TEXT ++ *(.fixup) ++ *(.gnu.warning) ++ } =0 ++ ++ . = ALIGN(4) ; ++ _etext = .; /* End of text section */ ++ ++ . = ALIGN(32); /* Exception table */ ++ __start___ex_table = .; ++ __ex_table : { *(__ex_table) } ++ __stop___ex_table = .; ++ ++ RODATA ++ ++ /* writeable */ ++ .data : { /* Data */ ++ /* ++ * This ALIGN is needed as a workaround for a bug a gcc bug upto 4.1 which ++ * limits the maximum alignment to at most 32kB and results in the following ++ * warning: ++ * ++ * CC arch/mips/kernel/init_task.o ++ * arch/mips/kernel/init_task.c:30: warning: alignment of ‘init_thread_union’ ++ * is greater than maximum object file alignment. Using 32768 ++ */ ++ . = ALIGN(4096); ++ *(.data.init_task) ++ ++ *(.data) ++ ++ CONSTRUCTORS ++ } ++ ++ .lit8 : { *(.lit8) } ++ .lit4 : { *(.lit4) } ++ /* We want the small data sections together, so single-instruction offsets ++ can access them all, and initialized data all before uninitialized, so ++ we can shorten the on-disk segment size. */ ++ .sdata : { *(.sdata) } ++ ++ . = ALIGN(4096); ++ __nosave_begin = .; ++ .data_nosave : { *(.data.nosave) } ++ . = ALIGN(4096); ++ __nosave_end = .; ++ ++ . = ALIGN(32); ++ .data.cacheline_aligned : { *(.data.cacheline_aligned) } ++ ++ _edata = .; /* End of data section */ ++ ++ /* will be freed after init */ ++ . = ALIGN(4096); /* Init code and data */ ++ __init_begin = .; ++ .init.text : { ++ _sinittext = .; ++ *(.init.text) ++ _einittext = .; ++ } ++ .init.data : { *(.init.data) } ++ . = ALIGN(16); ++ __setup_start = .; ++ .init.setup : { *(.init.setup) } ++ __setup_end = .; ++ ++ __initcall_start = .; ++ .initcall.init : { ++ INITCALLS ++ } ++ __initcall_end = .; ++ ++ __con_initcall_start = .; ++ .con_initcall.init : { *(.con_initcall.init) } ++ __con_initcall_end = .; ++ SECURITY_INIT ++ /* .exit.text is discarded at runtime, not link time, to deal with ++ references from .rodata */ ++ .exit.text : { *(.exit.text) } ++ .exit.data : { *(.exit.data) } ++ . = ALIGN(4096); ++ __initramfs_start = .; ++ .init.ramfs : { *(.init.ramfs) } ++ __initramfs_end = .; ++ . = ALIGN(32); ++ __per_cpu_start = .; ++ .data.percpu : { *(.data.percpu) } ++ __per_cpu_end = .; ++ . = ALIGN(4096); ++ __init_end = .; ++ /* freed after init ends here */ ++ ++ __bss_start = .; /* BSS */ ++ .sbss : { ++ *(.sbss) ++ *(.scommon) ++ } ++ .bss : { ++ *(.bss) ++ *(COMMON) ++ } ++ __bss_stop = .; ++ ++ _end = . ; ++ ++ /* Sections to be discarded */ ++ /DISCARD/ : { ++ *(.exit.text) ++ *(.exit.data) ++ *(.exitcall.exit) ++ } ++ ++ ++ STABS_DEBUG ++ ++ DWARF_DEBUG ++ ++ /* These must appear regardless of . */ ++ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } ++ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } ++ .note : { *(.note) } ++} +diff --git a/arch/nios2nommu/lib/Makefile b/arch/nios2nommu/lib/Makefile +new file mode 100644 +index 0000000..1315c57 +--- /dev/null ++++ b/arch/nios2nommu/lib/Makefile +@@ -0,0 +1,17 @@ ++# ++# Copyright (C) 2005 Microtronix Datacom Ltd ++# ++# This program is free software; you can redistribute it and/or modify it under ++# the terms of the GNU Library 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 Library General Public License for more ++# details. ++ ++####CSRC := $(wildcard *.c) ++####lib-y =$(patsubst %.c,%.o, $(CSRC)) ++####wapos! ++lib-y =checksum.o string.o memcpy.o +diff --git a/arch/nios2nommu/lib/checksum.c b/arch/nios2nommu/lib/checksum.c +new file mode 100644 +index 0000000..475f1a3 +--- /dev/null ++++ b/arch/nios2nommu/lib/checksum.c +@@ -0,0 +1,73 @@ ++/*-------------------------------------------------------------------- ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++#include ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++/* ++ * computes the checksum of a memory block at buff, length len, ++ * and adds in "sum" (32-bit) ++ * ++ * returns a 32-bit number suitable for feeding into itself ++ * or csum_tcpudp_magic ++ * ++ * this function must be called with even lengths, except ++ * for the last fragment, which may be odd ++ * ++ * it's best to have buff aligned on a 32-bit boundary ++ */ ++ ++unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) ++{ ++#if 0 ++ __asm__ __volatile__ ...//;dgt2;tmp;not (yet) available... ++ ...//;dgt2;tmp;NiosI didn't offer either... ++#else ++ unsigned int result = do_csum(buff, len); ++ ++ /* add in old sum, and carry.. */ ++ result += sum; ++ if (sum > result) ++ result += 1; ++ return result; ++#endif ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++/* ++ * the same as csum_partial, but copies from fs:src while it ++ * checksums ++ * ++ * here even more important to align src and dst on a 32-bit (or even ++ * better 64-bit) boundary ++ */ ++ ++unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum) ++{ ++ memcpy(dst, src, len); ++ return csum_partial(dst, len, sum); ++ ++} +diff --git a/arch/nios2nommu/lib/memcpy.c b/arch/nios2nommu/lib/memcpy.c +new file mode 100644 +index 0000000..6586b99 +--- /dev/null ++++ b/arch/nios2nommu/lib/memcpy.c +@@ -0,0 +1,62 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/lib/memcpy.c ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jun/09/2004 dgt Split out separate source file from string.c ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef __HAVE_ARCH_MEMCPY ++ void * memcpy(void * d, const void * s, size_t count) ++ { ++ unsigned long dst, src; ++ dst = (unsigned long) d; ++ src = (unsigned long) s; ++ ++ if ((count < 8) || ((dst ^ src) & 3)) ++ goto restup; ++ ++ if (dst & 1) { ++ *(char*)dst++=*(char*)src++; ++ count--; ++ } ++ if (dst & 2) { ++ *(short*)dst=*(short*)src; ++ src += 2; ++ dst += 2; ++ count -= 2; ++ } ++ while (count > 3) { ++ *(long*)dst=*(long*)src; ++ src += 4; ++ dst += 4; ++ count -= 4; ++ } ++ ++ restup: ++ while (count--) ++ *(char*)dst++=*(char*)src++; ++ ++ return d; ++ } ++#endif +diff --git a/arch/nios2nommu/lib/string.c b/arch/nios2nommu/lib/string.c +new file mode 100644 +index 0000000..b87c195 +--- /dev/null ++++ b/arch/nios2nommu/lib/string.c +@@ -0,0 +1,180 @@ ++/*-------------------------------------------------------------------- ++ * ++ * arch/nios2nommu/lib/string.c ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * Jun/09/2004 dgt Split out memcpy into separate source file ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef __HAVE_ARCH_MEMSET ++void * memset(void * s,int c,size_t count) ++{ ++ ++ if (count > 8) { ++ int destptr, charcnt, dwordcnt, fill8reg, wrkrega; ++ __asm__ __volatile__ ( ++ // fill8 %3, %5 (c & 0xff)\n\t" ++ // ++ " slli %4, %5, 8\n\t" ++ " or %4, %4, %5\n\t" ++ " slli %3, %4, 16\n\t" ++ " or %3, %3, %4\n\t" ++ // ++ // Word-align %0 (s) if necessary ++ // ++ " andi %4, %0, 0x01\n\t" ++ " beq %4, zero, 1f\n\t" ++ " addi %1, %1, -1\n\t" ++ " stb %3, 0(%0)\n\t" ++ " addi %0, %0, 1\n\t" ++ "1: \n\t" ++ " mov %2, %1\n\t" ++ // ++ // Dword-align %0 (s) if necessary ++ // ++ " andi %4, %0, 0x02\n\t" ++ " beq %4, zero, 2f\n\t" ++ " addi %1, %1, -2\n\t" ++ " sth %3, 0(%0)\n\t" ++ " addi %0, %0, 2\n\t" ++ " mov %2, %1\n\t" ++ "2: \n\t" ++ // %1 and %2 are how many more bytes to set ++ // ++ " srli %2, %2, 2\n\t" ++ // ++ // %2 is how many dwords to set ++ // ++ "3: ;\n\t" ++ " stw %3, 0(%0)\n\t" ++ " addi %0, %0, 4\n\t" ++ " addi %2, %2, -1\n\t" ++ " bne %2, zero, 3b\n\t" ++ // ++ // store residual word and/or byte if necessary ++ // ++ " andi %4, %1, 0x02\n\t" ++ " beq %4, zero, 4f\n\t" ++ " sth %3, 0(%0)\n\t" ++ " addi %0, %0, 2\n\t" ++ "4: \n\t" ++ // store residual byte if necessary ++ // ++ " andi %4, %1, 0x01\n\t" ++ " beq %4, zero, 5f\n\t" ++ " stb %3, 0(%0)\n\t" ++ "5: \n\t" ++ ++ : "=r" (destptr), /* %0 Output */ ++ "=r" (charcnt), /* %1 Output */ ++ "=r" (dwordcnt), /* %2 Output */ ++ "=r" (fill8reg), /* %3 Output */ ++ "=r" (wrkrega) /* %4 Output */ ++ ++ : "r" (c & 0xff), /* %5 Input */ ++ "0" (s), /* %0 Input/Output */ ++ "1" (count) /* %1 Input/Output */ ++ ++ : "memory" /* clobbered */ ++ ); ++ } ++ else { ++ char* xs=(char*)s; ++ while (count--) ++ *xs++ = c; ++ } ++ return s; ++} ++#endif ++ ++#ifdef __HAVE_ARCH_MEMMOVE ++void * memmove(void * d, const void * s, size_t count) ++{ ++ unsigned long dst, src; ++ ++ if (d < s) { ++ dst = (unsigned long) d; ++ src = (unsigned long) s; ++ ++ if ((count < 8) || ((dst ^ src) & 3)) ++ goto restup; ++ ++ if (dst & 1) { ++ *(char*)dst++=*(char*)src++; ++ count--; ++ } ++ if (dst & 2) { ++ *(short*)dst=*(short*)src; ++ src += 2; ++ dst += 2; ++ count -= 2; ++ } ++ while (count > 3) { ++ *(long*)dst=*(long*)src; ++ src += 4; ++ dst += 4; ++ count -= 4; ++ } ++ ++ restup: ++ while (count--) ++ *(char*)dst++=*(char*)src++; ++ } else { ++ dst = (unsigned long) d + count; ++ src = (unsigned long) s + count; ++ ++ if ((count < 8) || ((dst ^ src) & 3)) ++ goto restdown; ++ ++ if (dst & 1) { ++ src--; ++ dst--; ++ count--; ++ *(char*)dst=*(char*)src; ++ } ++ if (dst & 2) { ++ src -= 2; ++ dst -= 2; ++ count -= 2; ++ *(short*)dst=*(short*)src; ++ } ++ while (count > 3) { ++ src -= 4; ++ dst -= 4; ++ count -= 4; ++ *(long*)dst=*(long*)src; ++ } ++ ++ restdown: ++ while (count--) { ++ src--; ++ dst--; ++ *(char*)dst=*(char*)src; ++ } ++ } ++ ++ return d; ++ ++} ++#endif +diff --git a/arch/nios2nommu/mm/Makefile b/arch/nios2nommu/mm/Makefile +new file mode 100644 +index 0000000..b007a11 +--- /dev/null ++++ b/arch/nios2nommu/mm/Makefile +@@ -0,0 +1,12 @@ ++# $Id: Makefile,v 1.1 2006/07/05 06:23:18 gerg Exp $ ++# Makefile for the linux Sparc-specific parts of the memory manager. ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++obj-y := init.o ioremap.o extable.o memory.o ++obj-y += dma-noncoherent.o ++ +diff --git a/arch/nios2nommu/mm/dma-noncoherent.c b/arch/nios2nommu/mm/dma-noncoherent.c +new file mode 100644 +index 0000000..5649940 +--- /dev/null ++++ b/arch/nios2nommu/mm/dma-noncoherent.c +@@ -0,0 +1,373 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2000 Ani Joshi ++ * Copyright (C) 2000, 2001 Ralf Baechle ++ * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define UNCAC_ADDR(addr) ((void *)((unsigned long)(addr) | 0x80000000)) ++#define CAC_ADDR(addr) ((void *)((unsigned long)(addr) & ~0x80000000)) ++ ++/* ++ * Warning on the terminology - Linux calls an uncached area coherent; ++ * MIPS terminology calls memory areas with hardware maintained coherency ++ * coherent. ++ */ ++ ++void *dma_alloc_noncoherent(struct device *dev, size_t size, ++ dma_addr_t * dma_handle, gfp_t gfp) ++{ ++ void *ret; ++ /* ignore region specifiers */ ++ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); ++ ++ if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) ++ gfp |= GFP_DMA; ++ ret = (void *) __get_free_pages(gfp, get_order(size)); ++ ++ if (ret != NULL) { ++ memset(ret, 0, size); ++ *dma_handle = virt_to_phys(ret); ++ } ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(dma_alloc_noncoherent); ++ ++void *dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t * dma_handle, gfp_t gfp) ++{ ++ void *ret; ++ ++ ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp); ++ if (ret) { ++ dma_cache_wback_inv((unsigned long) ret, size); ++ ret = UNCAC_ADDR(ret); ++ } ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(dma_alloc_coherent); ++ ++void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle) ++{ ++ free_pages((unsigned long) vaddr, get_order(size)); ++} ++ ++EXPORT_SYMBOL(dma_free_noncoherent); ++ ++void dma_free_coherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle) ++{ ++ unsigned long addr = (unsigned long) vaddr; ++ ++ addr = (unsigned long) CAC_ADDR(addr); ++ free_pages(addr, get_order(size)); ++} ++ ++EXPORT_SYMBOL(dma_free_coherent); ++ ++static inline void __dma_sync(unsigned long addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ switch (direction) { ++ case DMA_TO_DEVICE: ++ dma_cache_wback(addr, size); ++ break; ++ ++ case DMA_FROM_DEVICE: ++ dma_cache_inv(addr, size); ++ break; ++ ++ case DMA_BIDIRECTIONAL: ++ dma_cache_wback_inv(addr, size); ++ break; ++ ++ default: ++ BUG(); ++ } ++} ++ ++dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction direction) ++{ ++ unsigned long addr = (unsigned long) ptr; ++ ++ __dma_sync(addr, size, direction); ++ ++ return virt_to_phys(ptr); ++} ++ ++EXPORT_SYMBOL(dma_map_single); ++ ++void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ unsigned long addr; ++ addr = dma_addr + PAGE_OFFSET; ++ ++ //__dma_sync(addr, size, direction); ++} ++ ++EXPORT_SYMBOL(dma_unmap_single); ++ ++int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction) ++{ ++ int i; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ for (i = 0; i < nents; i++, sg++) { ++ unsigned long addr; ++ ++ addr = (unsigned long) page_address(sg->page); ++ if (addr) { ++ __dma_sync(addr + sg->offset, sg->length, direction); ++ sg->dma_address = (dma_addr_t)page_to_phys(sg->page) ++ + sg->offset; ++ } ++ } ++ ++ return nents; ++} ++ ++EXPORT_SYMBOL(dma_map_sg); ++ ++dma_addr_t dma_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, enum dma_data_direction direction) ++{ ++ unsigned long addr; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ addr = (unsigned long) page_address(page) + offset; ++ dma_cache_wback_inv(addr, size); ++ ++ return page_to_phys(page) + offset; ++} ++ ++EXPORT_SYMBOL(dma_map_page); ++ ++void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(direction == DMA_NONE); ++ ++ if (direction != DMA_TO_DEVICE) { ++ unsigned long addr; ++ ++ addr = dma_address + PAGE_OFFSET; ++ dma_cache_wback_inv(addr, size); ++ } ++} ++ ++EXPORT_SYMBOL(dma_unmap_page); ++ ++void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, ++ enum dma_data_direction direction) ++{ ++ unsigned long addr; ++ int i; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ if (direction == DMA_TO_DEVICE) ++ return; ++ ++ for (i = 0; i < nhwentries; i++, sg++) { ++ addr = (unsigned long) page_address(sg->page); ++ if (addr) ++ __dma_sync(addr + sg->offset, sg->length, direction); ++ } ++} ++ ++EXPORT_SYMBOL(dma_unmap_sg); ++ ++void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, ++ size_t size, enum dma_data_direction direction) ++{ ++ unsigned long addr; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ addr = dma_handle + PAGE_OFFSET; ++ __dma_sync(addr, size, direction); ++} ++ ++EXPORT_SYMBOL(dma_sync_single_for_cpu); ++ ++void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, ++ size_t size, enum dma_data_direction direction) ++{ ++ unsigned long addr; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ addr = dma_handle + PAGE_OFFSET; ++ __dma_sync(addr, size, direction); ++} ++ ++EXPORT_SYMBOL(dma_sync_single_for_device); ++ ++void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, ++ unsigned long offset, size_t size, enum dma_data_direction direction) ++{ ++ unsigned long addr; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ addr = dma_handle + offset + PAGE_OFFSET; ++ __dma_sync(addr, size, direction); ++} ++ ++EXPORT_SYMBOL(dma_sync_single_range_for_cpu); ++ ++void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, ++ unsigned long offset, size_t size, enum dma_data_direction direction) ++{ ++ unsigned long addr; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ addr = dma_handle + offset + PAGE_OFFSET; ++ __dma_sync(addr, size, direction); ++} ++ ++EXPORT_SYMBOL(dma_sync_single_range_for_device); ++ ++void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ int i; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ /* Make sure that gcc doesn't leave the empty loop body. */ ++ for (i = 0; i < nelems; i++, sg++) ++ __dma_sync((unsigned long)page_address(sg->page), ++ sg->length, direction); ++} ++ ++EXPORT_SYMBOL(dma_sync_sg_for_cpu); ++ ++void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ int i; ++ ++ BUG_ON(direction == DMA_NONE); ++ ++ /* Make sure that gcc doesn't leave the empty loop body. */ ++ for (i = 0; i < nelems; i++, sg++) ++ __dma_sync((unsigned long)page_address(sg->page), ++ sg->length, direction); ++} ++ ++EXPORT_SYMBOL(dma_sync_sg_for_device); ++ ++int dma_mapping_error(dma_addr_t dma_addr) ++{ ++ return 0; ++} ++ ++EXPORT_SYMBOL(dma_mapping_error); ++ ++int dma_supported(struct device *dev, u64 mask) ++{ ++ /* ++ * we fall back to GFP_DMA when the mask isn't all 1s, ++ * so we can't guarantee allocations that must be ++ * within a tighter range than GFP_DMA.. ++ */ ++ if (mask < 0x00ffffff) ++ return 0; ++ ++ return 1; ++} ++ ++EXPORT_SYMBOL(dma_supported); ++ ++int dma_is_consistent(dma_addr_t dma_addr) ++{ ++ return 1; ++} ++ ++EXPORT_SYMBOL(dma_is_consistent); ++ ++void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction direction) ++{ ++ if (direction == DMA_NONE) ++ return; ++ ++ dma_cache_wback_inv((unsigned long)vaddr, size); ++} ++ ++EXPORT_SYMBOL(dma_cache_sync); ++ ++/* The DAC routines are a PCIism.. */ ++ ++#ifdef CONFIG_PCI ++ ++#include ++ ++dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, ++ struct page *page, unsigned long offset, int direction) ++{ ++ return (dma64_addr_t)page_to_phys(page) + offset; ++} ++ ++EXPORT_SYMBOL(pci_dac_page_to_dma); ++ ++struct page *pci_dac_dma_to_page(struct pci_dev *pdev, ++ dma64_addr_t dma_addr) ++{ ++ return mem_map + (dma_addr >> PAGE_SHIFT); ++} ++ ++EXPORT_SYMBOL(pci_dac_dma_to_page); ++ ++unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, ++ dma64_addr_t dma_addr) ++{ ++ return dma_addr & ~PAGE_MASK; ++} ++ ++EXPORT_SYMBOL(pci_dac_dma_to_offset); ++ ++void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, ++ dma64_addr_t dma_addr, size_t len, int direction) ++{ ++ BUG_ON(direction == PCI_DMA_NONE); ++ ++ dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); ++} ++ ++EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); ++ ++void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, ++ dma64_addr_t dma_addr, size_t len, int direction) ++{ ++ BUG_ON(direction == PCI_DMA_NONE); ++ ++ dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); ++} ++ ++EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); ++ ++#endif /* CONFIG_PCI */ +diff --git a/arch/nios2nommu/mm/extable.c b/arch/nios2nommu/mm/extable.c +new file mode 100644 +index 0000000..e23778f +--- /dev/null ++++ b/arch/nios2nommu/mm/extable.c +@@ -0,0 +1,29 @@ ++/* ++ * linux/arch/niosnommu/mm/extable.c ++ */ ++ ++#include ++#include ++#include ++ ++/* Simple binary search */ ++const struct exception_table_entry * ++search_extable(const struct exception_table_entry *first, ++ const struct exception_table_entry *last, ++ unsigned long value) ++{ ++ while (first <= last) { ++ const struct exception_table_entry *mid; ++ long diff; ++ ++ mid = (last - first) / 2 + first; ++ diff = mid->insn - value; ++ if (diff == 0) ++ return mid; ++ else if (diff < 0) ++ first = mid+1; ++ else ++ last = mid-1; ++ } ++ return NULL; ++} +diff --git a/arch/nios2nommu/mm/init.c b/arch/nios2nommu/mm/init.c +new file mode 100644 +index 0000000..21fe61b +--- /dev/null ++++ b/arch/nios2nommu/mm/init.c +@@ -0,0 +1,231 @@ ++/* ++ * linux/arch/nios2nommu/mm/init.c ++ * ++ * Copyright (C) 1998 D. Jeff Dionne , ++ * Kenneth Albanowski , ++ * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * Based on: ++ * ++ * linux/arch/m68k/mm/init.c ++ * ++ * Copyright (C) 1995 Hamish Macdonald ++ * ++ * JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com) ++ * DEC/2000 -- linux 2.4 support ++ * Jan/20/2004 dgt NiosII ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++//;dgt2;#include ++//;dgt2;#include ++ ++#undef DEBUG ++ ++extern void die_if_kernel(char *,struct pt_regs *,long); ++extern void free_initmem(void); ++ ++/* ++ * BAD_PAGE is the page that is used for page faults when linux ++ * is out-of-memory. Older versions of linux just did a ++ * do_exit(), but using this instead means there is less risk ++ * for a process dying in kernel mode, possibly leaving a inode ++ * unused etc.. ++ * ++ * BAD_PAGETABLE is the accompanying page-table: it is initialized ++ * to point to BAD_PAGE entries. ++ * ++ * ZERO_PAGE is a special page that is used for zero-initialized ++ * data and COW. ++ */ ++static unsigned long empty_bad_page_table; ++ ++static unsigned long empty_bad_page; ++ ++unsigned long empty_zero_page; ++ ++extern unsigned long rom_length; ++ ++void show_mem(void) ++{ ++ unsigned long i; ++ int free = 0, total = 0, reserved = 0, shared = 0; ++ int cached = 0; ++ ++ printk(KERN_INFO "\nMem-info:\n"); ++ show_free_areas(); ++ i = max_mapnr; ++ while (i-- > 0) { ++ total++; ++ if (PageReserved(mem_map+i)) ++ reserved++; ++ else if (PageSwapCache(mem_map+i)) ++ cached++; ++ else if (!page_count(mem_map+i)) ++ free++; ++ else ++ shared += page_count(mem_map+i) - 1; ++ } ++ printk(KERN_INFO "%d pages of RAM\n",total); ++ printk(KERN_INFO "%d free pages\n",free); ++ printk(KERN_INFO "%d reserved pages\n",reserved); ++ printk(KERN_INFO "%d pages shared\n",shared); ++ printk(KERN_INFO "%d pages swap cached\n",cached); ++} ++ ++extern unsigned long memory_start; ++extern unsigned long memory_end; ++ ++/* ++ * paging_init() continues the virtual memory environment setup which ++ * was begun by the code in arch/head.S. ++ * The parameters are pointers to where to stick the starting and ending ++ * addresses of available kernel virtual memory. ++ */ ++void __init paging_init(void) ++{ ++ /* ++ * Make sure start_mem is page aligned, otherwise bootmem and ++ * page_alloc get different views of the world. ++ */ ++#ifdef DEBUG ++ unsigned long start_mem = PAGE_ALIGN(memory_start); ++#endif ++ unsigned long end_mem = memory_end & PAGE_MASK; ++ ++#ifdef DEBUG ++ printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n", ++ start_mem, end_mem); ++#endif ++ ++ /* ++ * Initialize the bad page table and bad page to point ++ * to a couple of allocated pages. ++ */ ++ empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); ++ empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); ++ empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); ++ memset((void *)empty_zero_page, 0, PAGE_SIZE); ++ ++ /* ++ * Set up SFC/DFC registers (user data space). ++ */ ++ set_fs (USER_DS); ++ ++#ifdef DEBUG ++ printk (KERN_DEBUG "before free_area_init\n"); ++ ++ printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n", ++ start_mem, end_mem); ++#endif ++ ++ { ++ unsigned long zones_size[MAX_NR_ZONES] = {0, }; ++ ++ zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT; ++ zones_size[ZONE_NORMAL] = 0; ++#ifdef CONFIG_HIGHMEM ++ zones_size[ZONE_HIGHMEM] = 0; ++#endif ++ free_area_init(zones_size); ++ } ++} ++ ++void __init mem_init(void) ++{ ++ int codek = 0, datak = 0, initk = 0; ++ unsigned long tmp; ++ extern char _etext, _stext, __init_begin, __init_end, _end; ++ unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */ ++ unsigned long end_mem = memory_end; /* DAVIDM - this must not include kernel stack at top */ ++ ++#ifdef DEBUG ++ printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem); ++#endif ++ ++ end_mem &= PAGE_MASK; ++ high_memory = (void *) end_mem; ++ ++ start_mem = PAGE_ALIGN(start_mem); ++ max_mapnr = num_physpages = MAP_NR(high_memory); ++ ++ /* this will put all memory onto the freelists */ ++ totalram_pages = free_all_bootmem(); ++ ++ codek = (&_etext - &_stext) >> 10; ++ datak = (&_end - &_etext) >> 10; ++ initk = (&__init_begin - &__init_end) >> 10; ++ ++ tmp = nr_free_pages() << PAGE_SHIFT; ++ printk(KERN_INFO "Memory available: %luk/%luk RAM, %luk/%luk ROM (%dk kernel code, %dk data)\n", ++ tmp >> 10, ++ (&_end - &_stext) >> 10, ++ (rom_length > 0) ? ((rom_length >> 10) - codek) : 0, ++ rom_length >> 10, ++ codek, ++ datak ++ ); ++} ++ ++ ++#ifdef CONFIG_BLK_DEV_INITRD ++void __init free_initrd_mem(unsigned long start, unsigned long end) ++{ ++ int pages = 0; ++ for (; start < end; start += PAGE_SIZE) { ++ ClearPageReserved(virt_to_page(start)); ++ init_page_count(virt_to_page(start)); ++ free_page(start); ++ totalram_pages++; ++ pages++; ++ } ++ printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages); ++} ++#endif ++ ++void free_initmem(void) ++{ ++#ifdef CONFIG_RAMKERNEL ++ unsigned long addr; ++ extern char __init_begin, __init_end; ++ /* ++ * The following code should be cool even if these sections ++ * are not page aligned. ++ */ ++ addr = PAGE_ALIGN((unsigned long)(&__init_begin)); ++ /* next to check that the page we free is not a partial page */ ++ for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) { ++ ClearPageReserved(virt_to_page(addr)); ++ init_page_count(virt_to_page(addr)); ++ free_page(addr); ++ totalram_pages++; ++ } ++ printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n", ++ (addr - PAGE_ALIGN((long) &__init_begin)) >> 10, ++ (int)(PAGE_ALIGN((unsigned long)(&__init_begin))), ++ (int)(addr - PAGE_SIZE)); ++#endif ++} ++ +diff --git a/arch/nios2nommu/mm/ioremap.c b/arch/nios2nommu/mm/ioremap.c +new file mode 100644 +index 0000000..1c8b172 +--- /dev/null ++++ b/arch/nios2nommu/mm/ioremap.c +@@ -0,0 +1,65 @@ ++/* linux/arch/nios2nommu/mm/ioremap.c, based on: ++ * ++ * linux/arch/m68knommu/mm/kmap.c ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 2000 Lineo, ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Map some physical address range into the kernel address space. ++ */ ++ ++void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) ++{ ++ return (void *)physaddr; ++} ++ ++/* ++ * Unmap a ioremap()ed region again ++ */ ++void iounmap(void *addr) ++{ ++} ++ ++/* ++ * __iounmap unmaps nearly everything, so be careful ++ * it doesn't free currently pointer/page tables anymore but it ++ * wans't used anyway and might be added later. ++ */ ++void __iounmap(void *addr, unsigned long size) ++{ ++} ++ +diff --git a/arch/nios2nommu/mm/memory.c b/arch/nios2nommu/mm/memory.c +new file mode 100644 +index 0000000..76d60d9 +--- /dev/null ++++ b/arch/nios2nommu/mm/memory.c +@@ -0,0 +1,212 @@ ++/* ++ * linux/arch/nio2nommu/mm/memory.c ++ * ++ * Copyright (C) 1995 Hamish Macdonald ++ * Copyright (C) 1998 Kenneth Albanowski , ++ * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * Based on: ++ * ++ * linux/arch/m68k/mm/memory.c ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * cache_clear() semantics: Clear any cache entries for the area in question, ++ * without writing back dirty entries first. This is useful if the data will ++ * be overwritten anyway, e.g. by DMA to memory. The range is defined by a ++ * _physical_ address. ++ */ ++ ++void cache_clear (unsigned long paddr, int len) ++{ ++} ++ ++ ++/* ++ * Define cache invalidate functions. The instruction and data cache ++ * will need to be flushed. Write back the dirty data cache and invalidate ++ * the instruction cache for the range. ++ * ++ */ ++ ++static __inline__ void cache_invalidate_inst(unsigned long paddr, int len) ++{ ++ unsigned long sset, eset; ++ ++ sset = (paddr & (nasys_icache_size - 1)) & (~(nasys_icache_line_size - 1)); ++ eset = (((paddr & (nasys_icache_size - 1)) + len) & (~(nasys_icache_line_size - 1))) + nasys_icache_line_size; ++ ++ __asm__ __volatile__ ( ++ "1:\n\t" ++ "flushi %0\n\t" ++ "add %0,%0,%2\n\t" ++ "blt %0,%1,1b\n\t" ++ "flushp\n\t" ++ : : "r" (sset), "r" (eset), "r" (nasys_icache_line_size)); ++ ++} ++ ++static __inline__ void cache_invalidate_data(unsigned long paddr, int len) ++{ ++ unsigned long sset, eset; ++ ++ sset = (paddr & (nasys_dcache_size - 1)) & (~(nasys_dcache_line_size - 1)); ++ eset = (((paddr & (nasys_dcache_size - 1)) + len) & (~(nasys_dcache_line_size - 1))) + nasys_dcache_line_size; ++ ++ __asm__ __volatile__ ( ++ "1:\n\t" ++ "flushd 0(%0)\n\t" ++ "add %0,%0,%2\n\t" ++ "blt %0,%1,1b\n\t" ++ : : "r" (sset),"r" (eset), "r" (nasys_dcache_line_size)); ++ ++} ++ ++static __inline__ void cache_invalidate_lines(unsigned long paddr, int len) ++{ ++ unsigned long sset, eset; ++ ++ sset = (paddr & (nasys_dcache_size - 1)) & (~(nasys_dcache_line_size - 1)); ++ eset = (((paddr & (nasys_dcache_size - 1)) + len) & (~(nasys_dcache_line_size - 1))) + nasys_dcache_line_size; ++ ++ __asm__ __volatile__ ( ++ "1:\n\t" ++ "flushd 0(%0)\n\t" ++ "add %0,%0,%2\n\t" ++ "blt %0,%1,1b\n\t" ++ : : "r" (sset),"r" (eset), "r" (nasys_dcache_line_size)); ++ ++ sset = (paddr & (nasys_icache_size - 1)) & (~(nasys_icache_line_size - 1)); ++ eset = (((paddr & (nasys_icache_size - 1)) + len) & (~(nasys_icache_line_size - 1))) + nasys_icache_line_size; ++ ++ __asm__ __volatile__ ( ++ "1:\n\t" ++ "flushi %0\n\t" ++ "add %0,%0,%2\n\t" ++ "blt %0,%1,1b\n\t" ++ "flushp\n\t" ++ : : "r" (sset), "r" (eset), "r" (nasys_icache_line_size)); ++ ++} ++ ++/* ++ * cache_push() semantics: Write back any dirty cache data in the given area, ++ * and invalidate the range in the instruction cache. It needs not (but may) ++ * invalidate those entries also in the data cache. The range is defined by a ++ * _physical_ address. ++ */ ++ ++void cache_push (unsigned long paddr, int len) ++{ ++ cache_invalidate_lines(paddr, len); ++} ++ ++ ++/* ++ * cache_push_v() semantics: Write back any dirty cache data in the given ++ * area, and invalidate those entries at least in the instruction cache. This ++ * is intended to be used after data has been written that can be executed as ++ * code later. The range is defined by a _user_mode_ _virtual_ address. ++ */ ++ ++void cache_push_v (unsigned long vaddr, int len) ++{ ++ cache_invalidate_lines(vaddr, len); ++} ++ ++/* ++ * cache_push_all() semantics: Invalidate instruction cache and write back ++ * dirty data cache & invalidate. ++ */ ++void cache_push_all (void) ++{ ++ __asm__ __volatile__ ( ++ "1:\n\t" ++ "flushd 0(%0)\n\t" ++ "sub %0,%0,%1\n\t" ++ "bgt %0,r0,1b\n\t" ++ : : "r" (nasys_dcache_size), "r" (nasys_dcache_line_size)); ++ ++ __asm__ __volatile__ ( ++ "1:\n\t" ++ "flushi %0\n\t" ++ "sub %0,%0,%1\n\t" ++ "bgt %0,r0,1b\n\t" ++ "flushp\n\t" ++ : : "r" (nasys_icache_size), "r" (nasys_icache_line_size)); ++ ++} ++ ++/* ++ * dcache_push() semantics: Write back and dirty data cache and invalidate ++ * the range. ++ */ ++void dcache_push (unsigned long vaddr, int len) ++{ ++ cache_invalidate_data(vaddr, len); ++} ++ ++/* ++ * icache_push() semantics: Invalidate instruction cache in the range. ++ */ ++void icache_push (unsigned long vaddr, int len) ++{ ++ cache_invalidate_inst(vaddr, len); ++} ++ ++/* Map some physical address range into the kernel address space. The ++ * code is copied and adapted from map_chunk(). ++ */ ++ ++unsigned long kernel_map(unsigned long paddr, unsigned long size, ++ int nocacheflag, unsigned long *memavailp ) ++{ ++ return paddr; ++} ++ ++ ++int is_in_rom(unsigned long addr) ++{ ++ /* Default case, not in ROM */ ++ return(0); ++} ++ ++int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, ++ unsigned long address, int write_access) ++{ ++ BUG(); ++ return VM_FAULT_OOM; ++} +diff --git a/arch/nios2nommu/scripts/PTF/PTFParser.pm b/arch/nios2nommu/scripts/PTF/PTFParser.pm +new file mode 100644 +index 0000000..c243c7b +--- /dev/null ++++ b/arch/nios2nommu/scripts/PTF/PTFParser.pm +@@ -0,0 +1,873 @@ ++#################################################################### ++# ++# This file was generated using Parse::Yapp version 1.05. ++# ++# Don't edit this file, use source file instead. ++# ++# ANY CHANGE MADE HERE WILL BE LOST ! ++# ++#################################################################### ++package PTFParser; ++use vars qw ( @ISA ); ++use strict; ++ ++@ISA= qw ( Parse::Yapp::Driver ); ++#Included Parse/Yapp/Driver.pm file---------------------------------------- ++{ ++# ++# Module Parse::Yapp::Driver ++# ++# This module is part of the Parse::Yapp package available on your ++# nearest CPAN ++# ++# Any use of this module in a standalone parser make the included ++# text under the same copyright as the Parse::Yapp module itself. ++# ++# This notice should remain unchanged. ++# ++# (c) Copyright 1998-2001 Francois Desarmenien, all rights reserved. ++# (see the pod text in Parse::Yapp module for use and distribution rights) ++# ++ ++package Parse::Yapp::Driver; ++ ++require 5.004; ++ ++use strict; ++ ++use vars qw ( $VERSION $COMPATIBLE $FILENAME ); ++ ++$VERSION = '1.05'; ++$COMPATIBLE = '0.07'; ++$FILENAME=__FILE__; ++ ++use Carp; ++ ++#Known parameters, all starting with YY (leading YY will be discarded) ++my(%params)=(YYLEX => 'CODE', 'YYERROR' => 'CODE', YYVERSION => '', ++ YYRULES => 'ARRAY', YYSTATES => 'ARRAY', YYDEBUG => ''); ++#Mandatory parameters ++my(@params)=('LEX','RULES','STATES'); ++ ++sub new { ++ my($class)=shift; ++ my($errst,$nberr,$token,$value,$check,$dotpos); ++ my($self)={ ERROR => \&_Error, ++ ERRST => \$errst, ++ NBERR => \$nberr, ++ TOKEN => \$token, ++ VALUE => \$value, ++ DOTPOS => \$dotpos, ++ STACK => [], ++ DEBUG => 0, ++ CHECK => \$check }; ++ ++ _CheckParams( [], \%params, \@_, $self ); ++ ++ exists($$self{VERSION}) ++ and $$self{VERSION} < $COMPATIBLE ++ and croak "Yapp driver version $VERSION ". ++ "incompatible with version $$self{VERSION}:\n". ++ "Please recompile parser module."; ++ ++ ref($class) ++ and $class=ref($class); ++ ++ bless($self,$class); ++} ++ ++sub YYParse { ++ my($self)=shift; ++ my($retval); ++ ++ _CheckParams( \@params, \%params, \@_, $self ); ++ ++ if($$self{DEBUG}) { ++ _DBLoad(); ++ $retval = eval '$self->_DBParse()';#Do not create stab entry on compile ++ $@ and die $@; ++ } ++ else { ++ $retval = $self->_Parse(); ++ } ++ $retval ++} ++ ++sub YYData { ++ my($self)=shift; ++ ++ exists($$self{USER}) ++ or $$self{USER}={}; ++ ++ $$self{USER}; ++ ++} ++ ++sub YYErrok { ++ my($self)=shift; ++ ++ ${$$self{ERRST}}=0; ++ undef; ++} ++ ++sub YYNberr { ++ my($self)=shift; ++ ++ ${$$self{NBERR}}; ++} ++ ++sub YYRecovering { ++ my($self)=shift; ++ ++ ${$$self{ERRST}} != 0; ++} ++ ++sub YYAbort { ++ my($self)=shift; ++ ++ ${$$self{CHECK}}='ABORT'; ++ undef; ++} ++ ++sub YYAccept { ++ my($self)=shift; ++ ++ ${$$self{CHECK}}='ACCEPT'; ++ undef; ++} ++ ++sub YYError { ++ my($self)=shift; ++ ++ ${$$self{CHECK}}='ERROR'; ++ undef; ++} ++ ++sub YYSemval { ++ my($self)=shift; ++ my($index)= $_[0] - ${$$self{DOTPOS}} - 1; ++ ++ $index < 0 ++ and -$index <= @{$$self{STACK}} ++ and return $$self{STACK}[$index][1]; ++ ++ undef; #Invalid index ++} ++ ++sub YYCurtok { ++ my($self)=shift; ++ ++ @_ ++ and ${$$self{TOKEN}}=$_[0]; ++ ${$$self{TOKEN}}; ++} ++ ++sub YYCurval { ++ my($self)=shift; ++ ++ @_ ++ and ${$$self{VALUE}}=$_[0]; ++ ${$$self{VALUE}}; ++} ++ ++sub YYExpect { ++ my($self)=shift; ++ ++ keys %{$self->{STATES}[$self->{STACK}[-1][0]]{ACTIONS}} ++} ++ ++sub YYLexer { ++ my($self)=shift; ++ ++ $$self{LEX}; ++} ++ ++ ++################# ++# Private stuff # ++################# ++ ++ ++sub _CheckParams { ++ my($mandatory,$checklist,$inarray,$outhash)=@_; ++ my($prm,$value); ++ my($prmlst)={}; ++ ++ while(($prm,$value)=splice(@$inarray,0,2)) { ++ $prm=uc($prm); ++ exists($$checklist{$prm}) ++ or croak("Unknow parameter '$prm'"); ++ ref($value) eq $$checklist{$prm} ++ or croak("Invalid value for parameter '$prm'"); ++ $prm=unpack('@2A*',$prm); ++ $$outhash{$prm}=$value; ++ } ++ for (@$mandatory) { ++ exists($$outhash{$_}) ++ or croak("Missing mandatory parameter '".lc($_)."'"); ++ } ++} ++ ++sub _Error { ++ print "Parse error.\n"; ++} ++ ++sub _DBLoad { ++ { ++ no strict 'refs'; ++ ++ exists(${__PACKAGE__.'::'}{_DBParse})#Already loaded ? ++ and return; ++ } ++ my($fname)=__FILE__; ++ my(@drv); ++ open(DRV,"<$fname") or die "Report this as a BUG: Cannot open $fname"; ++ while() { ++ /^\s*sub\s+_Parse\s*{\s*$/ .. /^\s*}\s*#\s*_Parse\s*$/ ++ and do { ++ s/^#DBG>//; ++ push(@drv,$_); ++ } ++ } ++ close(DRV); ++ ++ $drv[0]=~s/_P/_DBP/; ++ eval join('',@drv); ++} ++ ++#Note that for loading debugging version of the driver, ++#this file will be parsed from 'sub _Parse' up to '}#_Parse' inclusive. ++#So, DO NOT remove comment at end of sub !!! ++sub _Parse { ++ my($self)=shift; ++ ++ my($rules,$states,$lex,$error) ++ = @$self{ 'RULES', 'STATES', 'LEX', 'ERROR' }; ++ my($errstatus,$nberror,$token,$value,$stack,$check,$dotpos) ++ = @$self{ 'ERRST', 'NBERR', 'TOKEN', 'VALUE', 'STACK', 'CHECK', 'DOTPOS' }; ++ ++#DBG> my($debug)=$$self{DEBUG}; ++#DBG> my($dbgerror)=0; ++ ++#DBG> my($ShowCurToken) = sub { ++#DBG> my($tok)='>'; ++#DBG> for (split('',$$token)) { ++#DBG> $tok.= (ord($_) < 32 or ord($_) > 126) ++#DBG> ? sprintf('<%02X>',ord($_)) ++#DBG> : $_; ++#DBG> } ++#DBG> $tok.='<'; ++#DBG> }; ++ ++ $$errstatus=0; ++ $$nberror=0; ++ ($$token,$$value)=(undef,undef); ++ @$stack=( [ 0, undef ] ); ++ $$check=''; ++ ++ while(1) { ++ my($actions,$act,$stateno); ++ ++ $stateno=$$stack[-1][0]; ++ $actions=$$states[$stateno]; ++ ++#DBG> print STDERR ('-' x 40),"\n"; ++#DBG> $debug & 0x2 ++#DBG> and print STDERR "In state $stateno:\n"; ++#DBG> $debug & 0x08 ++#DBG> and print STDERR "Stack:[". ++#DBG> join(',',map { $$_[0] } @$stack). ++#DBG> "]\n"; ++ ++ ++ if (exists($$actions{ACTIONS})) { ++ ++ defined($$token) ++ or do { ++ ($$token,$$value)=&$lex($self); ++#DBG> $debug & 0x01 ++#DBG> and print STDERR "Need token. Got ".&$ShowCurToken."\n"; ++ }; ++ ++ $act= exists($$actions{ACTIONS}{$$token}) ++ ? $$actions{ACTIONS}{$$token} ++ : exists($$actions{DEFAULT}) ++ ? $$actions{DEFAULT} ++ : undef; ++ } ++ else { ++ $act=$$actions{DEFAULT}; ++#DBG> $debug & 0x01 ++#DBG> and print STDERR "Don't need token.\n"; ++ } ++ ++ defined($act) ++ and do { ++ ++ $act > 0 ++ and do { #shift ++ ++#DBG> $debug & 0x04 ++#DBG> and print STDERR "Shift and go to state $act.\n"; ++ ++ $$errstatus ++ and do { ++ --$$errstatus; ++ ++#DBG> $debug & 0x10 ++#DBG> and $dbgerror ++#DBG> and $$errstatus == 0 ++#DBG> and do { ++#DBG> print STDERR "**End of Error recovery.\n"; ++#DBG> $dbgerror=0; ++#DBG> }; ++ }; ++ ++ ++ push(@$stack,[ $act, $$value ]); ++ ++ $$token ne '' #Don't eat the eof ++ and $$token=$$value=undef; ++ next; ++ }; ++ ++ #reduce ++ my($lhs,$len,$code,@sempar,$semval); ++ ($lhs,$len,$code)=@{$$rules[-$act]}; ++ ++#DBG> $debug & 0x04 ++#DBG> and $act ++#DBG> and print STDERR "Reduce using rule ".-$act." ($lhs,$len): "; ++ ++ $act ++ or $self->YYAccept(); ++ ++ $$dotpos=$len; ++ ++ unpack('A1',$lhs) eq '@' #In line rule ++ and do { ++ $lhs =~ /^\@[0-9]+\-([0-9]+)$/ ++ or die "In line rule name '$lhs' ill formed: ". ++ "report it as a BUG.\n"; ++ $$dotpos = $1; ++ }; ++ ++ @sempar = $$dotpos ++ ? map { $$_[1] } @$stack[ -$$dotpos .. -1 ] ++ : (); ++ ++ $semval = $code ? &$code( $self, @sempar ) ++ : @sempar ? $sempar[0] : undef; ++ ++ splice(@$stack,-$len,$len); ++ ++ $$check eq 'ACCEPT' ++ and do { ++ ++#DBG> $debug & 0x04 ++#DBG> and print STDERR "Accept.\n"; ++ ++ return($semval); ++ }; ++ ++ $$check eq 'ABORT' ++ and do { ++ ++#DBG> $debug & 0x04 ++#DBG> and print STDERR "Abort.\n"; ++ ++ return(undef); ++ ++ }; ++ ++#DBG> $debug & 0x04 ++#DBG> and print STDERR "Back to state $$stack[-1][0], then "; ++ ++ $$check eq 'ERROR' ++ or do { ++#DBG> $debug & 0x04 ++#DBG> and print STDERR ++#DBG> "go to state $$states[$$stack[-1][0]]{GOTOS}{$lhs}.\n"; ++ ++#DBG> $debug & 0x10 ++#DBG> and $dbgerror ++#DBG> and $$errstatus == 0 ++#DBG> and do { ++#DBG> print STDERR "**End of Error recovery.\n"; ++#DBG> $dbgerror=0; ++#DBG> }; ++ ++ push(@$stack, ++ [ $$states[$$stack[-1][0]]{GOTOS}{$lhs}, $semval ]); ++ $$check=''; ++ next; ++ }; ++ ++#DBG> $debug & 0x04 ++#DBG> and print STDERR "Forced Error recovery.\n"; ++ ++ $$check=''; ++ ++ }; ++ ++ #Error ++ $$errstatus ++ or do { ++ ++ $$errstatus = 1; ++ &$error($self); ++ $$errstatus # if 0, then YYErrok has been called ++ or next; # so continue parsing ++ ++#DBG> $debug & 0x10 ++#DBG> and do { ++#DBG> print STDERR "**Entering Error recovery.\n"; ++#DBG> ++$dbgerror; ++#DBG> }; ++ ++ ++$$nberror; ++ ++ }; ++ ++ $$errstatus == 3 #The next token is not valid: discard it ++ and do { ++ $$token eq '' # End of input: no hope ++ and do { ++#DBG> $debug & 0x10 ++#DBG> and print STDERR "**At eof: aborting.\n"; ++ return(undef); ++ }; ++ ++#DBG> $debug & 0x10 ++#DBG> and print STDERR "**Dicard invalid token ".&$ShowCurToken.".\n"; ++ ++ $$token=$$value=undef; ++ }; ++ ++ $$errstatus=3; ++ ++ while( @$stack ++ and ( not exists($$states[$$stack[-1][0]]{ACTIONS}) ++ or not exists($$states[$$stack[-1][0]]{ACTIONS}{error}) ++ or $$states[$$stack[-1][0]]{ACTIONS}{error} <= 0)) { ++ ++#DBG> $debug & 0x10 ++#DBG> and print STDERR "**Pop state $$stack[-1][0].\n"; ++ ++ pop(@$stack); ++ } ++ ++ @$stack ++ or do { ++ ++#DBG> $debug & 0x10 ++#DBG> and print STDERR "**No state left on stack: aborting.\n"; ++ ++ return(undef); ++ }; ++ ++ #shift the error token ++ ++#DBG> $debug & 0x10 ++#DBG> and print STDERR "**Shift \$error token and go to state ". ++#DBG> $$states[$$stack[-1][0]]{ACTIONS}{error}. ++#DBG> ".\n"; ++ ++ push(@$stack, [ $$states[$$stack[-1][0]]{ACTIONS}{error}, undef ]); ++ ++ } ++ ++ #never reached ++ croak("Error in driver logic. Please, report it as a BUG"); ++ ++}#_Parse ++#DO NOT remove comment ++ ++1; ++ ++} ++#End of include-------------------------------------------------- ++ ++ ++#line 1 "PTFParser.yp" ++# ++# Altera PTF file parser ++# ++# Copyright (c) 2004 Microtronix Datacom Ltd. ++# ++ ++package PTFParser; ++ ++use PTF::PTFSection; ++ ++#global variables should go here. ++ ++#my $line = 0; # for error messages ++#my @sectionStack = (); # used to keep track of ptf sections ++#my $root; ++ ++my $fh; ++ ++sub new { ++ my($class)=shift; ++ ref($class) ++ and $class=ref($class); ++ ++ my($self)=$class->SUPER::new( yyversion => '1.05', ++ yystates => ++[ ++ {#State 0 ++ ACTIONS => { ++ 'IDENTIFIER' => 1 ++ }, ++ GOTOS => { ++ 'section' => 2, ++ 'section_title' => 3 ++ } ++ }, ++ {#State 1 ++ ACTIONS => { ++ 'IDENTIFIER' => 4, ++ 'STRING_LITERAL' => 6, ++ 'NUMBER' => 7 ++ }, ++ DEFAULT => -3, ++ GOTOS => { ++ 'section_name' => 5 ++ } ++ }, ++ {#State 2 ++ ACTIONS => { ++ '' => 8 ++ } ++ }, ++ {#State 3 ++ ACTIONS => { ++ "{" => 9 ++ } ++ }, ++ {#State 4 ++ DEFAULT => -4 ++ }, ++ {#State 5 ++ DEFAULT => -2 ++ }, ++ {#State 6 ++ DEFAULT => -6 ++ }, ++ {#State 7 ++ DEFAULT => -5 ++ }, ++ {#State 8 ++ DEFAULT => 0 ++ }, ++ {#State 9 ++ ACTIONS => { ++ 'IDENTIFIER' => 11, ++ 'HIERARCHICAL_NAME' => 13 ++ }, ++ DEFAULT => -7, ++ GOTOS => { ++ 'assignment_name' => 10, ++ 'assignment' => 12, ++ 'section_element' => 14, ++ 'section' => 15, ++ 'section_title' => 3 ++ } ++ }, ++ {#State 10 ++ ACTIONS => { ++ "=" => 16 ++ } ++ }, ++ {#State 11 ++ ACTIONS => { ++ 'IDENTIFIER' => 4, ++ 'STRING_LITERAL' => 6, ++ 'NUMBER' => 7, ++ "=" => -11 ++ }, ++ DEFAULT => -3, ++ GOTOS => { ++ 'section_name' => 5 ++ } ++ }, ++ {#State 12 ++ ACTIONS => { ++ 'IDENTIFIER' => 11, ++ 'HIERARCHICAL_NAME' => 13 ++ }, ++ DEFAULT => -7, ++ GOTOS => { ++ 'assignment_name' => 10, ++ 'assignment' => 12, ++ 'section_element' => 17, ++ 'section' => 15, ++ 'section_title' => 3 ++ } ++ }, ++ {#State 13 ++ DEFAULT => -12 ++ }, ++ {#State 14 ++ ACTIONS => { ++ "}" => 18 ++ } ++ }, ++ {#State 15 ++ ACTIONS => { ++ 'IDENTIFIER' => 11, ++ 'HIERARCHICAL_NAME' => 13 ++ }, ++ DEFAULT => -7, ++ GOTOS => { ++ 'assignment_name' => 10, ++ 'assignment' => 12, ++ 'section_element' => 19, ++ 'section' => 15, ++ 'section_title' => 3 ++ } ++ }, ++ {#State 16 ++ ACTIONS => { ++ 'STRING_LITERAL' => 20, ++ 'NUMBER' => 22 ++ }, ++ GOTOS => { ++ 'assignment_value' => 21 ++ } ++ }, ++ {#State 17 ++ DEFAULT => -8 ++ }, ++ {#State 18 ++ DEFAULT => -1 ++ }, ++ {#State 19 ++ DEFAULT => -9 ++ }, ++ {#State 20 ++ DEFAULT => -13 ++ }, ++ {#State 21 ++ ACTIONS => { ++ ";" => 23 ++ } ++ }, ++ {#State 22 ++ DEFAULT => -14 ++ }, ++ {#State 23 ++ DEFAULT => -10 ++ } ++], ++ yyrules => ++[ ++ [#Rule 0 ++ '$start', 2, undef ++ ], ++ [#Rule 1 ++ 'section', 4, ++sub ++#line 20 "PTFParser.yp" ++{ ++ my $sectionStack = $_[0]->YYData->{sectionStack}; ++ pop @{$sectionStack}; ++ } ++ ], ++ [#Rule 2 ++ 'section_title', 2, ++sub ++#line 26 "PTFParser.yp" ++{ ++ my $section = PTFSection->new (type => $_[1], name => $_[2]); ++ my $sectionStack = $_[0]->YYData->{sectionStack}; ++ ++ if (scalar(@{$sectionStack}) == 0) { ++ $_[0]->YYData->{root} = $section; ++ } else { ++ my $parent = $sectionStack->[$#{$sectionStack}]; ++ $parent->addSection ($section); ++ } ++ ++ push @{$sectionStack}, $section; ++ } ++ ], ++ [#Rule 3 ++ 'section_name', 0, undef ++ ], ++ [#Rule 4 ++ 'section_name', 1, undef ++ ], ++ [#Rule 5 ++ 'section_name', 1, undef ++ ], ++ [#Rule 6 ++ 'section_name', 1, undef ++ ], ++ [#Rule 7 ++ 'section_element', 0, undef ++ ], ++ [#Rule 8 ++ 'section_element', 2, undef ++ ], ++ [#Rule 9 ++ 'section_element', 2, undef ++ ], ++ [#Rule 10 ++ 'assignment', 4, ++sub ++#line 52 "PTFParser.yp" ++{ ++ my $sectionStack = $_[0]->YYData->{sectionStack}; ++ my $parent= $sectionStack->[$#{$sectionStack}]; ++ $parent->addAssignment ($_[1], $_[3]); ++ } ++ ], ++ [#Rule 11 ++ 'assignment_name', 1, undef ++ ], ++ [#Rule 12 ++ 'assignment_name', 1, undef ++ ], ++ [#Rule 13 ++ 'assignment_value', 1, undef ++ ], ++ [#Rule 14 ++ 'assignment_value', 1, undef ++ ] ++], ++ @_); ++ bless($self,$class); ++} ++ ++#line 67 "PTFParser.yp" ++ ++ ++sub _Error { ++# TODO: update this error function to be more useful ++ exists $_[0]->YYData->{ERRMSG} ++ and do { ++ print $_[0]->YYData->{ERRMSG}; ++ delete $_[0]->YYData->{ERRMSG}; ++ return; ++ }; ++ print "Syntax error on line $_[0]->YYData->{line}.\n"; ++} ++ ++sub _Lexer { ++ my($parser)=shift; ++ ++ if (! $parser->YYData->{INPUT}) { ++ if ($parser->YYData->{INPUT} = <$fh>) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ } ++ ++ $parser->YYData->{INPUT} and ++ $parser->YYData->{INPUT} =~ s/^\s*//; ++ ++ while (1) { ++ ++ # skip blank lines ++ if ($parser->YYData->{INPUT} =~ s/^[ \t\r\n]*$//) { ++ if ($parser->YYData->{INPUT} = <$fh>) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ $parser->YYData->{INPUT} and ++ $parser->YYData->{INPUT} =~ s/^\s*//; ++ next; ++ } ++ ++ # Skip comments ++ if ($parser->YYData->{INPUT} =~ s/^#.*//) { ++ if ($parser->YYData->{INPUT} = <$fh>) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ $parser->YYData->{INPUT} and ++ $parser->YYData->{INPUT} =~ s/^\s*//; ++ next; ++ } ++ ++ # Don't continue if the line length is 0; ++ if (length $parser->YYData->{INPUT} == 0) { ++ if ($parser->YYData->{INPUT} = <$fh>) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ $parser->YYData->{INPUT} and ++ $parser->YYData->{INPUT} =~ s/^\s*//; ++ next; ++ } ++ ++ # tokenize input ++ $parser->YYData->{INPUT} =~ s/^([a-zA-Z_][a-zA-Z_0-9\/]*)// ++ and return('IDENTIFIER',$1); ++ $parser->YYData->{INPUT} =~ s/^"([^"\\]*(\\.[^"\\]*)*)"// ++ and return('STRING_LITERAL',$1); ++ $parser->YYData->{INPUT} =~ s/^"([^"\\]*(\\.[^"\\]*)*)// ++ and do { ++ my $literal = $1; ++ ++ do { ++ if ($parser->YYData->{INPUT} = <$fh>) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ ++ $parser->YYData->{INPUT} =~ s/([^"\\]*(\\.[^"\\]*)*)"// ++ and do { ++ $literal .= $1; ++ return ('STRING_LITERAL', $literal); ++ }; ++ ++ $parser->YYData->{INPUT} =~ s/([^"\\]*(\\.[^"\\]*)*)// ++ and $literal .= $1; ++ } while (1); ++ }; ++ $parser->YYData->{INPUT} =~ s/^([0-9]+)// ++ and return('NUMBER',$1); ++ $parser->YYData->{INPUT} =~ s/^([\$]{1,2}[a-zA-Z0-9 \/_]+)// ++ and return('HIERARCHICAL_NAME',$1); ++ $parser->YYData->{INPUT} =~ s/^(.)// ++ and return($1,$1); ++ } ++} ++ ++sub readPTF { ++ my $self = shift; ++ my $filename = shift; ++ ++ # store information for later use ++ $self->YYData->{line} = 0; ++ $self->YYData->{sectionStack} = []; ++ undef $self->YYData->{root}; ++ ++ if (-e $filename) { ++ open (PTFFILE, $filename); ++ $fh = \*PTFFILE; ++ } else { ++ $fh = \*STDIN; ++ } ++ ++ $self->YYParse ( ++ yylex => \&_Lexer, ++ yyerror => \&_Error, ++ ); ++ ++ if (-e $filename) { ++ close PTFFILE; ++ } ++ ++ return $self->YYData->{root}; ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/PTF/PTFParser.yp b/arch/nios2nommu/scripts/PTF/PTFParser.yp +new file mode 100644 +index 0000000..e105e6a +--- /dev/null ++++ b/arch/nios2nommu/scripts/PTF/PTFParser.yp +@@ -0,0 +1,178 @@ ++%{# ++# Altera PTF file parser ++# ++# Copyright (c) 2004 Microtronix Datacom Ltd. ++# ++ ++package PTFParser; ++ ++use PTF::PTFSection; ++ ++%} ++ ++%% ++section: section_title '{' section_element '}' { ++ my $sectionStack = $_[0]->YYData->{sectionStack}; ++ pop @{$sectionStack}; ++ } ++; ++ ++section_title: IDENTIFIER section_name { ++ my $section = PTFSection->new (type => $_[1], name => $_[2]); ++ my $sectionStack = $_[0]->YYData->{sectionStack}; ++ ++ if (scalar(@{$sectionStack}) == 0) { ++ $_[0]->YYData->{root} = $section; ++ } else { ++ my $parent = $sectionStack->[$#{$sectionStack}]; ++ $parent->addSection ($section); ++ } ++ ++ push @{$sectionStack}, $section; ++ } ++; ++ ++section_name: # empty string ++ | IDENTIFIER ++ | NUMBER ++ | STRING_LITERAL ++; ++ ++section_element: # empty element ++ | assignment section_element ++ | section section_element ++; ++ ++assignment: assignment_name '=' assignment_value ';' { ++ my $sectionStack = $_[0]->YYData->{sectionStack}; ++ my $parent= $sectionStack->[$#{$sectionStack}]; ++ $parent->addAssignment ($_[1], $_[3]); ++ } ++; ++ ++assignment_name: IDENTIFIER ++ | HIERARCHICAL_NAME ++; ++ ++assignment_value: STRING_LITERAL ++ | NUMBER ++; ++ ++%% ++ ++sub _Error { ++# TODO: update this error function to be more useful ++ exists $_[0]->YYData->{ERRMSG} ++ and do { ++ print $_[0]->YYData->{ERRMSG}; ++ delete $_[0]->YYData->{ERRMSG}; ++ return; ++ }; ++ print "Syntax error on line $_[0]->YYData->{line}.\n"; ++} ++ ++sub _Lexer { ++ my($parser)=shift; ++ ++ if (! $parser->YYData->{INPUT}) { ++ if ($parser->YYData->{INPUT} = ) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ } ++ ++ $parser->YYData->{INPUT} and ++ $parser->YYData->{INPUT} =~ s/^\s*//; ++ ++ while (1) { ++ ++ # skip blank lines ++ if ($parser->YYData->{INPUT} =~ s/^[ \t\r\n]*$//) { ++ if ($parser->YYData->{INPUT} = ) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ $parser->YYData->{INPUT} and ++ $parser->YYData->{INPUT} =~ s/^\s*//; ++ next; ++ } ++ ++ # Skip comments ++ if ($parser->YYData->{INPUT} =~ s/^#.*//) { ++ if ($parser->YYData->{INPUT} = ) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ $parser->YYData->{INPUT} and ++ $parser->YYData->{INPUT} =~ s/^\s*//; ++ next; ++ } ++ ++ # Don't continue if the line length is 0; ++ if (length $parser->YYData->{INPUT} == 0) { ++ if ($parser->YYData->{INPUT} = ) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ $parser->YYData->{INPUT} and ++ $parser->YYData->{INPUT} =~ s/^\s*//; ++ next; ++ } ++ ++ # tokenize input ++ $parser->YYData->{INPUT} =~ s/^([a-zA-Z_][a-zA-Z_0-9\/]*)// ++ and return('IDENTIFIER',$1); ++ $parser->YYData->{INPUT} =~ s/^"([^"\\]*(\\.[^"\\]*)*)"// ++ and return('STRING_LITERAL',$1); ++ $parser->YYData->{INPUT} =~ s/^"([^"\\]*(\\.[^"\\]*)*)// ++ and do { ++ my $literal = $1; ++ ++ do { ++ if ($parser->YYData->{INPUT} = ) { ++ $parser->YYData->{line} += 1; ++ } else { ++ return ('', undef); ++ } ++ ++ $parser->YYData->{INPUT} =~ s/([^"\\]*(\\.[^"\\]*)*)"// ++ and do { ++ $literal .= $1; ++ return ('STRING_LITERAL', $literal); ++ }; ++ ++ $parser->YYData->{INPUT} =~ s/([^"\\]*(\\.[^"\\]*)*)// ++ and $literal .= $1; ++ } while (1); ++ }; ++ $parser->YYData->{INPUT} =~ s/^([0-9]+)// ++ and return('NUMBER',$1); ++ $parser->YYData->{INPUT} =~ s/^([\$]{1,2}[a-zA-Z0-9 \/_]+)// ++ and return('HIERARCHICAL_NAME',$1); ++ $parser->YYData->{INPUT} =~ s/^(.)// ++ and return($1,$1); ++ } ++} ++ ++sub readPTF { ++ my $self = shift; ++ my $filename = shift; ++ ++ # store information for later use ++ $self->YYData->{line} = 0; ++ $self->YYData->{sectionStack} = []; ++ undef $self->YYData->{root}; ++ ++ open (PTFFILE, $filename) or return undef; ++ $self->YYParse ( ++ yylex => \&_Lexer, ++ yyerror => \&_Error, ++ ); ++ close PTFFILE; ++ ++ return $self->YYData->{root}; ++} +diff --git a/arch/nios2nommu/scripts/PTF/PTFSection.pm b/arch/nios2nommu/scripts/PTF/PTFSection.pm +new file mode 100644 +index 0000000..a88d340 +--- /dev/null ++++ b/arch/nios2nommu/scripts/PTF/PTFSection.pm +@@ -0,0 +1,81 @@ ++package PTFSection; ++ ++use strict; ++ ++# Fields: ++# type = type of PTF Section ++# name = name of PTF Section (can be blank) ++# sections = array of section references ++# assignments = hash of assignments ++ ++sub new { ++ my $invocant = shift; ++ my $class = ref($invocant) || $invocant; ++ my $self = { ++ @_, ++ sections => [], ++ assignments => {}, ++ }; ++ bless ($self, $class); ++ return $self; ++} ++ ++sub addSection { ++ my ($self, $section) = @_; ++ push @{$self->{sections}}, $section; ++} ++ ++sub getSections { ++ my ($self, $type) = @_; ++ ++ if (! $type) { ++ return @{$self->{sections}}; ++ } ++ ++ my @matchedSections; ++ foreach my $section (@{$self->{sections}}) { ++ if ($section->type eq $type) { ++ push @matchedSections, $section; ++ } ++ } ++ ++ return @matchedSections; ++} ++ ++sub getSection { ++ my ($self, $type, $name) = @_; ++ ++ if (! $name) { ++ $name = ""; ++ } ++ ++ foreach my $section (@{$self->{sections}}) { ++ if ($section->type eq $type and $section->name eq $name) { ++ return $section; ++ } ++ } ++ ++} ++ ++sub addAssignment { ++ my ($self, $name, $value) = @_; ++ $self->{assignments}{$name} = $value; ++} ++ ++sub getAssignment { ++ my ($self, $name) = @_; ++ return $self->{assignments}{$name}; ++} ++ ++sub type { ++ my $self = shift; ++ return $self->{type}; ++} ++ ++sub name { ++ my $self = shift; ++ return $self->{name}; ++} ++ ++ ++1; +diff --git a/arch/nios2nommu/scripts/PTF/SystemPTF.pm b/arch/nios2nommu/scripts/PTF/SystemPTF.pm +new file mode 100644 +index 0000000..9f44cfe +--- /dev/null ++++ b/arch/nios2nommu/scripts/PTF/SystemPTF.pm +@@ -0,0 +1,149 @@ ++package SystemPTF; ++ ++use strict; ++ ++use PTF::PTFParser; ++use PTF::PTFSection; ++use PTF::SystemPTF::CPU; ++use PTF::SystemPTF::Board; ++use PTF::SystemPTF::Module; ++ ++# Fields: ++ ++my %module_order; ++ ++sub new { ++ my $invocant = shift; ++ my $class = ref($invocant) || $invocant; ++ my $self = { ++ filename => "", ++ @_, ++ }; ++ ++ my $parser = PTFParser->new; ++ $self->{root} = $parser->readPTF($self->{filename}); ++ ++ # if the specified PTF file could not be read properly, return undef; ++ $self->{root} or return; ++ ++ # if the specified PTF file is not a SYSTEM, return undef. ++ if ($self->{root}->type ne 'SYSTEM') { ++ return; ++ } ++ ++ # initialize the modulemap ++ my @modules = $self->{root}->getSections ("MODULE"); ++ my $index = 0; ++ foreach my $module (@modules) { ++ # if the module is not enabled then do not add ++ my $SBI = $module->getSection ('SYSTEM_BUILDER_INFO', ''); ++ if ($SBI->getAssignment ('Is_Enabled') eq "1") { ++ $self->{modules}->{$module->name} = $module; ++ $module_order{$module->name} = $index; ++ $index += 1; ++ } ++ } ++ ++ bless ($self, $class); ++ return $self; ++} ++ ++sub getName { ++ my ($self) = @_; ++ return $self->{root}->name; ++} ++ ++sub getCPUList { ++ my ($self, @classes) = @_; ++ my @cpulist = (); ++ ++ foreach my $module_name (keys (%{$self->{modules}})) { ++ my $module = $self->{modules}->{$module_name}; ++ my $module_class = $module->getAssignment ('class'); ++ foreach my $class (@classes) { ++ if ($module_class eq $class) { ++ push @cpulist, $module->name; ++ } ++ } ++ } ++ ++ return @cpulist; ++} ++ ++sub getCPU { ++ my ($self, $name) = @_; ++ ++ my $cpu = CPU->new (ptf => $self->{modules}->{$name}); ++} ++ ++sub getModule { ++ my ($self, $name) = @_; ++ ++ my $module = Module->new (ptf => $self->{modules}->{$name}); ++} ++ ++sub getSlaveModules { ++ my ($self, $master, $type) = @_; ++ ++ # create %connected set with just the master ++ # value of hash key is inconsequential ++ my %connected; ++ $connected{$master} = ( ); ++ ++ # create %pool set with all modules ++ # value of hash key is inconsequential ++ my %pool; ++ @pool{keys (%{$self->{modules}})} = ( ); ++ ++ my $dirty = 1; ++ while ($dirty) { ++ # %pool = difference (%pool, %connected) ++ delete @pool{ keys %connected }; ++ ++ $dirty = 0; ++ ++ foreach my $name (keys %pool) { ++ my $mod = $self->getModule ($name); ++ my %mod_masters; ++ @mod_masters{ $mod->getMasters ($type) } = ( ); ++ ++ # if intersection (%masters, %connected) is not empty ++ delete @mod_masters{ ++ grep ( ! exists $connected{ $_ }, ++ keys %mod_masters) }; ++ ++ if (scalar(keys(%mod_masters)) > 0) { ++ $connected{$name} = ( ); ++ $dirty = 1; ++ } ++ } ++ } ++ ++ delete $connected{$master}; ++ ++ return sort module_comparison keys (%connected); ++} ++ ++sub getClockFreq () { ++ my ($self) = @_; ++ ++ my $wsa = $self->{root}->getSection ('WIZARD_SCRIPT_ARGUMENTS', ''); ++ $wsa or return; ++ ++ my $result = $wsa->getAssignment ('clock_freq'); ++ return $result; ++} ++ ++# This is not really a class method... more of a helper function really... ++sub module_comparison { ++ if ($module_order{$a} > $module_order{$b}) { ++ return 1; ++ } elsif ($module_order{$a} < $module_order{$b}) { ++ return -1; ++ } else { ++ return 0; ++ } ++} ++ ++ ++1; +diff --git a/arch/nios2nommu/scripts/PTF/SystemPTF/Board.pm b/arch/nios2nommu/scripts/PTF/SystemPTF/Board.pm +new file mode 100644 +index 0000000..fe2bbc8 +--- /dev/null ++++ b/arch/nios2nommu/scripts/PTF/SystemPTF/Board.pm +@@ -0,0 +1,2 @@ ++1; ++ +diff --git a/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm b/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm +new file mode 100644 +index 0000000..ea10598 +--- /dev/null ++++ b/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm +@@ -0,0 +1,89 @@ ++package CPU; ++ ++use PTF::PTFSection; ++ ++sub new { ++ my $invocant = shift; ++ my $class = ref($invocant) || $invocant; ++ my $self = { ++ @_, ++ }; ++ ++ # if no ptf section was passed in, then return undef ++ $self->{ptf} or return; ++ ++ bless ($self, $class); ++ return $self; ++} ++ ++sub getClass { ++ my ($self) = @_; ++ ++ return $self->{ptf}->getAssignment ('class'); ++} ++ ++sub getVersion { ++ my ($self) = @_; ++ ++ return $self->{ptf}->getAssignment ('class_version'); ++} ++ ++sub getConstant { ++ my ($self, $name) = @_; ++ ++ # get WSA ++ $wsa = $self->{ptf}->getSection('WIZARD_SCRIPT_ARGUMENTS', ''); ++ $wsa or return; ++ ++ # get constants section ++ $constants = $wsa->getSection('CONSTANTS', ''); ++ $constants or return; ++ ++ # get section for specific constant ++ $constant = $constants->getSection ('CONSTANT', $name); ++ $constant or return; ++ ++ # get value of constant ++ $value = $constant->getAssignment ('value'); ++ return $value; ++} ++ ++sub getWSAAssignment { ++ my ($self, $name) = @_; ++ ++ # get WSA ++ $wsa = $self->{ptf}->getSection('WIZARD_SCRIPT_ARGUMENTS', ''); ++ $wsa or return; ++ ++ # get value of WSA Assignment ++ $value = $wsa->getAssignment ($name); ++ return $value; ++} ++ ++sub getResetLocationOffset { ++ my ($self) = @_; ++ ++ $wsa = $self->{ptf}->getSection('WIZARD_SCRIPT_ARGUMENTS', ''); ++ $wsa or return; ++ ++ my $location = $wsa->getAssignment ('reset_slave'); ++ my $offset = $wsa->getAssignment ('reset_offset'); ++ ++ return ($location, $offset); ++} ++ ++sub isEnabled { ++ my ($self) = @_; ++ ++ $sbi = $self->{ptf}->getSection('SYSTEM_BUILDER_INFO', ''); ++ $sbi or return; ++ ++ my $enabled = $sbi->getAssignment ('Is_Enabled'); ++ if ($enabled eq "1") { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/PTF/SystemPTF/Module.pm b/arch/nios2nommu/scripts/PTF/SystemPTF/Module.pm +new file mode 100644 +index 0000000..48d246b +--- /dev/null ++++ b/arch/nios2nommu/scripts/PTF/SystemPTF/Module.pm +@@ -0,0 +1,267 @@ ++package Module; ++ ++use PTF::PTFSection; ++ ++sub new { ++ my $invocant = shift; ++ my $class = ref($invocant) || $invocant; ++ my $self = { ++ @_, ++ }; ++ ++ # if no ptf section was passed in, then return undef ++ $self->{ptf} or return; ++ ++ bless ($self, $class); ++ return $self; ++} ++ ++sub getClass { ++ my ($self) = @_; ++ ++ return $self->{ptf}->getAssignment ('class'); ++} ++ ++sub getPorts { ++ my ($self) = @_; ++ ++ my @port_names; ++ ++ my @ports = $self->{ptf}->getSections ('SLAVE'); ++ foreach $port (@ports) { ++ push @port_names, $port->name; ++ } ++ ++ return @port_names; ++} ++ ++sub getPort { ++ my ($self, $port_name) = @_; ++ ++ my $port; ++ ++ if (! $port_name) { ++ # use first port found ++ my @port_names = $self->getPorts (); ++ $port = $self->{ptf}->getSection ('SLAVE', $port_names[0]); ++ } else { ++ $port = $self->{ptf}->getSection ('SLAVE', $port_name); ++ if (! $port) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ } ++ ++ return $port; ++} ++ ++sub getWSAAssignment { ++ my ($self, $assignment) = @_; ++ ++ my $WSA = $self->{ptf}->getSection ('WIZARD_SCRIPT_ARGUMENTS', ''); ++ if (! $WSA) { ++ # return undef if the WSA section doesn't exist. ++ return; ++ } ++ ++ my $result = $WSA->getAssignment ($assignment); ++ ++ return $result; ++ ++} ++ ++sub getWSAConstant { ++ my ($self, $name) = @_; ++ ++ my $WSA = $self->{ptf}->getSection ('WIZARD_SCRIPT_ARGUMENTS', ''); ++ if (! $WSA) { ++ # return undef if the WSA section doesn't exist. ++ return; ++ } ++ ++ my $constants = $WSA->getSection ('CONSTANTS', ''); ++ if (! $constants) { ++ # return undef if the CONSTANTS section doesn't exist. ++ return; ++ } ++ ++ my $constant = $constants->getSection ('CONSTANT', $name); ++ if (! $constant) { ++ # return undef if the CONSTANT $name section doesn't exist. ++ return; ++ } ++ ++ my $result = $constant->getAssignment ('value'); ++ return $result; ++ ++} ++ ++sub isMemoryDevice { ++ my ($self, $port_name) = @_; ++ ++ my $port = $self->getPort ($port_name); ++ if (! $port) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ ++ my $SBI = $port->getSection('SYSTEM_BUILDER_INFO', ''); ++ if (! $SBI) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ ++ my $result = $SBI->getAssignment('Is_Memory_Device'); ++ ++ return $result; ++} ++ ++sub isCustomInstruction { ++ my ($self, $port_name) = @_; ++ ++ my $port = $self->getPort ($port_name); ++ if (! $port) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ ++ my $SBI = $port->getSection('SYSTEM_BUILDER_INFO', ''); ++ if (! $SBI) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ ++ my $result = $SBI->getAssignment('Is_Custom_Instruction'); ++ ++ return $result; ++} ++ ++sub getBaseAddress { ++ my ($self, $port_name) = @_; ++ ++ my $port = $self->getPort ($port_name); ++ if (! $port) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ ++ my $SBI = $port->getSection('SYSTEM_BUILDER_INFO', ''); ++ if (! $SBI) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ ++ my $result = $SBI->getAssignment('Base_Address'); ++ if ($result eq 'N/A') { ++ return; ++ } ++ return $result; ++} ++ ++sub getSize { ++ my ($self, $port_name) = @_; ++ ++ my $port = $self->getPort ($port_name); ++ $port or return; #return undef if the ptf section doesn't exist ++ ++ my $SBI = $port->getSection ('SYSTEM_BUILDER_INFO', ''); ++ my $data_width = $SBI->getAssignment ('Data_Width'); ++ my $addr_width = $SBI->getAssignment ('Address_Width'); ++ ++ if ($data_width == 8) { ++ $size = 1 << $addr_width; ++ } elsif ($data_width == 16) { ++ $size = 1 << ($addr_width + 1); ++ } elsif ($data_width == 32) { ++ $size = 1 << ($addr_width + 2); ++ } elsif ($data_width == 64) { ++ $size = 1 << ($addr_width + 3); ++ } elsif ($data_width == 128) { ++ $size = 1 << ($addr_width + 4); ++ } else { ++ return; ++ } ++ ++ $size_text = sprintf ("%#010x", $size); ++ return $size_text; ++} ++ ++sub getIRQ { ++ my ($self, $port_name) = @_; ++ ++ my $port = $self->getPort ($port_name); ++ if (! $port) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ ++ my $SBI = $port->getSection('SYSTEM_BUILDER_INFO', ''); ++ if (! $SBI) { ++ # return undef if the PTF section doesn't exist ++ return; ++ } ++ ++ my $result = $SBI->getAssignment('Has_IRQ'); ++ if ($result ne "1") { ++ # this device has no associated IRQ ++ return; ++ } ++ ++ my @irq_masters = $SBI->getSections('IRQ_MASTER'); ++ return $irq_masters[0]->getAssignment('IRQ_Number'); ++} ++ ++sub getMasters { ++ my ($self, $type) = @_; ++ my %masters = (); ++ ++ # get list of all slave for device ++ my @slaves = $self->{ptf}->getSections ('SLAVE'); ++ ++ # get list of masters of relevant type for all slaves ++ foreach my $slave (@slaves) { ++ # get SBI for slave ++ my $SBI = $slave->getSection ('SYSTEM_BUILDER_INFO', ''); ++ ++ # get list of all MASTERED_BY and IRQ_MASTER sections ++ my @mastered_bys = $SBI->getSections ('MASTERED_BY'); ++ my @irq_masters = $SBI->getSections ('IRQ_MASTER'); ++ ++ # start adding masters to the list ++ foreach my $master (@mastered_bys, @irq_masters) { ++ my $section_name = $master->name; ++ $section_name =~ /(.*)\/(.*)/; ++ my $master_name = $1; ++ my $master_type = $2; ++ ++ if (! $type) { ++ $masters{$master_name} = (); ++ } else { ++ if ($master_type eq $type) { ++ $masters{$master_name} = (); ++ } ++ } ++ ++ } ++ ++ } ++ ++ return keys (%masters); ++} ++ ++sub isEnabled { ++ my ($self) = @_; ++ ++ $sbi = $self->{ptf}->getSection('SYSTEM_BUILDER_INFO', ''); ++ $sbi or return; ++ ++ my $enabled = $sbi->getAssignment ('Is_Enabled'); ++ if ($enabled eq "1") { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++1; ++ +diff --git a/arch/nios2nommu/scripts/gen_nios2_system.h.pl b/arch/nios2nommu/scripts/gen_nios2_system.h.pl +new file mode 100644 +index 0000000..b7bcff5 +--- /dev/null ++++ b/arch/nios2nommu/scripts/gen_nios2_system.h.pl +@@ -0,0 +1,314 @@ ++# This script generates an appropriate hardware.h file for Nios II Linux based ++# on information within the target hardware's system.ptf file. This script ++# outputs everything to stdout. ++# ++# usage: ++# ++# [SOPC Builder]$ perl gen_hardware.h.pl \ ++# ++# ++ ++use PTF::SystemPTF; ++use strict; ++use integer; ++ ++my $target_cpu; ++my $exec_location; ++my $upload_location; ++ ++if (scalar (@ARGV) != 3) { ++ print STDERR "ERROR: Invalid number of parameters.\n"; ++ print ("#error Invalid number of parameters.\n"); ++ exit; ++} else { ++ $target_cpu = $ARGV[0]; ++ $exec_location = $ARGV[1]; ++ $upload_location = $ARGV[2]; ++} ++ ++# ++# startup the parser. ++# ++my $system = SystemPTF->new; ++if (!$system) { ++ print STDERR "ERROR: Specified file is not a SYSTEM ptf file.\n"; ++ print ("#error Specified file is not a SYSTEM ptf file.\n"); ++ exit; ++} ++ ++# ++# print header for nios2_system.h ++# ++print <getCPU ($target_cpu); ++if (! $cpu) { ++ print STDERR "ERROR: $target_cpu is not a valid CPU in system: " . $system->getName () . ".\n"; ++ print "#error $target_cpu is not a valid CPU in system: " . $system->getName () . ".\n"; ++ exit 1; ++} ++ ++my $exec_module = $system->getModule ($exec_location); ++if (! $exec_module) { ++ print STDERR "ERROR: $exec_location is not a valid module in the system: " . $system->getName() . ".\n"; ++ print "#error $exec_location is not a valid module in system: " . $system->getName () . ".\n"; ++ exit 1; ++} ++ ++my $upload_module = $system->getModule ($upload_location); ++if (! $upload_module) { ++ print STDERR "ERROR: $upload_location is not a valid module in the system: " . $system->getName() . ".\n"; ++ print "#error $upload_location is not a valid module in system: " . $system->getName () . ".\n"; ++ exit 1; ++} ++ ++my %found_classes; ++my @found_classes_order; ++ ++# the SYSPTF environment variable is set by kernel build process. ++if ($ENV{SYSPTF} ne "") { ++ print "/* Input System: " . $ENV{SYSPTF} . ":" . $system->getName () . " */\n"; ++} else { ++ print "/* Input System: " . $system->getName () . " */\n"; ++} ++print "/* Target CPU: " . $target_cpu . " */\n"; ++ ++print "\n"; ++ ++print <getSlaveModules ($target_cpu); ++foreach my $module_name (@module_names) { ++ my $module = $system->getModule ($module_name); ++ my $module_class = $module->getClass (); ++ my @module_ports = $module->getPorts (); ++ my $mask = 0; ++ my $text_printed = 0; ++ my $output = ""; ++ ++ # $output .= "/* $module_name (of type $module_class) */\n"; ++ ++ if (! exists $found_classes{$module_class}) { ++ push @found_classes_order, $module_class; ++ } ++ push @{$found_classes{$module_class}}, $module_name; ++ ++ if (! $module->isMemoryDevice () && ! $module->isCustomInstruction ()) { ++ # turn on high bit for base address ++ $mask = 0x80000000; ++ } ++ ++ if (scalar (@module_ports) == 1) { ++ my $base_address; ++ my $mem_size; ++ my $mem_end; ++ ++ # base address information ++ $base_address = $module->getBaseAddress (); ++ if ($base_address) { ++ $output .= sprintf ("#define na_%-50s %#010x\n", ++ ($module_name, hex ($base_address) | $mask)); ++ $text_printed = 1; ++ } ++ if ($module->isMemoryDevice()) { ++ # output size and end address ++ $mem_size = $module->getSize(); ++ $output .= sprintf ("#define na_%-50s %#010x\n", ++ ($module_name . "_size", hex ($mem_size))); ++ $mem_end = hex ($mem_size) + hex($base_address); ++ $output .= sprintf ("#define na_%-50s %#010x\n", ++ ($module_name . "_end", $mem_end)); ++ ++ $text_printed = 1; ++ } ++ ++ # irq information ++ $result = $module->getIRQ (); ++ if (defined ($result)) { ++ $output .= sprintf ("#define na_%-30s %30s\n", ++ ($module_name . "_irq", $result)); ++ $text_printed = 1; ++ } ++ ++ } else { ++ # if device has multiple ports ++ foreach my $port_name (@module_ports) { ++ # base address information ++ $result = $module->getBaseAddress ($port_name); ++ if ($result) { ++ $output .= sprintf ("#define na_%-50s %#010x\n", ++ ($module_name . "_" . $port_name, hex ($result) | $mask)); ++ $text_printed = 1; ++ } ++ ++ # irq information ++ $result = $module->getIRQ ($port_name); ++ if (defined ($result)) { ++ $output .= sprintf ("#define na_%-30s %30s\n", ++ ($module_name . "_" . $port_name . "_irq", $result)); ++ $text_printed = 1; ++ } ++ } ++ } ++ ++ if ($text_printed == 1) { ++ # $output .= "\n"; ++ print $output; ++ } ++} ++ ++print "\n"; ++ ++# ++# Handle special cases through customized perl scripts ++# ++foreach my $class_name (@found_classes_order) { ++ my $code = ""; ++ ++ foreach my $dir (@INC) { ++ if (-e "$dir/nios2_system.h/$class_name.pm") { ++ print "/* Executing ...scripts/nios2_system.h/$class_name.pm */\n"; ++ $code .= "require \"$dir/nios2_system.h/BasicModule.pm\";"; ++ $code .= "require \"$dir/nios2_system.h/$class_name.pm\";"; ++ $code .= $class_name . "::run(\$system, \@{\$found_classes{\$class_name}});"; ++ eval $code; ++ if ($@) { ++ print "#warning Could not execute ...scripts/nios2_system.h/$class_name.pm\n"; ++ print "#warning Error message is stored in nios2_system.h:\n"; ++ print "/*\n"; ++ print "$@"; ++ print "*/\n"; ++ print STDERR "Could not execute ...scripts/nios2_system.h/$class_name.pm\n"; ++ print STDERR "Error message follows:\n"; ++ print STDERR "$@"; ++ } ++ last; ++ } ++ } ++} ++ ++# ++# Write out system information ++# ++print "/*\n"; ++print " * Basic System Information\n"; ++print " */\n"; ++ ++$result = $cpu->getWSAAssignment ('cache_icache_size'); ++printf ("#define %-53s %10d\n", ("nasys_icache_size", $result)); ++ ++$result = $cpu->getConstant ('nasys_icache_line_size'); ++printf ("#define %-53s %10d\n", ("nasys_icache_line_size", $result)); ++ ++$result = $cpu->getWSAAssignment ('cache_dcache_size'); ++printf ("#define %-53s %10d\n", ("nasys_dcache_size", $result)); ++ ++$result = $cpu->getConstant ('nasys_dcache_line_size'); ++printf ("#define %-53s %10d\n", ("nasys_dcache_line_size", $result)); ++ ++print "\n"; ++ ++printf ("#define %-33s %30s\n", ++ ("nasys_program_mem", "na_${exec_location}")); ++printf ("#define %-33s %30s\n", ++ ("nasys_program_mem_size", "na_${exec_location}_size")); ++printf ("#define %-33s %30s\n", ++ ("nasys_program_mem_end", "na_${exec_location}_end")); ++ ++print "\n"; ++ ++if ($upload_location eq "flash_kernel") { ++ # nothing to do ++ print ("/* Redefinition of CFI flash memory unecessary */\n"); ++} else { ++ my $module = $system->getModule ("flash_kernel"); ++ if ($module) { ++ # there is a conflicting module in the system, error. ++ print STDERR "Error, a SOPC module named flash_kernel already exists but is not the upload location.\n"; ++ print "#error The module name \"flash_kernel\" already exists but isn't the upload location.\n"; ++ print "#error This will break the kernel.\n"; ++ print "#error Please rename the module to something else in SOPC Builder.\n\n"; ++ exit 1; ++ } else { ++ print ("/*\n"); ++ print (" * Redefining upload location ($upload_location) to flash_kernel.\n"); ++ print (" */\n\n"); ++ # undefine the original module names and re-define them here. ++ print ("#undef na_${upload_location}\n"); ++ print ("#undef na_${upload_location}_size\n"); ++ print ("#undef na_${upload_location}_end\n"); ++ ++ my $base_address = $upload_module->getBaseAddress (); ++ printf ("#define %-33s %30s\n", ++ ("na_flash_kernel", $base_address)); ++ ++ my $mem_size = $upload_module->getSize(); ++ printf ("#define %-33s %30s\n", ++ ("na_flash_kernel_size", $mem_size)); ++ ++ my $mem_end = hex ($base_address) + hex ($mem_size); ++ printf ("#define %-53s %#010x\n", ++ ("na_flash_kernel_end", $mem_end)); ++ } ++} ++ ++print "\n"; ++ ++printf ("#define %-33s %30s\n", ++ ("nasys_clock_freq", $system->getClockFreq())); ++printf ("#define %-33s %30s\n", ++ ("nasys_clock_freq_1000", int ($system->getClockFreq()) / 1000)); ++ ++{ ++ my ($reset_location, $reset_offset) = $cpu->getResetLocationOffset(); ++ my ($reset_module_name, $reset_port_name) = ($reset_location =~ /(.*)\/(.*)/); ++ my $reset_module = $system->getModule ($reset_module_name); ++ my $reset_address = $reset_module->getBaseAddress ($reset_port_name); ++ ++ $reset_address = hex ($reset_address) + hex ($reset_offset); ++ printf ("#define %-53s %#010x\n", ++ ("CPU_RESET_ADDRESS", $reset_address)); ++} ++ ++print "\n"; ++ ++# ++# print footer for nios2_system.h ++# ++print < ++# ++ ++use PTF::SystemPTF; ++use strict; ++use integer; ++ ++my $ptf_filename; ++my $target_filename; ++my $index; ++my $system; ++ ++# ++# Subroutine: Prompt user for an answer ++# ++ ++sub request_answer { ++ my ($min, $max) = @_; ++ my $answer; ++ ++ do { ++ print "Selection: "; ++ $answer = ; ++ if (! ($answer >= $min && $answer <= $max)) { ++ print "Invalid response, please try again.\n"; ++ } ++ } until $answer >= $min && $answer <= $max; ++ ++ return $answer; ++} ++ ++# ++# Check for correct number of args ++# ++ ++if (scalar (@ARGV) != 2) { ++ print STDERR "ERROR: Invalid number of parameters.\n"; ++ exit; ++} else { ++ $ptf_filename = $ARGV[0]; ++ $target_filename = $ARGV[1]; ++} ++ ++# ++# Check to see if the specified file exists ++# ++ ++if (! -e $ptf_filename) { ++ print STDERR "ERROR: Could not open SYSTEM ptf file.\n"; ++ exit; ++} ++ ++# ++# startup the parser. ++# ++$system = SystemPTF->new (filename => $ptf_filename); ++if (!$system) { ++ print STDERR "ERROR: Specified file is not a SYSTEM ptf file.\n"; ++ exit; ++} ++ ++# ++# Grab listing of Nios II processors and force user to select one: ++# ++ ++print "\n--- Please select which CPU you wish to build the kernel against:\n\n"; ++ ++my @cpulist = $system->getCPUList ('altera_nios2'); ++my %cpuinfo; ++ ++$index = 1; ++foreach my $cpu (@cpulist) { ++ my $cpu_module = $system->getCPU ($cpu); ++ if ($cpu_module->isEnabled ()) { ++ my $class = $cpu_module->getClass(); ++ my $type = $cpu_module->getWSAAssignment('cpu_selection'); ++ my $version = $cpu_module->getVersion(); ++ ++ print "($index) $cpu - Class: $class Type: $type Version: $version\n"; ++ } ++ $index += 1; ++} ++ ++print "\n"; ++ ++my $cpu_selection = $cpulist[request_answer (1, $index - 1) - 1]; ++ ++# ++# Grab list of memory devices that $cpu_selection is hooked up to: ++# ++my @modulelist = $system->getSlaveModules ($cpu_selection); ++my %cfiinfo; ++my %meminfo; ++foreach my $module_name (@modulelist) { ++ my $module = $system->getModule ($module_name); ++ my $class = $module->getClass (); ++ ++ if ($module->isEnabled ()) { ++ if ($class eq 'altera_avalon_cfi_flash') { ++ $cfiinfo{$module_name}{class} = $class; ++ $cfiinfo{$module_name}{size} = $module->getSize(); ++ } ++ ++ if ($module->isMemoryDevice()) { ++ $meminfo{$module_name}{class} = $class; ++ $meminfo{$module_name}{size} = $module->getSize(); ++ } ++ } ++} ++ ++# ++# Select an upload device: ++# ++print "\n--- Please select a device to upload the kernel to:\n\n"; ++ ++$index = 1; ++foreach my $name (keys (%cfiinfo)) { ++ my $size = hex ($cfiinfo{$name}{size}); ++ print "($index) $name\n\tClass: $cfiinfo{$name}{class}\n\tSize: $size bytes\n\n"; ++ $index += 1; ++} ++ ++my @cfilist = keys (%cfiinfo); ++my $cfi_selected = $cfilist[request_answer (1, $index - 1) - 1]; ++ ++delete $meminfo{$cfi_selected}; ++ ++# ++# Select program memory to execute kernel from: ++# ++print "\n--- Please select a device to execute kernel from:\n\n"; ++ ++$index = 1; ++foreach my $name (keys (%meminfo)) { ++ my $size = hex ($meminfo{$name}{size}); ++ print "($index) $name\n\tClass: $meminfo{$name}{class}\n\tSize: $size bytes\n\n"; ++ $index += 1; ++} ++ ++my @memlist = keys (%meminfo); ++my $mem_selected = $memlist[request_answer (1, $index - 1) - 1]; ++ ++print "\n--- Summary using\n\n"; ++print "PTF: $ptf_filename\n"; ++print "CPU: $cpu_selection\n"; ++print "Device to upload to: $cfi_selected\n"; ++print "Program memory to execute from: $mem_selected\n"; ++ ++# ++# Write settings out to Makefile fragment ++# ++open (HWMK, ">$target_filename") || ++ die "Could not write to $target_filename"; ++ ++print HWMK "SYSPTF = $ptf_filename\n"; ++print HWMK "CPU = $cpu_selection\n"; ++print HWMK "UPLMEM = $cfi_selected\n"; ++print HWMK "EXEMEM = $mem_selected\n"; ++ ++close (HWMK); ++ ++print "\n--- Settings written to $target_filename\n\n"; +\ No newline at end of file +diff --git a/arch/nios2nommu/scripts/nios2_system.h/BasicModule.pm b/arch/nios2nommu/scripts/nios2_system.h/BasicModule.pm +new file mode 100644 +index 0000000..e15c26b +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/BasicModule.pm +@@ -0,0 +1,267 @@ ++package BasicModule; ++ ++require PTF::SystemPTF; ++require PTF::SystemPTF::Module; ++use strict; ++ ++# Description: Prints an error message to stdout. This should prefix each line ++# with "#error " so that it can be properly read by the C ++# pre-processor. ++# Args: $module_name: name of module that was is required by driver ++# $class_name: name of device class that module belongs to. ++sub print_error_name_used { ++ my ($class, $module_name, $class_name) = @_; ++ ++ print "#error The kernel requires that the $class->required_class_name device be named as $module_name.\n"; ++ print "#error The current hardware has $module_name defined as a(n) $class_name device.\n"; ++ print "#error This will cause the kernel to fail.\n"; ++ print "#error Please rename the current $module_name device to something else in SOPC Builder.\n"; ++} ++ ++# Description: This casts the base address to a specific data type ++# By default, it does not cast the base address to ++# anything. ++sub base_address_cast { ++ my ($class, $port_name) = @_; ++ return; ++} ++ ++# Description: This sub-routine prints out a prefix that is shown only once ++# before any translations take place. ++sub print_prefix { ++ my ($class, $system) = @_; ++ printf ("\n"); ++} ++ ++# Description: Prints a set of lines to stdout that re-defines all symbols ++# related to $module_name to the symbols required by the driver. ++# Typically starts off with "#undefine ..." statements followed ++# by one or more "#define statements". ++# Args: $required_module_name: the module name that's expected by the kernel. ++# $module_name: the name of the module that was found in the PTF file. ++sub translate { ++ my ($class, $system, $required_module_name, $module_name) = @_; ++ ++ # get the necessary info about the module ++ my $module = $system->getModule ($module_name); ++ my @port_names = $module->getPorts (); ++ ++ my $boolean_base_address_cast = 0; ++ if (scalar (@port_names) > 1) { ++ foreach my $port_name (@port_names) { ++ my $cast = $class->base_address_cast ($port_name); ++ if (defined ($cast)) { ++ $boolean_base_address_cast = 1; ++ last; ++ } ++ } ++ } else { ++ my $cast = $class->base_address_cast; ++ if (defined ($cast)) { ++ $boolean_base_address_cast = 1; ++ } ++ } ++ ++ if ($module_name eq $required_module_name && ++ !$boolean_base_address_cast) { ++ printf ("/* No translation necessary for $module_name */\n\n"); ++ return; ++ } ++ ++ # undefine the original entries ++ print "/* Redefining $module_name -> $required_module_name */\n"; ++ if (scalar (@port_names) == 1) { ++ my $irq = $module->getIRQ (); ++ print "#undef na_" . $module_name . "\n"; ++ if (defined ($irq)) { ++ print "#undef na_" . $module_name . "_irq\n"; ++ } ++ print "\n"; ++ } else { ++ foreach my $port_name (@port_names) { ++ print "#undef na_" . $module_name . "_" . ++ $port_name . "\n"; ++ my $irq = $module->getIRQ ($port_name); ++ if (defined ($irq)) { ++ print "#undef na_" . $module_name . "_" . ++ $port_name . "_irq\n"; ++ } ++ print "\n"; ++ } ++ } ++ ++ if (scalar (@port_names) == 1) { ++ # set up a string to pass to printf that will output the correct ++ # #define base address statement. ++ ++ # turn on the high bit for the base address to bypass cache. ++ my $base_address = $module->getBaseAddress (); ++ $base_address = hex ($base_address) | 0x80000000; ++ ++ my $cast = $class->base_address_cast; ++ $class->print_define_line ($required_module_name, ++ undef, "addr", $cast, $base_address); ++ ++ # print out an IRQ define statement if necessary ++ my $irq = $module->getIRQ (); ++ if (defined ($irq)) { ++ $class->print_define_line ($required_module_name, ++ undef, "irq", undef, $irq); ++ } ++ printf ("\n"); ++ } else { ++ foreach my $port_name (@port_names) { ++ my $cast = $class->base_address_cast ($port_name); ++ my $base_address = $module->getBaseAddress ($port_name); ++ $base_address = hex ($base_address) | 0x80000000; ++ $class->print_define_line ($required_module_name, ++ $port_name, "addr", $cast, $base_address); ++ ++ my $irq = $module->getIRQ ($port_name); ++ if (defined ($irq)) { ++ $class->print_define_line ( ++ $required_module_name, $port_name, ++ "irq", undef, $irq); ++ } ++ ++ print "\n"; ++ } ++ } ++} ++ ++# Description: The following sub-routine prints out "undef" or "define" ++# statements based on the arguments received. ++# Args: $name: "define" or "undef" ++# $port: name of port (if applicable) ++# $type: "addr" or "irq" ++# $cast: data type to cast base address to (if applicable) ++# $value: value of symbol to be defined (if applicable) ++sub print_define_line { ++ my ($class, $name, $port, $type, $cast, $value) = @_; ++ ++ # construct the symbol that is being used ++ my $symbol .= "na_"; ++ $symbol .= $name; ++ ++ $symbol .= defined ($port) ? "_" . $port : ""; ++ $symbol .= $type eq "irq" ? "_irq" : ""; ++ ++ my $string_value; ++ if ($type eq "addr") { ++ $string_value = sprintf ("%#010x", $value); ++ if (defined $cast) { ++ $string_value = "(($cast*) $string_value)"; ++ } ++ } else { ++ $string_value = $value; ++ } ++ printf ("%-41s %30s\n", "#define $symbol", $string_value); ++} ++ ++# Description: This sub-routine prints out a prefix that is shown only once ++# after any translations take place. ++sub print_suffix { ++ my ($class, $system) = @_; ++ # intentionally left empty ++} ++ ++# Description: The following function allows the class to further determine if ++# the module is valid. For instance, the timer class requires ++# that the selected module does not have a fixed period. ++# This function returns true by default which basically means ++# that all modules belonging to class are valid. ++sub is_module_valid { ++ my ($class, $system, $module_name) = @_; ++ return 1; ++} ++ ++# Description: This sub-routine is required. It is executed by the ++# "../gen_nios2_system_h.pl" script whenever any devices of type ++# $class->required_class_name are found in the PTF file. ++# ++# It looks for any conflicting module names first. If any are ++# found, "print_error_name_used" is called and this perl module ++# exits. ++# ++# It then goes through the list of module names found in the PTF ++# file that are of type $class->required_class_name and maps them to the ++# list of unused names in $class->required_module_names. ++# ++# Finally, it will call the "translate" sub-routine to output the ++# symbols required by the driver. ++# Args: $system: a variable containing a reference to the system.ptf file that ++# provides full access to any information in the file. ++# @found_module_names: a list of module names that are of type ++# $class->required_class_name ++sub run2 { ++ my ($class, $system, @found_module_names) = @_; ++ ++ # initialize a mapping of required module names to actual module names ++ my %module_map; ++ foreach my $module_name ($class->required_module_names) { ++ $module_map{$module_name} = ""; ++ } ++ ++ # if the required module name is already in use in the PTF file for a ++ # different device class, flag it as an error. ++ my $error_found = 0; ++ foreach my $module_name ($class->required_module_names) { ++ my $module = $system->getModule ($module_name); ++ ++ if (!defined ($module)) { ++ next; ++ } ++ ++ my $class_name = $module->getClass (); ++ if ($class_name ne $class->required_class_name) { ++ $class->print_error_name_used ($class, $module_name, $class_name); ++ $error_found = 1; ++ } ++ } ++ ++ # if errors were found, then there's no point in continuing. ++ if ($error_found == 1) { ++ return; ++ } ++ ++ # Run through list of modules that belong to the class and start ++ # mapping each module name to the first unused required module name ++ # as defined above ++ FOUND_MOD_LOOP: foreach my $module_name (@found_module_names) { ++ ++ # If the module name has already been used, then continue ++ # to the next one. ++ foreach my $required_module_name ($class->required_module_names) { ++ if ($module_map{$required_module_name} eq $module_name) { ++ next FOUND_MOD_LOOP; ++ } ++ } ++ ++ # assertion: $module_name is not mapped yet. ++ foreach my $required_module_name ($class->required_module_names) { ++ if ($module_map{$required_module_name} ne "") { ++ next; ++ } ++ ++ if ($class->is_module_valid ($system, $module_name)) { ++ $module_map{$required_module_name} = $module_name; ++ } ++ last; ++ } ++ } ++ ++ $class->print_prefix ($system); ++ ++ # Now that everything's been mapped (or as close as we're going to get ++ # to it being mapped), start printing out the literal translation. ++ foreach my $required_module_name ($class->required_module_names) { ++ my $module_name = $module_map{$required_module_name}; ++ if (length ($module_name) > 0) { ++ $class->translate ($system, $required_module_name, $module_name); ++ } ++ } ++ ++ $class->print_suffix ($system); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_cf.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_cf.pm +new file mode 100644 +index 0000000..dada452 +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_cf.pm +@@ -0,0 +1,18 @@ ++package altera_avalon_cf; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ "ide" ++} ++ ++sub required_class_name { ++ "altera_avalon_cf" ++} ++ ++sub run { ++ altera_avalon_cf->run2(@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_jtag_uart.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_jtag_uart.pm +new file mode 100644 +index 0000000..22bb9c9 +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_jtag_uart.pm +@@ -0,0 +1,18 @@ ++package altera_avalon_jtag_uart; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ ("jtag_uart") ++} ++ ++sub required_class_name { ++ "altera_avalon_jtag_uart"; ++} ++ ++sub run { ++ altera_avalon_jtag_uart->run2 (@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_lan91c111.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_lan91c111.pm +new file mode 100644 +index 0000000..5a29b7e +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_lan91c111.pm +@@ -0,0 +1,38 @@ ++package altera_avalon_lan91c111; ++ ++require PTF::SystemPTF; ++require PTF::SystemPTF::Module; ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ "enet" ++} ++ ++sub required_class_name { ++ "altera_avalon_lan91c111" ++} ++ ++sub translate { ++ my $class = shift; ++ my ($system, $required_module_name, $module_name) = @_; ++ $class->SUPER::translate (@_); ++ ++ my $module = $system->getModule ($module_name); ++ ++ my $offset_keyword = "LAN91C111_REGISTERS_OFFSET"; ++ my $offset = $module->getWSAConstant ($offset_keyword); ++ printf ("%-41s %30s\n", "#define $offset_keyword", $offset); ++ ++ my $width_keyword = "LAN91C111_DATA_BUS_WIDTH"; ++ my $width = $module->getWSAConstant ($width_keyword); ++ printf ("%-41s %30s\n", "#define $width_keyword", $width); ++ ++ print "\n"; ++} ++ ++sub run { ++ altera_avalon_lan91c111->run2 (@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_pio.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_pio.pm +new file mode 100644 +index 0000000..afdbcae +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_pio.pm +@@ -0,0 +1,46 @@ ++package altera_avalon_pio; ++ ++require PTF::SystemPTF; ++require PTF::SystemPTF::Module; ++use strict; ++ ++sub run { ++ my ($system, @pio_names) = @_; ++ ++ print "#ifndef __ASSEMBLY__\n"; ++ print "#include \n"; ++ print "#endif\n\n"; ++ ++ foreach my $pio_name (@pio_names) { ++ my $module = $system->getModule ($pio_name); ++ ++ # get all the relevant information ++ my $base_address = $module->getBaseAddress (); ++ $base_address = hex ($base_address) | 0x80000000; ++ my $irq = $module->getIRQ (); ++ ++ print "/* Casting base addresses to the appropriate structure */\n"; ++ ++ # undefine all the old symbols first ++ print "#undef na_${pio_name}\n"; ++ if (defined ($irq)) { ++ print "#undef na_${pio_name}_irq\n"; ++ print "\n"; ++ } ++ ++ # define base address ++ $base_address = sprintf ("%#010x", $base_address); ++ printf ("%-41s %30s\n", "#define na_${pio_name}", ++ "((np_pio*) ${base_address})"); ++ ++ # define irq ++ if (defined ($irq)) { ++ printf ("%-41s %30s\n", "#define na_${pio_name}_irq", ++ $irq); ++ } ++ ++ print "\n"; ++ } ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_spi.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_spi.pm +new file mode 100644 +index 0000000..719a22c +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_spi.pm +@@ -0,0 +1,30 @@ ++package altera_avalon_spi; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ "spi" ++} ++ ++sub required_class_name { ++ "altera_avalon_spi" ++} ++ ++sub base_address_cast { ++ "np_spi" ++} ++ ++sub print_prefix { ++ my ($class, $system) = @_; ++ ++ print "#ifndef __ASSEMBLY__\n"; ++ print "#include \n"; ++ print "#endif\n\n"; ++} ++ ++sub run { ++ altera_avalon_spi->run2 (@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_sysid.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_sysid.pm +new file mode 100644 +index 0000000..deb9826 +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_sysid.pm +@@ -0,0 +1,18 @@ ++package altera_avalon_sysid; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_class_name { ++ "altera_avalon_sysid" ++} ++ ++sub required_module_names { ++ "sysid" ++} ++ ++sub run { ++ altera_avalon_sysid->run2 (@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_timer.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_timer.pm +new file mode 100644 +index 0000000..495ccdc +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_timer.pm +@@ -0,0 +1,46 @@ ++package altera_avalon_timer; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_class_name { ++ "altera_avalon_timer"; ++} ++ ++sub required_module_names { ++ "timer0" ++} ++ ++sub print_prefix { ++ my ($class, $system) = @_; ++ ++ print "\n"; ++ print "#ifndef __ASSEMBLY__\n"; ++ print "#include \n"; ++ print "#endif\n"; ++ print "\n"; ++} ++ ++sub base_address_cast { ++ "np_timer" ++} ++ ++# only timers with a non-fixed-period are valid ++sub is_module_valid { ++ my ($class, $system, $module_name) = @_; ++ ++ my $module = $system->getModule ($module_name); ++ my $fixed_period = $module->getWSAAssignment ('fixed_period'); ++ ++ if ($fixed_period eq '0') { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++sub run { ++ altera_avalon_timer->run2 (@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_uart.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_uart.pm +new file mode 100644 +index 0000000..abf48d7 +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_uart.pm +@@ -0,0 +1,44 @@ ++package altera_avalon_uart; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ ("uart0", "uart1", "uart2", "uart3") ++} ++ ++sub required_class_name { ++ "altera_avalon_uart"; ++} ++ ++sub base_address_cast { ++ "np_uart" ++} ++ ++sub print_prefix { ++ my ($class, $system) = @_; ++ ++ print "#ifndef __ASSEMBLY__\n"; ++ print "#include \n"; ++ print "#endif\n\n"; ++} ++ ++sub translate { ++ my $class = shift; ++ my ($system, $required_module_name, $module_name) = @_; ++ ++ $class->SUPER::translate (@_); ++ ++ if (!defined ($altera_avalon_uart::default_uart)) { ++ print "/* The default uart is always the first one found in the PTF file */\n"; ++ print "#define nasys_printf_uart na_$required_module_name\n\n"; ++ $altera_avalon_uart::default_uart = $required_module_name; ++ } ++ ++} ++ ++sub run { ++ altera_avalon_uart->run2 (@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/mtip_avalon_10_100_mac.pm b/arch/nios2nommu/scripts/nios2_system.h/mtip_avalon_10_100_mac.pm +new file mode 100644 +index 0000000..fdd727b +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/mtip_avalon_10_100_mac.pm +@@ -0,0 +1,18 @@ ++package mtip_avalon_10_100_mac; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_class_name { ++ "mtip_avalon_10_100_mac"; ++} ++ ++sub required_module_names { ++ "mtip_mac" ++} ++ ++sub run { ++ mtip_avalon_10_100_mac->run2 (@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_dm9000.pm b/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_dm9000.pm +new file mode 100644 +index 0000000..5985c2f +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_dm9000.pm +@@ -0,0 +1,18 @@ ++package mtx_avalon_dm9000; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ "dm9000" ++} ++ ++sub required_class_name { ++ "mtx_avalon_dm9000" ++} ++ ++sub run { ++ mtx_avalon_dm9000->run2(@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_isp1161a1.pm b/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_isp1161a1.pm +new file mode 100644 +index 0000000..e70ffa3 +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_isp1161a1.pm +@@ -0,0 +1,18 @@ ++package mtx_avalon_isp1161a1; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ "usb" ++} ++ ++sub required_class_name { ++ "mtx_avalon_isp1161a1"; ++} ++ ++sub run { ++ mtx_avalon_isp1161a1->run2(@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/opencores_ethernet_mac.pm b/arch/nios2nommu/scripts/nios2_system.h/opencores_ethernet_mac.pm +new file mode 100644 +index 0000000..7b580b5 +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/opencores_ethernet_mac.pm +@@ -0,0 +1,18 @@ ++package opencores_ethernet_mac; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ "igor_mac" ++} ++ ++sub required_class_name { ++ "opencores_ethernet_mac" ++} ++ ++sub run { ++ opencores_ethernet_mac->run2 (@_); ++} ++ ++1; +diff --git a/arch/nios2nommu/scripts/nios2_system.h/opencores_i2c.pm b/arch/nios2nommu/scripts/nios2_system.h/opencores_i2c.pm +new file mode 100644 +index 0000000..512d12c +--- /dev/null ++++ b/arch/nios2nommu/scripts/nios2_system.h/opencores_i2c.pm +@@ -0,0 +1,18 @@ ++package opencores_i2c; ++ ++use base qw(BasicModule); ++use strict; ++ ++sub required_module_names { ++ ("i2c_0", "i2c_1") ++} ++ ++sub required_class_name { ++ "opencores_i2c"; ++} ++ ++sub run { ++ opencores_i2c->run2 (@_); ++} ++ ++1; +diff --git a/include/asm-nios2nommu/ChangeLog b/include/asm-nios2nommu/ChangeLog +new file mode 100644 +index 0000000..94aaa27 +--- /dev/null ++++ b/include/asm-nios2nommu/ChangeLog +@@ -0,0 +1,14 @@ ++2004-06-29 Ken Hill ++ ++ * bitops.h (find_next_zero_bit): Fix problem with with masking for found_first ++ handling. The masking of the upper bits for size < 32 bits would set all ++ the bits to 1. Removing any zero's there may have been. ++ ++2004-06-02 Ken Hill ++ ++ * processor.h (TASK_SIZE): Change na_sdram_end to nasys_program_mem_end to remove ++ dependancy on quartus memory component name. ++ ++ * page.h (PAGE_OFFSET): Change na_sdram to nasys_program_mem to remove ++ dependancy on quartus memory component name. ++ +diff --git a/include/asm-nios2nommu/Kbuild b/include/asm-nios2nommu/Kbuild +new file mode 100644 +index 0000000..abf0368 +--- /dev/null ++++ b/include/asm-nios2nommu/Kbuild +@@ -0,0 +1,4 @@ ++include include/asm-generic/Kbuild.asm ++ ++header-y += traps.h ++header-y += io.h +diff --git a/include/asm-nios2nommu/a.out.h b/include/asm-nios2nommu/a.out.h +new file mode 100644 +index 0000000..8297687 +--- /dev/null ++++ b/include/asm-nios2nommu/a.out.h +@@ -0,0 +1,85 @@ ++/* $Id: a.out.h,v 1.1 2006/07/05 06:20:25 gerg Exp $ */ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2NOMMU_A_OUT_H__ ++#define __NIOS2NOMMU_A_OUT_H__ ++ ++#define SPARC_PGSIZE 0x1000 /* Thanks to the sun4 architecture... */ ++#define SEGMENT_SIZE SPARC_PGSIZE /* whee... */ ++ ++struct exec { ++ unsigned char a_dynamic:1; /* A __DYNAMIC is in this image */ ++ unsigned char a_toolversion:7; ++ unsigned char a_machtype; ++ unsigned short a_info; ++ unsigned long a_text; /* length of text, in bytes */ ++ unsigned long a_data; /* length of data, in bytes */ ++ unsigned long a_bss; /* length of bss, in bytes */ ++ unsigned long a_syms; /* length of symbol table, in bytes */ ++ unsigned long a_entry; /* where program begins */ ++ unsigned long a_trsize; ++ unsigned long a_drsize; ++}; ++ ++#define INIT_EXEC { \ ++ .a_dynamic = 0, \ ++ .a_toolversion = 0, \ ++ .a_machtype = 0, \ ++ .a_info = 0, \ ++ .a_text = 0, \ ++ .a_data = 0, \ ++ .a_bss = 0, \ ++ .a_syms = 0, \ ++ .a_entry = 0, \ ++ .a_trsize = 0, \ ++ .a_drsize = 0, \ ++} ++ ++/* Where in the file does the text information begin? */ ++#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? 0 : sizeof (struct exec)) ++ ++/* Where do the Symbols start? */ ++#define N_SYMOFF(x) (N_TXTOFF(x) + (x).a_text + \ ++ (x).a_data + (x).a_trsize + \ ++ (x).a_drsize) ++ ++/* Where does text segment go in memory after being loaded? */ ++#define N_TXTADDR(x) (((N_MAGIC(x) == ZMAGIC) && \ ++ ((x).a_entry < SPARC_PGSIZE)) ? \ ++ 0 : SPARC_PGSIZE) ++ ++/* And same for the data segment.. */ ++#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC ? \ ++ (N_TXTADDR(x) + (x).a_text) \ ++ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) ++ ++#define N_TRSIZE(a) ((a).a_trsize) ++#define N_DRSIZE(a) ((a).a_drsize) ++#define N_SYMSIZE(a) ((a).a_syms) ++ ++#ifdef __KERNEL__ ++ ++#define STACK_TOP TASK_SIZE ++ ++#endif ++ ++#endif /* __NIOS2NOMMU_A_OUT_H__ */ +diff --git a/include/asm-nios2nommu/altera_juart.h b/include/asm-nios2nommu/altera_juart.h +new file mode 100644 +index 0000000..da6320d +--- /dev/null ++++ b/include/asm-nios2nommu/altera_juart.h +@@ -0,0 +1,36 @@ ++/*------------------------------------------------------------------------ ++ * ++ * linux/drivers/serial/altera_juart.h ++ * ++ * Driver for Altera JTAG UART core with Avalon interface ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * History: ++ * Jun/20/2005 DGT Microtronix Datacom NiosII ++ * ++ -----------------------------------------------------------------------*/ ++ ++#ifndef _ALTERA_JUART_H_ ++ #define _ALTERA_JUART_H_ ++ ++ /* jtag uart details needed outside of the driver itself: */ ++ /* by: arch/kernel/start.c - boot time error message(s) */ ++ ++ void jtaguart_console_write ++ ( struct console *co, ++ const char *s, ++ unsigned int count); ++ ++#endif /* _ALTERA_JUART_H_ */ +diff --git a/include/asm-nios2nommu/asm-macros.h b/include/asm-nios2nommu/asm-macros.h +new file mode 100644 +index 0000000..9dda7cd +--- /dev/null ++++ b/include/asm-nios2nommu/asm-macros.h +@@ -0,0 +1,331 @@ ++/* ++ * Macro used to simplify coding multi-line assembler. ++ * Some of the bit test macro can simplify down to one line ++ * depending on the mask value. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++/* ++ * ANDs reg2 with mask and places the result in reg1. ++ * ++ * You cannnot use the same register for reg1 & reg2. ++ */ ++ ++.macro ANDI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ movhi \reg1,%hi(\mask) ++ movui \reg1,%lo(\mask) ++ and \reg1,\reg1,\reg2 ++ .else ++ andi \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ andhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * ORs reg2 with mask and places the result in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro ORI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ orhi \reg1,\reg2,%hi(\mask) ++ ori \reg1,\reg2,%lo(\mask) ++ .else ++ ori \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ orhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * XORs reg2 with mask and places the result in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro XORI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ xorhi \reg1,\reg2,%hi(\mask) ++ xori \reg1,\reg1,%lo(\mask) ++ .else ++ xori \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ xorhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * This is a support macro for BTBZ & BTBNZ. It checks ++ * the bit to make sure it is valid 32 value. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BT reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and branches to label if the ++ * bit is zero. The result of the bit test is stored in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTBZ reg1,reg2,bit,label ++ BT \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and branches to label if the ++ * bit is non-zero. The result of the bit test is stored in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTBNZ reg1,reg2,bit,label ++ BT \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTC reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ xori \reg2,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ xorhi \reg2,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTS reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ ori \reg2,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ orhi \reg2,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTR reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ andi \reg2,\reg2,%lo(~(1 << \bit)) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ andhi \reg2,\reg2,%lo(~(1 << (\bit - 16))) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTCBZ reg1,reg2,bit,label ++ BTC \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTCBNZ reg1,reg2,bit,label ++ BTC \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTSBZ reg1,reg2,bit,label ++ BTS \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTSBNZ reg1,reg2,bit,label ++ BTS \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTRBZ reg1,reg2,bit,label ++ BTR \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTRBNZ reg1,reg2,bit,label ++ BTR \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bits in mask against reg2 stores the result in reg1. ++ * If the all the bits in the mask are zero it branches to label. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro TSTBZ reg1,reg2,mask,label ++ ANDI32 \reg1,\reg2,\mask ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bits in mask against reg2 stores the result in reg1. ++ * If the any of the bits in the mask are 1 it branches to label. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro TSTBNZ reg1,reg2,mask,label ++ ANDI32 \reg1,\reg2,\mask ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Pushes reg onto the stack. ++ */ ++ ++.macro PUSH reg ++ addi sp,sp,-4 ++ stw \reg,0(sp) ++.endm ++ ++/* ++ * Pops the top of the stack into reg. ++ */ ++ ++.macro POP reg ++ ldw \reg,0(sp) ++ addi sp,sp,4 ++.endm ++ ++/* ++ * Clears reg ++ */ ++ ++.macro CLR reg ++ mov \reg,r0 ++.endm ++ ++/* ++ * The preprocessor macro does not work for ++ * the nios2 compiler. Undefine ENTRY and define ++ * a real assembler macro. ++ */ ++#undef ENTRY ++#define ENTRY(name) ASM_ENTRY name ++ ++.macro ASM_ENTRY name ++.globl \name ++__ALIGN ++ \name: ++.endm +diff --git a/include/asm-nios2nommu/atomic.h b/include/asm-nios2nommu/atomic.h +new file mode 100644 +index 0000000..fb627de +--- /dev/null ++++ b/include/asm-nios2nommu/atomic.h +@@ -0,0 +1,146 @@ ++#ifndef __ASM_SH_ATOMIC_H ++#define __ASM_SH_ATOMIC_H ++ ++/* ++ * Atomic operations that C can't guarantee us. Useful for ++ * resource counting etc.. ++ * ++ */ ++ ++typedef struct { volatile int counter; } atomic_t; ++ ++#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) ++ ++#define atomic_read(v) ((v)->counter) ++#define atomic_set(v,i) ((v)->counter = (i)) ++ ++#include ++ ++/* ++ * To get proper branch prediction for the main line, we must branch ++ * forward to code at the end of this object's .text section, then ++ * branch back to restart the operation. ++ */ ++ ++static __inline__ void atomic_add(int i, atomic_t * v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ *(long *)v += i; ++ local_irq_restore(flags); ++} ++ ++static __inline__ void atomic_sub(int i, atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ *(long *)v -= i; ++ local_irq_restore(flags); ++} ++ ++static __inline__ int atomic_add_return(int i, atomic_t * v) ++{ ++ unsigned long temp, flags; ++ ++ local_irq_save(flags); ++ temp = *(long *)v; ++ temp += i; ++ *(long *)v = temp; ++ local_irq_restore(flags); ++ ++ return temp; ++} ++ ++#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) ++ ++static __inline__ int atomic_sub_return(int i, atomic_t * v) ++{ ++ unsigned long temp, flags; ++ ++ local_irq_save(flags); ++ temp = *(long *)v; ++ temp -= i; ++ *(long *)v = temp; ++ local_irq_restore(flags); ++ ++ return temp; ++} ++ ++#define atomic_dec_return(v) atomic_sub_return(1,(v)) ++#define atomic_inc_return(v) atomic_add_return(1,(v)) ++ ++/* ++ * atomic_inc_and_test - increment and test ++ * @v: pointer of type atomic_t ++ * ++ * Atomically increments @v by 1 ++ * and returns true if the result is zero, or false for all ++ * other cases. ++ */ ++#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) ++ ++#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) ++#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) ++ ++#define atomic_inc(v) atomic_add(1,(v)) ++#define atomic_dec(v) atomic_sub(1,(v)) ++ ++static inline int atomic_cmpxchg(atomic_t *v, int old, int new) ++{ ++ int ret; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ret = v->counter; ++ if (likely(ret == old)) ++ v->counter = new; ++ local_irq_restore(flags); ++ ++ return ret; ++} ++ ++#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) ++ ++static inline int atomic_add_unless(atomic_t *v, int a, int u) ++{ ++ int ret; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ret = v->counter; ++ if (ret != u) ++ v->counter += a; ++ local_irq_restore(flags); ++ ++ return ret != u; ++} ++#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) ++ ++static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ *(long *)v &= ~mask; ++ local_irq_restore(flags); ++} ++ ++static __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ *(long *)v |= mask; ++ local_irq_restore(flags); ++} ++ ++/* Atomic operations are already serializing on SH */ ++#define smp_mb__before_atomic_dec() barrier() ++#define smp_mb__after_atomic_dec() barrier() ++#define smp_mb__before_atomic_inc() barrier() ++#define smp_mb__after_atomic_inc() barrier() ++ ++#include ++#endif /* __ASM_SH_ATOMIC_H */ +diff --git a/include/asm-nios2nommu/auxvec.h b/include/asm-nios2nommu/auxvec.h +new file mode 100644 +index 0000000..fc21e4d +--- /dev/null ++++ b/include/asm-nios2nommu/auxvec.h +@@ -0,0 +1,4 @@ ++#ifndef __ASM_SH_AUXVEC_H ++#define __ASM_SH_AUXVEC_H ++ ++#endif /* __ASM_SH_AUXVEC_H */ +diff --git a/include/asm-nios2nommu/bitops.h b/include/asm-nios2nommu/bitops.h +new file mode 100644 +index 0000000..7bf1862 +--- /dev/null ++++ b/include/asm-nios2nommu/bitops.h +@@ -0,0 +1,11 @@ ++#ifndef __ASM_NIOS2NOMMU_BITOPS_H ++#define __ASM_NIOS2NOMMU_BITOPS_H ++ ++#ifdef __KERNEL__ ++#include ++#include ++#define smp_mb__before_clear_bit() barrier() ++#define smp_mb__after_clear_bit() barrier() ++#endif /* __KERNEL__ */ ++ ++#endif /* __ASM_NIOS2NOMMU_BITOPS_H */ +diff --git a/include/asm-nios2nommu/bootinfo.h b/include/asm-nios2nommu/bootinfo.h +new file mode 100644 +index 0000000..ee8c39e +--- /dev/null ++++ b/include/asm-nios2nommu/bootinfo.h +@@ -0,0 +1,2 @@ ++ ++/* Nothing for nios2nommu */ +diff --git a/include/asm-nios2nommu/bug.h b/include/asm-nios2nommu/bug.h +new file mode 100644 +index 0000000..d99ab08 +--- /dev/null ++++ b/include/asm-nios2nommu/bug.h +@@ -0,0 +1,4 @@ ++#ifndef _MNIOS2NOMMU_BUG_H ++#define _MNIOS2NOMMU_BUG_H ++#include ++#endif +diff --git a/include/asm-nios2nommu/bugs.h b/include/asm-nios2nommu/bugs.h +new file mode 100644 +index 0000000..a0753eb +--- /dev/null ++++ b/include/asm-nios2nommu/bugs.h +@@ -0,0 +1,40 @@ ++#ifndef __ASM_NIOS_BUGS_H ++#define __ASM_NIOS_BUGS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/bugs.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 1994 Linus Torvalds ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This is included by init/main.c to check for architecture-dependent bugs. ++ * ++ * Needs: ++ * void check_bugs(void); ++ */ ++ ++static void check_bugs(void) ++{ ++} ++ ++#endif +diff --git a/include/asm-nios2nommu/byteorder.h b/include/asm-nios2nommu/byteorder.h +new file mode 100644 +index 0000000..960b6d3 +--- /dev/null ++++ b/include/asm-nios2nommu/byteorder.h +@@ -0,0 +1,38 @@ ++#ifndef __ASM_NIOS_BYTEORDER_H ++#define __ASM_NIOS_BYTEORDER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/byteorder.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) ++# define __BYTEORDER_HAS_U64__ ++# define __SWAB_64_THRU_32__ ++#endif ++ ++#include ++ ++#endif ++ +diff --git a/include/asm-nios2nommu/cache.h b/include/asm-nios2nommu/cache.h +new file mode 100644 +index 0000000..82bbd14 +--- /dev/null ++++ b/include/asm-nios2nommu/cache.h +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __ARCH_NIOS2NOMMU_CACHE_H ++#define __ARCH_NIOS2NOMMU_CACHE_H ++ ++#include ++ ++/* bytes per L1 cache line */ ++#define L1_CACHE_BYTES nasys_icache_line_size /* 32, this need to be at least 1 */ ++#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) ++#define L1_CACHE_SHIFT 5 ++ ++ ++#define __cacheline_aligned ++#define ____cacheline_aligned ++ ++#endif +diff --git a/include/asm-nios2nommu/cachectl.h b/include/asm-nios2nommu/cachectl.h +new file mode 100644 +index 0000000..39d7d9d +--- /dev/null ++++ b/include/asm-nios2nommu/cachectl.h +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_CACHECTL_H ++#define _NIOS2NOMMU_CACHECTL_H ++ ++/* Definitions for the cacheflush system call. */ ++ ++#define FLUSH_SCOPE_LINE 1 /* Flush a cache line */ ++#define FLUSH_SCOPE_PAGE 2 /* Flush a page */ ++#define FLUSH_SCOPE_ALL 3 /* Flush the whole cache -- superuser only */ ++ ++#define FLUSH_CACHE_DATA 1 /* Writeback and flush data cache */ ++#define FLUSH_CACHE_INSN 2 /* Flush instruction cache */ ++#define FLUSH_CACHE_BOTH 3 /* Flush both caches */ ++ ++#endif /* _NIOS2NOMMU_CACHECTL_H */ +diff --git a/include/asm-nios2nommu/cacheflush.h b/include/asm-nios2nommu/cacheflush.h +new file mode 100644 +index 0000000..4543201 +--- /dev/null ++++ b/include/asm-nios2nommu/cacheflush.h +@@ -0,0 +1,59 @@ ++#ifndef _NIOS2NOMMU_CACHEFLUSH_H ++#define _NIOS2NOMMU_CACHEFLUSH_H ++ ++/* ++ * Ported from m68knommu. ++ * ++ * (C) Copyright 2003, Microtronix Datacom Ltd. ++ * (C) Copyright 2000-2002, Greg Ungerer ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#include ++ ++extern void cache_push (unsigned long vaddr, int len); ++extern void dcache_push (unsigned long vaddr, int len); ++extern void icache_push (unsigned long vaddr, int len); ++extern void cache_push_all (void); ++extern void cache_clear (unsigned long paddr, int len); ++ ++#define flush_cache_all() __flush_cache_all() ++#define flush_cache_mm(mm) do { } while (0) ++#define flush_cache_range(vma, start, end) cache_push(start, end - start) ++#define flush_cache_page(vma, vmaddr) do { } while (0) ++#define flush_dcache_range(start,end) dcache_push(start, end - start) ++#define flush_dcache_page(page) do { } while (0) ++#define flush_dcache_mmap_lock(mapping) do { } while (0) ++#define flush_dcache_mmap_unlock(mapping) do { } while (0) ++#define flush_icache_range(start,end) cache_push(start, end - start) ++#define flush_icache_page(vma,pg) do { } while (0) ++#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) ++ ++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ ++ memcpy(dst, src, len) ++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ ++ memcpy(dst, src, len) ++ ++ ++extern inline void __flush_cache_all(void) ++{ ++ cache_push_all(); ++} ++ ++#endif /* _NIOS2NOMMU_CACHEFLUSH_H */ +diff --git a/include/asm-nios2nommu/checksum.h b/include/asm-nios2nommu/checksum.h +new file mode 100644 +index 0000000..1f6879e +--- /dev/null ++++ b/include/asm-nios2nommu/checksum.h +@@ -0,0 +1,320 @@ ++#ifndef __NIOS2_CHECKSUM_H ++#define __NIOS2_CHECKSUM_H ++ ++/* checksum.h: IP/UDP/TCP checksum routines on the NIOS. ++ * ++ * Copyright(C) 1995 Linus Torvalds ++ * Copyright(C) 1995 Miguel de Icaza ++ * Copyright(C) 1996 David S. Miller ++ * Copyright(C) 2001 Ken Hill ++ * Copyright(C) 2004 Microtronix Datacom Ltd. ++ * ++ * derived from: ++ * Alpha checksum c-code ++ * ix86 inline assembly ++ * Spar nommu ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++/* ++ * computes the checksum of the TCP/UDP pseudo-header ++ * returns a 16-bit checksum, already complemented ++ */ ++ ++extern inline unsigned short csum_tcpudp_magic(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++" add %0, %3, %0\n" ++" bgeu %0, %3, 1f\n" ++" addi %0, %0, 1\n" ++"1: add %0, %4, %0\n" ++" bgeu %0, %4, 1f\n" ++" addi %0, %0, 1\n" ++"1: add %0, %5, %0\n" ++" bgeu %0, %5, 1f\n" ++" addi %0, %0, 1\n" ++"1:\n" ++/* ++ We need the carry from the addition of 16-bit ++ significant addition, so we zap out the low bits ++ in one half, zap out the high bits in another, ++ shift them both up to the top 16-bits of a word ++ and do the carry producing addition, finally ++ shift the result back down to the low 16-bits. ++ ++ Actually, we can further optimize away two shifts ++ because we know the low bits of the original ++ value will be added to zero-only bits so cannot ++ affect the addition result nor the final carry ++ bit. ++*/ ++" slli %1,%0, 16\n" /* Need a copy to fold with */ ++ /* Bring the LOW 16 bits up */ ++" add %0, %1, %0\n" /* add and set carry, neat eh? */ ++" cmpltu r15, %0, %1\n" /* get remaining carry bit */ ++" srli %0, %0, 16\n" /* shift back down the result */ ++" add %0, %0, r15\n" ++" nor %0, %0, %0\n" /* negate */ ++ : "=&r" (sum), "=&r" (saddr) ++ : "0" (sum), "1" (saddr), "r" (ntohl(len+proto)), "r" (daddr) ++ : "r15"); ++ return ((unsigned short) sum); ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++ extern inline unsigned short from32to16(unsigned long x) ++ { ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r15, %0, %1\n" ++ "srli %0, %0, 16\n" ++ "add %0, %0, r15\n" ++ : "=r" (x) ++ : "r" (x << 16), "0" (x) ++ : "r15"); ++ return x; ++ barrier(); ++ } ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++extern inline unsigned long do_csum(const unsigned char * buff, int len) ++{ ++ int odd, count; ++ unsigned long result = 0; ++ ++ barrier(); ++ if (len <= 0) ++ goto out; ++ odd = 1 & (unsigned long) buff; ++ if (odd) { ++////result = *buff; // dgt: Big endian ++ result = *buff << 8; // dgt: Little endian ++ ++ len--; ++ buff++; ++ } ++ count = len >> 1; /* nr of 16-bit words.. */ ++ if (count) { ++ if (2 & (unsigned long) buff) { ++ result += *(unsigned short *) buff; ++ count--; ++ len -= 2; ++ buff += 2; ++ } ++ count >>= 1; /* nr of 32-bit words.. */ ++ if (count) { ++ unsigned long carry = 0; ++ do { ++ unsigned long w = *(unsigned long *) buff; ++ count--; ++ buff += 4; ++ result += carry; ++ result += w; ++ carry = (w > result); ++ } while (count); ++ result += carry; ++ result = (result & 0xffff) + (result >> 16); ++ } ++ if (len & 2) { ++ result += *(unsigned short *) buff; ++ buff += 2; ++ } ++ } ++ if (len & 1) ++ result += *buff; /* This is little machine, byte is right */ ++ result = from32to16(result); ++ if (odd) ++ result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); ++out: ++ return result; ++ barrier(); ++ } ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++/* ihl is always 5 or greater, almost always is 5, iph is always word ++ * aligned but can fail to be dword aligned very often. ++ */ ++ ++ extern inline unsigned short ip_fast_csum(const unsigned char *iph, unsigned int ihl) ++ { ++ unsigned int sum; ++ ++ barrier(); ++ __asm__ __volatile__( ++" andi r8, %1, 2\n" /* Remember original alignment */ ++" ldw %0, (%1)\n" /* 16 or 32 bit boundary */ ++" beq r8, r0, 1f\n" /* Aligned on 32 bit boundary, go */ ++" srli %0, %0, 16\n" /* Get correct 16 bits */ ++" addi %2, %2, -1\n" /* Take off for 4 bytes, pickup last 2 at end */ ++" addi %1, %1, 2\n" /* Adjust pointer to 32 bit boundary */ ++" br 2f\n" ++"1:\n" ++" addi %2, %2, -1\n" ++" addi %1, %1, 4\n" /* Bump ptr a long word */ ++"2:\n" ++" ldw r9, (%1)\n" ++"1:\n" ++" add %0, r9, %0\n" ++" bgeu %0, r9, 2f\n" ++" addi %0, %0, 1\n" ++"2:\n" ++" addi %1, %1, 4\n" ++" addi %2, %2, -1\n" ++" ldw r9, (%1)\n" ++" bne %2, r0, 1b\n" ++" beq r8, r0, 1f\n" /* 32 bit boundary time to leave */ ++" srli r9, r9, 16\n" /* 16 bit boundary, get correct 16 bits */ ++" add %0, r9, %0\n" ++" bgeu %0, r9, 1f\n" ++" addi %0, %0, 1\n" ++"1:\n" ++" slli %2, %0, 16\n" ++" add %0, %2, %0\n" ++" cmpltu r8, %0, %2\n" ++" srli %0, %0, 16\n" ++" add %0, %0, r8\n" ++" nor %0, %0, %0\n" ++ : "=&r" (sum), "=&r" (iph), "=&r" (ihl) ++ : "1" (iph), "2" (ihl) ++ : "r8", "r9"); ++ return sum; ++ barrier(); ++ } ++ ++/*these 2 functions are now in checksum.c */ ++unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); ++unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++/* ++ * the same as csum_partial_copy, but copies from user space. ++ * ++ * here even more important to align src and dst on a 32-bit (or even ++ * better 64-bit) boundary ++ */ ++extern inline unsigned int ++csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *csum_err) ++{ ++ barrier(); ++ if (csum_err) *csum_err = 0; ++ memcpy(dst, src, len); ++ return csum_partial(dst, len, sum); ++ barrier(); ++} ++ ++#define csum_partial_copy_nocheck(src, dst, len, sum) \ ++ csum_partial_copy ((src), (dst), (len), (sum)) ++ ++ ++/* ++ * this routine is used for miscellaneous IP-like checksums, mainly ++ * in icmp.c ++ */ ++ ++extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) ++{ ++ barrier(); ++ return ~from32to16(do_csum(buff,len)); ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++#define csum_partial_copy_fromuser(s, d, l, w) \ ++ csum_partial_copy((char *) (s), (d), (l), (w)) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++/* ++ * Fold a partial checksum without adding pseudo headers ++ */ ++extern __inline__ unsigned int csum_fold(unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r8, %0, %1\n" ++ "srli %0, %0, 16\n" ++ "add %0, %0, r8\n" ++ "nor %0, %0, %0\n" ++ : "=r" (sum) ++ : "r" (sum << 16), "0" (sum) ++ : "r8"); ++ return sum; ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r8, %0, %1\n" ++ "add %0, %0, r8\n" /* add carry */ ++ "add %0, %2, %0\n" ++ "cmpltu r8, %0, %2\n" ++ "add %0, %0, r8\n" /* add carry */ ++ "add %0, %3, %0\n" ++ "cmpltu r8, %0, %3\n" ++ "add %0, %0, r8\n" /* add carry */ ++ : "=r" (sum), "=r" (saddr) ++ : "r" (daddr), "r" ( (ntohs(len)<<16) + (proto*256) ), ++ "0" (sum), ++ "1" (saddr) ++ : "r8"); ++ ++ return sum; ++ barrier(); ++} ++ ++ ++#endif /* (__NIOS2_CHECKSUM_H) */ +diff --git a/include/asm-nios2nommu/cprefix.h b/include/asm-nios2nommu/cprefix.h +new file mode 100644 +index 0000000..4983211 +--- /dev/null ++++ b/include/asm-nios2nommu/cprefix.h +@@ -0,0 +1,38 @@ ++/* cprefix.h: This file is included by assembly source which needs ++ * to know what the c-label prefixes are. The newer versions ++ * of cpp that come with gcc predefine such things to help ++ * us out. The reason this stuff is needed is to make ++ * solaris compiles of the kernel work. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2_CPREFIX_H ++#define __NIOS2_CPREFIX_H ++ ++#define C_LABEL_PREFIX ++ ++#define CONCAT(a, b) CONCAT2(a, b) ++#define CONCAT2(a, b) a##b ++ ++#define C_LABEL(name) CONCAT(C_LABEL_PREFIX, name) ++ ++#endif /* !(__NIOS2_CPREFIX_H) */ +diff --git a/include/asm-nios2nommu/cpumask.h b/include/asm-nios2nommu/cpumask.h +new file mode 100644 +index 0000000..86fb365 +--- /dev/null ++++ b/include/asm-nios2nommu/cpumask.h +@@ -0,0 +1,28 @@ ++/* ++ * All rights reserved. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2NOMMU_CPUMASK_H ++#define _ASM_NIOS2NOMMU_CPUMASK_H ++ ++#include ++ ++#endif /* _ASM_NIOS2NOMMU_CPUMASK_H */ +diff --git a/include/asm-nios2nommu/cputime.h b/include/asm-nios2nommu/cputime.h +new file mode 100644 +index 0000000..370e4f2 +--- /dev/null ++++ b/include/asm-nios2nommu/cputime.h +@@ -0,0 +1,31 @@ ++/* ++ * cputime.h ++ * (C) Copyright 2004, Microtronix Datacom Ltd. ++ * ++ * Taken from m68knommu ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_CPUTIME_H ++#define __NIOS2NOMMU_CPUTIME_H ++ ++#include ++ ++#endif /* __NIOS@NOMMU_CPUTIME_H */ +diff --git a/include/asm-nios2nommu/current.h b/include/asm-nios2nommu/current.h +new file mode 100644 +index 0000000..5ac1dbc +--- /dev/null ++++ b/include/asm-nios2nommu/current.h +@@ -0,0 +1,39 @@ ++#ifndef _NIOS2NOMMU_CURRENT_H ++#define _NIOS2NOMMU_CURRENT_H ++/* ++ * current.h ++ * (C) Copyright 2000, Lineo, David McCullough ++ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) ++ * (C) Copyright 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++ ++struct task_struct; ++ ++static inline struct task_struct *get_current(void) ++{ ++ return(current_thread_info()->task); ++} ++ ++#define current get_current() ++ ++#endif /* _NIOS2NOMMU_CURRENT_H */ +diff --git a/include/asm-nios2nommu/delay.h b/include/asm-nios2nommu/delay.h +new file mode 100644 +index 0000000..da0a184 +--- /dev/null ++++ b/include/asm-nios2nommu/delay.h +@@ -0,0 +1,96 @@ ++#ifndef _NIOS_DELAY_H ++#define _NIOS_DELAY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/delay.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++extern __inline__ void __delay(unsigned long loops) ++{ ++ int dummy; ++ ++ __asm__ __volatile__( ++ "1: \n\t" ++ " beq %0,zero,2f\n\t" ++ " addi %0, %0, -1\n\t" ++ " br 1b\n\t" ++ "2: \n\t" ++ ++ : "=r" (dummy) /* Need output for optimizer */ ++ ++ : "0" (loops) /* %0 Input */ ++ ); ++} ++ ++/* ++ * Note that 19 * 226 == 4294 ==~ 2^32 / 10^6, so ++ * loops = (4294 * usecs * loops_per_jiffy * HZ) / 2^32. ++ * ++ * The mul instruction gives us loops = (a * b) / 2^32. ++ * We choose a = usecs * 19 * HZ and b = loops_per_jiffy * 226 ++ * because this lets us support a wide range of HZ and ++ * loops_per_jiffy values without either a or b overflowing 2^32. ++ * Thus we need usecs * HZ <= (2^32 - 1) / 19 = 226050910 and ++ * loops_per_jiffy <= (2^32 - 1) / 226 = 19004280 ++ * (which corresponds to ~3800 bogomips at HZ = 100). ++ * -- paulus ++ */ ++#define __MAX_UDELAY (226050910UL/HZ) /* maximum udelay argument */ ++#define __MAX_NDELAY (4294967295UL/HZ) /* maximum ndelay argument */ ++ ++extern unsigned long loops_per_jiffy; ++ ++extern __inline__ void __udelay(unsigned int x) ++{ ++ unsigned int loops; ++ ++ __asm__("mulxuu %0,%1,%2" : "=r" (loops) : ++ "r" (x), "r" (loops_per_jiffy * 226)); ++ __delay(loops); ++} ++ ++extern __inline__ void __ndelay(unsigned int x) ++{ ++ unsigned int loops; ++ ++ __asm__("mulxuu %0,%1,%2" : "=r" (loops) : ++ "r" (x), "r" (loops_per_jiffy * 5)); ++ __delay(loops); ++} ++ ++extern void __bad_udelay(void); /* deliberately undefined */ ++extern void __bad_ndelay(void); /* deliberately undefined */ ++ ++#define udelay(n) (__builtin_constant_p(n)? \ ++ ((n) > __MAX_UDELAY? __bad_udelay(): __udelay((n) * (19 * HZ))) : \ ++ __udelay((n) * (19 * HZ))) ++ ++#define ndelay(n) (__builtin_constant_p(n)? \ ++ ((n) > __MAX_NDELAY? __bad_ndelay(): __ndelay((n) * HZ)) : \ ++ __ndelay((n) * HZ)) ++ ++#define muldiv(a, b, c) (((a)*(b))/(c)) ++ ++#endif /* defined(_NIOS_DELAY_H) */ +diff --git a/include/asm-nios2nommu/device.h b/include/asm-nios2nommu/device.h +new file mode 100644 +index 0000000..d8f9872 +--- /dev/null ++++ b/include/asm-nios2nommu/device.h +@@ -0,0 +1,7 @@ ++/* ++ * Arch specific extensions to struct device ++ * ++ * This file is released under the GPLv2 ++ */ ++#include ++ +diff --git a/include/asm-nios2nommu/div64.h b/include/asm-nios2nommu/div64.h +new file mode 100644 +index 0000000..68d72e4 +--- /dev/null ++++ b/include/asm-nios2nommu/div64.h +@@ -0,0 +1,31 @@ ++#ifndef __ASMNIOS_DIV64_H ++#define __ASMNIOS_DIV64_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/div64.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif ++ +diff --git a/include/asm-nios2nommu/dma-mapping.h b/include/asm-nios2nommu/dma-mapping.h +new file mode 100644 +index 0000000..6289370 +--- /dev/null ++++ b/include/asm-nios2nommu/dma-mapping.h +@@ -0,0 +1,79 @@ ++#ifndef _ASM_DMA_MAPPING_H ++#define _ASM_DMA_MAPPING_H ++ ++#include ++#include ++ ++void *dma_alloc_noncoherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t flag); ++ ++void dma_free_noncoherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle); ++ ++void *dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t flag); ++ ++void dma_free_coherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle); ++ ++extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction direction); ++extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, ++ size_t size, enum dma_data_direction direction); ++extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction); ++extern dma_addr_t dma_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, enum dma_data_direction direction); ++extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address, ++ size_t size, enum dma_data_direction direction); ++extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg, ++ int nhwentries, enum dma_data_direction direction); ++extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, ++ size_t size, enum dma_data_direction direction); ++extern void dma_sync_single_for_device(struct device *dev, ++ dma_addr_t dma_handle, size_t size, enum dma_data_direction direction); ++extern void dma_sync_single_range_for_cpu(struct device *dev, ++ dma_addr_t dma_handle, unsigned long offset, size_t size, ++ enum dma_data_direction direction); ++extern void dma_sync_single_range_for_device(struct device *dev, ++ dma_addr_t dma_handle, unsigned long offset, size_t size, ++ enum dma_data_direction direction); ++extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, ++ int nelems, enum dma_data_direction direction); ++extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, ++ int nelems, enum dma_data_direction direction); ++extern int dma_mapping_error(dma_addr_t dma_addr); ++extern int dma_supported(struct device *dev, u64 mask); ++ ++static inline int ++dma_set_mask(struct device *dev, u64 mask) ++{ ++ if(!dev->dma_mask || !dma_supported(dev, mask)) ++ return -EIO; ++ ++ *dev->dma_mask = mask; ++ ++ return 0; ++} ++ ++static inline int ++dma_get_cache_alignment(void) ++{ ++ /* XXX Largest on any MIPS */ ++ return 128; ++} ++ ++extern int dma_is_consistent(dma_addr_t dma_addr); ++ ++extern void dma_cache_sync(void *vaddr, size_t size, ++ enum dma_data_direction direction); ++ ++// #define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY ++// ++// extern int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, ++// dma_addr_t device_addr, size_t size, int flags); ++// extern void dma_release_declared_memory(struct device *dev); ++// extern void * dma_mark_declared_memory_occupied(struct device *dev, ++// dma_addr_t device_addr, size_t size); ++ ++#endif /* _ASM_DMA_MAPPING_H */ +diff --git a/include/asm-nios2nommu/dma.h b/include/asm-nios2nommu/dma.h +new file mode 100644 +index 0000000..ea098d5 +--- /dev/null ++++ b/include/asm-nios2nommu/dma.h +@@ -0,0 +1,63 @@ ++/* $Id: dma.h,v 1.1 2006/07/05 06:20:25 gerg Exp $ ++ * ++ * Copyright 2004 (C) Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2_DMA_H ++#define _ASM_NIOS2_DMA_H ++ ++#include ++#include ++ ++#define MAX_DMA_ADDRESS (LINUX_SDRAM_END) ++ ++int request_dma(unsigned int, const char *); ++void free_dma(unsigned int); ++void enable_dma(unsigned int dmanr); ++void disable_dma(unsigned int dmanr); ++void set_dma_count(unsigned int dmanr, unsigned int count); ++int get_dma_residue(unsigned int dmanr); ++void nios2_set_dma_data_width(unsigned int dmanr, unsigned int width); ++ ++void nios2_set_dma_handler(unsigned int dmanr, int (*handler)(void*, int), void* user); ++int nios2_request_dma(const char *); ++ ++void nios2_set_dma_mode(unsigned int dmanr, unsigned int mode); ++void nios2_set_dma_rcon(unsigned int dmanr, unsigned int set); ++void nios2_set_dma_wcon(unsigned int dmanr, unsigned int set); ++void nios2_set_dma_raddr(unsigned int dmanr, unsigned int a); ++void nios2_set_dma_waddr(unsigned int dmanr, unsigned int a); ++ ++static inline unsigned long claim_dma_lock(void) ++{ ++} ++ ++static inline void release_dma_lock(unsigned long flags) ++{ ++} ++ ++#ifdef CONFIG_PCI ++extern int isa_dma_bridge_buggy; ++#else ++#define isa_dma_bridge_buggy (0) ++#endif ++ ++#endif /* !(_ASM_NIOS2_DMA_H) */ +diff --git a/include/asm-nios2nommu/elf.h b/include/asm-nios2nommu/elf.h +new file mode 100644 +index 0000000..94b2ac0 +--- /dev/null ++++ b/include/asm-nios2nommu/elf.h +@@ -0,0 +1,140 @@ ++#ifndef __NIOS2_ELF_H ++#define __NIOS2_ELF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/elf.h ++ * ++ * Nio2 ELF relocation types ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * Mar/18/2004 xwt NiosII relocation types added ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++#include ++ ++#define R_NIOS2_NONE 0 ++#define R_NIOS2_S16 1 ++#define R_NIOS2_U16 2 ++#define R_NIOS2_PCREL16 3 ++#define R_NIOS2_CALL26 4 ++#define R_NIOS2_IMM5 5 ++#define R_NIOS2_CACHE_OPX 6 ++#define R_NIOS2_IMM6 7 ++#define R_NIOS2_IMM8 8 ++#define R_NIOS2_HI16 9 ++#define R_NIOS2_LO16 10 ++#define R_NIOS2_HIADJ16 11 ++#define R_NIOS2_BFD_RELOC_32 12 ++#define R_NIOS2_BFD_RELOC_16 13 ++#define R_NIOS2_BFD_RELOC_8 14 ++#define R_NIOS2_GPREL 15 ++#define R_NIOS2_GNU_VTINHERIT 16 ++#define R_NIOS2_GNU_VTENTRY 17 ++#define R_NIOS2_UJMP 18 ++#define R_NIOS2_CJMP 19 ++#define R_NIOS2_CALLR 20 ++#define R_NIOS2_ALIGN 21 ++/* Keep this the last entry. */ ++#define R_NIOS2_NUM 22 ++ ++typedef unsigned long elf_greg_t; ++ ++#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) ++typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ++ ++typedef unsigned long elf_fpregset_t; ++ ++/* ++ * This is used to ensure we don't load something for the wrong architecture. ++ */ ++#define elf_check_arch(x) \ ++ ((x)->e_machine == EM_ALTERA_NIOS2) ++ ++/* ++ * These are used to set parameters in the core dumps. ++ */ ++#define ELF_CLASS ELFCLASS32 ++#define ELF_DATA ELFDATA2LSB ++#define ELF_ARCH EM_ALTERA_NIOS2 ++ ++#define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 ++ ++#define USE_ELF_CORE_DUMP ++#define ELF_EXEC_PAGESIZE 4096 ++ ++/* This is the location that an ET_DYN program is loaded if exec'ed. Typical ++ use of this is to invoke "./ld.so someprog" to test out a new version of ++ the loader. We need to make sure that it is out of the way of the program ++ that it will "exec", and that there is sufficient room for the brk. */ ++ ++#define ELF_ET_DYN_BASE 0xD0000000UL ++ ++/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is ++ now struct_user_regs, they are different) */ ++ ++#define ELF_CORE_COPY_REGS(pr_reg, regs) \ ++ /* Bleech. */ \ ++ pr_reg[0] = regs->r1; \ ++ pr_reg[1] = regs->r2; \ ++ pr_reg[2] = regs->r3; \ ++ pr_reg[3] = regs->r4; \ ++ pr_reg[4] = regs->r5; \ ++ pr_reg[5] = regs->r6; \ ++ pr_reg[6] = regs->r7; \ ++ pr_reg[7] = regs->r8; \ ++ pr_reg[8] = regs->r9; \ ++ pr_reg[9] = regs->r10; \ ++ pr_reg[10] = regs->r11; \ ++ pr_reg[11] = regs->r12; \ ++ pr_reg[12] = regs->r13; \ ++ pr_reg[13] = regs->r14; \ ++ pr_reg[14] = regs->r15; \ ++ pr_reg[23] = regs->sp; \ ++ pr_reg[26] = regs->estatus; \ ++ { \ ++ struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ ++ pr_reg[15] = sw->r16; \ ++ pr_reg[16] = sw->r17; \ ++ pr_reg[17] = sw->r18; \ ++ pr_reg[18] = sw->r19; \ ++ pr_reg[19] = sw->r20; \ ++ pr_reg[20] = sw->r21; \ ++ pr_reg[21] = sw->r22; \ ++ pr_reg[22] = sw->r23; \ ++ pr_reg[24] = sw->fp; \ ++ pr_reg[25] = sw->gp; \ ++ } ++ ++/* This yields a mask that user programs can use to figure out what ++ instruction set this cpu supports. */ ++ ++#define ELF_HWCAP (0) ++ ++/* This yields a string that ld.so will use to load implementation ++ specific libraries for optimization. This is more specific in ++ intent than poking at uname or /proc/cpuinfo. */ ++ ++#define ELF_PLATFORM (NULL) ++ ++#ifdef __KERNEL__ ++#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) ++#endif ++ ++#endif +diff --git a/include/asm-nios2nommu/emergency-restart.h b/include/asm-nios2nommu/emergency-restart.h +new file mode 100644 +index 0000000..108d8c4 +--- /dev/null ++++ b/include/asm-nios2nommu/emergency-restart.h +@@ -0,0 +1,6 @@ ++#ifndef _ASM_EMERGENCY_RESTART_H ++#define _ASM_EMERGENCY_RESTART_H ++ ++#include ++ ++#endif /* _ASM_EMERGENCY_RESTART_H */ +diff --git a/include/asm-nios2nommu/entry.h b/include/asm-nios2nommu/entry.h +new file mode 100644 +index 0000000..4b1773f +--- /dev/null ++++ b/include/asm-nios2nommu/entry.h +@@ -0,0 +1,187 @@ ++/* ++ * Hacked from m68knommu port. ++ * ++ * Copyright(C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_ENTRY_H ++#define __NIOS2NOMMU_ENTRY_H ++ ++#ifdef __ASSEMBLY__ ++ ++#include ++#include ++#include ++ ++/* ++ * Stack layout in 'ret_from_exception': ++ * ++ * This allows access to the syscall arguments in registers r4-r8 ++ * ++ * 0(sp) - r8 ++ * 4(sp) - r9 ++ * 8(sp) - r10 ++ * C(sp) - r11 ++ * 10(sp) - r12 ++ * 14(sp) - r13 ++ * 18(sp) - r14 ++ * 1C(sp) - r15 ++ * 20(sp) - r1 ++ * 24(sp) - r2 ++ * 28(sp) - r3 ++ * 2C(sp) - r4 ++ * 30(sp) - r5 ++ * 34(sp) - r6 ++ * 38(sp) - r7 ++ * 3C(sp) - orig_r2 ++ * 40(sp) - ra ++ * 44(sp) - fp ++ * 48(sp) - sp ++ * 4C(sp) - gp ++ * 50(sp) - estatus ++ * 54(sp) - status_extension ++ * 58(sp) - ea ++ * ++ */ ++ ++/* process bits for task_struct.flags */ ++PF_TRACESYS_OFF = 3 ++PF_TRACESYS_BIT = 5 ++PF_PTRACED_OFF = 3 ++PF_PTRACED_BIT = 4 ++PF_DTRACE_OFF = 1 ++PF_DTRACE_BIT = 5 ++ ++LENOSYS = 38 ++ ++/* ++ * This defines the normal kernel pt-regs layout. ++ * ++ */ ++ ++/* ++ * Standard Nios2 interrupt entry and exit macros. ++ * Must be called with interrupts disabled. ++ */ ++.macro SAVE_ALL ++ movia r24,status_extension // Read status extension ++ ldw r24,0(r24) ++ andi r24,r24,PS_S_ASM ++ bne r24,r0,1f // In supervisor mode, already on kernel stack ++ movia r24,_current_thread // Switch to current kernel stack ++ ldw r24,0(r24) // using the thread_info ++ addi r24,r24,THREAD_SIZE_ASM-PT_REGS_SIZE ++ stw sp,PT_SP(r24) // Save user stack before changing ++ mov sp,r24 ++ br 2f ++ ++1: mov r24,sp ++ addi sp,sp,-PT_REGS_SIZE // Backup the kernel stack pointer ++ stw r24,PT_SP(sp) ++2: stw r1,PT_R1(sp) ++ stw r2,PT_R2(sp) ++ stw r3,PT_R3(sp) ++ stw r4,PT_R4(sp) ++ stw r5,PT_R5(sp) ++ stw r6,PT_R6(sp) ++ stw r7,PT_R7(sp) ++ stw r8,PT_R8(sp) ++ stw r9,PT_R9(sp) ++ stw r10,PT_R10(sp) ++ stw r11,PT_R11(sp) ++ stw r12,PT_R12(sp) ++ stw r13,PT_R13(sp) ++ stw r14,PT_R14(sp) ++ stw r15,PT_R15(sp) ++ stw r2,PT_ORIG_R2(sp) ++ stw ra,PT_RA(sp) ++ stw fp,PT_FP(sp) ++ stw gp,PT_GP(sp) ++ rdctl r24,estatus ++ stw r24,PT_ESTATUS(sp) ++ movia r24,status_extension // Read status extension ++ ldw r1,0(r24) ++ stw r1,PT_STATUS_EXTENSION(sp) // Store user/supervisor status ++ ORI32 r1,r1,PS_S_ASM // Set supervisor mode ++ stw r1,0(r24) ++ stw ea,PT_EA(sp) ++.endm ++ ++.macro RESTORE_ALL ++ ldw r1,PT_STATUS_EXTENSION(sp) // Restore user/supervisor status ++ movia r24,status_extension ++ stw r1,0(r24) ++ ldw r1,PT_R1(sp) // Restore registers ++ ldw r2,PT_R2(sp) ++ ldw r3,PT_R3(sp) ++ ldw r4,PT_R4(sp) ++ ldw r5,PT_R5(sp) ++ ldw r6,PT_R6(sp) ++ ldw r7,PT_R7(sp) ++ ldw r8,PT_R8(sp) ++ ldw r9,PT_R9(sp) ++ ldw r10,PT_R10(sp) ++ ldw r11,PT_R11(sp) ++ ldw r12,PT_R12(sp) ++ ldw r13,PT_R13(sp) ++ ldw r14,PT_R14(sp) ++ ldw r15,PT_R15(sp) ++ ldw ra,PT_RA(sp) ++ ldw fp,PT_FP(sp) ++ ldw gp,PT_GP(sp) ++ ldw r24,PT_ESTATUS(sp) ++ wrctl estatus,r24 ++ ldw ea,PT_EA(sp) ++ ldw sp,PT_SP(sp) // Restore sp last ++.endm ++ ++.macro SAVE_SWITCH_STACK ++ addi sp,sp,-SWITCH_STACK_SIZE ++ stw r16,SW_R16(sp) ++ stw r17,SW_R17(sp) ++ stw r18,SW_R18(sp) ++ stw r19,SW_R19(sp) ++ stw r20,SW_R20(sp) ++ stw r21,SW_R21(sp) ++ stw r22,SW_R22(sp) ++ stw r23,SW_R23(sp) ++ stw fp,SW_FP(sp) ++ stw gp,SW_GP(sp) ++ stw ra,SW_RA(sp) ++.endm ++ ++.macro RESTORE_SWITCH_STACK ++ ldw r16,SW_R16(sp) ++ ldw r17,SW_R17(sp) ++ ldw r18,SW_R18(sp) ++ ldw r19,SW_R19(sp) ++ ldw r20,SW_R20(sp) ++ ldw r21,SW_R21(sp) ++ ldw r22,SW_R22(sp) ++ ldw r23,SW_R23(sp) ++ ldw fp,SW_FP(sp) ++ ldw gp,SW_GP(sp) ++ ldw ra,SW_RA(sp) ++ addi sp,sp,SWITCH_STACK_SIZE ++.endm ++ ++#endif /* __ASSEMBLY__ */ ++#endif /* __NIOS2NOMMU_ENTRY_H */ +diff --git a/include/asm-nios2nommu/errno.h b/include/asm-nios2nommu/errno.h +new file mode 100644 +index 0000000..c2caf21 +--- /dev/null ++++ b/include/asm-nios2nommu/errno.h +@@ -0,0 +1,6 @@ ++#ifndef _NIOS2NOMMU_ERRNO_H ++#define _NIOS2NOMMU_ERRNO_H ++ ++#include ++ ++#endif /* _NIOS2NOMMU_ERRNO_H */ +diff --git a/include/asm-nios2nommu/fcntl.h b/include/asm-nios2nommu/fcntl.h +new file mode 100644 +index 0000000..9d98af2 +--- /dev/null ++++ b/include/asm-nios2nommu/fcntl.h +@@ -0,0 +1,11 @@ ++#ifndef _NIOS2_FCNTL_H ++#define _NIOS2_FCNTL_H ++ ++#define O_DIRECTORY 040000 /* must be a directory */ ++#define O_NOFOLLOW 0100000 /* don't follow links */ ++#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ ++#define O_LARGEFILE 0400000 ++ ++#include ++ ++#endif /* _NIOS2_FCNTL_H */ +diff --git a/include/asm-nios2nommu/flat.h b/include/asm-nios2nommu/flat.h +new file mode 100644 +index 0000000..681329a +--- /dev/null ++++ b/include/asm-nios2nommu/flat.h +@@ -0,0 +1,129 @@ ++/* ++ * include/asm-nios2nommu/flat.h -- uClinux bFLT relocations ++ * ++ * Copyright (C) 2004,05 Microtronix Datacom Ltd ++ * ++ * This file is subject to the terms and conditions of the GNU General ++ * Public License. See the file COPYING in the main directory of this ++ * archive for more details. ++ * ++ * Written by Wentao Xu ++ */ ++ ++#ifndef __NIOS2_FLAT_H__ ++#define __NIOS2_FLAT_H__ ++ ++#define flat_reloc_valid(reloc, size) ((reloc) <= (size + 0x8000)) ++ ++/* The stack is 64-bit aligned for Nios II, so (sp - 1) shall ++ * be 64-bit aligned, where -1 is for argc ++ */ ++#define flat_stack_align(sp) (sp = (unsigned long *)(((unsigned long)sp - 1) & (-8))) ++ ++/* The uClibc port for Nios II expects the argc is followed by argv and envp */ ++#define flat_argvp_envp_on_stack() 1 ++ ++#define flat_old_ram_flag(flags) (flags) ++ ++/* We store the type of relocation in the top 4 bits of the `relval.' */ ++ ++/* Convert a relocation entry into an address. */ ++static inline unsigned long ++flat_get_relocate_addr (unsigned long relval) ++{ ++ return relval & 0x0fffffff; /* Mask out top 4-bits */ ++} ++ ++#define FLAT_NIOS2_RELOC_TYPE(relval) ((relval) >> 28) ++ ++#define FLAT_NIOS2_R_32 0 /* Normal 32-bit reloc */ ++#define FLAT_NIOS2_R_HI_LO 1 /* High 16-bits + low 16-bits field */ ++#define FLAT_NIOS2_R_HIADJ_LO 2 /* High 16-bits adjust + low 16-bits field */ ++#define FLAT_NIOS2_R_CALL26 4 /* Call imm26 */ ++ ++#define flat_set_persistent(relval, p) 0 ++ ++/* Extract the address to be relocated from the symbol reference at rp; ++ * relval is the raw relocation-table entry from which RP is derived. ++ * rp shall always be 32-bit aligned ++ */ ++static inline unsigned long flat_get_addr_from_rp (unsigned long *rp, ++ unsigned long relval, ++ unsigned long flags, ++ unsigned long *persistent) ++{ ++ switch (FLAT_NIOS2_RELOC_TYPE(relval)) ++ { ++ case FLAT_NIOS2_R_32: ++ /* Simple 32-bit address. The loader expect it in bigger endian */ ++ return htonl(*rp); ++ ++ case FLAT_NIOS2_R_HI_LO: ++ /* get the two 16-bit immediate value from instructions, then ++ * construct a 32-bit value. Again the loader expect bigger endian ++ */ ++ return htonl ((((rp[0] >> 6) & 0xFFFF) << 16 ) | ++ ((rp[1] >> 6) & 0xFFFF)); ++ ++ case FLAT_NIOS2_R_HIADJ_LO: ++ { ++ /* get the two 16-bit immediate value from instructions, then ++ * construct a 32-bit value. Again the loader expect bigger endian ++ */ ++ unsigned int low, high; ++ high = (rp[0] >> 6) & 0xFFFF; ++ low = (rp[1] >> 6) & 0xFFFF; ++ ++ if ((low >> 15) & 1) high--; ++ ++ return htonl ((high << 16 ) | low ); ++ } ++ case FLAT_NIOS2_R_CALL26: ++ /* the 26-bit immediate value is actually 28-bit */ ++ return htonl(((*rp) >> 6) << 2); ++ ++ default: ++ return ~0; /* bogus value */ ++ } ++} ++ ++/* Insert the address addr into the symbol reference at rp; ++ * relval is the raw relocation-table entry from which rp is derived. ++ * rp shall always be 32-bit aligned ++ */ ++static inline void flat_put_addr_at_rp (unsigned long *rp, unsigned long addr, ++ unsigned long relval) ++{ ++ unsigned long exist_val; ++ switch (FLAT_NIOS2_RELOC_TYPE (relval)) { ++ case FLAT_NIOS2_R_32: ++ /* Simple 32-bit address. */ ++ *rp = addr; ++ break; ++ ++ case FLAT_NIOS2_R_HI_LO: ++ exist_val = rp[0]; ++ rp[0] = ((((exist_val >> 22) << 16) | (addr >> 16)) << 6) | (exist_val & 0x3F); ++ exist_val = rp[1]; ++ rp[1] = ((((exist_val >> 22) << 16) | (addr & 0xFFFF)) << 6) | (exist_val & 0x3F); ++ break; ++ ++ case FLAT_NIOS2_R_HIADJ_LO: ++ { ++ unsigned int high = (addr >> 16); ++ if ((addr >> 15) & 1) ++ high = (high + 1) & 0xFFFF; ++ exist_val = rp[0]; ++ rp[0] = ((((exist_val >> 22) << 16) | high) << 6) | (exist_val & 0x3F); ++ exist_val = rp[1]; ++ rp[1] = ((((exist_val >> 22) << 16) | (addr & 0xFFFF)) << 6) | (exist_val & 0x3F); ++ break; ++ } ++ case FLAT_NIOS2_R_CALL26: ++ /* the opcode of CALL is 0, so just store the value */ ++ *rp = ((addr >> 2) << 6); ++ break; ++ } ++} ++ ++#endif /* __NIOS2_FLAT_H__ */ +diff --git a/include/asm-nios2nommu/futex.h b/include/asm-nios2nommu/futex.h +new file mode 100644 +index 0000000..6a332a9 +--- /dev/null ++++ b/include/asm-nios2nommu/futex.h +@@ -0,0 +1,6 @@ ++#ifndef _ASM_FUTEX_H ++#define _ASM_FUTEX_H ++ ++#include ++ ++#endif +diff --git a/include/asm-nios2nommu/gpio.h b/include/asm-nios2nommu/gpio.h +new file mode 100644 +index 0000000..b91937b +--- /dev/null ++++ b/include/asm-nios2nommu/gpio.h +@@ -0,0 +1,11 @@ ++#ifndef _ASM_GPIO_H_ ++#define _ASM_GPIO_H_ 1 ++ ++ ++struct gpio_i2c_pins { ++ unsigned sda_pin; ++ unsigned scl_pin; ++}; ++ ++#endif /*_ASM_GPIO_*/ ++ +diff --git a/include/asm-nios2nommu/hardirq.h b/include/asm-nios2nommu/hardirq.h +new file mode 100644 +index 0000000..0041f51 +--- /dev/null ++++ b/include/asm-nios2nommu/hardirq.h +@@ -0,0 +1,43 @@ ++/* ++ * Ported from m68knommu ++ * ++ * Copyright (C) 2003, Microtronix Datacom Ltd. ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2_HARDIRQ_H ++#define __NIOS2_HARDIRQ_H ++ ++#include ++#include ++ ++typedef struct { ++ unsigned int __softirq_pending; ++} ____cacheline_aligned irq_cpustat_t; ++ ++#include /* Standard mappings for irq_cpustat_t above */ ++ ++#define HARDIRQ_BITS 8 ++ ++#ifdef CONFIG_SMP ++# error nios2nommu SMP is not available ++#endif /* CONFIG_SMP */ ++ ++#endif /* __NIOS2_HARDIRQ_H */ +diff --git a/include/asm-nios2nommu/hdreg.h b/include/asm-nios2nommu/hdreg.h +new file mode 100644 +index 0000000..b4d910a +--- /dev/null ++++ b/include/asm-nios2nommu/hdreg.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 1994-1996 Linus Torvalds & authors ++ * Copyright (C) 2002 Wentau Xu (www.microtronix.com) ++ * copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_HDREG_H ++#define __NIOS2_HDREG_H ++ ++typedef unsigned long ide_ioreg_t; ++ ++#endif /* __NIOS2_HDREG_H */ +diff --git a/include/asm-nios2nommu/hw_irq.h b/include/asm-nios2nommu/hw_irq.h +new file mode 100644 +index 0000000..d2fd3be +--- /dev/null ++++ b/include/asm-nios2nommu/hw_irq.h +@@ -0,0 +1,16 @@ ++#ifndef _ASM_HW_IRQ_H ++#define _ASM_HW_IRQ_H ++ ++/* ++ * linux/include/asm/hw_irq.h ++ * ++ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar ++ * ++ * moved some of the old arch/i386/kernel/irq.h to here. VY ++ * ++ * IRQ/IPI changes taken from work by Thomas Radke ++ * ++ */ ++ ++ ++#endif /* _ASM_HW_IRQ_H */ +diff --git a/include/asm-nios2nommu/ide.h b/include/asm-nios2nommu/ide.h +new file mode 100644 +index 0000000..f8ef9ad +--- /dev/null ++++ b/include/asm-nios2nommu/ide.h +@@ -0,0 +1,40 @@ ++/* ++ * linux/include/asm-niosnommu2/ide.h ++ * ++ * Copyright (C) 1994-1996 Linus Torvalds & authors ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ASMNIOS2_IDE_H ++#define __ASMNIOS2_IDE_H ++ ++#ifdef __KERNEL__ ++#undef MAX_HWIFS /* we're going to force it */ ++ ++#ifndef MAX_HWIFS ++#define MAX_HWIFS 1 ++#endif ++ ++#include ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* __ASMNIOS2_IDE_H */ +diff --git a/include/asm-nios2nommu/init.h b/include/asm-nios2nommu/init.h +new file mode 100644 +index 0000000..8641f4f +--- /dev/null ++++ b/include/asm-nios2nommu/init.h +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#error " should never be used - use instead" +diff --git a/include/asm-nios2nommu/io.h b/include/asm-nios2nommu/io.h +new file mode 100644 +index 0000000..d0e3741 +--- /dev/null ++++ b/include/asm-nios2nommu/io.h +@@ -0,0 +1,277 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_IO_H ++#define __NIOS2_IO_H ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#include /* IO address mapping routines need this */ ++#include ++#include ++ ++extern void insw(unsigned long port, void *dst, unsigned long count); ++extern void outsw(unsigned long port, void *src, unsigned long count); ++extern void insl(unsigned long port, void *dst, unsigned long count); ++extern void outsl(unsigned long port, void *src, unsigned long count); ++ ++#define readsb(p,d,l) insb(p,d,l) ++#define readsw(p,d,l) insw(p,d,l) ++#define readsl(p,d,l) insl(p,d,l) ++#define writesb(p,d,l) outsb(p,d,l) ++#define writesw(p,d,l) outsw(p,d,l) ++#define writesl(p,d,l) outsl(p,d,l) ++#ifndef irq_canonicalize ++#define irq_canonicalize(i) (i) ++#endif ++ ++#endif /* __KERNEL__ */ ++/* IO macros are needed by userspace programs */ ++ ++/* ++ * readX/writeX() are used to access memory mapped devices. On some ++ * architectures the memory mapped IO stuff needs to be accessed ++ * differently. On the Nios architecture, we just read/write the ++ * memory location directly. ++ */ ++ ++#define readb(addr) \ ++({ \ ++ unsigned char __res;\ ++ __asm__ __volatile__( \ ++ "ldbuio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define readw(addr) \ ++({ \ ++ unsigned short __res;\ ++ __asm__ __volatile__( \ ++ "ldhuio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define readl(addr) \ ++({ \ ++ unsigned int __res;\ ++ __asm__ __volatile__( \ ++ "ldwio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define writeb(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "stbio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define writew(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "sthio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define writel(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "stwio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define __raw_readb readb ++#define __raw_readw readw ++#define __raw_readl readl ++#define __raw_writeb writeb ++#define __raw_writew writew ++#define __raw_writel writel ++ ++#define mmiowb() ++ ++/* ++ * make the short names macros so specific devices ++ * can override them as required ++ */ ++ ++#define memset_io(addr,c,len) memset((void *)(((unsigned int)(addr)) | 0x80000000),(c),(len)) ++#define memcpy_fromio(to,from,len) memcpy((to),(void *)(((unsigned int)(from)) | 0x80000000),(len)) ++#define memcpy_toio(to,from,len) memcpy((void *)(((unsigned int)(to)) | 0x80000000),(from),(len)) ++ ++#define inb(addr) readb(addr) ++#define inw(addr) readw(addr) ++#define inl(addr) readl(addr) ++ ++#define outb(x,addr) ((void) writeb(x,addr)) ++#define outw(x,addr) ((void) writew(x,addr)) ++#define outl(x,addr) ((void) writel(x,addr)) ++ ++#define inb_p(addr) inb(addr) ++#define inw_p(addr) inw(addr) ++#define inl_p(addr) inl(addr) ++ ++#define outb_p(x,addr) outb(x,addr) ++#define outw_p(x,addr) outw(x,addr) ++#define outl_p(x,addr) outl(x,addr) ++ ++/* IO macros are needed by userspace programs */ ++#ifdef __KERNEL__ ++ ++extern inline void insb(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned char *p=(unsigned char*)dst; ++ while (count--) ++ *p++ = inb(port); ++} ++ ++/* See arch/niosnommu/io.c for optimized version */ ++extern inline void _insw(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned short *p=(unsigned short*)dst; ++ while (count--) ++ *p++ = inw(port); ++} ++ ++/* See arch/niosnommu/kernel/io.c for unaligned destination pointer */ ++extern inline void _insl(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned long *p=(unsigned long*)dst; ++ while (count--) ++ *p++ = inl(port); ++} ++ ++extern inline void outsb(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned char *p=(unsigned char*)src; ++ while (count--) ++ outb( *p++, port ); ++} ++ ++/* See arch/niosnommu/io.c for optimized version */ ++extern inline void _outsw(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned short *p=(unsigned short*)src; ++ while (count--) ++ outw( *p++, port ); ++} ++ ++/* See arch/niosnommu/kernel/io.c for unaligned source pointer */ ++extern inline void _outsl(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned long *p=(unsigned long*)src; ++ while (count--) ++ outl( *p++, port ); ++} ++ ++ ++ ++extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr, ++ int bus, int rdonly) ++{ ++ return; ++} ++ ++//vic - copied from m68knommu ++ ++/* Values for nocacheflag and cmode */ ++#define IOMAP_FULL_CACHING 0 ++#define IOMAP_NOCACHE_SER 1 ++#define IOMAP_NOCACHE_NONSER 2 ++#define IOMAP_WRITETHROUGH 3 ++ ++extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); ++extern void __iounmap(void *addr, unsigned long size); ++ ++extern inline void *ioremap(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); ++} ++extern inline void *ioremap_nocache(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); ++} ++extern inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); ++} ++extern inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_FULL_CACHING); ++} ++ ++extern void iounmap(void *addr); ++ ++ ++#define IO_SPACE_LIMIT 0xffffffff ++ ++#define dma_cache_inv(_start,_size) dcache_push(_start,_size) ++#define dma_cache_wback(_start,_size) dcache_push(_start,_size) ++#define dma_cache_wback_inv(_start,_size) dcache_push(_start,_size) ++ ++/* Pages to physical address... */ ++#define page_to_phys(page) page_to_virt(page) ++#define page_to_bus(page) page_to_virt(page) ++ ++#define mm_ptov(vaddr) ((void *) (vaddr)) ++#define mm_vtop(vaddr) ((unsigned long) (vaddr)) ++#define phys_to_virt(vaddr) ((void *) (vaddr)) ++#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) ++ ++#define virt_to_bus virt_to_phys ++#define bus_to_virt phys_to_virt ++ ++#define ioport_map(port, nr) ioremap(port, nr) ++#define ioport_unmap(port) iounmap(port) ++ ++/* ++ * Convert a physical pointer to a virtual kernel pointer for /dev/mem ++ * access ++ */ ++#define xlate_dev_mem_ptr(p) __va(p) ++ ++/* ++ * Convert a virtual cached pointer to an uncached pointer ++ */ ++#define xlate_dev_kmem_ptr(p) p ++ ++#define readsb(p,d,l) insb(p,d,l) ++#define readsw(p,d,l) insw(p,d,l) ++#define readsl(p,d,l) insl(p,d,l) ++#define writesb(p,d,l) outsb(p,d,l) ++#define writesw(p,d,l) outsw(p,d,l) ++#define writesl(p,d,l) outsl(p,d,l) ++#ifndef irq_canonicalize ++#define irq_canonicalize(i) (i) ++#endif ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* !(__NIOS2_IO_H) */ ++ +diff --git a/include/asm-nios2nommu/ioctl.h b/include/asm-nios2nommu/ioctl.h +new file mode 100644 +index 0000000..c02a36a +--- /dev/null ++++ b/include/asm-nios2nommu/ioctl.h +@@ -0,0 +1,100 @@ ++/* $Id: ioctl.h,v 1.1 2006/07/05 06:20:25 gerg Exp $ ++ * ++ * linux/ioctl.h for Linux by H.H. Bergman. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_IOCTL_H ++#define _NIOS2_IOCTL_H ++ ++/* ioctl command encoding: 32 bits total, command in lower 16 bits, ++ * size of the parameter structure in the lower 14 bits of the ++ * upper 16 bits. ++ * Encoding the size of the parameter structure in the ioctl request ++ * is useful for catching programs compiled with old versions ++ * and to avoid overwriting user space outside the user buffer area. ++ * The highest 2 bits are reserved for indicating the ``access mode''. ++ * NOTE: This limits the max parameter size to 16kB -1 ! ++ */ ++ ++/* ++ * I don't really have any idea about what this should look like, so ++ * for the time being, this is heavily based on the PC definitions. ++ */ ++ ++/* ++ * The following is for compatibility across the various Linux ++ * platforms. The i386 ioctl numbering scheme doesn't really enforce ++ * a type field. De facto, however, the top 8 bits of the lower 16 ++ * bits are indeed used as a type field, so we might just as well make ++ * this explicit here. Please be sure to use the decoding macros ++ * below from now on. ++ */ ++#define _IOC_NRBITS 8 ++#define _IOC_TYPEBITS 8 ++#define _IOC_SIZEBITS 14 ++#define _IOC_DIRBITS 2 ++ ++#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) ++#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) ++#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) ++#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) ++ ++#define _IOC_NRSHIFT 0 ++#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) ++#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) ++#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) ++ ++/* ++ * Direction bits. ++ */ ++#define _IOC_NONE 0U ++#define _IOC_WRITE 1U ++#define _IOC_READ 2U ++ ++#define _IOC(dir,type,nr,size) \ ++ (((dir) << _IOC_DIRSHIFT) | \ ++ ((type) << _IOC_TYPESHIFT) | \ ++ ((nr) << _IOC_NRSHIFT) | \ ++ ((size) << _IOC_SIZESHIFT)) ++ ++/* used to create numbers */ ++#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) ++#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) ++#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) ++#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) ++ ++/* used to decode ioctl numbers.. */ ++#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) ++#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) ++#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) ++#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) ++ ++/* ...and for the drivers/sound files... */ ++ ++#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) ++#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) ++#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) ++#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) ++#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) ++ ++#endif /* _NIOS2_IOCTL_H */ +diff --git a/include/asm-nios2nommu/ioctls.h b/include/asm-nios2nommu/ioctls.h +new file mode 100644 +index 0000000..288025c +--- /dev/null ++++ b/include/asm-nios2nommu/ioctls.h +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ARCH_NIOS2_IOCTLS_H__ ++#define __ARCH_NIOS2_IOCTLS_H__ ++ ++#include ++ ++/* 0x54 is just a magic number to make these relatively unique ('T') */ ++ ++#define TCGETS 0x5401 ++#define TCSETS 0x5402 ++#define TCSETSW 0x5403 ++#define TCSETSF 0x5404 ++#define TCGETA 0x5405 ++#define TCSETA 0x5406 ++#define TCSETAW 0x5407 ++#define TCSETAF 0x5408 ++#define TCSBRK 0x5409 ++#define TCXONC 0x540A ++#define TCFLSH 0x540B ++#define TIOCEXCL 0x540C ++#define TIOCNXCL 0x540D ++#define TIOCSCTTY 0x540E ++#define TIOCGPGRP 0x540F ++#define TIOCSPGRP 0x5410 ++#define TIOCOUTQ 0x5411 ++#define TIOCSTI 0x5412 ++#define TIOCGWINSZ 0x5413 ++#define TIOCSWINSZ 0x5414 ++#define TIOCMGET 0x5415 ++#define TIOCMBIS 0x5416 ++#define TIOCMBIC 0x5417 ++#define TIOCMSET 0x5418 ++#define TIOCGSOFTCAR 0x5419 ++#define TIOCSSOFTCAR 0x541A ++#define FIONREAD 0x541B ++#define TIOCINQ FIONREAD ++#define TIOCLINUX 0x541C ++#define TIOCCONS 0x541D ++#define TIOCGSERIAL 0x541E ++#define TIOCSSERIAL 0x541F ++#define TIOCPKT 0x5420 ++#define FIONBIO 0x5421 ++#define TIOCNOTTY 0x5422 ++#define TIOCSETD 0x5423 ++#define TIOCGETD 0x5424 ++#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ ++#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ ++#define TIOCSBRK 0x5427 /* BSD compatibility */ ++#define TIOCCBRK 0x5428 /* BSD compatibility */ ++#define TIOCGSID 0x5429 /* Return the session ID of FD */ ++#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ ++#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ ++ ++#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ ++#define FIOCLEX 0x5451 ++#define FIOASYNC 0x5452 ++#define TIOCSERCONFIG 0x5453 ++#define TIOCSERGWILD 0x5454 ++#define TIOCSERSWILD 0x5455 ++#define TIOCGLCKTRMIOS 0x5456 ++#define TIOCSLCKTRMIOS 0x5457 ++#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ ++#define TIOCSERGETLSR 0x5459 /* Get line status register */ ++#define TIOCSERGETMULTI 0x545A /* Get multiport config */ ++#define TIOCSERSETMULTI 0x545B /* Set multiport config */ ++ ++#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ ++#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ ++#define FIOQSIZE 0x545E ++ ++/* Used for packet mode */ ++#define TIOCPKT_DATA 0 ++#define TIOCPKT_FLUSHREAD 1 ++#define TIOCPKT_FLUSHWRITE 2 ++#define TIOCPKT_STOP 4 ++#define TIOCPKT_START 8 ++#define TIOCPKT_NOSTOP 16 ++#define TIOCPKT_DOSTOP 32 ++ ++#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ ++ ++#endif /* __ARCH_NIOS2_IOCTLS_H__ */ +diff --git a/include/asm-nios2nommu/ipc.h b/include/asm-nios2nommu/ipc.h +new file mode 100644 +index 0000000..cb86a31 +--- /dev/null ++++ b/include/asm-nios2nommu/ipc.h +@@ -0,0 +1,51 @@ ++#ifndef __NIOS2_IPC_H__ ++#define __NIOS2_IPC_H__ ++ ++/* Copied from sparc version ++ * These are used to wrap system calls on the Nios. ++ * ++ * See arch/niosnommu/kernel/sys_nios.c for ugly details.. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++struct ipc_kludge { ++ struct msgbuf *msgp; ++ long msgtyp; ++}; ++ ++#define SEMOP 1 ++#define SEMGET 2 ++#define SEMCTL 3 ++#define MSGSND 11 ++#define MSGRCV 12 ++#define MSGGET 13 ++#define MSGCTL 14 ++#define SHMAT 21 ++#define SHMDT 22 ++#define SHMGET 23 ++#define SHMCTL 24 ++ ++/* Used by the DIPC package, try and avoid reusing it */ ++#define DIPC 25 ++ ++#define IPCCALL(version,op) ((version)<<16 | (op)) ++ ++#endif +diff --git a/include/asm-nios2nommu/ipcbuf.h b/include/asm-nios2nommu/ipcbuf.h +new file mode 100644 +index 0000000..ef59533 +--- /dev/null ++++ b/include/asm-nios2nommu/ipcbuf.h +@@ -0,0 +1,49 @@ ++#ifndef __NIOS2_IPCBUF_H__ ++#define __NIOS2_IPCBUF_H__ ++ ++/* Copied from asm-m68k/ipcbuf.h ++ * The user_ipc_perm structure for Nios architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 32-bit mode_t and seq ++ * - 2 miscellaneous 32-bit values ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++struct ipc64_perm ++{ ++ __kernel_key_t key; ++ __kernel_uid32_t uid; ++ __kernel_gid32_t gid; ++ __kernel_uid32_t cuid; ++ __kernel_gid32_t cgid; ++ __kernel_mode_t mode; ++ unsigned short __pad1; ++ unsigned short seq; ++ unsigned short __pad2; ++ unsigned long __unused1; ++ unsigned long __unused2; ++}; ++ ++#endif /* __NIOS2_IPCBUF_H__ */ +diff --git a/include/asm-nios2nommu/irq.h b/include/asm-nios2nommu/irq.h +new file mode 100644 +index 0000000..f0e37a2 +--- /dev/null ++++ b/include/asm-nios2nommu/irq.h +@@ -0,0 +1,181 @@ ++/* ++ * 21Mar2001 1.1 dgt/microtronix ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++ ++#ifndef _NIOS2NOMMU_IRQ_H_ ++#define _NIOS2NOMMU_IRQ_H_ ++ ++extern void disable_irq(unsigned int); ++extern void enable_irq(unsigned int); ++ ++#include ++ ++#define SYS_IRQS 32 ++#define NR_IRQS SYS_IRQS ++ ++/* ++ * Interrupt source definitions ++ * General interrupt sources are the level 1-7. ++ * Adding an interrupt service routine for one of these sources ++ * results in the addition of that routine to a chain of routines. ++ * Each one is called in succession. Each individual interrupt ++ * service routine should determine if the device associated with ++ * that routine requires service. ++ */ ++ ++#define IRQ01 (1) /* level 1 interrupt */ ++#define IRQ02 (2) /* level 2 interrupt */ ++#define IRQ03 (3) /* level 3 interrupt */ ++#define IRQ04 (4) /* level 4 interrupt */ ++#define IRQ05 (5) /* level 5 interrupt */ ++#define IRQ06 (6) /* level 6 interrupt */ ++#define IRQ07 (7) /* level 7 interrupt */ ++#define IRQ08 (8) /* level 8 interrupt */ ++#define IRQ09 (9) /* level 9 interrupt */ ++#define IRQ0A (10) /* level 10 interrupt */ ++#define IRQ0B (11) /* level 11 interrupt */ ++#define IRQ0C (12) /* level 12 interrupt */ ++#define IRQ0D (13) /* level 13 interrupt */ ++#define IRQ0E (14) /* level 14 interrupt */ ++#define IRQ0F (15) /* level 15 interrupt */ ++#define IRQ10 (16) /* level 16 interrupt */ ++#define IRQ12 (17) /* level 17 interrupt */ ++#define IRQ13 (18) /* level 18 interrupt */ ++#define IRQ14 (19) /* level 19 interrupt */ ++#define IRQ15 (20) /* level 20 interrupt */ ++#define IRQ16 (21) /* level 21 interrupt */ ++#define IRQ17 (22) /* level 22 interrupt */ ++#define IRQ18 (23) /* level 23 interrupt */ ++#define IRQ19 (24) /* level 24 interrupt */ ++#define IRQ1A (25) /* level 25 interrupt */ ++#define IRQ1B (26) /* level 26 interrupt */ ++#define IRQ1C (27) /* level 27 interrupt */ ++#define IRQ1D (28) /* level 28 interrupt */ ++#define IRQ1E (29) /* level 29 interrupt */ ++#define IRQ1F (30) /* level 30 interrupt */ ++#define IRQ20 (31) /* level 31 interrupt */ ++#define IRQ21 (32) /* level 32 interrupt */ ++ ++#define IRQMAX IRQ21 ++ ++/* ++ * "Generic" interrupt sources ++ */ ++ ++/* ++ * Machine specific interrupt sources. ++ * ++ * Adding an interrupt service routine for a source with this bit ++ * set indicates a special machine specific interrupt source. ++ * The machine specific files define these sources. ++ * ++ * Removed, they are not used by any one. ++ */ ++ ++/* ++ * various flags for request_irq() ++ */ ++#define IRQ_FLG_LOCK (0x0001) /* handler is not replaceable */ ++#define IRQ_FLG_REPLACE (0x0002) /* replace existing handler */ ++#define IRQ_FLG_FAST (0x0004) ++#define IRQ_FLG_SLOW (0x0008) ++#define IRQ_FLG_STD (0x8000) /* internally used */ ++ ++/* ++ * Functions to set and clear the interrupt mask. ++ */ ++ ++/* ++ * Use a zero to clean the bit. ++ */ ++static inline void clrimr(int mask) ++{ ++ int flags; ++ ++ local_irq_save(flags); ++ __asm__ __volatile__( ++ "rdctl r8, ienable\n" ++ "and r8,r8,%0\n" ++ "wrctl ienable, r8\n" ++ : /* No output */ ++ : "r" (mask) ++ : "r8"); ++ local_irq_restore(flags); ++} ++ ++/* ++ * Use a one to set the bit. ++ */ ++static inline void setimr(int mask) ++{ ++ int flags; ++ ++ local_irq_save(flags); ++ __asm__ __volatile__( ++ "rdctl r8, ienable\n" ++ "or r8,r8,%0\n" ++ "wrctl ienable, r8\n" ++ : /* No output */ ++ : "r" (mask) ++ : "r8"); ++ local_irq_restore(flags); ++} ++ ++/* ++ * This structure is used to chain together the ISRs for a particular ++ * interrupt source (if it supports chaining). ++ */ ++typedef struct irq_node { ++ irq_handler_t handler; ++ unsigned long flags; ++ void *dev_id; ++ const char *devname; ++ struct irq_node *next; ++} irq_node_t; ++ ++/* ++ * This function returns a new irq_node_t ++ */ ++extern irq_node_t *new_irq_node(void); ++ ++/* ++ * This structure has only 4 elements for speed reasons ++ */ ++typedef struct irq_hand { ++ irq_handler_t handler; ++ unsigned long flags; ++ void *dev_id; ++ const char *devname; ++} irq_hand_t; ++ ++/* count of spurious interrupts */ ++extern volatile unsigned int num_spurious; ++ ++#define disable_irq_nosync(i) disable_irq(i) ++ ++#ifndef irq_canonicalize ++#define irq_canonicalize(i) (i) ++#endif ++ ++#endif /* _NIOS2NOMMU_IRQ_H_ */ +diff --git a/include/asm-nios2nommu/irq_node.h b/include/asm-nios2nommu/irq_node.h +new file mode 100644 +index 0000000..24f9763 +--- /dev/null ++++ b/include/asm-nios2nommu/irq_node.h +@@ -0,0 +1,36 @@ ++#ifndef _NIOS2NOMMU_IRQNODE_H_ ++#define _NIOS2NOMMU_IRQNODE_H_ ++ ++#include ++ ++/* ++ * This structure is used to chain together the ISRs for a particular ++ * interrupt source (if it supports chaining). ++ */ ++typedef struct irq_node { ++ irqreturn_t (*handler)(int, void *, struct pt_regs *); ++ unsigned long flags; ++ void *dev_id; ++ const char *devname; ++ struct irq_node *next; ++} irq_node_t; ++ ++/* ++ * This structure has only 4 elements for speed reasons ++ */ ++typedef struct irq_handler { ++ irqreturn_t (*handler)(int, void *, struct pt_regs *); ++ unsigned long flags; ++ void *dev_id; ++ const char *devname; ++} irq_handler_t; ++ ++/* count of spurious interrupts */ ++extern volatile unsigned int num_spurious; ++ ++/* ++ * This function returns a new irq_node_t ++ */ ++extern irq_node_t *new_irq_node(void); ++ ++#endif /* _NIOS2NOMMU_IRQNODE_H_ */ +diff --git a/include/asm-nios2nommu/irq_regs.h b/include/asm-nios2nommu/irq_regs.h +new file mode 100644 +index 0000000..3dd9c0b +--- /dev/null ++++ b/include/asm-nios2nommu/irq_regs.h +@@ -0,0 +1 @@ ++#include +diff --git a/include/asm-nios2nommu/kdebug.h b/include/asm-nios2nommu/kdebug.h +new file mode 100644 +index 0000000..6ece1b0 +--- /dev/null ++++ b/include/asm-nios2nommu/kdebug.h +@@ -0,0 +1 @@ ++#include +diff --git a/include/asm-nios2nommu/kmap_types.h b/include/asm-nios2nommu/kmap_types.h +new file mode 100644 +index 0000000..a26b91d +--- /dev/null ++++ b/include/asm-nios2nommu/kmap_types.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_KMAP_TYPES_H ++#define _ASM_KMAP_TYPES_H ++ ++enum km_type { ++ KM_BOUNCE_READ, ++ KM_SKB_SUNRPC_DATA, ++ KM_SKB_DATA_SOFTIRQ, ++ KM_USER0, ++ KM_USER1, ++ KM_BIO_SRC_IRQ, ++ KM_BIO_DST_IRQ, ++ KM_PTE0, ++ KM_PTE1, ++ KM_IRQ0, ++ KM_IRQ1, ++ KM_SOFTIRQ0, ++ KM_SOFTIRQ1, ++ KM_TYPE_NR ++}; ++ ++#endif +diff --git a/include/asm-nios2nommu/linkage.h b/include/asm-nios2nommu/linkage.h +new file mode 100644 +index 0000000..db79297 +--- /dev/null ++++ b/include/asm-nios2nommu/linkage.h +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ASM_LINKAGE_H ++#define __ASM_LINKAGE_H ++ ++#define __ALIGN .align 3 ++#define __ALIGN_STR ".align 3" ++ ++#endif +diff --git a/include/asm-nios2nommu/linux_logo.h b/include/asm-nios2nommu/linux_logo.h +new file mode 100644 +index 0000000..f9d38e7 +--- /dev/null ++++ b/include/asm-nios2nommu/linux_logo.h +@@ -0,0 +1,953 @@ ++/* $Id: linux_logo.h,v 1.1 2006/07/05 06:20:25 gerg Exp $ ++ * include/asm-nios/linux_logo.h: This is a linux logo ++ * to be displayed on boot. ++ * ++ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu) ++ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) ++ * Copyright (C) 2004 Micrtronix Datacom Ltd. ++ * ++ * You can put anything here, but: ++ * LINUX_LOGO_COLORS has to be less than 224 ++ * image size has to be 80x80 ++ * values have to start from 0x20 ++ * (i.e. RGB(linux_logo_red[0], ++ * linux_logo_green[0], ++ * linux_logo_blue[0]) is color 0x20) ++ * BW image has to be 80x80 as well, with MS bit ++ * on the left ++ * Serial_console ascii image can be any size, ++ * but should contain %s to display the version ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++ ++#define linux_logo_banner "Linux/NIOS2 version " UTS_RELEASE ++ ++#define __HAVE_ARCH_LINUX_LOGO ++#define __HAVE_ARCH_LINUX_LOGO16 ++ ++#define LINUX_LOGO_COLORS 221 ++ ++#ifdef INCLUDE_LINUX_LOGO_DATA ++ ++unsigned char linux_logo_red[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79, ++ 0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7, ++ 0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8, ++ 0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6, ++ 0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee, ++ 0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c, ++ 0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e, ++ 0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c, ++ 0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfe, ++ 0xf6, 0xec, 0xfe, 0xd2, 0xea, 0xf5, 0xf2, 0xf2, ++ 0xe9, 0xee, 0xf6, 0xf2, 0xee, 0xf6, 0xda, 0xd4, ++ 0xfa, 0xca, 0xf2, 0xf6, 0xfe, 0xf2, 0xda, 0xe4, ++ 0xf6, 0xdd, 0xf2, 0xee, 0xfa, 0xf0, 0x12, 0x4a, ++ 0xd6, 0xf2, 0x8e, 0xf2, 0xf6, 0xf6, 0xb5, 0xf1, ++ 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16, 0x9a, ++ 0x2e, 0xd2, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62, ++ 0xda, 0xee, 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xe0, ++ 0xae, 0xbe, 0xce, 0xe2, 0xa3, 0x8e, 0x6d, 0x8e, ++ 0x32, 0xaf, 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, ++ 0x7a, 0x82, 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, ++ 0x6a, 0x52, 0x59, 0x64, 0x5e, ++}; ++ ++unsigned char linux_logo_green[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c, ++ 0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae, ++ 0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8, ++ 0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda, ++ 0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca, ++ 0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76, ++ 0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46, ++ 0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b, ++ 0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfa, ++ 0xea, 0xd7, 0xf6, 0xbc, 0xda, 0xde, 0xda, 0xe6, ++ 0xca, 0xd8, 0xea, 0xe0, 0xcc, 0xf2, 0xce, 0xb2, ++ 0xee, 0xa2, 0xd6, 0xe6, 0xf6, 0xd7, 0xc5, 0xb8, ++ 0xc6, 0xb9, 0xce, 0xde, 0xce, 0xc6, 0x0e, 0x36, ++ 0xae, 0xbe, 0x86, 0xba, 0xbe, 0xe6, 0x8e, 0xc4, ++ 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12, 0x7a, ++ 0x20, 0xc6, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46, ++ 0xce, 0xd6, 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa6, ++ 0x87, 0x96, 0xa2, 0xd6, 0x85, 0x7a, 0x6a, 0x6e, ++ 0x22, 0x76, 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, ++ 0x66, 0x62, 0x42, 0x50, 0x56, 0x42, 0x56, 0x56, ++ 0x56, 0x3e, 0x51, 0x52, 0x56, ++}; ++ ++unsigned char linux_logo_blue[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08, ++ 0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f, ++ 0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e, ++ 0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c, ++ 0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f, ++ 0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a, ++ 0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e, ++ 0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b, ++ 0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xea, ++ 0xb6, 0x7c, 0xda, 0x8e, 0xa6, 0x87, 0x66, 0xb6, ++ 0x81, 0x6a, 0xc6, 0x9a, 0x5b, 0xd2, 0xb6, 0x6a, ++ 0xca, 0x45, 0x92, 0xb2, 0xca, 0x52, 0x8a, 0x3e, ++ 0x2e, 0x66, 0x66, 0xae, 0x3e, 0x47, 0x06, 0x0e, ++ 0x52, 0x36, 0x6a, 0x0e, 0x0e, 0xbe, 0x2c, 0x0e, ++ 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06, 0x2e, ++ 0x06, 0x9e, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06, ++ 0x9e, 0xae, 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x0a, ++ 0x32, 0x2e, 0x2a, 0xb2, 0x43, 0x48, 0x5f, 0x2e, ++ 0x06, 0x06, 0x07, 0x24, 0x06, 0x32, 0x06, 0x06, ++ 0x46, 0x2e, 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, ++ 0x3a, 0x22, 0x42, 0x34, 0x42, ++}; ++ ++unsigned char linux_logo[] __initdata = { ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, ++ 0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d, ++ 0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24, ++ 0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25, ++ 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, ++ 0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c, ++ 0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, ++ 0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31, ++ 0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34, ++ 0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36, ++ 0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22, ++ 0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25, ++ 0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22, ++ 0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36, ++ 0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, ++ 0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36, ++ 0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, ++ 0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36, ++ 0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23, ++ 0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21, ++ 0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b, ++ 0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26, ++ 0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d, ++ 0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32, ++ 0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a, ++ 0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b, ++ 0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37, ++ 0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58, ++ 0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35, ++ 0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, ++ 0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22, ++ 0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67, ++ 0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36, ++ 0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e, ++ 0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73, ++ 0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78, ++ 0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79, ++ 0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c, ++ 0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24, ++ 0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71, ++ 0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36, ++ 0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21, ++ 0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89, ++ 0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36, ++ 0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21, ++ 0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e, ++ 0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23, ++ 0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22, ++ 0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63, ++ 0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c, ++ 0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51, ++ 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21, ++ 0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97, ++ 0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98, ++ 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, ++ 0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32, ++ 0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50, ++ 0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48, ++ 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23, ++ 0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98, ++ 0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50, ++ 0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b, ++ 0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b, ++ 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48, ++ 0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, ++ 0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, ++ 0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34, ++ 0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52, ++ 0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c, ++ 0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c, ++ 0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b, ++ 0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93, ++ 0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28, ++ 0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99, ++ 0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93, ++ 0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36, ++ 0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x99, 0x9f, 0x52, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, ++ 0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30, ++ 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, ++ 0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36, ++ 0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48, ++ 0x47, 0x9f, 0x48, 0x48, 0x48, 0xa0, 0xa1, 0xa2, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36, ++ 0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f, ++ 0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36, ++ 0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48, ++ 0xa3, 0xa4, 0x48, 0x48, 0x9f, 0xa5, 0xa6, 0x9f, ++ 0x48, 0x48, 0x48, 0xa2, 0xa7, 0x47, 0x48, 0x48, ++ 0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23, ++ 0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d, ++ 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25, ++ 0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0xa8, 0xa1, 0x48, 0x48, 0x9f, 0xa9, 0xa6, 0x9f, ++ 0x48, 0x48, 0xaa, 0xa1, 0xa5, 0x9f, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30, ++ 0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32, ++ 0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a, ++ 0x36, 0x24, 0x4f, 0x48, 0x52, 0x52, 0x48, 0x48, ++ 0xab, 0xac, 0xa0, 0x48, 0xad, 0xa6, 0xa6, 0x9f, ++ 0x48, 0xa2, 0xa9, 0xa6, 0xa2, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30, ++ 0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21, ++ 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25, ++ 0x36, 0x3a, 0x48, 0x48, 0xae, 0xaf, 0x48, 0x48, ++ 0xad, 0xac, 0xa1, 0x9f, 0xa2, 0xa9, 0xa9, 0xa2, ++ 0x48, 0xab, 0x78, 0xa7, 0x48, 0x48, 0x48, 0x48, ++ 0x9f, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21, ++ 0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36, ++ 0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21, ++ 0x23, 0x43, 0x48, 0x48, 0xb0, 0xb1, 0xb2, 0x9f, ++ 0x48, 0xb3, 0xa5, 0xb3, 0xab, 0xa9, 0xa9, 0xb3, ++ 0xb4, 0xa9, 0xb5, 0xb0, 0x48, 0x48, 0xa0, 0xa5, ++ 0xa1, 0xad, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36, ++ 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, ++ 0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36, ++ 0x2e, 0x9b, 0x48, 0x48, 0x48, 0xb6, 0xb7, 0xa4, ++ 0xa2, 0xa7, 0xb5, 0x78, 0x6f, 0x6f, 0x6e, 0x6f, ++ 0xa9, 0xb5, 0xab, 0x48, 0x9f, 0xab, 0xa9, 0xa1, ++ 0xaa, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36, ++ 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, ++ 0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36, ++ 0x54, 0x48, 0x48, 0x48, 0x48, 0xa2, 0xa8, 0xa1, ++ 0xa5, 0xa6, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, ++ 0x6f, 0x78, 0xa5, 0xa0, 0xa0, 0x78, 0xa6, 0xa2, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, ++ 0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36, ++ 0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21, ++ 0x43, 0x48, 0x4b, 0xa2, 0x9f, 0x48, 0xa2, 0xa1, ++ 0xb8, 0x6e, 0x6e, 0xb5, 0x78, 0x6f, 0x78, 0x78, ++ 0x6e, 0x6f, 0x78, 0xb5, 0xa6, 0xa1, 0xa0, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21, ++ 0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25, ++ 0x52, 0x48, 0xa3, 0xb1, 0xb6, 0xb3, 0xaa, 0xac, ++ 0x68, 0x68, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, ++ 0x78, 0x6f, 0x6f, 0xb5, 0xa6, 0xb4, 0x48, 0x9f, ++ 0xb4, 0xb4, 0xa2, 0x9f, 0x48, 0x48, 0x4f, 0x21, ++ 0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a, ++ 0x47, 0x48, 0xa2, 0xb6, 0xaf, 0xb9, 0xba, 0x68, ++ 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x78, ++ 0x6f, 0x6f, 0xa6, 0x6f, 0xb5, 0xa0, 0xaa, 0xa6, ++ 0xa6, 0xa9, 0xb2, 0xb3, 0x48, 0x48, 0x4c, 0x22, ++ 0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39, ++ 0x9b, 0x48, 0x48, 0x48, 0xb0, 0xb0, 0xba, 0xb8, ++ 0x68, 0x68, 0x69, 0x78, 0x6f, 0xb5, 0x6f, 0xb5, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0xa5, 0xbb, 0xa9, ++ 0xa5, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23, ++ 0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31, ++ 0x9b, 0x48, 0x48, 0x48, 0x48, 0x9f, 0xac, 0x68, ++ 0xbc, 0x6e, 0x6e, 0x6e, 0xb5, 0x6f, 0x6e, 0x6f, ++ 0x6f, 0x78, 0x78, 0xb5, 0xb5, 0xa5, 0x9f, 0x9f, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22, ++ 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d, ++ 0x9b, 0x48, 0x48, 0xb0, 0xaa, 0xb3, 0xbd, 0xb8, ++ 0xb8, 0x68, 0x6e, 0x6e, 0xb5, 0x6f, 0x78, 0x6e, ++ 0x78, 0x6f, 0x78, 0x78, 0xb5, 0xa9, 0xa2, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, ++ 0x24, 0x27, 0xbe, 0x24, 0x25, 0x28, 0x21, 0x36, ++ 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25, ++ 0x39, 0x4d, 0xbf, 0x84, 0x81, 0x57, 0x21, 0x39, ++ 0x52, 0x48, 0x48, 0x62, 0xb1, 0xc0, 0xc1, 0xc1, ++ 0xb8, 0xb8, 0x68, 0xbc, 0x6e, 0x6e, 0x6e, 0x78, ++ 0x78, 0x78, 0x78, 0x6e, 0x78, 0xa9, 0xa0, 0xab, ++ 0xb3, 0xa2, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28, ++ 0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30, ++ 0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30, ++ 0x2d, 0xc2, 0x7a, 0xc3, 0xc4, 0xc4, 0x7f, 0x22, ++ 0x51, 0x52, 0x48, 0x48, 0xb0, 0xaa, 0xa8, 0xbd, ++ 0x68, 0xb8, 0xb8, 0x68, 0x68, 0x6e, 0x6e, 0x6f, ++ 0x6e, 0x6e, 0xb5, 0x6e, 0x78, 0xab, 0xab, 0xb5, ++ 0x78, 0xa6, 0xb3, 0xc5, 0xac, 0xac, 0xc6, 0x61, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32, ++ 0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31, ++ 0x4d, 0x91, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0x5a, ++ 0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0xb0, 0x64, ++ 0xc1, 0xb8, 0xb8, 0xb8, 0x68, 0x71, 0x6e, 0x6e, ++ 0x6f, 0x71, 0x6f, 0x6f, 0xa6, 0xa0, 0x9f, 0xb4, ++ 0xb4, 0xa0, 0xa1, 0xb7, 0xc7, 0x69, 0x66, 0xc8, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25, ++ 0x83, 0xc9, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a, ++ 0x60, 0x85, 0xca, 0xcb, 0xc4, 0xc4, 0xc4, 0x82, ++ 0x86, 0x36, 0x32, 0x3f, 0xa2, 0xa4, 0xa8, 0xa9, ++ 0xb8, 0xb8, 0xb8, 0xb8, 0x68, 0x6e, 0x6e, 0x6e, ++ 0x6e, 0x71, 0x6f, 0x71, 0xa6, 0xb4, 0x9f, 0x9f, ++ 0x48, 0x48, 0x48, 0xcc, 0xc3, 0xc7, 0xcd, 0xce, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57, ++ 0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x23, 0x30, 0x31, 0xcf, 0x91, 0x7e, 0x90, 0x90, ++ 0x8b, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0x5d, 0xd0, 0x36, 0x24, 0xd1, 0xb1, 0xaf, 0xaa, ++ 0xba, 0xb8, 0x68, 0x68, 0x68, 0x71, 0x6e, 0x6e, ++ 0x6e, 0x6f, 0x6e, 0x78, 0xa1, 0xa9, 0xa1, 0xb0, ++ 0x9f, 0x9b, 0x99, 0xcc, 0x64, 0x5c, 0x8b, 0xd0, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d, ++ 0x82, 0x5c, 0xd2, 0x2a, 0x23, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x24, 0x2b, 0xcf, 0x8b, 0x5b, 0x76, 0x5b, 0x5b, ++ 0x7b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc7, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48, ++ 0xa2, 0xa8, 0xb7, 0xc1, 0xb8, 0x68, 0x68, 0xbc, ++ 0x68, 0x6e, 0xb5, 0xb4, 0xb4, 0xab, 0xb5, 0xa1, ++ 0xb0, 0x4f, 0x3f, 0xd3, 0x7b, 0x7b, 0x85, 0x80, ++ 0xbe, 0x36, 0x36, 0x36, 0x21, 0xd4, 0x7e, 0x7b, ++ 0x64, 0x64, 0xd5, 0x35, 0x24, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x31, 0xd6, 0x5b, 0x64, 0xc3, 0xc3, 0xcb, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0x66, 0xd7, 0x36, 0x36, 0x36, 0x2c, 0x4b, ++ 0xd8, 0xd9, 0xb3, 0xa8, 0xbd, 0xbd, 0xbd, 0xbd, ++ 0xa9, 0xab, 0xb3, 0xa5, 0xa2, 0x9f, 0xa2, 0xa1, ++ 0x6a, 0x9a, 0x3f, 0xda, 0x76, 0x76, 0x7a, 0x63, ++ 0xdb, 0xdc, 0x86, 0xdc, 0xdd, 0x90, 0x5b, 0x64, ++ 0xc3, 0xc3, 0xde, 0x2d, 0x27, 0x23, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x26, 0x2d, 0x91, 0x5b, 0x64, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc7, 0x83, 0xce, 0x36, 0x36, 0x36, 0x30, ++ 0xb1, 0xd9, 0x48, 0xa1, 0xb2, 0xb0, 0xb0, 0xb3, ++ 0xa2, 0x48, 0xa7, 0xbd, 0xa9, 0xa2, 0x48, 0x9f, ++ 0xaa, 0x9a, 0x3f, 0xb1, 0x5b, 0x7b, 0xdf, 0x85, ++ 0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xc3, 0xc4, ++ 0xc4, 0xcb, 0x5d, 0xd5, 0x39, 0x26, 0x23, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2d, 0xe0, 0xdf, 0x64, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc7, 0x88, 0x36, 0x36, 0x36, 0x36, ++ 0x2d, 0x9b, 0x48, 0xb9, 0xaf, 0xa2, 0xa2, 0xb9, ++ 0xa8, 0x9f, 0x48, 0xa7, 0xb7, 0xd9, 0x48, 0x48, ++ 0x9b, 0x45, 0x3f, 0xe1, 0x6d, 0x7b, 0xca, 0xdf, ++ 0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc3, 0xe2, 0x37, 0x35, 0x26, 0x23, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2e, 0xe0, 0x7a, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc7, 0x72, 0x73, 0x36, 0x36, 0x36, ++ 0x24, 0x52, 0x48, 0xa3, 0xaf, 0x9f, 0x48, 0xb6, ++ 0xaf, 0xa2, 0x48, 0x9f, 0xe3, 0xd8, 0x48, 0x48, ++ 0x48, 0x46, 0x42, 0xd6, 0x7a, 0x7b, 0x64, 0x7b, ++ 0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xc3, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xcb, 0x64, 0xe2, 0x4d, 0x2c, 0x27, ++ 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x25, 0x31, 0xe4, 0x8b, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc7, 0x89, 0xbe, 0x36, 0x36, ++ 0x32, 0x47, 0x48, 0x4f, 0xa0, 0x48, 0x48, 0xe3, ++ 0x92, 0x9f, 0x48, 0x9f, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xc3, 0xcb, ++ 0xc3, 0x64, 0x64, 0xc3, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x5d, 0xe5, 0x2c, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x25, 0x31, 0xe4, 0x85, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x57, 0x27, 0x4d, ++ 0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x99, 0x34, 0xbe, 0xdb, 0x7a, 0x7b, 0xc3, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0xe4, ++ 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2d, 0xe4, 0x85, 0x7b, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc7, 0x5f, 0x92, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44, ++ 0x35, 0x36, 0xce, 0xdd, 0x7a, 0x7b, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0xc3, 0xe1, ++ 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x30, 0x2f, 0xd6, 0x8b, 0x7b, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x89, 0x45, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25, ++ 0x36, 0x36, 0x61, 0xdb, 0x6d, 0x64, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0xdf, 0xe5, ++ 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0xe6, 0x63, 0xdf, 0xc3, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x72, 0x81, 0xe7, ++ 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36, ++ 0x36, 0x36, 0xe8, 0x8f, 0x6d, 0x64, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc3, 0xca, 0x8b, 0xcf, 0x2c, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x35, 0x96, 0x75, 0xca, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0x81, 0xdb, ++ 0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b, ++ 0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x73, 0xdb, 0x7a, 0x7b, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0x64, 0x76, 0x7a, 0x91, 0xd5, 0x31, 0x30, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x39, 0x97, 0x75, 0xdf, 0x7b, 0x64, 0xc3, 0xc3, ++ 0xcb, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x7b, 0x7a, 0xe9, ++ 0xea, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30, ++ 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xea, 0xdd, 0x8b, 0x7b, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x64, 0x64, ++ 0x76, 0x85, 0xe0, 0xd5, 0x34, 0x2b, 0x27, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0xeb, 0x63, 0x7e, 0x7a, 0x6d, 0xdf, 0x5b, ++ 0x76, 0x7b, 0x64, 0x64, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x76, 0x85, 0xdb, ++ 0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xec, 0xdd, 0x75, 0x76, 0xc3, 0xc4, ++ 0xc4, 0xc4, 0xcb, 0xc3, 0x64, 0x76, 0xdf, 0x8b, ++ 0xd6, 0xd5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x27, 0x31, 0xed, 0xeb, 0xdd, 0x74, 0x63, 0x90, ++ 0x7e, 0x75, 0x8b, 0x6d, 0xdf, 0x76, 0x64, 0xc3, ++ 0xcb, 0xcb, 0xcb, 0xcb, 0x64, 0x7a, 0x84, 0xee, ++ 0x79, 0xbe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xea, 0xee, 0x63, 0x6d, 0x7b, 0x64, ++ 0xcb, 0xc3, 0x64, 0x7b, 0xdf, 0x75, 0x63, 0x96, ++ 0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x28, 0x27, 0x35, 0x2d, 0x41, 0xd5, 0xe7, 0x8f, ++ 0xdb, 0xdd, 0xe9, 0x74, 0x84, 0x90, 0x85, 0x6d, ++ 0x5b, 0x7b, 0x7b, 0xca, 0x6d, 0x90, 0xdb, 0xef, ++ 0xec, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36, ++ 0x36, 0x21, 0xd4, 0x80, 0xe9, 0x7e, 0x6d, 0x76, ++ 0xca, 0x76, 0x6d, 0x85, 0x63, 0xdb, 0xd5, 0x34, ++ 0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f, ++ 0x41, 0xf0, 0xf1, 0x6c, 0x80, 0xee, 0xdb, 0x74, ++ 0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xef, 0x79, ++ 0xe8, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d, ++ 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38, ++ 0x4d, 0x37, 0xf2, 0xf3, 0x8f, 0x74, 0x63, 0x7e, ++ 0x75, 0x7e, 0x63, 0xe9, 0x88, 0xe6, 0x31, 0x2a, ++ 0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30, ++ 0x33, 0x39, 0x2e, 0x51, 0x41, 0xd2, 0x6c, 0xf3, ++ 0x80, 0xee, 0xee, 0xee, 0xf4, 0xf3, 0xd7, 0xf5, ++ 0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27, ++ 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a, ++ 0x2b, 0x34, 0xf6, 0xec, 0xf7, 0x8f, 0xdd, 0xe9, ++ 0xe9, 0xdd, 0xee, 0x6c, 0x41, 0x39, 0x27, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, ++ 0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41, ++ 0xf8, 0xd7, 0x79, 0x79, 0x79, 0xec, 0xf9, 0x51, ++ 0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22, ++ 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, ++ 0x24, 0x2a, 0x31, 0xfa, 0xea, 0x79, 0xf3, 0x80, ++ 0xf7, 0xdc, 0xfb, 0x2f, 0x35, 0x26, 0x23, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b, ++ 0x31, 0x2f, 0xf6, 0xfa, 0xfa, 0x2f, 0x2e, 0x33, ++ 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x27, 0x35, 0x34, 0xfa, 0xfa, 0xfa, ++ 0xfc, 0xf6, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28, ++ 0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35, ++ 0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24, ++ 0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++}; ++ ++unsigned char linux_logo16[1]; ++ ++#endif /* INCLUDE_LINUX_LOGO_DATA */ ++ ++#include ++ +diff --git a/include/asm-nios2nommu/local.h b/include/asm-nios2nommu/local.h +new file mode 100644 +index 0000000..5ed7d1c +--- /dev/null ++++ b/include/asm-nios2nommu/local.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_LOCAL_H ++#define __NIOS2NOMMU_LOCAL_H ++ ++#include ++ ++#endif /* __NIOS2NOMMU_LOCAL_H */ +diff --git a/include/asm-nios2nommu/mc146818rtc.h b/include/asm-nios2nommu/mc146818rtc.h +new file mode 100644 +index 0000000..3492fc0 +--- /dev/null ++++ b/include/asm-nios2nommu/mc146818rtc.h +@@ -0,0 +1,29 @@ ++/* ++ * Machine dependent access functions for RTC registers. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2_MC146818RTC_H ++#define _NIOS2_MC146818RTC_H ++ ++/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */ ++ ++#endif /* _NIOS2_MC146818RTC_H */ +diff --git a/include/asm-nios2nommu/mman.h b/include/asm-nios2nommu/mman.h +new file mode 100644 +index 0000000..516ab26 +--- /dev/null ++++ b/include/asm-nios2nommu/mman.h +@@ -0,0 +1,68 @@ ++/* ++ * Copied from the m68k port. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_MMAN_H__ ++#define __NIOS2_MMAN_H__ ++ ++#define PROT_READ 0x1 /* page can be read */ ++#define PROT_WRITE 0x2 /* page can be written */ ++#define PROT_EXEC 0x4 /* page can be executed */ ++#define PROT_SEM 0x8 /* page may be used for atomic ops */ ++#define PROT_NONE 0x0 /* page can not be accessed */ ++#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ ++#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */ ++ ++#define MAP_SHARED 0x01 /* Share changes */ ++#define MAP_PRIVATE 0x02 /* Changes are private */ ++#define MAP_TYPE 0x0f /* Mask for type of mapping */ ++#define MAP_FIXED 0x10 /* Interpret addr exactly */ ++#define MAP_ANONYMOUS 0x20 /* don't use a file */ ++ ++#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ ++#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ ++#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ ++#define MAP_LOCKED 0x2000 /* pages are locked */ ++#define MAP_NORESERVE 0x4000 /* don't check for reservations */ ++#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ ++#define MAP_NONBLOCK 0x10000 /* do not block on IO */ ++ ++#define MS_ASYNC 1 /* sync memory asynchronously */ ++#define MS_INVALIDATE 2 /* invalidate the caches */ ++#define MS_SYNC 4 /* synchronous memory sync */ ++ ++#define MCL_CURRENT 1 /* lock all current mappings */ ++#define MCL_FUTURE 2 /* lock all future mappings */ ++ ++#define MADV_NORMAL 0x0 /* default page-in behavior */ ++#define MADV_RANDOM 0x1 /* page-in minimum required */ ++#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */ ++#define MADV_WILLNEED 0x3 /* pre-fault pages */ ++#define MADV_DONTNEED 0x4 /* discard these pages */ ++ ++/* compatibility flags */ ++#define MAP_ANON MAP_ANONYMOUS ++#define MAP_FILE 0 ++ ++#endif /* __NIOS2_MMAN_H__ */ ++ +diff --git a/include/asm-nios2nommu/mmu.h b/include/asm-nios2nommu/mmu.h +new file mode 100644 +index 0000000..b6e579d +--- /dev/null ++++ b/include/asm-nios2nommu/mmu.h +@@ -0,0 +1,36 @@ ++/* ++ * ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_MMU_H ++#define __NIOS2NOMMU_MMU_H ++ ++/* Copyright (C) 2002, David McCullough */ ++ ++typedef struct { ++ struct vm_list_struct *vmlist; ++ unsigned long end_brk; ++} mm_context_t; ++ ++#endif /* __NIOS2NOMMU_MMU_H */ +diff --git a/include/asm-nios2nommu/mmu_context.h b/include/asm-nios2nommu/mmu_context.h +new file mode 100644 +index 0000000..795cd09 +--- /dev/null ++++ b/include/asm-nios2nommu/mmu_context.h +@@ -0,0 +1,57 @@ ++/* ++ * ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_MMU_CONTEXT_H ++#define __NIOS2NOMMU_MMU_CONTEXT_H ++ ++#include ++#include ++#include ++ ++static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) ++{ ++} ++ ++extern inline int ++init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ // mm->context = virt_to_phys(mm->pgd); ++ return(0); ++} ++ ++#define destroy_context(mm) do { } while(0) ++ ++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) ++{ ++} ++ ++#define deactivate_mm(tsk,mm) do { } while (0) ++ ++extern inline void activate_mm(struct mm_struct *prev_mm, ++ struct mm_struct *next_mm) ++{ ++} ++ ++#endif +diff --git a/include/asm-nios2nommu/module.h b/include/asm-nios2nommu/module.h +new file mode 100644 +index 0000000..864f335 +--- /dev/null ++++ b/include/asm-nios2nommu/module.h +@@ -0,0 +1,36 @@ ++#ifndef _NIOS2_MODULE_H ++#define _NIOS2_MODULE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/module.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++struct mod_arch_specific ++{ ++}; ++ ++#define Elf_Shdr Elf32_Shdr ++#define Elf_Sym Elf32_Sym ++#define Elf_Ehdr Elf32_Ehdr ++ ++#endif /* _NIOS_MODULE_H */ +diff --git a/include/asm-nios2nommu/msgbuf.h b/include/asm-nios2nommu/msgbuf.h +new file mode 100644 +index 0000000..4d090f7 +--- /dev/null ++++ b/include/asm-nios2nommu/msgbuf.h +@@ -0,0 +1,56 @@ ++/* ++ * Taken from the m68k. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_MSGBUF_H ++#define _NIOS2_MSGBUF_H ++ ++/* ++ * The msqid64_ds structure for nios2 architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct msqid64_ds { ++ struct ipc64_perm msg_perm; ++ __kernel_time_t msg_stime; /* last msgsnd time */ ++ unsigned long __unused1; ++ __kernel_time_t msg_rtime; /* last msgrcv time */ ++ unsigned long __unused2; ++ __kernel_time_t msg_ctime; /* last change time */ ++ unsigned long __unused3; ++ unsigned long msg_cbytes; /* current number of bytes on queue */ ++ unsigned long msg_qnum; /* number of messages in queue */ ++ unsigned long msg_qbytes; /* max number of bytes on queue */ ++ __kernel_pid_t msg_lspid; /* pid of last msgsnd */ ++ __kernel_pid_t msg_lrpid; /* last receive pid */ ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++#endif /* _NIOS2_MSGBUF_H */ ++ +diff --git a/include/asm-nios2nommu/mutex.h b/include/asm-nios2nommu/mutex.h +new file mode 100644 +index 0000000..458c1f7 +--- /dev/null ++++ b/include/asm-nios2nommu/mutex.h +@@ -0,0 +1,9 @@ ++/* ++ * Pull in the generic implementation for the mutex fastpath. ++ * ++ * TODO: implement optimized primitives instead, or leave the generic ++ * implementation in place, or pick the atomic_xchg() based generic ++ * implementation. (see asm-generic/mutex-xchg.h for details) ++ */ ++ ++#include +diff --git a/include/asm-nios2nommu/namei.h b/include/asm-nios2nommu/namei.h +new file mode 100644 +index 0000000..d925c4e +--- /dev/null ++++ b/include/asm-nios2nommu/namei.h +@@ -0,0 +1,36 @@ ++/* ++ * linux/include/asm-nios/namei.h ++ * Moved from m68k version ++ * Included from linux/fs/namei.c ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_NAMEI_H ++#define __NIOS2_NAMEI_H ++ ++/* This dummy routine maybe changed to something useful ++ * for /usr/gnemul/ emulation stuff. ++ * Look at asm-sparc/namei.h for details. ++ */ ++ ++#define __emul_prefix() NULL ++ ++#endif +diff --git a/include/asm-nios2nommu/ndma.h b/include/asm-nios2nommu/ndma.h +new file mode 100644 +index 0000000..6b4604d +--- /dev/null ++++ b/include/asm-nios2nommu/ndma.h +@@ -0,0 +1,64 @@ ++#ifndef __NDMA_H__ ++ #define __NDMA_H__ ++ ++ #ifndef __ASSEMBLY__ ++ ++// DMA Registers ++typedef volatile struct ++{ ++ int np_dmastatus; // status register ++ int np_dmareadaddress; // read address ++ int np_dmawriteaddress; // write address ++ int np_dmalength; // length in bytes ++ int np_dmareserved1; // reserved ++ int np_dmareserved2; // reserved ++ int np_dmacontrol; // control register ++ int np_dmareserved3; // control register alternate ++} np_dma; ++ ++// DMA Register Bits ++enum ++{ ++ np_dmacontrol_byte_bit = 0, // Byte transaction ++ np_dmacontrol_hw_bit = 1, // Half-word transaction ++ np_dmacontrol_word_bit = 2, // Word transaction ++ np_dmacontrol_go_bit = 3, // enable execution ++ np_dmacontrol_i_en_bit = 4, // enable interrupt ++ np_dmacontrol_reen_bit = 5, // Enable read end-of-packet ++ np_dmacontrol_ween_bit = 6, // Enable write end-of-packet ++ np_dmacontrol_leen_bit = 7, // Enable length=0 transaction end ++ np_dmacontrol_rcon_bit = 8, // Read from a fixed address ++ np_dmacontrol_wcon_bit = 9, // Write to a fixed address ++ np_dmacontrol_doubleword_bit = 10, // Double-word transaction ++ np_dmacontrol_quadword_bit = 11, // Quad-word transaction ++ ++ np_dmastatus_done_bit = 0, // 1 when done. Status write clears. ++ np_dmastatus_busy_bit = 1, // 1 when busy. ++ np_dmastatus_reop_bit = 2, // read-eop received ++ np_dmastatus_weop_bit = 3, // write-eop received ++ np_dmastatus_len_bit = 4, // requested length transacted ++ ++ np_dmacontrol_byte_mask = (1 << 0), // Byte transaction ++ np_dmacontrol_hw_mask = (1 << 1), // Half-word transaction ++ np_dmacontrol_word_mask = (1 << 2), // Word transaction ++ np_dmacontrol_go_mask = (1 << 3), // enable execution ++ np_dmacontrol_i_en_mask = (1 << 4), // enable interrupt ++ np_dmacontrol_reen_mask = (1 << 5), // Enable read end-of-packet ++ np_dmacontrol_ween_mask = (1 << 6), // Enable write end-of-packet ++ np_dmacontrol_leen_mask = (1 << 7), // Enable length=0 transaction end ++ np_dmacontrol_rcon_mask = (1 << 8), // Read from a fixed address ++ np_dmacontrol_wcon_mask = (1 << 9), // Write to a fixed address ++ np_dmacontrol_doubleword_mask = (1 << 10), // Double-word transaction ++ np_dmacontrol_quadword_mask = (1 << 11), // Quad-word transaction ++ ++ np_dmastatus_done_mask = (1 << 0), // 1 when done. Status write clears. ++ np_dmastatus_busy_mask = (1 << 1), // 1 when busy. ++ np_dmastatus_reop_mask = (1 << 2), // read-eop received ++ np_dmastatus_weop_mask = (1 << 3), // write-eop received ++ np_dmastatus_len_mask = (1 << 4), // requested length transacted ++}; ++ ++ #endif /* __ASSEMBLY__ */ ++ ++#endif ++/* End of File */ +diff --git a/include/asm-nios2nommu/nios.h b/include/asm-nios2nommu/nios.h +new file mode 100644 +index 0000000..df17672 +--- /dev/null ++++ b/include/asm-nios2nommu/nios.h +@@ -0,0 +1,7 @@ ++#ifndef __NIOS_H__ ++#define __NIOS_H__ ++ ++#include ++ ++#endif ++ +diff --git a/include/asm-nios2nommu/page.h b/include/asm-nios2nommu/page.h +new file mode 100644 +index 0000000..764e73c +--- /dev/null ++++ b/include/asm-nios2nommu/page.h +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_PAGE_H ++#define _NIOS2_PAGE_H ++ ++/* copied from m68knommu arch */ ++ ++/* PAGE_SHIFT determines the page size */ ++ ++#define PAGE_SHIFT (12) ++#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#define PAGE_MASK (~(PAGE_SIZE-1)) ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#if PAGE_SHIFT < 13 ++#define THREAD_SIZE (8192) ++#else ++#define THREAD_SIZE PAGE_SIZE ++#endif ++ ++#ifndef __ASSEMBLY__ ++ ++#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) ++#define free_user_page(page, addr) free_page(addr) ++ ++#define clear_page(page) memset((page), 0, PAGE_SIZE) ++#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) ++ ++#define clear_user_page(page, vaddr, pg) clear_page(page) ++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) ++ ++/* ++ * These are used to make use of C type-checking.. ++ */ ++typedef struct { unsigned long pte; } pte_t; ++typedef struct { unsigned long pmd[16]; } pmd_t; ++typedef struct { unsigned long pgd; } pgd_t; ++typedef struct { unsigned long pgprot; } pgprot_t; ++ ++#define pte_val(x) ((x).pte) ++#define pmd_val(x) ((&x)->pmd[0]) ++#define pgd_val(x) ((x).pgd) ++#define pgprot_val(x) ((x).pgprot) ++ ++#define __pte(x) ((pte_t) { (x) } ) ++#define __pmd(x) ((pmd_t) { (x) } ) ++#define __pgd(x) ((pgd_t) { (x) } ) ++#define __pgprot(x) ((pgprot_t) { (x) } ) ++ ++/* to align the pointer to the (next) page boundary */ ++#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) ++ ++extern unsigned long memory_start; ++extern unsigned long memory_end; ++ ++#endif /* !__ASSEMBLY__ */ ++#include ++#define PAGE_OFFSET ((int)(nasys_program_mem)) ++ ++#ifndef __ASSEMBLY__ ++ ++#define __pa(vaddr) virt_to_phys((void *)(vaddr)) ++#define __va(paddr) phys_to_virt((unsigned long)(paddr)) ++ ++#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) ++ ++#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) ++#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) ++ ++#define virt_to_page(addr) ((void*) addr < (void*) memory_end ? mem_map + \ ++ (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) : 0UL) ++#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) ++#define VALID_PAGE(page) (((page) - mem_map) < max_mapnr) ++ ++#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) ++#define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) ++#define pfn_valid(pfn) ((pfn) < max_mapnr) ++ ++#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ ++ ((void *)(kaddr) < (void *)memory_end)) ++ ++#ifdef CONFIG_NO_KERNEL_MSG ++#define BUG_PRINT() ++#else ++#define BUG_PRINT() printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__) ++#endif ++ ++#ifdef na_cpu_oci_core ++#define BUG_PANIC() asm volatile ("break") /* drop to debugger */ ++#else ++// #define BUG_PANIC() while(1) ++#define BUG_PANIC() panic("BUG!") ++#endif ++ ++#endif /* __ASSEMBLY__ */ ++ ++#include ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS2_PAGE_H */ +diff --git a/include/asm-nios2nommu/param.h b/include/asm-nios2nommu/param.h +new file mode 100644 +index 0000000..e75a355 +--- /dev/null ++++ b/include/asm-nios2nommu/param.h +@@ -0,0 +1,49 @@ ++#ifndef _NIOS_PARAM_H ++#define _NIOS_PARAM_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/param.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifndef HZ ++#define HZ 100 ++#endif ++ ++#ifdef __KERNEL__ ++#define USER_HZ HZ ++#define CLOCKS_PER_SEC (USER_HZ) ++#endif ++ ++#define EXEC_PAGESIZE 4096 ++ ++#ifndef NGROUPS ++#define NGROUPS 32 ++#endif ++ ++#ifndef NOGROUP ++#define NOGROUP (-1) ++#endif ++ ++#define MAXHOSTNAMELEN 64 /* max length of hostname */ ++ ++#endif +diff --git a/include/asm-nios2nommu/pci.h b/include/asm-nios2nommu/pci.h +new file mode 100644 +index 0000000..be3b3b2 +--- /dev/null ++++ b/include/asm-nios2nommu/pci.h +@@ -0,0 +1,126 @@ ++#ifndef __ASM_SH_PCI_H ++#define __ASM_SH_PCI_H ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* Can be used to override the logic in pci_scan_bus for skipping ++ already-configured bus numbers - to be used for buggy BIOSes ++ or architectures with incomplete PCI setup by the loader */ ++ ++#define pcibios_assign_all_busses() 1 ++#define pcibios_scan_all_fns(a, b) 0 ++ ++/* ++ * A board can define one or more PCI channels that represent built-in (or ++ * external) PCI controllers. ++ */ ++struct pci_channel { ++ struct pci_ops *pci_ops; ++ struct resource *io_resource; ++ struct resource *mem_resource; ++ int first_devfn; ++ int last_devfn; ++}; ++ ++/* ++ * Each board initializes this array and terminates it with a NULL entry. ++ */ ++extern struct pci_channel board_pci_channels[]; ++ ++#define PCIBIOS_MIN_IO board_pci_channels->io_resource->start ++#define PCIBIOS_MIN_MEM board_pci_channels->mem_resource->start ++ ++struct pci_dev; ++ ++extern void pcibios_set_master(struct pci_dev *dev); ++ ++static inline void pcibios_penalize_isa_irq(int irq, int active) ++{ ++ /* We don't do dynamic PCI IRQ allocation */ ++} ++ ++/* Dynamic DMA mapping stuff. ++ * SuperH has everything mapped statically like x86. ++ */ ++ ++/* The PCI address space does equal the physical memory ++ * address space. The networking and block device layers use ++ * this boolean for bounce buffer decisions. ++ */ ++#define PCI_DMA_BUS_IS_PHYS (1) ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* pci_unmap_{single,page} being a nop depends upon the ++ * configuration. ++ */ ++#ifdef CONFIG_SH_PCIDMA_NONCOHERENT ++#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ ++ dma_addr_t ADDR_NAME; ++#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ ++ __u32 LEN_NAME; ++#define pci_unmap_addr(PTR, ADDR_NAME) \ ++ ((PTR)->ADDR_NAME) ++#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ ++ (((PTR)->ADDR_NAME) = (VAL)) ++#define pci_unmap_len(PTR, LEN_NAME) \ ++ ((PTR)->LEN_NAME) ++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ ++ (((PTR)->LEN_NAME) = (VAL)) ++#else ++#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) ++#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) ++#define pci_unmap_addr(PTR, ADDR_NAME) (0) ++#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) ++#define pci_unmap_len(PTR, LEN_NAME) (0) ++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) ++#endif ++ ++/* Not supporting more than 32-bit PCI bus addresses now, but ++ * must satisfy references to this function. Change if needed. ++ */ ++#define pci_dac_dma_supported(pci_dev, mask) (0) ++ ++/* These macros should be used after a pci_map_sg call has been done ++ * to get bus addresses of each of the SG entries and their lengths. ++ * You should only work with the number of sg entries pci_map_sg ++ * returns, or alternatively stop on the first sg_dma_len(sg) which ++ * is 0. ++ */ ++#define sg_dma_address(sg) (virt_to_bus((sg)->dma_address)) ++#define sg_dma_len(sg) ((sg)->length) ++ ++#ifdef CONFIG_PCI ++static inline void pci_dma_burst_advice(struct pci_dev *pdev, ++ enum pci_dma_burst_strategy *strat, ++ unsigned long *strategy_parameter) ++{ ++ *strat = PCI_DMA_BURST_INFINITY; ++ *strategy_parameter = ~0UL; ++} ++#endif ++ ++/* Board-specific fixup routines. */ ++extern void pcibios_fixup(void); ++extern void pcibios_fixup_irqs(void); ++ ++#ifdef CONFIG_PCI_AUTO ++extern int pciauto_assign_resources(int busno, struct pci_channel *hose); ++#endif ++ ++#endif /* __KERNEL__ */ ++ ++/* generic pci stuff */ ++#include ++ ++/* generic DMA-mapping stuff */ ++#include ++ ++#endif /* __ASM_SH_PCI_H */ ++ +diff --git a/include/asm-nios2nommu/percpu.h b/include/asm-nios2nommu/percpu.h +new file mode 100644 +index 0000000..cd6d4a3 +--- /dev/null ++++ b/include/asm-nios2nommu/percpu.h +@@ -0,0 +1,30 @@ ++#ifndef __ARCH_NIOS2NOMMU_PERCPU__ ++#define __ARCH_NIOS2NOMMU_PERCPU__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/percpu.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* __ARCH_NIOS2NOMMU_PERCPU__ */ +diff --git a/include/asm-nios2nommu/pgalloc.h b/include/asm-nios2nommu/pgalloc.h +new file mode 100644 +index 0000000..a997ada +--- /dev/null ++++ b/include/asm-nios2nommu/pgalloc.h +@@ -0,0 +1,32 @@ ++#ifndef _NIOS2NOMMU_PGALLOC_H ++#define _NIOS2NOMMU_PGALLOC_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/pgalloc.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#define check_pgt_cache() do { } while (0) ++ ++#endif /* _NIOS2NOMMU_PGALLOC_H */ +diff --git a/include/asm-nios2nommu/pgtable.h b/include/asm-nios2nommu/pgtable.h +new file mode 100644 +index 0000000..4124a33 +--- /dev/null ++++ b/include/asm-nios2nommu/pgtable.h +@@ -0,0 +1,112 @@ ++#ifndef _NIOS_PGTABLE_H ++#define _NIOS_PGTABLE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/pgtable.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++ ++//vic - this bit copied from m68knommu version ++#include ++#include ++#include ++ ++typedef pte_t *pte_addr_t; ++ ++#define pgd_present(pgd) (1) /* pages are always present on NO_MM */ ++#define pgd_none(pgd) (0) ++#define pgd_bad(pgd) (0) ++#define pgd_clear(pgdp) ++#define kern_addr_valid(addr) (1) ++#define pmd_offset(a, b) ((void *)0) ++ ++#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */ ++//vic - this bit copied from m68knommu version ++ ++extern void paging_init(void); ++#define swapper_pg_dir ((pgd_t *) 0) ++ ++#define __swp_type(x) (0) ++#define __swp_offset(x) (0) ++#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) ++#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) ++#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) ++ ++static inline int pte_file(pte_t pte) { return 0; } ++ ++/* ++ * ZERO_PAGE is a global shared page that is always zero: used ++ * for zero-mapped memory areas etc.. ++ */ ++#define ZERO_PAGE(vaddr) (virt_to_page(0)) ++ ++extern unsigned int kobjsize(const void *objp); ++extern int is_in_rom(unsigned long); ++ ++/* ++ * No page table caches to initialise ++ */ ++#define pgtable_cache_init() do { } while (0) ++ ++#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ ++ remap_pfn_range(vma, vaddr, pfn, size, prot) ++ ++extern inline void flush_cache_mm(struct mm_struct *mm) ++{ ++} ++ ++extern inline void flush_cache_range(struct mm_struct *mm, ++ unsigned long start, ++ unsigned long end) ++{ ++} ++ ++/* Push the page at kernel virtual address and clear the icache */ ++extern inline void flush_page_to_ram (unsigned long address) ++{ ++} ++ ++/* Push n pages at kernel virtual address and clear the icache */ ++extern inline void flush_pages_to_ram (unsigned long address, int n) ++{ ++} ++ ++/* ++ * All 32bit addresses are effectively valid for vmalloc... ++ * Sort of meaningless for non-VM targets. ++ */ ++#define VMALLOC_START 0 ++#define VMALLOC_END 0xffffffff ++ ++#define arch_enter_lazy_mmu_mode() do {} while (0) ++#define arch_leave_lazy_mmu_mode() do {} while (0) ++#define arch_flush_lazy_mmu_mode() do {} while (0) ++#define arch_enter_lazy_cpu_mode() do {} while (0) ++#define arch_leave_lazy_cpu_mode() do {} while (0) ++#define arch_flush_lazy_cpu_mode() do {} while (0) ++ ++#endif /* _NIOS_PGTABLE_H */ +diff --git a/include/asm-nios2nommu/pio_struct.h b/include/asm-nios2nommu/pio_struct.h +new file mode 100644 +index 0000000..8ce5176 +--- /dev/null ++++ b/include/asm-nios2nommu/pio_struct.h +@@ -0,0 +1,14 @@ ++// PIO Peripheral ++ ++// PIO Registers ++typedef volatile struct ++ { ++ int np_piodata; // read/write, up to 32 bits ++ int np_piodirection; // write/readable, up to 32 bits, 1->output bit ++ int np_piointerruptmask; // write/readable, up to 32 bits, 1->enable interrupt ++ int np_pioedgecapture; // read, up to 32 bits, cleared by any write ++ } np_pio; ++ ++// PIO Routines ++void nr_pio_showhex(int value); // shows low byte on pio named na_seven_seg_pio ++ +diff --git a/include/asm-nios2nommu/poll.h b/include/asm-nios2nommu/poll.h +new file mode 100644 +index 0000000..f6b9ab8 +--- /dev/null ++++ b/include/asm-nios2nommu/poll.h +@@ -0,0 +1,48 @@ ++#ifndef __NIOS2_POLL_H ++#define __NIOS2_POLL_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/poll.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define POLLIN 1 ++#define POLLPRI 2 ++#define POLLOUT 4 ++#define POLLERR 8 ++#define POLLHUP 16 ++#define POLLNVAL 32 ++#define POLLRDNORM 64 ++#define POLLWRNORM POLLOUT ++#define POLLRDBAND 128 ++#define POLLWRBAND 256 ++#define POLLMSG 0x0400 ++#define POLLREMOVE 0x1000 ++#define POLLRDHUP 0x2000 ++ ++struct pollfd { ++ int fd; ++ short events; ++ short revents; ++}; ++ ++#endif +diff --git a/include/asm-nios2nommu/posix_types.h b/include/asm-nios2nommu/posix_types.h +new file mode 100644 +index 0000000..0b019b5 +--- /dev/null ++++ b/include/asm-nios2nommu/posix_types.h +@@ -0,0 +1,89 @@ ++#ifndef __ARCH_NIOS2_POSIX_TYPES_H ++#define __ARCH_NIOS2_POSIX_TYPES_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/posix_types.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This file is generally used by user-level software, so you need to ++ * be a little careful about namespace pollution etc. Also, we cannot ++ * assume GCC is being used. ++ */ ++ ++typedef unsigned long __kernel_ino_t; ++typedef unsigned short __kernel_mode_t; ++typedef unsigned short __kernel_nlink_t; ++typedef long __kernel_off_t; ++typedef int __kernel_pid_t; ++typedef unsigned short __kernel_ipc_pid_t; ++typedef unsigned short __kernel_uid_t; ++typedef unsigned short __kernel_gid_t; ++typedef unsigned int __kernel_size_t; ++typedef int __kernel_ssize_t; ++typedef int __kernel_ptrdiff_t; ++typedef long __kernel_time_t; ++typedef long __kernel_suseconds_t; ++typedef long __kernel_clock_t; ++typedef int __kernel_timer_t; ++typedef int __kernel_clockid_t; ++typedef int __kernel_daddr_t; ++typedef char * __kernel_caddr_t; ++typedef unsigned short __kernel_uid16_t; ++typedef unsigned short __kernel_gid16_t; ++typedef unsigned int __kernel_uid32_t; ++typedef unsigned int __kernel_gid32_t; ++ ++typedef unsigned short __kernel_old_uid_t; ++typedef unsigned short __kernel_old_gid_t; ++typedef unsigned short __kernel_old_dev_t; ++ ++#ifdef __GNUC__ ++typedef long long __kernel_loff_t; ++#endif ++ ++typedef struct { ++#if defined(__KERNEL__) || defined(__USE_ALL) ++ int val[2]; ++#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ ++ int __val[2]; ++#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ ++} __kernel_fsid_t; ++ ++#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) ++ ++#undef __FD_SET ++#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) ++ ++#undef __FD_CLR ++#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) ++ ++#undef __FD_ISSET ++#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) ++ ++#undef __FD_ZERO ++#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) ++ ++#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ ++ ++#endif +diff --git a/include/asm-nios2nommu/preem_latency.h b/include/asm-nios2nommu/preem_latency.h +new file mode 100644 +index 0000000..6defb5c +--- /dev/null ++++ b/include/asm-nios2nommu/preem_latency.h +@@ -0,0 +1,39 @@ ++#ifndef _ASM_PREEM_LATENCY_H ++#define _ASM_PREEM_LATENCY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/preem_latency.h ++ * ++ * timing support for preempt-stats patch ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#define readclock(low) \ ++do {\ ++ *(volatile unsigned long *)na_Counter_64_bit=1; \ ++ low=*(volatile unsigned long *)na_Counter_64_bit; \ ++} while (0) ++#define readclock_init() ++ ++#endif /* _ASM_PREEM_LATENCY_H */ +diff --git a/include/asm-nios2nommu/processor.h b/include/asm-nios2nommu/processor.h +new file mode 100644 +index 0000000..5332f94 +--- /dev/null ++++ b/include/asm-nios2nommu/processor.h +@@ -0,0 +1,148 @@ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/processor.h ++ * ++ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) ++ * Copyright (C) 2001 Ken Hill (khill@microtronix.com) ++ * Vic Phillips (vic@microtronix.com) ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * hacked from: ++ * include/asm-sparc/processor.h ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * Nov/02/2003 dgt Fix task_size ++ * ++ ---------------------------------------------------------------------*/ ++ ++#ifndef __ASM_NIOS_PROCESSOR_H ++#define __ASM_NIOS_PROCESSOR_H ++ ++#define NIOS2_FLAG_KTHREAD 0x00000001 /* task is a kernel thread */ ++#define NIOS2_FLAG_COPROC 0x00000002 /* Thread used coprocess */ ++#define NIOS2_FLAG_DEBUG 0x00000004 /* task is being debugged */ ++ ++#define NIOS2_OP_NOP 0x1883a ++#define NIOS2_OP_BREAK 0x3da03a ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * Default implementation of macro that returns current ++ * instruction pointer ("program counter"). ++ */ ++#define current_text_addr() ({ __label__ _l; _l: &&_l;}) ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include /* for get_hi_limit */ ++ ++/* ++ * Bus types ++ */ ++#define EISA_bus 0 ++#define EISA_bus__is_a_macro /* for versions in ksyms.c */ ++#define MCA_bus 0 ++#define MCA_bus__is_a_macro /* for versions in ksyms.c */ ++ ++/* ++ * The nios has no problems with write protection ++ */ ++#define wp_works_ok 1 ++#define wp_works_ok__is_a_macro /* for versions in ksyms.c */ ++ ++/* Whee, this is STACK_TOP and the lowest kernel address too... */ ++#if 0 ++#define KERNBASE 0x00000000 /* First address the kernel will eventually be */ ++#define TASK_SIZE (KERNBASE) ++#define MAX_USER_ADDR TASK_SIZE ++#define MMAP_SEARCH_START (TASK_SIZE/3) ++#endif ++ ++#define TASK_SIZE ((unsigned int) nasys_program_mem_end) //...this is better... ++ ++/* ++ * This decides where the kernel will search for a free chunk of vm ++ * space during mmap's. We won't be using it ++ */ ++#define TASK_UNMAPPED_BASE 0 ++ ++/* The Nios processor specific thread struct. */ ++struct thread_struct { ++ struct pt_regs *kregs; ++ ++ /* For signal handling */ ++ unsigned long sig_address; ++ unsigned long sig_desc; ++ ++ /* Context switch saved kernel state. */ ++ unsigned long ksp; ++ unsigned long kpsr; ++ unsigned long kesr; ++ ++ /* Flags are defined below */ ++ ++ unsigned long flags; ++ int current_ds; ++ struct exec core_exec; /* just what it says. */ ++}; ++ ++#define INIT_MMAP { &init_mm, (0), (0), \ ++ __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC } ++ ++#define INIT_THREAD { \ ++ .kregs = 0, \ ++ .sig_address = 0, \ ++ .sig_desc = 0, \ ++ .ksp = 0, \ ++ .kpsr = 0, \ ++ .kesr = PS_S, \ ++ .flags = NIOS2_FLAG_KTHREAD, \ ++ .current_ds = __KERNEL_DS, \ ++ .core_exec = INIT_EXEC \ ++} ++ ++/* Free all resources held by a thread. */ ++extern void release_thread(struct task_struct *); ++ ++extern unsigned long thread_saved_pc(struct task_struct *t); ++ ++extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); ++ ++/* Prepare to copy thread state - unlazy all lazy status */ ++#define prepare_to_copy(tsk) do { } while (0) ++ ++extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); ++ ++unsigned long get_wchan(struct task_struct *p); ++ ++#define KSTK_EIP(tsk) ((tsk)->thread.kregs->ea) ++#define KSTK_ESP(tsk) ((tsk)->thread.kregs->sp) ++ ++#ifdef __KERNEL__ ++/* Allocation and freeing of basic task resources. */ ++ ++//;dgt2;#define alloc_task_struct() ((struct task_struct *) xx..see..linux..fork..xx __get_free_pages(GFP_KERNEL,1)) ++//;dgt2;#define get_task_struct(tsk) xx..see..linux..sched.h...atomic_inc(&mem_map[MAP_NR(tsk)].count) ++ ++#endif ++ ++#define cpu_relax() do { } while (0) ++#endif /* __ASSEMBLY__ */ ++#endif /* __ASM_NIOS_PROCESSOR_H */ +diff --git a/include/asm-nios2nommu/ptrace.h b/include/asm-nios2nommu/ptrace.h +new file mode 100644 +index 0000000..d669e08 +--- /dev/null ++++ b/include/asm-nios2nommu/ptrace.h +@@ -0,0 +1,140 @@ ++/* ++ * Taken from the m68k port. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2NOMMU_PTRACE_H ++#define _NIOS2NOMMU_PTRACE_H ++ ++#ifndef __ASSEMBLY__ ++ ++#define PTR_R0 0 ++#define PTR_R1 1 ++#define PTR_R2 2 ++#define PTR_R3 3 ++#define PTR_R4 4 ++#define PTR_R5 5 ++#define PTR_R6 6 ++#define PTR_R7 7 ++#define PTR_R8 8 ++#define PTR_R9 9 ++#define PTR_R10 10 ++#define PTR_R11 11 ++#define PTR_R12 12 ++#define PTR_R13 13 ++#define PTR_R14 14 ++#define PTR_R15 15 ++#define PTR_R16 16 ++#define PTR_R17 17 ++#define PTR_R18 18 ++#define PTR_R19 19 ++#define PTR_R20 20 ++#define PTR_R21 21 ++#define PTR_R22 22 ++#define PTR_R23 23 ++#define PTR_R24 24 ++#define PTR_R25 25 ++#define PTR_GP 26 ++#define PTR_SP 27 ++#define PTR_FP 28 ++#define PTR_EA 29 ++#define PTR_BA 30 ++#define PTR_RA 31 ++#define PTR_STATUS 32 ++#define PTR_ESTATUS 33 ++#define PTR_BSTATUS 34 ++#define PTR_IENABLE 35 ++#define PTR_IPENDING 36 ++ ++/* this struct defines the way the registers are stored on the ++ stack during a system call. ++ ++ There is a fake_regs in setup.c that has to match pt_regs.*/ ++ ++struct pt_regs { ++ unsigned long r8; ++ unsigned long r9; ++ unsigned long r10; ++ unsigned long r11; ++ unsigned long r12; ++ unsigned long r13; ++ unsigned long r14; ++ unsigned long r15; ++ unsigned long r1; ++ unsigned long r2; ++ unsigned long r3; ++ unsigned long r4; ++ unsigned long r5; ++ unsigned long r6; ++ unsigned long r7; ++ unsigned long orig_r2; ++ unsigned long ra; ++ unsigned long fp; ++ unsigned long sp; ++ unsigned long gp; ++ unsigned long estatus; ++ unsigned long status_extension; ++ unsigned long ea; ++}; ++ ++ ++/* ++ * This is the extended stack used by signal handlers and the context ++ * switcher: it's pushed after the normal "struct pt_regs". ++ */ ++struct switch_stack { ++ unsigned long r16; ++ unsigned long r17; ++ unsigned long r18; ++ unsigned long r19; ++ unsigned long r20; ++ unsigned long r21; ++ unsigned long r22; ++ unsigned long r23; ++ unsigned long fp; ++ unsigned long gp; ++ unsigned long ra; ++}; ++ ++#ifdef __KERNEL__ ++/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ ++#define PTRACE_GETREGS 12 ++#define PTRACE_SETREGS 13 ++#ifdef CONFIG_FPU ++#define PTRACE_GETFPREGS 14 ++#define PTRACE_SETFPREGS 15 ++#endif ++ ++#ifndef PS_S ++#define PS_S (0x00000001) ++#endif ++#ifndef PS_T ++#define PS_T (0x00000002) ++#endif ++ ++#define user_mode(regs) (!((regs)->status_extension & PS_S)) ++#define instruction_pointer(regs) ((regs)->ra) ++#define profile_pc(regs) instruction_pointer(regs) ++extern void show_regs(struct pt_regs *); ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASSEMBLY__ */ ++#endif /* _NIOS2NOMMU_PTRACE_H */ +diff --git a/include/asm-nios2nommu/resource.h b/include/asm-nios2nommu/resource.h +new file mode 100644 +index 0000000..9c2499a +--- /dev/null ++++ b/include/asm-nios2nommu/resource.h +@@ -0,0 +1,6 @@ ++#ifndef __ASM_SH_RESOURCE_H ++#define __ASM_SH_RESOURCE_H ++ ++#include ++ ++#endif /* __ASM_SH_RESOURCE_H */ +diff --git a/include/asm-nios2nommu/rmap.h b/include/asm-nios2nommu/rmap.h +new file mode 100644 +index 0000000..b3664cc +--- /dev/null ++++ b/include/asm-nios2nommu/rmap.h +@@ -0,0 +1,2 @@ ++/* Do not need anything here */ ++ +diff --git a/include/asm-nios2nommu/scatterlist.h b/include/asm-nios2nommu/scatterlist.h +new file mode 100644 +index 0000000..20898e2 +--- /dev/null ++++ b/include/asm-nios2nommu/scatterlist.h +@@ -0,0 +1,13 @@ ++#ifndef __ASM_SH_SCATTERLIST_H ++#define __ASM_SH_SCATTERLIST_H ++ ++struct scatterlist { ++ struct page * page; /* Location for highmem page, if any */ ++ unsigned int offset;/* for highmem, page offset */ ++ dma_addr_t dma_address; ++ unsigned int length; ++}; ++ ++#define ISA_DMA_THRESHOLD (0xffffffff) ++ ++#endif /* !(__ASM_SH_SCATTERLIST_H) */ +diff --git a/include/asm-nios2nommu/sections.h b/include/asm-nios2nommu/sections.h +new file mode 100644 +index 0000000..61b3f71 +--- /dev/null ++++ b/include/asm-nios2nommu/sections.h +@@ -0,0 +1,30 @@ ++#ifndef _NIOS2NOMMU_SECTIONS_H ++#define _NIOS2NOMMU_SECTIONS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sections.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _NIOS2NOMMU_SECTIONS_H */ +diff --git a/include/asm-nios2nommu/segment.h b/include/asm-nios2nommu/segment.h +new file mode 100644 +index 0000000..25871b3 +--- /dev/null ++++ b/include/asm-nios2nommu/segment.h +@@ -0,0 +1,75 @@ ++#ifndef _NIOS2NOMMU_SEGMENT_H ++#define _NIOS2NOMMU_SEGMENT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/segment.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* define constants */ ++/* Address spaces (FC0-FC2) */ ++#define USER_DATA (1) ++#ifndef __USER_DS ++#define __USER_DS (USER_DATA) ++#endif ++#define USER_PROGRAM (2) ++#define SUPER_DATA (5) ++#ifndef __KERNEL_DS ++#define __KERNEL_DS (SUPER_DATA) ++#endif ++#define SUPER_PROGRAM (6) ++#define CPU_SPACE (7) ++ ++#ifndef __ASSEMBLY__ ++ ++typedef struct { ++ unsigned long seg; ++} mm_segment_t; ++ ++#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) ++#define USER_DS MAKE_MM_SEG(__USER_DS) ++#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS) ++ ++/* ++ * Get/set the SFC/DFC registers for MOVES instructions ++ */ ++ ++static inline mm_segment_t get_fs(void) ++{ ++ return USER_DS; ++} ++ ++static inline mm_segment_t get_ds(void) ++{ ++ /* return the supervisor data space code */ ++ return KERNEL_DS; ++} ++ ++static inline void set_fs(mm_segment_t val) ++{ ++} ++ ++#define segment_eq(a,b) ((a).seg == (b).seg) ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* _NIOS2NOMMU_SEGMENT_H */ +diff --git a/include/asm-nios2nommu/semaphore-helper.h b/include/asm-nios2nommu/semaphore-helper.h +new file mode 100644 +index 0000000..a8905d1 +--- /dev/null ++++ b/include/asm-nios2nommu/semaphore-helper.h +@@ -0,0 +1,99 @@ ++#ifndef _NIOS2NOMMU_SEMAPHORE_HELPER_H ++#define _NIOS2NOMMU_SEMAPHORE_HELPER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/semaphore.h ++ * ++ * SMP- and interrupt-safe semaphores helper functions. ++ * ++ * Derived from M68knommu ++ * ++ * (C) Copyright 1996 Linus Torvalds ++ * m68k version by Andreas Schwab ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++/* ++ * These two _must_ execute atomically wrt each other. ++ */ ++static inline void wake_one_more(struct semaphore * sem) ++{ ++ atomic_inc(&sem->waking); ++} ++ ++static inline int waking_non_zero(struct semaphore *sem) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 0; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 1; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++/* ++ * waking_non_zero_interruptible: ++ * 1 got the lock ++ * 0 go to sleep ++ * -EINTR interrupted ++ */ ++static inline int waking_non_zero_interruptible(struct semaphore *sem, ++ struct task_struct *tsk) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 0; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 1; ++ } else if (signal_pending(tsk)) { ++ atomic_inc(&sem->count); ++ ret = -EINTR; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++/* ++ * waking_non_zero_trylock: ++ * 1 failed to lock ++ * 0 got the lock ++ */ ++static inline int waking_non_zero_trylock(struct semaphore *sem) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 1; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 0; ++ } else ++ atomic_inc(&sem->count); ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++#endif +diff --git a/include/asm-nios2nommu/semaphore.h b/include/asm-nios2nommu/semaphore.h +new file mode 100644 +index 0000000..8d66c77 +--- /dev/null ++++ b/include/asm-nios2nommu/semaphore.h +@@ -0,0 +1,152 @@ ++#ifndef _NIOS2NOMMU_SEMAPHORE_H ++#define _NIOS2NOMMU_SEMAPHORE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/semaphore.h ++ * ++ * Interrupt-safe semaphores.. ++ * ++ * Derived from M68knommu ++ * ++ * (C) Copyright 1996 Linus Torvalds ++ * m68k version by Andreas Schwab ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#define RW_LOCK_BIAS 0x01000000 ++ ++#ifndef __ASSEMBLY__ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct semaphore { ++ atomic_t count; ++ atomic_t waking; ++ wait_queue_head_t wait; ++}; ++ ++#define __SEMAPHORE_INITIALIZER(name, n) \ ++{ \ ++ .count = ATOMIC_INIT(n), \ ++ .waking = ATOMIC_INIT(0), \ ++ .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ ++} ++ ++#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) ++ ++#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) ++#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) ++ ++static inline void sema_init (struct semaphore *sem, int val) ++{ ++ *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); ++} ++ ++static inline void init_MUTEX (struct semaphore *sem) ++{ ++ sema_init(sem, 1); ++} ++ ++static inline void init_MUTEX_LOCKED (struct semaphore *sem) ++{ ++ sema_init(sem, 0); ++} ++ ++asmlinkage void __down_failed(void /* special register calling convention */); ++asmlinkage int __down_failed_interruptible(void /* params in registers */); ++asmlinkage int __down_failed_trylock(void /* params in registers */); ++asmlinkage void __up_wakeup(void /* special register calling convention */); ++ ++asmlinkage void __down(struct semaphore * sem); ++asmlinkage int __down_interruptible(struct semaphore * sem); ++asmlinkage int __down_trylock(struct semaphore * sem); ++asmlinkage void __up(struct semaphore * sem); ++ ++extern spinlock_t semaphore_wake_lock; ++ ++/* ++ * This is ugly, but we want the default case to fall through. ++ * "down_failed" is a special asm handler that calls the C ++ * routine that actually waits. ++ */ ++static inline void down(struct semaphore * sem) ++{ ++ might_sleep(); ++ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ if (atomic_dec_return(&sem->count) < 0) ++ __down(sem); ++ #endif ++} ++ ++static inline int down_interruptible(struct semaphore * sem) ++{ ++ int ret = 0; ++ ++ ++ might_sleep(); ++ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ if(atomic_dec_return(&sem->count) < 0) ++ ret = __down_interruptible(sem); ++ return ret; ++ #endif ++} ++ ++static inline int down_trylock(struct semaphore * sem) ++{ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ int ret = 0; ++ ++ if (atomic_dec_return (&sem->count) < 0) ++ ret = __down_trylock(sem); ++ return ret; ++ #endif ++} ++ ++/* ++ * Note! This is subtle. We jump to wake people up only if ++ * the semaphore was negative (== somebody was waiting on it). ++ * The default case (no contention) will result in NO ++ * jumps for both down() and up(). ++ */ ++static inline void up(struct semaphore * sem) ++{ ++ #if 0 ++ ...Nios2 has no atomic "increment memory".... ++ #else ++ if (atomic_inc_return(&sem->count) <= 0) ++ __up(sem); ++ #endif ++} ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif +diff --git a/include/asm-nios2nommu/sembuf.h b/include/asm-nios2nommu/sembuf.h +new file mode 100644 +index 0000000..e530cab +--- /dev/null ++++ b/include/asm-nios2nommu/sembuf.h +@@ -0,0 +1,48 @@ ++#ifndef _NIOS_SEMBUF_H ++#define _NIOS_SEMBUF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sembuf.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct semid64_ds { ++ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ ++ __kernel_time_t sem_otime; /* last semop time */ ++ unsigned long __unused1; ++ __kernel_time_t sem_ctime; /* last change time */ ++ unsigned long __unused2; ++ unsigned long sem_nsems; /* no. of semaphores in array */ ++ unsigned long __unused3; ++ unsigned long __unused4; ++}; ++ ++#endif /* _NIOS_SEMBUF_H */ +diff --git a/include/asm-nios2nommu/setup.h b/include/asm-nios2nommu/setup.h +new file mode 100644 +index 0000000..c5a655a +--- /dev/null ++++ b/include/asm-nios2nommu/setup.h +@@ -0,0 +1,31 @@ ++/* Copied from i386 port. ++ * Just a place holder. We don't want to have to test x86 before ++ * we include stuff ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_SETUP_H ++#define _NIOS2_SETUP_H ++ ++#define COMMAND_LINE_SIZE 512 ++ ++#endif /* _NIOS2_SETUP_H */ +diff --git a/include/asm-nios2nommu/shmbuf.h b/include/asm-nios2nommu/shmbuf.h +new file mode 100644 +index 0000000..f6e6e7d +--- /dev/null ++++ b/include/asm-nios2nommu/shmbuf.h +@@ -0,0 +1,64 @@ ++#ifndef _NIOS_SHMBUF_H ++#define _NIOS_SHMBUF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/shmbuf.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct shmid64_ds { ++ struct ipc64_perm shm_perm; /* operation perms */ ++ size_t shm_segsz; /* size of segment (bytes) */ ++ __kernel_time_t shm_atime; /* last attach time */ ++ unsigned long __unused1; ++ __kernel_time_t shm_dtime; /* last detach time */ ++ unsigned long __unused2; ++ __kernel_time_t shm_ctime; /* last change time */ ++ unsigned long __unused3; ++ __kernel_pid_t shm_cpid; /* pid of creator */ ++ __kernel_pid_t shm_lpid; /* pid of last operator */ ++ unsigned long shm_nattch; /* no. of current attaches */ ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++struct shminfo64 { ++ unsigned long shmmax; ++ unsigned long shmmin; ++ unsigned long shmmni; ++ unsigned long shmseg; ++ unsigned long shmall; ++ unsigned long __unused1; ++ unsigned long __unused2; ++ unsigned long __unused3; ++ unsigned long __unused4; ++}; ++ ++#endif /* _NIOS_SHMBUF_H */ +diff --git a/include/asm-nios2nommu/shmparam.h b/include/asm-nios2nommu/shmparam.h +new file mode 100644 +index 0000000..94efe2d +--- /dev/null ++++ b/include/asm-nios2nommu/shmparam.h +@@ -0,0 +1,30 @@ ++#ifndef __NIOS2NOMMU_SHMPARAM_H__ ++#define __NIOS2NOMMU_SHMPARAM_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/shmparam.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ ++ ++#endif /* __NIOS2NOMMU_SHMPARAM_H__ */ +diff --git a/include/asm-nios2nommu/sigcontext.h b/include/asm-nios2nommu/sigcontext.h +new file mode 100644 +index 0000000..7321e7d +--- /dev/null ++++ b/include/asm-nios2nommu/sigcontext.h +@@ -0,0 +1,35 @@ ++/* ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2NOMMU_SIGCONTEXT_H ++#define _ASM_NIOS2NOMMU_SIGCONTEXT_H ++ ++#include ++ ++struct sigcontext { ++ struct pt_regs regs; ++ unsigned long sc_mask; /* old sigmask */ ++}; ++ ++#endif +diff --git a/include/asm-nios2nommu/siginfo.h b/include/asm-nios2nommu/siginfo.h +new file mode 100644 +index 0000000..c047c0b +--- /dev/null ++++ b/include/asm-nios2nommu/siginfo.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_SIGINFO_H ++#define _NIOS2NOMMU_SIGINFO_H ++ ++#include ++ ++#endif +diff --git a/include/asm-nios2nommu/signal.h b/include/asm-nios2nommu/signal.h +new file mode 100644 +index 0000000..c86a20c +--- /dev/null ++++ b/include/asm-nios2nommu/signal.h +@@ -0,0 +1,181 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_SIGNAL_H ++#define _NIOS2_SIGNAL_H ++ ++#include ++ ++/* Avoid too many header ordering problems. */ ++struct siginfo; ++ ++#ifdef __KERNEL__ ++/* Most things should be clean enough to redefine this at will, if care ++ is taken to make libc match. */ ++ ++#define _NSIG 64 ++#define _NSIG_BPW 32 ++#define _NSIG_WORDS (_NSIG / _NSIG_BPW) ++ ++typedef unsigned long old_sigset_t; /* at least 32 bits */ ++ ++typedef struct { ++ unsigned long sig[_NSIG_WORDS]; ++} sigset_t; ++ ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++#define NSIG 32 ++typedef unsigned long sigset_t; ++ ++#endif /* __KERNEL__ */ ++ ++#define SIGHUP 1 ++#define SIGINT 2 ++#define SIGQUIT 3 ++#define SIGILL 4 ++#define SIGTRAP 5 ++#define SIGABRT 6 ++#define SIGIOT 6 ++#define SIGBUS 7 ++#define SIGFPE 8 ++#define SIGKILL 9 ++#define SIGUSR1 10 ++#define SIGSEGV 11 ++#define SIGUSR2 12 ++#define SIGPIPE 13 ++#define SIGALRM 14 ++#define SIGTERM 15 ++#define SIGSTKFLT 16 ++#define SIGCHLD 17 ++#define SIGCONT 18 ++#define SIGSTOP 19 ++#define SIGTSTP 20 ++#define SIGTTIN 21 ++#define SIGTTOU 22 ++#define SIGURG 23 ++#define SIGXCPU 24 ++#define SIGXFSZ 25 ++#define SIGVTALRM 26 ++#define SIGPROF 27 ++#define SIGWINCH 28 ++#define SIGIO 29 ++#define SIGPOLL SIGIO ++/* ++#define SIGLOST 29 ++*/ ++#define SIGPWR 30 ++#define SIGSYS 31 ++#define SIGUNUSED 31 ++ ++/* These should not be considered constants from userland. */ ++#define SIGRTMIN 32 ++#define SIGRTMAX _NSIG ++ ++/* ++ * SA_FLAGS values: ++ * ++ * SA_ONSTACK indicates that a registered stack_t will be used. ++ * SA_RESTART flag to get restarting signals (which were the default long ago) ++ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. ++ * SA_RESETHAND clears the handler when the signal is delivered. ++ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. ++ * SA_NODEFER prevents the current signal from being masked in the handler. ++ * ++ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single ++ * Unix names RESETHAND and NODEFER respectively. ++ */ ++#define SA_NOCLDSTOP 0x00000001 ++#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ ++#define SA_SIGINFO 0x00000004 ++#define SA_ONSTACK 0x08000000 ++#define SA_RESTART 0x10000000 ++#define SA_NODEFER 0x40000000 ++#define SA_RESETHAND 0x80000000 ++ ++#define SA_NOMASK SA_NODEFER ++#define SA_ONESHOT SA_RESETHAND ++ ++/* ++ * sigaltstack controls ++ */ ++#define SS_ONSTACK 1 ++#define SS_DISABLE 2 ++ ++#define MINSIGSTKSZ 2048 ++#define SIGSTKSZ 8192 ++ ++#include ++ ++#ifdef __KERNEL__ ++struct old_sigaction { ++ __sighandler_t sa_handler; ++ old_sigset_t sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++}; ++ ++struct sigaction { ++ __sighandler_t sa_handler; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++ sigset_t sa_mask; /* mask last for extensibility */ ++}; ++ ++struct k_sigaction { ++ struct sigaction sa; ++}; ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++struct sigaction { ++ union { ++ __sighandler_t _sa_handler; ++ void (*_sa_sigaction)(int, struct siginfo *, void *); ++ } _u; ++ sigset_t sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++}; ++ ++#define sa_handler _u._sa_handler ++#define sa_sigaction _u._sa_sigaction ++ ++#endif /* __KERNEL__ */ ++ ++typedef struct sigaltstack { ++ void *ss_sp; ++ int ss_flags; ++ size_t ss_size; ++} stack_t; ++ ++#ifdef __KERNEL__ ++ ++#include ++#undef __HAVE_ARCH_SIG_BITOPS ++ ++#define ptrace_signal_deliver(regs, cookie) do { } while (0) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS2_SIGNAL_H */ +diff --git a/include/asm-nios2nommu/smp.h b/include/asm-nios2nommu/smp.h +new file mode 100644 +index 0000000..fb23307 +--- /dev/null ++++ b/include/asm-nios2nommu/smp.h +@@ -0,0 +1,32 @@ ++#ifndef __ASM_SMP_H ++#define __ASM_SMP_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/smp.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifdef CONFIG_SMP ++#error SMP not supported ++#endif ++ ++#endif +diff --git a/include/asm-nios2nommu/socket.h b/include/asm-nios2nommu/socket.h +new file mode 100644 +index 0000000..5452e2b +--- /dev/null ++++ b/include/asm-nios2nommu/socket.h +@@ -0,0 +1,79 @@ ++#ifndef _ASM_SOCKET_H ++#define _ASM_SOCKET_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/socket.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* For setsockopt(2) */ ++#define SOL_SOCKET 1 ++ ++#define SO_DEBUG 1 ++#define SO_REUSEADDR 2 ++#define SO_TYPE 3 ++#define SO_ERROR 4 ++#define SO_DONTROUTE 5 ++#define SO_BROADCAST 6 ++#define SO_SNDBUF 7 ++#define SO_RCVBUF 8 ++#define SO_SNDBUFFORCE 32 ++#define SO_RCVBUFFORCE 33 ++#define SO_KEEPALIVE 9 ++#define SO_OOBINLINE 10 ++#define SO_NO_CHECK 11 ++#define SO_PRIORITY 12 ++#define SO_LINGER 13 ++#define SO_BSDCOMPAT 14 ++/* To add :#define SO_REUSEPORT 15 */ ++#define SO_PASSCRED 16 ++#define SO_PEERCRED 17 ++#define SO_RCVLOWAT 18 ++#define SO_SNDLOWAT 19 ++#define SO_RCVTIMEO 20 ++#define SO_SNDTIMEO 21 ++ ++/* Security levels - as per NRL IPv6 - don't actually do anything */ ++#define SO_SECURITY_AUTHENTICATION 22 ++#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 ++#define SO_SECURITY_ENCRYPTION_NETWORK 24 ++ ++#define SO_BINDTODEVICE 25 ++ ++/* Socket filtering */ ++#define SO_ATTACH_FILTER 26 ++#define SO_DETACH_FILTER 27 ++ ++#define SO_PEERNAME 28 ++#define SO_TIMESTAMP 29 ++#define SCM_TIMESTAMP SO_TIMESTAMP ++ ++#define SO_ACCEPTCONN 30 ++ ++#define SO_PEERSEC 31 /* ;dgt2;tmp; */ ++#define SO_PASSSEC 34 ++#define SO_TIMESTAMPNS 35 ++#define SCM_TIMESTAMPNS SO_TIMESTAMPNS ++ ++#endif /* _ASM_SOCKET_H */ +diff --git a/include/asm-nios2nommu/sockios.h b/include/asm-nios2nommu/sockios.h +new file mode 100644 +index 0000000..c604aa7 +--- /dev/null ++++ b/include/asm-nios2nommu/sockios.h +@@ -0,0 +1,39 @@ ++#ifndef _ASM_NIOS_SOCKIOS_H ++#define _ASM_NIOS_SOCKIOS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sockios.h ++ * ++ * Socket-level I/O control calls. ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define FIOSETOWN 0x8901 ++#define SIOCSPGRP 0x8902 ++#define FIOGETOWN 0x8903 ++#define SIOCGPGRP 0x8904 ++#define SIOCATMARK 0x8905 ++#define SIOCGSTAMP 0x8906 /* Get stamp */ ++#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ ++ ++#endif /* !(_ASM_NIOS_SOCKIOS_H) */ ++ +diff --git a/include/asm-nios2nommu/spi.h b/include/asm-nios2nommu/spi.h +new file mode 100644 +index 0000000..6efb82c +--- /dev/null ++++ b/include/asm-nios2nommu/spi.h +@@ -0,0 +1,92 @@ ++#ifndef _ASM_SPI_H_ ++#define _ASM_SPI_H_ 1 ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/spi.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++int register_NIOS_SPI( void ); ++void unregister_NIOS_SPI( void ); ++ ++#if defined(MODULE) ++void cleanup_module( void ); ++int init_module( void ); ++#endif ++ ++#if defined(__KERNEL__) ++int spi_reset ( void ); ++#endif ++ ++ ++#define clockCS 0x01 ++#define temperatureCS 0x02 ++ ++#define clock_read_base 0x00 ++#define clock_write_base 0x80 ++#define clock_read_control 0x0F ++#define clock_read_trickle 0x11 ++ ++#define clock_read_sec 0x00 ++#define clock_read_min 0x01 ++#define clock_read_hour 0x02 ++#define clock_read_day 0x03 ++#define clock_read_date 0x04 ++#define clock_read_month 0x05 ++#define clock_read_year 0x06 ++ ++#define clock_write_control 0x8F ++#define clock_write_trickle 0x91 ++#define clock_write_sec 0x80 ++#define clock_write_min 0x81 ++#define clock_write_hour 0x82 ++#define clock_write_day 0x83 ++#define clock_write_date 0x84 ++#define clock_write_month 0x85 ++#define clock_write_year 0x86 ++ ++#define clock_write_ram_start 0xA0 ++#define clock_write_ram_end 0x100 ++#define clock_read_ram_start 0x20 ++#define clock_read_ram_end 0x80 ++ ++ ++#define clock_sec_def 0x11 ++#define clock_min_def 0x59 ++#define clock_hour_def 0x71 ++#define clock_day_def 0x00 ++#define clock_date_def 0x20 ++#define clock_month_def 0x12 ++#define clock_year_def 0x34 ++ ++#define temp_read_base 0x00 ++#define temp_write_base 0x80 ++#define temp_read_control 0x00 ++#define temp_write_control 0x80 ++#define temp_read_msb 0x02 ++#define temp_read_lsb 0x01 ++ ++#define MAX_TEMP_VAR 10 ++ ++#endif /*_ASM_SPI_H_*/ +diff --git a/include/asm-nios2nommu/spi_struct.h b/include/asm-nios2nommu/spi_struct.h +new file mode 100644 +index 0000000..c7b2faf +--- /dev/null ++++ b/include/asm-nios2nommu/spi_struct.h +@@ -0,0 +1,57 @@ ++// SPI Registers ++typedef volatile struct ++ { ++ int np_spirxdata; // Read-only, 1-16 bit ++ int np_spitxdata; // Write-only, same width as rxdata ++ int np_spistatus; // Read-only, 9-bit ++ int np_spicontrol; // Read/Write, 9-bit ++ int np_spireserved; // reserved ++ int np_spislaveselect; // Read/Write, 1-16 bit, master only ++ int np_spiendofpacket; // Read/write, same width as txdata, rxdata. ++ } np_spi; ++ ++// SPI Status Register Bits ++enum ++ { ++ np_spistatus_eop_bit = 9, ++ np_spistatus_e_bit = 8, ++ np_spistatus_rrdy_bit = 7, ++ np_spistatus_trdy_bit = 6, ++ np_spistatus_tmt_bit = 5, ++ np_spistatus_toe_bit = 4, ++ np_spistatus_roe_bit = 3, ++ ++ np_spistatus_eop_mask = (1 << 9), ++ np_spistatus_e_mask = (1 << 8), ++ np_spistatus_rrdy_mask = (1 << 7), ++ np_spistatus_trdy_mask = (1 << 6), ++ np_spistatus_tmt_mask = (1 << 5), ++ np_spistatus_toe_mask = (1 << 4), ++ np_spistatus_roe_mask = (1 << 3), ++ }; ++ ++// SPI Control Register Bits ++enum ++ { ++ np_spicontrol_sso_bit = 10, ++ np_spicontrol_ieop_bit = 9, ++ np_spicontrol_ie_bit = 8, ++ np_spicontrol_irrdy_bit = 7, ++ np_spicontrol_itrdy_bit = 6, ++ np_spicontrol_itoe_bit = 4, ++ np_spicontrol_iroe_bit = 3, ++ ++ np_spicontrol_sso_mask = (1 << 10), ++ np_spicontrol_ieop_mask = (1 << 9), ++ np_spicontrol_ie_mask = (1 << 8), ++ np_spicontrol_irrdy_mask = (1 << 7), ++ np_spicontrol_itrdy_mask = (1 << 6), ++ np_spicontrol_itoe_mask = (1 << 4), ++ np_spicontrol_iroe_mask = (1 << 3), ++ }; ++ ++// SPI Routines. ++int nr_spi_rxchar(np_spi *spiBase); ++int nr_spi_txchar(int i, np_spi *spiBase); ++ ++ +diff --git a/include/asm-nios2nommu/spinlock.h b/include/asm-nios2nommu/spinlock.h +new file mode 100644 +index 0000000..f518755 +--- /dev/null ++++ b/include/asm-nios2nommu/spinlock.h +@@ -0,0 +1,30 @@ ++#ifndef __NIOS_SPINLOCK_H ++#define __NIOS_SPINLOCK_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/spinlock.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#error "Nios doesn't do SMP yet" ++ ++#endif +diff --git a/include/asm-nios2nommu/stat.h b/include/asm-nios2nommu/stat.h +new file mode 100644 +index 0000000..bd27a97 +--- /dev/null ++++ b/include/asm-nios2nommu/stat.h +@@ -0,0 +1,102 @@ ++#ifndef _ASMNIOS2NOMMU_STAT_H ++#define _ASMNIOS2NOMMU_STAT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/stat.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++struct __old_kernel_stat { ++ unsigned short st_dev; ++ unsigned short st_ino; ++ unsigned short st_mode; ++ unsigned short st_nlink; ++ unsigned short st_uid; ++ unsigned short st_gid; ++ unsigned short st_rdev; ++ unsigned long st_size; ++ unsigned long st_atime; ++ unsigned long st_mtime; ++ unsigned long st_ctime; ++}; ++ ++struct stat { ++ unsigned short st_dev; ++ unsigned short __pad1; ++ unsigned long st_ino; ++ unsigned short st_mode; ++ unsigned short st_nlink; ++ unsigned short st_uid; ++ unsigned short st_gid; ++ unsigned short st_rdev; ++ unsigned short __pad2; ++ unsigned long st_size; ++ unsigned long st_blksize; ++ unsigned long st_blocks; ++ unsigned long st_atime; ++ unsigned long __unused1; ++ unsigned long st_mtime; ++ unsigned long __unused2; ++ unsigned long st_ctime; ++ unsigned long __unused3; ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++/* This matches struct stat64 in glibc2.1, hence the absolutely ++ * insane amounts of padding around dev_t's. ++ */ ++struct stat64 { ++ unsigned long long st_dev; ++ unsigned char __pad1[4]; ++ ++#define STAT64_HAS_BROKEN_ST_INO 1 ++ unsigned long __st_ino; ++ ++ unsigned int st_mode; ++ unsigned int st_nlink; ++ ++ unsigned long st_uid; ++ unsigned long st_gid; ++ ++ unsigned long long st_rdev; ++ unsigned char __pad3[4]; ++ ++ long long st_size; ++ unsigned long st_blksize; ++ ++ unsigned long __pad4; /* future possible st_blocks high bits */ ++ unsigned long st_blocks; /* Number 512-byte blocks allocated. */ ++ ++ unsigned long st_atime; ++ unsigned long st_atime_nsec; ++ ++ unsigned long st_mtime; ++ unsigned long st_mtime_nsec; ++ ++ unsigned long st_ctime; ++ unsigned long st_ctime_nsec; ++ ++ unsigned long long st_ino; ++}; ++ ++#endif +diff --git a/include/asm-nios2nommu/statfs.h b/include/asm-nios2nommu/statfs.h +new file mode 100644 +index 0000000..c4637f6 +--- /dev/null ++++ b/include/asm-nios2nommu/statfs.h +@@ -0,0 +1,30 @@ ++#ifndef _NIOS2NOMMU_STATFS_H ++#define _NIOS2NOMMU_STATFS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/statfs.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _NIOS2NOMMU_STATFS_H */ +diff --git a/include/asm-nios2nommu/string.h b/include/asm-nios2nommu/string.h +new file mode 100644 +index 0000000..7e39479 +--- /dev/null ++++ b/include/asm-nios2nommu/string.h +@@ -0,0 +1,45 @@ ++#ifndef __NIOS_STRING_H__ ++#define __NIOS_STRING_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/string.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifdef __KERNEL__ /* only set these up for kernel code */ ++ ++#define __HAVE_ARCH_MEMMOVE ++void * memmove(void * d, const void * s, size_t count); ++#define __HAVE_ARCH_MEMCPY ++extern void * memcpy(void *d, const void *s, size_t count); ++#define __HAVE_ARCH_MEMSET ++extern void * memset(void * s,int c,size_t count); ++ ++#if 0 ++#define __HAVE_ARCH_BCOPY ++#define __HAVE_ARCH_STRLEN ++#endif ++ ++#endif /* KERNEL */ ++ ++#endif /* !(__NIOS_STRING_H__) */ +diff --git a/include/asm-nios2nommu/system.h b/include/asm-nios2nommu/system.h +new file mode 100644 +index 0000000..7c35af0 +--- /dev/null ++++ b/include/asm-nios2nommu/system.h +@@ -0,0 +1,172 @@ ++/* ++ * Taken from the m68k. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_SYSTEM_H ++#define _NIOS2NOMMU_SYSTEM_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * switch_to(n) should switch tasks to task ptr, first checking that ++ * ptr isn't the current task, in which case it does nothing. This ++ * also clears the TS-flag if the task we switched to has used the ++ * math co-processor latest. ++ */ ++ ++/* ++ */ ++asmlinkage void resume(void); ++#define switch_to(prev,next,last) \ ++{ \ ++ void *_last; \ ++ __asm__ __volatile__( \ ++ "mov r4, %1\n" \ ++ "mov r5, %2\n" \ ++ "call resume\n" \ ++ "mov %0,r4\n" \ ++ : "=r" (_last) \ ++ : "r" (prev), "r" (next) \ ++ : "r4","r5","r7","r8","ra"); \ ++ (last) = _last; \ ++} ++ ++#define local_irq_enable() __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "ori r8, r8, 1\n" \ ++ "wrctl status, r8\n" \ ++ : : : "r8") ++ ++#define local_irq_disable() __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "andi r8, r8, 0xfffe\n" \ ++ "wrctl status, r8\n" \ ++ : : : "r8") ++ ++#define local_save_flags(x) __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "mov %0, r8\n" \ ++ :"=r" (x) : : "r8", "memory") ++ ++#define local_irq_restore(x) __asm__ __volatile__ ( \ ++ "mov r8, %0\n" \ ++ "wrctl status, r8\n" \ ++ : :"r" (x) : "memory") ++ ++/* For spinlocks etc */ ++#define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } while (0) ++ ++#define irqs_disabled() \ ++({ \ ++ unsigned long flags; \ ++ local_save_flags(flags); \ ++ ((flags & NIOS2_STATUS_PIE_MSK) == 0x0); \ ++}) ++ ++#define iret() __asm__ __volatile__ ("eret": : :"memory", "ea") ++ ++/* ++ * Force strict CPU ordering. ++ * Not really required on m68k... ++ */ ++#define nop() asm volatile ("nop"::) ++#define mb() asm volatile ("" : : :"memory") ++#define rmb() asm volatile ("" : : :"memory") ++#define wmb() asm volatile ("" : : :"memory") ++#define set_rmb(var, value) do { xchg(&var, value); } while (0) ++#define set_mb(var, value) set_rmb(var, value) ++#define set_wmb(var, value) do { var = value; wmb(); } while (0) ++ ++#ifdef CONFIG_SMP ++#define smp_mb() mb() ++#define smp_rmb() rmb() ++#define smp_wmb() wmb() ++#define smp_read_barrier_depends() read_barrier_depends() ++#else ++#define smp_mb() barrier() ++#define smp_rmb() barrier() ++#define smp_wmb() barrier() ++#define smp_read_barrier_depends() do { } while(0) ++#endif ++ ++#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) ++#define tas(ptr) (xchg((ptr),1)) ++ ++struct __xchg_dummy { unsigned long a[100]; }; ++#define __xg(x) ((volatile struct __xchg_dummy *)(x)) ++ ++static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) ++{ ++ unsigned long tmp, flags; ++ ++ local_irq_save(flags); ++ ++ switch (size) { ++ case 1: ++ __asm__ __volatile__( \ ++ "ldb %0, %2\n" \ ++ "stb %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ case 2: ++ __asm__ __volatile__( \ ++ "ldh %0, %2\n" \ ++ "sth %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ case 4: ++ __asm__ __volatile__( \ ++ "ldw %0, %2\n" \ ++ "stw %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ } ++ local_irq_restore(flags); ++ return tmp; ++} ++ ++/* ++ * Atomic compare and exchange. Compare OLD with MEM, if identical, ++ * store NEW in MEM. Return the initial value in MEM. Success is ++ * indicated by comparing RETURN with OLD. ++ */ ++#define __HAVE_ARCH_CMPXCHG 1 ++ ++static __inline__ unsigned long ++cmpxchg(volatile int *p, int old, int new) ++{ ++ unsigned long flags; ++ int prev; ++ ++ local_irq_save(flags); ++ if ((prev = *p) == old) ++ *p = new; ++ local_irq_restore(flags); ++ return(prev); ++} ++ ++#endif /* _NIOS2NOMMU_SYSTEM_H */ +diff --git a/include/asm-nios2nommu/termbits.h b/include/asm-nios2nommu/termbits.h +new file mode 100644 +index 0000000..74ef61d +--- /dev/null ++++ b/include/asm-nios2nommu/termbits.h +@@ -0,0 +1,210 @@ ++#ifndef __ARCH_NIOS_TERMBITS_H__ ++#define __ARCH_NIOS_TERMBITS_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/termbits.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++typedef unsigned char cc_t; ++typedef unsigned int speed_t; ++typedef unsigned int tcflag_t; ++ ++#define NCCS 19 ++struct termios { ++ tcflag_t c_iflag; /* input mode flags */ ++ tcflag_t c_oflag; /* output mode flags */ ++ tcflag_t c_cflag; /* control mode flags */ ++ tcflag_t c_lflag; /* local mode flags */ ++ cc_t c_line; /* line discipline */ ++ cc_t c_cc[NCCS]; /* control characters */ ++}; ++ ++struct ktermios { ++ tcflag_t c_iflag; /* input mode flags */ ++ tcflag_t c_oflag; /* output mode flags */ ++ tcflag_t c_cflag; /* control mode flags */ ++ tcflag_t c_lflag; /* local mode flags */ ++ cc_t c_line; /* line discipline */ ++ cc_t c_cc[NCCS]; /* control characters */ ++ speed_t c_ispeed; /* input speed */ ++ speed_t c_ospeed; /* output speed */ ++}; ++ ++/* c_cc characters */ ++#define VINTR 0 ++#define VQUIT 1 ++#define VERASE 2 ++#define VKILL 3 ++#define VEOF 4 ++#define VTIME 5 ++#define VMIN 6 ++#define VSWTC 7 ++#define VSTART 8 ++#define VSTOP 9 ++#define VSUSP 10 ++#define VEOL 11 ++#define VREPRINT 12 ++#define VDISCARD 13 ++#define VWERASE 14 ++#define VLNEXT 15 ++#define VEOL2 16 ++ ++ ++/* c_iflag bits */ ++#define IGNBRK 0000001 ++#define BRKINT 0000002 ++#define IGNPAR 0000004 ++#define PARMRK 0000010 ++#define INPCK 0000020 ++#define ISTRIP 0000040 ++#define INLCR 0000100 ++#define IGNCR 0000200 ++#define ICRNL 0000400 ++#define IUCLC 0001000 ++#define IXON 0002000 ++#define IXANY 0004000 ++#define IXOFF 0010000 ++#define IMAXBEL 0020000 ++#define IUTF8 0040000 ++ ++/* c_oflag bits */ ++#define OPOST 0000001 ++#define OLCUC 0000002 ++#define ONLCR 0000004 ++#define OCRNL 0000010 ++#define ONOCR 0000020 ++#define ONLRET 0000040 ++#define OFILL 0000100 ++#define OFDEL 0000200 ++#define NLDLY 0000400 ++#define NL0 0000000 ++#define NL1 0000400 ++#define CRDLY 0003000 ++#define CR0 0000000 ++#define CR1 0001000 ++#define CR2 0002000 ++#define CR3 0003000 ++#define TABDLY 0014000 ++#define TAB0 0000000 ++#define TAB1 0004000 ++#define TAB2 0010000 ++#define TAB3 0014000 ++#define XTABS 0014000 ++#define BSDLY 0020000 ++#define BS0 0000000 ++#define BS1 0020000 ++#define VTDLY 0040000 ++#define VT0 0000000 ++#define VT1 0040000 ++#define FFDLY 0100000 ++#define FF0 0000000 ++#define FF1 0100000 ++ ++/* c_cflag bit meaning */ ++#define CBAUD 0010017 ++#define B0 0000000 /* hang up */ ++#define B50 0000001 ++#define B75 0000002 ++#define B110 0000003 ++#define B134 0000004 ++#define B150 0000005 ++#define B200 0000006 ++#define B300 0000007 ++#define B600 0000010 ++#define B1200 0000011 ++#define B1800 0000012 ++#define B2400 0000013 ++#define B4800 0000014 ++#define B9600 0000015 ++#define B19200 0000016 ++#define B38400 0000017 ++#define EXTA B19200 ++#define EXTB B38400 ++#define CSIZE 0000060 ++#define CS5 0000000 ++#define CS6 0000020 ++#define CS7 0000040 ++#define CS8 0000060 ++#define CSTOPB 0000100 ++#define CREAD 0000200 ++#define PARENB 0000400 ++#define PARODD 0001000 ++#define HUPCL 0002000 ++#define CLOCAL 0004000 ++#define CBAUDEX 0010000 ++#define B57600 0010001 ++#define B115200 0010002 ++#define B230400 0010003 ++#define B460800 0010004 ++#define B500000 0010005 ++#define B576000 0010006 ++#define B921600 0010007 ++#define B1000000 0010010 ++#define B1152000 0010011 ++#define B1500000 0010012 ++#define B2000000 0010013 ++#define B2500000 0010014 ++#define B3000000 0010015 ++#define B3500000 0010016 ++#define B4000000 0010017 ++#define CIBAUD 002003600000 /* input baud rate (not used) */ ++#define CMSPAR 010000000000 /* mark or space (stick) parity */ ++#define CRTSCTS 020000000000 /* flow control */ ++ ++/* c_lflag bits */ ++#define ISIG 0000001 ++#define ICANON 0000002 ++#define XCASE 0000004 ++#define ECHO 0000010 ++#define ECHOE 0000020 ++#define ECHOK 0000040 ++#define ECHONL 0000100 ++#define NOFLSH 0000200 ++#define TOSTOP 0000400 ++#define ECHOCTL 0001000 ++#define ECHOPRT 0002000 ++#define ECHOKE 0004000 ++#define FLUSHO 0010000 ++#define PENDIN 0040000 ++#define IEXTEN 0100000 ++ ++ ++/* tcflow() and TCXONC use these */ ++#define TCOOFF 0 ++#define TCOON 1 ++#define TCIOFF 2 ++#define TCION 3 ++ ++/* tcflush() and TCFLSH use these */ ++#define TCIFLUSH 0 ++#define TCOFLUSH 1 ++#define TCIOFLUSH 2 ++ ++/* tcsetattr uses these */ ++#define TCSANOW 0 ++#define TCSADRAIN 1 ++#define TCSAFLUSH 2 ++ ++#endif /* __ARCH_NIOS_TERMBITS_H__ */ +diff --git a/include/asm-nios2nommu/termios.h b/include/asm-nios2nommu/termios.h +new file mode 100644 +index 0000000..db0dddf +--- /dev/null ++++ b/include/asm-nios2nommu/termios.h +@@ -0,0 +1,132 @@ ++#ifndef _NIOS_TERMIOS_H ++#define _NIOS_TERMIOS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/termios.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++#include ++ ++struct winsize { ++ unsigned short ws_row; ++ unsigned short ws_col; ++ unsigned short ws_xpixel; ++ unsigned short ws_ypixel; ++}; ++ ++#define NCC 8 ++struct termio { ++ unsigned short c_iflag; /* input mode flags */ ++ unsigned short c_oflag; /* output mode flags */ ++ unsigned short c_cflag; /* control mode flags */ ++ unsigned short c_lflag; /* local mode flags */ ++ unsigned char c_line; /* line discipline */ ++ unsigned char c_cc[NCC]; /* control characters */ ++}; ++ ++#ifdef __KERNEL__ ++/* intr=^C quit=^| erase=del kill=^U ++ eof=^D vtime=\0 vmin=\1 sxtc=\0 ++ start=^Q stop=^S susp=^Z eol=\0 ++ reprint=^R discard=^U werase=^W lnext=^V ++ eol2=\0 ++*/ ++#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" ++#endif ++ ++/* modem lines */ ++#define TIOCM_LE 0x001 ++#define TIOCM_DTR 0x002 ++#define TIOCM_RTS 0x004 ++#define TIOCM_ST 0x008 ++#define TIOCM_SR 0x010 ++#define TIOCM_CTS 0x020 ++#define TIOCM_CAR 0x040 ++#define TIOCM_RNG 0x080 ++#define TIOCM_DSR 0x100 ++#define TIOCM_CD TIOCM_CAR ++#define TIOCM_RI TIOCM_RNG ++#define TIOCM_OUT1 0x2000 ++#define TIOCM_OUT2 0x4000 ++#define TIOCM_LOOP 0x8000 ++ ++/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ ++ ++/* line disciplines */ ++#define N_TTY 0 ++#define N_SLIP 1 ++#define N_MOUSE 2 ++#define N_PPP 3 ++#define N_STRIP 4 ++#define N_AX25 5 ++#define N_X25 6 /* X.25 async */ ++#define N_6PACK 7 ++#define N_MASC 8 /* Reserved for Mobitex module */ ++#define N_R3964 9 /* Reserved for Simatic R3964 module */ ++#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ ++#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */ ++#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ ++#define N_HDLC 13 /* synchronous HDLC */ ++#define N_SYNC_PPP 14 ++#define N_HCI 15 /* Bluetooth HCI UART */ ++ ++#ifdef __KERNEL__ ++ ++/* ++ * Translate a "termio" structure into a "termios". Ugh. ++ */ ++#define user_termio_to_kernel_termios(termios, termio) \ ++({ \ ++ unsigned short tmp; \ ++ get_user(tmp, &(termio)->c_iflag); \ ++ (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_oflag); \ ++ (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_cflag); \ ++ (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_lflag); \ ++ (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ ++ get_user((termios)->c_line, &(termio)->c_line); \ ++ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ ++}) ++ ++/* ++ * Translate a "termios" structure into a "termio". Ugh. ++ */ ++#define kernel_termios_to_user_termio(termio, termios) \ ++({ \ ++ put_user((termios)->c_iflag, &(termio)->c_iflag); \ ++ put_user((termios)->c_oflag, &(termio)->c_oflag); \ ++ put_user((termios)->c_cflag, &(termio)->c_cflag); \ ++ put_user((termios)->c_lflag, &(termio)->c_lflag); \ ++ put_user((termios)->c_line, &(termio)->c_line); \ ++ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ ++}) ++ ++#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) ++#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS_TERMIOS_H */ +diff --git a/include/asm-nios2nommu/thread_info.h b/include/asm-nios2nommu/thread_info.h +new file mode 100644 +index 0000000..6d51e0c +--- /dev/null ++++ b/include/asm-nios2nommu/thread_info.h +@@ -0,0 +1,127 @@ ++/* thread_info.h: niosnommu low-level thread information ++ * adapted from the m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 2002 Microtronix Datacom ++ * ++ * - Incorporating suggestions made by Linus Torvalds and Dave Miller ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_THREAD_INFO_H ++#define _ASM_THREAD_INFO_H ++ ++#include ++ ++#ifdef __KERNEL__ ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * low level task data. ++ */ ++struct thread_info { ++ struct task_struct *task; /* main task structure */ ++ struct exec_domain *exec_domain; /* execution domain */ ++ unsigned long flags; /* low level flags */ ++ int cpu; /* cpu we're on */ ++ int preempt_count; /* 0 => preemptable, <0 => BUG*/ ++ struct restart_block restart_block; ++}; ++ ++/* ++ * macros/functions for gaining access to the thread information structure ++ */ ++#define INIT_THREAD_INFO(tsk) \ ++{ \ ++ .task = &tsk, \ ++ .exec_domain = &default_exec_domain, \ ++ .flags = 0, \ ++ .cpu = 0, \ ++ .preempt_count = 1, \ ++ .restart_block = { \ ++ .fn = do_no_restart_syscall, \ ++ }, \ ++} ++ ++#define init_thread_info (init_thread_union.thread_info) ++#define init_stack (init_thread_union.stack) ++ ++ ++/* how to get the thread information struct from C ++ usable only in supervisor mode */ ++static inline struct thread_info *current_thread_info(void) ++{ ++ struct thread_info *ti; ++ __asm__ __volatile__( ++ "mov %0, sp\n" ++ "and %0, %0, %1\n" ++ : "=&r"(ti) ++ : "r" (~(THREAD_SIZE-1)) ++ ); ++ return ti; ++} ++ ++/* thread information allocation */ ++#define alloc_thread_info(tsk) ((struct thread_info *) \ ++ __get_free_pages(GFP_KERNEL, 1)) ++#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) ++#define put_thread_info(ti) put_task_struct((ti)->task) ++ ++#define PREEMPT_ACTIVE 0x4000000 ++ ++/* ++ * thread information flag bit numbers ++ */ ++#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ ++#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ ++#define TIF_SIGPENDING 2 /* signal pending */ ++#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ ++#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling ++ TIF_NEED_RESCHED */ ++#define TIF_MEMDIE 5 ++ ++/* as above, but as bit values */ ++#define _TIF_SYSCALL_TRACE (1< ++ ++ ++#define CLOCK_TICK_RATE nasys_clock_freq /* Underlying HZ */ ++ ++#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ ++ ++#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ ++ (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ ++ << (SHIFT_SCALE-SHIFT_HZ)) / HZ) ++ ++typedef unsigned long cycles_t; ++ ++static inline cycles_t get_cycles(void) ++{ ++ return 0; ++} ++ ++#endif +diff --git a/include/asm-nios2nommu/tlb.h b/include/asm-nios2nommu/tlb.h +new file mode 100644 +index 0000000..c597b25 +--- /dev/null ++++ b/include/asm-nios2nommu/tlb.h +@@ -0,0 +1,35 @@ ++#ifndef __NIOS_TLB_H__ ++#define __NIOS_TLB_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/tlb.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2003 Microtronix Datacom Ltd ++ * Copyright (C) 2002 NEC Corporation ++ * Copyright (C) 2002 Miles Bader ++ * ++ * 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. ++ * ++ * ++ * Written by Miles Bader ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#define tlb_flush(tlb) ((void)0) ++ ++#include ++ ++#endif /* __NIOS_TLB_H__ */ ++ +diff --git a/include/asm-nios2nommu/tlbflush.h b/include/asm-nios2nommu/tlbflush.h +new file mode 100644 +index 0000000..63cbe52 +--- /dev/null ++++ b/include/asm-nios2nommu/tlbflush.h +@@ -0,0 +1,86 @@ ++#ifndef _NIOS2NOMMU_TLBFLUSH_H ++#define _NIOS2NOMMU_TLBFLUSH_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/tlbflush.h ++ * ++ * Ported from m68knommu. ++ * ++ * Copyright (C) 2003 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++ ++/* ++ * flush all user-space atc entries. ++ */ ++static inline void __flush_tlb(void) ++{ ++ BUG(); ++} ++ ++static inline void __flush_tlb_one(unsigned long addr) ++{ ++ BUG(); ++} ++ ++#define flush_tlb() __flush_tlb() ++ ++/* ++ * flush all atc entries (both kernel and user-space entries). ++ */ ++static inline void flush_tlb_all(void) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_mm(struct mm_struct *mm) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_range(struct mm_struct *mm, ++ unsigned long start, unsigned long end) ++{ ++ BUG(); ++} ++ ++extern inline void flush_tlb_kernel_page(unsigned long addr) ++{ ++ BUG(); ++} ++ ++extern inline void flush_tlb_pgtables(struct mm_struct *mm, ++ unsigned long start, unsigned long end) ++{ ++ BUG(); ++} ++ ++#endif /* _NIOS2NOMMU_TLBFLUSH_H */ +diff --git a/include/asm-nios2nommu/topology.h b/include/asm-nios2nommu/topology.h +new file mode 100644 +index 0000000..cfe1054 +--- /dev/null ++++ b/include/asm-nios2nommu/topology.h +@@ -0,0 +1,30 @@ ++#ifndef _ASM_NIOS2NOMMU_TOPOLOGY_H ++#define _ASM_NIOS2NOMMU_TOPOLOGY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/topology.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _ASM_NIOS2NOMMU_TOPOLOGY_H */ +diff --git a/include/asm-nios2nommu/traps.h b/include/asm-nios2nommu/traps.h +new file mode 100644 +index 0000000..e03ef7f +--- /dev/null ++++ b/include/asm-nios2nommu/traps.h +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2_TRAPS_H ++#define _NIOS2_TRAPS_H ++ ++#define TRAP_ID_SYSCALL 0 ++#define TRAP_ID_APPDEBUG 1 ++#endif /* !(_NIOS2_TRAPS_H) */ +diff --git a/include/asm-nios2nommu/types.h b/include/asm-nios2nommu/types.h +new file mode 100644 +index 0000000..dd7a48e +--- /dev/null ++++ b/include/asm-nios2nommu/types.h +@@ -0,0 +1,91 @@ ++#ifndef _NIOS_TYPES_H ++#define _NIOS_TYPES_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/types.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This file is never included by application software unless ++ * explicitly requested (e.g., via linux/types.h) in which case the ++ * application is Linux specific so (user-) name space pollution is ++ * not a major issue. However, for interoperability, libraries still ++ * need to be careful to avoid a name clashes. ++ */ ++ ++#ifndef __ASSEMBLY__ ++ ++typedef unsigned short umode_t; ++ ++/* ++ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the ++ * header files exported to user space ++ */ ++ ++typedef __signed__ char __s8; ++typedef unsigned char __u8; ++ ++typedef __signed__ short __s16; ++typedef unsigned short __u16; ++ ++typedef __signed__ int __s32; ++typedef unsigned int __u32; ++ ++#if defined(__GNUC__) && !defined(__STRICT_ANSI__) ++typedef __signed__ long long __s64; ++typedef unsigned long long __u64; ++#endif ++ ++#endif /* __ASSEMBLY__ */ ++ ++/* ++ * These aren't exported outside the kernel to avoid name space clashes ++ */ ++#ifdef __KERNEL__ ++ ++#define BITS_PER_LONG 32 ++ ++#ifndef __ASSEMBLY__ ++ ++typedef signed char s8; ++typedef unsigned char u8; ++ ++typedef signed short s16; ++typedef unsigned short u16; ++ ++typedef signed int s32; ++typedef unsigned int u32; ++ ++typedef signed long long s64; ++typedef unsigned long long u64; ++ ++/* DMA addresses are always 32-bits wide */ ++ ++typedef u32 dma_addr_t; ++typedef u32 dma64_addr_t; ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS_TYPES_H */ +diff --git a/include/asm-nios2nommu/uaccess.h b/include/asm-nios2nommu/uaccess.h +new file mode 100644 +index 0000000..e7ea20a +--- /dev/null ++++ b/include/asm-nios2nommu/uaccess.h +@@ -0,0 +1,184 @@ ++#ifndef __NIOS2NOMMU_UACCESS_H ++#define __NIOS2NOMMU_UACCESS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * asm-nios2nommu/uaccess.h ++ * ++ * User space memory access functions ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Ported from asm-m68knommu/uaccess.h --wentao ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++#include ++#include ++#include ++ ++#define VERIFY_READ 0 ++#define VERIFY_WRITE 1 ++ ++#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size)) ++ ++static inline int _access_ok(unsigned long addr, unsigned long size) ++{ ++ return (((unsigned long)addr < (unsigned long)nasys_program_mem_end) && ++ (((unsigned long)addr >= (unsigned long)nasys_program_mem))); ++} ++ ++extern inline int verify_area(int type, const void * addr, unsigned long size) ++{ ++ return access_ok(type,addr,size)?0:-EFAULT; ++} ++ ++/* ++ * The exception table consists of pairs of addresses: the first is the ++ * address of an instruction that is allowed to fault, and the second is ++ * the address at which the program should continue. No registers are ++ * modified, so it is entirely up to the continuation code to figure out ++ * what to do. ++ * ++ * All the routines below use bits of fixup code that are out of line ++ * with the main instruction path. This means when everything is well, ++ * we don't even have to jump over them. Further, they do not intrude ++ * on our cache or tlb entries. ++ */ ++ ++#define ARCH_HAS_SEARCH_EXTABLE ++//;dgt2;tmp; ++ ++struct exception_table_entry ++{ ++ unsigned long insn, fixup; ++}; ++ ++/* Returns 0 if exception not found and fixup otherwise. */ ++extern unsigned long search_exception_table(unsigned long); ++ ++ ++/* ++ * These are the main single-value transfer routines. They automatically ++ * use the right size if we just have the right pointer type. ++ */ ++ ++#define put_user(x, ptr) \ ++({ \ ++ int __pu_err = 0; \ ++ typeof(*(ptr)) __pu_val = (x); \ ++ switch (sizeof (*(ptr))) { \ ++ case 1: \ ++ case 2: \ ++ case 4: \ ++ case 8: \ ++ memcpy(ptr, &__pu_val, sizeof (*(ptr))); \ ++ break; \ ++ default: \ ++ __pu_err = __put_user_bad(); \ ++ break; \ ++ } \ ++ __pu_err; \ ++}) ++#define __put_user(x, ptr) put_user(x, ptr) ++ ++extern int __put_user_bad(void); ++ ++/* ++ * Tell gcc we read from memory instead of writing: this is because ++ * we do not write to any memory gcc knows about, so there are no ++ * aliasing issues. ++ */ ++ ++#define __ptr(x) ((unsigned long *)(x)) ++ ++#define get_user(x, ptr) \ ++({ \ ++ int __gu_err = 0; \ ++ typeof(*(ptr)) __gu_val = 0; \ ++ switch (sizeof(*(ptr))) { \ ++ case 1: \ ++ case 2: \ ++ case 4: \ ++ case 8: \ ++ memcpy(&__gu_val, ptr, sizeof (*(ptr))); \ ++ break; \ ++ default: \ ++ __gu_val = 0; \ ++ __gu_err = __get_user_bad(); \ ++ break; \ ++ } \ ++ (x) = __gu_val; \ ++ __gu_err; \ ++}) ++#define __get_user(x, ptr) get_user(x, ptr) ++ ++extern int __get_user_bad(void); ++ ++#define copy_from_user(to, from, n) (memcpy(to, from, n), 0) ++#define copy_to_user(to, from, n) (memcpy(to, from, n), 0) ++ ++#define __copy_from_user(to, from, n) copy_from_user(to, from, n) ++#define __copy_to_user(to, from, n) copy_to_user(to, from, n) ++#define __copy_to_user_inatomic __copy_to_user ++#define __copy_from_user_inatomic __copy_from_user ++ ++#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) ++ ++#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) ++ ++/* ++ * Copy a null terminated string from userspace. ++ */ ++ ++static inline long ++strncpy_from_user(char *dst, const char *src, long count) ++{ ++ char *tmp; ++ strncpy(dst, src, count); ++ for (tmp = dst; *tmp && count > 0; tmp++, count--) ++ ; ++ return(tmp - dst); /* DAVIDM should we count a NUL ? check getname */ ++} ++ ++/* ++ * Return the size of a string (including the ending 0) ++ * ++ * Return 0 on exception, a value greater than N if too long ++ */ ++static inline long strnlen_user(const char *src, long n) ++{ ++ return(strlen(src) + 1); /* DAVIDM make safer */ ++} ++ ++#define strlen_user(str) strnlen_user(str, 32767) ++ ++/* ++ * Zero Userspace ++ */ ++ ++static inline unsigned long __clear_user(void *to, unsigned long n) ++{ ++ memset(to, 0, n); ++ return(0); ++} ++ ++#define clear_user(to, n) __clear_user(to, n) ++ ++#endif /* _NIOS2NOMMU_UACCESS_H */ +diff --git a/include/asm-nios2nommu/uart_struct.h b/include/asm-nios2nommu/uart_struct.h +new file mode 100644 +index 0000000..d955192 +--- /dev/null ++++ b/include/asm-nios2nommu/uart_struct.h +@@ -0,0 +1,83 @@ ++ ++// UART Registers ++typedef volatile struct ++ { ++ int np_uartrxdata; // Read-only, 8-bit ++ int np_uarttxdata; // Write-only, 8-bit ++ int np_uartstatus; // Read-only, 8-bit ++ int np_uartcontrol; // Read/Write, 9-bit ++ int np_uartdivisor; // Read/Write, 16-bit, optional ++ int np_uartendofpacket; // Read/Write, end-of-packet character ++ } np_uart; ++ ++// UART Status Register Bits ++enum ++ { ++ np_uartstatus_eop_bit = 12, ++ np_uartstatus_cts_bit = 11, ++ np_uartstatus_dcts_bit = 10, ++ np_uartstatus_e_bit = 8, ++ np_uartstatus_rrdy_bit = 7, ++ np_uartstatus_trdy_bit = 6, ++ np_uartstatus_tmt_bit = 5, ++ np_uartstatus_toe_bit = 4, ++ np_uartstatus_roe_bit = 3, ++ np_uartstatus_brk_bit = 2, ++ np_uartstatus_fe_bit = 1, ++ np_uartstatus_pe_bit = 0, ++ ++ np_uartstatus_eop_mask = (1<<12), ++ np_uartstatus_cts_mask = (1<<11), ++ np_uartstatus_dcts_mask = (1<<10), ++ np_uartstatus_e_mask = (1<<8), ++ np_uartstatus_rrdy_mask = (1<<7), ++ np_uartstatus_trdy_mask = (1<<6), ++ np_uartstatus_tmt_mask = (1<<5), ++ np_uartstatus_toe_mask = (1<<4), ++ np_uartstatus_roe_mask = (1<<3), ++ np_uartstatus_brk_mask = (1<<2), ++ np_uartstatus_fe_mask = (1<<1), ++ np_uartstatus_pe_mask = (1<<0) ++ }; ++ ++// UART Control Register Bits ++enum ++ { ++ np_uartcontrol_ieop_bit = 12, ++ np_uartcontrol_rts_bit = 11, ++ np_uartcontrol_idcts_bit = 10, ++ np_uartcontrol_tbrk_bit = 9, ++ np_uartcontrol_ie_bit = 8, ++ np_uartcontrol_irrdy_bit = 7, ++ np_uartcontrol_itrdy_bit = 6, ++ np_uartcontrol_itmt_bit = 5, ++ np_uartcontrol_itoe_bit = 4, ++ np_uartcontrol_iroe_bit = 3, ++ np_uartcontrol_ibrk_bit = 2, ++ np_uartcontrol_ife_bit = 1, ++ np_uartcontrol_ipe_bit = 0, ++ ++ np_uartcontrol_ieop_mask = (1<<12), ++ np_uartcontrol_rts_mask = (1<<11), ++ np_uartcontrol_idcts_mask = (1<<10), ++ np_uartcontrol_tbrk_mask = (1<<9), ++ np_uartcontrol_ie_mask = (1<<8), ++ np_uartcontrol_irrdy_mask = (1<<7), ++ np_uartcontrol_itrdy_mask = (1<<6), ++ np_uartcontrol_itmt_mask = (1<<5), ++ np_uartcontrol_itoe_mask = (1<<4), ++ np_uartcontrol_iroe_mask = (1<<3), ++ np_uartcontrol_ibrk_mask = (1<<2), ++ np_uartcontrol_ife_mask = (1<<1), ++ np_uartcontrol_ipe_mask = (1<<0) ++ }; ++ ++// UART Routines ++int nr_uart_rxchar(np_uart *uartBase); // 0 for default UART ++void nr_uart_txcr(void); ++void nr_uart_txchar(int c,np_uart *uartBase); // 0 for default UART ++void nr_uart_txhex(int x); // 16 or 32 bits ++void nr_uart_txhex16(short x); ++void nr_uart_txhex32(long x); ++void nr_uart_txstring(char *s); ++ +diff --git a/include/asm-nios2nommu/ucontext.h b/include/asm-nios2nommu/ucontext.h +new file mode 100644 +index 0000000..f2e7ce2 +--- /dev/null ++++ b/include/asm-nios2nommu/ucontext.h +@@ -0,0 +1,63 @@ ++#ifndef _NIOSKNOMMU_UCONTEXT_H ++#define _NIOSKNOMMU_UCONTEXT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/ucontext.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++typedef int greg_t; ++#define NGREG 32 ++typedef greg_t gregset_t[NGREG]; ++ ++#ifdef CONFIG_FPU ++typedef struct fpregset { ++ int f_pcr; ++ int f_psr; ++ int f_fpiaddr; ++ int f_fpregs[8][3]; ++} fpregset_t; ++#endif ++ ++struct mcontext { ++ int version; ++ int status_extension; ++ gregset_t gregs; ++#ifdef CONFIG_FPU ++ fpregset_t fpregs; ++#endif ++}; ++ ++#define MCONTEXT_VERSION 2 ++ ++struct ucontext { ++ unsigned long uc_flags; ++ struct ucontext *uc_link; ++ stack_t uc_stack; ++ struct mcontext uc_mcontext; ++#ifdef CONFIG_FPU ++ unsigned long uc_filler[80]; ++#endif ++ sigset_t uc_sigmask; /* mask last for extensibility */ ++}; ++ ++#endif +diff --git a/include/asm-nios2nommu/unaligned.h b/include/asm-nios2nommu/unaligned.h +new file mode 100644 +index 0000000..4876185 +--- /dev/null ++++ b/include/asm-nios2nommu/unaligned.h +@@ -0,0 +1,6 @@ ++#ifndef __NIOS2_UNALIGNED_H ++#define __NIOS2_UNALIGNED_H ++ ++#include ++ ++#endif /* __NIOS2_UNALIGNED_H */ +diff --git a/include/asm-nios2nommu/unistd.h b/include/asm-nios2nommu/unistd.h +new file mode 100644 +index 0000000..43cd165 +--- /dev/null ++++ b/include/asm-nios2nommu/unistd.h +@@ -0,0 +1,395 @@ ++#ifndef _ASM_NIOS_UNISTD_H_ ++#define _ASM_NIOS_UNISTD_H_ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/unistd.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * //vic - kernel_thread moved to process.c ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* TRAP isr expects the trap# (syscall=#TRAP_ID_SYSCALL) in r2, ++ * the syscall # in r3, and arguments in r4, r5, ... ++ * Return argument expected in r2. ++ */ ++ ++#define __NR_restart_syscall 0 ++#define __NR_exit 1 ++#define __NR_fork 2 ++#define __NR_read 3 ++#define __NR_write 4 ++#define __NR_open 5 ++#define __NR_close 6 ++#define __NR_waitpid 7 ++#define __NR_creat 8 ++#define __NR_link 9 ++#define __NR_unlink 10 ++#define __NR_execve 11 ++#define __NR_chdir 12 ++#define __NR_time 13 ++#define __NR_mknod 14 ++#define __NR_chmod 15 ++#define __NR_chown 16 ++#define __NR_break 17 ++#define __NR_oldstat 18 ++#define __NR_lseek 19 ++#define __NR_getpid 20 ++#define __NR_mount 21 ++#define __NR_umount 22 ++#define __NR_setuid 23 ++#define __NR_getuid 24 ++#define __NR_stime 25 ++#define __NR_ptrace 26 ++#define __NR_alarm 27 ++#define __NR_oldfstat 28 ++#define __NR_pause 29 ++#define __NR_utime 30 ++#define __NR_stty 31 ++#define __NR_gtty 32 ++#define __NR_access 33 ++#define __NR_nice 34 ++#define __NR_ftime 35 ++#define __NR_sync 36 ++#define __NR_kill 37 ++#define __NR_rename 38 ++#define __NR_mkdir 39 ++#define __NR_rmdir 40 ++#define __NR_dup 41 ++#define __NR_pipe 42 ++#define __NR_times 43 ++#define __NR_prof 44 ++#define __NR_brk 45 ++#define __NR_setgid 46 ++#define __NR_getgid 47 ++#define __NR_signal 48 ++#define __NR_geteuid 49 ++#define __NR_getegid 50 ++#define __NR_acct 51 ++#define __NR_umount2 52 //vic #define __NR_phys 52 ++#define __NR_lock 53 ++#define __NR_ioctl 54 ++#define __NR_fcntl 55 ++#define __NR_mpx 56 ++#define __NR_setpgid 57 ++#define __NR_ulimit 58 ++#define __NR_oldolduname 59 ++#define __NR_umask 60 ++#define __NR_chroot 61 ++#define __NR_ustat 62 ++#define __NR_dup2 63 ++#define __NR_getppid 64 ++#define __NR_getpgrp 65 ++#define __NR_setsid 66 ++#define __NR_sigaction 67 ++#define __NR_sgetmask 68 ++#define __NR_ssetmask 69 ++#define __NR_setreuid 70 ++#define __NR_setregid 71 ++#define __NR_sigsuspend 72 ++#define __NR_sigpending 73 ++#define __NR_sethostname 74 ++#define __NR_setrlimit 75 ++#define __NR_getrlimit 76 ++#define __NR_getrusage 77 ++#define __NR_gettimeofday 78 ++#define __NR_settimeofday 79 ++#define __NR_getgroups 80 ++#define __NR_setgroups 81 ++#define __NR_select 82 ++#define __NR_symlink 83 ++#define __NR_oldlstat 84 ++#define __NR_readlink 85 ++#define __NR_uselib 86 ++#define __NR_swapon 87 ++#define __NR_reboot 88 ++#define __NR_readdir 89 ++#define __NR_mmap 90 ++#define __NR_munmap 91 ++#define __NR_truncate 92 ++#define __NR_ftruncate 93 ++#define __NR_fchmod 94 ++#define __NR_fchown 95 ++#define __NR_getpriority 96 ++#define __NR_setpriority 97 ++#define __NR_profil 98 ++#define __NR_statfs 99 ++#define __NR_fstatfs 100 ++#define __NR_ioperm 101 ++#define __NR_socketcall 102 ++#define __NR_syslog 103 ++#define __NR_setitimer 104 ++#define __NR_getitimer 105 ++#define __NR_stat 106 ++#define __NR_lstat 107 ++#define __NR_fstat 108 ++#define __NR_olduname 109 ++#define __NR_iopl /* 110 */ not supported ++#define __NR_vhangup 111 ++#define __NR_idle /* 112 */ Obsolete ++#define __NR_vm86 /* 113 */ not supported ++#define __NR_wait4 114 ++#define __NR_swapoff 115 ++#define __NR_sysinfo 116 ++#define __NR_ipc 117 ++#define __NR_fsync 118 ++#define __NR_sigreturn 119 ++#define __NR_clone 120 ++#define __NR_setdomainname 121 ++#define __NR_uname 122 ++#define __NR_cacheflush 123 ++#define __NR_adjtimex 124 ++#define __NR_mprotect 125 ++#define __NR_sigprocmask 126 ++#define __NR_create_module 127 ++#define __NR_init_module 128 ++#define __NR_delete_module 129 ++#define __NR_get_kernel_syms 130 ++#define __NR_quotactl 131 ++#define __NR_getpgid 132 ++#define __NR_fchdir 133 ++#define __NR_bdflush 134 ++#define __NR_sysfs 135 ++#define __NR_personality 136 ++#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ ++#define __NR_setfsuid 138 ++#define __NR_setfsgid 139 ++#define __NR__llseek 140 ++#define __NR_getdents 141 ++#define __NR__newselect 142 ++#define __NR_flock 143 ++ /* 144 __NR_msync obsolete */ ++#define __NR_readv 145 ++#define __NR_writev 146 ++#define __NR_getsid 147 ++#define __NR_fdatasync 148 ++#define __NR__sysctl 149 ++#define __NR_mlock 150 ++#define __NR_munlock 151 ++#define __NR_mlockall 152 ++#define __NR_munlockall 153 ++#define __NR_sched_setparam 154 ++#define __NR_sched_getparam 155 ++#define __NR_sched_setscheduler 156 ++#define __NR_sched_getscheduler 157 ++#define __NR_sched_yield 158 ++#define __NR_sched_get_priority_max 159 ++#define __NR_sched_get_priority_min 160 ++#define __NR_sched_rr_get_interval 161 ++#define __NR_nanosleep 162 ++#define __NR_mremap 163 ++#define __NR_setresuid 164 ++#define __NR_getresuid 165 ++#define __NR_getpagesize 166 ++#define __NR_query_module 167 ++#define __NR_poll 168 ++#define __NR_nfsservctl 169 ++#define __NR_setresgid 170 ++#define __NR_getresgid 171 ++#define __NR_prctl 172 ++#define __NR_rt_sigreturn 173 ++#define __NR_rt_sigaction 174 ++#define __NR_rt_sigprocmask 175 ++#define __NR_rt_sigpending 176 ++#define __NR_rt_sigtimedwait 177 ++#define __NR_rt_sigqueueinfo 178 ++#define __NR_rt_sigsuspend 179 ++#define __NR_pread 180 ++#define __NR_pwrite 181 ++#define __NR_lchown 182 ++#define __NR_getcwd 183 ++#define __NR_capget 184 ++#define __NR_capset 185 ++#define __NR_sigaltstack 186 ++#define __NR_sendfile 187 ++#define __NR_getpmsg 188 /* some people actually want streams */ ++#define __NR_putpmsg 189 /* some people actually want streams */ ++#define __NR_vfork 190 ++#define __NR_ugetrlimit 191 ++#define __NR_mmap2 192 ++#define __NR_truncate64 193 ++#define __NR_ftruncate64 194 ++#define __NR_stat64 195 ++#define __NR_lstat64 196 ++#define __NR_fstat64 197 ++#define __NR_chown32 198 ++#define __NR_getuid32 199 ++#define __NR_getgid32 200 ++#define __NR_geteuid32 201 ++#define __NR_getegid32 202 ++#define __NR_setreuid32 203 ++#define __NR_setregid32 204 ++#define __NR_getgroups32 205 ++#define __NR_setgroups32 206 ++#define __NR_fchown32 207 ++#define __NR_setresuid32 208 ++#define __NR_getresuid32 209 ++#define __NR_setresgid32 210 ++#define __NR_getresgid32 211 ++#define __NR_lchown32 212 ++#define __NR_setuid32 213 ++#define __NR_setgid32 214 ++#define __NR_setfsuid32 215 ++#define __NR_setfsgid32 216 ++#define __NR_pivot_root 217 ++/* 218 unused */ ++/* 219 unused */ ++#define __NR_getdents64 220 ++#define __NR_gettid 221 ++#define __NR_tkill 222 ++#define __NR_setxattr 223 ++#define __NR_lsetxattr 224 ++#define __NR_fsetxattr 225 ++#define __NR_getxattr 226 ++#define __NR_lgetxattr 227 ++#define __NR_fgetxattr 228 ++#define __NR_listxattr 229 ++#define __NR_llistxattr 230 ++#define __NR_flistxattr 231 ++#define __NR_removexattr 232 ++#define __NR_lremovexattr 233 ++#define __NR_fremovexattr 234 ++#define __NR_futex 235 ++#define __NR_sendfile64 236 ++#define __NR_mincore 237 ++#define __NR_madvise 238 ++#define __NR_fcntl64 239 ++#define __NR_readahead 240 ++#define __NR_io_setup 241 ++#define __NR_io_destroy 242 ++#define __NR_io_getevents 243 ++#define __NR_io_submit 244 ++#define __NR_io_cancel 245 ++#define __NR_fadvise64 246 ++#define __NR_exit_group 247 ++#define __NR_lookup_dcookie 248 ++#define __NR_epoll_create 249 ++#define __NR_epoll_ctl 250 ++#define __NR_epoll_wait 251 ++#define __NR_remap_file_pages 252 ++#define __NR_set_tid_address 253 ++#define __NR_timer_create 254 ++#define __NR_timer_settime 255 ++#define __NR_timer_gettime 256 ++#define __NR_timer_getoverrun 257 ++#define __NR_timer_delete 258 ++#define __NR_clock_settime 259 ++#define __NR_clock_gettime 260 ++#define __NR_clock_getres 261 ++#define __NR_clock_nanosleep 262 ++#define __NR_statfs64 263 ++#define __NR_fstatfs64 264 ++#define __NR_tgkill 265 ++#define __NR_utimes 266 ++#define __NR_fadvise64_64 267 ++#define __NR_mbind 268 ++#define __NR_get_mempolicy 269 ++#define __NR_set_mempolicy 270 ++#define __NR_mq_open 271 ++#define __NR_mq_unlink 272 ++#define __NR_mq_timedsend 273 ++#define __NR_mq_timedreceive 274 ++#define __NR_mq_notify 275 ++#define __NR_mq_getsetattr 276 ++#define __NR_waitid 277 ++#define __NR_sys_setaltroot 278 ++#define __NR_add_key 279 ++#define __NR_request_key 280 ++#define __NR_keyctl 281 ++#define __NR_ioprio_set 282 ++#define __NR_ioprio_get 283 ++#define __NR_inotify_init 284 ++#define __NR_inotify_add_watch 285 ++#define __NR_inotify_rm_watch 286 ++#define __NR_migrate_pages 287 ++#define __NR_openat 288 ++#define __NR_mkdirat 289 ++#define __NR_mknodat 290 ++#define __NR_fchownat 291 ++#define __NR_futimesat 292 ++#define __NR_fstatat64 293 ++#define __NR_unlinkat 294 ++#define __NR_renameat 295 ++#define __NR_linkat 296 ++#define __NR_symlinkat 297 ++#define __NR_readlinkat 298 ++#define __NR_fchmodat 299 ++#define __NR_faccessat 300 ++#define __NR_pselect6 301 ++#define __NR_ppoll 302 ++#define __NR_unshare 303 ++#define __NR_set_robust_list 304 ++#define __NR_get_robust_list 305 ++#define __NR_splice 306 ++#define __NR_sync_file_range 307 ++#define __NR_tee 308 ++#define __NR_vmsplice 309 ++#define __NR_move_pages 310 ++#define __NR_sched_setaffinity 311 ++#define __NR_sched_getaffinity 312 ++#define __NR_kexec_load 313 ++#define __NR_getcpu 314 ++#define __NR_epoll_pwait 315 ++#define __NR_utimensat 316 ++#define __NR_signalfd 317 ++#define __NR_timerfd 318 ++#define __NR_eventfd 319 ++#define __NR_pread64 320 ++#define __NR_pwrite64 321 ++ ++#ifdef __KERNEL__ ++#define NR_syscalls 322 ++ ++#define __ARCH_WANT_IPC_PARSE_VERSION ++#define __ARCH_WANT_OLD_READDIR ++#define __ARCH_WANT_OLD_STAT ++#define __ARCH_WANT_STAT64 ++#define __ARCH_WANT_SYS_ALARM ++#define __ARCH_WANT_SYS_GETHOSTNAME ++#define __ARCH_WANT_SYS_PAUSE ++#define __ARCH_WANT_SYS_SGETMASK ++#define __ARCH_WANT_SYS_SIGNAL ++#define __ARCH_WANT_SYS_TIME ++#define __ARCH_WANT_SYS_UTIME ++#define __ARCH_WANT_SYS_WAITPID ++#define __ARCH_WANT_SYS_SOCKETCALL ++#define __ARCH_WANT_SYS_FADVISE64 ++#define __ARCH_WANT_SYS_GETPGRP ++#define __ARCH_WANT_SYS_LLSEEK ++#define __ARCH_WANT_SYS_NICE ++#define __ARCH_WANT_SYS_OLD_GETRLIMIT ++#define __ARCH_WANT_SYS_OLDUMOUNT ++#define __ARCH_WANT_SYS_SIGPENDING ++#define __ARCH_WANT_SYS_SIGPROCMASK ++#define __ARCH_WANT_SYS_RT_SIGACTION ++ ++/* ++ * "Conditional" syscalls ++ * ++ * What we want is __attribute__((weak,alias("sys_ni_syscall"))), ++ * but it doesn't work on all toolchains, so we just do it by hand ++ */ ++#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _ASM_NIOS_UNISTD_H_ */ +diff --git a/include/asm-nios2nommu/user.h b/include/asm-nios2nommu/user.h +new file mode 100644 +index 0000000..3cdc2ba +--- /dev/null ++++ b/include/asm-nios2nommu/user.h +@@ -0,0 +1,112 @@ ++#ifndef _NIOS2NOMMU_USER_H ++#define _NIOS2NOMMU_USER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/user.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* Core file format: The core file is written in such a way that gdb ++ can understand it and provide useful information to the user (under ++ linux we use the 'trad-core' bfd). There are quite a number of ++ obstacles to being able to view the contents of the floating point ++ registers, and until these are solved you will not be able to view the ++ contents of them. Actually, you can read in the core file and look at ++ the contents of the user struct to find out what the floating point ++ registers contain. ++ The actual file contents are as follows: ++ UPAGE: 1 page consisting of a user struct that tells gdb what is present ++ in the file. Directly after this is a copy of the task_struct, which ++ is currently not used by gdb, but it may come in useful at some point. ++ All of the registers are stored as part of the upage. The upage should ++ always be only one page. ++ DATA: The data area is stored. We use current->end_text to ++ current->brk to pick up all of the user variables, plus any memory ++ that may have been malloced. No attempt is made to determine if a page ++ is demand-zero or if a page is totally unused, we just cover the entire ++ range. All of the addresses are rounded in such a way that an integral ++ number of pages is written. ++ STACK: We need the stack information in order to get a meaningful ++ backtrace. We need to write the data from (esp) to ++ current->start_stack, so we round each of these off in order to be able ++ to write an integer number of pages. ++ The minimum core file size is 3 pages, or 12288 bytes. ++*/ ++ ++struct user_m68kfp_struct { ++ unsigned long fpregs[8*3]; /* fp0-fp7 registers */ ++ unsigned long fpcntl[3]; /* fp control regs */ ++}; ++ ++/* This is needs more work, probably should look like gdb useage */ ++struct user_regs_struct { ++ long r1,r2,r3,r4,r5,r6,r7,r8; ++ long r9,r10,r11,r12,r13,r14,r15; ++ long r16,r17,r18,r19,r20,r21,r22,r23; ++ long gp; ++ long sp; ++ long ra; ++ long fp; ++ long orig_r2; ++ long estatus; ++ long status_extension; ++ long ea; ++}; ++ ++ ++/* When the kernel dumps core, it starts by dumping the user struct - ++ this will be used by gdb to figure out where the data and stack segments ++ are within the file, and what virtual addresses to use. */ ++struct user{ ++/* We start with the registers, to mimic the way that "memory" is returned ++ from the ptrace(3,...) function. */ ++ struct user_regs_struct regs; /* Where the registers are actually stored */ ++/* ptrace does not yet supply these. Someday.... */ ++ int u_fpvalid; /* True if math co-processor being used. */ ++ /* for this mess. Not yet used. */ ++ struct user_m68kfp_struct m68kfp; /* Math Co-processor registers. */ ++/* The rest of this junk is to help gdb figure out what goes where */ ++ unsigned long int u_tsize; /* Text segment size (pages). */ ++ unsigned long int u_dsize; /* Data segment size (pages). */ ++ unsigned long int u_ssize; /* Stack segment size (pages). */ ++ unsigned long start_code; /* Starting virtual address of text. */ ++ unsigned long start_stack; /* Starting virtual address of stack area. ++ This is actually the bottom of the stack, ++ the top of the stack is always found in the ++ esp register. */ ++ long int signal; /* Signal that caused the core dump. */ ++ int reserved; /* No longer used */ ++ struct user_regs_struct *u_ar0; ++ /* Used by gdb to help find the values for */ ++ /* the registers. */ ++ struct user_m68kfp_struct* u_fpstate; /* Math Co-processor pointer. */ ++ unsigned long magic; /* To uniquely identify a core file */ ++ char u_comm[32]; /* User command that was responsible */ ++}; ++#define NBPG PAGE_SIZE ++#define UPAGES 1 ++#define HOST_TEXT_START_ADDR (u.start_code) ++#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) ++ ++#endif +diff --git a/include/asm-nios2nommu/virtconvert.h b/include/asm-nios2nommu/virtconvert.h +new file mode 100644 +index 0000000..89bf899 +--- /dev/null ++++ b/include/asm-nios2nommu/virtconvert.h +@@ -0,0 +1,46 @@ ++#ifndef __NIOS_VIRT_CONVERT__ ++#define __NIOS_VIRT_CONVERT__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/virtconvert.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * Macros used for converting between virtual and physical mappings. ++ */ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++#define mm_ptov(vaddr) ((void *) (vaddr)) ++#define mm_vtop(vaddr) ((unsigned long) (vaddr)) ++#define phys_to_virt(vaddr) ((void *) (vaddr)) ++#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) ++ ++#define virt_to_bus virt_to_phys ++#define bus_to_virt phys_to_virt ++ ++#endif /*__KERNEL__ */ ++#endif /*__NIOS_VIRT_CONVERT__*/ diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.25.9-export-linux-aout.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.25.9-export-linux-aout.patch new file mode 100644 index 0000000000..972fa76b06 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-2.6.25.9-export-linux-aout.patch @@ -0,0 +1,24 @@ +[PATCH] export linux/a.out.h + +Export linux/a.out.h like we do for asm/a.out.h. One minor complication is +that the interesting stuff is protected by an CONFIG_ARCH_SUPPORTS_AOUT ifdef, +so make sure this gets defined for unifdef. + +Signed-off-by: Peter Korsgaard +--- + include/linux/Kbuild | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.25.6/include/linux/Kbuild +=================================================================== +--- linux-2.6.25.6.orig/include/linux/Kbuild ++++ linux-2.6.25.6/include/linux/Kbuild +@@ -159,6 +159,8 @@ + header-y += videotext.h + header-y += x25.h + ++UNIFDEF += -DCONFIG_ARCH_SUPPORTS_AOUT ++unifdef-y += a.out.h + unifdef-y += acct.h + unifdef-y += adb.h + unifdef-y += adfs_fs.h diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11-nios2nommu.patch.conditional b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11-nios2nommu.patch.conditional new file mode 100644 index 0000000000..b8c3fff8f0 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11-nios2nommu.patch.conditional @@ -0,0 +1,13527 @@ +--- linux/include/asm-generic/4level-fixup.h ++++ linux/include/asm-generic/4level-fixup.h +@@ -0,0 +1,34 @@ ++#ifndef _4LEVEL_FIXUP_H ++#define _4LEVEL_FIXUP_H ++ ++#define __ARCH_HAS_4LEVEL_HACK ++ ++#define PUD_SIZE PGDIR_SIZE ++#define PUD_MASK PGDIR_MASK ++#define PTRS_PER_PUD 1 ++ ++#define pud_t pgd_t ++ ++#define pmd_alloc(mm, pud, address) \ ++({ pmd_t *ret; \ ++ if (pgd_none(*pud)) \ ++ ret = __pmd_alloc(mm, pud, address); \ ++ else \ ++ ret = pmd_offset(pud, address); \ ++ ret; \ ++}) ++ ++#define pud_alloc(mm, pgd, address) (pgd) ++#define pud_offset(pgd, start) (pgd) ++#define pud_none(pud) 0 ++#define pud_bad(pud) 0 ++#define pud_present(pud) 1 ++#define pud_ERROR(pud) do { } while (0) ++#define pud_clear(pud) pgd_clear(pud) ++ ++#undef pud_free_tlb ++#define pud_free_tlb(tlb, x) do { } while (0) ++#define pud_free(x) do { } while (0) ++#define __pud_free_tlb(tlb, x) do { } while (0) ++ ++#endif +--- linux/include/asm-generic/bitops.h ++++ linux/include/asm-generic/bitops.h +@@ -0,0 +1,81 @@ ++#ifndef _ASM_GENERIC_BITOPS_H_ ++#define _ASM_GENERIC_BITOPS_H_ ++ ++/* ++ * For the benefit of those who are trying to port Linux to another ++ * architecture, here are some C-language equivalents. You should ++ * recode these in the native assembly language, if at all possible. ++ * To guarantee atomicity, these routines call cli() and sti() to ++ * disable interrupts while they operate. (You have to provide inline ++ * routines to cli() and sti().) ++ * ++ * Also note, these routines assume that you have 32 bit longs. ++ * You will have to change this if you are trying to port Linux to the ++ * Alpha architecture or to a Cray. :-) ++ * ++ * C language equivalents written by Theodore Ts'o, 9/26/92 ++ */ ++ ++extern __inline__ int set_bit(int nr,long * addr) ++{ ++ int mask, retval; ++ ++ addr += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ cli(); ++ retval = (mask & *addr) != 0; ++ *addr |= mask; ++ sti(); ++ return retval; ++} ++ ++extern __inline__ int clear_bit(int nr, long * addr) ++{ ++ int mask, retval; ++ ++ addr += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ cli(); ++ retval = (mask & *addr) != 0; ++ *addr &= ~mask; ++ sti(); ++ return retval; ++} ++ ++extern __inline__ int test_bit(int nr, const unsigned long * addr) ++{ ++ int mask; ++ ++ addr += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ return ((mask & *addr) != 0); ++} ++ ++/* ++ * fls: find last bit set. ++ */ ++ ++#define fls(x) generic_fls(x) ++ ++#ifdef __KERNEL__ ++ ++/* ++ * ffs: find first bit set. This is defined the same way as ++ * the libc and compiler builtin ffs routines, therefore ++ * differs in spirit from the above ffz (man ffs). ++ */ ++ ++#define ffs(x) generic_ffs(x) ++ ++/* ++ * hweightN: returns the hamming weight (i.e. the number ++ * of bits set) of a N-bit word ++ */ ++ ++#define hweight32(x) generic_hweight32(x) ++#define hweight16(x) generic_hweight16(x) ++#define hweight8(x) generic_hweight8(x) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _ASM_GENERIC_BITOPS_H */ +--- linux/include/asm-generic/bug.h ++++ linux/include/asm-generic/bug.h +@@ -0,0 +1,34 @@ ++#ifndef _ASM_GENERIC_BUG_H ++#define _ASM_GENERIC_BUG_H ++ ++#include ++// #include ++ ++#ifndef HAVE_ARCH_BUG ++#define BUG() do { \ ++ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ ++ panic("BUG!"); \ ++} while (0) ++#endif ++ ++#ifndef HAVE_ARCH_PAGE_BUG ++#define PAGE_BUG(page) do { \ ++ printk("page BUG for page at %p\n", page); \ ++ BUG(); \ ++} while (0) ++#endif ++ ++#ifndef HAVE_ARCH_BUG_ON ++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) ++#endif ++ ++#ifndef HAVE_ARCH_WARN_ON ++#define WARN_ON(condition) do { \ ++ if (unlikely((condition)!=0)) { \ ++ printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ ++ dump_stack(); \ ++ } \ ++} while (0) ++#endif ++ ++#endif +--- linux/include/asm-generic/cpumask_arith.h ++++ linux/include/asm-generic/cpumask_arith.h +@@ -0,0 +1,49 @@ ++#ifndef __ASM_GENERIC_CPUMASK_ARITH_H ++#define __ASM_GENERIC_CPUMASK_ARITH_H ++ ++/* ++ * Arithmetic type -based cpu bitmaps. A single unsigned long is used ++ * to contain the whole cpu bitmap. ++ */ ++ ++#define cpu_set(cpu, map) set_bit(cpu, &(map)) ++#define cpu_clear(cpu, map) clear_bit(cpu, &(map)) ++#define cpu_isset(cpu, map) test_bit(cpu, &(map)) ++#define cpu_test_and_set(cpu, map) test_and_set_bit(cpu, &(map)) ++ ++#define cpus_and(dst,src1,src2) do { dst = (src1) & (src2); } while (0) ++#define cpus_or(dst,src1,src2) do { dst = (src1) | (src2); } while (0) ++#define cpus_clear(map) do { map = 0; } while (0) ++#define cpus_complement(map) do { map = ~(map); } while (0) ++#define cpus_equal(map1, map2) ((map1) == (map2)) ++#define cpus_empty(map) ((map) == 0) ++#define cpus_addr(map) (&(map)) ++ ++#if BITS_PER_LONG == 32 ++#define cpus_weight(map) hweight32(map) ++#elif BITS_PER_LONG == 64 ++#define cpus_weight(map) hweight64(map) ++#endif ++ ++#define cpus_shift_right(dst, src, n) do { dst = (src) >> (n); } while (0) ++#define cpus_shift_left(dst, src, n) do { dst = (src) << (n); } while (0) ++ ++#define any_online_cpu(map) \ ++({ \ ++ cpumask_t __tmp__; \ ++ cpus_and(__tmp__, map, cpu_online_map); \ ++ __tmp__ ? first_cpu(__tmp__) : NR_CPUS; \ ++}) ++ ++#define CPU_MASK_ALL (~((cpumask_t)0) >> (8*sizeof(cpumask_t) - NR_CPUS)) ++#define CPU_MASK_NONE ((cpumask_t)0) ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_coerce(map) ((unsigned long)(map)) ++#define cpus_promote(map) ({ map; }) ++#define cpumask_of_cpu(cpu) ({ ((cpumask_t)1) << (cpu); }) ++ ++#define first_cpu(map) __ffs(map) ++#define next_cpu(cpu, map) find_next_bit(&(map), NR_CPUS, cpu + 1) ++ ++#endif /* __ASM_GENERIC_CPUMASK_ARITH_H */ +--- linux/include/asm-generic/cpumask_array.h ++++ linux/include/asm-generic/cpumask_array.h +@@ -0,0 +1,54 @@ ++#ifndef __ASM_GENERIC_CPUMASK_ARRAY_H ++#define __ASM_GENERIC_CPUMASK_ARRAY_H ++ ++/* ++ * Array-based cpu bitmaps. An array of unsigned longs is used to contain ++ * the bitmap, and then contained in a structure so it may be passed by ++ * value. ++ */ ++ ++#define CPU_ARRAY_SIZE BITS_TO_LONGS(NR_CPUS) ++ ++#define cpu_set(cpu, map) set_bit(cpu, (map).mask) ++#define cpu_clear(cpu, map) clear_bit(cpu, (map).mask) ++#define cpu_isset(cpu, map) test_bit(cpu, (map).mask) ++#define cpu_test_and_set(cpu, map) test_and_set_bit(cpu, (map).mask) ++ ++#define cpus_and(dst,src1,src2) bitmap_and((dst).mask,(src1).mask, (src2).mask, NR_CPUS) ++#define cpus_or(dst,src1,src2) bitmap_or((dst).mask, (src1).mask, (src2).mask, NR_CPUS) ++#define cpus_clear(map) bitmap_clear((map).mask, NR_CPUS) ++#define cpus_complement(map) bitmap_complement((map).mask, NR_CPUS) ++#define cpus_equal(map1, map2) bitmap_equal((map1).mask, (map2).mask, NR_CPUS) ++#define cpus_empty(map) bitmap_empty(map.mask, NR_CPUS) ++#define cpus_addr(map) ((map).mask) ++#define cpus_weight(map) bitmap_weight((map).mask, NR_CPUS) ++#define cpus_shift_right(d, s, n) bitmap_shift_right((d).mask, (s).mask, n, NR_CPUS) ++#define cpus_shift_left(d, s, n) bitmap_shift_left((d).mask, (s).mask, n, NR_CPUS) ++#define first_cpu(map) find_first_bit((map).mask, NR_CPUS) ++#define next_cpu(cpu, map) find_next_bit((map).mask, NR_CPUS, cpu + 1) ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_coerce(map) ((map).mask[0]) ++#define cpus_promote(map) ({ cpumask_t __cpu_mask = CPU_MASK_NONE;\ ++ __cpu_mask.mask[0] = map; \ ++ __cpu_mask; \ ++ }) ++#define cpumask_of_cpu(cpu) ({ cpumask_t __cpu_mask = CPU_MASK_NONE;\ ++ cpu_set(cpu, __cpu_mask); \ ++ __cpu_mask; \ ++ }) ++#define any_online_cpu(map) \ ++({ \ ++ cpumask_t __tmp__; \ ++ cpus_and(__tmp__, map, cpu_online_map); \ ++ find_first_bit(__tmp__.mask, NR_CPUS); \ ++}) ++ ++ ++/* ++ * um, these need to be usable as static initializers ++ */ ++#define CPU_MASK_ALL { {[0 ... CPU_ARRAY_SIZE-1] = ~0UL} } ++#define CPU_MASK_NONE { {[0 ... CPU_ARRAY_SIZE-1] = 0UL} } ++ ++#endif /* __ASM_GENERIC_CPUMASK_ARRAY_H */ +--- linux/include/asm-generic/cpumask_const_reference.h ++++ linux/include/asm-generic/cpumask_const_reference.h +@@ -0,0 +1,29 @@ ++#ifndef __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H ++#define __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H ++ ++struct cpumask_ref { ++ const cpumask_t *val; ++}; ++ ++typedef const struct cpumask_ref cpumask_const_t; ++ ++#define mk_cpumask_const(map) ((cpumask_const_t){ &(map) }) ++#define cpu_isset_const(cpu, map) cpu_isset(cpu, *(map).val) ++ ++#define cpus_and_const(dst,src1,src2) cpus_and(dst,*(src1).val,*(src2).val) ++#define cpus_or_const(dst,src1,src2) cpus_or(dst,*(src1).val,*(src2).val) ++ ++#define cpus_equal_const(map1, map2) cpus_equal(*(map1).val, *(map2).val) ++ ++#define cpus_copy_const(map1, map2) bitmap_copy((map1).mask, (map2).val->mask, NR_CPUS) ++ ++#define cpus_empty_const(map) cpus_empty(*(map).val) ++#define cpus_weight_const(map) cpus_weight(*(map).val) ++#define first_cpu_const(map) first_cpu(*(map).val) ++#define next_cpu_const(cpu, map) next_cpu(cpu, *(map).val) ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_coerce_const(map) cpus_coerce(*(map).val) ++#define any_online_cpu_const(map) any_online_cpu(*(map).val) ++ ++#endif /* __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H */ +--- linux/include/asm-generic/cpumask_const_value.h ++++ linux/include/asm-generic/cpumask_const_value.h +@@ -0,0 +1,21 @@ ++#ifndef __ASM_GENERIC_CPUMASK_CONST_VALUE_H ++#define __ASM_GENERIC_CPUMASK_CONST_VALUE_H ++ ++typedef const cpumask_t cpumask_const_t; ++ ++#define mk_cpumask_const(map) (map) ++#define cpu_isset_const(cpu, map) cpu_isset(cpu, map) ++#define cpus_and_const(dst,src1,src2) cpus_and(dst, src1, src2) ++#define cpus_or_const(dst,src1,src2) cpus_or(dst, src1, src2) ++#define cpus_equal_const(map1, map2) cpus_equal(map1, map2) ++#define cpus_empty_const(map) cpus_empty(map) ++#define cpus_copy_const(map1, map2) do { map1 = (cpumask_t)map2; } while (0) ++#define cpus_weight_const(map) cpus_weight(map) ++#define first_cpu_const(map) first_cpu(map) ++#define next_cpu_const(cpu, map) next_cpu(cpu, map) ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_coerce_const(map) cpus_coerce(map) ++#define any_online_cpu_const(map) any_online_cpu(map) ++ ++#endif /* __ASM_GENERIC_CPUMASK_CONST_VALUE_H */ +--- linux/include/asm-generic/cpumask.h ++++ linux/include/asm-generic/cpumask.h +@@ -0,0 +1,40 @@ ++#ifndef __ASM_GENERIC_CPUMASK_H ++#define __ASM_GENERIC_CPUMASK_H ++ ++// #include ++#include ++#include ++#include ++#include ++ ++#if NR_CPUS > BITS_PER_LONG && NR_CPUS != 1 ++#define CPU_ARRAY_SIZE BITS_TO_LONGS(NR_CPUS) ++ ++struct cpumask ++{ ++ unsigned long mask[CPU_ARRAY_SIZE]; ++}; ++ ++typedef struct cpumask cpumask_t; ++ ++#else ++typedef unsigned long cpumask_t; ++#endif ++ ++#ifdef CONFIG_SMP ++#if NR_CPUS > BITS_PER_LONG ++#include ++#else ++#include ++#endif ++#else ++#include ++#endif ++ ++#if NR_CPUS <= 4*BITS_PER_LONG ++#include ++#else ++#include ++#endif ++ ++#endif /* __ASM_GENERIC_CPUMASK_H */ +--- linux/include/asm-generic/cpumask_up.h ++++ linux/include/asm-generic/cpumask_up.h +@@ -0,0 +1,59 @@ ++#ifndef __ASM_GENERIC_CPUMASK_UP_H ++#define __ASM_GENERIC_CPUMASK_UP_H ++ ++#define cpus_coerce(map) (map) ++ ++#define cpu_set(cpu, map) do { (void)(cpu); cpus_coerce(map) = 1UL; } while (0) ++#define cpu_clear(cpu, map) do { (void)(cpu); cpus_coerce(map) = 0UL; } while (0) ++#define cpu_isset(cpu, map) ((void)(cpu), cpus_coerce(map) != 0UL) ++#define cpu_test_and_set(cpu, map) ((void)(cpu), test_and_set_bit(0, &(map))) ++ ++#define cpus_and(dst, src1, src2) \ ++ do { \ ++ if (cpus_coerce(src1) && cpus_coerce(src2)) \ ++ cpus_coerce(dst) = 1UL; \ ++ else \ ++ cpus_coerce(dst) = 0UL; \ ++ } while (0) ++ ++#define cpus_or(dst, src1, src2) \ ++ do { \ ++ if (cpus_coerce(src1) || cpus_coerce(src2)) \ ++ cpus_coerce(dst) = 1UL; \ ++ else \ ++ cpus_coerce(dst) = 0UL; \ ++ } while (0) ++ ++#define cpus_clear(map) do { cpus_coerce(map) = 0UL; } while (0) ++ ++#define cpus_complement(map) \ ++ do { \ ++ cpus_coerce(map) = !cpus_coerce(map); \ ++ } while (0) ++ ++#define cpus_equal(map1, map2) (cpus_coerce(map1) == cpus_coerce(map2)) ++#define cpus_empty(map) (cpus_coerce(map) == 0UL) ++#define cpus_addr(map) (&(map)) ++#define cpus_weight(map) (cpus_coerce(map) ? 1UL : 0UL) ++#define cpus_shift_right(d, s, n) do { cpus_coerce(d) = 0UL; } while (0) ++#define cpus_shift_left(d, s, n) do { cpus_coerce(d) = 0UL; } while (0) ++#define first_cpu(map) (cpus_coerce(map) ? 0 : 1) ++#define next_cpu(cpu, map) 1 ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_promote(map) \ ++ ({ \ ++ cpumask_t __tmp__; \ ++ cpus_coerce(__tmp__) = map; \ ++ __tmp__; \ ++ }) ++#define cpumask_of_cpu(cpu) ((void)(cpu), cpus_promote(1)) ++#define any_online_cpu(map) (cpus_coerce(map) ? 0 : 1) ++ ++/* ++ * um, these need to be usable as static initializers ++ */ ++#define CPU_MASK_ALL 1UL ++#define CPU_MASK_NONE 0UL ++ ++#endif /* __ASM_GENERIC_CPUMASK_UP_H */ +--- linux/include/asm-generic/cputime.h ++++ linux/include/asm-generic/cputime.h +@@ -0,0 +1,64 @@ ++#ifndef _ASM_GENERIC_CPUTIME_H ++#define _ASM_GENERIC_CPUTIME_H ++ ++#include ++#include ++ ++typedef unsigned long cputime_t; ++ ++#define cputime_zero (0UL) ++#define cputime_max ((~0UL >> 1) - 1) ++#define cputime_add(__a, __b) ((__a) + (__b)) ++#define cputime_sub(__a, __b) ((__a) - (__b)) ++#define cputime_eq(__a, __b) ((__a) == (__b)) ++#define cputime_gt(__a, __b) ((__a) > (__b)) ++#define cputime_ge(__a, __b) ((__a) >= (__b)) ++#define cputime_lt(__a, __b) ((__a) < (__b)) ++#define cputime_le(__a, __b) ((__a) <= (__b)) ++#define cputime_to_jiffies(__ct) (__ct) ++#define jiffies_to_cputime(__hz) (__hz) ++ ++typedef u64 cputime64_t; ++ ++#define cputime64_zero (0ULL) ++#define cputime64_add(__a, __b) ((__a) + (__b)) ++#define cputime64_to_jiffies64(__ct) (__ct) ++#define cputime_to_cputime64(__ct) ((u64) __ct) ++ ++ ++/* ++ * Convert cputime to milliseconds and back. ++ */ ++#define cputime_to_msecs(__ct) jiffies_to_msecs(__ct) ++#define msecs_to_cputime(__msecs) msecs_to_jiffies(__msecs) ++ ++/* ++ * Convert cputime to seconds and back. ++ */ ++#define cputime_to_secs(jif) ((jif) / HZ) ++#define secs_to_cputime(sec) ((sec) * HZ) ++ ++/* ++ * Convert cputime to timespec and back. ++ */ ++#define timespec_to_cputime(__val) timespec_to_jiffies(__val) ++#define cputime_to_timespec(__ct,__val) jiffies_to_timespec(__ct,__val) ++ ++/* ++ * Convert cputime to timeval and back. ++ */ ++#define timeval_to_cputime(__val) timeval_to_jiffies(__val) ++#define cputime_to_timeval(__ct,__val) jiffies_to_timeval(__ct,__val) ++ ++/* ++ * Convert cputime to clock and back. ++ */ ++#define cputime_to_clock_t(__ct) jiffies_to_clock_t(__ct) ++#define clock_t_to_cputime(__x) clock_t_to_jiffies(__x) ++ ++/* ++ * Convert cputime64 to clock. ++ */ ++#define cputime64_to_clock_t(__ct) jiffies_64_to_clock_t(__ct) ++ ++#endif +--- linux/include/asm-generic/div64.h ++++ linux/include/asm-generic/div64.h +@@ -0,0 +1,58 @@ ++#ifndef _ASM_GENERIC_DIV64_H ++#define _ASM_GENERIC_DIV64_H ++/* ++ * Copyright (C) 2003 Bernardo Innocenti ++ * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h ++ * ++ * The semantics of do_div() are: ++ * ++ * uint32_t do_div(uint64_t *n, uint32_t base) ++ * { ++ * uint32_t remainder = *n % base; ++ * *n = *n / base; ++ * return remainder; ++ * } ++ * ++ * NOTE: macro parameter n is evaluated multiple times, ++ * beware of side effects! ++ */ ++ ++#include ++#include ++ ++#if BITS_PER_LONG == 64 ++ ++# define do_div(n,base) ({ \ ++ uint32_t __base = (base); \ ++ uint32_t __rem; \ ++ __rem = ((uint64_t)(n)) % __base; \ ++ (n) = ((uint64_t)(n)) / __base; \ ++ __rem; \ ++ }) ++ ++#elif BITS_PER_LONG == 32 ++ ++extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); ++ ++/* The unnecessary pointer compare is there ++ * to check for type safety (n must be 64bit) ++ */ ++# define do_div(n,base) ({ \ ++ uint32_t __base = (base); \ ++ uint32_t __rem; \ ++ (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ ++ if (likely(((n) >> 32) == 0)) { \ ++ __rem = (uint32_t)(n) % __base; \ ++ (n) = (uint32_t)(n) / __base; \ ++ } else \ ++ __rem = __div64_32(&(n), __base); \ ++ __rem; \ ++ }) ++ ++#else /* BITS_PER_LONG == ?? */ ++ ++# error do_div() does not yet support the C64 ++ ++#endif /* BITS_PER_LONG */ ++ ++#endif /* _ASM_GENERIC_DIV64_H */ +--- linux/include/asm-generic/dma-mapping-broken.h ++++ linux/include/asm-generic/dma-mapping-broken.h +@@ -0,0 +1,22 @@ ++#ifndef _ASM_GENERIC_DMA_MAPPING_H ++#define _ASM_GENERIC_DMA_MAPPING_H ++ ++/* This is used for archs that do not support DMA */ ++ ++ ++static inline void * ++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, ++ int flag) ++{ ++ BUG(); ++ return NULL; ++} ++ ++static inline void ++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t dma_handle) ++{ ++ BUG(); ++} ++ ++#endif /* _ASM_GENERIC_DMA_MAPPING_H */ +--- linux/include/asm-generic/dma-mapping.h ++++ linux/include/asm-generic/dma-mapping.h +@@ -0,0 +1,309 @@ ++/* Copyright (C) 2002 by James.Bottomley@HansenPartnership.com ++ * ++ * Implements the generic device dma API via the existing pci_ one ++ * for unconverted architectures ++ */ ++ ++#ifndef _ASM_GENERIC_DMA_MAPPING_H ++#define _ASM_GENERIC_DMA_MAPPING_H ++ ++// #include ++ ++#ifdef CONFIG_PCI ++ ++/* we implement the API below in terms of the existing PCI one, ++ * so include it */ ++#include ++/* need struct page definitions */ ++#include ++ ++static inline int ++dma_supported(struct device *dev, u64 mask) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_dma_supported(to_pci_dev(dev), mask); ++} ++ ++static inline int ++dma_set_mask(struct device *dev, u64 dma_mask) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_set_dma_mask(to_pci_dev(dev), dma_mask); ++} ++ ++static inline void * ++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, ++ int flag) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); ++} ++ ++static inline void ++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t dma_handle) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); ++} ++ ++static inline dma_addr_t ++dma_map_single(struct device *dev, void *cpu_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); ++} ++ ++static inline void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); ++} ++ ++static inline dma_addr_t ++dma_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); ++} ++ ++static inline void ++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); ++} ++ ++static inline int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); ++} ++ ++static inline void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); ++} ++ ++static inline void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, ++ size, (int)direction); ++} ++ ++static inline void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, ++ size, (int)direction); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); ++} ++ ++static inline int ++dma_mapping_error(dma_addr_t dma_addr) ++{ ++ return pci_dma_mapping_error(dma_addr); ++} ++ ++ ++#else ++ ++static inline int ++dma_supported(struct device *dev, u64 mask) ++{ ++ return 0; ++} ++ ++static inline int ++dma_set_mask(struct device *dev, u64 dma_mask) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void * ++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, ++ int flag) ++{ ++ BUG(); ++ return NULL; ++} ++ ++static inline void ++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t dma_handle) ++{ ++ BUG(); ++} ++ ++static inline dma_addr_t ++dma_map_single(struct device *dev, void *cpu_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline dma_addr_t ++dma_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void ++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline int ++dma_error(dma_addr_t dma_addr) ++{ ++ return 0; ++} ++ ++#endif ++ ++/* Now for the API extensions over the pci_ one */ ++ ++#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) ++#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) ++#define dma_is_consistent(d) (1) ++ ++static inline int ++dma_get_cache_alignment(void) ++{ ++ /* no easy way to get cache size on all processors, so return ++ * the maximum possible, to be safe */ ++ return (1 << L1_CACHE_SHIFT_MAX); ++} ++ ++static inline void ++dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ /* just sync everything, that's all the pci API can do */ ++ dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction); ++} ++ ++static inline void ++dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ /* just sync everything, that's all the pci API can do */ ++ dma_sync_single_for_device(dev, dma_handle, offset+size, direction); ++} ++ ++static inline void ++dma_cache_sync(void *vaddr, size_t size, ++ enum dma_data_direction direction) ++{ ++ /* could define this in terms of the dma_cache ... operations, ++ * but if you get this on a platform, you should convert the platform ++ * to using the generic device DMA API */ ++ BUG(); ++} ++ ++#endif ++ +--- linux/include/asm-generic/errno-base.h ++++ linux/include/asm-generic/errno-base.h +@@ -0,0 +1,39 @@ ++#ifndef _ASM_GENERIC_ERRNO_BASE_H ++#define _ASM_GENERIC_ERRNO_BASE_H ++ ++#define EPERM 1 /* Operation not permitted */ ++#define ENOENT 2 /* No such file or directory */ ++#define ESRCH 3 /* No such process */ ++#define EINTR 4 /* Interrupted system call */ ++#define EIO 5 /* I/O error */ ++#define ENXIO 6 /* No such device or address */ ++#define E2BIG 7 /* Argument list too long */ ++#define ENOEXEC 8 /* Exec format error */ ++#define EBADF 9 /* Bad file number */ ++#define ECHILD 10 /* No child processes */ ++#define EAGAIN 11 /* Try again */ ++#define ENOMEM 12 /* Out of memory */ ++#define EACCES 13 /* Permission denied */ ++#define EFAULT 14 /* Bad address */ ++#define ENOTBLK 15 /* Block device required */ ++#define EBUSY 16 /* Device or resource busy */ ++#define EEXIST 17 /* File exists */ ++#define EXDEV 18 /* Cross-device link */ ++#define ENODEV 19 /* No such device */ ++#define ENOTDIR 20 /* Not a directory */ ++#define EISDIR 21 /* Is a directory */ ++#define EINVAL 22 /* Invalid argument */ ++#define ENFILE 23 /* File table overflow */ ++#define EMFILE 24 /* Too many open files */ ++#define ENOTTY 25 /* Not a typewriter */ ++#define ETXTBSY 26 /* Text file busy */ ++#define EFBIG 27 /* File too large */ ++#define ENOSPC 28 /* No space left on device */ ++#define ESPIPE 29 /* Illegal seek */ ++#define EROFS 30 /* Read-only file system */ ++#define EMLINK 31 /* Too many links */ ++#define EPIPE 32 /* Broken pipe */ ++#define EDOM 33 /* Math argument out of domain of func */ ++#define ERANGE 34 /* Math result not representable */ ++ ++#endif +--- linux/include/asm-generic/errno.h ++++ linux/include/asm-generic/errno.h +@@ -0,0 +1,105 @@ ++#ifndef _ASM_GENERIC_ERRNO_H ++#define _ASM_GENERIC_ERRNO_H ++ ++#include ++ ++#define EDEADLK 35 /* Resource deadlock would occur */ ++#define ENAMETOOLONG 36 /* File name too long */ ++#define ENOLCK 37 /* No record locks available */ ++#define ENOSYS 38 /* Function not implemented */ ++#define ENOTEMPTY 39 /* Directory not empty */ ++#define ELOOP 40 /* Too many symbolic links encountered */ ++#define EWOULDBLOCK EAGAIN /* Operation would block */ ++#define ENOMSG 42 /* No message of desired type */ ++#define EIDRM 43 /* Identifier removed */ ++#define ECHRNG 44 /* Channel number out of range */ ++#define EL2NSYNC 45 /* Level 2 not synchronized */ ++#define EL3HLT 46 /* Level 3 halted */ ++#define EL3RST 47 /* Level 3 reset */ ++#define ELNRNG 48 /* Link number out of range */ ++#define EUNATCH 49 /* Protocol driver not attached */ ++#define ENOCSI 50 /* No CSI structure available */ ++#define EL2HLT 51 /* Level 2 halted */ ++#define EBADE 52 /* Invalid exchange */ ++#define EBADR 53 /* Invalid request descriptor */ ++#define EXFULL 54 /* Exchange full */ ++#define ENOANO 55 /* No anode */ ++#define EBADRQC 56 /* Invalid request code */ ++#define EBADSLT 57 /* Invalid slot */ ++ ++#define EDEADLOCK EDEADLK ++ ++#define EBFONT 59 /* Bad font file format */ ++#define ENOSTR 60 /* Device not a stream */ ++#define ENODATA 61 /* No data available */ ++#define ETIME 62 /* Timer expired */ ++#define ENOSR 63 /* Out of streams resources */ ++#define ENONET 64 /* Machine is not on the network */ ++#define ENOPKG 65 /* Package not installed */ ++#define EREMOTE 66 /* Object is remote */ ++#define ENOLINK 67 /* Link has been severed */ ++#define EADV 68 /* Advertise error */ ++#define ESRMNT 69 /* Srmount error */ ++#define ECOMM 70 /* Communication error on send */ ++#define EPROTO 71 /* Protocol error */ ++#define EMULTIHOP 72 /* Multihop attempted */ ++#define EDOTDOT 73 /* RFS specific error */ ++#define EBADMSG 74 /* Not a data message */ ++#define EOVERFLOW 75 /* Value too large for defined data type */ ++#define ENOTUNIQ 76 /* Name not unique on network */ ++#define EBADFD 77 /* File descriptor in bad state */ ++#define EREMCHG 78 /* Remote address changed */ ++#define ELIBACC 79 /* Can not access a needed shared library */ ++#define ELIBBAD 80 /* Accessing a corrupted shared library */ ++#define ELIBSCN 81 /* .lib section in a.out corrupted */ ++#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ ++#define ELIBEXEC 83 /* Cannot exec a shared library directly */ ++#define EILSEQ 84 /* Illegal byte sequence */ ++#define ERESTART 85 /* Interrupted system call should be restarted */ ++#define ESTRPIPE 86 /* Streams pipe error */ ++#define EUSERS 87 /* Too many users */ ++#define ENOTSOCK 88 /* Socket operation on non-socket */ ++#define EDESTADDRREQ 89 /* Destination address required */ ++#define EMSGSIZE 90 /* Message too long */ ++#define EPROTOTYPE 91 /* Protocol wrong type for socket */ ++#define ENOPROTOOPT 92 /* Protocol not available */ ++#define EPROTONOSUPPORT 93 /* Protocol not supported */ ++#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ ++#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ ++#define EPFNOSUPPORT 96 /* Protocol family not supported */ ++#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ ++#define EADDRINUSE 98 /* Address already in use */ ++#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ ++#define ENETDOWN 100 /* Network is down */ ++#define ENETUNREACH 101 /* Network is unreachable */ ++#define ENETRESET 102 /* Network dropped connection because of reset */ ++#define ECONNABORTED 103 /* Software caused connection abort */ ++#define ECONNRESET 104 /* Connection reset by peer */ ++#define ENOBUFS 105 /* No buffer space available */ ++#define EISCONN 106 /* Transport endpoint is already connected */ ++#define ENOTCONN 107 /* Transport endpoint is not connected */ ++#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ ++#define ETOOMANYREFS 109 /* Too many references: cannot splice */ ++#define ETIMEDOUT 110 /* Connection timed out */ ++#define ECONNREFUSED 111 /* Connection refused */ ++#define EHOSTDOWN 112 /* Host is down */ ++#define EHOSTUNREACH 113 /* No route to host */ ++#define EALREADY 114 /* Operation already in progress */ ++#define EINPROGRESS 115 /* Operation now in progress */ ++#define ESTALE 116 /* Stale NFS file handle */ ++#define EUCLEAN 117 /* Structure needs cleaning */ ++#define ENOTNAM 118 /* Not a XENIX named type file */ ++#define ENAVAIL 119 /* No XENIX semaphores available */ ++#define EISNAM 120 /* Is a named type file */ ++#define EREMOTEIO 121 /* Remote I/O error */ ++#define EDQUOT 122 /* Quota exceeded */ ++ ++#define ENOMEDIUM 123 /* No medium found */ ++#define EMEDIUMTYPE 124 /* Wrong medium type */ ++#define ECANCELED 125 /* Operation Canceled */ ++#define ENOKEY 126 /* Required key not available */ ++#define EKEYEXPIRED 127 /* Key has expired */ ++#define EKEYREVOKED 128 /* Key has been revoked */ ++#define EKEYREJECTED 129 /* Key was rejected by service */ ++ ++#endif +--- linux/include/asm-generic/hdreg.h ++++ linux/include/asm-generic/hdreg.h +@@ -0,0 +1,8 @@ ++#warning is obsolete, please do not use it ++ ++#ifndef __ASM_GENERIC_HDREG_H ++#define __ASM_GENERIC_HDREG_H ++ ++typedef unsigned long ide_ioreg_t; ++ ++#endif /* __ASM_GENERIC_HDREG_H */ +--- linux/include/asm-generic/ide_iops.h ++++ linux/include/asm-generic/ide_iops.h +@@ -0,0 +1,38 @@ ++/* Generic I/O and MEMIO string operations. */ ++ ++#define __ide_insw insw ++#define __ide_insl insl ++#define __ide_outsw outsw ++#define __ide_outsl outsl ++ ++static __inline__ void __ide_mm_insw(void __iomem *port, void *addr, u32 count) ++{ ++ while (count--) { ++ *(u16 *)addr = readw(port); ++ addr += 2; ++ } ++} ++ ++static __inline__ void __ide_mm_insl(void __iomem *port, void *addr, u32 count) ++{ ++ while (count--) { ++ *(u32 *)addr = readl(port); ++ addr += 4; ++ } ++} ++ ++static __inline__ void __ide_mm_outsw(void __iomem *port, void *addr, u32 count) ++{ ++ while (count--) { ++ writew(*(u16 *)addr, port); ++ addr += 2; ++ } ++} ++ ++static __inline__ void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) ++{ ++ while (count--) { ++ writel(*(u32 *)addr, port); ++ addr += 4; ++ } ++} +--- linux/include/asm-generic/iomap.h ++++ linux/include/asm-generic/iomap.h +@@ -0,0 +1,63 @@ ++#ifndef __GENERIC_IO_H ++#define __GENERIC_IO_H ++ ++#include ++ ++/* ++ * These are the "generic" interfaces for doing new-style ++ * memory-mapped or PIO accesses. Architectures may do ++ * their own arch-optimized versions, these just act as ++ * wrappers around the old-style IO register access functions: ++ * read[bwl]/write[bwl]/in[bwl]/out[bwl] ++ * ++ * Don't include this directly, include it from . ++ */ ++ ++/* ++ * Read/write from/to an (offsettable) iomem cookie. It might be a PIO ++ * access or a MMIO access, these functions don't care. The info is ++ * encoded in the hardware mapping set up by the mapping functions ++ * (or the cookie itself, depending on implementation and hw). ++ * ++ * The generic routines just encode the PIO/MMIO as part of the ++ * cookie, and coldly assume that the MMIO IO mappings are not ++ * in the low address range. Architectures for which this is not ++ * true can't use this generic implementation. ++ */ ++extern unsigned int fastcall ioread8(void __iomem *); ++extern unsigned int fastcall ioread16(void __iomem *); ++extern unsigned int fastcall ioread32(void __iomem *); ++ ++extern void fastcall iowrite8(u8, void __iomem *); ++extern void fastcall iowrite16(u16, void __iomem *); ++extern void fastcall iowrite32(u32, void __iomem *); ++ ++/* ++ * "string" versions of the above. Note that they ++ * use native byte ordering for the accesses (on ++ * the assumption that IO and memory agree on a ++ * byte order, and CPU byteorder is irrelevant). ++ * ++ * They do _not_ update the port address. If you ++ * want MMIO that copies stuff laid out in MMIO ++ * memory across multiple ports, use "memcpy_toio()" ++ * and friends. ++ */ ++extern void fastcall ioread8_rep(void __iomem *port, void *buf, unsigned long count); ++extern void fastcall ioread16_rep(void __iomem *port, void *buf, unsigned long count); ++extern void fastcall ioread32_rep(void __iomem *port, void *buf, unsigned long count); ++ ++extern void fastcall iowrite8_rep(void __iomem *port, const void *buf, unsigned long count); ++extern void fastcall iowrite16_rep(void __iomem *port, const void *buf, unsigned long count); ++extern void fastcall iowrite32_rep(void __iomem *port, const void *buf, unsigned long count); ++ ++/* Create a virtual mapping cookie for an IO port range */ ++extern void __iomem *ioport_map(unsigned long port, unsigned int nr); ++extern void ioport_unmap(void __iomem *); ++ ++/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ ++struct pci_dev; ++extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); ++extern void pci_iounmap(struct pci_dev *dev, void __iomem *); ++ ++#endif +--- linux/include/asm-generic/local.h ++++ linux/include/asm-generic/local.h +@@ -0,0 +1,118 @@ ++#ifndef _ASM_GENERIC_LOCAL_H ++#define _ASM_GENERIC_LOCAL_H ++ ++// #include ++#include ++#include ++#include ++ ++/* An unsigned long type for operations which are atomic for a single ++ * CPU. Usually used in combination with per-cpu variables. */ ++ ++#if BITS_PER_LONG == 32 ++/* Implement in terms of atomics. */ ++ ++/* Don't use typedef: don't want them to be mixed with atomic_t's. */ ++typedef struct ++{ ++ atomic_t a; ++} local_t; ++ ++#define LOCAL_INIT(i) { ATOMIC_INIT(i) } ++ ++#define local_read(l) ((unsigned long)atomic_read(&(l)->a)) ++#define local_set(l,i) atomic_set((&(l)->a),(i)) ++#define local_inc(l) atomic_inc(&(l)->a) ++#define local_dec(l) atomic_dec(&(l)->a) ++#define local_add(i,l) atomic_add((i),(&(l)->a)) ++#define local_sub(i,l) atomic_sub((i),(&(l)->a)) ++ ++/* Non-atomic variants, ie. preemption disabled and won't be touched ++ * in interrupt, etc. Some archs can optimize this case well. */ ++#define __local_inc(l) local_set((l), local_read(l) + 1) ++#define __local_dec(l) local_set((l), local_read(l) - 1) ++#define __local_add(i,l) local_set((l), local_read(l) + (i)) ++#define __local_sub(i,l) local_set((l), local_read(l) - (i)) ++ ++#else /* ... can't use atomics. */ ++/* Implement in terms of three variables. ++ Another option would be to use local_irq_save/restore. */ ++ ++typedef struct ++{ ++ /* 0 = in hardirq, 1 = in softirq, 2 = usermode. */ ++ unsigned long v[3]; ++} local_t; ++ ++#define _LOCAL_VAR(l) ((l)->v[!in_interrupt() + !in_irq()]) ++ ++#define LOCAL_INIT(i) { { (i), 0, 0 } } ++ ++static inline unsigned long local_read(local_t *l) ++{ ++ return l->v[0] + l->v[1] + l->v[2]; ++} ++ ++static inline void local_set(local_t *l, unsigned long v) ++{ ++ l->v[0] = v; ++ l->v[1] = l->v[2] = 0; ++} ++ ++static inline void local_inc(local_t *l) ++{ ++ preempt_disable(); ++ _LOCAL_VAR(l)++; ++ preempt_enable(); ++} ++ ++static inline void local_dec(local_t *l) ++{ ++ preempt_disable(); ++ _LOCAL_VAR(l)--; ++ preempt_enable(); ++} ++ ++static inline void local_add(unsigned long v, local_t *l) ++{ ++ preempt_disable(); ++ _LOCAL_VAR(l) += v; ++ preempt_enable(); ++} ++ ++static inline void local_sub(unsigned long v, local_t *l) ++{ ++ preempt_disable(); ++ _LOCAL_VAR(l) -= v; ++ preempt_enable(); ++} ++ ++/* Non-atomic variants, ie. preemption disabled and won't be touched ++ * in interrupt, etc. Some archs can optimize this case well. */ ++#define __local_inc(l) ((l)->v[0]++) ++#define __local_dec(l) ((l)->v[0]--) ++#define __local_add(i,l) ((l)->v[0] += (i)) ++#define __local_sub(i,l) ((l)->v[0] -= (i)) ++ ++#endif /* Non-atomic implementation */ ++ ++/* Use these for per-cpu local_t variables: on some archs they are ++ * much more efficient than these naive implementations. Note they take ++ * a variable (eg. mystruct.foo), not an address. ++ */ ++#define cpu_local_read(v) local_read(&__get_cpu_var(v)) ++#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i)) ++#define cpu_local_inc(v) local_inc(&__get_cpu_var(v)) ++#define cpu_local_dec(v) local_dec(&__get_cpu_var(v)) ++#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v)) ++#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v)) ++ ++/* Non-atomic increments, ie. preemption disabled and won't be touched ++ * in interrupt, etc. Some archs can optimize this case well. ++ */ ++#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v)) ++#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v)) ++#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v)) ++#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v)) ++ ++#endif /* _ASM_GENERIC_LOCAL_H */ +--- linux/include/asm-generic/pci-dma-compat.h ++++ linux/include/asm-generic/pci-dma-compat.h +@@ -0,0 +1,107 @@ ++/* include this file if the platform implements the dma_ DMA Mapping API ++ * and wants to provide the pci_ DMA Mapping API in terms of it */ ++ ++#ifndef _ASM_GENERIC_PCI_DMA_COMPAT_H ++#define _ASM_GENERIC_PCI_DMA_COMPAT_H ++ ++#include ++ ++/* note pci_set_dma_mask isn't here, since it's a public function ++ * exported from drivers/pci, use dma_supported instead */ ++ ++static inline int ++pci_dma_supported(struct pci_dev *hwdev, u64 mask) ++{ ++ return dma_supported(hwdev == NULL ? NULL : &hwdev->dev, mask); ++} ++ ++static inline void * ++pci_alloc_consistent(struct pci_dev *hwdev, size_t size, ++ dma_addr_t *dma_handle) ++{ ++ return dma_alloc_coherent(hwdev == NULL ? NULL : &hwdev->dev, size, dma_handle, GFP_ATOMIC); ++} ++ ++static inline void ++pci_free_consistent(struct pci_dev *hwdev, size_t size, ++ void *vaddr, dma_addr_t dma_handle) ++{ ++ dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev, size, vaddr, dma_handle); ++} ++ ++static inline dma_addr_t ++pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) ++{ ++ return dma_map_single(hwdev == NULL ? NULL : &hwdev->dev, ptr, size, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, ++ size_t size, int direction) ++{ ++ dma_unmap_single(hwdev == NULL ? NULL : &hwdev->dev, dma_addr, size, (enum dma_data_direction)direction); ++} ++ ++static inline dma_addr_t ++pci_map_page(struct pci_dev *hwdev, struct page *page, ++ unsigned long offset, size_t size, int direction) ++{ ++ return dma_map_page(hwdev == NULL ? NULL : &hwdev->dev, page, offset, size, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address, ++ size_t size, int direction) ++{ ++ dma_unmap_page(hwdev == NULL ? NULL : &hwdev->dev, dma_address, size, (enum dma_data_direction)direction); ++} ++ ++static inline int ++pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, ++ int nents, int direction) ++{ ++ return dma_map_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, ++ int nents, int direction) ++{ ++ dma_unmap_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, ++ size_t size, int direction) ++{ ++ dma_sync_single_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, ++ size_t size, int direction) ++{ ++ dma_sync_single_for_device(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, ++ int nelems, int direction) ++{ ++ dma_sync_sg_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, ++ int nelems, int direction) ++{ ++ dma_sync_sg_for_device(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); ++} ++ ++static inline int ++pci_dma_mapping_error(dma_addr_t dma_addr) ++{ ++ return dma_mapping_error(dma_addr); ++} ++ ++#endif +--- linux/include/asm-generic/pci.h ++++ linux/include/asm-generic/pci.h +@@ -0,0 +1,34 @@ ++/* ++ * linux/include/asm-generic/pci.h ++ * ++ * Copyright (C) 2003 Russell King ++ */ ++#ifndef _ASM_GENERIC_PCI_H ++#define _ASM_GENERIC_PCI_H ++ ++/** ++ * pcibios_resource_to_bus - convert resource to PCI bus address ++ * @dev: device which owns this resource ++ * @region: converted bus-centric region (start,end) ++ * @res: resource to convert ++ * ++ * Convert a resource to a PCI device bus address or bus window. ++ */ ++static inline void ++pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, ++ struct resource *res) ++{ ++ region->start = res->start; ++ region->end = res->end; ++} ++ ++#define pcibios_scan_all_fns(a, b) 0 ++ ++#ifndef HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ ++static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) ++{ ++ return channel ? 15 : 14; ++} ++#endif /* HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ */ ++ ++#endif +--- linux/include/asm-generic/percpu.h ++++ linux/include/asm-generic/percpu.h +@@ -0,0 +1,42 @@ ++#ifndef _ASM_GENERIC_PERCPU_H_ ++#define _ASM_GENERIC_PERCPU_H_ ++#include ++ ++#define __GENERIC_PER_CPU ++#ifdef CONFIG_SMP ++ ++extern unsigned long __per_cpu_offset[NR_CPUS]; ++ ++/* Separate out the type, so (int[3], foo) works. */ ++#define DEFINE_PER_CPU(type, name) \ ++ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name ++ ++/* var is in discarded region: offset to particular copy we want */ ++#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) ++#define __get_cpu_var(var) per_cpu(var, smp_processor_id()) ++ ++/* A macro to avoid #include hell... */ ++#define percpu_modcopy(pcpudst, src, size) \ ++do { \ ++ unsigned int __i; \ ++ for (__i = 0; __i < NR_CPUS; __i++) \ ++ if (cpu_possible(__i)) \ ++ memcpy((pcpudst)+__per_cpu_offset[__i], \ ++ (src), (size)); \ ++} while (0) ++#else /* ! SMP */ ++ ++#define DEFINE_PER_CPU(type, name) \ ++ __typeof__(type) per_cpu__##name ++ ++#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var)) ++#define __get_cpu_var(var) per_cpu__##var ++ ++#endif /* SMP */ ++ ++#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name ++ ++#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var) ++#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var) ++ ++#endif /* _ASM_GENERIC_PERCPU_H_ */ +--- linux/include/asm-generic/pgtable.h ++++ linux/include/asm-generic/pgtable.h +@@ -0,0 +1,137 @@ ++#ifndef _ASM_GENERIC_PGTABLE_H ++#define _ASM_GENERIC_PGTABLE_H ++ ++#ifndef __HAVE_ARCH_PTEP_ESTABLISH ++/* ++ * Establish a new mapping: ++ * - flush the old one ++ * - update the page tables ++ * - inform the TLB about the new one ++ * ++ * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock. ++ * ++ * Note: the old pte is known to not be writable, so we don't need to ++ * worry about dirty bits etc getting lost. ++ */ ++#ifndef __HAVE_ARCH_SET_PTE_ATOMIC ++#define ptep_establish(__vma, __address, __ptep, __entry) \ ++do { \ ++ set_pte(__ptep, __entry); \ ++ flush_tlb_page(__vma, __address); \ ++} while (0) ++#else /* __HAVE_ARCH_SET_PTE_ATOMIC */ ++#define ptep_establish(__vma, __address, __ptep, __entry) \ ++do { \ ++ set_pte_atomic(__ptep, __entry); \ ++ flush_tlb_page(__vma, __address); \ ++} while (0) ++#endif /* __HAVE_ARCH_SET_PTE_ATOMIC */ ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS ++/* ++ * Largely same as above, but only sets the access flags (dirty, ++ * accessed, and writable). Furthermore, we know it always gets set ++ * to a "more permissive" setting, which allows most architectures ++ * to optimize this. ++ */ ++#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ ++do { \ ++ set_pte(__ptep, __entry); \ ++ flush_tlb_page(__vma, __address); \ ++} while (0) ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++static inline int ptep_test_and_clear_young(pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (!pte_young(pte)) ++ return 0; ++ set_pte(ptep, pte_mkold(pte)); ++ return 1; ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH ++#define ptep_clear_flush_young(__vma, __address, __ptep) \ ++({ \ ++ int __young = ptep_test_and_clear_young(__ptep); \ ++ if (__young) \ ++ flush_tlb_page(__vma, __address); \ ++ __young; \ ++}) ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY ++static inline int ptep_test_and_clear_dirty(pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (!pte_dirty(pte)) ++ return 0; ++ set_pte(ptep, pte_mkclean(pte)); ++ return 1; ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH ++#define ptep_clear_flush_dirty(__vma, __address, __ptep) \ ++({ \ ++ int __dirty = ptep_test_and_clear_dirty(__ptep); \ ++ if (__dirty) \ ++ flush_tlb_page(__vma, __address); \ ++ __dirty; \ ++}) ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR ++static inline pte_t ptep_get_and_clear(pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ pte_clear(ptep); ++ return pte; ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH ++#define ptep_clear_flush(__vma, __address, __ptep) \ ++({ \ ++ pte_t __pte = ptep_get_and_clear(__ptep); \ ++ flush_tlb_page(__vma, __address); \ ++ __pte; \ ++}) ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_SET_WRPROTECT ++static inline void ptep_set_wrprotect(pte_t *ptep) ++{ ++ pte_t old_pte = *ptep; ++ set_pte(ptep, pte_wrprotect(old_pte)); ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_MKDIRTY ++static inline void ptep_mkdirty(pte_t *ptep) ++{ ++ pte_t old_pte = *ptep; ++ set_pte(ptep, pte_mkdirty(old_pte)); ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTE_SAME ++#define pte_same(A,B) (pte_val(A) == pte_val(B)) ++#endif ++ ++#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY ++#define page_test_and_clear_dirty(page) (0) ++#endif ++ ++#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG ++#define page_test_and_clear_young(page) (0) ++#endif ++ ++#ifndef __HAVE_ARCH_PGD_OFFSET_GATE ++#define pgd_offset_gate(mm, addr) pgd_offset(mm, addr) ++#endif ++ ++#endif /* _ASM_GENERIC_PGTABLE_H */ +--- linux/include/asm-generic/pgtable-nopmd.h ++++ linux/include/asm-generic/pgtable-nopmd.h +@@ -0,0 +1,60 @@ ++#ifndef _PGTABLE_NOPMD_H ++#define _PGTABLE_NOPMD_H ++ ++#ifndef __ASSEMBLY__ ++ ++#include ++ ++/* ++ * Having the pmd type consist of a pud gets the size right, and allows ++ * us to conceptually access the pud entry that this pmd is folded into ++ * without casting. ++ */ ++typedef struct { pud_t pud; } pmd_t; ++ ++#define PMD_SHIFT PUD_SHIFT ++#define PTRS_PER_PMD 1 ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PMD_MASK (~(PMD_SIZE-1)) ++ ++/* ++ * The "pud_xxx()" functions here are trivial for a folded two-level ++ * setup: the pmd is never bad, and a pmd always exists (as it's folded ++ * into the pud entry) ++ */ ++static inline int pud_none(pud_t pud) { return 0; } ++static inline int pud_bad(pud_t pud) { return 0; } ++static inline int pud_present(pud_t pud) { return 1; } ++static inline void pud_clear(pud_t *pud) { } ++#define pmd_ERROR(pmd) (pud_ERROR((pmd).pud)) ++ ++#define pud_populate(mm, pmd, pte) do { } while (0) ++ ++/* ++ * (pmds are folded into puds so this doesn't get actually called, ++ * but the define is needed for a generic inline function.) ++ */ ++#define set_pud(pudptr, pudval) set_pmd((pmd_t *)(pudptr), (pmd_t) { pudval }) ++ ++static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address) ++{ ++ return (pmd_t *)pud; ++} ++ ++#define pmd_val(x) (pud_val((x).pud)) ++#define __pmd(x) ((pmd_t) { __pud(x) } ) ++ ++#define pud_page(pud) (pmd_page((pmd_t){ pud })) ++#define pud_page_kernel(pud) (pmd_page_kernel((pmd_t){ pud })) ++ ++/* ++ * allocating and freeing a pmd is trivial: the 1-entry pmd is ++ * inside the pud, so has no extra memory associated with it. ++ */ ++#define pmd_alloc_one(mm, address) NULL ++#define pmd_free(x) do { } while (0) ++#define __pmd_free_tlb(tlb, x) do { } while (0) ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* _PGTABLE_NOPMD_H */ +--- linux/include/asm-generic/pgtable-nopud.h ++++ linux/include/asm-generic/pgtable-nopud.h +@@ -0,0 +1,56 @@ ++#ifndef _PGTABLE_NOPUD_H ++#define _PGTABLE_NOPUD_H ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * Having the pud type consist of a pgd gets the size right, and allows ++ * us to conceptually access the pgd entry that this pud is folded into ++ * without casting. ++ */ ++typedef struct { pgd_t pgd; } pud_t; ++ ++#define PUD_SHIFT PGDIR_SHIFT ++#define PTRS_PER_PUD 1 ++#define PUD_SIZE (1UL << PUD_SHIFT) ++#define PUD_MASK (~(PUD_SIZE-1)) ++ ++/* ++ * The "pgd_xxx()" functions here are trivial for a folded two-level ++ * setup: the pud is never bad, and a pud always exists (as it's folded ++ * into the pgd entry) ++ */ ++static inline int pgd_none(pgd_t pgd) { return 0; } ++static inline int pgd_bad(pgd_t pgd) { return 0; } ++static inline int pgd_present(pgd_t pgd) { return 1; } ++static inline void pgd_clear(pgd_t *pgd) { } ++#define pud_ERROR(pud) (pgd_ERROR((pud).pgd)) ++ ++#define pgd_populate(mm, pgd, pud) do { } while (0) ++/* ++ * (puds are folded into pgds so this doesn't get actually called, ++ * but the define is needed for a generic inline function.) ++ */ ++#define set_pgd(pgdptr, pgdval) set_pud((pud_t *)(pgdptr), (pud_t) { pgdval }) ++ ++static inline pud_t * pud_offset(pgd_t * pgd, unsigned long address) ++{ ++ return (pud_t *)pgd; ++} ++ ++#define pud_val(x) (pgd_val((x).pgd)) ++#define __pud(x) ((pud_t) { __pgd(x) } ) ++ ++#define pgd_page(pgd) (pud_page((pud_t){ pgd })) ++#define pgd_page_kernel(pgd) (pud_page_kernel((pud_t){ pgd })) ++ ++/* ++ * allocating and freeing a pud is trivial: the 1-entry pud is ++ * inside the pgd, so has no extra memory associated with it. ++ */ ++#define pud_alloc_one(mm, address) NULL ++#define pud_free(x) do { } while (0) ++#define __pud_free_tlb(tlb, x) do { } while (0) ++ ++#endif /* __ASSEMBLY__ */ ++#endif /* _PGTABLE_NOPUD_H */ +--- linux/include/asm-generic/resource.h ++++ linux/include/asm-generic/resource.h +@@ -0,0 +1,60 @@ ++#ifndef _ASM_GENERIC_RESOURCE_H ++#define _ASM_GENERIC_RESOURCE_H ++ ++/* ++ * Resource limits ++ */ ++ ++/* Allow arch to control resource order */ ++#ifndef __ARCH_RLIMIT_ORDER ++#define RLIMIT_CPU 0 /* CPU time in ms */ ++#define RLIMIT_FSIZE 1 /* Maximum filesize */ ++#define RLIMIT_DATA 2 /* max data size */ ++#define RLIMIT_STACK 3 /* max stack size */ ++#define RLIMIT_CORE 4 /* max core file size */ ++#define RLIMIT_RSS 5 /* max resident set size */ ++#define RLIMIT_NPROC 6 /* max number of processes */ ++#define RLIMIT_NOFILE 7 /* max number of open files */ ++#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ ++#define RLIMIT_AS 9 /* address space limit */ ++#define RLIMIT_LOCKS 10 /* maximum file locks held */ ++#define RLIMIT_SIGPENDING 11 /* max number of pending signals */ ++#define RLIMIT_MSGQUEUE 12 /* maximum bytes in POSIX mqueues */ ++ ++#define RLIM_NLIMITS 13 ++#endif ++ ++/* ++ * SuS says limits have to be unsigned. ++ * Which makes a ton more sense anyway. ++ */ ++#ifndef RLIM_INFINITY ++#define RLIM_INFINITY (~0UL) ++#endif ++ ++#ifndef _STK_LIM_MAX ++#define _STK_LIM_MAX RLIM_INFINITY ++#endif ++ ++#ifdef __KERNEL__ ++ ++#define INIT_RLIMITS \ ++{ \ ++ [RLIMIT_CPU] = { RLIM_INFINITY, RLIM_INFINITY }, \ ++ [RLIMIT_FSIZE] = { RLIM_INFINITY, RLIM_INFINITY }, \ ++ [RLIMIT_DATA] = { RLIM_INFINITY, RLIM_INFINITY }, \ ++ [RLIMIT_STACK] = { _STK_LIM, _STK_LIM_MAX }, \ ++ [RLIMIT_CORE] = { 0, RLIM_INFINITY }, \ ++ [RLIMIT_RSS] = { RLIM_INFINITY, RLIM_INFINITY }, \ ++ [RLIMIT_NPROC] = { 0, 0 }, \ ++ [RLIMIT_NOFILE] = { INR_OPEN, INR_OPEN }, \ ++ [RLIMIT_MEMLOCK] = { MLOCK_LIMIT, MLOCK_LIMIT }, \ ++ [RLIMIT_AS] = { RLIM_INFINITY, RLIM_INFINITY }, \ ++ [RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY }, \ ++ [RLIMIT_SIGPENDING] = { MAX_SIGPENDING, MAX_SIGPENDING }, \ ++ [RLIMIT_MSGQUEUE] = { MQ_BYTES_MAX, MQ_BYTES_MAX }, \ ++} ++ ++#endif /* __KERNEL__ */ ++ ++#endif +--- linux/include/asm-generic/rmap.h ++++ linux/include/asm-generic/rmap.h +@@ -0,0 +1,90 @@ ++#ifndef _GENERIC_RMAP_H ++#define _GENERIC_RMAP_H ++/* ++ * linux/include/asm-generic/rmap.h ++ * ++ * Architecture dependent parts of the reverse mapping code, ++ * this version should work for most architectures with a ++ * 'normal' page table layout. ++ * ++ * We use the struct page of the page table page to find out ++ * the process and full address of a page table entry: ++ * - page->mapping points to the process' mm_struct ++ * - page->index has the high bits of the address ++ * - the lower bits of the address are calculated from the ++ * offset of the page table entry within the page table page ++ * ++ * For CONFIG_HIGHPTE, we need to represent the address of a pte in a ++ * scalar pte_addr_t. The pfn of the pte's page is shifted left by PAGE_SIZE ++ * bits and is then ORed with the byte offset of the pte within its page. ++ * ++ * For CONFIG_HIGHMEM4G, the pte_addr_t is 32 bits. 20 for the pfn, 12 for ++ * the offset. ++ * ++ * For CONFIG_HIGHMEM64G, the pte_addr_t is 64 bits. 52 for the pfn, 12 for ++ * the offset. ++ */ ++#include ++ ++static inline void pgtable_add_rmap(struct page * page, struct mm_struct * mm, unsigned long address) ++{ ++#ifdef BROKEN_PPC_PTE_ALLOC_ONE ++ /* OK, so PPC calls pte_alloc() before mem_map[] is setup ... ;( */ ++ extern int mem_init_done; ++ ++ if (!mem_init_done) ++ return; ++#endif ++ page->mapping = (void *)mm; ++ page->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1); ++ inc_page_state(nr_page_table_pages); ++} ++ ++static inline void pgtable_remove_rmap(struct page * page) ++{ ++ page->mapping = NULL; ++ page->index = 0; ++ dec_page_state(nr_page_table_pages); ++} ++ ++static inline struct mm_struct * ptep_to_mm(pte_t * ptep) ++{ ++ struct page * page = kmap_atomic_to_page(ptep); ++ return (struct mm_struct *) page->mapping; ++} ++ ++static inline unsigned long ptep_to_address(pte_t * ptep) ++{ ++ struct page * page = kmap_atomic_to_page(ptep); ++ unsigned long low_bits; ++ low_bits = ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE; ++ return page->index + low_bits; ++} ++ ++#ifdef CONFIG_HIGHPTE ++static inline pte_addr_t ptep_to_paddr(pte_t *ptep) ++{ ++ pte_addr_t paddr; ++ paddr = ((pte_addr_t)page_to_pfn(kmap_atomic_to_page(ptep))) << PAGE_SHIFT; ++ return paddr + (pte_addr_t)((unsigned long)ptep & ~PAGE_MASK); ++} ++#else ++static inline pte_addr_t ptep_to_paddr(pte_t *ptep) ++{ ++ return (pte_addr_t)ptep; ++} ++#endif ++ ++#ifndef CONFIG_HIGHPTE ++static inline pte_t *rmap_ptep_map(pte_addr_t pte_paddr) ++{ ++ return (pte_t *)pte_paddr; ++} ++ ++static inline void rmap_ptep_unmap(pte_t *pte) ++{ ++ return; ++} ++#endif ++ ++#endif /* _GENERIC_RMAP_H */ +--- linux/include/asm-generic/rtc.h ++++ linux/include/asm-generic/rtc.h +@@ -0,0 +1,213 @@ ++/* ++ * inclue/asm-generic/rtc.h ++ * ++ * Author: Tom Rini ++ * ++ * Based on: ++ * drivers/char/rtc.c ++ * ++ * Please read the COPYING file for all license details. ++ */ ++ ++#ifndef __ASM_RTC_H__ ++#define __ASM_RTC_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++#define RTC_PIE 0x40 /* periodic interrupt enable */ ++#define RTC_AIE 0x20 /* alarm interrupt enable */ ++#define RTC_UIE 0x10 /* update-finished interrupt enable */ ++ ++/* some dummy definitions */ ++#define RTC_BATT_BAD 0x100 /* battery bad */ ++#define RTC_SQWE 0x08 /* enable square-wave output */ ++#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ ++#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ ++#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ ++ ++/* ++ * Returns true if a clock update is in progress ++ */ ++static inline unsigned char rtc_is_updating(void) ++{ ++ unsigned char uip; ++ ++ spin_lock_irq(&rtc_lock); ++ uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); ++ spin_unlock_irq(&rtc_lock); ++ return uip; ++} ++ ++static inline unsigned int get_rtc_time(struct rtc_time *time) ++{ ++ unsigned long uip_watchdog = jiffies; ++ unsigned char ctrl; ++#ifdef CONFIG_MACH_DECSTATION ++ unsigned int real_year; ++#endif ++ ++ /* ++ * read RTC once any update in progress is done. The update ++ * can take just over 2ms. We wait 10 to 20ms. There is no need to ++ * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. ++ * If you need to know *exactly* when a second has started, enable ++ * periodic update complete interrupts, (via ioctl) and then ++ * immediately read /dev/rtc which will block until you get the IRQ. ++ * Once the read clears, read the RTC time (again via ioctl). Easy. ++ */ ++ ++ if (rtc_is_updating() != 0) ++ while (jiffies - uip_watchdog < 2*HZ/100) { ++ barrier(); ++ cpu_relax(); ++ } ++ ++ /* ++ * Only the values that we read from the RTC are set. We leave ++ * tm_wday, tm_yday and tm_isdst untouched. Even though the ++ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated ++ * by the RTC when initially set to a non-zero value. ++ */ ++ spin_lock_irq(&rtc_lock); ++ time->tm_sec = CMOS_READ(RTC_SECONDS); ++ time->tm_min = CMOS_READ(RTC_MINUTES); ++ time->tm_hour = CMOS_READ(RTC_HOURS); ++ time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); ++ time->tm_mon = CMOS_READ(RTC_MONTH); ++ time->tm_year = CMOS_READ(RTC_YEAR); ++#ifdef CONFIG_MACH_DECSTATION ++ real_year = CMOS_READ(RTC_DEC_YEAR); ++#endif ++ ctrl = CMOS_READ(RTC_CONTROL); ++ spin_unlock_irq(&rtc_lock); ++ ++ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) ++ { ++ BCD_TO_BIN(time->tm_sec); ++ BCD_TO_BIN(time->tm_min); ++ BCD_TO_BIN(time->tm_hour); ++ BCD_TO_BIN(time->tm_mday); ++ BCD_TO_BIN(time->tm_mon); ++ BCD_TO_BIN(time->tm_year); ++ } ++ ++#ifdef CONFIG_MACH_DECSTATION ++ time->tm_year += real_year - 72; ++#endif ++ ++ /* ++ * Account for differences between how the RTC uses the values ++ * and how they are defined in a struct rtc_time; ++ */ ++ if (time->tm_year <= 69) ++ time->tm_year += 100; ++ ++ time->tm_mon--; ++ ++ return RTC_24H; ++} ++ ++/* Set the current date and time in the real time clock. */ ++static inline int set_rtc_time(struct rtc_time *time) ++{ ++ unsigned char mon, day, hrs, min, sec; ++ unsigned char save_control, save_freq_select; ++ unsigned int yrs; ++#ifdef CONFIG_MACH_DECSTATION ++ unsigned int real_yrs, leap_yr; ++#endif ++ ++ yrs = time->tm_year; ++ mon = time->tm_mon + 1; /* tm_mon starts at zero */ ++ day = time->tm_mday; ++ hrs = time->tm_hour; ++ min = time->tm_min; ++ sec = time->tm_sec; ++ ++ if (yrs > 255) /* They are unsigned */ ++ return -EINVAL; ++ ++ spin_lock_irq(&rtc_lock); ++#ifdef CONFIG_MACH_DECSTATION ++ real_yrs = yrs; ++ leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || ++ !((yrs + 1900) % 400)); ++ yrs = 72; ++ ++ /* ++ * We want to keep the year set to 73 until March ++ * for non-leap years, so that Feb, 29th is handled ++ * correctly. ++ */ ++ if (!leap_yr && mon < 3) { ++ real_yrs--; ++ yrs = 73; ++ } ++#endif ++ /* These limits and adjustments are independent of ++ * whether the chip is in binary mode or not. ++ */ ++ if (yrs > 169) { ++ spin_unlock_irq(&rtc_lock); ++ return -EINVAL; ++ } ++ ++ if (yrs >= 100) ++ yrs -= 100; ++ ++ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ++ || RTC_ALWAYS_BCD) { ++ BIN_TO_BCD(sec); ++ BIN_TO_BCD(min); ++ BIN_TO_BCD(hrs); ++ BIN_TO_BCD(day); ++ BIN_TO_BCD(mon); ++ BIN_TO_BCD(yrs); ++ } ++ ++ save_control = CMOS_READ(RTC_CONTROL); ++ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); ++ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); ++ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); ++ ++#ifdef CONFIG_MACH_DECSTATION ++ CMOS_WRITE(real_yrs, RTC_DEC_YEAR); ++#endif ++ CMOS_WRITE(yrs, RTC_YEAR); ++ CMOS_WRITE(mon, RTC_MONTH); ++ CMOS_WRITE(day, RTC_DAY_OF_MONTH); ++ CMOS_WRITE(hrs, RTC_HOURS); ++ CMOS_WRITE(min, RTC_MINUTES); ++ CMOS_WRITE(sec, RTC_SECONDS); ++ ++ CMOS_WRITE(save_control, RTC_CONTROL); ++ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); ++ ++ spin_unlock_irq(&rtc_lock); ++ ++ return 0; ++} ++ ++static inline unsigned int get_rtc_ss(void) ++{ ++ struct rtc_time h; ++ ++ get_rtc_time(&h); ++ return h.tm_sec; ++} ++ ++static inline int get_rtc_pll(struct rtc_pll_info *pll) ++{ ++ return -EINVAL; ++} ++static inline int set_rtc_pll(struct rtc_pll_info *pll) ++{ ++ return -EINVAL; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASM_RTC_H__ */ +--- linux/include/asm-generic/sections.h ++++ linux/include/asm-generic/sections.h +@@ -0,0 +1,13 @@ ++#ifndef _ASM_GENERIC_SECTIONS_H_ ++#define _ASM_GENERIC_SECTIONS_H_ ++ ++/* References to section boundaries */ ++ ++extern char _text[], _stext[], _etext[]; ++extern char _data[], _sdata[], _edata[]; ++extern char __bss_start[], __bss_stop[]; ++extern char __init_begin[], __init_end[]; ++extern char _sinittext[], _einittext[]; ++extern char _end[]; ++ ++#endif /* _ASM_GENERIC_SECTIONS_H_ */ +--- linux/include/asm-generic/siginfo.h ++++ linux/include/asm-generic/siginfo.h +@@ -0,0 +1,288 @@ ++#ifndef _ASM_GENERIC_SIGINFO_H ++#define _ASM_GENERIC_SIGINFO_H ++ ++#include ++#include ++#include ++ ++typedef union sigval { ++ int sival_int; ++ void __user *sival_ptr; ++} sigval_t; ++ ++/* ++ * This is the size (including padding) of the part of the ++ * struct siginfo that is before the union. ++ */ ++#ifndef __ARCH_SI_PREAMBLE_SIZE ++#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int)) ++#endif ++ ++#define SI_MAX_SIZE 128 ++#ifndef SI_PAD_SIZE ++#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int)) ++#endif ++ ++#ifndef __ARCH_SI_UID_T ++#define __ARCH_SI_UID_T uid_t ++#endif ++ ++/* ++ * The default "si_band" type is "long", as specified by POSIX. ++ * However, some architectures want to override this to "int" ++ * for historical compatibility reasons, so we allow that. ++ */ ++#ifndef __ARCH_SI_BAND_T ++#define __ARCH_SI_BAND_T long ++#endif ++ ++#ifndef HAVE_ARCH_SIGINFO_T ++ ++typedef struct siginfo { ++ int si_signo; ++ int si_errno; ++ int si_code; ++ ++ union { ++ int _pad[SI_PAD_SIZE]; ++ ++ /* kill() */ ++ struct { ++ pid_t _pid; /* sender's pid */ ++ __ARCH_SI_UID_T _uid; /* sender's uid */ ++ } _kill; ++ ++ /* POSIX.1b timers */ ++ struct { ++ timer_t _tid; /* timer id */ ++ int _overrun; /* overrun count */ ++ char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)]; ++ sigval_t _sigval; /* same as below */ ++ int _sys_private; /* not to be passed to user */ ++ } _timer; ++ ++ /* POSIX.1b signals */ ++ struct { ++ pid_t _pid; /* sender's pid */ ++ __ARCH_SI_UID_T _uid; /* sender's uid */ ++ sigval_t _sigval; ++ } _rt; ++ ++ /* SIGCHLD */ ++ struct { ++ pid_t _pid; /* which child */ ++ __ARCH_SI_UID_T _uid; /* sender's uid */ ++ int _status; /* exit code */ ++ clock_t _utime; ++ clock_t _stime; ++ } _sigchld; ++ ++ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ ++ struct { ++ void __user *_addr; /* faulting insn/memory ref. */ ++#ifdef __ARCH_SI_TRAPNO ++ int _trapno; /* TRAP # which caused the signal */ ++#endif ++ } _sigfault; ++ ++ /* SIGPOLL */ ++ struct { ++ __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ ++ int _fd; ++ } _sigpoll; ++ } _sifields; ++} siginfo_t; ++ ++#endif ++ ++/* ++ * How these fields are to be accessed. ++ */ ++#define si_pid _sifields._kill._pid ++#define si_uid _sifields._kill._uid ++#define si_tid _sifields._timer._tid ++#define si_overrun _sifields._timer._overrun ++#define si_sys_private _sifields._timer._sys_private ++#define si_status _sifields._sigchld._status ++#define si_utime _sifields._sigchld._utime ++#define si_stime _sifields._sigchld._stime ++#define si_value _sifields._rt._sigval ++#define si_int _sifields._rt._sigval.sival_int ++#define si_ptr _sifields._rt._sigval.sival_ptr ++#define si_addr _sifields._sigfault._addr ++#ifdef __ARCH_SI_TRAPNO ++#define si_trapno _sifields._sigfault._trapno ++#endif ++#define si_band _sifields._sigpoll._band ++#define si_fd _sifields._sigpoll._fd ++ ++#ifdef __KERNEL__ ++#define __SI_MASK 0xffff0000u ++#define __SI_KILL (0 << 16) ++#define __SI_TIMER (1 << 16) ++#define __SI_POLL (2 << 16) ++#define __SI_FAULT (3 << 16) ++#define __SI_CHLD (4 << 16) ++#define __SI_RT (5 << 16) ++#define __SI_MESGQ (6 << 16) ++#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) ++#else ++#define __SI_KILL 0 ++#define __SI_TIMER 0 ++#define __SI_POLL 0 ++#define __SI_FAULT 0 ++#define __SI_CHLD 0 ++#define __SI_RT 0 ++#define __SI_MESGQ 0 ++#define __SI_CODE(T,N) (N) ++#endif ++ ++/* ++ * si_code values ++ * Digital reserves positive values for kernel-generated signals. ++ */ ++#define SI_USER 0 /* sent by kill, sigsend, raise */ ++#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ ++#define SI_QUEUE -1 /* sent by sigqueue */ ++#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */ ++#define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change */ ++#define SI_ASYNCIO -4 /* sent by AIO completion */ ++#define SI_SIGIO -5 /* sent by queued SIGIO */ ++#define SI_TKILL -6 /* sent by tkill system call */ ++#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */ ++ ++#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) ++#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) ++ ++/* ++ * SIGILL si_codes ++ */ ++#define ILL_ILLOPC (__SI_FAULT|1) /* illegal opcode */ ++#define ILL_ILLOPN (__SI_FAULT|2) /* illegal operand */ ++#define ILL_ILLADR (__SI_FAULT|3) /* illegal addressing mode */ ++#define ILL_ILLTRP (__SI_FAULT|4) /* illegal trap */ ++#define ILL_PRVOPC (__SI_FAULT|5) /* privileged opcode */ ++#define ILL_PRVREG (__SI_FAULT|6) /* privileged register */ ++#define ILL_COPROC (__SI_FAULT|7) /* coprocessor error */ ++#define ILL_BADSTK (__SI_FAULT|8) /* internal stack error */ ++#define NSIGILL 8 ++ ++/* ++ * SIGFPE si_codes ++ */ ++#define FPE_INTDIV (__SI_FAULT|1) /* integer divide by zero */ ++#define FPE_INTOVF (__SI_FAULT|2) /* integer overflow */ ++#define FPE_FLTDIV (__SI_FAULT|3) /* floating point divide by zero */ ++#define FPE_FLTOVF (__SI_FAULT|4) /* floating point overflow */ ++#define FPE_FLTUND (__SI_FAULT|5) /* floating point underflow */ ++#define FPE_FLTRES (__SI_FAULT|6) /* floating point inexact result */ ++#define FPE_FLTINV (__SI_FAULT|7) /* floating point invalid operation */ ++#define FPE_FLTSUB (__SI_FAULT|8) /* subscript out of range */ ++#define NSIGFPE 8 ++ ++/* ++ * SIGSEGV si_codes ++ */ ++#define SEGV_MAPERR (__SI_FAULT|1) /* address not mapped to object */ ++#define SEGV_ACCERR (__SI_FAULT|2) /* invalid permissions for mapped object */ ++#define NSIGSEGV 2 ++ ++/* ++ * SIGBUS si_codes ++ */ ++#define BUS_ADRALN (__SI_FAULT|1) /* invalid address alignment */ ++#define BUS_ADRERR (__SI_FAULT|2) /* non-existant physical address */ ++#define BUS_OBJERR (__SI_FAULT|3) /* object specific hardware error */ ++#define NSIGBUS 3 ++ ++/* ++ * SIGTRAP si_codes ++ */ ++#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ ++#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ ++#define NSIGTRAP 2 ++ ++/* ++ * SIGCHLD si_codes ++ */ ++#define CLD_EXITED (__SI_CHLD|1) /* child has exited */ ++#define CLD_KILLED (__SI_CHLD|2) /* child was killed */ ++#define CLD_DUMPED (__SI_CHLD|3) /* child terminated abnormally */ ++#define CLD_TRAPPED (__SI_CHLD|4) /* traced child has trapped */ ++#define CLD_STOPPED (__SI_CHLD|5) /* child has stopped */ ++#define CLD_CONTINUED (__SI_CHLD|6) /* stopped child has continued */ ++#define NSIGCHLD 6 ++ ++/* ++ * SIGPOLL si_codes ++ */ ++#define POLL_IN (__SI_POLL|1) /* data input available */ ++#define POLL_OUT (__SI_POLL|2) /* output buffers available */ ++#define POLL_MSG (__SI_POLL|3) /* input message available */ ++#define POLL_ERR (__SI_POLL|4) /* i/o error */ ++#define POLL_PRI (__SI_POLL|5) /* high priority input available */ ++#define POLL_HUP (__SI_POLL|6) /* device disconnected */ ++#define NSIGPOLL 6 ++ ++/* ++ * sigevent definitions ++ * ++ * It seems likely that SIGEV_THREAD will have to be handled from ++ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the ++ * thread manager then catches and does the appropriate nonsense. ++ * However, everything is written out here so as to not get lost. ++ */ ++#define SIGEV_SIGNAL 0 /* notify via signal */ ++#define SIGEV_NONE 1 /* other notification: meaningless */ ++#define SIGEV_THREAD 2 /* deliver via thread creation */ ++#define SIGEV_THREAD_ID 4 /* deliver to thread */ ++ ++#define SIGEV_MAX_SIZE 64 ++#ifndef SIGEV_PAD_SIZE ++#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) ++#endif ++ ++typedef struct sigevent { ++ sigval_t sigev_value; ++ int sigev_signo; ++ int sigev_notify; ++ union { ++ int _pad[SIGEV_PAD_SIZE]; ++ int _tid; ++ ++ struct { ++ void (*_function)(sigval_t); ++ void *_attribute; /* really pthread_attr_t */ ++ } _sigev_thread; ++ } _sigev_un; ++} sigevent_t; ++ ++#define sigev_notify_function _sigev_un._sigev_thread._function ++#define sigev_notify_attributes _sigev_un._sigev_thread._attribute ++#define sigev_notify_thread_id _sigev_un._tid ++ ++#ifdef __KERNEL__ ++ ++struct siginfo; ++void do_schedule_next_timer(struct siginfo *info); ++ ++#ifndef HAVE_ARCH_COPY_SIGINFO ++ ++#include ++ ++static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) ++{ ++ if (from->si_code < 0) ++ memcpy(to, from, sizeof(*to)); ++ else ++ /* _sigchld is currently the largest know union member */ ++ memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld)); ++} ++ ++#endif ++ ++extern int copy_siginfo_to_user(struct siginfo __user *to, struct siginfo *from); ++ ++#endif /* __KERNEL__ */ ++ ++#endif +--- linux/include/asm-generic/statfs.h ++++ linux/include/asm-generic/statfs.h +@@ -0,0 +1,51 @@ ++#ifndef _GENERIC_STATFS_H ++#define _GENERIC_STATFS_H ++ ++#ifndef __KERNEL_STRICT_NAMES ++# include ++typedef __kernel_fsid_t fsid_t; ++#endif ++ ++struct statfs { ++ __u32 f_type; ++ __u32 f_bsize; ++ __u32 f_blocks; ++ __u32 f_bfree; ++ __u32 f_bavail; ++ __u32 f_files; ++ __u32 f_ffree; ++ __kernel_fsid_t f_fsid; ++ __u32 f_namelen; ++ __u32 f_frsize; ++ __u32 f_spare[5]; ++}; ++ ++struct statfs64 { ++ __u32 f_type; ++ __u32 f_bsize; ++ __u64 f_blocks; ++ __u64 f_bfree; ++ __u64 f_bavail; ++ __u64 f_files; ++ __u64 f_ffree; ++ __kernel_fsid_t f_fsid; ++ __u32 f_namelen; ++ __u32 f_frsize; ++ __u32 f_spare[5]; ++}; ++ ++struct compat_statfs64 { ++ __u32 f_type; ++ __u32 f_bsize; ++ __u64 f_blocks; ++ __u64 f_bfree; ++ __u64 f_bavail; ++ __u64 f_files; ++ __u64 f_ffree; ++ __kernel_fsid_t f_fsid; ++ __u32 f_namelen; ++ __u32 f_frsize; ++ __u32 f_spare[5]; ++}; ++ ++#endif +--- linux/include/asm-generic/termios.h ++++ linux/include/asm-generic/termios.h +@@ -0,0 +1,69 @@ ++/* termios.h: generic termios/termio user copying/translation ++ */ ++ ++#ifndef _ASM_GENERIC_TERMIOS_H ++#define _ASM_GENERIC_TERMIOS_H ++ ++#include ++ ++#ifndef __ARCH_TERMIO_GETPUT ++ ++/* ++ * Translate a "termio" structure into a "termios". Ugh. ++ */ ++static inline int user_termio_to_kernel_termios(struct termios *termios, ++ struct termio __user *termio) ++{ ++ unsigned short tmp; ++ ++ if (get_user(tmp, &termio->c_iflag) < 0) ++ goto fault; ++ termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp; ++ ++ if (get_user(tmp, &termio->c_oflag) < 0) ++ goto fault; ++ termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp; ++ ++ if (get_user(tmp, &termio->c_cflag) < 0) ++ goto fault; ++ termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp; ++ ++ if (get_user(tmp, &termio->c_lflag) < 0) ++ goto fault; ++ termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp; ++ ++ if (get_user(termios->c_line, &termio->c_line) < 0) ++ goto fault; ++ ++ if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0) ++ goto fault; ++ ++ return 0; ++ ++ fault: ++ return -EFAULT; ++} ++ ++/* ++ * Translate a "termios" structure into a "termio". Ugh. ++ */ ++static inline int kernel_termios_to_user_termio(struct termio __user *termio, ++ struct termios *termios) ++{ ++ if (put_user(termios->c_iflag, &termio->c_iflag) < 0 || ++ put_user(termios->c_oflag, &termio->c_oflag) < 0 || ++ put_user(termios->c_cflag, &termio->c_cflag) < 0 || ++ put_user(termios->c_lflag, &termio->c_lflag) < 0 || ++ put_user(termios->c_line, &termio->c_line) < 0 || ++ copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) ++#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) ++ ++#endif /* __ARCH_TERMIO_GETPUT */ ++ ++#endif /* _ASM_GENERIC_TERMIOS_H */ +--- linux/include/asm-generic/tlb.h ++++ linux/include/asm-generic/tlb.h +@@ -0,0 +1,160 @@ ++/* asm-generic/tlb.h ++ * ++ * Generic TLB shootdown code ++ * ++ * Copyright 2001 Red Hat, Inc. ++ * Based on code from mm/memory.c Copyright Linus Torvalds and others. ++ * ++ * 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. ++ */ ++#ifndef _ASM_GENERIC__TLB_H ++#define _ASM_GENERIC__TLB_H ++ ++// #include ++#include ++#include ++#include ++ ++/* ++ * For UP we don't need to worry about TLB flush ++ * and page free order so much.. ++ */ ++#ifdef CONFIG_SMP ++ #define FREE_PTE_NR 506 ++ #define tlb_fast_mode(tlb) ((tlb)->nr == ~0U) ++#else ++ #define FREE_PTE_NR 1 ++ #define tlb_fast_mode(tlb) 1 ++#endif ++ ++/* struct mmu_gather is an opaque type used by the mm code for passing around ++ * any data needed by arch specific code for tlb_remove_page. This structure ++ * can be per-CPU or per-MM as the page table lock is held for the duration of ++ * TLB shootdown. ++ */ ++struct mmu_gather { ++ struct mm_struct *mm; ++ unsigned int nr; /* set to ~0U means fast mode */ ++ unsigned int need_flush;/* Really unmapped some ptes? */ ++ unsigned int fullmm; /* non-zero means full mm flush */ ++ unsigned long freed; ++ struct page * pages[FREE_PTE_NR]; ++}; ++ ++/* Users of the generic TLB shootdown code must declare this storage space. */ ++DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); ++ ++/* tlb_gather_mmu ++ * Return a pointer to an initialized struct mmu_gather. ++ */ ++static inline struct mmu_gather * ++tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) ++{ ++ struct mmu_gather *tlb = &per_cpu(mmu_gathers, smp_processor_id()); ++ ++ tlb->mm = mm; ++ ++ /* Use fast mode if only one CPU is online */ ++ tlb->nr = num_online_cpus() > 1 ? 0U : ~0U; ++ ++ tlb->fullmm = full_mm_flush; ++ tlb->freed = 0; ++ ++ return tlb; ++} ++ ++static inline void ++tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) ++{ ++ if (!tlb->need_flush) ++ return; ++ tlb->need_flush = 0; ++ tlb_flush(tlb); ++ if (!tlb_fast_mode(tlb)) { ++ free_pages_and_swap_cache(tlb->pages, tlb->nr); ++ tlb->nr = 0; ++ } ++} ++ ++/* tlb_finish_mmu ++ * Called at the end of the shootdown operation to free up any resources ++ * that were required. The page table lock is still held at this point. ++ */ ++static inline void ++tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) ++{ ++ int freed = tlb->freed; ++ struct mm_struct *mm = tlb->mm; ++ int rss = mm->rss; ++ ++ if (rss < freed) ++ freed = rss; ++ mm->rss = rss - freed; ++ tlb_flush_mmu(tlb, start, end); ++ ++ /* keep the page table cache within bounds */ ++ check_pgt_cache(); ++} ++ ++static inline unsigned int ++tlb_is_full_mm(struct mmu_gather *tlb) ++{ ++ return tlb->fullmm; ++} ++ ++/* tlb_remove_page ++ * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while ++ * handling the additional races in SMP caused by other CPUs caching valid ++ * mappings in their TLBs. ++ */ ++static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) ++{ ++ tlb->need_flush = 1; ++ if (tlb_fast_mode(tlb)) { ++ free_page_and_swap_cache(page); ++ return; ++ } ++ tlb->pages[tlb->nr++] = page; ++ if (tlb->nr >= FREE_PTE_NR) ++ tlb_flush_mmu(tlb, 0, 0); ++} ++ ++/** ++ * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation. ++ * ++ * Record the fact that pte's were really umapped in ->need_flush, so we can ++ * later optimise away the tlb invalidate. This helps when userspace is ++ * unmapping already-unmapped pages, which happens quite a lot. ++ */ ++#define tlb_remove_tlb_entry(tlb, ptep, address) \ ++ do { \ ++ tlb->need_flush = 1; \ ++ __tlb_remove_tlb_entry(tlb, ptep, address); \ ++ } while (0) ++ ++#define pte_free_tlb(tlb, ptep) \ ++ do { \ ++ tlb->need_flush = 1; \ ++ __pte_free_tlb(tlb, ptep); \ ++ } while (0) ++ ++#ifndef __ARCH_HAS_4LEVEL_HACK ++#define pud_free_tlb(tlb, pudp) \ ++ do { \ ++ tlb->need_flush = 1; \ ++ __pud_free_tlb(tlb, pudp); \ ++ } while (0) ++#endif ++ ++#define pmd_free_tlb(tlb, pmdp) \ ++ do { \ ++ tlb->need_flush = 1; \ ++ __pmd_free_tlb(tlb, pmdp); \ ++ } while (0) ++ ++#define tlb_migrate_finish(mm) do {} while (0) ++ ++#endif /* _ASM_GENERIC__TLB_H */ +--- linux/include/asm-generic/topology.h ++++ linux/include/asm-generic/topology.h +@@ -0,0 +1,48 @@ ++/* ++ * linux/include/asm-generic/topology.h ++ * ++ * Written by: Matthew Dobson, IBM Corporation ++ * ++ * Copyright (C) 2002, IBM Corp. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Send feedback to ++ */ ++#ifndef _ASM_GENERIC_TOPOLOGY_H ++#define _ASM_GENERIC_TOPOLOGY_H ++ ++/* Other architectures wishing to use this simple topology API should fill ++ in the below functions as appropriate in their own file. */ ++#ifndef cpu_to_node ++#define cpu_to_node(cpu) (0) ++#endif ++#ifndef parent_node ++#define parent_node(node) (0) ++#endif ++#ifndef node_to_cpumask ++#define node_to_cpumask(node) (cpu_online_map) ++#endif ++#ifndef node_to_first_cpu ++#define node_to_first_cpu(node) (0) ++#endif ++#ifndef pcibus_to_cpumask ++#define pcibus_to_cpumask(bus) (cpu_online_map) ++#endif ++ ++#endif /* _ASM_GENERIC_TOPOLOGY_H */ +--- linux/include/asm-generic/uaccess.h ++++ linux/include/asm-generic/uaccess.h +@@ -0,0 +1,26 @@ ++#ifndef _ASM_GENERIC_UACCESS_H_ ++#define _ASM_GENERIC_UACCESS_H_ ++ ++/* ++ * This macro should be used instead of __get_user() when accessing ++ * values at locations that are not known to be aligned. ++ */ ++#define __get_user_unaligned(x, ptr) \ ++({ \ ++ __typeof__ (*(ptr)) __x; \ ++ __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ ++ (x) = __x; \ ++}) ++ ++ ++/* ++ * This macro should be used instead of __put_user() when accessing ++ * values at locations that are not known to be aligned. ++ */ ++#define __put_user_unaligned(x, ptr) \ ++({ \ ++ __typeof__ (*(ptr)) __x = (x); \ ++ __copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0; \ ++}) ++ ++#endif /* _ASM_GENERIC_UACCESS_H */ +--- linux/include/asm-generic/unaligned.h ++++ linux/include/asm-generic/unaligned.h +@@ -0,0 +1,20 @@ ++#ifndef _ASM_GENERIC_UNALIGNED_H_ ++#define _ASM_GENERIC_UNALIGNED_H_ ++ ++/* ++ * For the benefit of those who are trying to port Linux to another ++ * architecture, here are some C-language equivalents. ++ */ ++ ++#include ++ ++ ++#define get_unaligned(ptr) \ ++ ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; }) ++ ++#define put_unaligned(val, ptr) \ ++ ({ __typeof__(*(ptr)) __tmp = (val); \ ++ memcpy((ptr), &__tmp, sizeof(*(ptr))); \ ++ (void)0; }) ++ ++#endif /* _ASM_GENERIC_UNALIGNED_H */ +--- linux/include/asm-generic/vmlinux.lds.h ++++ linux/include/asm-generic/vmlinux.lds.h +@@ -0,0 +1,90 @@ ++#ifndef LOAD_OFFSET ++#define LOAD_OFFSET 0 ++#endif ++ ++#ifndef VMLINUX_SYMBOL ++#define VMLINUX_SYMBOL(_sym_) _sym_ ++#endif ++ ++#define RODATA \ ++ .rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \ ++ *(.rodata) *(.rodata.*) \ ++ *(__vermagic) /* Kernel version magic */ \ ++ } \ ++ \ ++ .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ ++ *(.rodata1) \ ++ } \ ++ \ ++ /* PCI quirks */ \ ++ .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ ++ *(.pci_fixup_early) \ ++ VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \ ++ VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ ++ *(.pci_fixup_header) \ ++ VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ ++ VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \ ++ *(.pci_fixup_final) \ ++ VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \ ++ VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \ ++ *(.pci_fixup_enable) \ ++ VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: Normal symbols */ \ ++ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___ksymtab) = .; \ ++ *(__ksymtab) \ ++ VMLINUX_SYMBOL(__stop___ksymtab) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: GPL-only symbols */ \ ++ __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ ++ *(__ksymtab_gpl) \ ++ VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: Normal symbols */ \ ++ __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___kcrctab) = .; \ ++ *(__kcrctab) \ ++ VMLINUX_SYMBOL(__stop___kcrctab) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: GPL-only symbols */ \ ++ __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ ++ *(__kcrctab_gpl) \ ++ VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: strings */ \ ++ __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ ++ *(__ksymtab_strings) \ ++ } \ ++ \ ++ /* Built-in module parameters. */ \ ++ __param : AT(ADDR(__param) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___param) = .; \ ++ *(__param) \ ++ VMLINUX_SYMBOL(__stop___param) = .; \ ++ } ++ ++#define SECURITY_INIT \ ++ .security_initcall.init : { \ ++ VMLINUX_SYMBOL(__security_initcall_start) = .; \ ++ *(.security_initcall.init) \ ++ VMLINUX_SYMBOL(__security_initcall_end) = .; \ ++ } ++ ++#define SCHED_TEXT \ ++ VMLINUX_SYMBOL(__sched_text_start) = .; \ ++ *(.sched.text) \ ++ VMLINUX_SYMBOL(__sched_text_end) = .; ++ ++#define LOCK_TEXT \ ++ VMLINUX_SYMBOL(__lock_text_start) = .; \ ++ *(.spinlock.text) \ ++ VMLINUX_SYMBOL(__lock_text_end) = .; +--- linux/include/asm-generic/xor.h ++++ linux/include/asm-generic/xor.h +@@ -0,0 +1,718 @@ ++/* ++ * include/asm-generic/xor.h ++ * ++ * Generic optimized RAID-5 checksumming functions. ++ * ++ * 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, or (at your option) ++ * any later version. ++ * ++ * You should have received a copy of the GNU General Public License ++ * (for example /usr/src/linux/COPYING); if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++ ++static void ++xor_8regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ p1[0] ^= p2[0]; ++ p1[1] ^= p2[1]; ++ p1[2] ^= p2[2]; ++ p1[3] ^= p2[3]; ++ p1[4] ^= p2[4]; ++ p1[5] ^= p2[5]; ++ p1[6] ^= p2[6]; ++ p1[7] ^= p2[7]; ++ p1 += 8; ++ p2 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_8regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ p1[0] ^= p2[0] ^ p3[0]; ++ p1[1] ^= p2[1] ^ p3[1]; ++ p1[2] ^= p2[2] ^ p3[2]; ++ p1[3] ^= p2[3] ^ p3[3]; ++ p1[4] ^= p2[4] ^ p3[4]; ++ p1[5] ^= p2[5] ^ p3[5]; ++ p1[6] ^= p2[6] ^ p3[6]; ++ p1[7] ^= p2[7] ^ p3[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_8regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ p1[0] ^= p2[0] ^ p3[0] ^ p4[0]; ++ p1[1] ^= p2[1] ^ p3[1] ^ p4[1]; ++ p1[2] ^= p2[2] ^ p3[2] ^ p4[2]; ++ p1[3] ^= p2[3] ^ p3[3] ^ p4[3]; ++ p1[4] ^= p2[4] ^ p3[4] ^ p4[4]; ++ p1[5] ^= p2[5] ^ p3[5] ^ p4[5]; ++ p1[6] ^= p2[6] ^ p3[6] ^ p4[6]; ++ p1[7] ^= p2[7] ^ p3[7] ^ p4[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_8regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0]; ++ p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1]; ++ p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2]; ++ p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3]; ++ p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4]; ++ p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5]; ++ p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6]; ++ p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ p5 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_32regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_32regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_32regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ d0 ^= p4[0]; ++ d1 ^= p4[1]; ++ d2 ^= p4[2]; ++ d3 ^= p4[3]; ++ d4 ^= p4[4]; ++ d5 ^= p4[5]; ++ d6 ^= p4[6]; ++ d7 ^= p4[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_32regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ d0 ^= p4[0]; ++ d1 ^= p4[1]; ++ d2 ^= p4[2]; ++ d3 ^= p4[3]; ++ d4 ^= p4[4]; ++ d5 ^= p4[5]; ++ d6 ^= p4[6]; ++ d7 ^= p4[7]; ++ d0 ^= p5[0]; ++ d1 ^= p5[1]; ++ d2 ^= p5[2]; ++ d3 ^= p5[3]; ++ d4 ^= p5[4]; ++ d5 ^= p5[5]; ++ d6 ^= p5[6]; ++ d7 ^= p5[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ p5 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_8regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ prefetchw(p1); ++ prefetch(p2); ++ ++ do { ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ once_more: ++ p1[0] ^= p2[0]; ++ p1[1] ^= p2[1]; ++ p1[2] ^= p2[2]; ++ p1[3] ^= p2[3]; ++ p1[4] ^= p2[4]; ++ p1[5] ^= p2[5]; ++ p1[6] ^= p2[6]; ++ p1[7] ^= p2[7]; ++ p1 += 8; ++ p2 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_8regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ ++ do { ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ once_more: ++ p1[0] ^= p2[0] ^ p3[0]; ++ p1[1] ^= p2[1] ^ p3[1]; ++ p1[2] ^= p2[2] ^ p3[2]; ++ p1[3] ^= p2[3] ^ p3[3]; ++ p1[4] ^= p2[4] ^ p3[4]; ++ p1[5] ^= p2[5] ^ p3[5]; ++ p1[6] ^= p2[6] ^ p3[6]; ++ p1[7] ^= p2[7] ^ p3[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_8regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ prefetch(p4); ++ ++ do { ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ prefetch(p4+8); ++ once_more: ++ p1[0] ^= p2[0] ^ p3[0] ^ p4[0]; ++ p1[1] ^= p2[1] ^ p3[1] ^ p4[1]; ++ p1[2] ^= p2[2] ^ p3[2] ^ p4[2]; ++ p1[3] ^= p2[3] ^ p3[3] ^ p4[3]; ++ p1[4] ^= p2[4] ^ p3[4] ^ p4[4]; ++ p1[5] ^= p2[5] ^ p3[5] ^ p4[5]; ++ p1[6] ^= p2[6] ^ p3[6] ^ p4[6]; ++ p1[7] ^= p2[7] ^ p3[7] ^ p4[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_8regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ prefetch(p4); ++ prefetch(p5); ++ ++ do { ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ prefetch(p4+8); ++ prefetch(p5+8); ++ once_more: ++ p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0]; ++ p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1]; ++ p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2]; ++ p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3]; ++ p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4]; ++ p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5]; ++ p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6]; ++ p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ p5 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_32regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ once_more: ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_32regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ once_more: ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_32regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ prefetch(p4); ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ prefetch(p4+8); ++ once_more: ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ d0 ^= p4[0]; ++ d1 ^= p4[1]; ++ d2 ^= p4[2]; ++ d3 ^= p4[3]; ++ d4 ^= p4[4]; ++ d5 ^= p4[5]; ++ d6 ^= p4[6]; ++ d7 ^= p4[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_32regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ prefetch(p4); ++ prefetch(p5); ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ prefetch(p4+8); ++ prefetch(p5+8); ++ once_more: ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ d0 ^= p4[0]; ++ d1 ^= p4[1]; ++ d2 ^= p4[2]; ++ d3 ^= p4[3]; ++ d4 ^= p4[4]; ++ d5 ^= p4[5]; ++ d6 ^= p4[6]; ++ d7 ^= p4[7]; ++ d0 ^= p5[0]; ++ d1 ^= p5[1]; ++ d2 ^= p5[2]; ++ d3 ^= p5[3]; ++ d4 ^= p5[4]; ++ d5 ^= p5[5]; ++ d6 ^= p5[6]; ++ d7 ^= p5[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ p5 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static struct xor_block_template xor_block_8regs = { ++ .name = "8regs", ++ .do_2 = xor_8regs_2, ++ .do_3 = xor_8regs_3, ++ .do_4 = xor_8regs_4, ++ .do_5 = xor_8regs_5, ++}; ++ ++static struct xor_block_template xor_block_32regs = { ++ .name = "32regs", ++ .do_2 = xor_32regs_2, ++ .do_3 = xor_32regs_3, ++ .do_4 = xor_32regs_4, ++ .do_5 = xor_32regs_5, ++}; ++ ++static struct xor_block_template xor_block_8regs_p = { ++ .name = "8regs_prefetch", ++ .do_2 = xor_8regs_p_2, ++ .do_3 = xor_8regs_p_3, ++ .do_4 = xor_8regs_p_4, ++ .do_5 = xor_8regs_p_5, ++}; ++ ++static struct xor_block_template xor_block_32regs_p = { ++ .name = "32regs_prefetch", ++ .do_2 = xor_32regs_p_2, ++ .do_3 = xor_32regs_p_3, ++ .do_4 = xor_32regs_p_4, ++ .do_5 = xor_32regs_p_5, ++}; ++ ++#define XOR_TRY_TEMPLATES \ ++ do { \ ++ xor_speed(&xor_block_8regs); \ ++ xor_speed(&xor_block_8regs_p); \ ++ xor_speed(&xor_block_32regs); \ ++ xor_speed(&xor_block_32regs_p); \ ++ } while (0) +--- linux/include/asm-nios2nommu/altera_juart.h ++++ linux/include/asm-nios2nommu/altera_juart.h +@@ -0,0 +1,36 @@ ++/*------------------------------------------------------------------------ ++ * ++ * linux/drivers/serial/altera_juart.h ++ * ++ * Driver for Altera JTAG UART core with Avalon interface ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * History: ++ * Jun/20/2005 DGT Microtronix Datacom NiosII ++ * ++ -----------------------------------------------------------------------*/ ++ ++#ifndef _ALTERA_JUART_H_ ++ #define _ALTERA_JUART_H_ ++ ++ /* jtag uart details needed outside of the driver itself: */ ++ /* by: arch/kernel/start.c - boot time error message(s) */ ++ ++ void jtaguart_console_write ++ ( struct console *co, ++ const char *s, ++ unsigned int count); ++ ++#endif /* _ALTERA_JUART_H_ */ +--- linux/include/asm-nios2nommu/a.out.h ++++ linux/include/asm-nios2nommu/a.out.h +@@ -0,0 +1,85 @@ ++/* $Id: a.out.h,v 1.4 2004/03/30 19:35:04 ken-h Exp $ */ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2NOMMU_A_OUT_H__ ++#define __NIOS2NOMMU_A_OUT_H__ ++ ++#define SPARC_PGSIZE 0x1000 /* Thanks to the sun4 architecture... */ ++#define SEGMENT_SIZE SPARC_PGSIZE /* whee... */ ++ ++struct exec { ++ unsigned char a_dynamic:1; /* A __DYNAMIC is in this image */ ++ unsigned char a_toolversion:7; ++ unsigned char a_machtype; ++ unsigned short a_info; ++ unsigned long a_text; /* length of text, in bytes */ ++ unsigned long a_data; /* length of data, in bytes */ ++ unsigned long a_bss; /* length of bss, in bytes */ ++ unsigned long a_syms; /* length of symbol table, in bytes */ ++ unsigned long a_entry; /* where program begins */ ++ unsigned long a_trsize; ++ unsigned long a_drsize; ++}; ++ ++#define INIT_EXEC { \ ++ .a_dynamic = 0, \ ++ .a_toolversion = 0, \ ++ .a_machtype = 0, \ ++ .a_info = 0, \ ++ .a_text = 0, \ ++ .a_data = 0, \ ++ .a_bss = 0, \ ++ .a_syms = 0, \ ++ .a_entry = 0, \ ++ .a_trsize = 0, \ ++ .a_drsize = 0, \ ++} ++ ++/* Where in the file does the text information begin? */ ++#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? 0 : sizeof (struct exec)) ++ ++/* Where do the Symbols start? */ ++#define N_SYMOFF(x) (N_TXTOFF(x) + (x).a_text + \ ++ (x).a_data + (x).a_trsize + \ ++ (x).a_drsize) ++ ++/* Where does text segment go in memory after being loaded? */ ++#define N_TXTADDR(x) (((N_MAGIC(x) == ZMAGIC) && \ ++ ((x).a_entry < SPARC_PGSIZE)) ? \ ++ 0 : SPARC_PGSIZE) ++ ++/* And same for the data segment.. */ ++#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC ? \ ++ (N_TXTADDR(x) + (x).a_text) \ ++ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) ++ ++#define N_TRSIZE(a) ((a).a_trsize) ++#define N_DRSIZE(a) ((a).a_drsize) ++#define N_SYMSIZE(a) ((a).a_syms) ++ ++#ifdef __KERNEL__ ++ ++#define STACK_TOP TASK_SIZE ++ ++#endif ++ ++#endif /* __NIOS2NOMMU_A_OUT_H__ */ +--- linux/include/asm-nios2nommu/asm-macros.h ++++ linux/include/asm-nios2nommu/asm-macros.h +@@ -0,0 +1,331 @@ ++/* ++ * Macro used to simplify coding multi-line assembler. ++ * Some of the bit test macro can simplify down to one line ++ * depending on the mask value. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++/* ++ * ANDs reg2 with mask and places the result in reg1. ++ * ++ * You cannnot use the same register for reg1 & reg2. ++ */ ++ ++.macro ANDI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ movhi \reg1,%hi(\mask) ++ movui \reg1,%lo(\mask) ++ and \reg1,\reg1,\reg2 ++ .else ++ andi \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ andhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * ORs reg2 with mask and places the result in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro ORI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ orhi \reg1,\reg2,%hi(\mask) ++ ori \reg1,\reg2,%lo(\mask) ++ .else ++ ori \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ orhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * XORs reg2 with mask and places the result in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro XORI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ xorhi \reg1,\reg2,%hi(\mask) ++ xori \reg1,\reg1,%lo(\mask) ++ .else ++ xori \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ xorhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * This is a support macro for BTBZ & BTBNZ. It checks ++ * the bit to make sure it is valid 32 value. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BT reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and branches to label if the ++ * bit is zero. The result of the bit test is stored in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTBZ reg1,reg2,bit,label ++ BT \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and branches to label if the ++ * bit is non-zero. The result of the bit test is stored in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTBNZ reg1,reg2,bit,label ++ BT \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTC reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ xori \reg2,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ xorhi \reg2,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTS reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ ori \reg2,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ orhi \reg2,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTR reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ andi \reg2,\reg2,%lo(~(1 << \bit)) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ andhi \reg2,\reg2,%lo(~(1 << (\bit - 16))) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTCBZ reg1,reg2,bit,label ++ BTC \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTCBNZ reg1,reg2,bit,label ++ BTC \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTSBZ reg1,reg2,bit,label ++ BTS \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTSBNZ reg1,reg2,bit,label ++ BTS \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTRBZ reg1,reg2,bit,label ++ BTR \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTRBNZ reg1,reg2,bit,label ++ BTR \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bits in mask against reg2 stores the result in reg1. ++ * If the all the bits in the mask are zero it branches to label. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro TSTBZ reg1,reg2,mask,label ++ ANDI32 \reg1,\reg2,\mask ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bits in mask against reg2 stores the result in reg1. ++ * If the any of the bits in the mask are 1 it branches to label. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro TSTBNZ reg1,reg2,mask,label ++ ANDI32 \reg1,\reg2,\mask ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Pushes reg onto the stack. ++ */ ++ ++.macro PUSH reg ++ addi sp,sp,-4 ++ stw \reg,0(sp) ++.endm ++ ++/* ++ * Pops the top of the stack into reg. ++ */ ++ ++.macro POP reg ++ ldw \reg,0(sp) ++ addi sp,sp,4 ++.endm ++ ++/* ++ * Clears reg ++ */ ++ ++.macro CLR reg ++ mov \reg,r0 ++.endm ++ ++/* ++ * The preprocessor macro does not work for ++ * the nios2 compiler. Undefine ENTRY and define ++ * a real assembler macro. ++ */ ++#undef ENTRY ++#define ENTRY(name) ASM_ENTRY name ++ ++.macro ASM_ENTRY name ++.globl \name ++__ALIGN ++ \name: ++.endm +--- linux/include/asm-nios2nommu/atomic.h ++++ linux/include/asm-nios2nommu/atomic.h +@@ -0,0 +1,190 @@ ++//vic - add 'atomic_add/sub_return', 'atomic_add_negative' ++//vic from v850 architecture ++ ++/* atomic.h: ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 2001 Vic Phillips (vic@microtronix.com) ++ * ++ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ARCH_NIOS2NOMMU_ATOMIC__ ++#define __ARCH_NIOS2NOMMU_ATOMIC__ ++ ++#include ++ ++typedef struct { int counter; } atomic_t; ++#define ATOMIC_INIT(i) { (i) } ++ ++#define atomic_read(v) ((v)->counter) ++#define atomic_set(v, i) (((v)->counter) = i) ++ ++ ++extern __inline__ void atomic_add(int i, atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter += i; ++ local_irq_restore(flags); ++} ++ ++extern __inline__ int atomic_add_negative(int i, atomic_t *v) ++{ ++ unsigned long flags; ++ int result; ++ ++ local_irq_save(flags); ++ v->counter += i; ++ result = (v->counter < 0); ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ void atomic_sub(int i, atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ local_irq_restore(flags); ++} ++ ++extern __inline__ int atomic_sub_and_test(int i, atomic_t *v) ++{ ++ int result; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ result = (v->counter == 0); ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ void atomic_inc(atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter += 1; ++ local_irq_restore(flags); ++} ++ ++extern __inline__ int atomic_inc_and_test(atomic_t *v) ++{ ++ unsigned long flags; ++ int result; ++ ++ local_irq_save(flags); ++ v->counter += 1; ++ result = (v->counter == 0); ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ void atomic_dec(atomic_t *v) ++{ ++ int i = 1; /* the compiler optimizes better this way */ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ local_irq_restore(flags); ++} ++ ++extern __inline__ int atomic_dec_and_test(atomic_t *v) ++{ ++ int result; ++ int i = 1; /* the compiler optimizes better this way */ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ result = (v->counter == 0); ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ int atomic_inc_return(atomic_t *v) ++{ ++ int result; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ result = ++v->counter; ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ int atomic_dec_return(atomic_t *v) ++{ ++ int result; ++ int i = 1; /* the compiler optimizes better this way */ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ result = v->counter; ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ int atomic_add_return (int i, volatile atomic_t *v) ++{ ++ int res; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ res = v->counter + i; ++ v->counter = res; ++ local_irq_restore(flags); ++ ++ return res; ++} ++ ++static __inline__ int atomic_sub_return (int i, volatile atomic_t *v) ++{ ++ int res; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ res = v->counter - i; ++ v->counter = res; ++ local_irq_restore(flags); ++ ++ return res; ++} ++ ++#define atomic_dec_return(v) atomic_sub_return(1,(v)) ++#define atomic_inc_return(v) atomic_add_return(1,(v)) ++ ++/* Atomic operations are already serializing */ ++#define smp_mb__before_atomic_dec() barrier() ++#define smp_mb__after_atomic_dec() barrier() ++#define smp_mb__before_atomic_inc() barrier() ++#define smp_mb__after_atomic_inc() barrier() ++ ++ ++#endif /* !(__ARCH_NIOS2NOMMU_ATOMIC__) */ ++ ++ +--- linux/include/asm-nios2nommu/bitops.h ++++ linux/include/asm-nios2nommu/bitops.h +@@ -0,0 +1,472 @@ ++#ifndef _ASM_NIOS_BITOPS_H_ ++#define _ASM_NIOS_BITOPS_H_ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/bitops.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifdef __KERNEL__ ++// #include ++#include ++#include /* swab32 */ ++#include ++#endif ++ ++/* ++ * Adapted to NIOS from generic bitops.h: ++ * ++ * For the benefit of those who are trying to port Linux to another ++ * architecture, here are some C-language equivalents. You should ++ * recode these in the native assembly language, if at all possible. ++ * To guarantee atomicity, these routines call cli() and sti() to ++ * disable interrupts while they operate. (You have to provide inline ++ * routines to cli() and sti().) ++ * ++ * Also note, these routines assume that you have 32 bit integers. ++ * You will have to change this if you are trying to port Linux to the ++ * Alpha architecture or to a Cray. :-) ++ * ++ * C language equivalents written by Theodore Ts'o, 9/26/92 ++ */ ++ ++/* ++ * Generic ffs(). ++ */ ++static inline int ffs(int x) ++{ ++ int r = 1; ++ ++ if (!x) ++ return 0; ++ if (!(x & 0xffff)) { ++ x >>= 16; ++ r += 16; ++ } ++ if (!(x & 0xff)) { ++ x >>= 8; ++ r += 8; ++ } ++ if (!(x & 0xf)) { ++ x >>= 4; ++ r += 4; ++ } ++ if (!(x & 3)) { ++ x >>= 2; ++ r += 2; ++ } ++ if (!(x & 1)) { ++ x >>= 1; ++ r += 1; ++ } ++ return r; ++} ++ ++/* ++ * Generic __ffs(). ++ */ ++static inline int __ffs(int x) ++{ ++ int r = 0; ++ ++ if (!x) ++ return 0; ++ if (!(x & 0xffff)) { ++ x >>= 16; ++ r += 16; ++ } ++ if (!(x & 0xff)) { ++ x >>= 8; ++ r += 8; ++ } ++ if (!(x & 0xf)) { ++ x >>= 4; ++ r += 4; ++ } ++ if (!(x & 3)) { ++ x >>= 2; ++ r += 2; ++ } ++ if (!(x & 1)) { ++ x >>= 1; ++ r += 1; ++ } ++ return r; ++} ++ ++/* ++ * fls: find last bit set. ++ */ ++#define fls(x) generic_fls(x) ++ ++ ++/* ++ * Every architecture must define this function. It's the fastest ++ * way of searching a 140-bit bitmap where the first 100 bits are ++ * unlikely to be set. It's guaranteed that at least one of the 140 ++ * bits is cleared. ++ */ ++static inline int sched_find_first_bit(unsigned long *b) ++{ ++ if (unlikely(b[0])) ++ return __ffs(b[0]); ++ if (unlikely(b[1])) ++ return __ffs(b[1]) + 32; ++ if (unlikely(b[2])) ++ return __ffs(b[2]) + 64; ++ if (b[3]) ++ return __ffs(b[3]) + 96; ++ return __ffs(b[4]) + 128; ++} ++ ++/* ++ * ffz = Find First Zero in word. Undefined if no zero exists, ++ * so code should check against ~0UL first.. ++ */ ++static __inline__ unsigned long ffz(unsigned long word) ++{ ++ unsigned long result = 0; ++ ++ while(word & 1) { ++ result++; ++ word >>= 1; ++ } ++ return result; ++} ++ ++ ++static __inline__ void set_bit(int nr, volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ *a |= mask; ++ local_irq_restore(flags); ++} ++ ++static __inline__ void __set_bit(int nr, volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ *a |= mask; ++} ++ ++/* ++ * clear_bit() doesn't provide any barrier for the compiler. ++ */ ++#define smp_mb__before_clear_bit() barrier() ++#define smp_mb__after_clear_bit() barrier() ++ ++static __inline__ void clear_bit(int nr, volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ *a &= ~mask; ++ local_irq_restore(flags); ++} ++ ++static __inline__ void __clear_bit(int nr, volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ *a &= ~mask; ++} ++ ++static __inline__ void change_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, flags; ++ unsigned long *ADDR = (unsigned long *) addr; ++ ++ ADDR += nr >> 5; ++ mask = 1 << (nr & 31); ++ local_irq_save(flags); ++ *ADDR ^= mask; ++ local_irq_restore(flags); ++} ++ ++static __inline__ void __change_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask; ++ unsigned long *ADDR = (unsigned long *) addr; ++ ++ ADDR += nr >> 5; ++ mask = 1 << (nr & 31); ++ *ADDR ^= mask; ++} ++ ++static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ retval = (mask & *a) != 0; ++ *a |= mask; ++ local_irq_restore(flags); ++ ++ return retval; ++} ++ ++static __inline__ int __test_and_set_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ retval = (mask & *a) != 0; ++ *a |= mask; ++ return retval; ++} ++ ++static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ retval = (mask & *a) != 0; ++ *a &= ~mask; ++ local_irq_restore(flags); ++ ++ return retval; ++} ++ ++static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ retval = (mask & *a) != 0; ++ *a &= ~mask; ++ return retval; ++} ++ ++static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ retval = (mask & *a) != 0; ++ *a ^= mask; ++ local_irq_restore(flags); ++ ++ return retval; ++} ++ ++static __inline__ int __test_and_change_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ retval = (mask & *a) != 0; ++ *a ^= mask; ++ return retval; ++} ++ ++/* ++ * This routine doesn't need to be atomic. ++ */ ++static __inline__ int __constant_test_bit(int nr, const volatile unsigned long * addr) ++{ ++ return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; ++} ++ ++static __inline__ int __test_bit(int nr, const volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ return ((mask & *a) != 0); ++} ++ ++#define test_bit(nr,addr) \ ++(__builtin_constant_p(nr) ? \ ++ __constant_test_bit((nr),(unsigned long *)(addr)) : \ ++ __test_bit((nr),(unsigned long *)(addr))) ++ ++ ++/* find_next_zero_bit() finds the first zero bit in a bit string of length ++ * 'size' bits, starting the search at bit 'offset'. This is largely based ++ * on Linus's ALPHA routines, which are pretty portable BTW. ++ */ ++ ++extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) ++{ ++ unsigned long *p = ((unsigned long *) addr) + (offset >> 5); ++ unsigned long result = offset & ~31UL; ++ unsigned long tmp; ++ ++ if (offset >= size) ++ return size; ++ size -= result; ++ offset &= 31UL; ++ if (offset) { ++ tmp = *(p++); ++ tmp |= ~0UL >> (32-offset); ++ if (size < 32) ++ goto found_first; ++ if (~tmp) ++ goto found_middle; ++ size -= 32; ++ result += 32; ++ } ++ while (size & ~31UL) { ++ if (~(tmp = *(p++))) ++ goto found_middle; ++ result += 32; ++ size -= 32; ++ } ++ if (!size) ++ return result; ++ tmp = *p; ++ ++found_first: ++ tmp |= ~0UL << size; ++ if (tmp == ~0UL) ++ return result + size; ++found_middle: ++ return result + ffz(tmp); ++} ++ ++/* ++ * Find next one bit in a bitmap reasonably efficiently. ++ */ ++extern __inline__ unsigned long find_next_bit(const unsigned long *addr, ++ unsigned long size, unsigned long offset) ++{ ++ unsigned int *p = ((unsigned int *) addr) + (offset >> 5); ++ unsigned int result = offset & ~31UL; ++ unsigned int tmp; ++ ++ if (offset >= size) ++ return size; ++ size -= result; ++ offset &= 31UL; ++ if (offset) { ++ tmp = *p++; ++ tmp &= ~0UL << offset; ++ if (size < 32) ++ goto found_first; ++ if (tmp) ++ goto found_middle; ++ size -= 32; ++ result += 32; ++ } ++ while (size >= 32) { ++ if ((tmp = *p++) != 0) ++ goto found_middle; ++ result += 32; ++ size -= 32; ++ } ++ if (!size) ++ return result; ++ tmp = *p; ++ ++found_first: ++ tmp &= ~0UL >> (32 - size); ++ if (tmp == 0UL) /* Are any bits set? */ ++ return result + size; /* Nope. */ ++found_middle: ++ return result + __ffs(tmp); ++} ++ ++/* ++ * hweightN: returns the hamming weight (i.e. the number ++ * of bits set) of a N-bit word ++ */ ++ ++#define hweight32(x) generic_hweight32(x) ++#define hweight16(x) generic_hweight16(x) ++#define hweight8(x) generic_hweight8(x) ++ ++/* Linus sez that gcc can optimize the following correctly, we'll see if this ++ * holds on the Sparc as it does for the ALPHA. ++ */ ++ ++#define find_first_zero_bit(addr, size) \ ++ find_next_zero_bit((addr), (size), 0) ++#define find_first_bit(addr, size) \ ++ find_next_bit((addr), (size), 0) ++ ++/* Now for the ext2 filesystem bit operations and helper routines. ++ * ++ * Both NIOS and ext2 are little endian, so these are the same as above. ++ */ ++ ++#define ext2_set_bit test_and_set_bit ++#define ext2_clear_bit test_and_clear_bit ++#define ext2_test_bit test_bit ++ ++#define ext2_set_bit_atomic(lock, nr, addr) \ ++ ({ \ ++ int ret; \ ++ spin_lock(lock); \ ++ ret = ext2_set_bit((nr),(unsigned long *) (addr)); \ ++ spin_unlock(lock); \ ++ ret; \ ++ }) ++ ++#define ext2_clear_bit_atomic(lock, nr, addr) \ ++ ({ \ ++ int ret; \ ++ spin_lock(lock); \ ++ ret = ext2_clear_bit((nr),(unsigned long *) (addr)); \ ++ spin_unlock(lock); \ ++ ret; \ ++ }) ++ ++#define ext2_find_first_zero_bit find_first_zero_bit ++#define ext2_find_next_zero_bit find_next_zero_bit ++ ++#endif /* _ASM_NIOS_BITOPS_H */ +--- linux/include/asm-nios2nommu/bootinfo.h ++++ linux/include/asm-nios2nommu/bootinfo.h +@@ -0,0 +1,2 @@ ++ ++/* Nothing for nios2nommu */ +--- linux/include/asm-nios2nommu/bug.h ++++ linux/include/asm-nios2nommu/bug.h +@@ -0,0 +1,48 @@ ++#ifndef _NIOS2NOMMU_BUG_H ++#define _NIOS2NOMMU_BUG_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/bug.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define BUG() do { \ ++ printk("%s(%d): kernel BUG!\n", __FILE__, __LINE__); \ ++} while (0) ++ ++#define BUG_ON(condition) do { \ ++ if (unlikely((condition)!=0)) \ ++ BUG(); \ ++} while(0) ++ ++#define PAGE_BUG(page) do { \ ++ BUG(); \ ++} while (0) ++ ++#define WARN_ON(condition) do { \ ++ if (unlikely((condition)!=0)) { \ ++ printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ ++ dump_stack(); \ ++ } \ ++} while (0) ++ ++#endif +--- linux/include/asm-nios2nommu/bugs.h ++++ linux/include/asm-nios2nommu/bugs.h +@@ -0,0 +1,40 @@ ++#ifndef __ASM_NIOS_BUGS_H ++#define __ASM_NIOS_BUGS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/bugs.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 1994 Linus Torvalds ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This is included by init/main.c to check for architecture-dependent bugs. ++ * ++ * Needs: ++ * void check_bugs(void); ++ */ ++ ++static void check_bugs(void) ++{ ++} ++ ++#endif +--- linux/include/asm-nios2nommu/byteorder.h ++++ linux/include/asm-nios2nommu/byteorder.h +@@ -0,0 +1,38 @@ ++#ifndef __ASM_NIOS_BYTEORDER_H ++#define __ASM_NIOS_BYTEORDER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/byteorder.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) ++# define __BYTEORDER_HAS_U64__ ++# define __SWAB_64_THRU_32__ ++#endif ++ ++#include ++ ++#endif ++ +--- linux/include/asm-nios2nommu/cachectl.h ++++ linux/include/asm-nios2nommu/cachectl.h +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_CACHECTL_H ++#define _NIOS2NOMMU_CACHECTL_H ++ ++/* Definitions for the cacheflush system call. */ ++ ++#define FLUSH_SCOPE_LINE 1 /* Flush a cache line */ ++#define FLUSH_SCOPE_PAGE 2 /* Flush a page */ ++#define FLUSH_SCOPE_ALL 3 /* Flush the whole cache -- superuser only */ ++ ++#define FLUSH_CACHE_DATA 1 /* Writeback and flush data cache */ ++#define FLUSH_CACHE_INSN 2 /* Flush instruction cache */ ++#define FLUSH_CACHE_BOTH 3 /* Flush both caches */ ++ ++#endif /* _NIOS2NOMMU_CACHECTL_H */ +--- linux/include/asm-nios2nommu/cacheflush.h ++++ linux/include/asm-nios2nommu/cacheflush.h +@@ -0,0 +1,59 @@ ++#ifndef _NIOS2NOMMU_CACHEFLUSH_H ++#define _NIOS2NOMMU_CACHEFLUSH_H ++ ++/* ++ * Ported from m68knommu. ++ * ++ * (C) Copyright 2003, Microtronix Datacom Ltd. ++ * (C) Copyright 2000-2002, Greg Ungerer ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#include ++ ++extern void cache_push (unsigned long vaddr, int len); ++extern void dcache_push (unsigned long vaddr, int len); ++extern void icache_push (unsigned long vaddr, int len); ++extern void cache_push_all (void); ++extern void cache_clear (unsigned long paddr, int len); ++ ++#define flush_cache_all() __flush_cache_all() ++#define flush_cache_mm(mm) do { } while (0) ++#define flush_cache_range(vma, start, end) cache_push(start, end - start) ++#define flush_cache_page(vma, vmaddr) do { } while (0) ++#define flush_dcache_range(start,end) dcache_push(start, end - start) ++#define flush_dcache_page(page) do { } while (0) ++#define flush_dcache_mmap_lock(mapping) do { } while (0) ++#define flush_dcache_mmap_unlock(mapping) do { } while (0) ++#define flush_icache_range(start,end) cache_push(start, end - start) ++#define flush_icache_page(vma,pg) do { } while (0) ++#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) ++ ++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ ++ memcpy(dst, src, len) ++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ ++ memcpy(dst, src, len) ++ ++ ++extern inline void __flush_cache_all(void) ++{ ++ cache_push_all(); ++} ++ ++#endif /* _NIOS2NOMMU_CACHEFLUSH_H */ +--- linux/include/asm-nios2nommu/cache.h ++++ linux/include/asm-nios2nommu/cache.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __ARCH_NIOS2NOMMU_CACHE_H ++#define __ARCH_NIOS2NOMMU_CACHE_H ++ ++#include ++ ++/* bytes per L1 cache line */ ++#define L1_CACHE_BYTES nasys_icache_line_size /* this need to be at least 1 */ ++ ++ ++#define __cacheline_aligned ++#define ____cacheline_aligned ++ ++#endif +--- linux/include/asm-nios2nommu/ChangeLog ++++ linux/include/asm-nios2nommu/ChangeLog +@@ -0,0 +1,14 @@ ++2004-06-29 Ken Hill ++ ++ * bitops.h (find_next_zero_bit): Fix problem with with masking for found_first ++ handling. The masking of the upper bits for size < 32 bits would set all ++ the bits to 1. Removing any zero's there may have been. ++ ++2004-06-02 Ken Hill ++ ++ * processor.h (TASK_SIZE): Change na_sdram_end to nasys_program_mem_end to remove ++ dependancy on quartus memory component name. ++ ++ * page.h (PAGE_OFFSET): Change na_sdram to nasys_program_mem to remove ++ dependancy on quartus memory component name. ++ +--- linux/include/asm-nios2nommu/checksum.h ++++ linux/include/asm-nios2nommu/checksum.h +@@ -0,0 +1,320 @@ ++#ifndef __NIOS2_CHECKSUM_H ++#define __NIOS2_CHECKSUM_H ++ ++/* checksum.h: IP/UDP/TCP checksum routines on the NIOS. ++ * ++ * Copyright(C) 1995 Linus Torvalds ++ * Copyright(C) 1995 Miguel de Icaza ++ * Copyright(C) 1996 David S. Miller ++ * Copyright(C) 2001 Ken Hill ++ * Copyright(C) 2004 Microtronix Datacom Ltd. ++ * ++ * derived from: ++ * Alpha checksum c-code ++ * ix86 inline assembly ++ * Spar nommu ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++/* ++ * computes the checksum of the TCP/UDP pseudo-header ++ * returns a 16-bit checksum, already complemented ++ */ ++ ++extern inline unsigned short csum_tcpudp_magic(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++" add %0, %3, %0\n" ++" bgeu %0, %3, 1f\n" ++" addi %0, %0, 1\n" ++"1: add %0, %4, %0\n" ++" bgeu %0, %4, 1f\n" ++" addi %0, %0, 1\n" ++"1: add %0, %5, %0\n" ++" bgeu %0, %5, 1f\n" ++" addi %0, %0, 1\n" ++"1:\n" ++/* ++ We need the carry from the addition of 16-bit ++ significant addition, so we zap out the low bits ++ in one half, zap out the high bits in another, ++ shift them both up to the top 16-bits of a word ++ and do the carry producing addition, finally ++ shift the result back down to the low 16-bits. ++ ++ Actually, we can further optimize away two shifts ++ because we know the low bits of the original ++ value will be added to zero-only bits so cannot ++ affect the addition result nor the final carry ++ bit. ++*/ ++" slli %1,%0, 16\n" /* Need a copy to fold with */ ++ /* Bring the LOW 16 bits up */ ++" add %0, %1, %0\n" /* add and set carry, neat eh? */ ++" cmpltu r15, %0, %1\n" /* get remaining carry bit */ ++" srli %0, %0, 16\n" /* shift back down the result */ ++" add %0, %0, r15\n" ++" nor %0, %0, %0\n" /* negate */ ++ : "=&r" (sum), "=&r" (saddr) ++ : "0" (sum), "1" (saddr), "r" (ntohl(len+proto)), "r" (daddr) ++ : "r15"); ++ return ((unsigned short) sum); ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++ extern inline unsigned short from32to16(unsigned long x) ++ { ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r15, %0, %1\n" ++ "srli %0, %0, 16\n" ++ "add %0, %0, r15\n" ++ : "=r" (x) ++ : "r" (x << 16), "0" (x) ++ : "r15"); ++ return x; ++ barrier(); ++ } ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++extern inline unsigned long do_csum(const unsigned char * buff, int len) ++{ ++ int odd, count; ++ unsigned long result = 0; ++ ++ barrier(); ++ if (len <= 0) ++ goto out; ++ odd = 1 & (unsigned long) buff; ++ if (odd) { ++////result = *buff; // dgt: Big endian ++ result = *buff << 8; // dgt: Little endian ++ ++ len--; ++ buff++; ++ } ++ count = len >> 1; /* nr of 16-bit words.. */ ++ if (count) { ++ if (2 & (unsigned long) buff) { ++ result += *(unsigned short *) buff; ++ count--; ++ len -= 2; ++ buff += 2; ++ } ++ count >>= 1; /* nr of 32-bit words.. */ ++ if (count) { ++ unsigned long carry = 0; ++ do { ++ unsigned long w = *(unsigned long *) buff; ++ count--; ++ buff += 4; ++ result += carry; ++ result += w; ++ carry = (w > result); ++ } while (count); ++ result += carry; ++ result = (result & 0xffff) + (result >> 16); ++ } ++ if (len & 2) { ++ result += *(unsigned short *) buff; ++ buff += 2; ++ } ++ } ++ if (len & 1) ++ result += *buff; /* This is little machine, byte is right */ ++ result = from32to16(result); ++ if (odd) ++ result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); ++out: ++ return result; ++ barrier(); ++ } ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++/* ihl is always 5 or greater, almost always is 5, iph is always word ++ * aligned but can fail to be dword aligned very often. ++ */ ++ ++ extern inline unsigned short ip_fast_csum(const unsigned char *iph, unsigned int ihl) ++ { ++ unsigned int sum; ++ ++ barrier(); ++ __asm__ __volatile__( ++" andi r8, %1, 2\n" /* Remember original alignment */ ++" ldw %0, (%1)\n" /* 16 or 32 bit boundary */ ++" beq r8, r0, 1f\n" /* Aligned on 32 bit boundary, go */ ++" srli %0, %0, 16\n" /* Get correct 16 bits */ ++" addi %2, %2, -1\n" /* Take off for 4 bytes, pickup last 2 at end */ ++" addi %1, %1, 2\n" /* Adjust pointer to 32 bit boundary */ ++" br 2f\n" ++"1:\n" ++" addi %2, %2, -1\n" ++" addi %1, %1, 4\n" /* Bump ptr a long word */ ++"2:\n" ++" ldw r9, (%1)\n" ++"1:\n" ++" add %0, r9, %0\n" ++" bgeu %0, r9, 2f\n" ++" addi %0, %0, 1\n" ++"2:\n" ++" addi %1, %1, 4\n" ++" addi %2, %2, -1\n" ++" ldw r9, (%1)\n" ++" bne %2, r0, 1b\n" ++" beq r8, r0, 1f\n" /* 32 bit boundary time to leave */ ++" srli r9, r9, 16\n" /* 16 bit boundary, get correct 16 bits */ ++" add %0, r9, %0\n" ++" bgeu %0, r9, 1f\n" ++" addi %0, %0, 1\n" ++"1:\n" ++" slli %2, %0, 16\n" ++" add %0, %2, %0\n" ++" cmpltu r8, %0, %2\n" ++" srli %0, %0, 16\n" ++" add %0, %0, r8\n" ++" nor %0, %0, %0\n" ++ : "=&r" (sum), "=&r" (iph), "=&r" (ihl) ++ : "1" (iph), "2" (ihl) ++ : "r8", "r9"); ++ return sum; ++ barrier(); ++ } ++ ++/*these 2 functions are now in checksum.c */ ++unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); ++unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++/* ++ * the same as csum_partial_copy, but copies from user space. ++ * ++ * here even more important to align src and dst on a 32-bit (or even ++ * better 64-bit) boundary ++ */ ++extern inline unsigned int ++csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *csum_err) ++{ ++ barrier(); ++ if (csum_err) *csum_err = 0; ++ memcpy(dst, src, len); ++ return csum_partial(dst, len, sum); ++ barrier(); ++} ++ ++#define csum_partial_copy_nocheck(src, dst, len, sum) \ ++ csum_partial_copy ((src), (dst), (len), (sum)) ++ ++ ++/* ++ * this routine is used for miscellaneous IP-like checksums, mainly ++ * in icmp.c ++ */ ++ ++extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) ++{ ++ barrier(); ++ return ~from32to16(do_csum(buff,len)); ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++#define csum_partial_copy_fromuser(s, d, l, w) \ ++ csum_partial_copy((char *) (s), (d), (l), (w)) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++/* ++ * Fold a partial checksum without adding pseudo headers ++ */ ++extern __inline__ unsigned int csum_fold(unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r8, %0, %1\n" ++ "srli %0, %0, 16\n" ++ "add %0, %0, r8\n" ++ "nor %0, %0, %0\n" ++ : "=r" (sum) ++ : "r" (sum << 16), "0" (sum) ++ : "r8"); ++ return sum; ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r8, %0, %1\n" ++ "add %0, %0, r8\n" /* add carry */ ++ "add %0, %2, %0\n" ++ "cmpltu r8, %0, %2\n" ++ "add %0, %0, r8\n" /* add carry */ ++ "add %0, %3, %0\n" ++ "cmpltu r8, %0, %3\n" ++ "add %0, %0, r8\n" /* add carry */ ++ : "=r" (sum), "=r" (saddr) ++ : "r" (daddr), "r" ( (ntohs(len)<<16) + (proto*256) ), ++ "0" (sum), ++ "1" (saddr) ++ : "r8"); ++ ++ return sum; ++ barrier(); ++} ++ ++ ++#endif /* (__NIOS2_CHECKSUM_H) */ +--- linux/include/asm-nios2nommu/cprefix.h ++++ linux/include/asm-nios2nommu/cprefix.h +@@ -0,0 +1,38 @@ ++/* cprefix.h: This file is included by assembly source which needs ++ * to know what the c-label prefixes are. The newer versions ++ * of cpp that come with gcc predefine such things to help ++ * us out. The reason this stuff is needed is to make ++ * solaris compiles of the kernel work. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2_CPREFIX_H ++#define __NIOS2_CPREFIX_H ++ ++#define C_LABEL_PREFIX ++ ++#define CONCAT(a, b) CONCAT2(a, b) ++#define CONCAT2(a, b) a##b ++ ++#define C_LABEL(name) CONCAT(C_LABEL_PREFIX, name) ++ ++#endif /* !(__NIOS2_CPREFIX_H) */ +--- linux/include/asm-nios2nommu/cpumask.h ++++ linux/include/asm-nios2nommu/cpumask.h +@@ -0,0 +1,28 @@ ++/* ++ * All rights reserved. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2NOMMU_CPUMASK_H ++#define _ASM_NIOS2NOMMU_CPUMASK_H ++ ++#include ++ ++#endif /* _ASM_NIOS2NOMMU_CPUMASK_H */ +--- linux/include/asm-nios2nommu/cputime.h ++++ linux/include/asm-nios2nommu/cputime.h +@@ -0,0 +1,31 @@ ++/* ++ * cputime.h ++ * (C) Copyright 2004, Microtronix Datacom Ltd. ++ * ++ * Taken from m68knommu ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_CPUTIME_H ++#define __NIOS2NOMMU_CPUTIME_H ++ ++#include ++ ++#endif /* __NIOS@NOMMU_CPUTIME_H */ +--- linux/include/asm-nios2nommu/current.h ++++ linux/include/asm-nios2nommu/current.h +@@ -0,0 +1,39 @@ ++#ifndef _NIOS2NOMMU_CURRENT_H ++#define _NIOS2NOMMU_CURRENT_H ++/* ++ * current.h ++ * (C) Copyright 2000, Lineo, David McCullough ++ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) ++ * (C) Copyright 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++ ++struct task_struct; ++ ++static inline struct task_struct *get_current(void) ++{ ++ return(current_thread_info()->task); ++} ++ ++#define current get_current() ++ ++#endif /* _NIOS2NOMMU_CURRENT_H */ +--- linux/include/asm-nios2nommu/delay.h ++++ linux/include/asm-nios2nommu/delay.h +@@ -0,0 +1,96 @@ ++#ifndef _NIOS_DELAY_H ++#define _NIOS_DELAY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/delay.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++extern __inline__ void __delay(unsigned long loops) ++{ ++ int dummy; ++ ++ __asm__ __volatile__( ++ "1: \n\t" ++ " beq %0,zero,2f\n\t" ++ " addi %0, %0, -1\n\t" ++ " br 1b\n\t" ++ "2: \n\t" ++ ++ : "=r" (dummy) /* Need output for optimizer */ ++ ++ : "0" (loops) /* %0 Input */ ++ ); ++} ++ ++/* ++ * Note that 19 * 226 == 4294 ==~ 2^32 / 10^6, so ++ * loops = (4294 * usecs * loops_per_jiffy * HZ) / 2^32. ++ * ++ * The mul instruction gives us loops = (a * b) / 2^32. ++ * We choose a = usecs * 19 * HZ and b = loops_per_jiffy * 226 ++ * because this lets us support a wide range of HZ and ++ * loops_per_jiffy values without either a or b overflowing 2^32. ++ * Thus we need usecs * HZ <= (2^32 - 1) / 19 = 226050910 and ++ * loops_per_jiffy <= (2^32 - 1) / 226 = 19004280 ++ * (which corresponds to ~3800 bogomips at HZ = 100). ++ * -- paulus ++ */ ++#define __MAX_UDELAY (226050910UL/HZ) /* maximum udelay argument */ ++#define __MAX_NDELAY (4294967295UL/HZ) /* maximum ndelay argument */ ++ ++extern unsigned long loops_per_jiffy; ++ ++extern __inline__ void __udelay(unsigned int x) ++{ ++ unsigned int loops; ++ ++ __asm__("mulxuu %0,%1,%2" : "=r" (loops) : ++ "r" (x), "r" (loops_per_jiffy * 226)); ++ __delay(loops); ++} ++ ++extern __inline__ void __ndelay(unsigned int x) ++{ ++ unsigned int loops; ++ ++ __asm__("mulxuu %0,%1,%2" : "=r" (loops) : ++ "r" (x), "r" (loops_per_jiffy * 5)); ++ __delay(loops); ++} ++ ++extern void __bad_udelay(void); /* deliberately undefined */ ++extern void __bad_ndelay(void); /* deliberately undefined */ ++ ++#define udelay(n) (__builtin_constant_p(n)? \ ++ ((n) > __MAX_UDELAY? __bad_udelay(): __udelay((n) * (19 * HZ))) : \ ++ __udelay((n) * (19 * HZ))) ++ ++#define ndelay(n) (__builtin_constant_p(n)? \ ++ ((n) > __MAX_NDELAY? __bad_ndelay(): __ndelay((n) * HZ)) : \ ++ __ndelay((n) * HZ)) ++ ++#define muldiv(a, b, c) (((a)*(b))/(c)) ++ ++#endif /* defined(_NIOS_DELAY_H) */ +--- linux/include/asm-nios2nommu/div64.h ++++ linux/include/asm-nios2nommu/div64.h +@@ -0,0 +1,31 @@ ++#ifndef __ASMNIOS_DIV64_H ++#define __ASMNIOS_DIV64_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/div64.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif ++ +--- linux/include/asm-nios2nommu/dma.h ++++ linux/include/asm-nios2nommu/dma.h +@@ -0,0 +1,57 @@ ++/* $Id: dma.h,v 1.6 2005/04/07 21:00:26 wentao Exp $ ++ * ++ * Copyright 2004 (C) Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2_DMA_H ++#define _ASM_NIOS2_DMA_H ++ ++#include ++#include ++ ++#define MAX_DMA_ADDRESS (LINUX_SDRAM_END) ++ ++int request_dma(unsigned int, const char *); ++void free_dma(unsigned int); ++void enable_dma(unsigned int dmanr); ++void disable_dma(unsigned int dmanr); ++void set_dma_count(unsigned int dmanr, unsigned int count); ++int get_dma_residue(unsigned int dmanr); ++void nios2_set_dma_data_width(unsigned int dmanr, unsigned int width); ++ ++void nios2_set_dma_handler(unsigned int dmanr, int (*handler)(void*, int), void* user); ++int nios2_request_dma(const char *); ++ ++void nios2_set_dma_mode(unsigned int dmanr, unsigned int mode); ++void nios2_set_dma_rcon(unsigned int dmanr, unsigned int set); ++void nios2_set_dma_wcon(unsigned int dmanr, unsigned int set); ++void nios2_set_dma_raddr(unsigned int dmanr, unsigned int a); ++void nios2_set_dma_waddr(unsigned int dmanr, unsigned int a); ++ ++static inline unsigned long claim_dma_lock(void) ++{ ++} ++ ++static inline void release_dma_lock(unsigned long flags) ++{ ++} ++ ++#endif /* !(_ASM_NIOS2_DMA_H) */ +--- linux/include/asm-nios2nommu/dma-mapping.h ++++ linux/include/asm-nios2nommu/dma-mapping.h +@@ -0,0 +1,133 @@ ++/* ++ * include/asm-nios2nommu/dma-mapping.h ++ * ++ * This file exists so that #include doesn't break anything. ++ */ ++ ++#ifndef _ASM_DMA_MAPPING_H ++#define _ASM_DMA_MAPPING_H ++ ++#include ++#include ++#include ++#include ++ ++static inline void *dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, int flag) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void dma_free_coherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle) ++{ ++ BUG(); ++} ++ ++/** ++ * dma_map_single - map a single buffer for streaming DMA ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @cpu_addr: CPU direct mapped address of buffer ++ * @size: size of buffer to map ++ * @dir: DMA transfer direction ++ * ++ * Ensure that any data held in the cache is appropriately discarded ++ * or written back. ++ * ++ * The device owns this memory once this call has completed. The CPU ++ * can regain ownership by calling dma_unmap_single() or ++ * dma_sync_single_for_cpu(). ++ */ ++static inline dma_addr_t ++dma_map_single(struct device *dev, void *cpu_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ cache_push ((unsigned long)cpu_addr, size); ++ return virt_to_bus((unsigned long)cpu_addr); ++} ++ ++/** ++ * dma_unmap_single - unmap a single buffer previously mapped ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @handle: DMA address of buffer ++ * @size: size of buffer to map ++ * @dir: DMA transfer direction ++ * ++ * Unmap a single streaming mode DMA translation. The handle and size ++ * must match what was provided in the previous dma_map_single() call. ++ * All other usages are undefined. ++ * ++ * After this call, reads by the CPU to the buffer are guaranteed to see ++ * whatever the device wrote there. ++ */ ++static inline void ++dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, ++ enum dma_data_direction dir) ++{ ++ cache_clear((unsigned long)bus_to_virt(handle), size); ++} ++ ++/** ++ * dma_map_sg - map a set of SG buffers for streaming mode DMA ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @sg: list of buffers ++ * @nents: number of buffers to map ++ * @dir: DMA transfer direction ++ * ++ * Map a set of buffers described by scatterlist in streaming ++ * mode for DMA. This is the scatter-gather version of the ++ * above dma_map_single interface. Here the scatter gather list ++ * elements are each tagged with the appropriate dma address ++ * and length. They are obtained via sg_dma_{address,length}(SG). ++ * ++ * NOTE: An implementation may be able to use a smaller number of ++ * DMA address/length pairs than there are SG table elements. ++ * (for example via virtual mapping capabilities) ++ * The routine returns the number of addr/length pairs actually ++ * used, at most nents. ++ * ++ * Device ownership issues as mentioned above for dma_map_single are ++ * the same here. ++ */ ++static inline int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ int i; ++ ++ for (i = 0; i < nents; i++, sg++) { ++ char *virt; ++ ++ sg->dma_address = page_to_bus(sg->page) + sg->offset; ++ virt = page_address(sg->page) + sg->offset; ++ cache_push ((unsigned long)virt, sg->length); ++ } ++ ++ return nents; ++} ++ ++/** ++ * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @sg: list of buffers ++ * @nents: number of buffers to map ++ * @dir: DMA transfer direction ++ * ++ * Unmap a set of streaming mode DMA translations. ++ * Again, CPU read rules concerning calls here are the same as for ++ * dma_unmap_single() above. ++ */ ++static inline void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ int i; ++ ++ for (i = 0; i < nents; i++, sg++) { ++ char *virt; ++ virt = page_address(sg->page) + sg->offset; ++ cache_clear ((unsigned long)virt, sg->length); ++ } ++} ++#endif /* _ASM_DMA_MAPPING_H */ +--- linux/include/asm-nios2nommu/elf.h ++++ linux/include/asm-nios2nommu/elf.h +@@ -0,0 +1,141 @@ ++#ifndef __NIOS2_ELF_H ++#define __NIOS2_ELF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/elf.h ++ * ++ * Nio2 ELF relocation types ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * Mar/18/2004 xwt NiosII relocation types added ++ * ++ ---------------------------------------------------------------------*/ ++ ++// #include ++#include ++#include ++ ++#define R_NIOS2_NONE 0 ++#define R_NIOS2_S16 1 ++#define R_NIOS2_U16 2 ++#define R_NIOS2_PCREL16 3 ++#define R_NIOS2_CALL26 4 ++#define R_NIOS2_IMM5 5 ++#define R_NIOS2_CACHE_OPX 6 ++#define R_NIOS2_IMM6 7 ++#define R_NIOS2_IMM8 8 ++#define R_NIOS2_HI16 9 ++#define R_NIOS2_LO16 10 ++#define R_NIOS2_HIADJ16 11 ++#define R_NIOS2_BFD_RELOC_32 12 ++#define R_NIOS2_BFD_RELOC_16 13 ++#define R_NIOS2_BFD_RELOC_8 14 ++#define R_NIOS2_GPREL 15 ++#define R_NIOS2_GNU_VTINHERIT 16 ++#define R_NIOS2_GNU_VTENTRY 17 ++#define R_NIOS2_UJMP 18 ++#define R_NIOS2_CJMP 19 ++#define R_NIOS2_CALLR 20 ++#define R_NIOS2_ALIGN 21 ++/* Keep this the last entry. */ ++#define R_NIOS2_NUM 22 ++ ++typedef unsigned long elf_greg_t; ++ ++#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) ++typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ++ ++typedef unsigned long elf_fpregset_t; ++ ++/* ++ * This is used to ensure we don't load something for the wrong architecture. ++ */ ++#define elf_check_arch(x) \ ++ ((x)->e_machine == EM_ALTERA_NIOS2) ++ ++/* ++ * These are used to set parameters in the core dumps. ++ */ ++#define ELF_CLASS ELFCLASS32 ++#define ELF_DATA ELFDATA2LSB ++#define ELF_ARCH EM_ALTERA_NIOS2 ++ ++#define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 ++ ++#define USE_ELF_CORE_DUMP ++#define ELF_EXEC_PAGESIZE 4096 ++ ++/* This is the location that an ET_DYN program is loaded if exec'ed. Typical ++ use of this is to invoke "./ld.so someprog" to test out a new version of ++ the loader. We need to make sure that it is out of the way of the program ++ that it will "exec", and that there is sufficient room for the brk. */ ++ ++#define ELF_ET_DYN_BASE 0xD0000000UL ++ ++/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is ++ now struct_user_regs, they are different) */ ++ ++#define ELF_CORE_COPY_REGS(pr_reg, regs) \ ++ /* Bleech. */ \ ++ pr_reg[0] = regs->r1; \ ++ pr_reg[1] = regs->r2; \ ++ pr_reg[2] = regs->r3; \ ++ pr_reg[3] = regs->r4; \ ++ pr_reg[4] = regs->r5; \ ++ pr_reg[5] = regs->r6; \ ++ pr_reg[6] = regs->r7; \ ++ pr_reg[7] = regs->r8; \ ++ pr_reg[8] = regs->r9; \ ++ pr_reg[9] = regs->r10; \ ++ pr_reg[10] = regs->r11; \ ++ pr_reg[11] = regs->r12; \ ++ pr_reg[12] = regs->r13; \ ++ pr_reg[13] = regs->r14; \ ++ pr_reg[14] = regs->r15; \ ++ pr_reg[23] = regs->sp; \ ++ pr_reg[26] = regs->estatus; \ ++ { \ ++ struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ ++ pr_reg[15] = sw->r16; \ ++ pr_reg[16] = sw->r17; \ ++ pr_reg[17] = sw->r18; \ ++ pr_reg[18] = sw->r19; \ ++ pr_reg[19] = sw->r20; \ ++ pr_reg[20] = sw->r21; \ ++ pr_reg[21] = sw->r22; \ ++ pr_reg[22] = sw->r23; \ ++ pr_reg[24] = sw->fp; \ ++ pr_reg[25] = sw->gp; \ ++ } ++ ++/* This yields a mask that user programs can use to figure out what ++ instruction set this cpu supports. */ ++ ++#define ELF_HWCAP (0) ++ ++/* This yields a string that ld.so will use to load implementation ++ specific libraries for optimization. This is more specific in ++ intent than poking at uname or /proc/cpuinfo. */ ++ ++#define ELF_PLATFORM (NULL) ++ ++#ifdef __KERNEL__ ++#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) ++#endif ++ ++#endif +--- linux/include/asm-nios2nommu/entry.h ++++ linux/include/asm-nios2nommu/entry.h +@@ -0,0 +1,188 @@ ++/* ++ * Hacked from m68knommu port. ++ * ++ * Copyright(C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_ENTRY_H ++#define __NIOS2NOMMU_ENTRY_H ++ ++#ifdef __ASSEMBLY__ ++ ++// #include ++#include ++#include ++#include ++ ++/* ++ * Stack layout in 'ret_from_exception': ++ * ++ * This allows access to the syscall arguments in registers r4-r8 ++ * ++ * 0(sp) - r8 ++ * 4(sp) - r9 ++ * 8(sp) - r10 ++ * C(sp) - r11 ++ * 10(sp) - r12 ++ * 14(sp) - r13 ++ * 18(sp) - r14 ++ * 1C(sp) - r15 ++ * 20(sp) - r1 ++ * 24(sp) - r2 ++ * 28(sp) - r3 ++ * 2C(sp) - r4 ++ * 30(sp) - r5 ++ * 34(sp) - r6 ++ * 38(sp) - r7 ++ * 3C(sp) - orig_r2 ++ * 40(sp) - ra ++ * 44(sp) - fp ++ * 48(sp) - sp ++ * 4C(sp) - gp ++ * 50(sp) - estatus ++ * 54(sp) - status_extension ++ * 58(sp) - ea ++ * ++ */ ++ ++/* process bits for task_struct.flags */ ++PF_TRACESYS_OFF = 3 ++PF_TRACESYS_BIT = 5 ++PF_PTRACED_OFF = 3 ++PF_PTRACED_BIT = 4 ++PF_DTRACE_OFF = 1 ++PF_DTRACE_BIT = 5 ++ ++LENOSYS = 38 ++ ++/* ++ * This defines the normal kernel pt-regs layout. ++ * ++ */ ++ ++/* ++ * Standard Nios2 interrupt entry and exit macros. ++ * Must be called with interrupts disabled. ++ */ ++.macro SAVE_ALL ++ movia r24,status_extension // Read status extension ++ ldw r24,0(r24) ++ andi r24,r24,PS_S_ASM ++ bne r24,r0,1f // In supervisor mode, already on kernel stack ++ movia r24,_current_thread // Switch to current kernel stack ++ ldw r24,0(r24) // using the thread_info ++ addi r24,r24,THREAD_SIZE_ASM-PT_REGS_SIZE ++ stw sp,PT_SP(r24) // Save user stack before changing ++ mov sp,r24 ++ br 2f ++ ++1: mov r24,sp ++ addi sp,sp,-PT_REGS_SIZE // Backup the kernel stack pointer ++ stw r24,PT_SP(sp) ++2: stw r1,PT_R1(sp) ++ stw r2,PT_R2(sp) ++ stw r3,PT_R3(sp) ++ stw r4,PT_R4(sp) ++ stw r5,PT_R5(sp) ++ stw r6,PT_R6(sp) ++ stw r7,PT_R7(sp) ++ stw r8,PT_R8(sp) ++ stw r9,PT_R9(sp) ++ stw r10,PT_R10(sp) ++ stw r11,PT_R11(sp) ++ stw r12,PT_R12(sp) ++ stw r13,PT_R13(sp) ++ stw r14,PT_R14(sp) ++ stw r15,PT_R15(sp) ++ stw r2,PT_ORIG_R2(sp) ++ stw ra,PT_RA(sp) ++ stw fp,PT_FP(sp) ++ stw gp,PT_GP(sp) ++ rdctl r24,estatus ++ stw r24,PT_ESTATUS(sp) ++ movia r24,status_extension // Read status extension ++ ldw r1,0(r24) ++ stw r1,PT_STATUS_EXTENSION(sp) // Store user/supervisor status ++ ORI32 r1,r1,PS_S_ASM // Set supervisor mode ++ stw r1,0(r24) ++ stw ea,PT_EA(sp) ++.endm ++ ++.macro RESTORE_ALL ++ ldw r1,PT_STATUS_EXTENSION(sp) // Restore user/supervisor status ++ movia r24,status_extension ++ stw r1,0(r24) ++ ldw r1,PT_R1(sp) // Restore registers ++ ldw r2,PT_R2(sp) ++ ldw r3,PT_R3(sp) ++ ldw r4,PT_R4(sp) ++ ldw r5,PT_R5(sp) ++ ldw r6,PT_R6(sp) ++ ldw r7,PT_R7(sp) ++ ldw r8,PT_R8(sp) ++ ldw r9,PT_R9(sp) ++ ldw r10,PT_R10(sp) ++ ldw r11,PT_R11(sp) ++ ldw r12,PT_R12(sp) ++ ldw r13,PT_R13(sp) ++ ldw r14,PT_R14(sp) ++ ldw r15,PT_R15(sp) ++ ldw ra,PT_RA(sp) ++ ldw fp,PT_FP(sp) ++ ldw gp,PT_GP(sp) ++ ldw r24,PT_ESTATUS(sp) ++ wrctl estatus,r24 ++ ldw ea,PT_EA(sp) ++ ldw sp,PT_SP(sp) // Restore sp last ++.endm ++ ++.macro SAVE_SWITCH_STACK ++ addi sp,sp,-SWITCH_STACK_SIZE ++ stw r16,SW_R16(sp) ++ stw r17,SW_R17(sp) ++ stw r18,SW_R18(sp) ++ stw r19,SW_R19(sp) ++ stw r20,SW_R20(sp) ++ stw r21,SW_R21(sp) ++ stw r22,SW_R22(sp) ++ stw r23,SW_R23(sp) ++ stw fp,SW_FP(sp) ++ stw gp,SW_GP(sp) ++ stw ra,SW_RA(sp) ++.endm ++ ++.macro RESTORE_SWITCH_STACK ++ ldw r16,SW_R16(sp) ++ ldw r17,SW_R17(sp) ++ ldw r18,SW_R18(sp) ++ ldw r19,SW_R19(sp) ++ ldw r20,SW_R20(sp) ++ ldw r21,SW_R21(sp) ++ ldw r22,SW_R22(sp) ++ ldw r23,SW_R23(sp) ++ ldw fp,SW_FP(sp) ++ ldw gp,SW_GP(sp) ++ ldw ra,SW_RA(sp) ++ addi sp,sp,SWITCH_STACK_SIZE ++.endm ++ ++#endif /* __ASSEMBLY__ */ ++#endif /* __NIOS2NOMMU_ENTRY_H */ +--- linux/include/asm-nios2nommu/errno.h ++++ linux/include/asm-nios2nommu/errno.h +@@ -0,0 +1,6 @@ ++#ifndef _NIOS2NOMMU_ERRNO_H ++#define _NIOS2NOMMU_ERRNO_H ++ ++#include ++ ++#endif /* _NIOS2NOMMU_ERRNO_H */ +--- linux/include/asm-nios2nommu/fcntl.h ++++ linux/include/asm-nios2nommu/fcntl.h +@@ -0,0 +1,110 @@ ++/* ++ * This file came from the m68k port. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2_FCNTL_H ++#define _NIOS2_FCNTL_H ++ ++/* open/fcntl - O_SYNC is only implemented on blocks devices and on files ++ located on an ext2 file system */ ++#define O_ACCMODE 0003 ++#define O_RDONLY 00 ++#define O_WRONLY 01 ++#define O_RDWR 02 ++#define O_CREAT 0100 /* not fcntl */ ++#define O_EXCL 0200 /* not fcntl */ ++#define O_NOCTTY 0400 /* not fcntl */ ++#define O_TRUNC 01000 /* not fcntl */ ++#define O_APPEND 02000 ++#define O_NONBLOCK 04000 ++#define O_NDELAY O_NONBLOCK ++#define O_SYNC 010000 ++#define FASYNC 020000 /* fcntl, for BSD compatibility */ ++#define O_DIRECTORY 040000 /* must be a directory */ ++#define O_NOFOLLOW 0100000 /* don't follow links */ ++#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ ++#define O_LARGEFILE 0400000 ++#define O_NOATIME 01000000 ++ ++#define F_DUPFD 0 /* dup */ ++#define F_GETFD 1 /* get close_on_exec */ ++#define F_SETFD 2 /* set/clear close_on_exec */ ++#define F_GETFL 3 /* get file->f_flags */ ++#define F_SETFL 4 /* set file->f_flags */ ++#define F_GETLK 5 ++#define F_SETLK 6 ++#define F_SETLKW 7 ++ ++#define F_SETOWN 8 /* for sockets. */ ++#define F_GETOWN 9 /* for sockets. */ ++#define F_SETSIG 10 /* for sockets. */ ++#define F_GETSIG 11 /* for sockets. */ ++ ++#define F_GETLK64 12 /* using 'struct flock64' */ ++#define F_SETLK64 13 ++#define F_SETLKW64 14 ++ ++/* for F_[GET|SET]FL */ ++#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ ++ ++/* for posix fcntl() and lockf() */ ++#define F_RDLCK 0 ++#define F_WRLCK 1 ++#define F_UNLCK 2 ++ ++/* for old implementation of bsd flock () */ ++#define F_EXLCK 4 /* or 3 */ ++#define F_SHLCK 8 /* or 4 */ ++ ++/* for leases */ ++#define F_INPROGRESS 16 ++ ++/* operations for bsd flock(), also used by the kernel implementation */ ++#define LOCK_SH 1 /* shared lock */ ++#define LOCK_EX 2 /* exclusive lock */ ++#define LOCK_NB 4 /* or'd with one of the above to prevent ++ blocking */ ++#define LOCK_UN 8 /* remove lock */ ++ ++#define LOCK_MAND 32 /* This is a mandatory flock */ ++#define LOCK_READ 64 /* ... Which allows concurrent read operations */ ++#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ ++#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ ++ ++struct flock { ++ short l_type; ++ short l_whence; ++ off_t l_start; ++ off_t l_len; ++ pid_t l_pid; ++}; ++ ++struct flock64 { ++ short l_type; ++ short l_whence; ++ loff_t l_start; ++ loff_t l_len; ++ pid_t l_pid; ++}; ++ ++#define F_LINUX_SPECIFIC_BASE 1024 ++#endif /* _NIOS2_FCNTL_H */ +--- linux/include/asm-nios2nommu/flat.h ++++ linux/include/asm-nios2nommu/flat.h +@@ -0,0 +1,126 @@ ++/* ++ * include/asm-nios2nommu/flat.h -- uClinux bFLT relocations ++ * ++ * Copyright (C) 2004,05 Microtronix Datacom Ltd ++ * ++ * This file is subject to the terms and conditions of the GNU General ++ * Public License. See the file COPYING in the main directory of this ++ * archive for more details. ++ * ++ * Written by Wentao Xu ++ */ ++ ++#ifndef __NIOS2_FLAT_H__ ++#define __NIOS2_FLAT_H__ ++ ++#define flat_reloc_valid(reloc, size) ((reloc) <= (size + 0x8000)) ++ ++/* The stack is 64-bit aligned for Nios II, so (sp - 1) shall ++ * be 64-bit aligned, where -1 is for argc ++ */ ++#define flat_stack_align(sp) (sp = (unsigned long *)(((unsigned long)sp - 1) & (-8))) ++ ++/* The uClibc port for Nios II expects the argc is followed by argv and envp */ ++#define flat_argvp_envp_on_stack() 1 ++ ++#define flat_old_ram_flag(flags) (flags) ++ ++/* We store the type of relocation in the top 4 bits of the `relval.' */ ++ ++/* Convert a relocation entry into an address. */ ++static inline unsigned long ++flat_get_relocate_addr (unsigned long relval) ++{ ++ return relval & 0x0fffffff; /* Mask out top 4-bits */ ++} ++ ++#define FLAT_NIOS2_RELOC_TYPE(relval) ((relval) >> 28) ++ ++#define FLAT_NIOS2_R_32 0 /* Normal 32-bit reloc */ ++#define FLAT_NIOS2_R_HI_LO 1 /* High 16-bits + low 16-bits field */ ++#define FLAT_NIOS2_R_HIADJ_LO 2 /* High 16-bits adjust + low 16-bits field */ ++#define FLAT_NIOS2_R_CALL26 4 /* Call imm26 */ ++ ++/* Extract the address to be relocated from the symbol reference at rp; ++ * relval is the raw relocation-table entry from which RP is derived. ++ * rp shall always be 32-bit aligned ++ */ ++static inline unsigned long flat_get_addr_from_rp (unsigned long *rp, ++ unsigned long relval, ++ unsigned long flags) ++{ ++ switch (FLAT_NIOS2_RELOC_TYPE(relval)) ++ { ++ case FLAT_NIOS2_R_32: ++ /* Simple 32-bit address. The loader expect it in bigger endian */ ++ return htonl(*rp); ++ ++ case FLAT_NIOS2_R_HI_LO: ++ /* get the two 16-bit immediate value from instructions, then ++ * construct a 32-bit value. Again the loader expect bigger endian ++ */ ++ return htonl ((((rp[0] >> 6) & 0xFFFF) << 16 ) | ++ ((rp[1] >> 6) & 0xFFFF)); ++ ++ case FLAT_NIOS2_R_HIADJ_LO: ++ { ++ /* get the two 16-bit immediate value from instructions, then ++ * construct a 32-bit value. Again the loader expect bigger endian ++ */ ++ unsigned int low, high; ++ high = (rp[0] >> 6) & 0xFFFF; ++ low = (rp[1] >> 6) & 0xFFFF; ++ ++ if ((low >> 15) & 1) high--; ++ ++ return htonl ((high << 16 ) | low ); ++ } ++ case FLAT_NIOS2_R_CALL26: ++ /* the 26-bit immediate value is actually 28-bit */ ++ return htonl(((*rp) >> 6) << 2); ++ ++ default: ++ return ~0; /* bogus value */ ++ } ++} ++ ++/* Insert the address addr into the symbol reference at rp; ++ * relval is the raw relocation-table entry from which rp is derived. ++ * rp shall always be 32-bit aligned ++ */ ++static inline void flat_put_addr_at_rp (unsigned long *rp, unsigned long addr, ++ unsigned long relval) ++{ ++ unsigned long exist_val; ++ switch (FLAT_NIOS2_RELOC_TYPE (relval)) { ++ case FLAT_NIOS2_R_32: ++ /* Simple 32-bit address. */ ++ *rp = addr; ++ break; ++ ++ case FLAT_NIOS2_R_HI_LO: ++ exist_val = rp[0]; ++ rp[0] = ((((exist_val >> 22) << 16) | (addr >> 16)) << 6) | (exist_val & 0x3F); ++ exist_val = rp[1]; ++ rp[1] = ((((exist_val >> 22) << 16) | (addr & 0xFFFF)) << 6) | (exist_val & 0x3F); ++ break; ++ ++ case FLAT_NIOS2_R_HIADJ_LO: ++ { ++ unsigned int high = (addr >> 16); ++ if ((addr >> 15) & 1) ++ high = (high + 1) & 0xFFFF; ++ exist_val = rp[0]; ++ rp[0] = ((((exist_val >> 22) << 16) | high) << 6) | (exist_val & 0x3F); ++ exist_val = rp[1]; ++ rp[1] = ((((exist_val >> 22) << 16) | (addr & 0xFFFF)) << 6) | (exist_val & 0x3F); ++ break; ++ } ++ case FLAT_NIOS2_R_CALL26: ++ /* the opcode of CALL is 0, so just store the value */ ++ *rp = ((addr >> 2) << 6); ++ break; ++ } ++} ++ ++#endif /* __NIOS2_FLAT_H__ */ +--- linux/include/asm-nios2nommu/hardirq.h ++++ linux/include/asm-nios2nommu/hardirq.h +@@ -0,0 +1,53 @@ ++/* ++ * Ported from m68knommu ++ * ++ * Copyright (C) 2003, Microtronix Datacom Ltd. ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2_HARDIRQ_H ++#define __NIOS2_HARDIRQ_H ++ ++// #include ++#include ++#include ++ ++typedef struct { ++ unsigned int __softirq_pending; ++} ____cacheline_aligned irq_cpustat_t; ++ ++#include /* Standard mappings for irq_cpustat_t above */ ++ ++#define HARDIRQ_BITS 8 ++ ++/* ++ * The hardirq mask has to be large enough to have ++ * space for potentially all IRQ sources in the system ++ * nesting on a single CPU: ++ */ ++#if (1 << HARDIRQ_BITS) < NR_IRQS ++# error HARDIRQ_BITS is too low! ++#endif ++ ++#ifdef CONFIG_SMP ++# error nios2nommu SMP is not available ++#endif /* CONFIG_SMP */ ++ ++#endif /* __NIOS2_HARDIRQ_H */ +--- linux/include/asm-nios2nommu/hdreg.h ++++ linux/include/asm-nios2nommu/hdreg.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 1994-1996 Linus Torvalds & authors ++ * Copyright (C) 2002 Wentau Xu (www.microtronix.com) ++ * copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_HDREG_H ++#define __NIOS2_HDREG_H ++ ++typedef unsigned long ide_ioreg_t; ++ ++#endif /* __NIOS2_HDREG_H */ +--- linux/include/asm-nios2nommu/hw_irq.h ++++ linux/include/asm-nios2nommu/hw_irq.h +@@ -0,0 +1,16 @@ ++#ifndef _ASM_HW_IRQ_H ++#define _ASM_HW_IRQ_H ++ ++/* ++ * linux/include/asm/hw_irq.h ++ * ++ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar ++ * ++ * moved some of the old arch/i386/kernel/irq.h to here. VY ++ * ++ * IRQ/IPI changes taken from work by Thomas Radke ++ * ++ */ ++ ++ ++#endif /* _ASM_HW_IRQ_H */ +--- linux/include/asm-nios2nommu/ide.h ++++ linux/include/asm-nios2nommu/ide.h +@@ -0,0 +1,47 @@ ++/* ++ * linux/include/asm-niosnommu2/ide.h ++ * ++ * Copyright (C) 1994-1996 Linus Torvalds & authors ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ASMNIOS2_IDE_H ++#define __ASMNIOS2_IDE_H ++ ++#ifdef __KERNEL__ ++#undef MAX_HWIFS /* we're going to force it */ ++ ++#ifndef MAX_HWIFS ++#define MAX_HWIFS 1 ++#endif ++ ++#define IDE_ARCH_OBSOLETE_INIT ++#define IDE_ARCH_OBSOLETE_DEFAULTS ++#define ide_default_io_base(i) ((unsigned long)na_ide_ide) ++#define ide_default_irq(b) (na_ide_ide_irq) ++#define ide_init_default_irq(base) ide_default_irq(base) ++#define ide_default_io_ctl(base) ((base) + (0xE*4)) ++ ++#include ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* __ASMNIOS2_IDE_H */ +--- linux/include/asm-nios2nommu/init.h ++++ linux/include/asm-nios2nommu/init.h +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#error " should never be used - use instead" +--- linux/include/asm-nios2nommu/ioctl.h ++++ linux/include/asm-nios2nommu/ioctl.h +@@ -0,0 +1,100 @@ ++/* $Id: ioctl.h,v 1.3 2004/02/12 23:06:40 ken-h Exp $ ++ * ++ * linux/ioctl.h for Linux by H.H. Bergman. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_IOCTL_H ++#define _NIOS2_IOCTL_H ++ ++/* ioctl command encoding: 32 bits total, command in lower 16 bits, ++ * size of the parameter structure in the lower 14 bits of the ++ * upper 16 bits. ++ * Encoding the size of the parameter structure in the ioctl request ++ * is useful for catching programs compiled with old versions ++ * and to avoid overwriting user space outside the user buffer area. ++ * The highest 2 bits are reserved for indicating the ``access mode''. ++ * NOTE: This limits the max parameter size to 16kB -1 ! ++ */ ++ ++/* ++ * I don't really have any idea about what this should look like, so ++ * for the time being, this is heavily based on the PC definitions. ++ */ ++ ++/* ++ * The following is for compatibility across the various Linux ++ * platforms. The i386 ioctl numbering scheme doesn't really enforce ++ * a type field. De facto, however, the top 8 bits of the lower 16 ++ * bits are indeed used as a type field, so we might just as well make ++ * this explicit here. Please be sure to use the decoding macros ++ * below from now on. ++ */ ++#define _IOC_NRBITS 8 ++#define _IOC_TYPEBITS 8 ++#define _IOC_SIZEBITS 14 ++#define _IOC_DIRBITS 2 ++ ++#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) ++#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) ++#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) ++#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) ++ ++#define _IOC_NRSHIFT 0 ++#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) ++#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) ++#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) ++ ++/* ++ * Direction bits. ++ */ ++#define _IOC_NONE 0U ++#define _IOC_WRITE 1U ++#define _IOC_READ 2U ++ ++#define _IOC(dir,type,nr,size) \ ++ (((dir) << _IOC_DIRSHIFT) | \ ++ ((type) << _IOC_TYPESHIFT) | \ ++ ((nr) << _IOC_NRSHIFT) | \ ++ ((size) << _IOC_SIZESHIFT)) ++ ++/* used to create numbers */ ++#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) ++#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) ++#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) ++#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) ++ ++/* used to decode ioctl numbers.. */ ++#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) ++#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) ++#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) ++#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) ++ ++/* ...and for the drivers/sound files... */ ++ ++#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) ++#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) ++#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) ++#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) ++#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) ++ ++#endif /* _NIOS2_IOCTL_H */ +--- linux/include/asm-nios2nommu/ioctls.h ++++ linux/include/asm-nios2nommu/ioctls.h +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ARCH_NIOS2_IOCTLS_H__ ++#define __ARCH_NIOS2_IOCTLS_H__ ++ ++#include ++ ++/* 0x54 is just a magic number to make these relatively unique ('T') */ ++ ++#define TCGETS 0x5401 ++#define TCSETS 0x5402 ++#define TCSETSW 0x5403 ++#define TCSETSF 0x5404 ++#define TCGETA 0x5405 ++#define TCSETA 0x5406 ++#define TCSETAW 0x5407 ++#define TCSETAF 0x5408 ++#define TCSBRK 0x5409 ++#define TCXONC 0x540A ++#define TCFLSH 0x540B ++#define TIOCEXCL 0x540C ++#define TIOCNXCL 0x540D ++#define TIOCSCTTY 0x540E ++#define TIOCGPGRP 0x540F ++#define TIOCSPGRP 0x5410 ++#define TIOCOUTQ 0x5411 ++#define TIOCSTI 0x5412 ++#define TIOCGWINSZ 0x5413 ++#define TIOCSWINSZ 0x5414 ++#define TIOCMGET 0x5415 ++#define TIOCMBIS 0x5416 ++#define TIOCMBIC 0x5417 ++#define TIOCMSET 0x5418 ++#define TIOCGSOFTCAR 0x5419 ++#define TIOCSSOFTCAR 0x541A ++#define FIONREAD 0x541B ++#define TIOCINQ FIONREAD ++#define TIOCLINUX 0x541C ++#define TIOCCONS 0x541D ++#define TIOCGSERIAL 0x541E ++#define TIOCSSERIAL 0x541F ++#define TIOCPKT 0x5420 ++#define FIONBIO 0x5421 ++#define TIOCNOTTY 0x5422 ++#define TIOCSETD 0x5423 ++#define TIOCGETD 0x5424 ++#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ ++#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ ++#define TIOCSBRK 0x5427 /* BSD compatibility */ ++#define TIOCCBRK 0x5428 /* BSD compatibility */ ++#define TIOCGSID 0x5429 /* Return the session ID of FD */ ++#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ ++#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ ++ ++#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ ++#define FIOCLEX 0x5451 ++#define FIOASYNC 0x5452 ++#define TIOCSERCONFIG 0x5453 ++#define TIOCSERGWILD 0x5454 ++#define TIOCSERSWILD 0x5455 ++#define TIOCGLCKTRMIOS 0x5456 ++#define TIOCSLCKTRMIOS 0x5457 ++#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ ++#define TIOCSERGETLSR 0x5459 /* Get line status register */ ++#define TIOCSERGETMULTI 0x545A /* Get multiport config */ ++#define TIOCSERSETMULTI 0x545B /* Set multiport config */ ++ ++#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ ++#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ ++#define FIOQSIZE 0x545E ++ ++/* Used for packet mode */ ++#define TIOCPKT_DATA 0 ++#define TIOCPKT_FLUSHREAD 1 ++#define TIOCPKT_FLUSHWRITE 2 ++#define TIOCPKT_STOP 4 ++#define TIOCPKT_START 8 ++#define TIOCPKT_NOSTOP 16 ++#define TIOCPKT_DOSTOP 32 ++ ++#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ ++ ++#endif /* __ARCH_NIOS2_IOCTLS_H__ */ +--- linux/include/asm-nios2nommu/io.h ++++ linux/include/asm-nios2nommu/io.h +@@ -0,0 +1,240 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_IO_H ++#define __NIOS2_IO_H ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#include /* IO address mapping routines need this */ ++#include ++#include ++ ++extern void insw(unsigned long port, void *dst, unsigned long count); ++extern void outsw(unsigned long port, void *src, unsigned long count); ++extern void insl(unsigned long port, void *dst, unsigned long count); ++extern void outsl(unsigned long port, void *src, unsigned long count); ++ ++ ++/* ++ * readX/writeX() are used to access memory mapped devices. On some ++ * architectures the memory mapped IO stuff needs to be accessed ++ * differently. On the Nios architecture, we just read/write the ++ * memory location directly. ++ */ ++ ++#define readb(addr) \ ++({ \ ++ unsigned char __res;\ ++ __asm__ __volatile__( \ ++ "ldbuio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define readw(addr) \ ++({ \ ++ unsigned short __res;\ ++ __asm__ __volatile__( \ ++ "ldhuio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define readl(addr) \ ++({ \ ++ unsigned int __res;\ ++ __asm__ __volatile__( \ ++ "ldwio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define writeb(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "stbio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define writew(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "sthio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define writel(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "stwio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define __raw_readb readb ++#define __raw_readw readw ++#define __raw_readl readl ++#define __raw_writeb writeb ++#define __raw_writew writew ++#define __raw_writel writel ++ ++#define mmiowb() ++ ++/* ++ * make the short names macros so specific devices ++ * can override them as required ++ */ ++ ++#define memset_io(addr,c,len) memset((void *)(((unsigned int)(addr)) | 0x80000000),(c),(len)) ++#define memcpy_fromio(to,from,len) memcpy((to),(void *)(((unsigned int)(from)) | 0x80000000),(len)) ++#define memcpy_toio(to,from,len) memcpy((void *)(((unsigned int)(to)) | 0x80000000),(from),(len)) ++ ++#define inb(addr) readb(addr) ++#define inw(addr) readw(addr) ++#define inl(addr) readl(addr) ++ ++#define outb(x,addr) ((void) writeb(x,addr)) ++#define outw(x,addr) ((void) writew(x,addr)) ++#define outl(x,addr) ((void) writel(x,addr)) ++ ++#define inb_p(addr) inb(addr) ++#define inw_p(addr) inw(addr) ++#define inl_p(addr) inl(addr) ++ ++#define outb_p(x,addr) outb(x,addr) ++#define outw_p(x,addr) outw(x,addr) ++#define outl_p(x,addr) outl(x,addr) ++ ++ ++ ++extern inline void insb(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned char *p=(unsigned char*)dst; ++ while (count--) ++ *p++ = inb(port); ++} ++ ++/* See arch/niosnommu/io.c for optimized version */ ++extern inline void _insw(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned short *p=(unsigned short*)dst; ++ while (count--) ++ *p++ = inw(port); ++} ++ ++/* See arch/niosnommu/kernel/io.c for unaligned destination pointer */ ++extern inline void _insl(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned long *p=(unsigned long*)dst; ++ while (count--) ++ *p++ = inl(port); ++} ++ ++extern inline void outsb(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned char *p=(unsigned char*)src; ++ while (count--) ++ outb( *p++, port ); ++} ++ ++/* See arch/niosnommu/io.c for optimized version */ ++extern inline void _outsw(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned short *p=(unsigned short*)src; ++ while (count--) ++ outw( *p++, port ); ++} ++ ++/* See arch/niosnommu/kernel/io.c for unaligned source pointer */ ++extern inline void _outsl(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned long *p=(unsigned long*)src; ++ while (count--) ++ outl( *p++, port ); ++} ++ ++ ++ ++extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr, ++ int bus, int rdonly) ++{ ++ return; ++} ++ ++//vic - copied from m68knommu ++ ++/* Values for nocacheflag and cmode */ ++#define IOMAP_FULL_CACHING 0 ++#define IOMAP_NOCACHE_SER 1 ++#define IOMAP_NOCACHE_NONSER 2 ++#define IOMAP_WRITETHROUGH 3 ++ ++extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); ++extern void __iounmap(void *addr, unsigned long size); ++ ++extern inline void *ioremap(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); ++} ++extern inline void *ioremap_nocache(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); ++} ++extern inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); ++} ++extern inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_FULL_CACHING); ++} ++ ++extern void iounmap(void *addr); ++ ++ ++#define IO_SPACE_LIMIT 0xffffffff ++ ++#define dma_cache_inv(_start,_size) do { } while (0) ++#define dma_cache_wback(_start,_size) do { } while (0) ++#define dma_cache_wback_inv(_start,_size) do { } while (0) ++ ++/* Pages to physical address... */ ++#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) ++#define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT) ++ ++#define mm_ptov(vaddr) ((void *) (vaddr)) ++#define mm_vtop(vaddr) ((unsigned long) (vaddr)) ++#define phys_to_virt(vaddr) ((void *) (vaddr)) ++#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) ++ ++#define virt_to_bus virt_to_phys ++#define bus_to_virt phys_to_virt ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* !(__NIOS2_IO_H) */ ++ +--- linux/include/asm-nios2nommu/ipcbuf.h ++++ linux/include/asm-nios2nommu/ipcbuf.h +@@ -0,0 +1,49 @@ ++#ifndef __NIOS2_IPCBUF_H__ ++#define __NIOS2_IPCBUF_H__ ++ ++/* Copied from asm-m68k/ipcbuf.h ++ * The user_ipc_perm structure for Nios architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 32-bit mode_t and seq ++ * - 2 miscellaneous 32-bit values ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++struct ipc64_perm ++{ ++ __kernel_key_t key; ++ __kernel_uid32_t uid; ++ __kernel_gid32_t gid; ++ __kernel_uid32_t cuid; ++ __kernel_gid32_t cgid; ++ __kernel_mode_t mode; ++ unsigned short __pad1; ++ unsigned short seq; ++ unsigned short __pad2; ++ unsigned long __unused1; ++ unsigned long __unused2; ++}; ++ ++#endif /* __NIOS2_IPCBUF_H__ */ +--- linux/include/asm-nios2nommu/ipc.h ++++ linux/include/asm-nios2nommu/ipc.h +@@ -0,0 +1,51 @@ ++#ifndef __NIOS2_IPC_H__ ++#define __NIOS2_IPC_H__ ++ ++/* Copied from sparc version ++ * These are used to wrap system calls on the Nios. ++ * ++ * See arch/niosnommu/kernel/sys_nios.c for ugly details.. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++struct ipc_kludge { ++ struct msgbuf *msgp; ++ long msgtyp; ++}; ++ ++#define SEMOP 1 ++#define SEMGET 2 ++#define SEMCTL 3 ++#define MSGSND 11 ++#define MSGRCV 12 ++#define MSGGET 13 ++#define MSGCTL 14 ++#define SHMAT 21 ++#define SHMDT 22 ++#define SHMGET 23 ++#define SHMCTL 24 ++ ++/* Used by the DIPC package, try and avoid reusing it */ ++#define DIPC 25 ++ ++#define IPCCALL(version,op) ((version)<<16 | (op)) ++ ++#endif +--- linux/include/asm-nios2nommu/irq.h ++++ linux/include/asm-nios2nommu/irq.h +@@ -0,0 +1,182 @@ ++/* ++ * 21Mar2001 1.1 dgt/microtronix ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++ ++#ifndef _NIOS2NOMMU_IRQ_H_ ++#define _NIOS2NOMMU_IRQ_H_ ++ ++extern void disable_irq(unsigned int); ++extern void enable_irq(unsigned int); ++ ++// #include ++#include ++ ++#define SYS_IRQS 32 ++#define NR_IRQS SYS_IRQS ++ ++/* ++ * Interrupt source definitions ++ * General interrupt sources are the level 1-7. ++ * Adding an interrupt service routine for one of these sources ++ * results in the addition of that routine to a chain of routines. ++ * Each one is called in succession. Each individual interrupt ++ * service routine should determine if the device associated with ++ * that routine requires service. ++ */ ++ ++#define IRQ01 (1) /* level 1 interrupt */ ++#define IRQ02 (2) /* level 2 interrupt */ ++#define IRQ03 (3) /* level 3 interrupt */ ++#define IRQ04 (4) /* level 4 interrupt */ ++#define IRQ05 (5) /* level 5 interrupt */ ++#define IRQ06 (6) /* level 6 interrupt */ ++#define IRQ07 (7) /* level 7 interrupt */ ++#define IRQ08 (8) /* level 8 interrupt */ ++#define IRQ09 (9) /* level 9 interrupt */ ++#define IRQ0A (10) /* level 10 interrupt */ ++#define IRQ0B (11) /* level 11 interrupt */ ++#define IRQ0C (12) /* level 12 interrupt */ ++#define IRQ0D (13) /* level 13 interrupt */ ++#define IRQ0E (14) /* level 14 interrupt */ ++#define IRQ0F (15) /* level 15 interrupt */ ++#define IRQ10 (16) /* level 16 interrupt */ ++#define IRQ12 (17) /* level 17 interrupt */ ++#define IRQ13 (18) /* level 18 interrupt */ ++#define IRQ14 (19) /* level 19 interrupt */ ++#define IRQ15 (20) /* level 20 interrupt */ ++#define IRQ16 (21) /* level 21 interrupt */ ++#define IRQ17 (22) /* level 22 interrupt */ ++#define IRQ18 (23) /* level 23 interrupt */ ++#define IRQ19 (24) /* level 24 interrupt */ ++#define IRQ1A (25) /* level 25 interrupt */ ++#define IRQ1B (26) /* level 26 interrupt */ ++#define IRQ1C (27) /* level 27 interrupt */ ++#define IRQ1D (28) /* level 28 interrupt */ ++#define IRQ1E (29) /* level 29 interrupt */ ++#define IRQ1F (30) /* level 30 interrupt */ ++#define IRQ20 (31) /* level 31 interrupt */ ++#define IRQ21 (32) /* level 32 interrupt */ ++ ++#define IRQMAX IRQ21 ++ ++/* ++ * "Generic" interrupt sources ++ */ ++ ++/* ++ * Machine specific interrupt sources. ++ * ++ * Adding an interrupt service routine for a source with this bit ++ * set indicates a special machine specific interrupt source. ++ * The machine specific files define these sources. ++ * ++ * Removed, they are not used by any one. ++ */ ++ ++/* ++ * various flags for request_irq() ++ */ ++#define IRQ_FLG_LOCK (0x0001) /* handler is not replaceable */ ++#define IRQ_FLG_REPLACE (0x0002) /* replace existing handler */ ++#define IRQ_FLG_FAST (0x0004) ++#define IRQ_FLG_SLOW (0x0008) ++#define IRQ_FLG_STD (0x8000) /* internally used */ ++ ++/* ++ * Functions to set and clear the interrupt mask. ++ */ ++ ++/* ++ * Use a zero to clean the bit. ++ */ ++static inline void clrimr(int mask) ++{ ++ int flags; ++ ++ local_irq_save(flags); ++ __asm__ __volatile__( ++ "rdctl r8, ienable\n" ++ "and r8,r8,%0\n" ++ "wrctl ienable, r8\n" ++ : /* No output */ ++ : "r" (mask) ++ : "r8"); ++ local_irq_restore(flags); ++} ++ ++/* ++ * Use a one to set the bit. ++ */ ++static inline void setimr(int mask) ++{ ++ int flags; ++ ++ local_irq_save(flags); ++ __asm__ __volatile__( ++ "rdctl r8, ienable\n" ++ "or r8,r8,%0\n" ++ "wrctl ienable, r8\n" ++ : /* No output */ ++ : "r" (mask) ++ : "r8"); ++ local_irq_restore(flags); ++} ++ ++/* ++ * This structure is used to chain together the ISRs for a particular ++ * interrupt source (if it supports chaining). ++ */ ++typedef struct irq_node { ++ irqreturn_t (*handler)(int, void *, struct pt_regs *); ++ unsigned long flags; ++ void *dev_id; ++ const char *devname; ++ struct irq_node *next; ++} irq_node_t; ++ ++/* ++ * This function returns a new irq_node_t ++ */ ++extern irq_node_t *new_irq_node(void); ++ ++/* ++ * This structure has only 4 elements for speed reasons ++ */ ++typedef struct irq_handler { ++ irqreturn_t (*handler)(int, void *, struct pt_regs *); ++ unsigned long flags; ++ void *dev_id; ++ const char *devname; ++} irq_handler_t; ++ ++/* count of spurious interrupts */ ++extern volatile unsigned int num_spurious; ++ ++#define disable_irq_nosync(i) disable_irq(i) ++ ++#ifndef irq_canonicalize ++#define irq_canonicalize(i) (i) ++#endif ++ ++#endif /* _NIOS2NOMMU_IRQ_H_ */ +--- linux/include/asm-nios2nommu/kmap_types.h ++++ linux/include/asm-nios2nommu/kmap_types.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_KMAP_TYPES_H ++#define _ASM_KMAP_TYPES_H ++ ++enum km_type { ++ KM_BOUNCE_READ, ++ KM_SKB_SUNRPC_DATA, ++ KM_SKB_DATA_SOFTIRQ, ++ KM_USER0, ++ KM_USER1, ++ KM_BIO_SRC_IRQ, ++ KM_BIO_DST_IRQ, ++ KM_PTE0, ++ KM_PTE1, ++ KM_IRQ0, ++ KM_IRQ1, ++ KM_SOFTIRQ0, ++ KM_SOFTIRQ1, ++ KM_TYPE_NR ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/linkage.h ++++ linux/include/asm-nios2nommu/linkage.h +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ASM_LINKAGE_H ++#define __ASM_LINKAGE_H ++ ++#define __ALIGN .align 3 ++#define __ALIGN_STR ".align 3" ++ ++#endif +--- linux/include/asm-nios2nommu/linux_logo.h ++++ linux/include/asm-nios2nommu/linux_logo.h +@@ -0,0 +1,953 @@ ++/* $Id: linux_logo.h,v 1.3 2004/02/12 23:06:40 ken-h Exp $ ++ * include/asm-nios/linux_logo.h: This is a linux logo ++ * to be displayed on boot. ++ * ++ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu) ++ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) ++ * Copyright (C) 2004 Micrtronix Datacom Ltd. ++ * ++ * You can put anything here, but: ++ * LINUX_LOGO_COLORS has to be less than 224 ++ * image size has to be 80x80 ++ * values have to start from 0x20 ++ * (i.e. RGB(linux_logo_red[0], ++ * linux_logo_green[0], ++ * linux_logo_blue[0]) is color 0x20) ++ * BW image has to be 80x80 as well, with MS bit ++ * on the left ++ * Serial_console ascii image can be any size, ++ * but should contain %s to display the version ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++ ++#define linux_logo_banner "Linux/NIOS2 version " UTS_RELEASE ++ ++#define __HAVE_ARCH_LINUX_LOGO ++#define __HAVE_ARCH_LINUX_LOGO16 ++ ++#define LINUX_LOGO_COLORS 221 ++ ++#ifdef INCLUDE_LINUX_LOGO_DATA ++ ++unsigned char linux_logo_red[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79, ++ 0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7, ++ 0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8, ++ 0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6, ++ 0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee, ++ 0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c, ++ 0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e, ++ 0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c, ++ 0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfe, ++ 0xf6, 0xec, 0xfe, 0xd2, 0xea, 0xf5, 0xf2, 0xf2, ++ 0xe9, 0xee, 0xf6, 0xf2, 0xee, 0xf6, 0xda, 0xd4, ++ 0xfa, 0xca, 0xf2, 0xf6, 0xfe, 0xf2, 0xda, 0xe4, ++ 0xf6, 0xdd, 0xf2, 0xee, 0xfa, 0xf0, 0x12, 0x4a, ++ 0xd6, 0xf2, 0x8e, 0xf2, 0xf6, 0xf6, 0xb5, 0xf1, ++ 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16, 0x9a, ++ 0x2e, 0xd2, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62, ++ 0xda, 0xee, 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xe0, ++ 0xae, 0xbe, 0xce, 0xe2, 0xa3, 0x8e, 0x6d, 0x8e, ++ 0x32, 0xaf, 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, ++ 0x7a, 0x82, 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, ++ 0x6a, 0x52, 0x59, 0x64, 0x5e, ++}; ++ ++unsigned char linux_logo_green[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c, ++ 0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae, ++ 0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8, ++ 0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda, ++ 0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca, ++ 0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76, ++ 0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46, ++ 0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b, ++ 0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfa, ++ 0xea, 0xd7, 0xf6, 0xbc, 0xda, 0xde, 0xda, 0xe6, ++ 0xca, 0xd8, 0xea, 0xe0, 0xcc, 0xf2, 0xce, 0xb2, ++ 0xee, 0xa2, 0xd6, 0xe6, 0xf6, 0xd7, 0xc5, 0xb8, ++ 0xc6, 0xb9, 0xce, 0xde, 0xce, 0xc6, 0x0e, 0x36, ++ 0xae, 0xbe, 0x86, 0xba, 0xbe, 0xe6, 0x8e, 0xc4, ++ 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12, 0x7a, ++ 0x20, 0xc6, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46, ++ 0xce, 0xd6, 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa6, ++ 0x87, 0x96, 0xa2, 0xd6, 0x85, 0x7a, 0x6a, 0x6e, ++ 0x22, 0x76, 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, ++ 0x66, 0x62, 0x42, 0x50, 0x56, 0x42, 0x56, 0x56, ++ 0x56, 0x3e, 0x51, 0x52, 0x56, ++}; ++ ++unsigned char linux_logo_blue[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08, ++ 0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f, ++ 0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e, ++ 0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c, ++ 0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f, ++ 0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a, ++ 0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e, ++ 0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b, ++ 0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xea, ++ 0xb6, 0x7c, 0xda, 0x8e, 0xa6, 0x87, 0x66, 0xb6, ++ 0x81, 0x6a, 0xc6, 0x9a, 0x5b, 0xd2, 0xb6, 0x6a, ++ 0xca, 0x45, 0x92, 0xb2, 0xca, 0x52, 0x8a, 0x3e, ++ 0x2e, 0x66, 0x66, 0xae, 0x3e, 0x47, 0x06, 0x0e, ++ 0x52, 0x36, 0x6a, 0x0e, 0x0e, 0xbe, 0x2c, 0x0e, ++ 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06, 0x2e, ++ 0x06, 0x9e, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06, ++ 0x9e, 0xae, 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x0a, ++ 0x32, 0x2e, 0x2a, 0xb2, 0x43, 0x48, 0x5f, 0x2e, ++ 0x06, 0x06, 0x07, 0x24, 0x06, 0x32, 0x06, 0x06, ++ 0x46, 0x2e, 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, ++ 0x3a, 0x22, 0x42, 0x34, 0x42, ++}; ++ ++unsigned char linux_logo[] __initdata = { ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, ++ 0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d, ++ 0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24, ++ 0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25, ++ 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, ++ 0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c, ++ 0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, ++ 0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31, ++ 0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34, ++ 0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36, ++ 0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22, ++ 0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25, ++ 0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22, ++ 0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36, ++ 0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, ++ 0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36, ++ 0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, ++ 0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36, ++ 0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23, ++ 0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21, ++ 0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b, ++ 0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26, ++ 0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d, ++ 0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32, ++ 0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a, ++ 0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b, ++ 0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37, ++ 0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58, ++ 0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35, ++ 0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, ++ 0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22, ++ 0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67, ++ 0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36, ++ 0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e, ++ 0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73, ++ 0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78, ++ 0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79, ++ 0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c, ++ 0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24, ++ 0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71, ++ 0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36, ++ 0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21, ++ 0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89, ++ 0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36, ++ 0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21, ++ 0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e, ++ 0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23, ++ 0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22, ++ 0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63, ++ 0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c, ++ 0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51, ++ 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21, ++ 0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97, ++ 0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98, ++ 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, ++ 0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32, ++ 0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50, ++ 0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48, ++ 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23, ++ 0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98, ++ 0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50, ++ 0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b, ++ 0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b, ++ 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48, ++ 0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, ++ 0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, ++ 0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34, ++ 0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52, ++ 0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c, ++ 0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c, ++ 0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b, ++ 0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93, ++ 0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28, ++ 0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99, ++ 0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93, ++ 0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36, ++ 0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x99, 0x9f, 0x52, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, ++ 0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30, ++ 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, ++ 0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36, ++ 0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48, ++ 0x47, 0x9f, 0x48, 0x48, 0x48, 0xa0, 0xa1, 0xa2, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36, ++ 0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f, ++ 0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36, ++ 0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48, ++ 0xa3, 0xa4, 0x48, 0x48, 0x9f, 0xa5, 0xa6, 0x9f, ++ 0x48, 0x48, 0x48, 0xa2, 0xa7, 0x47, 0x48, 0x48, ++ 0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23, ++ 0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d, ++ 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25, ++ 0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0xa8, 0xa1, 0x48, 0x48, 0x9f, 0xa9, 0xa6, 0x9f, ++ 0x48, 0x48, 0xaa, 0xa1, 0xa5, 0x9f, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30, ++ 0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32, ++ 0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a, ++ 0x36, 0x24, 0x4f, 0x48, 0x52, 0x52, 0x48, 0x48, ++ 0xab, 0xac, 0xa0, 0x48, 0xad, 0xa6, 0xa6, 0x9f, ++ 0x48, 0xa2, 0xa9, 0xa6, 0xa2, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30, ++ 0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21, ++ 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25, ++ 0x36, 0x3a, 0x48, 0x48, 0xae, 0xaf, 0x48, 0x48, ++ 0xad, 0xac, 0xa1, 0x9f, 0xa2, 0xa9, 0xa9, 0xa2, ++ 0x48, 0xab, 0x78, 0xa7, 0x48, 0x48, 0x48, 0x48, ++ 0x9f, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21, ++ 0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36, ++ 0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21, ++ 0x23, 0x43, 0x48, 0x48, 0xb0, 0xb1, 0xb2, 0x9f, ++ 0x48, 0xb3, 0xa5, 0xb3, 0xab, 0xa9, 0xa9, 0xb3, ++ 0xb4, 0xa9, 0xb5, 0xb0, 0x48, 0x48, 0xa0, 0xa5, ++ 0xa1, 0xad, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36, ++ 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, ++ 0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36, ++ 0x2e, 0x9b, 0x48, 0x48, 0x48, 0xb6, 0xb7, 0xa4, ++ 0xa2, 0xa7, 0xb5, 0x78, 0x6f, 0x6f, 0x6e, 0x6f, ++ 0xa9, 0xb5, 0xab, 0x48, 0x9f, 0xab, 0xa9, 0xa1, ++ 0xaa, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36, ++ 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, ++ 0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36, ++ 0x54, 0x48, 0x48, 0x48, 0x48, 0xa2, 0xa8, 0xa1, ++ 0xa5, 0xa6, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, ++ 0x6f, 0x78, 0xa5, 0xa0, 0xa0, 0x78, 0xa6, 0xa2, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, ++ 0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36, ++ 0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21, ++ 0x43, 0x48, 0x4b, 0xa2, 0x9f, 0x48, 0xa2, 0xa1, ++ 0xb8, 0x6e, 0x6e, 0xb5, 0x78, 0x6f, 0x78, 0x78, ++ 0x6e, 0x6f, 0x78, 0xb5, 0xa6, 0xa1, 0xa0, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21, ++ 0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25, ++ 0x52, 0x48, 0xa3, 0xb1, 0xb6, 0xb3, 0xaa, 0xac, ++ 0x68, 0x68, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, ++ 0x78, 0x6f, 0x6f, 0xb5, 0xa6, 0xb4, 0x48, 0x9f, ++ 0xb4, 0xb4, 0xa2, 0x9f, 0x48, 0x48, 0x4f, 0x21, ++ 0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a, ++ 0x47, 0x48, 0xa2, 0xb6, 0xaf, 0xb9, 0xba, 0x68, ++ 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x78, ++ 0x6f, 0x6f, 0xa6, 0x6f, 0xb5, 0xa0, 0xaa, 0xa6, ++ 0xa6, 0xa9, 0xb2, 0xb3, 0x48, 0x48, 0x4c, 0x22, ++ 0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39, ++ 0x9b, 0x48, 0x48, 0x48, 0xb0, 0xb0, 0xba, 0xb8, ++ 0x68, 0x68, 0x69, 0x78, 0x6f, 0xb5, 0x6f, 0xb5, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0xa5, 0xbb, 0xa9, ++ 0xa5, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23, ++ 0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31, ++ 0x9b, 0x48, 0x48, 0x48, 0x48, 0x9f, 0xac, 0x68, ++ 0xbc, 0x6e, 0x6e, 0x6e, 0xb5, 0x6f, 0x6e, 0x6f, ++ 0x6f, 0x78, 0x78, 0xb5, 0xb5, 0xa5, 0x9f, 0x9f, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22, ++ 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d, ++ 0x9b, 0x48, 0x48, 0xb0, 0xaa, 0xb3, 0xbd, 0xb8, ++ 0xb8, 0x68, 0x6e, 0x6e, 0xb5, 0x6f, 0x78, 0x6e, ++ 0x78, 0x6f, 0x78, 0x78, 0xb5, 0xa9, 0xa2, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, ++ 0x24, 0x27, 0xbe, 0x24, 0x25, 0x28, 0x21, 0x36, ++ 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25, ++ 0x39, 0x4d, 0xbf, 0x84, 0x81, 0x57, 0x21, 0x39, ++ 0x52, 0x48, 0x48, 0x62, 0xb1, 0xc0, 0xc1, 0xc1, ++ 0xb8, 0xb8, 0x68, 0xbc, 0x6e, 0x6e, 0x6e, 0x78, ++ 0x78, 0x78, 0x78, 0x6e, 0x78, 0xa9, 0xa0, 0xab, ++ 0xb3, 0xa2, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28, ++ 0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30, ++ 0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30, ++ 0x2d, 0xc2, 0x7a, 0xc3, 0xc4, 0xc4, 0x7f, 0x22, ++ 0x51, 0x52, 0x48, 0x48, 0xb0, 0xaa, 0xa8, 0xbd, ++ 0x68, 0xb8, 0xb8, 0x68, 0x68, 0x6e, 0x6e, 0x6f, ++ 0x6e, 0x6e, 0xb5, 0x6e, 0x78, 0xab, 0xab, 0xb5, ++ 0x78, 0xa6, 0xb3, 0xc5, 0xac, 0xac, 0xc6, 0x61, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32, ++ 0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31, ++ 0x4d, 0x91, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0x5a, ++ 0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0xb0, 0x64, ++ 0xc1, 0xb8, 0xb8, 0xb8, 0x68, 0x71, 0x6e, 0x6e, ++ 0x6f, 0x71, 0x6f, 0x6f, 0xa6, 0xa0, 0x9f, 0xb4, ++ 0xb4, 0xa0, 0xa1, 0xb7, 0xc7, 0x69, 0x66, 0xc8, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25, ++ 0x83, 0xc9, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a, ++ 0x60, 0x85, 0xca, 0xcb, 0xc4, 0xc4, 0xc4, 0x82, ++ 0x86, 0x36, 0x32, 0x3f, 0xa2, 0xa4, 0xa8, 0xa9, ++ 0xb8, 0xb8, 0xb8, 0xb8, 0x68, 0x6e, 0x6e, 0x6e, ++ 0x6e, 0x71, 0x6f, 0x71, 0xa6, 0xb4, 0x9f, 0x9f, ++ 0x48, 0x48, 0x48, 0xcc, 0xc3, 0xc7, 0xcd, 0xce, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57, ++ 0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x23, 0x30, 0x31, 0xcf, 0x91, 0x7e, 0x90, 0x90, ++ 0x8b, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0x5d, 0xd0, 0x36, 0x24, 0xd1, 0xb1, 0xaf, 0xaa, ++ 0xba, 0xb8, 0x68, 0x68, 0x68, 0x71, 0x6e, 0x6e, ++ 0x6e, 0x6f, 0x6e, 0x78, 0xa1, 0xa9, 0xa1, 0xb0, ++ 0x9f, 0x9b, 0x99, 0xcc, 0x64, 0x5c, 0x8b, 0xd0, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d, ++ 0x82, 0x5c, 0xd2, 0x2a, 0x23, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x24, 0x2b, 0xcf, 0x8b, 0x5b, 0x76, 0x5b, 0x5b, ++ 0x7b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc7, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48, ++ 0xa2, 0xa8, 0xb7, 0xc1, 0xb8, 0x68, 0x68, 0xbc, ++ 0x68, 0x6e, 0xb5, 0xb4, 0xb4, 0xab, 0xb5, 0xa1, ++ 0xb0, 0x4f, 0x3f, 0xd3, 0x7b, 0x7b, 0x85, 0x80, ++ 0xbe, 0x36, 0x36, 0x36, 0x21, 0xd4, 0x7e, 0x7b, ++ 0x64, 0x64, 0xd5, 0x35, 0x24, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x31, 0xd6, 0x5b, 0x64, 0xc3, 0xc3, 0xcb, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0x66, 0xd7, 0x36, 0x36, 0x36, 0x2c, 0x4b, ++ 0xd8, 0xd9, 0xb3, 0xa8, 0xbd, 0xbd, 0xbd, 0xbd, ++ 0xa9, 0xab, 0xb3, 0xa5, 0xa2, 0x9f, 0xa2, 0xa1, ++ 0x6a, 0x9a, 0x3f, 0xda, 0x76, 0x76, 0x7a, 0x63, ++ 0xdb, 0xdc, 0x86, 0xdc, 0xdd, 0x90, 0x5b, 0x64, ++ 0xc3, 0xc3, 0xde, 0x2d, 0x27, 0x23, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x26, 0x2d, 0x91, 0x5b, 0x64, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc7, 0x83, 0xce, 0x36, 0x36, 0x36, 0x30, ++ 0xb1, 0xd9, 0x48, 0xa1, 0xb2, 0xb0, 0xb0, 0xb3, ++ 0xa2, 0x48, 0xa7, 0xbd, 0xa9, 0xa2, 0x48, 0x9f, ++ 0xaa, 0x9a, 0x3f, 0xb1, 0x5b, 0x7b, 0xdf, 0x85, ++ 0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xc3, 0xc4, ++ 0xc4, 0xcb, 0x5d, 0xd5, 0x39, 0x26, 0x23, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2d, 0xe0, 0xdf, 0x64, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc7, 0x88, 0x36, 0x36, 0x36, 0x36, ++ 0x2d, 0x9b, 0x48, 0xb9, 0xaf, 0xa2, 0xa2, 0xb9, ++ 0xa8, 0x9f, 0x48, 0xa7, 0xb7, 0xd9, 0x48, 0x48, ++ 0x9b, 0x45, 0x3f, 0xe1, 0x6d, 0x7b, 0xca, 0xdf, ++ 0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc3, 0xe2, 0x37, 0x35, 0x26, 0x23, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2e, 0xe0, 0x7a, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc7, 0x72, 0x73, 0x36, 0x36, 0x36, ++ 0x24, 0x52, 0x48, 0xa3, 0xaf, 0x9f, 0x48, 0xb6, ++ 0xaf, 0xa2, 0x48, 0x9f, 0xe3, 0xd8, 0x48, 0x48, ++ 0x48, 0x46, 0x42, 0xd6, 0x7a, 0x7b, 0x64, 0x7b, ++ 0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xc3, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xcb, 0x64, 0xe2, 0x4d, 0x2c, 0x27, ++ 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x25, 0x31, 0xe4, 0x8b, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc7, 0x89, 0xbe, 0x36, 0x36, ++ 0x32, 0x47, 0x48, 0x4f, 0xa0, 0x48, 0x48, 0xe3, ++ 0x92, 0x9f, 0x48, 0x9f, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xc3, 0xcb, ++ 0xc3, 0x64, 0x64, 0xc3, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x5d, 0xe5, 0x2c, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x25, 0x31, 0xe4, 0x85, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x57, 0x27, 0x4d, ++ 0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x99, 0x34, 0xbe, 0xdb, 0x7a, 0x7b, 0xc3, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0xe4, ++ 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2d, 0xe4, 0x85, 0x7b, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc7, 0x5f, 0x92, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44, ++ 0x35, 0x36, 0xce, 0xdd, 0x7a, 0x7b, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0xc3, 0xe1, ++ 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x30, 0x2f, 0xd6, 0x8b, 0x7b, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x89, 0x45, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25, ++ 0x36, 0x36, 0x61, 0xdb, 0x6d, 0x64, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0xdf, 0xe5, ++ 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0xe6, 0x63, 0xdf, 0xc3, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x72, 0x81, 0xe7, ++ 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36, ++ 0x36, 0x36, 0xe8, 0x8f, 0x6d, 0x64, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc3, 0xca, 0x8b, 0xcf, 0x2c, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x35, 0x96, 0x75, 0xca, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0x81, 0xdb, ++ 0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b, ++ 0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x73, 0xdb, 0x7a, 0x7b, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0x64, 0x76, 0x7a, 0x91, 0xd5, 0x31, 0x30, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x39, 0x97, 0x75, 0xdf, 0x7b, 0x64, 0xc3, 0xc3, ++ 0xcb, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x7b, 0x7a, 0xe9, ++ 0xea, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30, ++ 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xea, 0xdd, 0x8b, 0x7b, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x64, 0x64, ++ 0x76, 0x85, 0xe0, 0xd5, 0x34, 0x2b, 0x27, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0xeb, 0x63, 0x7e, 0x7a, 0x6d, 0xdf, 0x5b, ++ 0x76, 0x7b, 0x64, 0x64, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x76, 0x85, 0xdb, ++ 0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xec, 0xdd, 0x75, 0x76, 0xc3, 0xc4, ++ 0xc4, 0xc4, 0xcb, 0xc3, 0x64, 0x76, 0xdf, 0x8b, ++ 0xd6, 0xd5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x27, 0x31, 0xed, 0xeb, 0xdd, 0x74, 0x63, 0x90, ++ 0x7e, 0x75, 0x8b, 0x6d, 0xdf, 0x76, 0x64, 0xc3, ++ 0xcb, 0xcb, 0xcb, 0xcb, 0x64, 0x7a, 0x84, 0xee, ++ 0x79, 0xbe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xea, 0xee, 0x63, 0x6d, 0x7b, 0x64, ++ 0xcb, 0xc3, 0x64, 0x7b, 0xdf, 0x75, 0x63, 0x96, ++ 0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x28, 0x27, 0x35, 0x2d, 0x41, 0xd5, 0xe7, 0x8f, ++ 0xdb, 0xdd, 0xe9, 0x74, 0x84, 0x90, 0x85, 0x6d, ++ 0x5b, 0x7b, 0x7b, 0xca, 0x6d, 0x90, 0xdb, 0xef, ++ 0xec, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36, ++ 0x36, 0x21, 0xd4, 0x80, 0xe9, 0x7e, 0x6d, 0x76, ++ 0xca, 0x76, 0x6d, 0x85, 0x63, 0xdb, 0xd5, 0x34, ++ 0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f, ++ 0x41, 0xf0, 0xf1, 0x6c, 0x80, 0xee, 0xdb, 0x74, ++ 0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xef, 0x79, ++ 0xe8, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d, ++ 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38, ++ 0x4d, 0x37, 0xf2, 0xf3, 0x8f, 0x74, 0x63, 0x7e, ++ 0x75, 0x7e, 0x63, 0xe9, 0x88, 0xe6, 0x31, 0x2a, ++ 0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30, ++ 0x33, 0x39, 0x2e, 0x51, 0x41, 0xd2, 0x6c, 0xf3, ++ 0x80, 0xee, 0xee, 0xee, 0xf4, 0xf3, 0xd7, 0xf5, ++ 0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27, ++ 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a, ++ 0x2b, 0x34, 0xf6, 0xec, 0xf7, 0x8f, 0xdd, 0xe9, ++ 0xe9, 0xdd, 0xee, 0x6c, 0x41, 0x39, 0x27, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, ++ 0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41, ++ 0xf8, 0xd7, 0x79, 0x79, 0x79, 0xec, 0xf9, 0x51, ++ 0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22, ++ 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, ++ 0x24, 0x2a, 0x31, 0xfa, 0xea, 0x79, 0xf3, 0x80, ++ 0xf7, 0xdc, 0xfb, 0x2f, 0x35, 0x26, 0x23, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b, ++ 0x31, 0x2f, 0xf6, 0xfa, 0xfa, 0x2f, 0x2e, 0x33, ++ 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x27, 0x35, 0x34, 0xfa, 0xfa, 0xfa, ++ 0xfc, 0xf6, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28, ++ 0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35, ++ 0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24, ++ 0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++}; ++ ++unsigned char linux_logo16[1]; ++ ++#endif /* INCLUDE_LINUX_LOGO_DATA */ ++ ++#include ++ +--- linux/include/asm-nios2nommu/local.h ++++ linux/include/asm-nios2nommu/local.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_LOCAL_H ++#define __NIOS2NOMMU_LOCAL_H ++ ++#include ++ ++#endif /* __NIOS2NOMMU_LOCAL_H */ +--- linux/include/asm-nios2nommu/mc146818rtc.h ++++ linux/include/asm-nios2nommu/mc146818rtc.h +@@ -0,0 +1,29 @@ ++/* ++ * Machine dependent access functions for RTC registers. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2_MC146818RTC_H ++#define _NIOS2_MC146818RTC_H ++ ++/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */ ++ ++#endif /* _NIOS2_MC146818RTC_H */ +--- linux/include/asm-nios2nommu/mman.h ++++ linux/include/asm-nios2nommu/mman.h +@@ -0,0 +1,68 @@ ++/* ++ * Copied from the m68k port. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_MMAN_H__ ++#define __NIOS2_MMAN_H__ ++ ++#define PROT_READ 0x1 /* page can be read */ ++#define PROT_WRITE 0x2 /* page can be written */ ++#define PROT_EXEC 0x4 /* page can be executed */ ++#define PROT_SEM 0x8 /* page may be used for atomic ops */ ++#define PROT_NONE 0x0 /* page can not be accessed */ ++#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ ++#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */ ++ ++#define MAP_SHARED 0x01 /* Share changes */ ++#define MAP_PRIVATE 0x02 /* Changes are private */ ++#define MAP_TYPE 0x0f /* Mask for type of mapping */ ++#define MAP_FIXED 0x10 /* Interpret addr exactly */ ++#define MAP_ANONYMOUS 0x20 /* don't use a file */ ++ ++#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ ++#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ ++#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ ++#define MAP_LOCKED 0x2000 /* pages are locked */ ++#define MAP_NORESERVE 0x4000 /* don't check for reservations */ ++#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ ++#define MAP_NONBLOCK 0x10000 /* do not block on IO */ ++ ++#define MS_ASYNC 1 /* sync memory asynchronously */ ++#define MS_INVALIDATE 2 /* invalidate the caches */ ++#define MS_SYNC 4 /* synchronous memory sync */ ++ ++#define MCL_CURRENT 1 /* lock all current mappings */ ++#define MCL_FUTURE 2 /* lock all future mappings */ ++ ++#define MADV_NORMAL 0x0 /* default page-in behavior */ ++#define MADV_RANDOM 0x1 /* page-in minimum required */ ++#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */ ++#define MADV_WILLNEED 0x3 /* pre-fault pages */ ++#define MADV_DONTNEED 0x4 /* discard these pages */ ++ ++/* compatibility flags */ ++#define MAP_ANON MAP_ANONYMOUS ++#define MAP_FILE 0 ++ ++#endif /* __NIOS2_MMAN_H__ */ ++ +--- linux/include/asm-nios2nommu/mmu_context.h ++++ linux/include/asm-nios2nommu/mmu_context.h +@@ -0,0 +1,58 @@ ++/* ++ * ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_MMU_CONTEXT_H ++#define __NIOS2NOMMU_MMU_CONTEXT_H ++ ++#include ++#include ++#include ++#include ++ ++static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) ++{ ++} ++ ++extern inline int ++init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ // mm->context = virt_to_phys(mm->pgd); ++ return(0); ++} ++ ++#define destroy_context(mm) do { } while(0) ++ ++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) ++{ ++} ++ ++#define deactivate_mm(tsk,mm) do { } while (0) ++ ++extern inline void activate_mm(struct mm_struct *prev_mm, ++ struct mm_struct *next_mm) ++{ ++} ++ ++#endif +--- linux/include/asm-nios2nommu/mmu.h ++++ linux/include/asm-nios2nommu/mmu.h +@@ -0,0 +1,36 @@ ++/* ++ * ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_MMU_H ++#define __NIOS2NOMMU_MMU_H ++ ++/* Copyright (C) 2002, David McCullough */ ++ ++typedef struct { ++ struct vm_list_struct *vmlist; ++ unsigned long end_brk; ++} mm_context_t; ++ ++#endif /* __NIOS2NOMMU_MMU_H */ +--- linux/include/asm-nios2nommu/module.h ++++ linux/include/asm-nios2nommu/module.h +@@ -0,0 +1,36 @@ ++#ifndef _NIOS2_MODULE_H ++#define _NIOS2_MODULE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/module.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++struct mod_arch_specific ++{ ++}; ++ ++#define Elf_Shdr Elf32_Shdr ++#define Elf_Sym Elf32_Sym ++#define Elf_Ehdr Elf32_Ehdr ++ ++#endif /* _NIOS_MODULE_H */ +--- linux/include/asm-nios2nommu/msgbuf.h ++++ linux/include/asm-nios2nommu/msgbuf.h +@@ -0,0 +1,56 @@ ++/* ++ * Taken from the m68k. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_MSGBUF_H ++#define _NIOS2_MSGBUF_H ++ ++/* ++ * The msqid64_ds structure for nios2 architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct msqid64_ds { ++ struct ipc64_perm msg_perm; ++ __kernel_time_t msg_stime; /* last msgsnd time */ ++ unsigned long __unused1; ++ __kernel_time_t msg_rtime; /* last msgrcv time */ ++ unsigned long __unused2; ++ __kernel_time_t msg_ctime; /* last change time */ ++ unsigned long __unused3; ++ unsigned long msg_cbytes; /* current number of bytes on queue */ ++ unsigned long msg_qnum; /* number of messages in queue */ ++ unsigned long msg_qbytes; /* max number of bytes on queue */ ++ __kernel_pid_t msg_lspid; /* pid of last msgsnd */ ++ __kernel_pid_t msg_lrpid; /* last receive pid */ ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++#endif /* _NIOS2_MSGBUF_H */ ++ +--- linux/include/asm-nios2nommu/namei.h ++++ linux/include/asm-nios2nommu/namei.h +@@ -0,0 +1,36 @@ ++/* ++ * linux/include/asm-nios/namei.h ++ * Moved from m68k version ++ * Included from linux/fs/namei.c ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_NAMEI_H ++#define __NIOS2_NAMEI_H ++ ++/* This dummy routine maybe changed to something useful ++ * for /usr/gnemul/ emulation stuff. ++ * Look at asm-sparc/namei.h for details. ++ */ ++ ++#define __emul_prefix() NULL ++ ++#endif +--- linux/include/asm-nios2nommu/ndma.h ++++ linux/include/asm-nios2nommu/ndma.h +@@ -0,0 +1,64 @@ ++#ifndef __NDMA_H__ ++ #define __NDMA_H__ ++ ++ #ifndef __ASSEMBLY__ ++ ++// DMA Registers ++typedef volatile struct ++{ ++ int np_dmastatus; // status register ++ int np_dmareadaddress; // read address ++ int np_dmawriteaddress; // write address ++ int np_dmalength; // length in bytes ++ int np_dmareserved1; // reserved ++ int np_dmareserved2; // reserved ++ int np_dmacontrol; // control register ++ int np_dmareserved3; // control register alternate ++} np_dma; ++ ++// DMA Register Bits ++enum ++{ ++ np_dmacontrol_byte_bit = 0, // Byte transaction ++ np_dmacontrol_hw_bit = 1, // Half-word transaction ++ np_dmacontrol_word_bit = 2, // Word transaction ++ np_dmacontrol_go_bit = 3, // enable execution ++ np_dmacontrol_i_en_bit = 4, // enable interrupt ++ np_dmacontrol_reen_bit = 5, // Enable read end-of-packet ++ np_dmacontrol_ween_bit = 6, // Enable write end-of-packet ++ np_dmacontrol_leen_bit = 7, // Enable length=0 transaction end ++ np_dmacontrol_rcon_bit = 8, // Read from a fixed address ++ np_dmacontrol_wcon_bit = 9, // Write to a fixed address ++ np_dmacontrol_doubleword_bit = 10, // Double-word transaction ++ np_dmacontrol_quadword_bit = 11, // Quad-word transaction ++ ++ np_dmastatus_done_bit = 0, // 1 when done. Status write clears. ++ np_dmastatus_busy_bit = 1, // 1 when busy. ++ np_dmastatus_reop_bit = 2, // read-eop received ++ np_dmastatus_weop_bit = 3, // write-eop received ++ np_dmastatus_len_bit = 4, // requested length transacted ++ ++ np_dmacontrol_byte_mask = (1 << 0), // Byte transaction ++ np_dmacontrol_hw_mask = (1 << 1), // Half-word transaction ++ np_dmacontrol_word_mask = (1 << 2), // Word transaction ++ np_dmacontrol_go_mask = (1 << 3), // enable execution ++ np_dmacontrol_i_en_mask = (1 << 4), // enable interrupt ++ np_dmacontrol_reen_mask = (1 << 5), // Enable read end-of-packet ++ np_dmacontrol_ween_mask = (1 << 6), // Enable write end-of-packet ++ np_dmacontrol_leen_mask = (1 << 7), // Enable length=0 transaction end ++ np_dmacontrol_rcon_mask = (1 << 8), // Read from a fixed address ++ np_dmacontrol_wcon_mask = (1 << 9), // Write to a fixed address ++ np_dmacontrol_doubleword_mask = (1 << 10), // Double-word transaction ++ np_dmacontrol_quadword_mask = (1 << 11), // Quad-word transaction ++ ++ np_dmastatus_done_mask = (1 << 0), // 1 when done. Status write clears. ++ np_dmastatus_busy_mask = (1 << 1), // 1 when busy. ++ np_dmastatus_reop_mask = (1 << 2), // read-eop received ++ np_dmastatus_weop_mask = (1 << 3), // write-eop received ++ np_dmastatus_len_mask = (1 << 4), // requested length transacted ++}; ++ ++ #endif /* __ASSEMBLY__ */ ++ ++#endif ++/* End of File */ +--- linux/include/asm-nios2nommu/nios.h ++++ linux/include/asm-nios2nommu/nios.h +@@ -0,0 +1,7 @@ ++#ifndef __NIOS_H__ ++#define __NIOS_H__ ++ ++#include "nios2_system.h" ++ ++#endif ++ +--- linux/include/asm-nios2nommu/page.h ++++ linux/include/asm-nios2nommu/page.h +@@ -0,0 +1,135 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_PAGE_H ++#define _NIOS2_PAGE_H ++ ++/* copied from m68knommu arch */ ++// #include ++ ++/* PAGE_SHIFT determines the page size */ ++ ++#define PAGE_SHIFT (12) ++#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#define PAGE_MASK (~(PAGE_SIZE-1)) ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#if PAGE_SHIFT < 13 ++#define THREAD_SIZE (8192) ++#else ++#define THREAD_SIZE PAGE_SIZE ++#endif ++ ++#ifndef __ASSEMBLY__ ++ ++#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) ++#define free_user_page(page, addr) free_page(addr) ++ ++#define clear_page(page) memset((page), 0, PAGE_SIZE) ++#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) ++ ++#define clear_user_page(page, vaddr, pg) clear_page(page) ++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) ++ ++/* ++ * These are used to make use of C type-checking.. ++ */ ++typedef struct { unsigned long pte; } pte_t; ++typedef struct { unsigned long pmd[16]; } pmd_t; ++typedef struct { unsigned long pgd; } pgd_t; ++typedef struct { unsigned long pgprot; } pgprot_t; ++ ++#define pte_val(x) ((x).pte) ++#define pmd_val(x) ((&x)->pmd[0]) ++#define pgd_val(x) ((x).pgd) ++#define pgprot_val(x) ((x).pgprot) ++ ++#define __pte(x) ((pte_t) { (x) } ) ++#define __pmd(x) ((pmd_t) { (x) } ) ++#define __pgd(x) ((pgd_t) { (x) } ) ++#define __pgprot(x) ((pgprot_t) { (x) } ) ++ ++/* to align the pointer to the (next) page boundary */ ++#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) ++ ++/* Pure 2^n version of get_order */ ++extern __inline__ int get_order(unsigned long size) ++{ ++ int order; ++ ++ size = (size-1) >> (PAGE_SHIFT-1); ++ order = -1; ++ do { ++ size >>= 1; ++ order++; ++ } while (size); ++ return order; ++} ++ ++extern unsigned long memory_start; ++extern unsigned long memory_end; ++ ++#endif /* !__ASSEMBLY__ */ ++#include ++#define PAGE_OFFSET ((int)(nasys_program_mem)) ++ ++#ifndef __ASSEMBLY__ ++ ++#define __pa(vaddr) virt_to_phys((void *)vaddr) ++#define __va(paddr) phys_to_virt((unsigned long)paddr) ++ ++#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) ++ ++#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) ++#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) ++ ++#define virt_to_page(addr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) ++#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) ++#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) ++ ++#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) ++#define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) ++ ++#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ ++ ((void *)(kaddr) < (void *)memory_end)) ++ ++#ifdef CONFIG_NO_KERNEL_MSG ++#define BUG_PRINT() ++#else ++#define BUG_PRINT() printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__) ++#endif ++ ++#ifdef na_cpu_oci_core ++#define BUG_PANIC() asm volatile ("break") /* drop to debugger */ ++#else ++// #define BUG_PANIC() while(1) ++#define BUG_PANIC() panic("BUG!") ++#endif ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS2_PAGE_H */ +--- linux/include/asm-nios2nommu/param.h ++++ linux/include/asm-nios2nommu/param.h +@@ -0,0 +1,49 @@ ++#ifndef _NIOS_PARAM_H ++#define _NIOS_PARAM_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/param.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifndef HZ ++#define HZ 100 ++#endif ++ ++#ifdef __KERNEL__ ++#define USER_HZ HZ ++#define CLOCKS_PER_SEC (USER_HZ) ++#endif ++ ++#define EXEC_PAGESIZE 4096 ++ ++#ifndef NGROUPS ++#define NGROUPS 32 ++#endif ++ ++#ifndef NOGROUP ++#define NOGROUP (-1) ++#endif ++ ++#define MAXHOSTNAMELEN 64 /* max length of hostname */ ++ ++#endif +--- linux/include/asm-nios2nommu/pci.h ++++ linux/include/asm-nios2nommu/pci.h +@@ -0,0 +1,75 @@ ++#ifndef _ASM_NIOS2NOMMU_PCI_H ++#define _ASM_NIOS2NOMMU_PCI_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/pci.h ++ * ++ * Derived from asm-m68k/pci_m68k.h ++ * - m68k specific PCI declarations, by Wout Klaren. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++struct pci_ops; ++ ++/* ++ * Structure with hardware dependent information and functions of the ++ * PCI bus. ++ */ ++ ++struct pci_bus_info ++{ ++ /* ++ * Resources of the PCI bus. ++ */ ++ ++ struct resource mem_space; ++ struct resource io_space; ++ ++ /* ++ * System dependent functions. ++ */ ++ ++ struct pci_ops *m68k_pci_ops; ++ ++ void (*fixup)(int pci_modify); ++ void (*conf_device)(struct pci_dev *dev); ++}; ++ ++#define pcibios_assign_all_busses() 0 ++ ++extern inline void pcibios_set_master(struct pci_dev *dev) ++{ ++ /* No special bus mastering setup handling */ ++} ++ ++extern inline void pcibios_penalize_isa_irq(int irq) ++{ ++ /* We don't do dynamic PCI IRQ allocation */ ++} ++ ++/* The PCI address space does equal the physical memory ++ * address space. The networking and block device layers use ++ * this boolean for bounce buffer decisions. ++ */ ++#define PCI_DMA_BUS_IS_PHYS (1) ++ ++#endif /* _ASM_NIOS2NOMMU_PCI_H */ +--- linux/include/asm-nios2nommu/percpu.h ++++ linux/include/asm-nios2nommu/percpu.h +@@ -0,0 +1,30 @@ ++#ifndef __ARCH_NIOS2NOMMU_PERCPU__ ++#define __ARCH_NIOS2NOMMU_PERCPU__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/percpu.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* __ARCH_NIOS2NOMMU_PERCPU__ */ +--- linux/include/asm-nios2nommu/pgalloc.h ++++ linux/include/asm-nios2nommu/pgalloc.h +@@ -0,0 +1,32 @@ ++#ifndef _NIOS2NOMMU_PGALLOC_H ++#define _NIOS2NOMMU_PGALLOC_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/pgalloc.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#define check_pgt_cache() do { } while (0) ++ ++#endif /* _NIOS2NOMMU_PGALLOC_H */ +--- linux/include/asm-nios2nommu/pgtable.h ++++ linux/include/asm-nios2nommu/pgtable.h +@@ -0,0 +1,104 @@ ++#ifndef _NIOS_PGTABLE_H ++#define _NIOS_PGTABLE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/pgtable.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++ ++//vic - this bit copied from m68knommu version ++// #include ++#include ++#include ++ ++typedef pte_t *pte_addr_t; ++ ++#define pgd_present(pgd) (1) /* pages are always present on NO_MM */ ++#define pgd_none(pgd) (0) ++#define pgd_bad(pgd) (0) ++#define pgd_clear(pgdp) ++#define kern_addr_valid(addr) (1) ++#define pmd_offset(a, b) ((void *)0) ++ ++#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */ ++//vic - this bit copied from m68knommu version ++ ++extern void paging_init(void); ++#define swapper_pg_dir ((pgd_t *) 0) ++ ++#define __swp_type(x) (0) ++#define __swp_offset(x) (0) ++#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) ++#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) ++#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) ++ ++static inline int pte_file(pte_t pte) { return 0; } ++ ++/* ++ * ZERO_PAGE is a global shared page that is always zero: used ++ * for zero-mapped memory areas etc.. ++ */ ++#define ZERO_PAGE(vaddr) (virt_to_page(0)) ++ ++extern unsigned int kobjsize(const void *objp); ++extern int is_in_rom(unsigned long); ++ ++/* ++ * No page table caches to initialise ++ */ ++#define pgtable_cache_init() do { } while (0) ++#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ ++ remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) ++ ++extern inline void flush_cache_mm(struct mm_struct *mm) ++{ ++} ++ ++extern inline void flush_cache_range(struct mm_struct *mm, ++ unsigned long start, ++ unsigned long end) ++{ ++} ++ ++/* Push the page at kernel virtual address and clear the icache */ ++extern inline void flush_page_to_ram (unsigned long address) ++{ ++} ++ ++/* Push n pages at kernel virtual address and clear the icache */ ++extern inline void flush_pages_to_ram (unsigned long address, int n) ++{ ++} ++ ++/* ++ * All 32bit addresses are effectively valid for vmalloc... ++ * Sort of meaningless for non-VM targets. ++ */ ++#define VMALLOC_START 0 ++#define VMALLOC_END 0xffffffff ++ ++#endif /* _NIOS_PGTABLE_H */ +--- linux/include/asm-nios2nommu/pio_struct.h ++++ linux/include/asm-nios2nommu/pio_struct.h +@@ -0,0 +1,14 @@ ++// PIO Peripheral ++ ++// PIO Registers ++typedef volatile struct ++ { ++ int np_piodata; // read/write, up to 32 bits ++ int np_piodirection; // write/readable, up to 32 bits, 1->output bit ++ int np_piointerruptmask; // write/readable, up to 32 bits, 1->enable interrupt ++ int np_pioedgecapture; // read, up to 32 bits, cleared by any write ++ } np_pio; ++ ++// PIO Routines ++void nr_pio_showhex(int value); // shows low byte on pio named na_seven_seg_pio ++ +--- linux/include/asm-nios2nommu/poll.h ++++ linux/include/asm-nios2nommu/poll.h +@@ -0,0 +1,46 @@ ++#ifndef __NIOS2_POLL_H ++#define __NIOS2_POLL_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/poll.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define POLLIN 1 ++#define POLLPRI 2 ++#define POLLOUT 4 ++#define POLLERR 8 ++#define POLLHUP 16 ++#define POLLNVAL 32 ++#define POLLRDNORM 64 ++#define POLLWRNORM POLLOUT ++#define POLLRDBAND 128 ++#define POLLWRBAND 256 ++#define POLLMSG 0x0400 ++ ++struct pollfd { ++ int fd; ++ short events; ++ short revents; ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/posix_types.h ++++ linux/include/asm-nios2nommu/posix_types.h +@@ -0,0 +1,89 @@ ++#ifndef __ARCH_NIOS2_POSIX_TYPES_H ++#define __ARCH_NIOS2_POSIX_TYPES_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/posix_types.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This file is generally used by user-level software, so you need to ++ * be a little careful about namespace pollution etc. Also, we cannot ++ * assume GCC is being used. ++ */ ++ ++typedef unsigned long __kernel_ino_t; ++typedef unsigned short __kernel_mode_t; ++typedef unsigned short __kernel_nlink_t; ++typedef long __kernel_off_t; ++typedef int __kernel_pid_t; ++typedef unsigned short __kernel_ipc_pid_t; ++typedef unsigned short __kernel_uid_t; ++typedef unsigned short __kernel_gid_t; ++typedef unsigned int __kernel_size_t; ++typedef int __kernel_ssize_t; ++typedef int __kernel_ptrdiff_t; ++typedef long __kernel_time_t; ++typedef long __kernel_suseconds_t; ++typedef long __kernel_clock_t; ++typedef int __kernel_timer_t; ++typedef int __kernel_clockid_t; ++typedef int __kernel_daddr_t; ++typedef char * __kernel_caddr_t; ++typedef unsigned short __kernel_uid16_t; ++typedef unsigned short __kernel_gid16_t; ++typedef unsigned int __kernel_uid32_t; ++typedef unsigned int __kernel_gid32_t; ++ ++typedef unsigned short __kernel_old_uid_t; ++typedef unsigned short __kernel_old_gid_t; ++typedef unsigned short __kernel_old_dev_t; ++ ++#ifdef __GNUC__ ++typedef long long __kernel_loff_t; ++#endif ++ ++typedef struct { ++#if defined(__KERNEL__) || defined(__USE_ALL) ++ int val[2]; ++#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ ++ int __val[2]; ++#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ ++} __kernel_fsid_t; ++ ++#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) ++ ++#undef __FD_SET ++#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) ++ ++#undef __FD_CLR ++#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) ++ ++#undef __FD_ISSET ++#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) ++ ++#undef __FD_ZERO ++#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) ++ ++#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ ++ ++#endif +--- linux/include/asm-nios2nommu/preem_latency.h ++++ linux/include/asm-nios2nommu/preem_latency.h +@@ -0,0 +1,39 @@ ++#ifndef _ASM_PREEM_LATENCY_H ++#define _ASM_PREEM_LATENCY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/preem_latency.h ++ * ++ * timing support for preempt-stats patch ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#define readclock(low) \ ++do {\ ++ *(volatile unsigned long *)na_Counter_64_bit=1; \ ++ low=*(volatile unsigned long *)na_Counter_64_bit; \ ++} while (0) ++#define readclock_init() ++ ++#endif /* _ASM_PREEM_LATENCY_H */ +--- linux/include/asm-nios2nommu/processor.h ++++ linux/include/asm-nios2nommu/processor.h +@@ -0,0 +1,148 @@ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/processor.h ++ * ++ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) ++ * Copyright (C) 2001 Ken Hill (khill@microtronix.com) ++ * Vic Phillips (vic@microtronix.com) ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * hacked from: ++ * include/asm-sparc/processor.h ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * Nov/02/2003 dgt Fix task_size ++ * ++ ---------------------------------------------------------------------*/ ++ ++#ifndef __ASM_NIOS_PROCESSOR_H ++#define __ASM_NIOS_PROCESSOR_H ++ ++#define NIOS2_FLAG_KTHREAD 0x00000001 /* task is a kernel thread */ ++#define NIOS2_FLAG_COPROC 0x00000002 /* Thread used coprocess */ ++#define NIOS2_FLAG_DEBUG 0x00000004 /* task is being debugged */ ++ ++#define NIOS2_OP_NOP 0x1883a ++#define NIOS2_OP_BREAK 0x3da03a ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * Default implementation of macro that returns current ++ * instruction pointer ("program counter"). ++ */ ++#define current_text_addr() ({ __label__ _l; _l: &&_l;}) ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include /* for get_hi_limit */ ++ ++/* ++ * Bus types ++ */ ++#define EISA_bus 0 ++#define EISA_bus__is_a_macro /* for versions in ksyms.c */ ++#define MCA_bus 0 ++#define MCA_bus__is_a_macro /* for versions in ksyms.c */ ++ ++/* ++ * The nios has no problems with write protection ++ */ ++#define wp_works_ok 1 ++#define wp_works_ok__is_a_macro /* for versions in ksyms.c */ ++ ++/* Whee, this is STACK_TOP and the lowest kernel address too... */ ++#if 0 ++#define KERNBASE 0x00000000 /* First address the kernel will eventually be */ ++#define TASK_SIZE (KERNBASE) ++#define MAX_USER_ADDR TASK_SIZE ++#define MMAP_SEARCH_START (TASK_SIZE/3) ++#endif ++ ++#define TASK_SIZE ((unsigned int) nasys_program_mem_end) //...this is better... ++ ++/* ++ * This decides where the kernel will search for a free chunk of vm ++ * space during mmap's. We won't be using it ++ */ ++#define TASK_UNMAPPED_BASE 0 ++ ++/* The Nios processor specific thread struct. */ ++struct thread_struct { ++ struct pt_regs *kregs; ++ ++ /* For signal handling */ ++ unsigned long sig_address; ++ unsigned long sig_desc; ++ ++ /* Context switch saved kernel state. */ ++ unsigned long ksp; ++ unsigned long kpsr; ++ unsigned long kesr; ++ ++ /* Flags are defined below */ ++ ++ unsigned long flags; ++ int current_ds; ++ struct exec core_exec; /* just what it says. */ ++}; ++ ++#define INIT_MMAP { &init_mm, (0), (0), \ ++ __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC } ++ ++#define INIT_THREAD { \ ++ .kregs = 0, \ ++ .sig_address = 0, \ ++ .sig_desc = 0, \ ++ .ksp = 0, \ ++ .kpsr = 0, \ ++ .kesr = PS_S, \ ++ .flags = NIOS2_FLAG_KTHREAD, \ ++ .current_ds = __KERNEL_DS, \ ++ .core_exec = INIT_EXEC \ ++} ++ ++/* Free all resources held by a thread. */ ++extern void release_thread(struct task_struct *); ++ ++extern unsigned long thread_saved_pc(struct task_struct *t); ++ ++extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); ++ ++/* Prepare to copy thread state - unlazy all lazy status */ ++#define prepare_to_copy(tsk) do { } while (0) ++ ++extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); ++ ++unsigned long get_wchan(struct task_struct *p); ++ ++#define KSTK_EIP(tsk) ((tsk)->thread.kregs->ea) ++#define KSTK_ESP(tsk) ((tsk)->thread.kregs->sp) ++ ++#ifdef __KERNEL__ ++/* Allocation and freeing of basic task resources. */ ++ ++//;dgt2;#define alloc_task_struct() ((struct task_struct *) xx..see..linux..fork..xx __get_free_pages(GFP_KERNEL,1)) ++//;dgt2;#define get_task_struct(tsk) xx..see..linux..sched.h...atomic_inc(&mem_map[MAP_NR(tsk)].count) ++ ++#endif ++ ++#define cpu_relax() do { } while (0) ++#endif /* __ASSEMBLY__ */ ++#endif /* __ASM_NIOS_PROCESSOR_H */ +--- linux/include/asm-nios2nommu/ptrace.h ++++ linux/include/asm-nios2nommu/ptrace.h +@@ -0,0 +1,141 @@ ++/* ++ * Taken from the m68k port. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2NOMMU_PTRACE_H ++#define _NIOS2NOMMU_PTRACE_H ++ ++#ifndef __ASSEMBLY__ ++ ++#define PTR_R0 0 ++#define PTR_R1 1 ++#define PTR_R2 2 ++#define PTR_R3 3 ++#define PTR_R4 4 ++#define PTR_R5 5 ++#define PTR_R6 6 ++#define PTR_R7 7 ++#define PTR_R8 8 ++#define PTR_R9 9 ++#define PTR_R10 10 ++#define PTR_R11 11 ++#define PTR_R12 12 ++#define PTR_R13 13 ++#define PTR_R14 14 ++#define PTR_R15 15 ++#define PTR_R16 16 ++#define PTR_R17 17 ++#define PTR_R18 18 ++#define PTR_R19 19 ++#define PTR_R20 20 ++#define PTR_R21 21 ++#define PTR_R22 22 ++#define PTR_R23 23 ++#define PTR_R24 24 ++#define PTR_R25 25 ++#define PTR_GP 26 ++#define PTR_SP 27 ++#define PTR_FP 28 ++#define PTR_EA 29 ++#define PTR_BA 30 ++#define PTR_RA 31 ++#define PTR_STATUS 32 ++#define PTR_ESTATUS 33 ++#define PTR_BSTATUS 34 ++#define PTR_IENABLE 35 ++#define PTR_IPENDING 36 ++ ++/* this struct defines the way the registers are stored on the ++ stack during a system call. ++ ++ There is a fake_regs in setup.c that has to match pt_regs.*/ ++ ++struct pt_regs { ++ unsigned long r8; ++ unsigned long r9; ++ unsigned long r10; ++ unsigned long r11; ++ unsigned long r12; ++ unsigned long r13; ++ unsigned long r14; ++ unsigned long r15; ++ unsigned long r1; ++ unsigned long r2; ++ unsigned long r3; ++ unsigned long r4; ++ unsigned long r5; ++ unsigned long r6; ++ unsigned long r7; ++ unsigned long orig_r2; ++ unsigned long ra; ++ unsigned long fp; ++ unsigned long sp; ++ unsigned long gp; ++ unsigned long estatus; ++ unsigned long status_extension; ++ unsigned long ea; ++}; ++ ++ ++/* ++ * This is the extended stack used by signal handlers and the context ++ * switcher: it's pushed after the normal "struct pt_regs". ++ */ ++struct switch_stack { ++ unsigned long r16; ++ unsigned long r17; ++ unsigned long r18; ++ unsigned long r19; ++ unsigned long r20; ++ unsigned long r21; ++ unsigned long r22; ++ unsigned long r23; ++ unsigned long fp; ++ unsigned long gp; ++ unsigned long ra; ++}; ++ ++/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ ++#define PTRACE_GETREGS 12 ++#define PTRACE_SETREGS 13 ++#ifdef CONFIG_FPU ++#define PTRACE_GETFPREGS 14 ++#define PTRACE_SETFPREGS 15 ++#endif ++ ++#ifdef __KERNEL__ ++ ++#ifndef PS_S ++#define PS_S (0x00000001) ++#endif ++#ifndef PS_T ++#define PS_T (0x00000002) ++#endif ++ ++#define user_mode(regs) (!((regs)->status_extension & PS_S)) ++#define instruction_pointer(regs) ((regs)->ra) ++#define profile_pc(regs) instruction_pointer(regs) ++extern void show_regs(struct pt_regs *); ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASSEMBLY__ */ ++#endif /* _NIOS2NOMMU_PTRACE_H */ +--- linux/include/asm-nios2nommu/resource.h ++++ linux/include/asm-nios2nommu/resource.h +@@ -0,0 +1,73 @@ ++#ifndef _NIOS2NOMMU_RESOURCE_H ++#define _NIOS2NOMMU_RESOURCE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * Resource limits ++ * ++ * include/asm-nios2nommu/resource.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define RLIMIT_CPU 0 /* CPU time in ms */ ++#define RLIMIT_FSIZE 1 /* Maximum filesize */ ++#define RLIMIT_DATA 2 /* max data size */ ++#define RLIMIT_STACK 3 /* max stack size */ ++#define RLIMIT_CORE 4 /* max core file size */ ++#define RLIMIT_RSS 5 /* max resident set size */ ++#define RLIMIT_NPROC 6 /* max number of processes */ ++#define RLIMIT_NOFILE 7 /* max number of open files */ ++#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ ++#define RLIMIT_AS 9 /* address space limit */ ++#define RLIMIT_LOCKS 10 /* maximum file locks held */ ++#define RLIMIT_SIGPENDING 11 /* max number of pending signals */ ++#define RLIMIT_MSGQUEUE 12 /* maximum bytes in POSIX mqueues */ ++ ++#define RLIM_NLIMITS 13 ++ ++/* ++ * SuS says limits have to be unsigned. ++ * Which makes a ton more sense anyway. ++ */ ++#define RLIM_INFINITY (~0UL) ++ ++#ifdef __KERNEL__ ++ ++#define INIT_RLIMITS \ ++{ \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { _STK_LIM, RLIM_INFINITY }, \ ++ { 0, RLIM_INFINITY }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { 0, 0 }, \ ++ { INR_OPEN, INR_OPEN }, \ ++ { MLOCK_LIMIT, MLOCK_LIMIT }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { MAX_SIGPENDING, MAX_SIGPENDING }, \ ++ { MQ_BYTES_MAX, MQ_BYTES_MAX }, \ ++} ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS2NOMMU_RESOURCE_H */ +--- linux/include/asm-nios2nommu/rmap.h ++++ linux/include/asm-nios2nommu/rmap.h +@@ -0,0 +1,2 @@ ++/* Do not need anything here */ ++ +--- linux/include/asm-nios2nommu/scatterlist.h ++++ linux/include/asm-nios2nommu/scatterlist.h +@@ -0,0 +1,42 @@ ++#ifndef _NIOS2NOMMU_SCATTERLIST_H ++#define _NIOS2NOMMU_SCATTERLIST_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/scatterlist.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++ ++struct scatterlist { ++ struct page *page; ++ unsigned int offset; ++ dma_addr_t dma_address; ++ unsigned int length; ++}; ++ ++#define sg_address(sg) (page_address((sg)->page) + (sg)->offset ++#define sg_dma_address(sg) ((sg)->dma_address) ++#define sg_dma_len(sg) ((sg)->length) ++ ++#define ISA_DMA_THRESHOLD (0xffffffff) ++ ++#endif /* !(_NIOS2NOMMU_SCATTERLIST_H) */ +--- linux/include/asm-nios2nommu/sections.h ++++ linux/include/asm-nios2nommu/sections.h +@@ -0,0 +1,30 @@ ++#ifndef _NIOS2NOMMU_SECTIONS_H ++#define _NIOS2NOMMU_SECTIONS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sections.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _NIOS2NOMMU_SECTIONS_H */ +--- linux/include/asm-nios2nommu/segment.h ++++ linux/include/asm-nios2nommu/segment.h +@@ -0,0 +1,75 @@ ++#ifndef _NIOS2NOMMU_SEGMENT_H ++#define _NIOS2NOMMU_SEGMENT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/segment.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* define constants */ ++/* Address spaces (FC0-FC2) */ ++#define USER_DATA (1) ++#ifndef __USER_DS ++#define __USER_DS (USER_DATA) ++#endif ++#define USER_PROGRAM (2) ++#define SUPER_DATA (5) ++#ifndef __KERNEL_DS ++#define __KERNEL_DS (SUPER_DATA) ++#endif ++#define SUPER_PROGRAM (6) ++#define CPU_SPACE (7) ++ ++#ifndef __ASSEMBLY__ ++ ++typedef struct { ++ unsigned long seg; ++} mm_segment_t; ++ ++#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) ++#define USER_DS MAKE_MM_SEG(__USER_DS) ++#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS) ++ ++/* ++ * Get/set the SFC/DFC registers for MOVES instructions ++ */ ++ ++static inline mm_segment_t get_fs(void) ++{ ++ return USER_DS; ++} ++ ++static inline mm_segment_t get_ds(void) ++{ ++ /* return the supervisor data space code */ ++ return KERNEL_DS; ++} ++ ++static inline void set_fs(mm_segment_t val) ++{ ++} ++ ++#define segment_eq(a,b) ((a).seg == (b).seg) ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* _NIOS2NOMMU_SEGMENT_H */ +--- linux/include/asm-nios2nommu/semaphore.h ++++ linux/include/asm-nios2nommu/semaphore.h +@@ -0,0 +1,155 @@ ++#ifndef _NIOS2NOMMU_SEMAPHORE_H ++#define _NIOS2NOMMU_SEMAPHORE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/semaphore.h ++ * ++ * Interrupt-safe semaphores.. ++ * ++ * Derived from M68knommu ++ * ++ * (C) Copyright 1996 Linus Torvalds ++ * m68k version by Andreas Schwab ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#define RW_LOCK_BIAS 0x01000000 ++ ++#ifndef __ASSEMBLY__ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct semaphore { ++ atomic_t count; ++ atomic_t waking; ++ wait_queue_head_t wait; ++}; ++ ++#define __SEMAPHORE_INITIALIZER(name, n) \ ++{ \ ++ .count = ATOMIC_INIT(n), \ ++ .waking = ATOMIC_INIT(0), \ ++ .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ ++} ++ ++#define __MUTEX_INITIALIZER(name) \ ++ __SEMAPHORE_INITIALIZER(name,1) ++ ++#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) ++ ++#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) ++#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) ++ ++extern inline void sema_init (struct semaphore *sem, int val) ++{ ++ *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); ++} ++ ++static inline void init_MUTEX (struct semaphore *sem) ++{ ++ sema_init(sem, 1); ++} ++ ++static inline void init_MUTEX_LOCKED (struct semaphore *sem) ++{ ++ sema_init(sem, 0); ++} ++ ++asmlinkage void __down(struct semaphore * sem); ++asmlinkage int __down_interruptible(struct semaphore * sem); ++asmlinkage int __down_trylock(struct semaphore * sem); ++asmlinkage void __up(struct semaphore * sem); ++ ++asmlinkage void __down_failed(void /* special register calling convention */); ++asmlinkage int __down_failed_interruptible(void /* params in registers */); ++asmlinkage int __down_failed_trylock(void /* params in registers */); ++asmlinkage void __up_wakeup(void /* special register calling convention */); ++ ++extern spinlock_t semaphore_wake_lock; ++ ++/* ++ * This is ugly, but we want the default case to fall through. ++ * "down_failed" is a special asm handler that calls the C ++ * routine that actually waits. ++ */ ++extern inline void down(struct semaphore * sem) ++{ ++ might_sleep(); ++ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ if (atomic_dec_return(&sem->count) < 0) ++ __down(sem); ++ #endif ++} ++ ++extern inline int down_interruptible(struct semaphore * sem) ++{ ++ int ret = 0; ++ ++ ++ might_sleep(); ++ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ if(atomic_dec_return(&sem->count) < 0) ++ ret = __down_interruptible(sem); ++ return ret; ++ #endif ++} ++ ++extern inline int down_trylock(struct semaphore * sem) ++{ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ int ret = 0; ++ ++ if (atomic_dec_return (&sem->count) < 0) ++ ret = __down_trylock(sem); ++ return ret; ++ #endif ++} ++ ++/* ++ * Note! This is subtle. We jump to wake people up only if ++ * the semaphore was negative (== somebody was waiting on it). ++ * The default case (no contention) will result in NO ++ * jumps for both down() and up(). ++ */ ++extern inline void up(struct semaphore * sem) ++{ ++ #if 0 ++ ...Nios2 has no atomic "increment memory".... ++ #else ++ if (atomic_inc_return(&sem->count) <= 0) ++ __up(sem); ++ #endif ++} ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif +--- linux/include/asm-nios2nommu/semaphore-helper.h ++++ linux/include/asm-nios2nommu/semaphore-helper.h +@@ -0,0 +1,101 @@ ++#ifndef _NIOS2NOMMU_SEMAPHORE_HELPER_H ++#define _NIOS2NOMMU_SEMAPHORE_HELPER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/semaphore.h ++ * ++ * SMP- and interrupt-safe semaphores helper functions. ++ * ++ * Derived from M68knommu ++ * ++ * (C) Copyright 1996 Linus Torvalds ++ * m68k version by Andreas Schwab ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++// #include ++ ++/* ++ * These two _must_ execute atomically wrt each other. ++ */ ++static inline void wake_one_more(struct semaphore * sem) ++{ ++ atomic_inc(&sem->waking); ++} ++ ++static inline int waking_non_zero(struct semaphore *sem) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 0; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 1; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++/* ++ * waking_non_zero_interruptible: ++ * 1 got the lock ++ * 0 go to sleep ++ * -EINTR interrupted ++ */ ++static inline int waking_non_zero_interruptible(struct semaphore *sem, ++ struct task_struct *tsk) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 0; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 1; ++ } else if (signal_pending(tsk)) { ++ atomic_inc(&sem->count); ++ ret = -EINTR; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++/* ++ * waking_non_zero_trylock: ++ * 1 failed to lock ++ * 0 got the lock ++ */ ++static inline int waking_non_zero_trylock(struct semaphore *sem) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 1; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 0; ++ } else ++ atomic_inc(&sem->count); ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++#endif +--- linux/include/asm-nios2nommu/sembuf.h ++++ linux/include/asm-nios2nommu/sembuf.h +@@ -0,0 +1,48 @@ ++#ifndef _NIOS_SEMBUF_H ++#define _NIOS_SEMBUF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sembuf.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct semid64_ds { ++ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ ++ __kernel_time_t sem_otime; /* last semop time */ ++ unsigned long __unused1; ++ __kernel_time_t sem_ctime; /* last change time */ ++ unsigned long __unused2; ++ unsigned long sem_nsems; /* no. of semaphores in array */ ++ unsigned long __unused3; ++ unsigned long __unused4; ++}; ++ ++#endif /* _NIOS_SEMBUF_H */ +--- linux/include/asm-nios2nommu/setup.h ++++ linux/include/asm-nios2nommu/setup.h +@@ -0,0 +1,31 @@ ++/* Copied from i386 port. ++ * Just a place holder. We don't want to have to test x86 before ++ * we include stuff ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_SETUP_H ++#define _NIOS2_SETUP_H ++ ++#define COMMAND_LINE_SIZE 512 ++ ++#endif /* _NIOS2_SETUP_H */ +--- linux/include/asm-nios2nommu/shmbuf.h ++++ linux/include/asm-nios2nommu/shmbuf.h +@@ -0,0 +1,64 @@ ++#ifndef _NIOS_SHMBUF_H ++#define _NIOS_SHMBUF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/shmbuf.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct shmid64_ds { ++ struct ipc64_perm shm_perm; /* operation perms */ ++ size_t shm_segsz; /* size of segment (bytes) */ ++ __kernel_time_t shm_atime; /* last attach time */ ++ unsigned long __unused1; ++ __kernel_time_t shm_dtime; /* last detach time */ ++ unsigned long __unused2; ++ __kernel_time_t shm_ctime; /* last change time */ ++ unsigned long __unused3; ++ __kernel_pid_t shm_cpid; /* pid of creator */ ++ __kernel_pid_t shm_lpid; /* pid of last operator */ ++ unsigned long shm_nattch; /* no. of current attaches */ ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++struct shminfo64 { ++ unsigned long shmmax; ++ unsigned long shmmin; ++ unsigned long shmmni; ++ unsigned long shmseg; ++ unsigned long shmall; ++ unsigned long __unused1; ++ unsigned long __unused2; ++ unsigned long __unused3; ++ unsigned long __unused4; ++}; ++ ++#endif /* _NIOS_SHMBUF_H */ +--- linux/include/asm-nios2nommu/shmparam.h ++++ linux/include/asm-nios2nommu/shmparam.h +@@ -0,0 +1,30 @@ ++#ifndef __NIOS2NOMMU_SHMPARAM_H__ ++#define __NIOS2NOMMU_SHMPARAM_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/shmparam.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ ++ ++#endif /* __NIOS2NOMMU_SHMPARAM_H__ */ +--- linux/include/asm-nios2nommu/sigcontext.h ++++ linux/include/asm-nios2nommu/sigcontext.h +@@ -0,0 +1,35 @@ ++/* ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2NOMMU_SIGCONTEXT_H ++#define _ASM_NIOS2NOMMU_SIGCONTEXT_H ++ ++#include ++ ++struct sigcontext { ++ struct pt_regs regs; ++ unsigned long sc_mask; /* old sigmask */ ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/siginfo.h ++++ linux/include/asm-nios2nommu/siginfo.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_SIGINFO_H ++#define _NIOS2NOMMU_SIGINFO_H ++ ++#include ++ ++#endif +--- linux/include/asm-nios2nommu/signal.h ++++ linux/include/asm-nios2nommu/signal.h +@@ -0,0 +1,207 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_SIGNAL_H ++#define _NIOS2_SIGNAL_H ++ ++#include ++ ++/* Avoid too many header ordering problems. */ ++struct siginfo; ++ ++#ifdef __KERNEL__ ++/* Most things should be clean enough to redefine this at will, if care ++ is taken to make libc match. */ ++ ++#define _NSIG 64 ++#define _NSIG_BPW 32 ++#define _NSIG_WORDS (_NSIG / _NSIG_BPW) ++ ++typedef unsigned long old_sigset_t; /* at least 32 bits */ ++ ++typedef struct { ++ unsigned long sig[_NSIG_WORDS]; ++} sigset_t; ++ ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++#define NSIG 32 ++typedef unsigned long sigset_t; ++ ++#endif /* __KERNEL__ */ ++ ++#define SIGHUP 1 ++#define SIGINT 2 ++#define SIGQUIT 3 ++#define SIGILL 4 ++#define SIGTRAP 5 ++#define SIGABRT 6 ++#define SIGIOT 6 ++#define SIGBUS 7 ++#define SIGFPE 8 ++#define SIGKILL 9 ++#define SIGUSR1 10 ++#define SIGSEGV 11 ++#define SIGUSR2 12 ++#define SIGPIPE 13 ++#define SIGALRM 14 ++#define SIGTERM 15 ++#define SIGSTKFLT 16 ++#define SIGCHLD 17 ++#define SIGCONT 18 ++#define SIGSTOP 19 ++#define SIGTSTP 20 ++#define SIGTTIN 21 ++#define SIGTTOU 22 ++#define SIGURG 23 ++#define SIGXCPU 24 ++#define SIGXFSZ 25 ++#define SIGVTALRM 26 ++#define SIGPROF 27 ++#define SIGWINCH 28 ++#define SIGIO 29 ++#define SIGPOLL SIGIO ++/* ++#define SIGLOST 29 ++*/ ++#define SIGPWR 30 ++#define SIGSYS 31 ++#define SIGUNUSED 31 ++ ++/* These should not be considered constants from userland. */ ++#define SIGRTMIN 32 ++#define SIGRTMAX _NSIG-1 ++ ++/* ++ * SA_FLAGS values: ++ * ++ * SA_ONSTACK indicates that a registered stack_t will be used. ++ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the ++ * SA_RESTART flag to get restarting signals (which were the default long ago) ++ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. ++ * SA_RESETHAND clears the handler when the signal is delivered. ++ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. ++ * SA_NODEFER prevents the current signal from being masked in the handler. ++ * ++ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single ++ * Unix names RESETHAND and NODEFER respectively. ++ */ ++#define SA_NOCLDSTOP 0x00000001 ++#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ ++#define SA_SIGINFO 0x00000004 ++#define SA_ONSTACK 0x08000000 ++#define SA_RESTART 0x10000000 ++#define SA_NODEFER 0x40000000 ++#define SA_RESETHAND 0x80000000 ++ ++#define SA_NOMASK SA_NODEFER ++#define SA_ONESHOT SA_RESETHAND ++#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ ++ ++#define SA_RESTORER 0x04000000 ++ ++/* ++ * sigaltstack controls ++ */ ++#define SS_ONSTACK 1 ++#define SS_DISABLE 2 ++ ++#define MINSIGSTKSZ 2048 ++#define SIGSTKSZ 8192 ++ ++#ifdef __KERNEL__ ++/* ++ * These values of sa_flags are used only by the kernel as part of the ++ * irq handling routines. ++ * ++ * SA_INTERRUPT is also used by the irq handling routines. ++ * SA_SHIRQ is for shared interrupt support on PCI and EISA. ++ */ ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#endif ++ ++#define SIG_BLOCK 0 /* for blocking signals */ ++#define SIG_UNBLOCK 1 /* for unblocking signals */ ++#define SIG_SETMASK 2 /* for setting the signal mask */ ++ ++/* Type of a signal handler. */ ++typedef void (*__sighandler_t)(int); ++ ++#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ ++#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ ++#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ ++ ++#ifdef __KERNEL__ ++struct old_sigaction { ++ __sighandler_t sa_handler; ++ old_sigset_t sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++}; ++ ++struct sigaction { ++ __sighandler_t sa_handler; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++ sigset_t sa_mask; /* mask last for extensibility */ ++}; ++ ++struct k_sigaction { ++ struct sigaction sa; ++}; ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++struct sigaction { ++ union { ++ __sighandler_t _sa_handler; ++ void (*_sa_sigaction)(int, struct siginfo *, void *); ++ } _u; ++ sigset_t sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++}; ++ ++#define sa_handler _u._sa_handler ++#define sa_sigaction _u._sa_sigaction ++ ++#endif /* __KERNEL__ */ ++ ++typedef struct sigaltstack { ++ void *ss_sp; ++ int ss_flags; ++ size_t ss_size; ++} stack_t; ++ ++#ifdef __KERNEL__ ++ ++#include ++#undef __HAVE_ARCH_SIG_BITOPS ++ ++#define ptrace_signal_deliver(regs, cookie) do { } while (0) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS2_SIGNAL_H */ +--- linux/include/asm-nios2nommu/smp.h ++++ linux/include/asm-nios2nommu/smp.h +@@ -0,0 +1,34 @@ ++#ifndef __ASM_SMP_H ++#define __ASM_SMP_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/smp.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++// #include ++ ++#ifdef CONFIG_SMP ++#error SMP not supported ++#endif ++ ++#endif +--- linux/include/asm-nios2nommu/socket.h ++++ linux/include/asm-nios2nommu/socket.h +@@ -0,0 +1,74 @@ ++#ifndef _ASM_SOCKET_H ++#define _ASM_SOCKET_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/socket.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* For setsockopt(2) */ ++#define SOL_SOCKET 1 ++ ++#define SO_DEBUG 1 ++#define SO_REUSEADDR 2 ++#define SO_TYPE 3 ++#define SO_ERROR 4 ++#define SO_DONTROUTE 5 ++#define SO_BROADCAST 6 ++#define SO_SNDBUF 7 ++#define SO_RCVBUF 8 ++#define SO_KEEPALIVE 9 ++#define SO_OOBINLINE 10 ++#define SO_NO_CHECK 11 ++#define SO_PRIORITY 12 ++#define SO_LINGER 13 ++#define SO_BSDCOMPAT 14 ++/* To add :#define SO_REUSEPORT 15 */ ++#define SO_PASSCRED 16 ++#define SO_PEERCRED 17 ++#define SO_RCVLOWAT 18 ++#define SO_SNDLOWAT 19 ++#define SO_RCVTIMEO 20 ++#define SO_SNDTIMEO 21 ++ ++/* Security levels - as per NRL IPv6 - don't actually do anything */ ++#define SO_SECURITY_AUTHENTICATION 22 ++#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 ++#define SO_SECURITY_ENCRYPTION_NETWORK 24 ++ ++#define SO_BINDTODEVICE 25 ++ ++/* Socket filtering */ ++#define SO_ATTACH_FILTER 26 ++#define SO_DETACH_FILTER 27 ++ ++#define SO_PEERNAME 28 ++#define SO_TIMESTAMP 29 ++#define SCM_TIMESTAMP SO_TIMESTAMP ++ ++#define SO_ACCEPTCONN 30 ++ ++#define SO_PEERSEC 31 /* ;dgt2;tmp; */ ++ ++#endif /* _ASM_SOCKET_H */ +--- linux/include/asm-nios2nommu/sockios.h ++++ linux/include/asm-nios2nommu/sockios.h +@@ -0,0 +1,38 @@ ++#ifndef _ASM_NIOS_SOCKIOS_H ++#define _ASM_NIOS_SOCKIOS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sockios.h ++ * ++ * Socket-level I/O control calls. ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define FIOSETOWN 0x8901 ++#define SIOCSPGRP 0x8902 ++#define FIOGETOWN 0x8903 ++#define SIOCGPGRP 0x8904 ++#define SIOCATMARK 0x8905 ++#define SIOCGSTAMP 0x8906 /* Get stamp */ ++ ++#endif /* !(_ASM_NIOS_SOCKIOS_H) */ ++ +--- linux/include/asm-nios2nommu/spi.h ++++ linux/include/asm-nios2nommu/spi.h +@@ -0,0 +1,92 @@ ++#ifndef _ASM_SPI_H_ ++#define _ASM_SPI_H_ 1 ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/spi.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++int register_NIOS_SPI( void ); ++void unregister_NIOS_SPI( void ); ++ ++#if defined(MODULE) ++void cleanup_module( void ); ++int init_module( void ); ++#endif ++ ++#if defined(__KERNEL__) ++int spi_reset ( void ); ++#endif ++ ++ ++#define clockCS 0x01 ++#define temperatureCS 0x02 ++ ++#define clock_read_base 0x00 ++#define clock_write_base 0x80 ++#define clock_read_control 0x0F ++#define clock_read_trickle 0x11 ++ ++#define clock_read_sec 0x00 ++#define clock_read_min 0x01 ++#define clock_read_hour 0x02 ++#define clock_read_day 0x03 ++#define clock_read_date 0x04 ++#define clock_read_month 0x05 ++#define clock_read_year 0x06 ++ ++#define clock_write_control 0x8F ++#define clock_write_trickle 0x91 ++#define clock_write_sec 0x80 ++#define clock_write_min 0x81 ++#define clock_write_hour 0x82 ++#define clock_write_day 0x83 ++#define clock_write_date 0x84 ++#define clock_write_month 0x85 ++#define clock_write_year 0x86 ++ ++#define clock_write_ram_start 0xA0 ++#define clock_write_ram_end 0x100 ++#define clock_read_ram_start 0x20 ++#define clock_read_ram_end 0x80 ++ ++ ++#define clock_sec_def 0x11 ++#define clock_min_def 0x59 ++#define clock_hour_def 0x71 ++#define clock_day_def 0x00 ++#define clock_date_def 0x20 ++#define clock_month_def 0x12 ++#define clock_year_def 0x34 ++ ++#define temp_read_base 0x00 ++#define temp_write_base 0x80 ++#define temp_read_control 0x00 ++#define temp_write_control 0x80 ++#define temp_read_msb 0x02 ++#define temp_read_lsb 0x01 ++ ++#define MAX_TEMP_VAR 10 ++ ++#endif /*_ASM_SPI_H_*/ +--- linux/include/asm-nios2nommu/spinlock.h ++++ linux/include/asm-nios2nommu/spinlock.h +@@ -0,0 +1,30 @@ ++#ifndef __NIOS_SPINLOCK_H ++#define __NIOS_SPINLOCK_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/spinlock.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#error "Nios doesn't do SMP yet" ++ ++#endif +--- linux/include/asm-nios2nommu/spi_struct.h ++++ linux/include/asm-nios2nommu/spi_struct.h +@@ -0,0 +1,57 @@ ++// SPI Registers ++typedef volatile struct ++ { ++ int np_spirxdata; // Read-only, 1-16 bit ++ int np_spitxdata; // Write-only, same width as rxdata ++ int np_spistatus; // Read-only, 9-bit ++ int np_spicontrol; // Read/Write, 9-bit ++ int np_spireserved; // reserved ++ int np_spislaveselect; // Read/Write, 1-16 bit, master only ++ int np_spiendofpacket; // Read/write, same width as txdata, rxdata. ++ } np_spi; ++ ++// SPI Status Register Bits ++enum ++ { ++ np_spistatus_eop_bit = 9, ++ np_spistatus_e_bit = 8, ++ np_spistatus_rrdy_bit = 7, ++ np_spistatus_trdy_bit = 6, ++ np_spistatus_tmt_bit = 5, ++ np_spistatus_toe_bit = 4, ++ np_spistatus_roe_bit = 3, ++ ++ np_spistatus_eop_mask = (1 << 9), ++ np_spistatus_e_mask = (1 << 8), ++ np_spistatus_rrdy_mask = (1 << 7), ++ np_spistatus_trdy_mask = (1 << 6), ++ np_spistatus_tmt_mask = (1 << 5), ++ np_spistatus_toe_mask = (1 << 4), ++ np_spistatus_roe_mask = (1 << 3), ++ }; ++ ++// SPI Control Register Bits ++enum ++ { ++ np_spicontrol_sso_bit = 10, ++ np_spicontrol_ieop_bit = 9, ++ np_spicontrol_ie_bit = 8, ++ np_spicontrol_irrdy_bit = 7, ++ np_spicontrol_itrdy_bit = 6, ++ np_spicontrol_itoe_bit = 4, ++ np_spicontrol_iroe_bit = 3, ++ ++ np_spicontrol_sso_mask = (1 << 10), ++ np_spicontrol_ieop_mask = (1 << 9), ++ np_spicontrol_ie_mask = (1 << 8), ++ np_spicontrol_irrdy_mask = (1 << 7), ++ np_spicontrol_itrdy_mask = (1 << 6), ++ np_spicontrol_itoe_mask = (1 << 4), ++ np_spicontrol_iroe_mask = (1 << 3), ++ }; ++ ++// SPI Routines. ++int nr_spi_rxchar(np_spi *spiBase); ++int nr_spi_txchar(int i, np_spi *spiBase); ++ ++ +--- linux/include/asm-nios2nommu/statfs.h ++++ linux/include/asm-nios2nommu/statfs.h +@@ -0,0 +1,30 @@ ++#ifndef _NIOS2NOMMU_STATFS_H ++#define _NIOS2NOMMU_STATFS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/statfs.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _NIOS2NOMMU_STATFS_H */ +--- linux/include/asm-nios2nommu/stat.h ++++ linux/include/asm-nios2nommu/stat.h +@@ -0,0 +1,102 @@ ++#ifndef _ASMNIOS2NOMMU_STAT_H ++#define _ASMNIOS2NOMMU_STAT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/stat.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++struct __old_kernel_stat { ++ unsigned short st_dev; ++ unsigned short st_ino; ++ unsigned short st_mode; ++ unsigned short st_nlink; ++ unsigned short st_uid; ++ unsigned short st_gid; ++ unsigned short st_rdev; ++ unsigned long st_size; ++ unsigned long st_atime; ++ unsigned long st_mtime; ++ unsigned long st_ctime; ++}; ++ ++struct stat { ++ unsigned short st_dev; ++ unsigned short __pad1; ++ unsigned long st_ino; ++ unsigned short st_mode; ++ unsigned short st_nlink; ++ unsigned short st_uid; ++ unsigned short st_gid; ++ unsigned short st_rdev; ++ unsigned short __pad2; ++ unsigned long st_size; ++ unsigned long st_blksize; ++ unsigned long st_blocks; ++ unsigned long st_atime; ++ unsigned long __unused1; ++ unsigned long st_mtime; ++ unsigned long __unused2; ++ unsigned long st_ctime; ++ unsigned long __unused3; ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++/* This matches struct stat64 in glibc2.1, hence the absolutely ++ * insane amounts of padding around dev_t's. ++ */ ++struct stat64 { ++ unsigned long long st_dev; ++ unsigned char __pad1[4]; ++ ++#define STAT64_HAS_BROKEN_ST_INO 1 ++ unsigned long __st_ino; ++ ++ unsigned int st_mode; ++ unsigned int st_nlink; ++ ++ unsigned long st_uid; ++ unsigned long st_gid; ++ ++ unsigned long long st_rdev; ++ unsigned char __pad3[4]; ++ ++ long long st_size; ++ unsigned long st_blksize; ++ ++ unsigned long __pad4; /* future possible st_blocks high bits */ ++ unsigned long st_blocks; /* Number 512-byte blocks allocated. */ ++ ++ unsigned long st_atime; ++ unsigned long st_atime_nsec; ++ ++ unsigned long st_mtime; ++ unsigned long st_mtime_nsec; ++ ++ unsigned long st_ctime; ++ unsigned long st_ctime_nsec; ++ ++ unsigned long long st_ino; ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/string.h ++++ linux/include/asm-nios2nommu/string.h +@@ -0,0 +1,45 @@ ++#ifndef __NIOS_STRING_H__ ++#define __NIOS_STRING_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/string.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifdef __KERNEL__ /* only set these up for kernel code */ ++ ++#define __HAVE_ARCH_MEMMOVE ++void * memmove(void * d, const void * s, size_t count); ++#define __HAVE_ARCH_MEMCPY ++extern void * memcpy(void *d, const void *s, size_t count); ++#define __HAVE_ARCH_MEMSET ++extern void * memset(void * s,int c,size_t count); ++ ++#if 0 ++#define __HAVE_ARCH_BCOPY ++#define __HAVE_ARCH_STRLEN ++#endif ++ ++#endif /* KERNEL */ ++ ++#endif /* !(__NIOS_STRING_H__) */ +--- linux/include/asm-nios2nommu/system.h ++++ linux/include/asm-nios2nommu/system.h +@@ -0,0 +1,172 @@ ++/* ++ * Taken from the m68k. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_SYSTEM_H ++#define _NIOS2NOMMU_SYSTEM_H ++ ++// #include /* get configuration macros */ ++#include ++#include ++#include ++#include ++ ++/* ++ * switch_to(n) should switch tasks to task ptr, first checking that ++ * ptr isn't the current task, in which case it does nothing. This ++ * also clears the TS-flag if the task we switched to has used the ++ * math co-processor latest. ++ */ ++ ++/* ++ */ ++asmlinkage void resume(void); ++#define switch_to(prev,next,last) \ ++{ \ ++ void *_last; \ ++ __asm__ __volatile__( \ ++ "mov r4, %1\n" \ ++ "mov r5, %2\n" \ ++ "call resume\n" \ ++ "mov %0,r4\n" \ ++ : "=r" (_last) \ ++ : "r" (prev), "r" (next) \ ++ : "r4","r5","r7","r8","ra"); \ ++ (last) = _last; \ ++} ++ ++#define local_irq_enable() __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "ori r8, r8, 1\n" \ ++ "wrctl status, r8\n" \ ++ : : : "r8") ++ ++#define local_irq_disable() __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "andi r8, r8, 0xfffe\n" \ ++ "wrctl status, r8\n" \ ++ : : : "r8") ++ ++#define local_save_flags(x) __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "mov %0, r8\n" \ ++ :"=r" (x) : : "r8", "memory") ++ ++#define local_irq_restore(x) __asm__ __volatile__ ( \ ++ "mov r8, %0\n" \ ++ "wrctl status, r8\n" \ ++ : :"r" (x) : "memory") ++ ++/* For spinlocks etc */ ++#define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } while (0) ++ ++#define irqs_disabled() \ ++({ \ ++ unsigned long flags; \ ++ local_save_flags(flags); \ ++ ((flags & NIOS2_STATUS_PIE_MSK) == 0x0); \ ++}) ++ ++#define iret() __asm__ __volatile__ ("eret": : :"memory", "ea") ++ ++/* ++ * Force strict CPU ordering. ++ * Not really required on m68k... ++ */ ++#define nop() asm volatile ("nop"::) ++#define mb() asm volatile ("" : : :"memory") ++#define rmb() asm volatile ("" : : :"memory") ++#define wmb() asm volatile ("" : : :"memory") ++#define set_rmb(var, value) do { xchg(&var, value); } while (0) ++#define set_mb(var, value) set_rmb(var, value) ++#define set_wmb(var, value) do { var = value; wmb(); } while (0) ++ ++#ifdef CONFIG_SMP ++#define smp_mb() mb() ++#define smp_rmb() rmb() ++#define smp_wmb() wmb() ++#define smp_read_barrier_depends() read_barrier_depends() ++#else ++#define smp_mb() barrier() ++#define smp_rmb() barrier() ++#define smp_wmb() barrier() ++#define smp_read_barrier_depends() do { } while(0) ++#endif ++ ++#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) ++#define tas(ptr) (xchg((ptr),1)) ++ ++struct __xchg_dummy { unsigned long a[100]; }; ++#define __xg(x) ((volatile struct __xchg_dummy *)(x)) ++ ++static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) ++{ ++ unsigned long tmp, flags; ++ ++ local_irq_save(flags); ++ ++ switch (size) { ++ case 1: ++ __asm__ __volatile__( \ ++ "ldb %0, %2\n" \ ++ "stb %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ case 2: ++ __asm__ __volatile__( \ ++ "ldh %0, %2\n" \ ++ "sth %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ case 4: ++ __asm__ __volatile__( \ ++ "ldw %0, %2\n" \ ++ "stw %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ } ++ local_irq_restore(flags); ++ return tmp; ++} ++ ++/* ++ * Atomic compare and exchange. Compare OLD with MEM, if identical, ++ * store NEW in MEM. Return the initial value in MEM. Success is ++ * indicated by comparing RETURN with OLD. ++ */ ++#define __HAVE_ARCH_CMPXCHG 1 ++ ++static __inline__ unsigned long ++cmpxchg(volatile int *p, int old, int new) ++{ ++ unsigned long flags; ++ int prev; ++ ++ local_irq_save(flags); ++ if ((prev = *p) == old) ++ *p = new; ++ local_irq_restore(flags); ++ return(prev); ++} ++ ++#endif /* _NIOS2NOMMU_SYSTEM_H */ +--- linux/include/asm-nios2nommu/termbits.h ++++ linux/include/asm-nios2nommu/termbits.h +@@ -0,0 +1,199 @@ ++#ifndef __ARCH_NIOS_TERMBITS_H__ ++#define __ARCH_NIOS_TERMBITS_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/termbits.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++typedef unsigned char cc_t; ++typedef unsigned int speed_t; ++typedef unsigned int tcflag_t; ++ ++#define NCCS 19 ++struct termios { ++ tcflag_t c_iflag; /* input mode flags */ ++ tcflag_t c_oflag; /* output mode flags */ ++ tcflag_t c_cflag; /* control mode flags */ ++ tcflag_t c_lflag; /* local mode flags */ ++ cc_t c_line; /* line discipline */ ++ cc_t c_cc[NCCS]; /* control characters */ ++}; ++ ++/* c_cc characters */ ++#define VINTR 0 ++#define VQUIT 1 ++#define VERASE 2 ++#define VKILL 3 ++#define VEOF 4 ++#define VTIME 5 ++#define VMIN 6 ++#define VSWTC 7 ++#define VSTART 8 ++#define VSTOP 9 ++#define VSUSP 10 ++#define VEOL 11 ++#define VREPRINT 12 ++#define VDISCARD 13 ++#define VWERASE 14 ++#define VLNEXT 15 ++#define VEOL2 16 ++ ++ ++/* c_iflag bits */ ++#define IGNBRK 0000001 ++#define BRKINT 0000002 ++#define IGNPAR 0000004 ++#define PARMRK 0000010 ++#define INPCK 0000020 ++#define ISTRIP 0000040 ++#define INLCR 0000100 ++#define IGNCR 0000200 ++#define ICRNL 0000400 ++#define IUCLC 0001000 ++#define IXON 0002000 ++#define IXANY 0004000 ++#define IXOFF 0010000 ++#define IMAXBEL 0020000 ++#define IUTF8 0040000 ++ ++/* c_oflag bits */ ++#define OPOST 0000001 ++#define OLCUC 0000002 ++#define ONLCR 0000004 ++#define OCRNL 0000010 ++#define ONOCR 0000020 ++#define ONLRET 0000040 ++#define OFILL 0000100 ++#define OFDEL 0000200 ++#define NLDLY 0000400 ++#define NL0 0000000 ++#define NL1 0000400 ++#define CRDLY 0003000 ++#define CR0 0000000 ++#define CR1 0001000 ++#define CR2 0002000 ++#define CR3 0003000 ++#define TABDLY 0014000 ++#define TAB0 0000000 ++#define TAB1 0004000 ++#define TAB2 0010000 ++#define TAB3 0014000 ++#define XTABS 0014000 ++#define BSDLY 0020000 ++#define BS0 0000000 ++#define BS1 0020000 ++#define VTDLY 0040000 ++#define VT0 0000000 ++#define VT1 0040000 ++#define FFDLY 0100000 ++#define FF0 0000000 ++#define FF1 0100000 ++ ++/* c_cflag bit meaning */ ++#define CBAUD 0010017 ++#define B0 0000000 /* hang up */ ++#define B50 0000001 ++#define B75 0000002 ++#define B110 0000003 ++#define B134 0000004 ++#define B150 0000005 ++#define B200 0000006 ++#define B300 0000007 ++#define B600 0000010 ++#define B1200 0000011 ++#define B1800 0000012 ++#define B2400 0000013 ++#define B4800 0000014 ++#define B9600 0000015 ++#define B19200 0000016 ++#define B38400 0000017 ++#define EXTA B19200 ++#define EXTB B38400 ++#define CSIZE 0000060 ++#define CS5 0000000 ++#define CS6 0000020 ++#define CS7 0000040 ++#define CS8 0000060 ++#define CSTOPB 0000100 ++#define CREAD 0000200 ++#define PARENB 0000400 ++#define PARODD 0001000 ++#define HUPCL 0002000 ++#define CLOCAL 0004000 ++#define CBAUDEX 0010000 ++#define B57600 0010001 ++#define B115200 0010002 ++#define B230400 0010003 ++#define B460800 0010004 ++#define B500000 0010005 ++#define B576000 0010006 ++#define B921600 0010007 ++#define B1000000 0010010 ++#define B1152000 0010011 ++#define B1500000 0010012 ++#define B2000000 0010013 ++#define B2500000 0010014 ++#define B3000000 0010015 ++#define B3500000 0010016 ++#define B4000000 0010017 ++#define CIBAUD 002003600000 /* input baud rate (not used) */ ++#define CMSPAR 010000000000 /* mark or space (stick) parity */ ++#define CRTSCTS 020000000000 /* flow control */ ++ ++/* c_lflag bits */ ++#define ISIG 0000001 ++#define ICANON 0000002 ++#define XCASE 0000004 ++#define ECHO 0000010 ++#define ECHOE 0000020 ++#define ECHOK 0000040 ++#define ECHONL 0000100 ++#define NOFLSH 0000200 ++#define TOSTOP 0000400 ++#define ECHOCTL 0001000 ++#define ECHOPRT 0002000 ++#define ECHOKE 0004000 ++#define FLUSHO 0010000 ++#define PENDIN 0040000 ++#define IEXTEN 0100000 ++ ++ ++/* tcflow() and TCXONC use these */ ++#define TCOOFF 0 ++#define TCOON 1 ++#define TCIOFF 2 ++#define TCION 3 ++ ++/* tcflush() and TCFLSH use these */ ++#define TCIFLUSH 0 ++#define TCOFLUSH 1 ++#define TCIOFLUSH 2 ++ ++/* tcsetattr uses these */ ++#define TCSANOW 0 ++#define TCSADRAIN 1 ++#define TCSAFLUSH 2 ++ ++#endif /* __ARCH_NIOS_TERMBITS_H__ */ +--- linux/include/asm-nios2nommu/termios.h ++++ linux/include/asm-nios2nommu/termios.h +@@ -0,0 +1,132 @@ ++#ifndef _NIOS_TERMIOS_H ++#define _NIOS_TERMIOS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/termios.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++#include ++ ++struct winsize { ++ unsigned short ws_row; ++ unsigned short ws_col; ++ unsigned short ws_xpixel; ++ unsigned short ws_ypixel; ++}; ++ ++#define NCC 8 ++struct termio { ++ unsigned short c_iflag; /* input mode flags */ ++ unsigned short c_oflag; /* output mode flags */ ++ unsigned short c_cflag; /* control mode flags */ ++ unsigned short c_lflag; /* local mode flags */ ++ unsigned char c_line; /* line discipline */ ++ unsigned char c_cc[NCC]; /* control characters */ ++}; ++ ++#ifdef __KERNEL__ ++/* intr=^C quit=^| erase=del kill=^U ++ eof=^D vtime=\0 vmin=\1 sxtc=\0 ++ start=^Q stop=^S susp=^Z eol=\0 ++ reprint=^R discard=^U werase=^W lnext=^V ++ eol2=\0 ++*/ ++#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" ++#endif ++ ++/* modem lines */ ++#define TIOCM_LE 0x001 ++#define TIOCM_DTR 0x002 ++#define TIOCM_RTS 0x004 ++#define TIOCM_ST 0x008 ++#define TIOCM_SR 0x010 ++#define TIOCM_CTS 0x020 ++#define TIOCM_CAR 0x040 ++#define TIOCM_RNG 0x080 ++#define TIOCM_DSR 0x100 ++#define TIOCM_CD TIOCM_CAR ++#define TIOCM_RI TIOCM_RNG ++#define TIOCM_OUT1 0x2000 ++#define TIOCM_OUT2 0x4000 ++#define TIOCM_LOOP 0x8000 ++ ++/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ ++ ++/* line disciplines */ ++#define N_TTY 0 ++#define N_SLIP 1 ++#define N_MOUSE 2 ++#define N_PPP 3 ++#define N_STRIP 4 ++#define N_AX25 5 ++#define N_X25 6 /* X.25 async */ ++#define N_6PACK 7 ++#define N_MASC 8 /* Reserved for Mobitex module */ ++#define N_R3964 9 /* Reserved for Simatic R3964 module */ ++#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ ++#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */ ++#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ ++#define N_HDLC 13 /* synchronous HDLC */ ++#define N_SYNC_PPP 14 ++#define N_HCI 15 /* Bluetooth HCI UART */ ++ ++#ifdef __KERNEL__ ++ ++/* ++ * Translate a "termio" structure into a "termios". Ugh. ++ */ ++#define user_termio_to_kernel_termios(termios, termio) \ ++({ \ ++ unsigned short tmp; \ ++ get_user(tmp, &(termio)->c_iflag); \ ++ (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_oflag); \ ++ (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_cflag); \ ++ (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_lflag); \ ++ (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ ++ get_user((termios)->c_line, &(termio)->c_line); \ ++ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ ++}) ++ ++/* ++ * Translate a "termios" structure into a "termio". Ugh. ++ */ ++#define kernel_termios_to_user_termio(termio, termios) \ ++({ \ ++ put_user((termios)->c_iflag, &(termio)->c_iflag); \ ++ put_user((termios)->c_oflag, &(termio)->c_oflag); \ ++ put_user((termios)->c_cflag, &(termio)->c_cflag); \ ++ put_user((termios)->c_lflag, &(termio)->c_lflag); \ ++ put_user((termios)->c_line, &(termio)->c_line); \ ++ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ ++}) ++ ++#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) ++#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS_TERMIOS_H */ +--- linux/include/asm-nios2nommu/thread_info.h ++++ linux/include/asm-nios2nommu/thread_info.h +@@ -0,0 +1,127 @@ ++/* thread_info.h: niosnommu low-level thread information ++ * adapted from the m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 2002 Microtronix Datacom ++ * ++ * - Incorporating suggestions made by Linus Torvalds and Dave Miller ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_THREAD_INFO_H ++#define _ASM_THREAD_INFO_H ++ ++#include ++ ++#ifdef __KERNEL__ ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * low level task data. ++ */ ++struct thread_info { ++ struct task_struct *task; /* main task structure */ ++ struct exec_domain *exec_domain; /* execution domain */ ++ unsigned long flags; /* low level flags */ ++ int cpu; /* cpu we're on */ ++ int preempt_count; /* 0 => preemptable, <0 => BUG*/ ++ struct restart_block restart_block; ++}; ++ ++/* ++ * macros/functions for gaining access to the thread information structure ++ */ ++#define INIT_THREAD_INFO(tsk) \ ++{ \ ++ .task = &tsk, \ ++ .exec_domain = &default_exec_domain, \ ++ .flags = 0, \ ++ .cpu = 0, \ ++ .preempt_count = 1, \ ++ .restart_block = { \ ++ .fn = do_no_restart_syscall, \ ++ }, \ ++} ++ ++#define init_thread_info (init_thread_union.thread_info) ++#define init_stack (init_thread_union.stack) ++ ++ ++/* how to get the thread information struct from C ++ usable only in supervisor mode */ ++static inline struct thread_info *current_thread_info(void) ++{ ++ struct thread_info *ti; ++ __asm__ __volatile__( ++ "mov %0, sp\n" ++ "and %0, %0, %1\n" ++ : "=&r"(ti) ++ : "r" (~(THREAD_SIZE-1)) ++ ); ++ return ti; ++} ++ ++/* thread information allocation */ ++#define alloc_thread_info(tsk) ((struct thread_info *) \ ++ __get_free_pages(GFP_KERNEL, 1)) ++#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) ++#define put_thread_info(ti) put_task_struct((ti)->task) ++ ++#define PREEMPT_ACTIVE 0x4000000 ++ ++/* ++ * thread information flag bit numbers ++ */ ++#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ ++#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ ++#define TIF_SIGPENDING 2 /* signal pending */ ++#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ ++#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling ++ TIF_NEED_RESCHED */ ++#define TIF_MEMDIE 5 ++ ++/* as above, but as bit values */ ++#define _TIF_SYSCALL_TRACE (1< ++ ++ ++#define CLOCK_TICK_RATE nasys_clock_freq /* Underlying HZ */ ++ ++#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ ++ ++#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ ++ (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ ++ << (SHIFT_SCALE-SHIFT_HZ)) / HZ) ++ ++typedef unsigned long cycles_t; ++ ++static inline cycles_t get_cycles(void) ++{ ++ return 0; ++} ++ ++#endif +--- linux/include/asm-nios2nommu/tlbflush.h ++++ linux/include/asm-nios2nommu/tlbflush.h +@@ -0,0 +1,86 @@ ++#ifndef _NIOS2NOMMU_TLBFLUSH_H ++#define _NIOS2NOMMU_TLBFLUSH_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/tlbflush.h ++ * ++ * Ported from m68knommu. ++ * ++ * Copyright (C) 2003 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++ ++/* ++ * flush all user-space atc entries. ++ */ ++static inline void __flush_tlb(void) ++{ ++ BUG(); ++} ++ ++static inline void __flush_tlb_one(unsigned long addr) ++{ ++ BUG(); ++} ++ ++#define flush_tlb() __flush_tlb() ++ ++/* ++ * flush all atc entries (both kernel and user-space entries). ++ */ ++static inline void flush_tlb_all(void) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_mm(struct mm_struct *mm) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_range(struct mm_struct *mm, ++ unsigned long start, unsigned long end) ++{ ++ BUG(); ++} ++ ++extern inline void flush_tlb_kernel_page(unsigned long addr) ++{ ++ BUG(); ++} ++ ++extern inline void flush_tlb_pgtables(struct mm_struct *mm, ++ unsigned long start, unsigned long end) ++{ ++ BUG(); ++} ++ ++#endif /* _NIOS2NOMMU_TLBFLUSH_H */ +--- linux/include/asm-nios2nommu/tlb.h ++++ linux/include/asm-nios2nommu/tlb.h +@@ -0,0 +1,35 @@ ++#ifndef __NIOS_TLB_H__ ++#define __NIOS_TLB_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/tlb.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2003 Microtronix Datacom Ltd ++ * Copyright (C) 2002 NEC Corporation ++ * Copyright (C) 2002 Miles Bader ++ * ++ * 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. ++ * ++ * ++ * Written by Miles Bader ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#define tlb_flush(tlb) ((void)0) ++ ++#include ++ ++#endif /* __NIOS_TLB_H__ */ ++ +--- linux/include/asm-nios2nommu/topology.h ++++ linux/include/asm-nios2nommu/topology.h +@@ -0,0 +1,30 @@ ++#ifndef _ASM_NIOS2NOMMU_TOPOLOGY_H ++#define _ASM_NIOS2NOMMU_TOPOLOGY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/topology.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _ASM_NIOS2NOMMU_TOPOLOGY_H */ +--- linux/include/asm-nios2nommu/traps.h ++++ linux/include/asm-nios2nommu/traps.h +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2_TRAPS_H ++#define _NIOS2_TRAPS_H ++ ++#define TRAP_ID_SYSCALL 0 ++#define TRAP_ID_APPDEBUG 1 ++#endif /* !(_NIOS2_TRAPS_H) */ +--- linux/include/asm-nios2nommu/types.h ++++ linux/include/asm-nios2nommu/types.h +@@ -0,0 +1,93 @@ ++#ifndef _NIOS_TYPES_H ++#define _NIOS_TYPES_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/types.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This file is never included by application software unless ++ * explicitly requested (e.g., via linux/types.h) in which case the ++ * application is Linux specific so (user-) name space pollution is ++ * not a major issue. However, for interoperability, libraries still ++ * need to be careful to avoid a name clashes. ++ */ ++ ++#ifndef __ASSEMBLY__ ++ ++typedef unsigned short umode_t; ++ ++/* ++ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the ++ * header files exported to user space ++ */ ++ ++typedef __signed__ char __s8; ++typedef unsigned char __u8; ++ ++typedef __signed__ short __s16; ++typedef unsigned short __u16; ++ ++typedef __signed__ int __s32; ++typedef unsigned int __u32; ++ ++#if defined(__GNUC__) && !defined(__STRICT_ANSI__) ++typedef __signed__ long long __s64; ++typedef unsigned long long __u64; ++#endif ++ ++#endif /* __ASSEMBLY__ */ ++ ++/* ++ * These aren't exported outside the kernel to avoid name space clashes ++ */ ++#ifdef __KERNEL__ ++ ++#define BITS_PER_LONG 32 ++ ++#ifndef __ASSEMBLY__ ++ ++typedef signed char s8; ++typedef unsigned char u8; ++ ++typedef signed short s16; ++typedef unsigned short u16; ++ ++typedef signed int s32; ++typedef unsigned int u32; ++ ++typedef signed long long s64; ++typedef unsigned long long u64; ++ ++/* DMA addresses are always 32-bits wide */ ++ ++typedef u32 dma_addr_t; ++typedef u32 dma64_addr_t; ++ ++typedef unsigned short kmem_bufctl_t; ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS_TYPES_H */ +--- linux/include/asm-nios2nommu/uaccess.h ++++ linux/include/asm-nios2nommu/uaccess.h +@@ -0,0 +1,183 @@ ++#ifndef __NIOS2NOMMU_UACCESS_H ++#define __NIOS2NOMMU_UACCESS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * asm-nios2nommu/uaccess.h ++ * ++ * User space memory access functions ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Ported from asm-m68knommu/uaccess.h --wentao ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++#include ++#include ++#include ++ ++#define VERIFY_READ 0 ++#define VERIFY_WRITE 1 ++ ++#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size)) ++ ++static inline int _access_ok(unsigned long addr, unsigned long size) ++{ ++ return (((unsigned long)addr < (unsigned long)nasys_program_mem_end) && ++ (((unsigned long)addr >= (unsigned long)nasys_program_mem))); ++} ++ ++extern inline int verify_area(int type, const void * addr, unsigned long size) ++{ ++ return access_ok(type,addr,size)?0:-EFAULT; ++} ++ ++/* ++ * The exception table consists of pairs of addresses: the first is the ++ * address of an instruction that is allowed to fault, and the second is ++ * the address at which the program should continue. No registers are ++ * modified, so it is entirely up to the continuation code to figure out ++ * what to do. ++ * ++ * All the routines below use bits of fixup code that are out of line ++ * with the main instruction path. This means when everything is well, ++ * we don't even have to jump over them. Further, they do not intrude ++ * on our cache or tlb entries. ++ */ ++ ++#define ARCH_HAS_SEARCH_EXTABLE ++//;dgt2;tmp; ++ ++struct exception_table_entry ++{ ++ unsigned long insn, fixup; ++}; ++ ++/* Returns 0 if exception not found and fixup otherwise. */ ++extern unsigned long search_exception_table(unsigned long); ++ ++ ++/* ++ * These are the main single-value transfer routines. They automatically ++ * use the right size if we just have the right pointer type. ++ */ ++ ++#define put_user(x, ptr) \ ++({ \ ++ int __pu_err = 0; \ ++ typeof(*(ptr)) __pu_val = (x); \ ++ switch (sizeof (*(ptr))) { \ ++ case 1: \ ++ case 2: \ ++ case 4: \ ++ case 8: \ ++ memcpy(ptr, &__pu_val, sizeof (*(ptr))); \ ++ break; \ ++ default: \ ++ __pu_err = __put_user_bad(); \ ++ break; \ ++ } \ ++ __pu_err; \ ++}) ++#define __put_user(x, ptr) put_user(x, ptr) ++ ++extern int __put_user_bad(void); ++ ++/* ++ * Tell gcc we read from memory instead of writing: this is because ++ * we do not write to any memory gcc knows about, so there are no ++ * aliasing issues. ++ */ ++ ++#define __ptr(x) ((unsigned long *)(x)) ++ ++#define get_user(x, ptr) \ ++({ \ ++ int __gu_err = 0; \ ++ typeof(*(ptr)) __gu_val = 0; \ ++ switch (sizeof(*(ptr))) { \ ++ case 1: \ ++ case 2: \ ++ case 4: \ ++ case 8: \ ++ memcpy(&__gu_val, ptr, sizeof (*(ptr))); \ ++ break; \ ++ default: \ ++ __gu_val = 0; \ ++ __gu_err = __get_user_bad(); \ ++ break; \ ++ } \ ++ (x) = __gu_val; \ ++ __gu_err; \ ++}) ++#define __get_user(x, ptr) get_user(x, ptr) ++ ++extern int __get_user_bad(void); ++ ++#define copy_from_user(to, from, n) (memcpy(to, from, n), 0) ++#define copy_to_user(to, from, n) (memcpy(to, from, n), 0) ++ ++#define __copy_from_user(to, from, n) copy_from_user(to, from, n) ++#define __copy_to_user(to, from, n) copy_to_user(to, from, n) ++#define __copy_to_user_inatomic __copy_to_user ++#define __copy_from_user_inatomic __copy_from_user ++ ++#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) ++ ++#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) ++ ++/* ++ * Copy a null terminated string from userspace. ++ */ ++ ++static inline long ++strncpy_from_user(char *dst, const char *src, long count) ++{ ++ char *tmp; ++ strncpy(dst, src, count); ++ for (tmp = dst; *tmp && count > 0; tmp++, count--) ++ ; ++ return(tmp - dst); /* DAVIDM should we count a NUL ? check getname */ ++} ++ ++/* ++ * Return the size of a string (including the ending 0) ++ * ++ * Return 0 on exception, a value greater than N if too long ++ */ ++static inline long strnlen_user(const char *src, long n) ++{ ++ return(strlen(src) + 1); /* DAVIDM make safer */ ++} ++ ++#define strlen_user(str) strnlen_user(str, 32767) ++ ++/* ++ * Zero Userspace ++ */ ++ ++static inline unsigned long ++clear_user(void *to, unsigned long n) ++{ ++ memset(to, 0, n); ++ return(0); ++} ++ ++#endif /* _NIOS2NOMMU_UACCESS_H */ +--- linux/include/asm-nios2nommu/uart_struct.h ++++ linux/include/asm-nios2nommu/uart_struct.h +@@ -0,0 +1,83 @@ ++ ++// UART Registers ++typedef volatile struct ++ { ++ int np_uartrxdata; // Read-only, 8-bit ++ int np_uarttxdata; // Write-only, 8-bit ++ int np_uartstatus; // Read-only, 8-bit ++ int np_uartcontrol; // Read/Write, 9-bit ++ int np_uartdivisor; // Read/Write, 16-bit, optional ++ int np_uartendofpacket; // Read/Write, end-of-packet character ++ } np_uart; ++ ++// UART Status Register Bits ++enum ++ { ++ np_uartstatus_eop_bit = 12, ++ np_uartstatus_cts_bit = 11, ++ np_uartstatus_dcts_bit = 10, ++ np_uartstatus_e_bit = 8, ++ np_uartstatus_rrdy_bit = 7, ++ np_uartstatus_trdy_bit = 6, ++ np_uartstatus_tmt_bit = 5, ++ np_uartstatus_toe_bit = 4, ++ np_uartstatus_roe_bit = 3, ++ np_uartstatus_brk_bit = 2, ++ np_uartstatus_fe_bit = 1, ++ np_uartstatus_pe_bit = 0, ++ ++ np_uartstatus_eop_mask = (1<<12), ++ np_uartstatus_cts_mask = (1<<11), ++ np_uartstatus_dcts_mask = (1<<10), ++ np_uartstatus_e_mask = (1<<8), ++ np_uartstatus_rrdy_mask = (1<<7), ++ np_uartstatus_trdy_mask = (1<<6), ++ np_uartstatus_tmt_mask = (1<<5), ++ np_uartstatus_toe_mask = (1<<4), ++ np_uartstatus_roe_mask = (1<<3), ++ np_uartstatus_brk_mask = (1<<2), ++ np_uartstatus_fe_mask = (1<<1), ++ np_uartstatus_pe_mask = (1<<0) ++ }; ++ ++// UART Control Register Bits ++enum ++ { ++ np_uartcontrol_ieop_bit = 12, ++ np_uartcontrol_rts_bit = 11, ++ np_uartcontrol_idcts_bit = 10, ++ np_uartcontrol_tbrk_bit = 9, ++ np_uartcontrol_ie_bit = 8, ++ np_uartcontrol_irrdy_bit = 7, ++ np_uartcontrol_itrdy_bit = 6, ++ np_uartcontrol_itmt_bit = 5, ++ np_uartcontrol_itoe_bit = 4, ++ np_uartcontrol_iroe_bit = 3, ++ np_uartcontrol_ibrk_bit = 2, ++ np_uartcontrol_ife_bit = 1, ++ np_uartcontrol_ipe_bit = 0, ++ ++ np_uartcontrol_ieop_mask = (1<<12), ++ np_uartcontrol_rts_mask = (1<<11), ++ np_uartcontrol_idcts_mask = (1<<10), ++ np_uartcontrol_tbrk_mask = (1<<9), ++ np_uartcontrol_ie_mask = (1<<8), ++ np_uartcontrol_irrdy_mask = (1<<7), ++ np_uartcontrol_itrdy_mask = (1<<6), ++ np_uartcontrol_itmt_mask = (1<<5), ++ np_uartcontrol_itoe_mask = (1<<4), ++ np_uartcontrol_iroe_mask = (1<<3), ++ np_uartcontrol_ibrk_mask = (1<<2), ++ np_uartcontrol_ife_mask = (1<<1), ++ np_uartcontrol_ipe_mask = (1<<0) ++ }; ++ ++// UART Routines ++int nr_uart_rxchar(np_uart *uartBase); // 0 for default UART ++void nr_uart_txcr(void); ++void nr_uart_txchar(int c,np_uart *uartBase); // 0 for default UART ++void nr_uart_txhex(int x); // 16 or 32 bits ++void nr_uart_txhex16(short x); ++void nr_uart_txhex32(long x); ++void nr_uart_txstring(char *s); ++ +--- linux/include/asm-nios2nommu/ucontext.h ++++ linux/include/asm-nios2nommu/ucontext.h +@@ -0,0 +1,63 @@ ++#ifndef _NIOSKNOMMU_UCONTEXT_H ++#define _NIOSKNOMMU_UCONTEXT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/ucontext.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++typedef int greg_t; ++#define NGREG 32 ++typedef greg_t gregset_t[NGREG]; ++ ++#ifdef CONFIG_FPU ++typedef struct fpregset { ++ int f_pcr; ++ int f_psr; ++ int f_fpiaddr; ++ int f_fpregs[8][3]; ++} fpregset_t; ++#endif ++ ++struct mcontext { ++ int version; ++ int status_extension; ++ gregset_t gregs; ++#ifdef CONFIG_FPU ++ fpregset_t fpregs; ++#endif ++}; ++ ++#define MCONTEXT_VERSION 2 ++ ++struct ucontext { ++ unsigned long uc_flags; ++ struct ucontext *uc_link; ++ stack_t uc_stack; ++ struct mcontext uc_mcontext; ++#ifdef CONFIG_FPU ++ unsigned long uc_filler[80]; ++#endif ++ sigset_t uc_sigmask; /* mask last for extensibility */ ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/unaligned.h ++++ linux/include/asm-nios2nommu/unaligned.h +@@ -0,0 +1,43 @@ ++#ifndef __NIOS_UNALIGNED_H ++#define __NIOS_UNALIGNED_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/unaligned.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * The nios cannot do unaligned accesses itself. ++ */ ++ ++#define get_unaligned(ptr) ({ \ ++ typeof((*(ptr))) x; \ ++ memcpy(&x, (void*)ptr, sizeof(*(ptr))); \ ++ x; \ ++}) ++ ++#define put_unaligned(val, ptr) ({ \ ++ typeof((*(ptr))) x = val; \ ++ memcpy((void*)ptr, &x, sizeof(*(ptr))); \ ++}) ++ ++#endif /* __NIOS_UNALIGNED_H */ +--- linux/include/asm-nios2nommu/unistd.h ++++ linux/include/asm-nios2nommu/unistd.h +@@ -0,0 +1,686 @@ ++#ifndef _ASM_NIOS_UNISTD_H_ ++#define _ASM_NIOS_UNISTD_H_ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/unistd.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * //vic - kernel_thread moved to process.c ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* TRAP isr expects the trap# (syscall=#TRAP_ID_SYSCALL) in r2, ++ * the syscall # in r3, and arguments in r4, r5, ... ++ * Return argument expected in r2. ++ */ ++ ++#define __NR_restart_syscall 0 ++#define __NR_exit 1 ++#define __NR_fork 2 ++#define __NR_read 3 ++#define __NR_write 4 ++#define __NR_open 5 ++#define __NR_close 6 ++#define __NR_waitpid 7 ++#define __NR_creat 8 ++#define __NR_link 9 ++#define __NR_unlink 10 ++#define __NR_execve 11 ++#define __NR_chdir 12 ++#define __NR_time 13 ++#define __NR_mknod 14 ++#define __NR_chmod 15 ++#define __NR_chown 16 ++#define __NR_break 17 ++#define __NR_oldstat 18 ++#define __NR_lseek 19 ++#define __NR_getpid 20 ++#define __NR_mount 21 ++#define __NR_umount 22 ++#define __NR_setuid 23 ++#define __NR_getuid 24 ++#define __NR_stime 25 ++#define __NR_ptrace 26 ++#define __NR_alarm 27 ++#define __NR_oldfstat 28 ++#define __NR_pause 29 ++#define __NR_utime 30 ++#define __NR_stty 31 ++#define __NR_gtty 32 ++#define __NR_access 33 ++#define __NR_nice 34 ++#define __NR_ftime 35 ++#define __NR_sync 36 ++#define __NR_kill 37 ++#define __NR_rename 38 ++#define __NR_mkdir 39 ++#define __NR_rmdir 40 ++#define __NR_dup 41 ++#define __NR_pipe 42 ++#define __NR_times 43 ++#define __NR_prof 44 ++#define __NR_brk 45 ++#define __NR_setgid 46 ++#define __NR_getgid 47 ++#define __NR_signal 48 ++#define __NR_geteuid 49 ++#define __NR_getegid 50 ++#define __NR_acct 51 ++#define __NR_umount2 52 //vic #define __NR_phys 52 ++#define __NR_lock 53 ++#define __NR_ioctl 54 ++#define __NR_fcntl 55 ++#define __NR_mpx 56 ++#define __NR_setpgid 57 ++#define __NR_ulimit 58 ++#define __NR_oldolduname 59 ++#define __NR_umask 60 ++#define __NR_chroot 61 ++#define __NR_ustat 62 ++#define __NR_dup2 63 ++#define __NR_getppid 64 ++#define __NR_getpgrp 65 ++#define __NR_setsid 66 ++#define __NR_sigaction 67 ++#define __NR_sgetmask 68 ++#define __NR_ssetmask 69 ++#define __NR_setreuid 70 ++#define __NR_setregid 71 ++#define __NR_sigsuspend 72 ++#define __NR_sigpending 73 ++#define __NR_sethostname 74 ++#define __NR_setrlimit 75 ++#define __NR_getrlimit 76 ++#define __NR_getrusage 77 ++#define __NR_gettimeofday 78 ++#define __NR_settimeofday 79 ++#define __NR_getgroups 80 ++#define __NR_setgroups 81 ++#define __NR_select 82 ++#define __NR_symlink 83 ++#define __NR_oldlstat 84 ++#define __NR_readlink 85 ++#define __NR_uselib 86 ++#define __NR_swapon 87 ++#define __NR_reboot 88 ++#define __NR_readdir 89 ++#define __NR_mmap 90 ++#define __NR_munmap 91 ++#define __NR_truncate 92 ++#define __NR_ftruncate 93 ++#define __NR_fchmod 94 ++#define __NR_fchown 95 ++#define __NR_getpriority 96 ++#define __NR_setpriority 97 ++#define __NR_profil 98 ++#define __NR_statfs 99 ++#define __NR_fstatfs 100 ++#define __NR_ioperm 101 ++#define __NR_socketcall 102 ++#define __NR_syslog 103 ++#define __NR_setitimer 104 ++#define __NR_getitimer 105 ++#define __NR_stat 106 ++#define __NR_lstat 107 ++#define __NR_fstat 108 ++#define __NR_olduname 109 ++#define __NR_iopl /* 110 */ not supported ++#define __NR_vhangup 111 ++#define __NR_idle /* 112 */ Obsolete ++#define __NR_vm86 /* 113 */ not supported ++#define __NR_wait4 114 ++#define __NR_swapoff 115 ++#define __NR_sysinfo 116 ++#define __NR_ipc 117 ++#define __NR_fsync 118 ++#define __NR_sigreturn 119 ++#define __NR_clone 120 ++#define __NR_setdomainname 121 ++#define __NR_uname 122 ++#define __NR_cacheflush 123 ++#define __NR_adjtimex 124 ++#define __NR_mprotect 125 ++#define __NR_sigprocmask 126 ++#define __NR_create_module 127 ++#define __NR_init_module 128 ++#define __NR_delete_module 129 ++#define __NR_get_kernel_syms 130 ++#define __NR_quotactl 131 ++#define __NR_getpgid 132 ++#define __NR_fchdir 133 ++#define __NR_bdflush 134 ++#define __NR_sysfs 135 ++#define __NR_personality 136 ++#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ ++#define __NR_setfsuid 138 ++#define __NR_setfsgid 139 ++#define __NR__llseek 140 ++#define __NR_getdents 141 ++#define __NR__newselect 142 ++#define __NR_flock 143 ++#define __NR_msync 144 ++#define __NR_readv 145 ++#define __NR_writev 146 ++#define __NR_getsid 147 ++#define __NR_fdatasync 148 ++#define __NR__sysctl 149 ++#define __NR_mlock 150 ++#define __NR_munlock 151 ++#define __NR_mlockall 152 ++#define __NR_munlockall 153 ++#define __NR_sched_setparam 154 ++#define __NR_sched_getparam 155 ++#define __NR_sched_setscheduler 156 ++#define __NR_sched_getscheduler 157 ++#define __NR_sched_yield 158 ++#define __NR_sched_get_priority_max 159 ++#define __NR_sched_get_priority_min 160 ++#define __NR_sched_rr_get_interval 161 ++#define __NR_nanosleep 162 ++#define __NR_mremap 163 ++#define __NR_setresuid 164 ++#define __NR_getresuid 165 ++#define __NR_getpagesize 166 ++#define __NR_query_module 167 ++#define __NR_poll 168 ++#define __NR_nfsservctl 169 ++#define __NR_setresgid 170 ++#define __NR_getresgid 171 ++#define __NR_prctl 172 ++#define __NR_rt_sigreturn 173 ++#define __NR_rt_sigaction 174 ++#define __NR_rt_sigprocmask 175 ++#define __NR_rt_sigpending 176 ++#define __NR_rt_sigtimedwait 177 ++#define __NR_rt_sigqueueinfo 178 ++#define __NR_rt_sigsuspend 179 ++#define __NR_pread 180 ++#define __NR_pwrite 181 ++#define __NR_lchown 182 ++#define __NR_getcwd 183 ++#define __NR_capget 184 ++#define __NR_capset 185 ++#define __NR_sigaltstack 186 ++#define __NR_sendfile 187 ++#define __NR_getpmsg 188 /* some people actually want streams */ ++#define __NR_putpmsg 189 /* some people actually want streams */ ++#define __NR_vfork 190 ++#define __NR_ugetrlimit 191 ++#define __NR_mmap2 192 ++#define __NR_truncate64 193 ++#define __NR_ftruncate64 194 ++#define __NR_stat64 195 ++#define __NR_lstat64 196 ++#define __NR_fstat64 197 ++#define __NR_chown32 198 ++#define __NR_getuid32 199 ++#define __NR_getgid32 200 ++#define __NR_geteuid32 201 ++#define __NR_getegid32 202 ++#define __NR_setreuid32 203 ++#define __NR_setregid32 204 ++#define __NR_getgroups32 205 ++#define __NR_setgroups32 206 ++#define __NR_fchown32 207 ++#define __NR_setresuid32 208 ++#define __NR_getresuid32 209 ++#define __NR_setresgid32 210 ++#define __NR_getresgid32 211 ++#define __NR_lchown32 212 ++#define __NR_setuid32 213 ++#define __NR_setgid32 214 ++#define __NR_setfsuid32 215 ++#define __NR_setfsgid32 216 ++#define __NR_pivot_root 217 ++/* 218 unused */ ++/* 219 unused */ ++#define __NR_getdents64 220 ++#define __NR_gettid 221 ++#define __NR_tkill 222 ++#define __NR_setxattr 223 ++#define __NR_lsetxattr 224 ++#define __NR_fsetxattr 225 ++#define __NR_getxattr 226 ++#define __NR_lgetxattr 227 ++#define __NR_fgetxattr 228 ++#define __NR_listxattr 229 ++#define __NR_llistxattr 230 ++#define __NR_flistxattr 231 ++#define __NR_removexattr 232 ++#define __NR_lremovexattr 233 ++#define __NR_fremovexattr 234 ++#define __NR_futex 235 ++#define __NR_sendfile64 236 ++#define __NR_mincore 237 ++#define __NR_madvise 238 ++#define __NR_fcntl64 239 ++#define __NR_readahead 240 ++#define __NR_io_setup 241 ++#define __NR_io_destroy 242 ++#define __NR_io_getevents 243 ++#define __NR_io_submit 244 ++#define __NR_io_cancel 245 ++#define __NR_fadvise64 246 ++#define __NR_exit_group 247 ++#define __NR_lookup_dcookie 248 ++#define __NR_epoll_create 249 ++#define __NR_epoll_ctl 250 ++#define __NR_epoll_wait 251 ++#define __NR_remap_file_pages 252 ++#define __NR_set_tid_address 253 ++#define __NR_timer_create 254 ++#define __NR_timer_settime 255 ++#define __NR_timer_gettime 256 ++#define __NR_timer_getoverrun 257 ++#define __NR_timer_delete 258 ++#define __NR_clock_settime 259 ++#define __NR_clock_gettime 260 ++#define __NR_clock_getres 261 ++#define __NR_clock_nanosleep 262 ++#define __NR_statfs64 263 ++#define __NR_fstatfs64 264 ++#define __NR_tgkill 265 ++#define __NR_utimes 266 ++#define __NR_fadvise64_64 267 ++#define __NR_mbind 268 ++#define __NR_get_mempolicy 269 ++#define __NR_set_mempolicy 270 ++#define __NR_mq_open 271 ++#define __NR_mq_unlink 272 ++#define __NR_mq_timedsend 273 ++#define __NR_mq_timedreceive 274 ++#define __NR_mq_notify 275 ++#define __NR_mq_getsetattr 276 ++#define __NR_waitid 277 ++#define __NR_sys_setaltroot 278 ++#define __NR_add_key 279 ++#define __NR_request_key 280 ++#define __NR_keyctl 281 ++ ++#define NR_syscalls 282 ++ ++/* user-visible error numbers are in the range -1 - -122: see ++ */ ++ ++#define __syscall_return(type, res) \ ++do { \ ++ if ((unsigned long)(res) >= (unsigned long)(-125)) { \ ++ \ ++ /* avoid using res which is declared to be in \ ++ register r2; errno might expand to a function \ ++ call and clobber it. */ \ ++ \ ++ int __err = -(res); \ ++ errno = __err; \ ++ res = -1; \ ++ } \ ++ return (type) (res); \ ++} while (0) ++ ++#define _syscall0(type,name) \ ++type name(void) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall1 arg a ++//;dgt2;tmp; already being in r4 ? ++#define _syscall1(type,name,atype,a) \ ++type name(atype a) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall2 args a,b ++//;dgt2;tmp; already being in r4,r5 ? ++#define _syscall2(type,name,atype,a,btype,b) \ ++type name(atype a,btype b) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall3 args a,b,c ++//;dgt2;tmp; already being in r4,r5,r6 ? ++#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ ++type name(atype a,btype b,ctype c) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ " mov r6, %5\n\t" /* (long) c */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ , "r" ((long) c) /* %5 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ , "r6" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall4 args a,b,c,d ++//;dgt2;tmp; already being in r4,r5,r6,r7 ? ++#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ ++type name (atype a, btype b, ctype c, dtype d) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ " mov r6, %5\n\t" /* (long) c */ \ ++ " mov r7, %6\n\t" /* (long) d */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ , "r" ((long) c) /* %5 */ \ ++ , "r" ((long) d) /* %6 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ , "r6" /* Clobbered */ \ ++ , "r7" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall5 args a,b,c,d ++//;dgt2;tmp; already being in r4,r5,r6,r7 ? ++#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ ++type name (atype a,btype b,ctype c,dtype d,etype e) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ " mov r6, %5\n\t" /* (long) c */ \ ++ " mov r7, %6\n\t" /* (long) c */ \ ++ " mov r8, %7\n\t" /* (long) e */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ , "r" ((long) c) /* %5 */ \ ++ , "r" ((long) d) /* %6 */ \ ++ , "r" ((long) e) /* %7 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ , "r6" /* Clobbered */ \ ++ , "r7" /* Clobbered */ \ ++ , "r8" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall6 args a,b,c,d ++//;dgt2;tmp; already being in r4,r5,r6,r7 ? ++#define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \ ++type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ " mov r6, %5\n\t" /* (long) c */ \ ++ " mov r7, %6\n\t" /* (long) c */ \ ++ " mov r8, %7\n\t" /* (long) e */ \ ++ " mov r9, %8\n\t" /* (long) f */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ , "r" ((long) c) /* %5 */ \ ++ , "r" ((long) d) /* %6 */ \ ++ , "r" ((long) e) /* %7 */ \ ++ , "r" ((long) f) /* %8 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ , "r6" /* Clobbered */ \ ++ , "r7" /* Clobbered */ \ ++ , "r8" /* Clobbered */ \ ++ , "r9" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++#ifdef __KERNEL__ ++#define __ARCH_WANT_IPC_PARSE_VERSION ++#define __ARCH_WANT_OLD_READDIR ++#define __ARCH_WANT_OLD_STAT ++#define __ARCH_WANT_STAT64 ++#define __ARCH_WANT_SYS_ALARM ++#define __ARCH_WANT_SYS_GETHOSTNAME ++#define __ARCH_WANT_SYS_PAUSE ++#define __ARCH_WANT_SYS_SGETMASK ++#define __ARCH_WANT_SYS_SIGNAL ++#define __ARCH_WANT_SYS_TIME ++#define __ARCH_WANT_SYS_UTIME ++#define __ARCH_WANT_SYS_WAITPID ++#define __ARCH_WANT_SYS_SOCKETCALL ++#define __ARCH_WANT_SYS_FADVISE64 ++#define __ARCH_WANT_SYS_GETPGRP ++#define __ARCH_WANT_SYS_LLSEEK ++#define __ARCH_WANT_SYS_NICE ++#define __ARCH_WANT_SYS_OLD_GETRLIMIT ++#define __ARCH_WANT_SYS_OLDUMOUNT ++#define __ARCH_WANT_SYS_SIGPENDING ++#define __ARCH_WANT_SYS_SIGPROCMASK ++#define __ARCH_WANT_SYS_RT_SIGACTION ++#endif ++ ++#ifdef __KERNEL_SYSCALLS__ ++ ++/* ++ * we need this inline - forking from kernel space will result ++ * in NO COPY ON WRITE (!!!), until an execve is executed. This ++ * is no problem, but for the stack. This is handled by not letting ++ * main() use the stack at all after fork(). Thus, no function ++ * calls - which means inline code for fork too, as otherwise we ++ * would use the stack upon exit from 'fork()'. ++ * ++ * Actually only pause and fork are needed inline, so that there ++ * won't be any messing with the stack from main(), but we define ++ * some others too. ++ */ ++#define __NR__exit __NR_exit ++static inline _syscall0(int,pause) ++static inline _syscall0(int,sync) ++static inline _syscall0(pid_t,setsid) ++static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) ++static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) ++static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) ++static inline _syscall1(int,dup,int,fd) ++static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) ++static inline _syscall3(int,open,const char *,file,int,flag,int,mode) ++static inline _syscall1(int,close,int,fd) ++static inline _syscall1(int,_exit,int,exitcode) ++static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) ++static inline _syscall1(int,delete_module,const char *,name) ++ ++static inline pid_t wait(int * wait_stat) ++{ ++ return waitpid(-1,wait_stat,0); ++} ++ ++#endif ++ ++/* ++ * "Conditional" syscalls ++ * ++ * What we want is __attribute__((weak,alias("sys_ni_syscall"))), ++ * but it doesn't work on all toolchains, so we just do it by hand ++ */ ++#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); ++ ++#endif /* _ASM_NIOS_UNISTD_H_ */ +--- linux/include/asm-nios2nommu/user.h ++++ linux/include/asm-nios2nommu/user.h +@@ -0,0 +1,112 @@ ++#ifndef _NIOS2NOMMU_USER_H ++#define _NIOS2NOMMU_USER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/user.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* Core file format: The core file is written in such a way that gdb ++ can understand it and provide useful information to the user (under ++ linux we use the 'trad-core' bfd). There are quite a number of ++ obstacles to being able to view the contents of the floating point ++ registers, and until these are solved you will not be able to view the ++ contents of them. Actually, you can read in the core file and look at ++ the contents of the user struct to find out what the floating point ++ registers contain. ++ The actual file contents are as follows: ++ UPAGE: 1 page consisting of a user struct that tells gdb what is present ++ in the file. Directly after this is a copy of the task_struct, which ++ is currently not used by gdb, but it may come in useful at some point. ++ All of the registers are stored as part of the upage. The upage should ++ always be only one page. ++ DATA: The data area is stored. We use current->end_text to ++ current->brk to pick up all of the user variables, plus any memory ++ that may have been malloced. No attempt is made to determine if a page ++ is demand-zero or if a page is totally unused, we just cover the entire ++ range. All of the addresses are rounded in such a way that an integral ++ number of pages is written. ++ STACK: We need the stack information in order to get a meaningful ++ backtrace. We need to write the data from (esp) to ++ current->start_stack, so we round each of these off in order to be able ++ to write an integer number of pages. ++ The minimum core file size is 3 pages, or 12288 bytes. ++*/ ++ ++struct user_m68kfp_struct { ++ unsigned long fpregs[8*3]; /* fp0-fp7 registers */ ++ unsigned long fpcntl[3]; /* fp control regs */ ++}; ++ ++/* This is needs more work, probably should look like gdb useage */ ++struct user_regs_struct { ++ long r1,r2,r3,r4,r5,r6,r7,r8; ++ long r9,r10,r11,r12,r13,r14,r15; ++ long r16,r17,r18,r19,r20,r21,r22,r23; ++ long gp; ++ long sp; ++ long ra; ++ long fp; ++ long orig_r2; ++ long estatus; ++ long status_extension; ++ long ea; ++}; ++ ++ ++/* When the kernel dumps core, it starts by dumping the user struct - ++ this will be used by gdb to figure out where the data and stack segments ++ are within the file, and what virtual addresses to use. */ ++struct user{ ++/* We start with the registers, to mimic the way that "memory" is returned ++ from the ptrace(3,...) function. */ ++ struct user_regs_struct regs; /* Where the registers are actually stored */ ++/* ptrace does not yet supply these. Someday.... */ ++ int u_fpvalid; /* True if math co-processor being used. */ ++ /* for this mess. Not yet used. */ ++ struct user_m68kfp_struct m68kfp; /* Math Co-processor registers. */ ++/* The rest of this junk is to help gdb figure out what goes where */ ++ unsigned long int u_tsize; /* Text segment size (pages). */ ++ unsigned long int u_dsize; /* Data segment size (pages). */ ++ unsigned long int u_ssize; /* Stack segment size (pages). */ ++ unsigned long start_code; /* Starting virtual address of text. */ ++ unsigned long start_stack; /* Starting virtual address of stack area. ++ This is actually the bottom of the stack, ++ the top of the stack is always found in the ++ esp register. */ ++ long int signal; /* Signal that caused the core dump. */ ++ int reserved; /* No longer used */ ++ struct user_regs_struct *u_ar0; ++ /* Used by gdb to help find the values for */ ++ /* the registers. */ ++ struct user_m68kfp_struct* u_fpstate; /* Math Co-processor pointer. */ ++ unsigned long magic; /* To uniquely identify a core file */ ++ char u_comm[32]; /* User command that was responsible */ ++}; ++#define NBPG PAGE_SIZE ++#define UPAGES 1 ++#define HOST_TEXT_START_ADDR (u.start_code) ++#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) ++ ++#endif +--- linux/include/asm-nios2nommu/virtconvert.h ++++ linux/include/asm-nios2nommu/virtconvert.h +@@ -0,0 +1,47 @@ ++#ifndef __NIOS_VIRT_CONVERT__ ++#define __NIOS_VIRT_CONVERT__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/virtconvert.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * Macros used for converting between virtual and physical mappings. ++ */ ++ ++#ifdef __KERNEL__ ++ ++// #include ++#include ++#include ++ ++#define mm_ptov(vaddr) ((void *) (vaddr)) ++#define mm_vtop(vaddr) ((unsigned long) (vaddr)) ++#define phys_to_virt(vaddr) ((void *) (vaddr)) ++#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) ++ ++#define virt_to_bus virt_to_phys ++#define bus_to_virt phys_to_virt ++ ++#endif /*__KERNEL__ */ ++#endif /*__NIOS_VIRT_CONVERT__*/ diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11.0-mips-nptl.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11.0-mips-nptl.patch new file mode 100644 index 0000000000..72571b05e9 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11.0-mips-nptl.patch @@ -0,0 +1,75 @@ +diff -urN linux-libc-headers-2.6.11.0/include/asm-mips/inst.h linux-libc-headers-2.6.11.0-nptl/include/asm-mips/inst.h +--- linux-libc-headers-2.6.11.0/include/asm-mips/inst.h 2004-10-31 13:54:20.000000000 -0600 ++++ linux-libc-headers-2.6.11.0-nptl/include/asm-mips/inst.h 2005-05-04 23:15:45.890613280 -0500 +@@ -28,7 +28,7 @@ + sdl_op, sdr_op, swr_op, cache_op, + ll_op, lwc1_op, lwc2_op, pref_op, + lld_op, ldc1_op, ldc2_op, ld_op, +- sc_op, swc1_op, swc2_op, major_3b_op, /* Opcode 0x3b is unused */ ++ sc_op, swc1_op, swc2_op, rdhwr_op, + scd_op, sdc1_op, sdc2_op, sd_op + }; + +diff -urN linux-libc-headers-2.6.11.0/include/asm-mips/unistd.h linux-libc-headers-2.6.11.0-nptl/include/asm-mips/unistd.h +--- linux-libc-headers-2.6.11.0/include/asm-mips/unistd.h 2005-01-08 08:02:51.000000000 -0600 ++++ linux-libc-headers-2.6.11.0-nptl/include/asm-mips/unistd.h 2005-05-04 23:16:48.240229738 -0500 +@@ -303,16 +303,17 @@ + #define __NR_add_key (__NR_Linux + 280) + #define __NR_request_key (__NR_Linux + 281) + #define __NR_keyctl (__NR_Linux + 282) ++#define __NR_set_thread_area (__NR_Linux + 283) + + /* + * Offset of the last Linux o32 flavoured syscall + */ +-#define __NR_Linux_syscalls 282 ++#define __NR_Linux_syscalls 283 + + #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ + + #define __NR_O32_Linux 4000 +-#define __NR_O32_Linux_syscalls 282 ++#define __NR_O32_Linux_syscalls 283 + + #if _MIPS_SIM == _MIPS_SIM_ABI64 + +@@ -562,16 +563,17 @@ + #define __NR_add_key (__NR_Linux + 239) + #define __NR_request_key (__NR_Linux + 240) + #define __NR_keyctl (__NR_Linux + 241) ++#define __NR_set_thread_area (__NR_Linux + 242) + + /* + * Offset of the last Linux 64-bit flavoured syscall + */ +-#define __NR_Linux_syscalls 241 ++#define __NR_Linux_syscalls 242 + + #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ + + #define __NR_64_Linux 5000 +-#define __NR_64_Linux_syscalls 241 ++#define __NR_64_Linux_syscalls 242 + + #if _MIPS_SIM == _MIPS_SIM_NABI32 + +@@ -825,16 +827,17 @@ + #define __NR_add_key (__NR_Linux + 243) + #define __NR_request_key (__NR_Linux + 244) + #define __NR_keyctl (__NR_Linux + 245) ++#define __NR_set_thread_area (__NR_Linux + 246) + + /* + * Offset of the last N32 flavoured syscall + */ +-#define __NR_Linux_syscalls 245 ++#define __NR_Linux_syscalls 246 + + #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ + + #define __NR_N32_Linux 6000 +-#define __NR_N32_Linux_syscalls 245 ++#define __NR_N32_Linux_syscalls 246 + + #ifndef __ASSEMBLY__ + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11.0.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11.0.patch new file mode 100644 index 0000000000..f528b8b4c3 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.11.0.patch @@ -0,0 +1,18 @@ +--- linux/include/linux/netfilter_ipv4/ip_nat.h.orig 2005-03-21 16:18:40.000000000 -0700 ++++ linux/include/linux/netfilter_ipv4/ip_nat.h 2005-03-21 16:23:54.000000000 -0700 +@@ -66,6 +66,15 @@ + struct ip_conntrack_manip manip; + }; + ++/* For backwards compat: don't use in modern code. */ ++struct ip_nat_multi_range_compat ++{ ++ unsigned int rangesize; /* Must be 1. */ ++ ++ /* hangs off end. */ ++ struct ip_nat_range range[1]; ++}; ++ + #define ip_nat_multi_range ip_nat_multi_range_compat + + #endif diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-arm-eabi.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-arm-eabi.patch new file mode 100644 index 0000000000..dcbd21b0a1 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-arm-eabi.patch @@ -0,0 +1,166 @@ +--- linux-libc-headers-2.6.12.0/include/asm-arm/unistd.h 2005-07-06 03:17:41.000000000 +0300 ++++ linux-libc-headers-2.6.12.0-arm-eabi/include/asm-arm/unistd.h 2006-06-05 17:14:09.000000000 +0300 +@@ -15,10 +15,12 @@ + + #include + +-#if defined(__thumb__) ++#define __NR_OABI_SYSCALL_BASE 0x900000 ++ ++#if defined(__thumb__) || defined(__ARM_EABI__) + #define __NR_SYSCALL_BASE 0 + #else +-#define __NR_SYSCALL_BASE 0x900000 ++#define __NR_SYSCALL_BASE __NR_OABI_SYSCALL_BASE + #endif + + /* +@@ -365,13 +375,13 @@ + #define __sys1(x) __sys2(x) + + #ifndef __syscall +-#if defined(__thumb__) +-#define __syscall(name) \ +- "push {r7}\n\t" \ +- "mov r7, #" __sys1(__NR_##name) "\n\t" \ +- "swi 0\n\t" \ +- "pop {r7}" ++#if defined(__thumb__) || defined(__ARM_EABI__) ++#define __SYS_REG(name) register long __sysreg __asm__("r7") = __NR_##name; ++#define __SYS_REG_LIST(regs...) "r" (__sysreg) , ##regs ++#define __syscall(name) "swi\t0" + #else ++#define __SYS_REG(name) ++#define __SYS_REG_LIST(regs...) regs + #define __syscall(name) "swi\t" __sys1(__NR_##name) "" + #endif + #endif +@@ -387,33 +397,34 @@ + + #define _syscall0(type,name) \ + type name(void) { \ ++ __SYS_REG(name) \ + register long __res_r0 __asm__("r0"); \ + long __res; \ + __asm__ __volatile__ ( \ + __syscall(name) \ + : "=r" (__res_r0) \ +- : \ +- : "lr"); \ ++ : __SYS_REG_LIST() ); \ + __res = __res_r0; \ + __syscall_return(type,__res); \ + } + + #define _syscall1(type,name,type1,arg1) \ + type name(type1 arg1) { \ ++ __SYS_REG(name) \ + register long __r0 __asm__("r0") = (long)arg1; \ + register long __res_r0 __asm__("r0"); \ + long __res; \ + __asm__ __volatile__ ( \ + __syscall(name) \ + : "=r" (__res_r0) \ +- : "r" (__r0) \ +- : "lr"); \ ++ : __SYS_REG_LIST( "0" (__r0) ) ); \ + __res = __res_r0; \ + __syscall_return(type,__res); \ + } + + #define _syscall2(type,name,type1,arg1,type2,arg2) \ + type name(type1 arg1,type2 arg2) { \ ++ __SYS_REG(name) \ + register long __r0 __asm__("r0") = (long)arg1; \ + register long __r1 __asm__("r1") = (long)arg2; \ + register long __res_r0 __asm__("r0"); \ +@@ -421,8 +432,7 @@ + __asm__ __volatile__ ( \ + __syscall(name) \ + : "=r" (__res_r0) \ +- : "r" (__r0),"r" (__r1) \ +- : "lr"); \ ++ : __SYS_REG_LIST( "0" (__r0), "r" (__r1) ) ); \ + __res = __res_r0; \ + __syscall_return(type,__res); \ + } +@@ -430,6 +440,7 @@ + + #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ + type name(type1 arg1,type2 arg2,type3 arg3) { \ ++ __SYS_REG(name) \ + register long __r0 __asm__("r0") = (long)arg1; \ + register long __r1 __asm__("r1") = (long)arg2; \ + register long __r2 __asm__("r2") = (long)arg3; \ +@@ -438,8 +449,7 @@ + __asm__ __volatile__ ( \ + __syscall(name) \ + : "=r" (__res_r0) \ +- : "r" (__r0),"r" (__r1),"r" (__r2) \ +- : "lr"); \ ++ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2) ) ); \ + __res = __res_r0; \ + __syscall_return(type,__res); \ + } +@@ -447,6 +457,7 @@ + + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\ + type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ __SYS_REG(name) \ + register long __r0 __asm__("r0") = (long)arg1; \ + register long __r1 __asm__("r1") = (long)arg2; \ + register long __r2 __asm__("r2") = (long)arg3; \ +@@ -456,8 +467,7 @@ + __asm__ __volatile__ ( \ + __syscall(name) \ + : "=r" (__res_r0) \ +- : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3) \ +- : "lr"); \ ++ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) ) ); \ + __res = __res_r0; \ + __syscall_return(type,__res); \ + } +@@ -465,6 +475,7 @@ + + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ + type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ ++ __SYS_REG(name) \ + register long __r0 __asm__("r0") = (long)arg1; \ + register long __r1 __asm__("r1") = (long)arg2; \ + register long __r2 __asm__("r2") = (long)arg3; \ +@@ -475,14 +486,15 @@ + __asm__ __volatile__ ( \ + __syscall(name) \ + : "=r" (__res_r0) \ +- : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3),"r" (__r4) \ +- : "lr"); \ ++ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), \ ++ "r" (__r3), "r" (__r4) ) ); \ + __res = __res_r0; \ + __syscall_return(type,__res); \ + } + + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ + type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) { \ ++ __SYS_REG(name) \ + register long __r0 __asm__("r0") = (long)arg1; \ + register long __r1 __asm__("r1") = (long)arg2; \ + register long __r2 __asm__("r2") = (long)arg3; \ +@@ -494,14 +506,15 @@ + __asm__ __volatile__ ( \ + __syscall(name) \ + : "=r" (__res_r0) \ +- : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3), "r" (__r4),"r" (__r5) \ +- : "lr"); \ ++ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), \ ++ "r" (__r3), "r" (__r4), "r" (__r5) ) ); \ + __res = __res_r0; \ + __syscall_return(type,__res); \ + } + + #ifdef __KERNEL_SYSCALLS__ + ++#include + #include + #include + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-config-base-small.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-config-base-small.patch new file mode 100644 index 0000000000..b6bbfd64ab --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-config-base-small.patch @@ -0,0 +1,30 @@ +diff -urN linux-libc-headers-2.6.12.0/include/linux/threads.h linux-libc-headers-2.6.12.0-patched/include/linux/threads.h +--- linux-libc-headers-2.6.12.0/include/linux/threads.h 2005-07-05 19:17:23.000000000 -0500 ++++ linux-libc-headers-2.6.12.0-patched/include/linux/threads.h 2005-08-18 11:39:15.000000000 -0500 +@@ -24,12 +24,11 @@ + /* + * This controls the default maximum pid allocated to a process + */ +-#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000) ++#define PID_MAX_DEFAULT 0x8000 + + /* + * A maximum of 4 million PIDs should be enough for a while: + */ +-#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \ +- (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT)) ++#define PID_MAX_LIMIT (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT) + + #endif +diff -urN linux-libc-headers-2.6.12.0/include/linux/vt_kern.h linux-libc-headers-2.6.12.0-patched/include/linux/vt_kern.h +--- linux-libc-headers-2.6.12.0/include/linux/vt_kern.h 2005-07-05 19:17:23.000000000 -0500 ++++ linux-libc-headers-2.6.12.0-patched/include/linux/vt_kern.h 2005-08-18 11:39:30.000000000 -0500 +@@ -77,7 +77,7 @@ + * we can easily avoid touching user space while holding the console spinlock. + */ + +-#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) ++#define CON_BUF_SIZE PAGE_SIZE + extern char con_buf[CON_BUF_SIZE]; + extern struct semaphore con_buf_sem; + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-i2c_msg.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-i2c_msg.patch new file mode 100644 index 0000000000..2c1eac3f8b --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-i2c_msg.patch @@ -0,0 +1,12 @@ +diff -urpN linux-libc-headers-2.6.12.0/include/linux/i2c-dev.h linux-libc-headers-2.6.12.0-patched/include/linux/i2c-dev.h +--- linux-libc-headers-2.6.12.0/include/linux/i2c-dev.h 2005-07-06 02:17:21.000000000 +0200 ++++ linux-libc-headers-2.6.12.0-patched/include/linux/i2c-dev.h 2006-04-26 13:10:56.000000000 +0200 +@@ -44,8 +44,6 @@ struct i2c_msg { + #define I2C_M_NO_RD_ACK 0x0800 + short len; /* msg length */ + char *buf; /* pointer to msg data */ +- int err; +- short done; + }; + + /* To determine what functionality is present */ diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-mips-nptl.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-mips-nptl.patch new file mode 100644 index 0000000000..5f7167b62b --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.12.0-mips-nptl.patch @@ -0,0 +1,90 @@ +diff -urN linux-libc-headers-2.6.12.0/include/asm-mips/inst.h linux-libc-headers-2.6.12.0-mips-nptl/include/asm-mips/inst.h +--- linux-libc-headers-2.6.12.0/include/asm-mips/inst.h 2004-10-31 13:54:20.000000000 -0600 ++++ linux-libc-headers-2.6.12.0-mips-nptl/include/asm-mips/inst.h 2005-08-10 21:20:57.000000000 -0500 +@@ -28,7 +28,7 @@ + sdl_op, sdr_op, swr_op, cache_op, + ll_op, lwc1_op, lwc2_op, pref_op, + lld_op, ldc1_op, ldc2_op, ld_op, +- sc_op, swc1_op, swc2_op, major_3b_op, /* Opcode 0x3b is unused */ ++ sc_op, swc1_op, swc2_op, rdhwr_op, + scd_op, sdc1_op, sdc2_op, sd_op + }; + +@@ -62,10 +62,10 @@ + spimi_op, unused_rt_op_0x05, unused_rt_op_0x06, unused_rt_op_0x07, + tgei_op, tgeiu_op, tlti_op, tltiu_op, + teqi_op, unused_0x0d_rt_op, tnei_op, unused_0x0f_rt_op, +- bltzal_op, bgezal_op, bltzall_op, bgezall_op +- /* +- * The others (0x14 - 0x1f) are unused. +- */ ++ bltzal_op, bgezal_op, bltzall_op, bgezall_op, ++ rt_op_0x14, rt_op_0x15, rt_op_0x16, rt_op_0x17, ++ rt_op_0x18, rt_op_0x19, rt_op_0x1a, rt_op_0x1b, ++ bposge32_op, rt_op_0x1d, rt_op_0x1e, rt_op_0x1f + }; + + /* +diff -urN linux-libc-headers-2.6.12.0/include/asm-mips/unistd.h linux-libc-headers-2.6.12.0-mips-nptl/include/asm-mips/unistd.h +--- linux-libc-headers-2.6.12.0/include/asm-mips/unistd.h 2005-07-05 19:17:29.000000000 -0500 ++++ linux-libc-headers-2.6.12.0-mips-nptl/include/asm-mips/unistd.h 2005-08-10 21:22:27.000000000 -0500 +@@ -303,16 +303,17 @@ + #define __NR_add_key (__NR_Linux + 280) + #define __NR_request_key (__NR_Linux + 281) + #define __NR_keyctl (__NR_Linux + 282) ++#define __NR_set_thread_area (__NR_Linux + 283) + + /* + * Offset of the last Linux o32 flavoured syscall + */ +-#define __NR_Linux_syscalls 282 ++#define __NR_Linux_syscalls 283 + + #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ + + #define __NR_O32_Linux 4000 +-#define __NR_O32_Linux_syscalls 282 ++#define __NR_O32_Linux_syscalls 283 + + #if _MIPS_SIM == _MIPS_SIM_ABI64 + +@@ -562,16 +563,17 @@ + #define __NR_add_key (__NR_Linux + 239) + #define __NR_request_key (__NR_Linux + 240) + #define __NR_keyctl (__NR_Linux + 241) ++#define __NR_set_thread_area (__NR_Linux + 242) + + /* + * Offset of the last Linux 64-bit flavoured syscall + */ +-#define __NR_Linux_syscalls 241 ++#define __NR_Linux_syscalls 242 + + #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ + + #define __NR_64_Linux 5000 +-#define __NR_64_Linux_syscalls 241 ++#define __NR_64_Linux_syscalls 242 + + #if _MIPS_SIM == _MIPS_SIM_NABI32 + +@@ -825,16 +827,17 @@ + #define __NR_add_key (__NR_Linux + 243) + #define __NR_request_key (__NR_Linux + 244) + #define __NR_keyctl (__NR_Linux + 245) ++#define __NR_set_thread_area (__NR_Linux + 246) + + /* + * Offset of the last N32 flavoured syscall + */ +-#define __NR_Linux_syscalls 245 ++#define __NR_Linux_syscalls 246 + + #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ + + #define __NR_N32_Linux 6000 +-#define __NR_N32_Linux_syscalls 245 ++#define __NR_N32_Linux_syscalls 246 + + #ifndef __ASSEMBLY__ + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.8-cleanup.patch b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.8-cleanup.patch new file mode 100644 index 0000000000..44461d1abf --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.8-cleanup.patch @@ -0,0 +1,8153 @@ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/addrspace.h linux-libc-headers-2.6.8.0/include/asm-mips/addrspace.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/addrspace.h 2004-03-28 07:51:50.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/addrspace.h 2004-08-26 05:53:12.000000000 -0500 +@@ -10,7 +10,23 @@ + #ifndef _ASM_ADDRSPACE_H + #define _ASM_ADDRSPACE_H + +-#include ++/**********************************************************************/ ++/* Include the common bits for #include */ ++#ifndef __mips64 ++ ++#define CAC_BASE 0x80000000 ++#define IO_BASE 0xa0000000 ++#define UNCAC_BASE 0xa0000000 ++#define MAP_BASE 0xc0000000 ++ ++/* ++ * This handles the memory map. ++ * We handle pages at KSEG0 for kernels with 32 bit address space. ++ */ ++#define PAGE_OFFSET 0x80000000UL ++ ++#endif /* ndef __mips64 */ ++/**********************************************************************/ + + /* + * Configure language +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/asmmacro.h linux-libc-headers-2.6.8.0/include/asm-mips/asmmacro.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/asmmacro.h 2004-08-18 13:15:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/asmmacro.h 2004-08-26 05:14:41.000000000 -0500 +@@ -9,10 +9,10 @@ + #define _ASM_ASMMACRO_H + + +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + #include + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + #include + #endif + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/checksum.h linux-libc-headers-2.6.8.0/include/asm-mips/checksum.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/checksum.h 2004-06-23 16:52:45.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/checksum.h 2004-08-26 05:14:41.000000000 -0500 +@@ -125,7 +125,7 @@ + { + __asm__( + ".set\tnoat\t\t\t# csum_tcpudp_nofold\n\t" +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + "addu\t%0, %2\n\t" + "sltu\t$1, %0, %2\n\t" + "addu\t%0, $1\n\t" +@@ -138,7 +138,7 @@ + "sltu\t$1, %0, %4\n\t" + "addu\t%0, $1\n\t" + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + "daddu\t%0, %2\n\t" + "daddu\t%0, %3\n\t" + "daddu\t%0, %4\n\t" +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/compat.h linux-libc-headers-2.6.8.0/include/asm-mips/compat.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/compat.h 2003-12-15 12:47:02.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/compat.h 2004-08-26 05:23:05.000000000 -0500 +@@ -8,64 +8,64 @@ + + #define COMPAT_USER_HZ 100 + +-typedef u32 compat_size_t; +-typedef s32 compat_ssize_t; +-typedef s32 compat_time_t; +-typedef s32 compat_clock_t; +-typedef s32 compat_suseconds_t; +- +-typedef s32 compat_pid_t; +-typedef s32 compat_uid_t; +-typedef s32 compat_gid_t; +-typedef u32 compat_mode_t; +-typedef u32 compat_ino_t; +-typedef u32 compat_dev_t; +-typedef s32 compat_off_t; +-typedef s64 compat_loff_t; +-typedef u32 compat_nlink_t; +-typedef s32 compat_ipc_pid_t; +-typedef s32 compat_daddr_t; +-typedef s32 compat_caddr_t; ++typedef __u32 compat_size_t; ++typedef __s32 compat_ssize_t; ++typedef __s32 compat_time_t; ++typedef __s32 compat_clock_t; ++typedef __s32 compat_suseconds_t; ++ ++typedef __s32 compat_pid_t; ++typedef __s32 compat_uid_t; ++typedef __s32 compat_gid_t; ++typedef __u32 compat_mode_t; ++typedef __u32 compat_ino_t; ++typedef __u32 compat_dev_t; ++typedef __s32 compat_off_t; ++typedef __s64 compat_loff_t; ++typedef __u32 compat_nlink_t; ++typedef __s32 compat_ipc_pid_t; ++typedef __s32 compat_daddr_t; ++typedef __s32 compat_caddr_t; + typedef struct { +- s32 val[2]; ++ __s32 val[2]; + } compat_fsid_t; + +-typedef s32 compat_int_t; +-typedef s32 compat_long_t; +-typedef u32 compat_uint_t; +-typedef u32 compat_ulong_t; ++typedef __s32 compat_int_t; ++typedef __s32 compat_long_t; ++typedef __u32 compat_uint_t; ++typedef __u32 compat_ulong_t; + + struct compat_timespec { + compat_time_t tv_sec; +- s32 tv_nsec; ++ __s32 tv_nsec; + }; + + struct compat_timeval { + compat_time_t tv_sec; +- s32 tv_usec; ++ __s32 tv_usec; + }; + + struct compat_stat { + compat_dev_t st_dev; +- s32 st_pad1[3]; ++ __s32 st_pad1[3]; + compat_ino_t st_ino; + compat_mode_t st_mode; + compat_nlink_t st_nlink; + compat_uid_t st_uid; + compat_gid_t st_gid; + compat_dev_t st_rdev; +- s32 st_pad2[2]; ++ __s32 st_pad2[2]; + compat_off_t st_size; +- s32 st_pad3; ++ __s32 st_pad3; + compat_time_t st_atime; +- s32 st_atime_nsec; ++ __s32 st_atime_nsec; + compat_time_t st_mtime; +- s32 st_mtime_nsec; ++ __s32 st_mtime_nsec; + compat_time_t st_ctime; +- s32 st_ctime_nsec; +- s32 st_blksize; +- s32 st_blocks; +- s32 st_pad4[14]; ++ __s32 st_ctime_nsec; ++ __s32 st_blksize; ++ __s32 st_blocks; ++ __s32 st_pad4[14]; + }; + + struct compat_flock { +@@ -73,10 +73,10 @@ + short l_whence; + compat_off_t l_start; + compat_off_t l_len; +- s32 l_sysid; ++ __s32 l_sysid; + compat_pid_t l_pid; + short __unused; +- s32 pad[4]; ++ __s32 pad[4]; + }; + + #define F_GETLK64 33 +@@ -107,12 +107,12 @@ + + #define COMPAT_RLIM_INFINITY 0x7fffffffUL + +-typedef u32 compat_old_sigset_t; /* at least 32 bits */ ++typedef __u32 compat_old_sigset_t; /* at least 32 bits */ + + #define _COMPAT_NSIG 128 /* Don't ask !$@#% ... */ + #define _COMPAT_NSIG_BPW 32 + +-typedef u32 compat_sigset_word; ++typedef __u32 compat_sigset_word; + + #define COMPAT_OFF_T_MAX 0x7fffffff + #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL +@@ -123,7 +123,7 @@ + * as pointers because the syscall entry code will have + * appropriately comverted them already. + */ +-typedef u32 compat_uptr_t; ++typedef __u32 compat_uptr_t; + + static inline void *compat_ptr(compat_uptr_t uptr) + { +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/ddb5xxx/ddb5074.h linux-libc-headers-2.6.8.0/include/asm-mips/ddb5xxx/ddb5074.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/ddb5xxx/ddb5074.h 2003-12-15 12:47:03.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/ddb5xxx/ddb5074.h 2004-08-26 13:21:48.000000000 -0500 +@@ -34,5 +34,5 @@ + extern void ddb5074_led_d2(int on); + extern void ddb5074_led_d3(int on); + +-extern void nile4_irq_setup(u32 base); ++extern void nile4_irq_setup(__u32 base); + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/ddb5xxx/ddb5476.h linux-libc-headers-2.6.8.0/include/asm-mips/ddb5xxx/ddb5476.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/ddb5xxx/ddb5476.h 2003-12-15 12:47:03.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/ddb5xxx/ddb5476.h 2004-08-26 05:24:06.000000000 -0500 +@@ -145,13 +145,13 @@ + extern void nile4_enable_irq(int nile4_irq); + extern void nile4_disable_irq(int nile4_irq); + extern void nile4_disable_irq_all(void); +-extern u16 nile4_get_irq_stat(int cpu_irq); ++extern __u16 nile4_get_irq_stat(int cpu_irq); + extern void nile4_enable_irq_output(int cpu_irq); + extern void nile4_disable_irq_output(int cpu_irq); + extern void nile4_set_pci_irq_polarity(int pci_irq, int high); + extern void nile4_set_pci_irq_level_or_edge(int pci_irq, int level); + extern void nile4_clear_irq(int nile4_irq); +-extern void nile4_clear_irq_mask(u32 mask); +-extern u8 nile4_i8259_iack(void); ++extern void nile4_clear_irq_mask(__u32 mask); ++extern __u8 nile4_i8259_iack(void); + extern void nile4_dump_irq_status(void); /* Debug */ + #endif /* !__ASSEMBLY__ */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/ddb5xxx/ddb5xxx.h linux-libc-headers-2.6.8.0/include/asm-mips/ddb5xxx/ddb5xxx.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/ddb5xxx/ddb5xxx.h 2004-01-17 17:03:47.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/ddb5xxx/ddb5xxx.h 2004-08-26 05:24:01.000000000 -0500 +@@ -177,46 +177,46 @@ + * interrupt load + */ + #ifndef CONFIG_DDB5074 +- volatile u32 *p = (volatile u32 *)0xbfc00000; ++ volatile __u32 *p = (volatile __u32 *)0xbfc00000; + (void)(*p); + #endif + } + +-static inline void ddb_out32(u32 offset, u32 val) ++static inline void ddb_out32(__u32 offset, __u32 val) + { +- *(volatile u32 *)(DDB_BASE+offset) = val; ++ *(volatile __u32 *)(DDB_BASE+offset) = val; + ddb_sync(); + } + +-static inline u32 ddb_in32(u32 offset) ++static inline __u32 ddb_in32(__u32 offset) + { +- u32 val = *(volatile u32 *)(DDB_BASE+offset); ++ __u32 val = *(volatile __u32 *)(DDB_BASE+offset); + ddb_sync(); + return val; + } + +-static inline void ddb_out16(u32 offset, u16 val) ++static inline void ddb_out16(__u32 offset, __u16 val) + { +- *(volatile u16 *)(DDB_BASE+offset) = val; ++ *(volatile __u16 *)(DDB_BASE+offset) = val; + ddb_sync(); + } + +-static inline u16 ddb_in16(u32 offset) ++static inline __u16 ddb_in16(__u32 offset) + { +- u16 val = *(volatile u16 *)(DDB_BASE+offset); ++ __u16 val = *(volatile __u16 *)(DDB_BASE+offset); + ddb_sync(); + return val; + } + +-static inline void ddb_out8(u32 offset, u8 val) ++static inline void ddb_out8(__u32 offset, __u8 val) + { +- *(volatile u8 *)(DDB_BASE+offset) = val; ++ *(volatile __u8 *)(DDB_BASE+offset) = val; + ddb_sync(); + } + +-static inline u8 ddb_in8(u32 offset) ++static inline __u8 ddb_in8(__u32 offset) + { +- u8 val = *(volatile u8 *)(DDB_BASE+offset); ++ __u8 val = *(volatile __u8 *)(DDB_BASE+offset); + ddb_sync(); + return val; + } +@@ -226,10 +226,10 @@ + * Physical Device Address Registers + */ + +-extern u32 +-ddb_calc_pdar(u32 phys, u32 size, int width, int on_memory_bus, int pci_visible); ++extern __u32 ++ddb_calc_pdar(__u32 phys, __u32 size, int width, int on_memory_bus, int pci_visible); + extern void +-ddb_set_pdar(u32 pdar, u32 phys, u32 size, int width, ++ddb_set_pdar(__u32 pdar, __u32 phys, __u32 size, int width, + int on_memory_bus, int pci_visible); + + /* +@@ -248,7 +248,7 @@ + #define DDB_PCI_ACCESS_32 0x10 /* for pci init0/1 regs */ + + +-extern void ddb_set_pmr(u32 pmr, u32 type, u32 addr, u32 options); ++extern void ddb_set_pmr(__u32 pmr, __u32 type, __u32 addr, __u32 options); + + /* + * we need to reset pci bus when we start up and shutdown +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/dec/ioasic.h linux-libc-headers-2.6.8.0/include/asm-mips/dec/ioasic.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/dec/ioasic.h 2004-01-17 17:03:47.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/dec/ioasic.h 2004-08-26 05:25:44.000000000 -0500 +@@ -18,14 +18,14 @@ + + extern spinlock_t ioasic_ssr_lock; + +-extern volatile u32 *ioasic_base; ++extern volatile __u32 *ioasic_base; + +-static inline void ioasic_write(unsigned int reg, u32 v) ++static inline void ioasic_write(unsigned int reg, __u32 v) + { + ioasic_base[reg / 4] = v; + } + +-static inline u32 ioasic_read(unsigned int reg) ++static inline __u32 ioasic_read(unsigned int reg) + { + return ioasic_base[reg / 4]; + } +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/dec/kn02.h linux-libc-headers-2.6.8.0/include/asm-mips/dec/kn02.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/dec/kn02.h 2004-01-17 17:03:47.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/dec/kn02.h 2004-08-26 05:25:47.000000000 -0500 +@@ -97,7 +97,7 @@ + + + #ifndef __ASSEMBLY__ +-extern u32 cached_kn02_csr; ++extern __u32 cached_kn02_csr; + extern spinlock_t kn02_lock; + extern void init_kn02_irqs(int base); + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/elf.h linux-libc-headers-2.6.8.0/include/asm-mips/elf.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/elf.h 2004-03-28 07:51:51.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/elf.h 2004-08-26 05:17:25.000000000 -0500 +@@ -122,7 +122,7 @@ + typedef double elf_fpreg_t; + typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + + /* + * This is used to ensure we don't load something for the wrong architecture. +@@ -150,9 +150,9 @@ + */ + #define ELF_CLASS ELFCLASS32 + +-#endif /* CONFIG_MIPS32 */ ++#endif /* ndef __mips64 */ + +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + /* + * This is used to ensure we don't load something for the wrong architecture. + */ +@@ -174,7 +174,7 @@ + */ + #define ELF_CLASS ELFCLASS64 + +-#endif /* CONFIG_MIPS64 */ ++#endif /* __mips64 */ + + /* + * These are used to set parameters in the core dumps. +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/galileo-boards/ev96100.h linux-libc-headers-2.6.8.0/include/asm-mips/galileo-boards/ev96100.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/galileo-boards/ev96100.h 2004-03-28 07:51:53.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/galileo-boards/ev96100.h 2004-08-26 05:23:12.000000000 -0500 +@@ -46,9 +46,9 @@ + * bytes when running bigendian. + */ + #define __GT_READ(ofs) \ +- (*(volatile u32 *)(GT64120_BASE+(ofs))) ++ (*(volatile __u32 *)(GT64120_BASE+(ofs))) + #define __GT_WRITE(ofs, data) \ +- do { *(volatile u32 *)(GT64120_BASE+(ofs)) = (data); } while (0) ++ do { *(volatile __u32 *)(GT64120_BASE+(ofs)) = (data); } while (0) + #define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs)) + #define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data)) + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/galileo-boards/gt96100.h linux-libc-headers-2.6.8.0/include/asm-mips/galileo-boards/gt96100.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/galileo-boards/gt96100.h 2004-03-28 07:51:53.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/galileo-boards/gt96100.h 2004-08-26 05:23:17.000000000 -0500 +@@ -27,9 +27,9 @@ + #define MIPS_GT96100_BASE (KSEG1ADDR(0x14000000)) + + #define GT96100_WRITE(ofs, data) \ +- *(volatile u32 *)(MIPS_GT96100_BASE+ofs) = cpu_to_le32(data) ++ *(volatile __u32 *)(MIPS_GT96100_BASE+ofs) = cpu_to_le32(data) + #define GT96100_READ(ofs) \ +- le32_to_cpu(*(volatile u32 *)(MIPS_GT96100_BASE+ofs)) ++ le32_to_cpu(*(volatile __u32 *)(MIPS_GT96100_BASE+ofs)) + + #define GT96100_ETH_IO_SIZE 0x4000 + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/gt64120.h linux-libc-headers-2.6.8.0/include/asm-mips/gt64120.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/gt64120.h 2004-03-28 07:51:51.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/gt64120.h 2004-08-26 05:22:36.000000000 -0500 +@@ -420,9 +420,9 @@ + * bytes when running bigendian. We also provide non-swapping versions. + */ + #define __GT_READ(ofs) \ +- (*(volatile u32 *)(GT64120_BASE+(ofs))) ++ (*(volatile __u32 *)(GT64120_BASE+(ofs))) + #define __GT_WRITE(ofs, data) \ +- do { *(volatile u32 *)(GT64120_BASE+(ofs)) = (data); } while (0) ++ do { *(volatile __u32 *)(GT64120_BASE+(ofs)) = (data); } while (0) + #define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs)) + #define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data)) + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/io.h linux-libc-headers-2.6.8.0/include/asm-mips/io.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/io.h 2004-03-28 07:51:51.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/io.h 2004-08-26 05:24:16.000000000 -0500 +@@ -173,14 +173,14 @@ + unsigned long flags) + { + if (cpu_has_64bit_addresses) { +- u64 base = UNCAC_BASE; ++ __u64 base = UNCAC_BASE; + + /* + * R10000 supports a 2 bit uncached attribute therefore + * UNCAC_BASE may not equal IO_BASE. + */ + if (flags == _CACHE_UNCACHED) +- base = (u64) IO_BASE; ++ base = (__u64) IO_BASE; + return (void *) (unsigned long) (base + offset); + } + +@@ -245,10 +245,10 @@ + #define __raw_readb(addr) (*(volatile unsigned char *)(addr)) + #define __raw_readw(addr) (*(volatile unsigned short *)(addr)) + #define __raw_readl(addr) (*(volatile unsigned int *)(addr)) +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + #define ____raw_readq(addr) \ + ({ \ +- u64 __res; \ ++ __u64 __res; \ + \ + __asm__ __volatile__ ( \ + " .set mips3 # ____raw_readq \n" \ +@@ -263,7 +263,7 @@ + #define __raw_readq(addr) \ + ({ \ + unsigned long __flags; \ +- u64 __res; \ ++ __u64 __res; \ + \ + local_irq_save(__flags); \ + __res = ____raw_readq(addr); \ +@@ -271,7 +271,7 @@ + __res; \ + }) + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + #define ____raw_readq(addr) (*(volatile unsigned long *)(addr)) + #define __raw_readq(addr) ____raw_readq(addr) + #endif +@@ -288,10 +288,10 @@ + #define __raw_writeb(b,addr) ((*(volatile unsigned char *)(addr)) = (b)) + #define __raw_writew(w,addr) ((*(volatile unsigned short *)(addr)) = (w)) + #define __raw_writel(l,addr) ((*(volatile unsigned int *)(addr)) = (l)) +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + #define ____raw_writeq(val,addr) \ + ({ \ +- u64 __tmp; \ ++ __u64 __tmp; \ + \ + __asm__ __volatile__ ( \ + " .set mips3 \n" \ +@@ -313,7 +313,7 @@ + local_irq_restore(__flags); \ + }) + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + #define ____raw_writeq(q,addr) ((*(volatile unsigned long *)(addr)) = (q)) + #define __raw_writeq(q,addr) ____raw_writeq(q, addr) + #endif +@@ -400,28 +400,28 @@ + { + port = __swizzle_addr_b(port); + +- *(volatile u8 *)(mips_io_port_base + port) = __ioswab8(val); ++ *(volatile __u8 *)(mips_io_port_base + port) = __ioswab8(val); + } + + static inline void __outw(unsigned short val, unsigned long port) + { + port = __swizzle_addr_w(port); + +- *(volatile u16 *)(mips_io_port_base + port) = __ioswab16(val); ++ *(volatile __u16 *)(mips_io_port_base + port) = __ioswab16(val); + } + + static inline void __outl(unsigned int val, unsigned long port) + { + port = __swizzle_addr_l(port); + +- *(volatile u32 *)(mips_io_port_base + port) = __ioswab32(val); ++ *(volatile __u32 *)(mips_io_port_base + port) = __ioswab32(val); + } + + static inline void __outb_p(unsigned char val, unsigned long port) + { + port = __swizzle_addr_b(port); + +- *(volatile u8 *)(mips_io_port_base + port) = __ioswab8(val); ++ *(volatile __u8 *)(mips_io_port_base + port) = __ioswab8(val); + SLOW_DOWN_IO; + } + +@@ -429,7 +429,7 @@ + { + port = __swizzle_addr_w(port); + +- *(volatile u16 *)(mips_io_port_base + port) = __ioswab16(val); ++ *(volatile __u16 *)(mips_io_port_base + port) = __ioswab16(val); + SLOW_DOWN_IO; + } + +@@ -437,7 +437,7 @@ + { + port = __swizzle_addr_l(port); + +- *(volatile u32 *)(mips_io_port_base + port) = __ioswab32(val); ++ *(volatile __u32 *)(mips_io_port_base + port) = __ioswab32(val); + SLOW_DOWN_IO; + } + +@@ -452,30 +452,30 @@ + { + port = __swizzle_addr_b(port); + +- return __ioswab8(*(volatile u8 *)(mips_io_port_base + port)); ++ return __ioswab8(*(volatile __u8 *)(mips_io_port_base + port)); + } + + static inline unsigned short __inw(unsigned long port) + { + port = __swizzle_addr_w(port); + +- return __ioswab16(*(volatile u16 *)(mips_io_port_base + port)); ++ return __ioswab16(*(volatile __u16 *)(mips_io_port_base + port)); + } + + static inline unsigned int __inl(unsigned long port) + { + port = __swizzle_addr_l(port); + +- return __ioswab32(*(volatile u32 *)(mips_io_port_base + port)); ++ return __ioswab32(*(volatile __u32 *)(mips_io_port_base + port)); + } + + static inline unsigned char __inb_p(unsigned long port) + { +- u8 __val; ++ __u8 __val; + + port = __swizzle_addr_b(port); + +- __val = *(volatile u8 *)(mips_io_port_base + port); ++ __val = *(volatile __u8 *)(mips_io_port_base + port); + SLOW_DOWN_IO; + + return __ioswab8(__val); +@@ -483,11 +483,11 @@ + + static inline unsigned short __inw_p(unsigned long port) + { +- u16 __val; ++ __u16 __val; + + port = __swizzle_addr_w(port); + +- __val = *(volatile u16 *)(mips_io_port_base + port); ++ __val = *(volatile __u16 *)(mips_io_port_base + port); + SLOW_DOWN_IO; + + return __ioswab16(__val); +@@ -495,11 +495,11 @@ + + static inline unsigned int __inl_p(unsigned long port) + { +- u32 __val; ++ __u32 __val; + + port = __swizzle_addr_l(port); + +- __val = *(volatile u32 *)(mips_io_port_base + port); ++ __val = *(volatile __u32 *)(mips_io_port_base + port); + SLOW_DOWN_IO; + + return __ioswab32(__val); +@@ -515,7 +515,7 @@ + static inline void __outsb(unsigned long port, void *addr, unsigned int count) + { + while (count--) { +- outb(*(u8 *)addr, port); ++ outb(*(__u8 *)addr, port); + addr++; + } + } +@@ -523,7 +523,7 @@ + static inline void __insb(unsigned long port, void *addr, unsigned int count) + { + while (count--) { +- *(u8 *)addr = inb(port); ++ *(__u8 *)addr = inb(port); + addr++; + } + } +@@ -531,7 +531,7 @@ + static inline void __outsw(unsigned long port, void *addr, unsigned int count) + { + while (count--) { +- outw(*(u16 *)addr, port); ++ outw(*(__u16 *)addr, port); + addr += 2; + } + } +@@ -539,7 +539,7 @@ + static inline void __insw(unsigned long port, void *addr, unsigned int count) + { + while (count--) { +- *(u16 *)addr = inw(port); ++ *(__u16 *)addr = inw(port); + addr += 2; + } + } +@@ -547,7 +547,7 @@ + static inline void __outsl(unsigned long port, void *addr, unsigned int count) + { + while (count--) { +- outl(*(u32 *)addr, port); ++ outl(*(__u32 *)addr, port); + addr += 4; + } + } +@@ -555,7 +555,7 @@ + static inline void __insl(unsigned long port, void *addr, unsigned int count) + { + while (count--) { +- *(u32 *)addr = inl(port); ++ *(__u32 *)addr = inl(port); + addr += 4; + } + } +@@ -617,7 +617,7 @@ + #define __CSR_32_ADJUST 0 + #endif + +-#define csr_out32(v,a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v)) +-#define csr_in32(a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST)) ++#define csr_out32(v,a) (*(volatile __u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v)) ++#define csr_in32(a) (*(volatile __u32 *)((unsigned long)(a) + __CSR_32_ADJUST)) + + #endif /* _ASM_IO_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/ip32/mace.h linux-libc-headers-2.6.8.0/include/asm-mips/ip32/mace.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/ip32/mace.h 2004-06-09 07:00:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/ip32/mace.h 2004-08-26 05:14:41.000000000 -0500 +@@ -22,7 +22,7 @@ + #undef BIT + #define BIT(x) (1ULL << (x)) + +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + typedef struct { + volatile unsigned long long reg; + } mace64_t; +@@ -32,7 +32,7 @@ + volatile unsigned long reg; + } mace32_t; + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + typedef struct { + volatile unsigned long reg; + } mace64_t; +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/it8172/it8172.h linux-libc-headers-2.6.8.0/include/asm-mips/it8172/it8172.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/it8172/it8172.h 2003-12-15 12:47:03.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/it8172/it8172.h 2004-08-26 05:22:54.000000000 -0500 +@@ -336,13 +336,13 @@ + #define TIMER_TIDR 0x0E + + +-#define IT_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data +-#define IT_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) ++#define IT_WRITE(ofs, data) *(volatile __u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data ++#define IT_READ(ofs, data) data = *(volatile __u32 *)KSEG1ADDR((IT8172_BASE+ofs)) + +-#define IT_IO_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data +-#define IT_IO_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) ++#define IT_IO_WRITE(ofs, data) *(volatile __u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data ++#define IT_IO_READ(ofs, data) data = *(volatile __u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) + +-#define IT_IO_WRITE16(ofs, data) *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data +-#define IT_IO_READ16(ofs, data) data = *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) ++#define IT_IO_WRITE16(ofs, data) *(volatile __u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data ++#define IT_IO_READ16(ofs, data) data = *(volatile __u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) + + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/lasat/head.h linux-libc-headers-2.6.8.0/include/asm-mips/lasat/head.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/lasat/head.h 2003-12-15 12:47:03.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/lasat/head.h 2004-08-26 05:23:42.000000000 -0500 +@@ -10,12 +10,12 @@ + #ifndef _LANGUAGE_ASSEMBLY + #include + struct bootloader_header { +- u32 magic[2]; +- u32 version; +- u32 image_start; +- u32 image_size; +- u32 kernel_start; +- u32 kernel_entry; ++ __u32 magic[2]; ++ __u32 version; ++ __u32 image_start; ++ __u32 image_size; ++ __u32 kernel_start; ++ __u32 kernel_entry; + }; + #endif + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/lasat/lasat.h linux-libc-headers-2.6.8.0/include/asm-mips/lasat/lasat.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/lasat/lasat.h 2004-06-09 07:00:42.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/lasat/lasat.h 2004-08-26 05:23:50.000000000 -0500 +@@ -25,9 +25,9 @@ + #ifndef _LANGUAGE_ASSEMBLY + + extern struct lasat_misc { +- volatile u32 *reset_reg; +- volatile u32 *flash_wp_reg; +- u32 flash_wp_bit; ++ volatile __u32 *reset_reg; ++ volatile __u32 *flash_wp_reg; ++ __u32 flash_wp_bit; + } *lasat_misc; + + enum lasat_mtdparts { +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/m48t35.h linux-libc-headers-2.6.8.0/include/asm-mips/m48t35.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/m48t35.h 2004-01-17 17:03:44.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/m48t35.h 2004-08-26 05:23:39.000000000 -0500 +@@ -8,15 +8,15 @@ + extern spinlock_t rtc_lock; + + struct m48t35_rtc { +- volatile u8 pad[0x7ff8]; /* starts at 0x7ff8 */ +- volatile u8 control; +- volatile u8 sec; +- volatile u8 min; +- volatile u8 hour; +- volatile u8 day; +- volatile u8 date; +- volatile u8 month; +- volatile u8 year; ++ volatile __u8 pad[0x7ff8]; /* starts at 0x7ff8 */ ++ volatile __u8 control; ++ volatile __u8 sec; ++ volatile __u8 min; ++ volatile __u8 hour; ++ volatile __u8 day; ++ volatile __u8 date; ++ volatile __u8 month; ++ volatile __u8 year; + }; + + #define M48T35_RTC_SET 0x80 +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/mips-boards/bonito64.h linux-libc-headers-2.6.8.0/include/asm-mips/mips-boards/bonito64.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/mips-boards/bonito64.h 2004-03-28 07:51:54.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/mips-boards/bonito64.h 2004-08-26 05:21:59.000000000 -0500 +@@ -34,7 +34,7 @@ + extern unsigned long _pcictrl_bonito; + extern unsigned long _pcictrl_bonito_pcicfg; + +-#define BONITO(x) *(volatile u32 *)(_pcictrl_bonito + (x)) ++#define BONITO(x) *(volatile __u32 *)(_pcictrl_bonito + (x)) + + #endif /* __ASSEMBLY__ */ + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/mips-boards/generic.h linux-libc-headers-2.6.8.0/include/asm-mips/mips-boards/generic.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/mips-boards/generic.h 2004-03-28 07:51:54.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/mips-boards/generic.h 2004-08-26 05:22:06.000000000 -0500 +@@ -74,7 +74,7 @@ + #define MIPS_REVISION_CORID_CORE_EMUL_BON 0x63 + #define MIPS_REVISION_CORID_CORE_EMUL_MSC 0x65 + +-#define MIPS_REVISION_CORID (((*(volatile u32 *)ioremap(MIPS_REVISION_REG, 4)) >> 10) & 0x3f) ++#define MIPS_REVISION_CORID (((*(volatile __u32 *)ioremap(MIPS_REVISION_REG, 4)) >> 10) & 0x3f) + + extern unsigned int mips_revision_corid; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/mips-boards/msc01_pci.h linux-libc-headers-2.6.8.0/include/asm-mips/mips-boards/msc01_pci.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/mips-boards/msc01_pci.h 2004-03-28 07:51:54.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/mips-boards/msc01_pci.h 2004-08-26 05:22:10.000000000 -0500 +@@ -212,8 +212,8 @@ + + #define MSC01_PCI_REG_BASE _pcictrl_msc + +-#define MSC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0) +-#define MSC_READ(reg, data) do { data = *(volatile u32 *)(reg); } while (0) ++#define MSC_WRITE(reg, data) do { *(volatile __u32 *)(reg) = data; } while (0) ++#define MSC_READ(reg, data) do { data = *(volatile __u32 *)(reg); } while (0) + + /* + * Registers absolute addresses +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/mipsregs.h linux-libc-headers-2.6.8.0/include/asm-mips/mipsregs.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/mipsregs.h 2004-08-18 13:15:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/mipsregs.h 2004-08-26 13:00:51.000000000 -0500 +@@ -14,7 +14,6 @@ + #define _ASM_MIPSREGS_H + + #include +-#include + + /* + * The following macros are especially useful for __asm__ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/mmu_context.h linux-libc-headers-2.6.8.0/include/asm-mips/mmu_context.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/mmu_context.h 2004-08-18 13:15:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/mmu_context.h 2004-08-26 05:14:41.000000000 -0500 +@@ -27,12 +27,12 @@ + */ + #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ + pgd_current[smp_processor_id()] = (unsigned long)(pgd) +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + #define TLBMISS_HANDLER_SETUP() \ + write_c0_context((unsigned long) smp_processor_id() << 23); \ + TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + #define TLBMISS_HANDLER_SETUP() \ + write_c0_context((unsigned long) &pgd_current[smp_processor_id()] << 23); \ + TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/module.h linux-libc-headers-2.6.8.0/include/asm-mips/module.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/module.h 2004-08-18 13:15:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/module.h 2004-08-26 05:14:41.000000000 -0500 +@@ -21,7 +21,7 @@ + Elf64_Sxword r_addend; /* Addend. */ + } Elf64_Mips_Rela; + +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym +@@ -29,7 +29,7 @@ + + #endif + +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + + #define Elf_Shdr Elf64_Shdr + #define Elf_Sym Elf64_Sym +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/msgbuf.h linux-libc-headers-2.6.8.0/include/asm-mips/msgbuf.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/msgbuf.h 2004-01-17 17:03:44.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/msgbuf.h 2004-08-26 05:15:04.000000000 -0500 +@@ -14,25 +14,25 @@ + + struct msqid64_ds { + struct ipc64_perm msg_perm; +-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN) ++#if !defined(__mips64) && !defined(CONFIG_CPU_LITTLE_ENDIAN) + unsigned long __unused1; + #endif + __kernel_time_t msg_stime; /* last msgsnd time */ +-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN) ++#if !defined(__mips64) && defined(CONFIG_CPU_LITTLE_ENDIAN) + unsigned long __unused1; + #endif +-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN) ++#if !defined(__mips64) && !defined(CONFIG_CPU_LITTLE_ENDIAN) + unsigned long __unused2; + #endif + __kernel_time_t msg_rtime; /* last msgrcv time */ +-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN) ++#if !defined(__mips64) && defined(CONFIG_CPU_LITTLE_ENDIAN) + unsigned long __unused2; + #endif +-#if defined(CONFIG_MIPS32) && !defined(CONFIG_CPU_LITTLE_ENDIAN) ++#if !defined(__mips64) && !defined(CONFIG_CPU_LITTLE_ENDIAN) + unsigned long __unused3; + #endif + __kernel_time_t msg_ctime; /* last change time */ +-#if defined(CONFIG_MIPS32) && defined(CONFIG_CPU_LITTLE_ENDIAN) ++#if !defined(__mips64) && defined(CONFIG_CPU_LITTLE_ENDIAN) + unsigned long __unused3; + #endif + unsigned long msg_cbytes; /* current number of bytes on queue */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/nile4.h linux-libc-headers-2.6.8.0/include/asm-mips/nile4.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/nile4.h 2003-12-15 12:47:02.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/nile4.h 2004-08-26 05:22:46.000000000 -0500 +@@ -202,45 +202,45 @@ + + static inline void nile4_sync(void) + { +- volatile u32 *p = (volatile u32 *)0xbfc00000; ++ volatile __u32 *p = (volatile __u32 *)0xbfc00000; + (void)(*p); + } + +-static inline void nile4_out32(u32 offset, u32 val) ++static inline void nile4_out32(__u32 offset, __u32 val) + { +- *(volatile u32 *)(NILE4_BASE+offset) = val; ++ *(volatile __u32 *)(NILE4_BASE+offset) = val; + nile4_sync(); + } + +-static inline u32 nile4_in32(u32 offset) ++static inline __u32 nile4_in32(__u32 offset) + { +- u32 val = *(volatile u32 *)(NILE4_BASE+offset); ++ __u32 val = *(volatile __u32 *)(NILE4_BASE+offset); + nile4_sync(); + return val; + } + +-static inline void nile4_out16(u32 offset, u16 val) ++static inline void nile4_out16(__u32 offset, __u16 val) + { +- *(volatile u16 *)(NILE4_BASE+offset) = val; ++ *(volatile __u16 *)(NILE4_BASE+offset) = val; + nile4_sync(); + } + +-static inline u16 nile4_in16(u32 offset) ++static inline __u16 nile4_in16(__u32 offset) + { +- u16 val = *(volatile u16 *)(NILE4_BASE+offset); ++ __u16 val = *(volatile __u16 *)(NILE4_BASE+offset); + nile4_sync(); + return val; + } + +-static inline void nile4_out8(u32 offset, u8 val) ++static inline void nile4_out8(__u32 offset, __u8 val) + { +- *(volatile u8 *)(NILE4_BASE+offset) = val; ++ *(volatile __u8 *)(NILE4_BASE+offset) = val; + nile4_sync(); + } + +-static inline u8 nile4_in8(u32 offset) ++static inline __u8 nile4_in8(__u32 offset) + { +- u8 val = *(volatile u8 *)(NILE4_BASE+offset); ++ __u8 val = *(volatile __u8 *)(NILE4_BASE+offset); + nile4_sync(); + return val; + } +@@ -250,7 +250,7 @@ + * Physical Device Address Registers + */ + +-extern void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, ++extern void nile4_set_pdar(__u32 pdar, __u32 phys, __u32 size, int width, + int on_memory_bus, int visible); + + +@@ -276,7 +276,7 @@ + #define NILE4_PCI_IACK_BASE NILE4_PCI_IO_BASE + + +-extern void nile4_set_pmr(u32 pmr, u32 type, u32 addr); ++extern void nile4_set_pmr(__u32 pmr, __u32 type, __u32 addr); + + + /* +@@ -296,14 +296,14 @@ + extern void nile4_enable_irq(unsigned int nile4_irq); + extern void nile4_disable_irq(unsigned int nile4_irq); + extern void nile4_disable_irq_all(void); +-extern u16 nile4_get_irq_stat(int cpu_irq); ++extern __u16 nile4_get_irq_stat(int cpu_irq); + extern void nile4_enable_irq_output(int cpu_irq); + extern void nile4_disable_irq_output(int cpu_irq); + extern void nile4_set_pci_irq_polarity(int pci_irq, int high); + extern void nile4_set_pci_irq_level_or_edge(int pci_irq, int level); + extern void nile4_clear_irq(int nile4_irq); +-extern void nile4_clear_irq_mask(u32 mask); +-extern u8 nile4_i8259_iack(void); ++extern void nile4_clear_irq_mask(__u32 mask); ++extern __u8 nile4_i8259_iack(void); + extern void nile4_dump_irq_status(void); /* Debug */ + + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/paccess.h linux-libc-headers-2.6.8.0/include/asm-mips/paccess.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/paccess.h 2004-01-17 17:03:44.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/paccess.h 2004-08-26 05:17:48.000000000 -0500 +@@ -14,11 +14,12 @@ + #define _ASM_PACCESS_H + + #include ++#include + +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + #define __PA_ADDR ".word" + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + #define __PA_ADDR ".dword" + #endif + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/pci/bridge.h linux-libc-headers-2.6.8.0/include/asm-mips/pci/bridge.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/pci/bridge.h 2004-03-28 07:51:54.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/pci/bridge.h 2004-08-26 05:25:40.000000000 -0500 +@@ -48,9 +48,9 @@ + * All accesses to bridge hardware registers must be done + * using 32-bit loads and stores. + */ +-typedef u32 bridgereg_t; ++typedef __u32 bridgereg_t; + +-typedef u64 bridge_ate_t; ++typedef __u64 bridge_ate_t; + + /* pointers to bridge ATEs + * are always "pointer to volatile" +@@ -199,37 +199,37 @@ + + /* PCI Device Configuration Spaces 0x020000-0x027FFF */ + union { /* make all access sizes available. */ +- u8 c[0x1000 / 1]; +- u16 s[0x1000 / 2]; +- u32 l[0x1000 / 4]; +- u64 d[0x1000 / 8]; ++ __u8 c[0x1000 / 1]; ++ __u16 s[0x1000 / 2]; ++ __u32 l[0x1000 / 4]; ++ __u64 d[0x1000 / 8]; + union { +- u8 c[0x100 / 1]; +- u16 s[0x100 / 2]; +- u32 l[0x100 / 4]; +- u64 d[0x100 / 8]; ++ __u8 c[0x100 / 1]; ++ __u16 s[0x100 / 2]; ++ __u32 l[0x100 / 4]; ++ __u64 d[0x100 / 8]; + } f[8]; + } b_type0_cfg_dev[8]; /* 0x020000 */ + + /* PCI Type 1 Configuration Space 0x028000-0x028FFF */ + union { /* make all access sizes available. */ +- u8 c[0x1000 / 1]; +- u16 s[0x1000 / 2]; +- u32 l[0x1000 / 4]; +- u64 d[0x1000 / 8]; ++ __u8 c[0x1000 / 1]; ++ __u16 s[0x1000 / 2]; ++ __u32 l[0x1000 / 4]; ++ __u64 d[0x1000 / 8]; + } b_type1_cfg; /* 0x028000-0x029000 */ + + char _pad_029000[0x007000]; /* 0x029000-0x030000 */ + + /* PCI Interrupt Acknowledge Cycle 0x030000 */ + union { +- u8 c[8 / 1]; +- u16 s[8 / 2]; +- u32 l[8 / 4]; +- u64 d[8 / 8]; ++ __u8 c[8 / 1]; ++ __u16 s[8 / 2]; ++ __u32 l[8 / 4]; ++ __u64 d[8 / 8]; + } b_pci_iack; /* 0x030000 */ + +- u8 _pad_030007[0x04fff8]; /* 0x030008-0x07FFFF */ ++ __u8 _pad_030007[0x04fff8]; /* 0x030008-0x07FFFF */ + + /* External Address Translation Entry RAM 0x080000-0x0FFFFF */ + bridge_ate_t b_ext_ate_ram[0x10000]; +@@ -239,10 +239,10 @@ + + /* PCI/GIO Device Spaces 0x200000-0xBFFFFF */ + union { /* make all access sizes available. */ +- u8 c[0x100000 / 1]; +- u16 s[0x100000 / 2]; +- u32 l[0x100000 / 4]; +- u64 d[0x100000 / 8]; ++ __u8 c[0x100000 / 1]; ++ __u16 s[0x100000 / 2]; ++ __u32 l[0x100000 / 4]; ++ __u64 d[0x100000 / 8]; + } b_devio_raw[10]; /* 0x200000 */ + + /* b_devio macro is a bit strange; it reflects the +@@ -253,10 +253,10 @@ + + /* External Flash Proms 1,0 0xC00000-0xFFFFFF */ + union { /* make all access sizes available. */ +- u8 c[0x400000 / 1]; /* read-only */ +- u16 s[0x400000 / 2]; /* read-write */ +- u32 l[0x400000 / 4]; /* read-only */ +- u64 d[0x400000 / 8]; /* read-only */ ++ __u8 c[0x400000 / 1]; /* read-only */ ++ __u16 s[0x400000 / 2]; /* read-write */ ++ __u32 l[0x400000 / 4]; /* read-only */ ++ __u64 d[0x400000 / 8]; /* read-only */ + } b_external_flash; /* 0xC00000 */ + } bridge_t; + +@@ -266,9 +266,9 @@ + */ + typedef struct bridge_err_cmdword_s { + union { +- u32 cmd_word; ++ __u32 cmd_word; + struct { +- u32 didn:4, /* Destination ID */ ++ __u32 didn:4, /* Destination ID */ + sidn:4, /* Source ID */ + pactyp:4, /* Packet type */ + tnum:5, /* Trans Number */ +@@ -799,17 +799,17 @@ + #ifndef __ASSEMBLY__ + /* Address translation entry for mapped pci32 accesses */ + typedef union ate_u { +- u64 ent; ++ __u64 ent; + struct ate_s { +- u64 rmf:16; +- u64 addr:36; +- u64 targ:4; +- u64 reserved:3; +- u64 barrier:1; +- u64 prefetch:1; +- u64 precise:1; +- u64 coherent:1; +- u64 valid:1; ++ __u64 rmf:16; ++ __u64 addr:36; ++ __u64 targ:4; ++ __u64 reserved:3; ++ __u64 barrier:1; ++ __u64 prefetch:1; ++ __u64 precise:1; ++ __u64 coherent:1; ++ __u64 valid:1; + } field; + } ate_t; + #endif /* !__ASSEMBLY__ */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/pci_channel.h linux-libc-headers-2.6.8.0/include/asm-mips/pci_channel.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/pci_channel.h 2004-03-28 07:51:52.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/pci_channel.h 2004-08-26 05:21:47.000000000 -0500 +@@ -41,6 +41,6 @@ + /* + * board supplied pci irq fixup routine + */ +-extern int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin); ++extern int pcibios_map_irq(struct pci_dev *dev, __u8 slot, __u8 pin); + + #endif /* __ASM_PCI_CHANNEL_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/pgalloc.h linux-libc-headers-2.6.8.0/include/asm-mips/pgalloc.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/pgalloc.h 2004-06-09 07:00:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/pgalloc.h 2004-08-26 05:14:41.000000000 -0500 +@@ -85,7 +85,7 @@ + + #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) + +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + #define pgd_populate(mm, pmd, pte) BUG() + + /* +@@ -97,7 +97,7 @@ + #define __pmd_free_tlb(tlb,x) do { } while (0) + #endif + +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + + #define pgd_populate(mm, pgd, pmd) set_pgd(pgd, __pgd(pmd)) + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/prctl.h linux-libc-headers-2.6.8.0/include/asm-mips/prctl.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/prctl.h 2003-12-15 12:47:02.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/prctl.h 2004-08-26 05:21:43.000000000 -0500 +@@ -12,21 +12,21 @@ + #define PRDA ((struct prda *) PRDA_ADDRESS) + + struct prda_sys { +- pid_t t_pid; +- u32 t_hint; +- u32 t_dlactseq; +- u32 t_fpflags; +- u32 t_prid; /* processor type, $prid CP0 register */ +- u32 t_dlendseq; +- u64 t_unused1[5]; +- pid_t t_rpid; +- s32 t_resched; +- u32 t_unused[8]; +- u32 t_cpu; /* current/last cpu */ ++ pid_t t_pid; ++ __u32 t_hint; ++ __u32 t_dlactseq; ++ __u32 t_fpflags; ++ __u32 t_prid; /* processor type, $prid CP0 register */ ++ __u32 t_dlendseq; ++ __u64 t_unused1[5]; ++ pid_t t_rpid; ++ __s32 t_resched; ++ __u32 t_unused[8]; ++ __u32 t_cpu; /* current/last cpu */ + + /* FIXME: The signal information, not supported by Linux now */ +- u32 t_flags; /* if true, then the sigprocmask is in userspace */ +- u32 t_sigprocmask [1]; /* the sigprocmask */ ++ __u32 t_flags; /* if true, then the sigprocmask is in userspace */ ++ __u32 t_sigprocmask [1]; /* the sigprocmask */ + }; + + struct prda { +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/processor.h linux-libc-headers-2.6.8.0/include/asm-mips/processor.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/processor.h 2004-08-18 13:15:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/processor.h 2004-08-26 05:23:24.000000000 -0500 +@@ -102,7 +102,7 @@ + #define MCA_bus 0 + #define MCA_bus__is_a_macro /* for versions in ksyms.c */ + +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + /* + * User space process size: 2GB. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. +@@ -116,7 +116,7 @@ + #define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) + #endif + +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + /* + * User space process size: 1TB. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. TASK_SIZE +@@ -142,7 +142,7 @@ + + #define NUM_FPU_REGS 32 + +-typedef u64 fpureg_t; ++typedef __u64 fpureg_t; + + struct mips_fpu_hard_struct { + fpureg_t fpr[NUM_FPU_REGS]; +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/ptrace.h linux-libc-headers-2.6.8.0/include/asm-mips/ptrace.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/ptrace.h 2004-03-28 07:51:52.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/ptrace.h 2004-08-26 05:14:41.000000000 -0500 +@@ -27,7 +27,7 @@ + * system call/exception. As usual the registers k0/k1 aren't being saved. + */ + struct pt_regs { +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + /* Pad bytes for argument save space on the stack. */ + unsigned long pad0[6]; + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/serial.h linux-libc-headers-2.6.8.0/include/asm-mips/serial.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/serial.h 2004-08-18 13:15:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/serial.h 2004-08-26 13:21:37.000000000 -0500 +@@ -68,7 +68,7 @@ + + #define _JAZZ_SERIAL_INIT(int, base) \ + { .baud_base = JAZZ_BASE_BAUD, .irq = int, .flags = STD_COM_FLAGS, \ +- .iomem_base = (u8 *) base, .iomem_reg_shift = 0, \ ++ .iomem_base = (__u8 *) base, .iomem_reg_shift = 0, \ + .io_type = SERIAL_IO_MEM } + #define JAZZ_SERIAL_PORT_DEFNS \ + _JAZZ_SERIAL_INIT(JAZZ_SERIAL1_IRQ, JAZZ_SERIAL1_BASE), \ +@@ -243,7 +243,7 @@ + #define _JAGUAR_ATX_SERIAL_INIT(int, base) \ + { baud_base: JAGUAR_ATX_BASE_BAUD, irq: int, \ + flags: (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ +- iomem_base: (u8 *) base, iomem_reg_shift: 2, \ ++ iomem_base: (__u8 *) base, iomem_reg_shift: 2, \ + io_type: SERIAL_IO_MEM } + #define MOMENCO_JAGUAR_ATX_SERIAL_PORT_DEFNS \ + _JAGUAR_ATX_SERIAL_INIT(JAGUAR_ATX_SERIAL1_IRQ, JAGUAR_ATX_SERIAL1_BASE) +@@ -260,7 +260,7 @@ + + #define _OCELOT_SERIAL_INIT(int, base) \ + { .baud_base = OCELOT_BASE_BAUD, .irq = int, .flags = STD_COM_FLAGS, \ +- .iomem_base = (u8 *) base, .iomem_reg_shift = 2, \ ++ .iomem_base = (__u8 *) base, .iomem_reg_shift = 2, \ + .io_type = SERIAL_IO_MEM } + #define MOMENCO_OCELOT_SERIAL_PORT_DEFNS \ + _OCELOT_SERIAL_INIT(OCELOT_SERIAL1_IRQ, OCELOT_SERIAL1_BASE) +@@ -281,7 +281,7 @@ + + #define _OCELOT_G_SERIAL_INIT(int, base) \ + { .baud_base = OCELOT_G_BASE_BAUD, .irq = int, .flags = STD_COM_FLAGS,\ +- .iomem_base = (u8 *) base, .iomem_reg_shift = 2, \ ++ .iomem_base = (__u8 *) base, .iomem_reg_shift = 2, \ + .io_type = SERIAL_IO_MEM } + #define MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \ + _OCELOT_G_SERIAL_INIT(OCELOT_G_SERIAL1_IRQ, OCELOT_G_SERIAL1_BASE) +@@ -303,7 +303,7 @@ + { .baud_base = OCELOT_C_BASE_BAUD, \ + .irq = (int), \ + .flags = STD_COM_FLAGS, \ +- .iomem_base = (u8 *) base, \ ++ .iomem_base = (__u8 *) base, \ + .iomem_reg_shift = 2, \ + .io_type = SERIAL_IO_MEM \ + } +@@ -318,10 +318,10 @@ + #include + #define DDB5477_SERIAL_PORT_DEFNS \ + { .baud_base = BASE_BAUD, .irq = VRC5477_IRQ_UART0, \ +- .flags = STD_COM_FLAGS, .iomem_base = (u8*)0xbfa04200, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (__u8*)0xbfa04200, \ + .iomem_reg_shift = 3, .io_type = SERIAL_IO_MEM}, \ + { .baud_base = BASE_BAUD, .irq = VRC5477_IRQ_UART1, \ +- .flags = STD_COM_FLAGS, .iomem_base = (u8*)0xbfa04240, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (__u8*)0xbfa04240, \ + .iomem_reg_shift = 3, .io_type = SERIAL_IO_MEM}, + #else + #define DDB5477_SERIAL_PORT_DEFNS +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sgi/hpc3.h linux-libc-headers-2.6.8.0/include/asm-mips/sgi/hpc3.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sgi/hpc3.h 2003-12-15 12:47:03.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sgi/hpc3.h 2004-08-26 05:24:34.000000000 -0500 +@@ -17,8 +17,8 @@ + + /* An HPC DMA descriptor. */ + struct hpc_dma_desc { +- u32 pbuf; /* physical address of data buffer */ +- u32 cntinfo; /* counter and info bits */ ++ __u32 pbuf; /* physical address of data buffer */ ++ __u32 cntinfo; /* counter and info bits */ + #define HPCDMA_EOX 0x80000000 /* last desc in chain for tx */ + #define HPCDMA_EOR 0x80000000 /* last desc in chain for rx */ + #define HPCDMA_EOXP 0x40000000 /* end of packet for tx */ +@@ -30,15 +30,15 @@ + #define HPCDMA_OWN 0x00004000 /* Denotes ring buffer ownership on rx */ + #define HPCDMA_BCNT 0x00003fff /* size in bytes of this dma buffer */ + +- u32 pnext; /* paddr of next hpc_dma_desc if any */ ++ __u32 pnext; /* paddr of next hpc_dma_desc if any */ + }; + + /* The set of regs for each HPC3 PBUS DMA channel. */ + struct hpc3_pbus_dmacregs { +- volatile u32 pbdma_bptr; /* pbus dma channel buffer ptr */ +- volatile u32 pbdma_dptr; /* pbus dma channel desc ptr */ +- u32 _unused0[0x1000/4 - 2]; /* padding */ +- volatile u32 pbdma_ctrl; /* pbus dma channel control register has ++ volatile __u32 pbdma_bptr; /* pbus dma channel buffer ptr */ ++ volatile __u32 pbdma_dptr; /* pbus dma channel desc ptr */ ++ __u32 _unused0[0x1000/4 - 2]; /* padding */ ++ volatile __u32 pbdma_ctrl; /* pbus dma channel control register has + * copletely different meaning for read + * compared with write */ + /* read */ +@@ -55,20 +55,20 @@ + #define HPC3_PDMACTRL_FB 0x003f0000 /* Ptr to beginning of fifo */ + #define HPC3_PDMACTRL_FE 0x3f000000 /* Ptr to end of fifo */ + +- u32 _unused1[0x1000/4 - 1]; /* padding */ ++ __u32 _unused1[0x1000/4 - 1]; /* padding */ + }; + + /* The HPC3 SCSI registers, this does not include external ones. */ + struct hpc3_scsiregs { +- volatile u32 cbptr; /* current dma buffer ptr, diagnostic use only */ +- volatile u32 ndptr; /* next dma descriptor ptr */ +- u32 _unused0[0x1000/4 - 2]; /* padding */ +- volatile u32 bcd; /* byte count info */ ++ volatile __u32 cbptr; /* current dma buffer ptr, diagnostic use only */ ++ volatile __u32 ndptr; /* next dma descriptor ptr */ ++ __u32 _unused0[0x1000/4 - 2]; /* padding */ ++ volatile __u32 bcd; /* byte count info */ + #define HPC3_SBCD_BCNTMSK 0x00003fff /* bytes to transfer from/to memory */ + #define HPC3_SBCD_XIE 0x00004000 /* Send IRQ when done with cur buf */ + #define HPC3_SBCD_EOX 0x00008000 /* Indicates this is last buf in chain */ + +- volatile u32 ctrl; /* control register */ ++ volatile __u32 ctrl; /* control register */ + #define HPC3_SCTRL_IRQ 0x01 /* IRQ asserted, either dma done or parity */ + #define HPC3_SCTRL_ENDIAN 0x02 /* DMA endian mode, 0=big 1=little */ + #define HPC3_SCTRL_DIR 0x04 /* DMA direction, 1=dev2mem 0=mem2dev */ +@@ -78,9 +78,9 @@ + #define HPC3_SCTRL_CRESET 0x40 /* Resets dma channel and external controller */ + #define HPC3_SCTRL_PERR 0x80 /* Bad parity on HPC3 iface to scsi controller */ + +- volatile u32 gfptr; /* current GIO fifo ptr */ +- volatile u32 dfptr; /* current device fifo ptr */ +- volatile u32 dconfig; /* DMA configuration register */ ++ volatile __u32 gfptr; /* current GIO fifo ptr */ ++ volatile __u32 dfptr; /* current device fifo ptr */ ++ volatile __u32 dconfig; /* DMA configuration register */ + #define HPC3_SDCFG_HCLK 0x00001 /* Enable DMA half clock mode */ + #define HPC3_SDCFG_D1 0x00006 /* Cycles to spend in D1 state */ + #define HPC3_SDCFG_D2 0x00038 /* Cycles to spend in D2 state */ +@@ -92,7 +92,7 @@ + #define HPC3_SDCFG_POLL 0x08000 /* hd_dreq polarity control */ + #define HPC3_SDCFG_ERLY 0x30000 /* hd_dreq behavior control bits */ + +- volatile u32 pconfig; /* PIO configuration register */ ++ volatile __u32 pconfig; /* PIO configuration register */ + #define HPC3_SPCFG_P3 0x0003 /* Cycles to spend in P3 state */ + #define HPC3_SPCFG_P2W 0x001c /* Cycles to spend in P2 state for writes */ + #define HPC3_SPCFG_P2R 0x01e0 /* Cycles to spend in P2 state for reads */ +@@ -102,21 +102,21 @@ + #define HPC3_SPCFG_EPAR 0x4000 /* Enable parity checking for PIO */ + #define HPC3_SPCFG_FUJI 0x8000 /* Fujitsu scsi controller mode for faster dma/pio */ + +- u32 _unused1[0x1000/4 - 6]; /* padding */ ++ __u32 _unused1[0x1000/4 - 6]; /* padding */ + }; + + /* SEEQ ethernet HPC3 registers, only one seeq per HPC3. */ + struct hpc3_ethregs { + /* Receiver registers. */ +- volatile u32 rx_cbptr; /* current dma buffer ptr, diagnostic use only */ +- volatile u32 rx_ndptr; /* next dma descriptor ptr */ +- u32 _unused0[0x1000/4 - 2]; /* padding */ +- volatile u32 rx_bcd; /* byte count info */ ++ volatile __u32 rx_cbptr; /* current dma buffer ptr, diagnostic use only */ ++ volatile __u32 rx_ndptr; /* next dma descriptor ptr */ ++ __u32 _unused0[0x1000/4 - 2]; /* padding */ ++ volatile __u32 rx_bcd; /* byte count info */ + #define HPC3_ERXBCD_BCNTMSK 0x00003fff /* bytes to be sent to memory */ + #define HPC3_ERXBCD_XIE 0x20000000 /* HPC3 interrupts cpu at end of this buf */ + #define HPC3_ERXBCD_EOX 0x80000000 /* flags this as end of descriptor chain */ + +- volatile u32 rx_ctrl; /* control register */ ++ volatile __u32 rx_ctrl; /* control register */ + #define HPC3_ERXCTRL_STAT50 0x0000003f /* Receive status reg bits of Seeq8003 */ + #define HPC3_ERXCTRL_STAT6 0x00000040 /* Rdonly irq status */ + #define HPC3_ERXCTRL_STAT7 0x00000080 /* Rdonlt old/new status bit from Seeq */ +@@ -125,15 +125,15 @@ + #define HPC3_ERXCTRL_AMASK 0x00000400 /* Tells if ACTIVE inhibits PIO's to hpc3 */ + #define HPC3_ERXCTRL_RBO 0x00000800 /* Receive buffer overflow if set to 1 */ + +- volatile u32 rx_gfptr; /* current GIO fifo ptr */ +- volatile u32 rx_dfptr; /* current device fifo ptr */ +- u32 _unused1; /* padding */ +- volatile u32 rx_reset; /* reset register */ ++ volatile __u32 rx_gfptr; /* current GIO fifo ptr */ ++ volatile __u32 rx_dfptr; /* current device fifo ptr */ ++ __u32 _unused1; /* padding */ ++ volatile __u32 rx_reset; /* reset register */ + #define HPC3_ERXRST_CRESET 0x1 /* Reset dma channel and external controller */ + #define HPC3_ERXRST_CLRIRQ 0x2 /* Clear channel interrupt */ + #define HPC3_ERXRST_LBACK 0x4 /* Enable diagnostic loopback mode of Seeq8003 */ + +- volatile u32 rx_dconfig; /* DMA configuration register */ ++ volatile __u32 rx_dconfig; /* DMA configuration register */ + #define HPC3_ERXDCFG_D1 0x0000f /* Cycles to spend in D1 state for PIO */ + #define HPC3_ERXDCFG_D2 0x000f0 /* Cycles to spend in D2 state for PIO */ + #define HPC3_ERXDCFG_D3 0x00f00 /* Cycles to spend in D3 state for PIO */ +@@ -143,26 +143,26 @@ + #define HPC3_ERXDCFG_FIRQ 0x08000 /* Another bad packet timeout enable */ + #define HPC3_ERXDCFG_PTO 0x30000 /* Programmed timeout value for above two */ + +- volatile u32 rx_pconfig; /* PIO configuration register */ ++ volatile __u32 rx_pconfig; /* PIO configuration register */ + #define HPC3_ERXPCFG_P1 0x000f /* Cycles to spend in P1 state for PIO */ + #define HPC3_ERXPCFG_P2 0x00f0 /* Cycles to spend in P2 state for PIO */ + #define HPC3_ERXPCFG_P3 0x0f00 /* Cycles to spend in P3 state for PIO */ + #define HPC3_ERXPCFG_TST 0x1000 /* Diagnistic ram test feature bit */ + +- u32 _unused2[0x1000/4 - 8]; /* padding */ ++ __u32 _unused2[0x1000/4 - 8]; /* padding */ + + /* Transmitter registers. */ +- volatile u32 tx_cbptr; /* current dma buffer ptr, diagnostic use only */ +- volatile u32 tx_ndptr; /* next dma descriptor ptr */ +- u32 _unused3[0x1000/4 - 2]; /* padding */ +- volatile u32 tx_bcd; /* byte count info */ ++ volatile __u32 tx_cbptr; /* current dma buffer ptr, diagnostic use only */ ++ volatile __u32 tx_ndptr; /* next dma descriptor ptr */ ++ __u32 _unused3[0x1000/4 - 2]; /* padding */ ++ volatile __u32 tx_bcd; /* byte count info */ + #define HPC3_ETXBCD_BCNTMSK 0x00003fff /* bytes to be read from memory */ + #define HPC3_ETXBCD_ESAMP 0x10000000 /* if set, too late to add descriptor */ + #define HPC3_ETXBCD_XIE 0x20000000 /* Interrupt cpu at end of cur desc */ + #define HPC3_ETXBCD_EOP 0x40000000 /* Last byte of cur buf is end of packet */ + #define HPC3_ETXBCD_EOX 0x80000000 /* This buf is the end of desc chain */ + +- volatile u32 tx_ctrl; /* control register */ ++ volatile __u32 tx_ctrl; /* control register */ + #define HPC3_ETXCTRL_STAT30 0x0000000f /* Rdonly copy of seeq tx stat reg */ + #define HPC3_ETXCTRL_STAT4 0x00000010 /* Indicate late collision occurred */ + #define HPC3_ETXCTRL_STAT75 0x000000e0 /* Rdonly irq status from seeq */ +@@ -170,9 +170,9 @@ + #define HPC3_ETXCTRL_ACTIVE 0x00000200 /* DMA tx channel is active */ + #define HPC3_ETXCTRL_AMASK 0x00000400 /* Indicates ACTIVE inhibits PIO's */ + +- volatile u32 tx_gfptr; /* current GIO fifo ptr */ +- volatile u32 tx_dfptr; /* current device fifo ptr */ +- u32 _unused4[0x1000/4 - 4]; /* padding */ ++ volatile __u32 tx_gfptr; /* current GIO fifo ptr */ ++ volatile __u32 tx_dfptr; /* current device fifo ptr */ ++ __u32 _unused4[0x1000/4 - 4]; /* padding */ + }; + + struct hpc3_regs { +@@ -188,7 +188,7 @@ + /* Here are where the hpc3 fifo's can be directly accessed + * via PIO accesses. Under normal operation we never stick + * our grubby paws in here so it's just padding. */ +- u32 _unused0[0x18000/4]; ++ __u32 _unused0[0x18000/4]; + + /* HPC3 irq status regs. Due to a peculiar bug you need to + * look at two different register addresses to get at all of +@@ -197,42 +197,42 @@ + * reliably report bits 9:5 of the hpc3 irq status. I told + * you it was a peculiar bug. ;-) + */ +- volatile u32 istat0; /* Irq status, only bits <4:0> reliable. */ ++ volatile __u32 istat0; /* Irq status, only bits <4:0> reliable. */ + #define HPC3_ISTAT_PBIMASK 0x0ff /* irq bits for pbus devs 0 --> 7 */ + #define HPC3_ISTAT_SC0MASK 0x100 /* irq bit for scsi channel 0 */ + #define HPC3_ISTAT_SC1MASK 0x200 /* irq bit for scsi channel 1 */ + +- volatile u32 gio_misc; /* GIO misc control bits. */ ++ volatile __u32 gio_misc; /* GIO misc control bits. */ + #define HPC3_GIOMISC_ERTIME 0x1 /* Enable external timer real time. */ + #define HPC3_GIOMISC_DENDIAN 0x2 /* dma descriptor endian, 1=lit 0=big */ + +- volatile u32 eeprom; /* EEPROM data reg. */ ++ volatile __u32 eeprom; /* EEPROM data reg. */ + #define HPC3_EEPROM_EPROT 0x01 /* Protect register enable */ + #define HPC3_EEPROM_CSEL 0x02 /* Chip select */ + #define HPC3_EEPROM_ECLK 0x04 /* EEPROM clock */ + #define HPC3_EEPROM_DATO 0x08 /* Data out */ + #define HPC3_EEPROM_DATI 0x10 /* Data in */ + +- volatile u32 istat1; /* Irq status, only bits <9:5> reliable. */ +- volatile u32 bestat; /* Bus error interrupt status reg. */ ++ volatile __u32 istat1; /* Irq status, only bits <9:5> reliable. */ ++ volatile __u32 bestat; /* Bus error interrupt status reg. */ + #define HPC3_BESTAT_BLMASK 0x000ff /* Bus lane where bad parity occurred */ + #define HPC3_BESTAT_CTYPE 0x00100 /* Bus cycle type, 0=PIO 1=DMA */ + #define HPC3_BESTAT_PIDSHIFT 9 + #define HPC3_BESTAT_PIDMASK 0x3f700 /* DMA channel parity identifier */ + +- u32 _unused1[0x14000/4 - 5]; /* padding */ ++ __u32 _unused1[0x14000/4 - 5]; /* padding */ + + /* Now direct PIO per-HPC3 peripheral access to external regs. */ +- volatile u32 scsi0_ext[256]; /* SCSI channel 0 external regs */ +- u32 _unused2[0x7c00/4]; +- volatile u32 scsi1_ext[256]; /* SCSI channel 1 external regs */ +- u32 _unused3[0x7c00/4]; +- volatile u32 eth_ext[320]; /* Ethernet external registers */ +- u32 _unused4[0x3b00/4]; ++ volatile __u32 scsi0_ext[256]; /* SCSI channel 0 external regs */ ++ __u32 _unused2[0x7c00/4]; ++ volatile __u32 scsi1_ext[256]; /* SCSI channel 1 external regs */ ++ __u32 _unused3[0x7c00/4]; ++ volatile __u32 eth_ext[320]; /* Ethernet external registers */ ++ __u32 _unused4[0x3b00/4]; + + /* Per-peripheral device external registers and DMA/PIO control. */ +- volatile u32 pbus_extregs[16][256]; +- volatile u32 pbus_dmacfg[8][128]; ++ volatile __u32 pbus_extregs[16][256]; ++ volatile __u32 pbus_dmacfg[8][128]; + /* Cycles to spend in D3 for reads */ + #define HPC3_DMACFG_D3R_MASK 0x00000001 + #define HPC3_DMACFG_D3R_SHIFT 0 +@@ -262,7 +262,7 @@ + #define HPC3_DMACFG_BURST_SHIFT 22 + /* Use live pbus_dreq unsynchronized signal */ + #define HPC3_DMACFG_DRQLIVE 0x08000000 +- volatile u32 pbus_piocfg[16][64]; ++ volatile __u32 pbus_piocfg[16][64]; + /* Cycles to spend in P2 state for reads */ + #define HPC3_PIOCFG_P2R_MASK 0x00001 + #define HPC3_PIOCFG_P2R_SHIFT 0 +@@ -287,21 +287,21 @@ + #define HPC3_PIOCFG_EVENHI 0x80000 + + /* PBUS PROM control regs. */ +- volatile u32 pbus_promwe; /* PROM write enable register */ ++ volatile __u32 pbus_promwe; /* PROM write enable register */ + #define HPC3_PROM_WENAB 0x1 /* Enable writes to the PROM */ + +- u32 _unused5[0x0800/4 - 1]; +- volatile u32 pbus_promswap; /* Chip select swap reg */ ++ __u32 _unused5[0x0800/4 - 1]; ++ volatile __u32 pbus_promswap; /* Chip select swap reg */ + #define HPC3_PROM_SWAP 0x1 /* invert GIO addr bit to select prom0 or prom1 */ + +- u32 _unused6[0x0800/4 - 1]; +- volatile u32 pbus_gout; /* PROM general purpose output reg */ ++ __u32 _unused6[0x0800/4 - 1]; ++ volatile __u32 pbus_gout; /* PROM general purpose output reg */ + #define HPC3_PROM_STAT 0x1 /* General purpose status bit in gout */ + +- u32 _unused7[0x1000/4 - 1]; +- volatile u32 rtcregs[14]; /* Dallas clock registers */ +- u32 _unused8[50]; +- volatile u32 bbram[8192-50-14]; /* Battery backed ram */ ++ __u32 _unused7[0x1000/4 - 1]; ++ volatile __u32 rtcregs[14]; /* Dallas clock registers */ ++ __u32 _unused8[50]; ++ volatile __u32 bbram[8192-50-14]; /* Battery backed ram */ + }; + + /* +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sgi/ioc.h linux-libc-headers-2.6.8.0/include/asm-mips/sgi/ioc.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sgi/ioc.h 2004-03-28 07:51:54.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sgi/ioc.h 2004-08-26 05:24:48.000000000 -0500 +@@ -22,26 +22,26 @@ + */ + + struct sgioc_uart_regs { +- u8 _ctrl1[3]; +- volatile u8 ctrl1; +- u8 _data1[3]; +- volatile u8 data1; +- u8 _ctrl2[3]; +- volatile u8 ctrl2; +- u8 _data2[3]; +- volatile u8 data2; ++ __u8 _ctrl1[3]; ++ volatile __u8 ctrl1; ++ __u8 _data1[3]; ++ volatile __u8 data1; ++ __u8 _ctrl2[3]; ++ volatile __u8 ctrl2; ++ __u8 _data2[3]; ++ volatile __u8 data2; + }; + + struct sgioc_keyb_regs { +- u8 _data[3]; +- volatile u8 data; +- u8 _command[3]; +- volatile u8 command; ++ __u8 _data[3]; ++ volatile __u8 data; ++ __u8 _command[3]; ++ volatile __u8 command; + }; + + struct sgint_regs { +- u8 _istat0[3]; +- volatile u8 istat0; /* Interrupt status zero */ ++ __u8 _istat0[3]; ++ volatile __u8 istat0; /* Interrupt status zero */ + #define SGINT_ISTAT0_FFULL 0x01 + #define SGINT_ISTAT0_SCSI0 0x02 + #define SGINT_ISTAT0_SCSI1 0x04 +@@ -50,10 +50,10 @@ + #define SGINT_ISTAT0_PPORT 0x20 + #define SGINT_ISTAT0_HPC2 0x40 + #define SGINT_ISTAT0_LIO2 0x80 +- u8 _imask0[3]; +- volatile u8 imask0; /* Interrupt mask zero */ +- u8 _istat1[3]; +- volatile u8 istat1; /* Interrupt status one */ ++ __u8 _imask0[3]; ++ volatile __u8 imask0; /* Interrupt mask zero */ ++ __u8 _istat1[3]; ++ volatile __u8 istat1; /* Interrupt status one */ + #define SGINT_ISTAT1_ISDNI 0x01 + #define SGINT_ISTAT1_PWR 0x02 + #define SGINT_ISTAT1_ISDNH 0x04 +@@ -62,29 +62,29 @@ + #define SGINT_ISTAT1_AFAIL 0x20 + #define SGINT_ISTAT1_VIDEO 0x40 + #define SGINT_ISTAT1_GIO2 0x80 +- u8 _imask1[3]; +- volatile u8 imask1; /* Interrupt mask one */ +- u8 _vmeistat[3]; +- volatile u8 vmeistat; /* VME interrupt status */ +- u8 _cmeimask0[3]; +- volatile u8 cmeimask0; /* VME interrupt mask zero */ +- u8 _cmeimask1[3]; +- volatile u8 cmeimask1; /* VME interrupt mask one */ +- u8 _cmepol[3]; +- volatile u8 cmepol; /* VME polarity */ +- u8 _tclear[3]; +- volatile u8 tclear; +- u8 _errstat[3]; +- volatile u8 errstat; /* Error status reg, reserved on INT2 */ +- u32 _unused0[2]; +- u8 _tcnt0[3]; +- volatile u8 tcnt0; /* counter 0 */ +- u8 _tcnt1[3]; +- volatile u8 tcnt1; /* counter 1 */ +- u8 _tcnt2[3]; +- volatile u8 tcnt2; /* counter 2 */ +- u8 _tcword[3]; +- volatile u8 tcword; /* control word */ ++ __u8 _imask1[3]; ++ volatile __u8 imask1; /* Interrupt mask one */ ++ __u8 _vmeistat[3]; ++ volatile __u8 vmeistat; /* VME interrupt status */ ++ __u8 _cmeimask0[3]; ++ volatile __u8 cmeimask0; /* VME interrupt mask zero */ ++ __u8 _cmeimask1[3]; ++ volatile __u8 cmeimask1; /* VME interrupt mask one */ ++ __u8 _cmepol[3]; ++ volatile __u8 cmepol; /* VME polarity */ ++ __u8 _tclear[3]; ++ volatile __u8 tclear; ++ __u8 _errstat[3]; ++ volatile __u8 errstat; /* Error status reg, reserved on INT2 */ ++ __u32 _unused0[2]; ++ __u8 _tcnt0[3]; ++ volatile __u8 tcnt0; /* counter 0 */ ++ __u8 _tcnt1[3]; ++ volatile __u8 tcnt1; /* counter 1 */ ++ __u8 _tcnt2[3]; ++ volatile __u8 tcnt2; /* counter 2 */ ++ __u8 _tcword[3]; ++ volatile __u8 tcword; /* control word */ + #define SGINT_TCWORD_BCD 0x01 /* Use BCD mode for counters */ + #define SGINT_TCWORD_MMASK 0x0e /* Mode bitmask. */ + #define SGINT_TCWORD_MITC 0x00 /* IRQ on terminal count (doesn't work) */ +@@ -115,55 +115,55 @@ + #define SGINT_TCSAMP_COUNTER ((SGINT_TIMER_CLOCK / HZ) + 255) + + /* We need software copies of these because they are write only. */ +-extern u8 sgi_ioc_reset, sgi_ioc_write; ++extern __u8 sgi_ioc_reset, sgi_ioc_write; + + struct sgioc_regs { + struct pi1_regs pport; +- u32 _unused0[2]; ++ __u32 _unused0[2]; + struct sgioc_uart_regs serport; + struct sgioc_keyb_regs kbdmouse; +- u8 _gcsel[3]; +- volatile u8 gcsel; +- u8 _genctrl[3]; +- volatile u8 genctrl; +- u8 _panel[3]; +- volatile u8 panel; ++ __u8 _gcsel[3]; ++ volatile __u8 gcsel; ++ __u8 _genctrl[3]; ++ volatile __u8 genctrl; ++ __u8 _panel[3]; ++ volatile __u8 panel; + #define SGIOC_PANEL_POWERON 0x01 + #define SGIOC_PANEL_POWERINTR 0x02 + #define SGIOC_PANEL_VOLDNINTR 0x10 + #define SGIOC_PANEL_VOLDNHOLD 0x20 + #define SGIOC_PANEL_VOLUPINTR 0x40 + #define SGIOC_PANEL_VOLUPHOLD 0x80 +- u32 _unused1; +- u8 _sysid[3]; +- volatile u8 sysid; ++ __u32 _unused1; ++ __u8 _sysid[3]; ++ volatile __u8 sysid; + #define SGIOC_SYSID_FULLHOUSE 0x01 + #define SGIOC_SYSID_BOARDREV(x) ((x & 0xe0) > 5) + #define SGIOC_SYSID_CHIPREV(x) ((x & 0x1e) > 1) +- u32 _unused2; +- u8 _read[3]; +- volatile u8 read; +- u32 _unused3; +- u8 _dmasel[3]; +- volatile u8 dmasel; ++ __u32 _unused2; ++ __u8 _read[3]; ++ volatile __u8 read; ++ __u32 _unused3; ++ __u8 _dmasel[3]; ++ volatile __u8 dmasel; + #define SGIOC_DMASEL_SCLK10MHZ 0x00 /* use 10MHZ serial clock */ + #define SGIOC_DMASEL_ISDNB 0x01 /* enable isdn B */ + #define SGIOC_DMASEL_ISDNA 0x02 /* enable isdn A */ + #define SGIOC_DMASEL_PPORT 0x04 /* use parallel DMA */ + #define SGIOC_DMASEL_SCLK667MHZ 0x10 /* use 6.67MHZ serial clock */ + #define SGIOC_DMASEL_SCLKEXT 0x20 /* use external serial clock */ +- u32 _unused4; +- u8 _reset[3]; +- volatile u8 reset; ++ __u32 _unused4; ++ __u8 _reset[3]; ++ volatile __u8 reset; + #define SGIOC_RESET_PPORT 0x01 /* 0=parport reset, 1=nornal */ + #define SGIOC_RESET_KBDMOUSE 0x02 /* 0=kbdmouse reset, 1=normal */ + #define SGIOC_RESET_EISA 0x04 /* 0=eisa reset, 1=normal */ + #define SGIOC_RESET_ISDN 0x08 /* 0=isdn reset, 1=normal */ + #define SGIOC_RESET_LC0OFF 0x10 /* guiness: turn led off (red, else green) */ + #define SGIOC_RESET_LC1OFF 0x20 /* guiness: turn led off (green, else amber) */ +- u32 _unused5; +- u8 _write[3]; +- volatile u8 write; ++ __u32 _unused5; ++ __u8 _write[3]; ++ volatile __u8 write; + #define SGIOC_WRITE_NTHRESH 0x01 /* use 4.5db threshhold */ + #define SGIOC_WRITE_TPSPEED 0x02 /* use 100ohm TP speed */ + #define SGIOC_WRITE_EPSEL 0x04 /* force cable mode: 1=AUI 0=TP */ +@@ -172,10 +172,10 @@ + #define SGIOC_WRITE_U0AMODE 0x20 /* 1=PC 0=MAC UART mode */ + #define SGIOC_WRITE_MLO 0x40 /* 1=4.75V 0=+5V */ + #define SGIOC_WRITE_MHI 0x80 /* 1=5.25V 0=+5V */ +- u32 _unused6; ++ __u32 _unused6; + struct sgint_regs int3; +- u32 _unused7[16]; +- volatile u32 extio; /* FullHouse only */ ++ __u32 _unused7[16]; ++ volatile __u32 extio; /* FullHouse only */ + #define EXTIO_S0_IRQ_3 0x8000 /* S0: vid.vsync */ + #define EXTIO_S0_IRQ_2 0x4000 /* S0: gfx.fifofull */ + #define EXTIO_S0_IRQ_1 0x2000 /* S0: gfx.int */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sgi/mc.h linux-libc-headers-2.6.8.0/include/asm-mips/sgi/mc.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sgi/mc.h 2003-12-15 12:47:03.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sgi/mc.h 2004-08-26 05:25:28.000000000 -0500 +@@ -14,8 +14,8 @@ + #define _SGI_MC_H + + struct sgimc_regs { +- u32 _unused0; +- volatile u32 cpuctrl0; /* CPU control register 0, readwrite */ ++ __u32 _unused0; ++ volatile __u32 cpuctrl0; /* CPU control register 0, readwrite */ + #define SGIMC_CCTRL0_REFS 0x0000000f /* REFS mask */ + #define SGIMC_CCTRL0_EREFRESH 0x00000010 /* Memory refresh enable */ + #define SGIMC_CCTRL0_EPERRGIO 0x00000020 /* GIO parity error enable */ +@@ -35,8 +35,8 @@ + #define SGIMC_CCTRL0_CMEMBADPAR 0x02000000 /* Generate bad perr from cpu to mem */ + #define SGIMC_CCTRL0_R4KNOCHKPARR 0x04000000 /* Don't chk parity on mem data reads */ + #define SGIMC_CCTRL0_GIOBTOB 0x08000000 /* Allow GIO back to back writes */ +- u32 _unused1; +- volatile u32 cpuctrl1; /* CPU control register 1, readwrite */ ++ __u32 _unused1; ++ volatile __u32 cpuctrl1; /* CPU control register 1, readwrite */ + #define SGIMC_CCTRL1_EGIOTIMEO 0x00000010 /* GIO bus timeout enable */ + #define SGIMC_CCTRL1_FIXEDEHPC 0x00001000 /* Fixed HPC endianness */ + #define SGIMC_CCTRL1_LITTLEHPC 0x00002000 /* Little endian HPC */ +@@ -45,33 +45,33 @@ + #define SGIMC_CCTRL1_FIXEDEEXP1 0x00010000 /* Fixed EXP1 endianness */ + #define SGIMC_CCTRL1_LITTLEEXP1 0x00020000 /* Little endian EXP1 */ + +- u32 _unused2; +- volatile u32 watchdogt; /* Watchdog reg rdonly, write clears */ ++ __u32 _unused2; ++ volatile __u32 watchdogt; /* Watchdog reg rdonly, write clears */ + +- u32 _unused3; +- volatile u32 systemid; /* MC system ID register, readonly */ ++ __u32 _unused3; ++ volatile __u32 systemid; /* MC system ID register, readonly */ + #define SGIMC_SYSID_MASKREV 0x0000000f /* Revision of MC controller */ + #define SGIMC_SYSID_EPRESENT 0x00000010 /* Indicates presence of EISA bus */ + +- u32 _unused4[3]; +- volatile u32 divider; /* Divider reg for RPSS */ ++ __u32 _unused4[3]; ++ volatile __u32 divider; /* Divider reg for RPSS */ + +- u32 _unused5; +- volatile u32 eeprom; /* EEPROM byte reg for r4k */ ++ __u32 _unused5; ++ volatile __u32 eeprom; /* EEPROM byte reg for r4k */ + #define SGIMC_EEPROM_PRE 0x00000001 /* eeprom chip PRE pin assertion */ + #define SGIMC_EEPROM_CSEL 0x00000002 /* Active high, eeprom chip select */ + #define SGIMC_EEPROM_SECLOCK 0x00000004 /* EEPROM serial clock */ + #define SGIMC_EEPROM_SDATAO 0x00000008 /* Serial EEPROM data-out */ + #define SGIMC_EEPROM_SDATAI 0x00000010 /* Serial EEPROM data-in */ + +- u32 _unused6[3]; +- volatile u32 rcntpre; /* Preload refresh counter */ ++ __u32 _unused6[3]; ++ volatile __u32 rcntpre; /* Preload refresh counter */ + +- u32 _unused7; +- volatile u32 rcounter; /* Readonly refresh counter */ ++ __u32 _unused7; ++ volatile __u32 rcounter; /* Readonly refresh counter */ + +- u32 _unused8[13]; +- volatile u32 giopar; /* Parameter word for GIO64 */ ++ __u32 _unused8[13]; ++ volatile __u32 giopar; /* Parameter word for GIO64 */ + #define SGIMC_GIOPAR_HPC64 0x00000001 /* HPC talks to GIO using 64-bits */ + #define SGIMC_GIOPAR_GFX64 0x00000002 /* GFX talks to GIO using 64-bits */ + #define SGIMC_GIOPAR_EXP064 0x00000004 /* EXP(slot0) talks using 64-bits */ +@@ -89,36 +89,36 @@ + #define SGIMC_GIOPAR_PLINEEXP0 0x00004000 /* EXP(slot0) has pipeline attr */ + #define SGIMC_GIOPAR_PLINEEXP1 0x00008000 /* EXP(slot1) has pipeline attr */ + +- u32 _unused9; +- volatile u32 cputp; /* CPU bus arb time period */ ++ __u32 _unused9; ++ volatile __u32 cputp; /* CPU bus arb time period */ + +- u32 _unused10[3]; +- volatile u32 lbursttp; /* Time period for long bursts */ ++ __u32 _unused10[3]; ++ volatile __u32 lbursttp; /* Time period for long bursts */ + + /* MC chip can drive up to 4 bank 4 SIMMs each. All SIMMs in bank must + * be the same size. The size encoding for supported SIMMs is bellow */ +- u32 _unused11[9]; +- volatile u32 mconfig0; /* Memory config register zero */ +- u32 _unused12; +- volatile u32 mconfig1; /* Memory config register one */ ++ __u32 _unused11[9]; ++ volatile __u32 mconfig0; /* Memory config register zero */ ++ __u32 _unused12; ++ volatile __u32 mconfig1; /* Memory config register one */ + #define SGIMC_MCONFIG_BASEADDR 0x000000ff /* Base address of bank*/ + #define SGIMC_MCONFIG_RMASK 0x00001f00 /* Ram config bitmask */ + #define SGIMC_MCONFIG_BVALID 0x00002000 /* Bank is valid */ + #define SGIMC_MCONFIG_SBANKS 0x00004000 /* Number of subbanks */ + +- u32 _unused13; +- volatile u32 cmacc; /* Mem access config for CPU */ +- u32 _unused14; +- volatile u32 gmacc; /* Mem access config for GIO */ ++ __u32 _unused13; ++ volatile __u32 cmacc; /* Mem access config for CPU */ ++ __u32 _unused14; ++ volatile __u32 gmacc; /* Mem access config for GIO */ + + /* This define applies to both cmacc and gmacc registers above. */ + #define SGIMC_MACC_ALIASBIG 0x20000000 /* 512MB home for alias */ + + /* Error address/status regs from GIO and CPU perspectives. */ +- u32 _unused15; +- volatile u32 cerr; /* Error address reg for CPU */ +- u32 _unused16; +- volatile u32 cstat; /* Status reg for CPU */ ++ __u32 _unused15; ++ volatile __u32 cerr; /* Error address reg for CPU */ ++ __u32 _unused16; ++ volatile __u32 cstat; /* Status reg for CPU */ + #define SGIMC_CSTAT_RD 0x00000100 /* read parity error */ + #define SGIMC_CSTAT_PAR 0x00000200 /* CPU parity error */ + #define SGIMC_CSTAT_ADDR 0x00000400 /* memory bus error bad addr */ +@@ -128,10 +128,10 @@ + #define SGIMC_CSTAT_PAR_MASK 0x00001f00 /* parity error mask */ + #define SGIMC_CSTAT_RD_PAR (SGIMC_CSTAT_RD | SGIMC_CSTAT_PAR) + +- u32 _unused17; +- volatile u32 gerr; /* Error address reg for GIO */ +- u32 _unused18; +- volatile u32 gstat; /* Status reg for GIO */ ++ __u32 _unused17; ++ volatile __u32 gerr; /* Error address reg for GIO */ ++ __u32 _unused18; ++ volatile __u32 gstat; /* Status reg for GIO */ + #define SGIMC_GSTAT_RD 0x00000100 /* read parity error */ + #define SGIMC_GSTAT_WR 0x00000200 /* write parity error */ + #define SGIMC_GSTAT_TIME 0x00000400 /* GIO bus timed out */ +@@ -142,76 +142,76 @@ + #define SGIMC_GSTAT_PIO_WR 0x00008000 /* write data parity on pio */ + + /* Special hard bus locking registers. */ +- u32 _unused19; +- volatile u32 syssembit; /* Uni-bit system semaphore */ +- u32 _unused20; +- volatile u32 mlock; /* Global GIO memory access lock */ +- u32 _unused21; +- volatile u32 elock; /* Locks EISA from GIO accesses */ ++ __u32 _unused19; ++ volatile __u32 syssembit; /* Uni-bit system semaphore */ ++ __u32 _unused20; ++ volatile __u32 mlock; /* Global GIO memory access lock */ ++ __u32 _unused21; ++ volatile __u32 elock; /* Locks EISA from GIO accesses */ + + /* GIO dma control registers. */ +- u32 _unused22[15]; +- volatile u32 gio_dma_trans; /* DMA mask to translation GIO addrs */ +- u32 _unused23; +- volatile u32 gio_dma_sbits; /* DMA GIO addr substitution bits */ +- u32 _unused24; +- volatile u32 dma_intr_cause; /* DMA IRQ cause indicator bits */ +- u32 _unused25; +- volatile u32 dma_ctrl; /* Main DMA control reg */ ++ __u32 _unused22[15]; ++ volatile __u32 gio_dma_trans; /* DMA mask to translation GIO addrs */ ++ __u32 _unused23; ++ volatile __u32 gio_dma_sbits; /* DMA GIO addr substitution bits */ ++ __u32 _unused24; ++ volatile __u32 dma_intr_cause; /* DMA IRQ cause indicator bits */ ++ __u32 _unused25; ++ volatile __u32 dma_ctrl; /* Main DMA control reg */ + + /* DMA TLB entry 0 */ +- u32 _unused26[5]; +- volatile u32 dtlb_hi0; +- u32 _unused27; +- volatile u32 dtlb_lo0; ++ __u32 _unused26[5]; ++ volatile __u32 dtlb_hi0; ++ __u32 _unused27; ++ volatile __u32 dtlb_lo0; + + /* DMA TLB entry 1 */ +- u32 _unused28; +- volatile u32 dtlb_hi1; +- u32 _unused29; +- volatile u32 dtlb_lo1; ++ __u32 _unused28; ++ volatile __u32 dtlb_hi1; ++ __u32 _unused29; ++ volatile __u32 dtlb_lo1; + + /* DMA TLB entry 2 */ +- u32 _unused30; +- volatile u32 dtlb_hi2; +- u32 _unused31; +- volatile u32 dtlb_lo2; ++ __u32 _unused30; ++ volatile __u32 dtlb_hi2; ++ __u32 _unused31; ++ volatile __u32 dtlb_lo2; + + /* DMA TLB entry 3 */ +- u32 _unused32; +- volatile u32 dtlb_hi3; +- u32 _unused33; +- volatile u32 dtlb_lo3; ++ __u32 _unused32; ++ volatile __u32 dtlb_hi3; ++ __u32 _unused33; ++ volatile __u32 dtlb_lo3; + +- u32 _unused34[0x0392]; ++ __u32 _unused34[0x0392]; + +- u32 _unused35; +- volatile u32 rpsscounter; /* Chirps at 100ns */ ++ __u32 _unused35; ++ volatile __u32 rpsscounter; /* Chirps at 100ns */ + +- u32 _unused36[0x1000/4-2*4]; ++ __u32 _unused36[0x1000/4-2*4]; + +- u32 _unused37; +- volatile u32 maddronly; /* Address DMA goes at */ +- u32 _unused38; +- volatile u32 maddrpdeflts; /* Same as above, plus set defaults */ +- u32 _unused39; +- volatile u32 dmasz; /* DMA count */ +- u32 _unused40; +- volatile u32 ssize; /* DMA stride size */ +- u32 _unused41; +- volatile u32 gmaddronly; /* Set GIO DMA but don't start trans */ +- u32 _unused42; +- volatile u32 dmaddnpgo; /* Set GIO DMA addr + start transfer */ +- u32 _unused43; +- volatile u32 dmamode; /* DMA mode config bit settings */ +- u32 _unused44; +- volatile u32 dmaccount; /* Zoom and byte count for DMA */ +- u32 _unused45; +- volatile u32 dmastart; /* Pedal to the metal. */ +- u32 _unused46; +- volatile u32 dmarunning; /* DMA op is in progress */ +- u32 _unused47; +- volatile u32 maddrdefstart; /* Set dma addr, defaults, and kick it */ ++ __u32 _unused37; ++ volatile __u32 maddronly; /* Address DMA goes at */ ++ __u32 _unused38; ++ volatile __u32 maddrpdeflts; /* Same as above, plus set defaults */ ++ __u32 _unused39; ++ volatile __u32 dmasz; /* DMA count */ ++ __u32 _unused40; ++ volatile __u32 ssize; /* DMA stride size */ ++ __u32 _unused41; ++ volatile __u32 gmaddronly; /* Set GIO DMA but don't start trans */ ++ __u32 _unused42; ++ volatile __u32 dmaddnpgo; /* Set GIO DMA addr + start transfer */ ++ __u32 _unused43; ++ volatile __u32 dmamode; /* DMA mode config bit settings */ ++ __u32 _unused44; ++ volatile __u32 dmaccount; /* Zoom and byte count for DMA */ ++ __u32 _unused45; ++ volatile __u32 dmastart; /* Pedal to the metal. */ ++ __u32 _unused46; ++ volatile __u32 dmarunning; /* DMA op is in progress */ ++ __u32 _unused47; ++ volatile __u32 maddrdefstart; /* Set dma addr, defaults, and kick it */ + }; + + extern struct sgimc_regs *sgimc; +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sgiarcs.h linux-libc-headers-2.6.8.0/include/asm-mips/sgiarcs.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sgiarcs.h 2004-03-28 07:51:52.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sgiarcs.h 2004-08-26 05:21:53.000000000 -0500 +@@ -164,11 +164,11 @@ + /* This prom has a bolixed design. */ + struct linux_bigint { + #ifdef __MIPSEL__ +- u32 lo; +- s32 hi; ++ __u32 lo; ++ __s32 hi; + #else /* !(__MIPSEL__) */ +- s32 hi; +- u32 lo; ++ __s32 hi; ++ __u32 lo; + #endif + }; + +@@ -366,7 +366,7 @@ + * Macros for calling a 32-bit ARC implementation from 64-bit code + */ + +-#if defined(CONFIG_MIPS64) && defined(CONFIG_ARC32) ++#if defined(__mips64) && defined(CONFIG_ARC32) + + #define __arc_clobbers \ + "$2","$3" /* ... */, "$8","$9","$10","$11", \ +@@ -475,10 +475,10 @@ + __res; \ + }) + +-#endif /* defined(CONFIG_MIPS64) && defined(CONFIG_ARC32) */ ++#endif /* defined(__mips64) && defined(CONFIG_ARC32) */ + +-#if (defined(CONFIG_MIPS32) && defined(CONFIG_ARC32)) || \ +- (defined(CONFIG_MIPS64) && defined(CONFIG_ARC64)) ++#if (!defined(__mips64) && defined(CONFIG_ARC32)) || \ ++ (defined(__mips64) && defined(CONFIG_ARC64)) + + #define ARC_CALL0(dest) \ + ({ long __res; \ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/siginfo.h linux-libc-headers-2.6.8.0/include/asm-mips/siginfo.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/siginfo.h 2004-06-09 07:00:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/siginfo.h 2004-08-26 05:14:41.000000000 -0500 +@@ -66,10 +66,10 @@ + + /* SIGPOLL, SIGXFSZ (To do ...) */ + struct { +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + long _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + #endif + int _fd; +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sim.h linux-libc-headers-2.6.8.0/include/asm-mips/sim.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sim.h 2004-03-28 07:51:52.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sim.h 2004-08-26 05:17:16.000000000 -0500 +@@ -18,7 +18,7 @@ + #define __str2(x) #x + #define __str(x) __str2(x) + +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + + #define save_static_function(symbol) \ + __asm__ ( \ +@@ -43,9 +43,9 @@ + + #define nabi_no_regargs + +-#endif /* CONFIG_MIPS32 */ ++#endif /* ndef __mips64 */ + +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + + #define save_static_function(symbol) \ + __asm__ ( \ +@@ -78,6 +78,6 @@ + unsigned long __dummy6, \ + unsigned long __dummy7, + +-#endif /* CONFIG_MIPS64 */ ++#endif /* __mips64 */ + + #endif /* _ASM_SIM_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/arch.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/arch.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/arch.h 2004-06-09 07:00:42.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/arch.h 2004-08-26 05:26:16.000000000 -0500 +@@ -17,8 +17,8 @@ + #include + #endif + +-typedef u64 hubreg_t; +-typedef u64 nic_t; ++typedef __u64 hubreg_t; ++typedef __u64 nic_t; + + #define cputonasid(cpu) (cpu_data[(cpu)].p_nasid) + #define cputoslice(cpu) (cpu_data[(cpu)].p_slice) +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/gda.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/gda.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/gda.h 2003-12-15 12:47:02.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/gda.h 2004-08-26 05:26:30.000000000 -0500 +@@ -44,11 +44,11 @@ + #ifndef __ASSEMBLY__ + + typedef struct gda { +- u32 g_magic; /* GDA magic number */ +- u16 g_version; /* Version of this structure */ +- u16 g_masterid; /* The NASID:CPUNUM of the master cpu */ +- u32 g_promop; /* Passes requests from the kernel to prom */ +- u32 g_vds; /* Store the virtual dipswitches here */ ++ __u32 g_magic; /* GDA magic number */ ++ __u16 g_version; /* Version of this structure */ ++ __u16 g_masterid; /* The NASID:CPUNUM of the master cpu */ ++ __u32 g_promop; /* Passes requests from the kernel to prom */ ++ __u32 g_vds; /* Store the virtual dipswitches here */ + void **g_hooked_norm;/* ptr to pda loc for norm hndlr */ + void **g_hooked_utlb;/* ptr to pda loc for utlb hndlr */ + void **g_hooked_xtlb;/* ptr to pda loc for xtlb hndlr */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/ioc3.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/ioc3.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/ioc3.h 2003-12-15 12:47:02.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/ioc3.h 2004-08-26 05:26:06.000000000 -0500 +@@ -8,23 +8,23 @@ + /* SUPERIO uart register map */ + typedef volatile struct ioc3_uartregs { + union { +- volatile u8 rbr; /* read only, DLAB == 0 */ +- volatile u8 thr; /* write only, DLAB == 0 */ +- volatile u8 dll; /* DLAB == 1 */ ++ volatile __u8 rbr; /* read only, DLAB == 0 */ ++ volatile __u8 thr; /* write only, DLAB == 0 */ ++ volatile __u8 dll; /* DLAB == 1 */ + } u1; + union { +- volatile u8 ier; /* DLAB == 0 */ +- volatile u8 dlm; /* DLAB == 1 */ ++ volatile __u8 ier; /* DLAB == 0 */ ++ volatile __u8 dlm; /* DLAB == 1 */ + } u2; + union { +- volatile u8 iir; /* read only */ +- volatile u8 fcr; /* write only */ ++ volatile __u8 iir; /* read only */ ++ volatile __u8 fcr; /* write only */ + } u3; +- volatile u8 iu_lcr; +- volatile u8 iu_mcr; +- volatile u8 iu_lsr; +- volatile u8 iu_msr; +- volatile u8 iu_scr; ++ volatile __u8 iu_lcr; ++ volatile __u8 iu_mcr; ++ volatile __u8 iu_lsr; ++ volatile __u8 iu_msr; ++ volatile __u8 iu_scr; + } ioc3_uregs_t; + + #define iu_rbr u1.rbr +@@ -36,29 +36,29 @@ + #define iu_fcr u3.fcr + + struct ioc3_sioregs { +- volatile u8 fill[0x141]; /* starts at 0x141 */ ++ volatile __u8 fill[0x141]; /* starts at 0x141 */ + +- volatile u8 uartc; +- volatile u8 kbdcg; ++ volatile __u8 uartc; ++ volatile __u8 kbdcg; + +- volatile u8 fill0[0x150 - 0x142 - 1]; ++ volatile __u8 fill0[0x150 - 0x142 - 1]; + +- volatile u8 pp_data; +- volatile u8 pp_dsr; +- volatile u8 pp_dcr; ++ volatile __u8 pp_data; ++ volatile __u8 pp_dsr; ++ volatile __u8 pp_dcr; + +- volatile u8 fill1[0x158 - 0x152 - 1]; ++ volatile __u8 fill1[0x158 - 0x152 - 1]; + +- volatile u8 pp_fifa; +- volatile u8 pp_cfgb; +- volatile u8 pp_ecr; ++ volatile __u8 pp_fifa; ++ volatile __u8 pp_cfgb; ++ volatile __u8 pp_ecr; + +- volatile u8 fill2[0x168 - 0x15a - 1]; ++ volatile __u8 fill2[0x168 - 0x15a - 1]; + +- volatile u8 rtcad; +- volatile u8 rtcdat; ++ volatile __u8 rtcad; ++ volatile __u8 rtcdat; + +- volatile u8 fill3[0x170 - 0x169 - 1]; ++ volatile __u8 fill3[0x170 - 0x169 - 1]; + + struct ioc3_uartregs uartb; /* 0x20170 */ + struct ioc3_uartregs uarta; /* 0x20178 */ +@@ -66,103 +66,103 @@ + + /* Register layout of IOC3 in configuration space. */ + struct ioc3 { +- volatile u32 pad0[7]; /* 0x00000 */ +- volatile u32 sio_ir; /* 0x0001c */ +- volatile u32 sio_ies; /* 0x00020 */ +- volatile u32 sio_iec; /* 0x00024 */ +- volatile u32 sio_cr; /* 0x00028 */ +- volatile u32 int_out; /* 0x0002c */ +- volatile u32 mcr; /* 0x00030 */ ++ volatile __u32 pad0[7]; /* 0x00000 */ ++ volatile __u32 sio_ir; /* 0x0001c */ ++ volatile __u32 sio_ies; /* 0x00020 */ ++ volatile __u32 sio_iec; /* 0x00024 */ ++ volatile __u32 sio_cr; /* 0x00028 */ ++ volatile __u32 int_out; /* 0x0002c */ ++ volatile __u32 mcr; /* 0x00030 */ + + /* General Purpose I/O registers */ +- volatile u32 gpcr_s; /* 0x00034 */ +- volatile u32 gpcr_c; /* 0x00038 */ +- volatile u32 gpdr; /* 0x0003c */ +- volatile u32 gppr_0; /* 0x00040 */ +- volatile u32 gppr_1; /* 0x00044 */ +- volatile u32 gppr_2; /* 0x00048 */ +- volatile u32 gppr_3; /* 0x0004c */ +- volatile u32 gppr_4; /* 0x00050 */ +- volatile u32 gppr_5; /* 0x00054 */ +- volatile u32 gppr_6; /* 0x00058 */ +- volatile u32 gppr_7; /* 0x0005c */ +- volatile u32 gppr_8; /* 0x00060 */ +- volatile u32 gppr_9; /* 0x00064 */ +- volatile u32 gppr_10; /* 0x00068 */ +- volatile u32 gppr_11; /* 0x0006c */ +- volatile u32 gppr_12; /* 0x00070 */ +- volatile u32 gppr_13; /* 0x00074 */ +- volatile u32 gppr_14; /* 0x00078 */ +- volatile u32 gppr_15; /* 0x0007c */ ++ volatile __u32 gpcr_s; /* 0x00034 */ ++ volatile __u32 gpcr_c; /* 0x00038 */ ++ volatile __u32 gpdr; /* 0x0003c */ ++ volatile __u32 gppr_0; /* 0x00040 */ ++ volatile __u32 gppr_1; /* 0x00044 */ ++ volatile __u32 gppr_2; /* 0x00048 */ ++ volatile __u32 gppr_3; /* 0x0004c */ ++ volatile __u32 gppr_4; /* 0x00050 */ ++ volatile __u32 gppr_5; /* 0x00054 */ ++ volatile __u32 gppr_6; /* 0x00058 */ ++ volatile __u32 gppr_7; /* 0x0005c */ ++ volatile __u32 gppr_8; /* 0x00060 */ ++ volatile __u32 gppr_9; /* 0x00064 */ ++ volatile __u32 gppr_10; /* 0x00068 */ ++ volatile __u32 gppr_11; /* 0x0006c */ ++ volatile __u32 gppr_12; /* 0x00070 */ ++ volatile __u32 gppr_13; /* 0x00074 */ ++ volatile __u32 gppr_14; /* 0x00078 */ ++ volatile __u32 gppr_15; /* 0x0007c */ + + /* Parallel Port Registers */ +- volatile u32 ppbr_h_a; /* 0x00080 */ +- volatile u32 ppbr_l_a; /* 0x00084 */ +- volatile u32 ppcr_a; /* 0x00088 */ +- volatile u32 ppcr; /* 0x0008c */ +- volatile u32 ppbr_h_b; /* 0x00090 */ +- volatile u32 ppbr_l_b; /* 0x00094 */ +- volatile u32 ppcr_b; /* 0x00098 */ ++ volatile __u32 ppbr_h_a; /* 0x00080 */ ++ volatile __u32 ppbr_l_a; /* 0x00084 */ ++ volatile __u32 ppcr_a; /* 0x00088 */ ++ volatile __u32 ppcr; /* 0x0008c */ ++ volatile __u32 ppbr_h_b; /* 0x00090 */ ++ volatile __u32 ppbr_l_b; /* 0x00094 */ ++ volatile __u32 ppcr_b; /* 0x00098 */ + + /* Keyboard and Mouse Registers */ +- volatile u32 km_csr; /* 0x0009c */ +- volatile u32 k_rd; /* 0x000a0 */ +- volatile u32 m_rd; /* 0x000a4 */ +- volatile u32 k_wd; /* 0x000a8 */ +- volatile u32 m_wd; /* 0x000ac */ ++ volatile __u32 km_csr; /* 0x0009c */ ++ volatile __u32 k_rd; /* 0x000a0 */ ++ volatile __u32 m_rd; /* 0x000a4 */ ++ volatile __u32 k_wd; /* 0x000a8 */ ++ volatile __u32 m_wd; /* 0x000ac */ + + /* Serial Port Registers */ +- volatile u32 sbbr_h; /* 0x000b0 */ +- volatile u32 sbbr_l; /* 0x000b4 */ +- volatile u32 sscr_a; /* 0x000b8 */ +- volatile u32 stpir_a; /* 0x000bc */ +- volatile u32 stcir_a; /* 0x000c0 */ +- volatile u32 srpir_a; /* 0x000c4 */ +- volatile u32 srcir_a; /* 0x000c8 */ +- volatile u32 srtr_a; /* 0x000cc */ +- volatile u32 shadow_a; /* 0x000d0 */ +- volatile u32 sscr_b; /* 0x000d4 */ +- volatile u32 stpir_b; /* 0x000d8 */ +- volatile u32 stcir_b; /* 0x000dc */ +- volatile u32 srpir_b; /* 0x000e0 */ +- volatile u32 srcir_b; /* 0x000e4 */ +- volatile u32 srtr_b; /* 0x000e8 */ +- volatile u32 shadow_b; /* 0x000ec */ ++ volatile __u32 sbbr_h; /* 0x000b0 */ ++ volatile __u32 sbbr_l; /* 0x000b4 */ ++ volatile __u32 sscr_a; /* 0x000b8 */ ++ volatile __u32 stpir_a; /* 0x000bc */ ++ volatile __u32 stcir_a; /* 0x000c0 */ ++ volatile __u32 srpir_a; /* 0x000c4 */ ++ volatile __u32 srcir_a; /* 0x000c8 */ ++ volatile __u32 srtr_a; /* 0x000cc */ ++ volatile __u32 shadow_a; /* 0x000d0 */ ++ volatile __u32 sscr_b; /* 0x000d4 */ ++ volatile __u32 stpir_b; /* 0x000d8 */ ++ volatile __u32 stcir_b; /* 0x000dc */ ++ volatile __u32 srpir_b; /* 0x000e0 */ ++ volatile __u32 srcir_b; /* 0x000e4 */ ++ volatile __u32 srtr_b; /* 0x000e8 */ ++ volatile __u32 shadow_b; /* 0x000ec */ + + /* Ethernet Registers */ +- volatile u32 emcr; /* 0x000f0 */ +- volatile u32 eisr; /* 0x000f4 */ +- volatile u32 eier; /* 0x000f8 */ +- volatile u32 ercsr; /* 0x000fc */ +- volatile u32 erbr_h; /* 0x00100 */ +- volatile u32 erbr_l; /* 0x00104 */ +- volatile u32 erbar; /* 0x00108 */ +- volatile u32 ercir; /* 0x0010c */ +- volatile u32 erpir; /* 0x00110 */ +- volatile u32 ertr; /* 0x00114 */ +- volatile u32 etcsr; /* 0x00118 */ +- volatile u32 ersr; /* 0x0011c */ +- volatile u32 etcdc; /* 0x00120 */ +- volatile u32 ebir; /* 0x00124 */ +- volatile u32 etbr_h; /* 0x00128 */ +- volatile u32 etbr_l; /* 0x0012c */ +- volatile u32 etcir; /* 0x00130 */ +- volatile u32 etpir; /* 0x00134 */ +- volatile u32 emar_h; /* 0x00138 */ +- volatile u32 emar_l; /* 0x0013c */ +- volatile u32 ehar_h; /* 0x00140 */ +- volatile u32 ehar_l; /* 0x00144 */ +- volatile u32 micr; /* 0x00148 */ +- volatile u32 midr_r; /* 0x0014c */ +- volatile u32 midr_w; /* 0x00150 */ +- volatile u32 pad1[(0x20000 - 0x00154) / 4]; ++ volatile __u32 emcr; /* 0x000f0 */ ++ volatile __u32 eisr; /* 0x000f4 */ ++ volatile __u32 eier; /* 0x000f8 */ ++ volatile __u32 ercsr; /* 0x000fc */ ++ volatile __u32 erbr_h; /* 0x00100 */ ++ volatile __u32 erbr_l; /* 0x00104 */ ++ volatile __u32 erbar; /* 0x00108 */ ++ volatile __u32 ercir; /* 0x0010c */ ++ volatile __u32 erpir; /* 0x00110 */ ++ volatile __u32 ertr; /* 0x00114 */ ++ volatile __u32 etcsr; /* 0x00118 */ ++ volatile __u32 ersr; /* 0x0011c */ ++ volatile __u32 etcdc; /* 0x00120 */ ++ volatile __u32 ebir; /* 0x00124 */ ++ volatile __u32 etbr_h; /* 0x00128 */ ++ volatile __u32 etbr_l; /* 0x0012c */ ++ volatile __u32 etcir; /* 0x00130 */ ++ volatile __u32 etpir; /* 0x00134 */ ++ volatile __u32 emar_h; /* 0x00138 */ ++ volatile __u32 emar_l; /* 0x0013c */ ++ volatile __u32 ehar_h; /* 0x00140 */ ++ volatile __u32 ehar_l; /* 0x00144 */ ++ volatile __u32 micr; /* 0x00148 */ ++ volatile __u32 midr_r; /* 0x0014c */ ++ volatile __u32 midr_w; /* 0x00150 */ ++ volatile __u32 pad1[(0x20000 - 0x00154) / 4]; + + /* SuperIO Registers XXX */ + struct ioc3_sioregs sregs; /* 0x20000 */ +- volatile u32 pad2[(0x40000 - 0x20180) / 4]; ++ volatile __u32 pad2[(0x40000 - 0x20180) / 4]; + + /* SSRAM Diagnostic Access */ +- volatile u32 ssram[(0x80000 - 0x40000) / 4]; ++ volatile __u32 ssram[(0x80000 - 0x40000) / 4]; + + /* Bytebus device offsets + 0x80000 - Access to the generic devices selected with DEV0 +@@ -179,8 +179,8 @@ + * Ethernet RX Buffer + */ + struct ioc3_erxbuf { +- u32 w0; /* first word (valid,bcnt,cksum) */ +- u32 err; /* second word various errors */ ++ __u32 w0; /* first word (valid,bcnt,cksum) */ ++ __u32 err; /* second word various errors */ + /* next comes n bytes of padding */ + /* then the received ethernet frame itself */ + }; +@@ -208,11 +208,11 @@ + */ + #define ETXD_DATALEN 104 + struct ioc3_etxd { +- u32 cmd; /* command field */ +- u32 bufcnt; /* buffer counts field */ +- u64 p1; /* buffer pointer 1 */ +- u64 p2; /* buffer pointer 2 */ +- u8 data[ETXD_DATALEN]; /* opt. tx data */ ++ __u32 cmd; /* command field */ ++ __u32 bufcnt; /* buffer counts field */ ++ __u64 p1; /* buffer pointer 1 */ ++ __u64 p2; /* buffer pointer 2 */ ++ __u8 data[ETXD_DATALEN]; /* opt. tx data */ + }; + + #define ETXD_BYTECNT_MASK 0x000007ff /* total byte count */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/klconfig.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/klconfig.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/klconfig.h 2004-03-28 07:51:55.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/klconfig.h 2004-08-26 05:26:13.000000000 -0500 +@@ -64,9 +64,9 @@ + #define KLCFGINFO_MAGIC 0xbeedbabe + + #ifdef FRUTEST +-typedef u64 klconf_off_t; ++typedef __u64 klconf_off_t; + #else +-typedef s32 klconf_off_t; ++typedef __s32 klconf_off_t; + #endif + + /* +@@ -160,8 +160,8 @@ + /* Functions/macros needed to use this structure */ + + typedef struct kl_config_hdr { +- u64 ch_magic; /* set this to KLCFGINFO_MAGIC */ +- u32 ch_version; /* structure version number */ ++ __u64 ch_magic; /* set this to KLCFGINFO_MAGIC */ ++ __u32 ch_version; /* structure version number */ + klconf_off_t ch_malloc_hdr_off; /* offset of ch_malloc_hdr */ + klconf_off_t ch_cons_off; /* offset of ch_cons */ + klconf_off_t ch_board_info; /* the link list of boards */ +@@ -609,14 +609,14 @@ + + /* Info holders for various hardware components */ + +-typedef u64 *pci_t; +-typedef u64 *vmeb_t; +-typedef u64 *vmed_t; +-typedef u64 *fddi_t; +-typedef u64 *scsi_t; +-typedef u64 *mio_t; +-typedef u64 *graphics_t; +-typedef u64 *router_t; ++typedef __u64 *pci_t; ++typedef __u64 *vmeb_t; ++typedef __u64 *vmed_t; ++typedef __u64 *fddi_t; ++typedef __u64 *scsi_t; ++typedef __u64 *mio_t; ++typedef __u64 *graphics_t; ++typedef __u64 *router_t; + + /* + * The port info in ip27_cfg area translates to a lboart_t in the +@@ -659,7 +659,7 @@ + klport_t hub_port; /* hub is connected to this */ + nic_t hub_box_nic; /* nic of containing box */ + klconf_off_t hub_mfg_nic; /* MFG NIC string */ +- u64 hub_speed; /* Speed of hub in HZ */ ++ __u64 hub_speed; /* Speed of hub in HZ */ + } klhub_t ; + + typedef struct klhub_uart_s { /* HUB */ +@@ -716,8 +716,8 @@ + #define MAX_PCI_SLOTS 8 + + typedef struct klpci_device_s { +- s32 pci_device_id; /* 32 bits of vendor/device ID. */ +- s32 pci_device_pad; /* 32 bits of padding. */ ++ __s32 pci_device_id; /* 32 bits of vendor/device ID. */ ++ __s32 pci_device_pad; /* 32 bits of padding. */ + } klpci_device_t; + + #define BRIDGE_STRUCT_VERSION 2 +@@ -767,7 +767,7 @@ + nic_t rou_box_nic ; /* nic of the containing module */ + klport_t rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */ + klconf_off_t rou_mfg_nic ; /* MFG NIC string */ +- u64 rou_vector; /* vector from master node */ ++ __u64 rou_vector; /* vector from master node */ + } klrou_t ; + + /* +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/kldir.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/kldir.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/kldir.h 2004-01-17 17:03:49.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/kldir.h 2004-08-26 05:26:25.000000000 -0500 +@@ -210,7 +210,7 @@ + + #ifndef __ASSEMBLY__ + typedef struct kldir_ent_s { +- u64 magic; /* Indicates validity of entry */ ++ __u64 magic; /* Indicates validity of entry */ + off_t offset; /* Offset from start of node space */ + #if defined(CONFIG_SGI_IO) /* FIXME */ + __psunsigned_t pointer; /* Pointer to area in some cases */ +@@ -218,7 +218,7 @@ + unsigned long pointer; /* Pointer to area in some cases */ + #endif + size_t size; /* Size in bytes */ +- u64 count; /* Repeat count if array, 1 if not */ ++ __u64 count; /* Repeat count if array, 1 if not */ + size_t stride; /* Stride if array, 0 if not */ + char rsvd[16]; /* Pad entry to 0x40 bytes */ + /* NOTE: These 16 bytes are used in the Partition KLDIR +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/launch.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/launch.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/launch.h 2004-01-17 17:03:49.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/launch.h 2004-08-26 05:25:52.000000000 -0500 +@@ -62,14 +62,14 @@ + #ifndef __ASSEMBLY__ + + typedef int launch_state_t; +-typedef void (*launch_proc_t)(u64 call_parm); ++typedef void (*launch_proc_t)(__u64 call_parm); + + typedef struct launch_s { +- volatile u64 magic; /* Magic number */ +- volatile u64 busy; /* Slave currently active */ ++ volatile __u64 magic; /* Magic number */ ++ volatile __u64 busy; /* Slave currently active */ + volatile launch_proc_t call_addr; /* Func. for slave to call */ +- volatile u64 call_addr_c; /* 1's complement of call_addr*/ +- volatile u64 call_parm; /* Single parm passed to call*/ ++ volatile __u64 call_addr_c; /* 1's complement of call_addr*/ ++ volatile __u64 call_parm; /* Single parm passed to call*/ + volatile void *stack_addr; /* Stack pointer for slave function */ + volatile void *gp_addr; /* Global pointer for slave func. */ + volatile char *bevutlb;/* Address of bev utlb ex handler */ +@@ -84,7 +84,7 @@ + + #define LAUNCH_SLAVE (*(void (*)(int nasid, int cpu, \ + launch_proc_t call_addr, \ +- u64 call_parm, \ ++ __u64 call_parm, \ + void *stack_addr, \ + void *gp_addr)) \ + IP27PROM_LAUNCHSLAVE) +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/sn0/hubio.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/sn0/hubio.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/sn0/hubio.h 2003-12-15 12:47:02.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/sn0/hubio.h 2004-08-26 05:27:21.000000000 -0500 +@@ -172,9 +172,9 @@ + #ifndef __ASSEMBLY__ + + typedef union hubii_wid_u { +- u64 wid_reg_value; ++ __u64 wid_reg_value; + struct { +- u64 wid_rsvd: 32, /* unused */ ++ __u64 wid_rsvd: 32, /* unused */ + wid_rev_num: 4, /* revision number */ + wid_part_num: 16, /* the widget type: hub=c101 */ + wid_mfg_num: 11, /* Manufacturer id (IBM) */ +@@ -184,9 +184,9 @@ + + + typedef union hubii_wcr_u { +- u64 wcr_reg_value; ++ __u64 wcr_reg_value; + struct { +- u64 wcr_rsvd: 41, /* unused */ ++ __u64 wcr_rsvd: 41, /* unused */ + wcr_e_thresh: 5, /* elasticity threshold */ + wcr_dir_con: 1, /* widget direct connect */ + wcr_f_bad_pkt: 1, /* Force bad llp pkt enable */ +@@ -200,9 +200,9 @@ + #define iwcr_dir_con wcr_fields_s.wcr_dir_con + + typedef union hubii_wstat_u { +- u64 reg_value; ++ __u64 reg_value; + struct { +- u64 rsvd1: 31, ++ __u64 rsvd1: 31, + crazy: 1, /* Crazy bit */ + rsvd2: 8, + llp_tx_cnt: 8, /* LLP Xmit retry counter */ +@@ -217,9 +217,9 @@ + + + typedef union hubii_ilcsr_u { +- u64 icsr_reg_value; ++ __u64 icsr_reg_value; + struct { +- u64 icsr_rsvd: 22, /* unused */ ++ __u64 icsr_rsvd: 22, /* unused */ + icsr_max_burst: 10, /* max burst */ + icsr_rsvd4: 6, /* reserved */ + icsr_max_retry: 10, /* max retry */ +@@ -237,9 +237,9 @@ + + + typedef union hubii_iowa_u { +- u64 iowa_reg_value; ++ __u64 iowa_reg_value; + struct { +- u64 iowa_rsvd: 48, /* unused */ ++ __u64 iowa_rsvd: 48, /* unused */ + iowa_wxoac: 8, /* xtalk widget access bits */ + iowa_rsvd1: 7, /* xtalk widget access bits */ + iowa_w0oac: 1; /* xtalk widget access bits */ +@@ -247,9 +247,9 @@ + } hubii_iowa_t; + + typedef union hubii_iiwa_u { +- u64 iiwa_reg_value; ++ __u64 iiwa_reg_value; + struct { +- u64 iiwa_rsvd: 48, /* unused */ ++ __u64 iiwa_rsvd: 48, /* unused */ + iiwa_wxiac: 8, /* hub wid access bits */ + iiwa_rsvd1: 7, /* reserved */ + iiwa_w0iac: 1; /* hub wid0 access */ +@@ -257,9 +257,9 @@ + } hubii_iiwa_t; + + typedef union hubii_illr_u { +- u64 illr_reg_value; ++ __u64 illr_reg_value; + struct { +- u64 illr_rsvd: 32, /* unused */ ++ __u64 illr_rsvd: 32, /* unused */ + illr_cb_cnt: 16, /* checkbit error count */ + illr_sn_cnt: 16; /* sequence number count */ + } illr_fields_s; +@@ -271,9 +271,9 @@ + /* io_perf_sel allows the caller to specify what tests will be + performed */ + typedef union io_perf_sel { +- u64 perf_sel_reg; ++ __u64 perf_sel_reg; + struct { +- u64 perf_rsvd : 48, ++ __u64 perf_rsvd : 48, + perf_icct : 8, + perf_ippr1 : 4, + perf_ippr0 : 4; +@@ -284,9 +284,9 @@ + hardware problems there is only one counter, not two. */ + + typedef union io_perf_cnt { +- u64 perf_cnt; ++ __u64 perf_cnt; + struct { +- u64 perf_rsvd1 : 32, ++ __u64 perf_rsvd1 : 32, + perf_rsvd2 : 12, + perf_cnt : 20; + } perf_cnt_bits; +@@ -442,9 +442,9 @@ + */ + #ifndef __ASSEMBLY__ + typedef union icrba_u { +- u64 reg_value; ++ __u64 reg_value; + struct { +- u64 resvd: 6, ++ __u64 resvd: 6, + stall_bte0: 1, /* Stall BTE 0 */ + stall_bte1: 1, /* Stall BTE 1 */ + error: 1, /* CRB has an error */ +@@ -464,10 +464,10 @@ + runtime selection of the format based on the REV_ID field of the + NI_STATUS_REV_ID register. */ + typedef union h1_icrba_u { +- u64 reg_value; ++ __u64 reg_value; + + struct { +- u64 resvd: 6, ++ __u64 resvd: 6, + unused: 1, /* Unused but RW!! */ + error: 1, /* CRB has an error */ + ecode: 4, /* Error Code */ +@@ -525,9 +525,9 @@ + */ + #ifndef __ASSEMBLY__ + typedef union icrbb_u { +- u64 reg_value; ++ __u64 reg_value; + struct { +- u64 rsvd1: 5, ++ __u64 rsvd1: 5, + btenum: 1, /* BTE to which entry belongs to */ + cohtrans: 1, /* Coherent transaction */ + xtsize: 2, /* Xtalk operation size +@@ -567,9 +567,9 @@ + runtime selection of the format based on the REV_ID field of the + NI_STATUS_REV_ID register. */ + typedef union h1_icrbb_u { +- u64 reg_value; ++ __u64 reg_value; + struct { +- u64 rsvd1: 5, ++ __u64 rsvd1: 5, + btenum: 1, /* BTE to which entry belongs to */ + cohtrans: 1, /* Coherent transaction */ + xtsize: 2, /* Xtalk operation size +@@ -683,9 +683,9 @@ + #ifndef __ASSEMBLY__ + + typedef union icrbc_s { +- u64 reg_value; ++ __u64 reg_value; + struct { +- u64 rsvd: 6, ++ __u64 rsvd: 6, + sleep: 1, + pricnt: 4, /* Priority count sent with Read req */ + pripsc: 4, /* Priority Pre scalar */ +@@ -720,9 +720,9 @@ + + #ifndef __ASSEMBLY__ + typedef union icrbd_s { +- u64 reg_value; ++ __u64 reg_value; + struct { +- u64 rsvd: 38, ++ __u64 rsvd: 38, + toutvld: 1, /* Timeout in progress for this CRB */ + ctxtvld: 1, /* Context field below is valid */ + rsvd2: 1, +@@ -742,9 +742,9 @@ + + + typedef union hubii_ifdr_u { +- u64 hi_ifdr_value; ++ __u64 hi_ifdr_value; + struct { +- u64 ifdr_rsvd: 49, ++ __u64 ifdr_rsvd: 49, + ifdr_maxrp: 7, + ifdr_rsvd1: 1, + ifdr_maxrq: 7; +@@ -801,9 +801,9 @@ + #ifndef __ASSEMBLY__ + + typedef union iprte_a { +- u64 entry; ++ __u64 entry; + struct { +- u64 rsvd1 : 7, /* Reserved field */ ++ __u64 rsvd1 : 7, /* Reserved field */ + valid : 1, /* Maps to a timeout entry */ + rsvd2 : 1, + srcnode : 9, /* Node which did this PIO */ +@@ -835,9 +835,9 @@ + */ + + typedef union iprb_u { +- u64 reg_value; ++ __u64 reg_value; + struct { +- u64 rsvd1: 15, ++ __u64 rsvd1: 15, + error: 1, /* Widget rcvd wr resp pkt w/ error */ + ovflow: 5, /* Over flow count. perf measurement */ + fire_and_forget: 1, /* Launch Write without response */ +@@ -877,9 +877,9 @@ + */ + #ifndef __ASSEMBLY__ + typedef union icrbp_a { +- u64 ip_reg; /* the entire register value */ ++ __u64 ip_reg; /* the entire register value */ + struct { +- u64 error: 1, /* 63, error occurred */ ++ __u64 error: 1, /* 63, error occurred */ + ln_uce: 1, /* 62: uncorrectable memory */ + ln_ae: 1, /* 61: protection violation */ + ln_werr:1, /* 60: write access error */ +@@ -919,9 +919,9 @@ + + #ifndef __ASSEMBLY__ + typedef union hubii_idsr { +- u64 iin_reg; ++ __u64 iin_reg; + struct { +- u64 rsvd1 : 35, ++ __u64 rsvd1 : 35, + isent : 1, + rsvd2 : 3, + ienable: 1, +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/sn0/hubmd.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/sn0/hubmd.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/sn0/hubmd.h 2004-01-17 17:03:49.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/sn0/hubmd.h 2004-08-26 05:27:00.000000000 -0500 +@@ -541,7 +541,7 @@ + */ + + struct dir_error_reg { +- u64 uce_vld: 1, /* 63: valid directory uce */ ++ __u64 uce_vld: 1, /* 63: valid directory uce */ + ae_vld: 1, /* 62: valid dir prot ecc error */ + ce_vld: 1, /* 61: valid correctable ECC err*/ + rsvd1: 19, /* 60-42: reserved */ +@@ -555,13 +555,13 @@ + }; + + typedef union md_dir_error { +- u64 derr_reg; /* the entire register */ ++ __u64 derr_reg; /* the entire register */ + struct dir_error_reg derr_fmt; /* the register format */ + } md_dir_error_t; + + + struct mem_error_reg { +- u64 uce_vld: 1, /* 63: valid memory uce */ ++ __u64 uce_vld: 1, /* 63: valid memory uce */ + ce_vld: 1, /* 62: valid correctable ECC err*/ + rsvd1: 22, /* 61-40: reserved */ + bad_syn: 8, /* 39-32: bad mem ecc syndrome */ +@@ -573,13 +573,13 @@ + + + typedef union md_mem_error { +- u64 merr_reg; /* the entire register */ ++ __u64 merr_reg; /* the entire register */ + struct mem_error_reg merr_fmt; /* format of the mem_error reg */ + } md_mem_error_t; + + + struct proto_error_reg { +- u64 valid: 1, /* 63: valid protocol error */ ++ __u64 valid: 1, /* 63: valid protocol error */ + rsvd1: 2, /* 62-61: reserved */ + initiator:11, /* 60-50: id of request initiator*/ + backoff: 2, /* 49-48: backoff control */ +@@ -594,7 +594,7 @@ + }; + + typedef union md_proto_error { +- u64 perr_reg; /* the entire register */ ++ __u64 perr_reg; /* the entire register */ + struct proto_error_reg perr_fmt; /* format of the register */ + } md_proto_error_t; + +@@ -642,7 +642,7 @@ + + + struct md_pdir_high_fmt { +- u64 pd_hi_unused : 16, ++ __u64 pd_hi_unused : 16, + pd_hi_bvec : 38, + pd_hi_unused1 : 3, + pd_hi_ecc : 7; +@@ -651,14 +651,14 @@ + + typedef union md_pdir_high { + /* The 48 bits of standard directory, upper word */ +- u64 pd_hi_val; ++ __u64 pd_hi_val; + struct md_pdir_high_fmt pd_hi_fmt; + }md_pdir_high_t; + + + struct md_pdir_low_shared_fmt { + /* The meaning of lower directory, shared */ +- u64 pds_lo_unused : 16, ++ __u64 pds_lo_unused : 16, + pds_lo_bvec : 26, + pds_lo_cnt : 6, + pds_lo_state : 3, +@@ -670,7 +670,7 @@ + + struct md_pdir_low_exclusive_fmt { + /* The meaning of lower directory, exclusive */ +- u64 pde_lo_unused : 31, ++ __u64 pde_lo_unused : 31, + pde_lo_ptr : 11, + pde_lo_unused1 : 6, + pde_lo_state : 3, +@@ -683,7 +683,7 @@ + + typedef union md_pdir_loent { + /* The 48 bits of premium directory, lower word */ +- u64 pd_lo_val; ++ __u64 pd_lo_val; + struct md_pdir_low_exclusive_fmt pde_lo_fmt; + struct md_pdir_low_shared_fmt pds_lo_fmt; + }md_pdir_low_t; +@@ -711,25 +711,25 @@ + } bddir_entry_t; + + typedef struct dir_mem_entry { +- u64 prcpf[MAX_REGIONS]; ++ __u64 prcpf[MAX_REGIONS]; + bddir_entry_t directory_words[MD_PAGE_SIZE/CACHE_SLINE_SIZE]; + } dir_mem_entry_t; + + + + typedef union md_perf_sel { +- u64 perf_sel_reg; ++ __u64 perf_sel_reg; + struct { +- u64 perf_rsvd : 60, ++ __u64 perf_rsvd : 60, + perf_en : 1, + perf_sel : 3; + } perf_sel_bits; + } md_perf_sel_t; + + typedef union md_perf_cnt { +- u64 perf_cnt; ++ __u64 perf_cnt; + struct { +- u64 perf_rsvd : 44, ++ __u64 perf_rsvd : 44, + perf_cnt : 20; + } perf_cnt_bits; + } md_perf_cnt_t; +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/sn0/hubni.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/sn0/hubni.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/sn0/hubni.h 2003-12-15 12:47:02.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/sn0/hubni.h 2004-08-26 05:26:48.000000000 -0500 +@@ -229,9 +229,9 @@ + #ifndef __ASSEMBLY__ + + typedef union hubni_port_error_u { +- u64 nipe_reg_value; ++ __u64 nipe_reg_value; + struct { +- u64 nipe_rsvd: 26, /* unused */ ++ __u64 nipe_rsvd: 26, /* unused */ + nipe_lnk_reset: 1, /* link reset */ + nipe_intl_err: 1, /* internal error */ + nipe_bad_msg: 1, /* bad message */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/sn0/hubpi.h linux-libc-headers-2.6.8.0/include/asm-mips/sn/sn0/hubpi.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/sn/sn0/hubpi.h 2003-12-15 12:47:02.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/sn/sn0/hubpi.h 2004-08-26 05:26:36.000000000 -0500 +@@ -312,7 +312,7 @@ + */ + + struct err_stack_format { +- u64 sk_addr : 33, /* address */ ++ __u64 sk_addr : 33, /* address */ + sk_cmd : 8, /* message command */ + sk_crb_sts : 10, /* status from RRB or WRB */ + sk_rw_rb : 1, /* RRB == 0, WRB == 1 */ +@@ -323,12 +323,12 @@ + }; + + typedef union pi_err_stack { +- u64 pi_stk_word; ++ __u64 pi_stk_word; + struct err_stack_format pi_stk_fmt; + } pi_err_stack_t; + + struct err_status0_format { +- u64 s0_valid : 1, /* Valid */ ++ __u64 s0_valid : 1, /* Valid */ + s0_ovr_run : 1, /* Overrun, spooled to memory */ + s0_addr : 37, /* address */ + s0_cmd : 8, /* message command */ +@@ -338,12 +338,12 @@ + }; + + typedef union pi_err_stat0 { +- u64 pi_stat0_word; ++ __u64 pi_stat0_word; + struct err_status0_format pi_stat0_fmt; + } pi_err_stat0_t; + + struct err_status1_format { +- u64 s1_src : 11, /* message source */ ++ __u64 s1_src : 11, /* message source */ + s1_crb_sts : 10, /* status from RRB or WRB */ + s1_rw_rb : 1, /* RRB == 0, WRB == 1 */ + s1_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ +@@ -353,11 +353,11 @@ + }; + + typedef union pi_err_stat1 { +- u64 pi_stat1_word; ++ __u64 pi_stat1_word; + struct err_status1_format pi_stat1_fmt; + } pi_err_stat1_t; + +-typedef u64 rtc_time_t; ++typedef __u64 rtc_time_t; + + #endif /* !__ASSEMBLY__ */ + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/stackframe.h linux-libc-headers-2.6.8.0/include/asm-mips/stackframe.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/stackframe.h 2004-08-18 13:15:41.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/stackframe.h 2004-08-26 05:14:41.000000000 -0500 +@@ -25,7 +25,7 @@ + + .macro SAVE_TEMP + mfhi v1 +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + LONG_S $8, PT_R8(sp) + LONG_S $9, PT_R9(sp) + #endif +@@ -55,7 +55,7 @@ + + #ifdef CONFIG_SMP + .macro get_saved_sp /* SMP variation */ +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + mfc0 k0, CP0_CONTEXT + lui k1, %hi(kernelsp) + srl k0, k0, 23 +@@ -63,7 +63,7 @@ + addu k1, k0 + LONG_L k1, %lo(kernelsp)(k1) + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + MFC0 k1, CP0_CONTEXT + dsra k1, 23 + lui k0, %hi(pgd_current) +@@ -76,13 +76,13 @@ + .endm + + .macro set_saved_sp stackp temp temp2 +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + mfc0 \temp, CP0_CONTEXT + srl \temp, 23 + sll \temp, 2 + LONG_S \stackp, kernelsp(\temp) + #endif +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + lw \temp, TI_CPU(gp) + dsll \temp, 3 + lui \temp2, %hi(kernelsp) +@@ -127,7 +127,7 @@ + LONG_S $6, PT_R6(sp) + MFC0 v1, CP0_EPC + LONG_S $7, PT_R7(sp) +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + LONG_S $8, PT_R8(sp) + LONG_S $9, PT_R9(sp) + #endif +@@ -156,7 +156,7 @@ + + .macro RESTORE_TEMP + LONG_L $24, PT_LO(sp) +-#ifdef CONFIG_MIPS32 ++#ifndef __mips64 + LONG_L $8, PT_R8(sp) + LONG_L $9, PT_R9(sp) + #endif +@@ -204,7 +204,7 @@ + LONG_L $31, PT_R31(sp) + LONG_L $28, PT_R28(sp) + LONG_L $25, PT_R25(sp) +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + LONG_L $8, PT_R8(sp) + LONG_L $9, PT_R9(sp) + #endif +@@ -249,7 +249,7 @@ + LONG_L $31, PT_R31(sp) + LONG_L $28, PT_R28(sp) + LONG_L $25, PT_R25(sp) +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + LONG_L $8, PT_R8(sp) + LONG_L $9, PT_R9(sp) + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/system.h linux-libc-headers-2.6.8.0/include/asm-mips/system.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/system.h 2004-08-18 13:15:42.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/system.h 2004-08-28 18:13:39.000000000 -0500 +@@ -15,10 +15,11 @@ + #include + + #include ++#include + + #include + #include +-#include ++#include + + __asm__ ( + ".macro\tlocal_irq_enable\n\t" +@@ -311,7 +312,7 @@ + return retval; + } + +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val) + { + __u64 retval; +@@ -406,7 +407,7 @@ + return retval; + } + +-#ifdef CONFIG_MIPS64 ++#ifdef __mips64 + static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old, + unsigned long new) + { +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/tx4927/tx4927_mips.h linux-libc-headers-2.6.8.0/include/asm-mips/tx4927/tx4927_mips.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/tx4927/tx4927_mips.h 2003-12-15 12:47:03.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/tx4927/tx4927_mips.h 2004-08-26 05:22:30.000000000 -0500 +@@ -36,15 +36,15 @@ + ".set\tmips0"); + } + +-#define reg_rd08(r) ((u8 )(*((vu8 *)(r)))) +-#define reg_rd16(r) ((u16)(*((vu16*)(r)))) +-#define reg_rd32(r) ((u32)(*((vu32*)(r)))) +-#define reg_rd64(r) ((u64)(*((vu64*)(r)))) ++#define reg_rd08(r) ((__u8 )(*((vu8 *)(r)))) ++#define reg_rd16(r) ((__u16)(*((vu16*)(r)))) ++#define reg_rd32(r) ((__u32)(*((vu32*)(r)))) ++#define reg_rd64(r) ((__u64)(*((vu64*)(r)))) + +-#define reg_wr08(r,v) ((*((vu8 *)(r)))=((u8 )(v))) +-#define reg_wr16(r,v) ((*((vu16*)(r)))=((u16)(v))) +-#define reg_wr32(r,v) ((*((vu32*)(r)))=((u32)(v))) +-#define reg_wr64(r,v) ((*((vu64*)(r)))=((u64)(v))) ++#define reg_wr08(r,v) ((*((vu8 *)(r)))=((__u8 )(v))) ++#define reg_wr16(r,v) ((*((vu16*)(r)))=((__u16)(v))) ++#define reg_wr32(r,v) ((*((vu32*)(r)))=((__u32)(v))) ++#define reg_wr64(r,v) ((*((vu64*)(r)))=((__u64)(v))) + + typedef volatile __signed char vs8; + typedef volatile unsigned char vu8; +@@ -55,10 +55,10 @@ + typedef volatile __signed int vs32; + typedef volatile unsigned int vu32; + +-typedef s8 s08; ++typedef __s8 s08; + typedef vs8 vs08; + +-typedef u8 u08; ++typedef __u8 u08; + typedef vu8 vu08; + + +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/unaligned.h linux-libc-headers-2.6.8.0/include/asm-mips/unaligned.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/unaligned.h 2004-08-15 15:38:27.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/unaligned.h 2004-08-26 05:22:21.000000000 -0500 +@@ -17,7 +17,7 @@ + * + * This macro should be used for accessing values larger in size than + * single bytes at locations that are expected to be improperly aligned, +- * e.g. retrieving a u16 value from a location not u16-aligned. ++ * e.g. retrieving a __u16 value from a location not __u16-aligned. + * + * Note that unaligned accesses can be very expensive on some architectures. + */ +@@ -31,7 +31,7 @@ + * + * This macro should be used for placing values larger in size than + * single bytes at locations that are expected to be improperly aligned, +- * e.g. writing a u16 value to a location not u16-aligned. ++ * e.g. writing a __u16 value to a location not __u16-aligned. + * + * Note that unaligned accesses can be very expensive on some architectures. + */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/asm-mips/xtalk/xwidget.h linux-libc-headers-2.6.8.0/include/asm-mips/xtalk/xwidget.h +--- linux-libc-headers-2.6.8.0-dist/include/asm-mips/xtalk/xwidget.h 2003-12-15 12:47:03.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/asm-mips/xtalk/xwidget.h 2004-08-26 05:23:33.000000000 -0500 +@@ -92,7 +92,7 @@ + * defined here + */ + #ifndef __ASSEMBLY__ +-typedef u32 widgetreg_t; ++typedef __u32 widgetreg_t; + + /* widget configuration registers */ + typedef volatile struct widget_cfg { +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/acpi.h linux-libc-headers-2.6.8.0/include/linux/acpi.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/acpi.h 2004-08-18 13:16:01.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/acpi.h 2004-08-26 05:41:49.000000000 -0500 +@@ -51,49 +51,49 @@ + + struct acpi_table_rsdp { + char signature[8]; +- u8 checksum; ++ __u8 checksum; + char oem_id[6]; +- u8 revision; +- u32 rsdt_address; ++ __u8 revision; ++ __u32 rsdt_address; + } __attribute__ ((packed)); + + struct acpi20_table_rsdp { + char signature[8]; +- u8 checksum; ++ __u8 checksum; + char oem_id[6]; +- u8 revision; +- u32 rsdt_address; +- u32 length; +- u64 xsdt_address; +- u8 ext_checksum; +- u8 reserved[3]; ++ __u8 revision; ++ __u32 rsdt_address; ++ __u32 length; ++ __u64 xsdt_address; ++ __u8 ext_checksum; ++ __u8 reserved[3]; + } __attribute__ ((packed)); + + typedef struct { +- u8 type; +- u8 length; ++ __u8 type; ++ __u8 length; + } __attribute__ ((packed)) acpi_table_entry_header; + + /* Root System Description Table (RSDT) */ + + struct acpi_table_rsdt { + struct acpi_table_header header; +- u32 entry[8]; ++ __u32 entry[8]; + } __attribute__ ((packed)); + + /* Extended System Description Table (XSDT) */ + + struct acpi_table_xsdt { + struct acpi_table_header header; +- u64 entry[1]; ++ __u64 entry[1]; + } __attribute__ ((packed)); + + /* Fixed ACPI Description Table (FADT) */ + + struct acpi_table_fadt { + struct acpi_table_header header; +- u32 facs_addr; +- u32 dsdt_addr; ++ __u32 facs_addr; ++ __u32 dsdt_addr; + /* ... */ + } __attribute__ ((packed)); + +@@ -101,10 +101,10 @@ + + struct acpi_table_madt { + struct acpi_table_header header; +- u32 lapic_address; ++ __u32 lapic_address; + struct { +- u32 pcat_compat:1; +- u32 reserved:31; ++ __u32 pcat_compat:1; ++ __u32 reserved:31; + } flags; + } __attribute__ ((packed)); + +@@ -122,85 +122,85 @@ + }; + + typedef struct { +- u16 polarity:2; +- u16 trigger:2; +- u16 reserved:12; ++ __u16 polarity:2; ++ __u16 trigger:2; ++ __u16 reserved:12; + } __attribute__ ((packed)) acpi_interrupt_flags; + + struct acpi_table_lapic { + acpi_table_entry_header header; +- u8 acpi_id; +- u8 id; ++ __u8 acpi_id; ++ __u8 id; + struct { +- u32 enabled:1; +- u32 reserved:31; ++ __u32 enabled:1; ++ __u32 reserved:31; + } flags; + } __attribute__ ((packed)); + + struct acpi_table_ioapic { + acpi_table_entry_header header; +- u8 id; +- u8 reserved; +- u32 address; +- u32 global_irq_base; ++ __u8 id; ++ __u8 reserved; ++ __u32 address; ++ __u32 global_irq_base; + } __attribute__ ((packed)); + + struct acpi_table_int_src_ovr { + acpi_table_entry_header header; +- u8 bus; +- u8 bus_irq; +- u32 global_irq; ++ __u8 bus; ++ __u8 bus_irq; ++ __u32 global_irq; + acpi_interrupt_flags flags; + } __attribute__ ((packed)); + + struct acpi_table_nmi_src { + acpi_table_entry_header header; + acpi_interrupt_flags flags; +- u32 global_irq; ++ __u32 global_irq; + } __attribute__ ((packed)); + + struct acpi_table_lapic_nmi { + acpi_table_entry_header header; +- u8 acpi_id; ++ __u8 acpi_id; + acpi_interrupt_flags flags; +- u8 lint; ++ __u8 lint; + } __attribute__ ((packed)); + + struct acpi_table_lapic_addr_ovr { + acpi_table_entry_header header; +- u8 reserved[2]; +- u64 address; ++ __u8 reserved[2]; ++ __u64 address; + } __attribute__ ((packed)); + + struct acpi_table_iosapic { + acpi_table_entry_header header; +- u8 id; +- u8 reserved; +- u32 global_irq_base; +- u64 address; ++ __u8 id; ++ __u8 reserved; ++ __u32 global_irq_base; ++ __u64 address; + } __attribute__ ((packed)); + + struct acpi_table_lsapic { + acpi_table_entry_header header; +- u8 acpi_id; +- u8 id; +- u8 eid; +- u8 reserved[3]; ++ __u8 acpi_id; ++ __u8 id; ++ __u8 eid; ++ __u8 reserved[3]; + struct { +- u32 enabled:1; +- u32 reserved:31; ++ __u32 enabled:1; ++ __u32 reserved:31; + } flags; + } __attribute__ ((packed)); + + struct acpi_table_plat_int_src { + acpi_table_entry_header header; + acpi_interrupt_flags flags; +- u8 type; /* See acpi_interrupt_type */ +- u8 id; +- u8 eid; +- u8 iosapic_vector; +- u32 global_irq; +- u32 reserved; ++ __u8 type; /* See acpi_interrupt_type */ ++ __u8 id; ++ __u8 eid; ++ __u8 iosapic_vector; ++ __u32 global_irq; ++ __u32 reserved; + } __attribute__ ((packed)); + + enum acpi_interrupt_id { +@@ -213,21 +213,21 @@ + #define ACPI_SPACE_MEM 0 + + struct acpi_gen_regaddr { +- u8 space_id; +- u8 bit_width; +- u8 bit_offset; +- u8 resv; +- u32 addrl; +- u32 addrh; ++ __u8 space_id; ++ __u8 bit_width; ++ __u8 bit_offset; ++ __u8 resv; ++ __u32 addrl; ++ __u32 addrh; + } __attribute__ ((packed)); + + struct acpi_table_hpet { + struct acpi_table_header header; +- u32 id; ++ __u32 id; + struct acpi_gen_regaddr addr; +- u8 number; +- u16 min_tick; +- u8 page_protect; ++ __u8 number; ++ __u16 min_tick; ++ __u8 page_protect; + } __attribute__ ((packed)); + + /* +@@ -236,17 +236,17 @@ + */ + struct acpi_table_sbf + { +- u8 sbf_signature[4]; +- u32 sbf_len; +- u8 sbf_revision; +- u8 sbf_csum; +- u8 sbf_oemid[6]; +- u8 sbf_oemtable[8]; +- u8 sbf_revdata[4]; +- u8 sbf_creator[4]; +- u8 sbf_crearev[4]; +- u8 sbf_cmos; +- u8 sbf_spare[3]; ++ __u8 sbf_signature[4]; ++ __u32 sbf_len; ++ __u8 sbf_revision; ++ __u8 sbf_csum; ++ __u8 sbf_oemid[6]; ++ __u8 sbf_oemtable[8]; ++ __u8 sbf_revdata[4]; ++ __u8 sbf_creator[4]; ++ __u8 sbf_crearev[4]; ++ __u8 sbf_cmos; ++ __u8 sbf_spare[3]; + } __attribute__ ((packed)); + + /* +@@ -256,8 +256,8 @@ + + struct acpi_table_srat { + struct acpi_table_header header; +- u32 table_revision; +- u64 reserved; ++ __u32 table_revision; ++ __u64 reserved; + } __attribute__ ((packed)); + + enum acpi_srat_entry_id { +@@ -268,31 +268,31 @@ + + struct acpi_table_processor_affinity { + acpi_table_entry_header header; +- u8 proximity_domain; +- u8 apic_id; ++ __u8 proximity_domain; ++ __u8 apic_id; + struct { +- u32 enabled:1; +- u32 reserved:31; ++ __u32 enabled:1; ++ __u32 reserved:31; + } flags; +- u8 lsapic_eid; +- u8 reserved[7]; ++ __u8 lsapic_eid; ++ __u8 reserved[7]; + } __attribute__ ((packed)); + + struct acpi_table_memory_affinity { + acpi_table_entry_header header; +- u8 proximity_domain; +- u8 reserved1[5]; +- u32 base_addr_lo; +- u32 base_addr_hi; +- u32 length_lo; +- u32 length_hi; +- u32 memory_type; /* See acpi_address_range_id */ ++ __u8 proximity_domain; ++ __u8 reserved1[5]; ++ __u32 base_addr_lo; ++ __u32 base_addr_hi; ++ __u32 length_lo; ++ __u32 length_hi; ++ __u32 memory_type; /* See acpi_address_range_id */ + struct { +- u32 enabled:1; +- u32 hot_pluggable:1; +- u32 reserved:30; ++ __u32 enabled:1; ++ __u32 hot_pluggable:1; ++ __u32 reserved:30; + } flags; +- u64 reserved2; ++ __u64 reserved2; + } __attribute__ ((packed)); + + enum acpi_address_range_id { +@@ -310,17 +310,17 @@ + + struct acpi_table_slit { + struct acpi_table_header header; +- u64 localities; +- u8 entry[1]; /* real size = localities^2 */ ++ __u64 localities; ++ __u8 entry[1]; /* real size = localities^2 */ + } __attribute__ ((packed)); + + /* Smart Battery Description Table (SBST) */ + + struct acpi_table_sbst { + struct acpi_table_header header; +- u32 warning; /* Warn user */ +- u32 low; /* Critical sleep */ +- u32 critical; /* Critical shutdown */ ++ __u32 warning; /* Warn user */ ++ __u32 low; /* Critical sleep */ ++ __u32 critical; /* Critical shutdown */ + } __attribute__ ((packed)); + + /* Embedded Controller Boot Resources Table (ECDT) */ +@@ -329,8 +329,8 @@ + struct acpi_table_header header; + struct acpi_generic_address ec_control; + struct acpi_generic_address ec_data; +- u32 uid; +- u8 gpe_bit; ++ __u32 uid; ++ __u8 gpe_bit; + char ec_id[0]; + } __attribute__ ((packed)); + +@@ -338,9 +338,9 @@ + + struct acpi_table_mcfg { + struct acpi_table_header header; +- u8 reserved[8]; +- u32 base_address; +- u32 base_reserved; ++ __u8 reserved[8]; ++ __u32 base_address; ++ __u32 base_reserved; + } __attribute__ ((packed)); + + /* Table Handlers */ +@@ -396,7 +396,7 @@ + + extern int acpi_mp_config; + +-extern u32 pci_mmcfg_base_addr; ++extern __u32 pci_mmcfg_base_addr; + + extern int sbf_port ; + +@@ -411,20 +411,20 @@ + + #endif /*!CONFIG_ACPI_BOOT*/ + +-unsigned int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low); +-int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); ++unsigned int acpi_register_gsi (__u32 gsi, int edge_level, int active_high_low); ++int acpi_gsi_to_irq (__u32 gsi, unsigned int *irq); + + #ifdef CONFIG_ACPI_PCI + + struct acpi_prt_entry { + struct list_head node; + struct acpi_pci_id id; +- u8 pin; ++ __u8 pin; + struct { + acpi_handle handle; +- u32 index; ++ __u32 index; + } link; +- u32 irq; ++ __u32 irq; + }; + + struct acpi_prt_list { +@@ -451,8 +451,8 @@ + + #ifdef CONFIG_ACPI_EC + +-int ec_read(u8 addr, u8 *val); +-int ec_write(u8 addr, u8 val); ++int ec_read(__u8 addr, __u8 *val); ++int ec_write(__u8 addr, __u8 val); + + #endif /*CONFIG_ACPI_EC*/ + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/affs_fs_i.h linux-libc-headers-2.6.8.0/include/linux/affs_fs_i.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/affs_fs_i.h 2003-12-31 17:46:48.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/affs_fs_i.h 2004-08-26 05:41:49.000000000 -0500 +@@ -9,13 +9,13 @@ + //#define AFFS_CACHE_SIZE (4*4) + + #define AFFS_MAX_PREALLOC 32 +-#define AFFS_LC_SIZE (AFFS_CACHE_SIZE/sizeof(u32)/2) ++#define AFFS_LC_SIZE (AFFS_CACHE_SIZE/sizeof(__u32)/2) + #define AFFS_AC_SIZE (AFFS_CACHE_SIZE/sizeof(struct affs_ext_key)/2) + #define AFFS_AC_MASK (AFFS_AC_SIZE-1) + + struct affs_ext_key { +- u32 ext; /* idx of the extended block */ +- u32 key; /* block number */ ++ __u32 ext; /* idx of the extended block */ ++ __u32 key; /* block number */ + }; + + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/affs_fs_sb.h linux-libc-headers-2.6.8.0/include/linux/affs_fs_sb.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/affs_fs_sb.h 2004-08-18 13:16:01.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/affs_fs_sb.h 2004-08-26 05:41:49.000000000 -0500 +@@ -9,8 +9,8 @@ + */ + + struct affs_bm_info { +- u32 bm_key; /* Disk block number */ +- u32 bm_free; /* Free blocks in here */ ++ __u32 bm_key; /* Disk block number */ ++ __u32 bm_free; /* Free blocks in here */ + }; + + #define SF_INTL 0x0001 /* International filesystem. */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/affs_hardblocks.h linux-libc-headers-2.6.8.0/include/linux/affs_hardblocks.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/affs_hardblocks.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/affs_hardblocks.h 2004-08-26 05:41:49.000000000 -0500 +@@ -4,59 +4,59 @@ + /* Just the needed definitions for the RDB of an Amiga HD. */ + + struct RigidDiskBlock { +- u32 rdb_ID; +- u32 rdb_SummedLongs; +- s32 rdb_ChkSum; +- u32 rdb_HostID; +- u32 rdb_BlockBytes; +- u32 rdb_Flags; +- u32 rdb_BadBlockList; +- u32 rdb_PartitionList; +- u32 rdb_FileSysHeaderList; +- u32 rdb_DriveInit; +- u32 rdb_Reserved1[6]; +- u32 rdb_Cylinders; +- u32 rdb_Sectors; +- u32 rdb_Heads; +- u32 rdb_Interleave; +- u32 rdb_Park; +- u32 rdb_Reserved2[3]; +- u32 rdb_WritePreComp; +- u32 rdb_ReducedWrite; +- u32 rdb_StepRate; +- u32 rdb_Reserved3[5]; +- u32 rdb_RDBBlocksLo; +- u32 rdb_RDBBlocksHi; +- u32 rdb_LoCylinder; +- u32 rdb_HiCylinder; +- u32 rdb_CylBlocks; +- u32 rdb_AutoParkSeconds; +- u32 rdb_HighRDSKBlock; +- u32 rdb_Reserved4; ++ __u32 rdb_ID; ++ __u32 rdb_SummedLongs; ++ __s32 rdb_ChkSum; ++ __u32 rdb_HostID; ++ __u32 rdb_BlockBytes; ++ __u32 rdb_Flags; ++ __u32 rdb_BadBlockList; ++ __u32 rdb_PartitionList; ++ __u32 rdb_FileSysHeaderList; ++ __u32 rdb_DriveInit; ++ __u32 rdb_Reserved1[6]; ++ __u32 rdb_Cylinders; ++ __u32 rdb_Sectors; ++ __u32 rdb_Heads; ++ __u32 rdb_Interleave; ++ __u32 rdb_Park; ++ __u32 rdb_Reserved2[3]; ++ __u32 rdb_WritePreComp; ++ __u32 rdb_ReducedWrite; ++ __u32 rdb_StepRate; ++ __u32 rdb_Reserved3[5]; ++ __u32 rdb_RDBBlocksLo; ++ __u32 rdb_RDBBlocksHi; ++ __u32 rdb_LoCylinder; ++ __u32 rdb_HiCylinder; ++ __u32 rdb_CylBlocks; ++ __u32 rdb_AutoParkSeconds; ++ __u32 rdb_HighRDSKBlock; ++ __u32 rdb_Reserved4; + char rdb_DiskVendor[8]; + char rdb_DiskProduct[16]; + char rdb_DiskRevision[4]; + char rdb_ControllerVendor[8]; + char rdb_ControllerProduct[16]; + char rdb_ControllerRevision[4]; +- u32 rdb_Reserved5[10]; ++ __u32 rdb_Reserved5[10]; + }; + + #define IDNAME_RIGIDDISK 0x5244534B /* "RDSK" */ + + struct PartitionBlock { +- u32 pb_ID; +- u32 pb_SummedLongs; +- s32 pb_ChkSum; +- u32 pb_HostID; +- u32 pb_Next; +- u32 pb_Flags; +- u32 pb_Reserved1[2]; +- u32 pb_DevFlags; +- u8 pb_DriveName[32]; +- u32 pb_Reserved2[15]; +- u32 pb_Environment[17]; +- u32 pb_EReserved[15]; ++ __u32 pb_ID; ++ __u32 pb_SummedLongs; ++ __s32 pb_ChkSum; ++ __u32 pb_HostID; ++ __u32 pb_Next; ++ __u32 pb_Flags; ++ __u32 pb_Reserved1[2]; ++ __u32 pb_DevFlags; ++ __u8 pb_DriveName[32]; ++ __u32 pb_Reserved2[15]; ++ __u32 pb_Environment[17]; ++ __u32 pb_EReserved[15]; + }; + + #define IDNAME_PARTITION 0x50415254 /* "PART" */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/amigaffs.h linux-libc-headers-2.6.8.0/include/linux/amigaffs.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/amigaffs.h 2003-12-31 17:46:48.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/amigaffs.h 2004-08-26 05:41:49.000000000 -0500 +@@ -64,90 +64,90 @@ + #define AFFS_DATA(bh) (((struct affs_data_head *)(bh)->b_data)->data) + + struct affs_date { +- u32 days; +- u32 mins; +- u32 ticks; ++ __u32 days; ++ __u32 mins; ++ __u32 ticks; + }; + + struct affs_short_date { +- u16 days; +- u16 mins; +- u16 ticks; ++ __u16 days; ++ __u16 mins; ++ __u16 ticks; + }; + + struct affs_root_head { +- u32 ptype; +- u32 spare1; +- u32 spare2; +- u32 hash_size; +- u32 spare3; +- u32 checksum; +- u32 hashtable[1]; ++ __u32 ptype; ++ __u32 spare1; ++ __u32 spare2; ++ __u32 hash_size; ++ __u32 spare3; ++ __u32 checksum; ++ __u32 hashtable[1]; + }; + + struct affs_root_tail { +- u32 bm_flag; +- u32 bm_blk[AFFS_ROOT_BMAPS]; +- u32 bm_ext; ++ __u32 bm_flag; ++ __u32 bm_blk[AFFS_ROOT_BMAPS]; ++ __u32 bm_ext; + struct affs_date root_change; +- u8 disk_name[32]; +- u32 spare1; +- u32 spare2; ++ __u8 disk_name[32]; ++ __u32 spare1; ++ __u32 spare2; + struct affs_date disk_change; + struct affs_date disk_create; +- u32 spare3; +- u32 spare4; +- u32 dcache; +- u32 stype; ++ __u32 spare3; ++ __u32 spare4; ++ __u32 dcache; ++ __u32 stype; + }; + + struct affs_head { +- u32 ptype; +- u32 key; +- u32 block_count; +- u32 spare1; +- u32 first_data; +- u32 checksum; +- u32 table[1]; ++ __u32 ptype; ++ __u32 key; ++ __u32 block_count; ++ __u32 spare1; ++ __u32 first_data; ++ __u32 checksum; ++ __u32 table[1]; + }; + + struct affs_tail { +- u32 spare1; +- u16 uid; +- u16 gid; +- u32 protect; +- u32 size; +- u8 comment[92]; ++ __u32 spare1; ++ __u16 uid; ++ __u16 gid; ++ __u32 protect; ++ __u32 size; ++ __u8 comment[92]; + struct affs_date change; +- u8 name[32]; +- u32 spare2; +- u32 original; +- u32 link_chain; +- u32 spare[5]; +- u32 hash_chain; +- u32 parent; +- u32 extension; +- u32 stype; ++ __u8 name[32]; ++ __u32 spare2; ++ __u32 original; ++ __u32 link_chain; ++ __u32 spare[5]; ++ __u32 hash_chain; ++ __u32 parent; ++ __u32 extension; ++ __u32 stype; + }; + + struct slink_front + { +- u32 ptype; +- u32 key; +- u32 spare1[3]; +- u32 checksum; +- u8 symname[1]; /* depends on block size */ ++ __u32 ptype; ++ __u32 key; ++ __u32 spare1[3]; ++ __u32 checksum; ++ __u8 symname[1]; /* depends on block size */ + }; + + struct affs_data_head + { +- u32 ptype; +- u32 key; +- u32 sequence; +- u32 size; +- u32 next; +- u32 checksum; +- u8 data[1]; /* depends on block size */ ++ __u32 ptype; ++ __u32 key; ++ __u32 sequence; ++ __u32 size; ++ __u32 next; ++ __u32 checksum; ++ __u8 data[1]; /* depends on block size */ + }; + + /* Permission bits */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/ata.h linux-libc-headers-2.6.8.0/include/linux/ata.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/ata.h 2004-08-18 13:16:01.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/ata.h 2004-08-26 05:41:49.000000000 -0500 +@@ -34,7 +34,7 @@ + ATA_MAX_PRD = 256, /* we could make these 256/256 */ + ATA_SECT_SIZE = 512, + ATA_SECT_SIZE_MASK = (ATA_SECT_SIZE - 1), +- ATA_SECT_DWORDS = ATA_SECT_SIZE / sizeof(u32), ++ ATA_SECT_DWORDS = ATA_SECT_SIZE / sizeof(__u32), + + ATA_ID_WORDS = 256, + ATA_ID_PROD_OFS = 27, +@@ -176,31 +176,31 @@ + /* core structures */ + + struct ata_prd { +- u32 addr; +- u32 flags_len; ++ __u32 addr; ++ __u32 flags_len; + } __attribute__((packed)); + + struct ata_taskfile { + unsigned long flags; /* ATA_TFLAG_xxx */ +- u8 protocol; /* ATA_PROT_xxx */ ++ __u8 protocol; /* ATA_PROT_xxx */ + +- u8 ctl; /* control reg */ ++ __u8 ctl; /* control reg */ + +- u8 hob_feature; /* additional data */ +- u8 hob_nsect; /* to support LBA48 */ +- u8 hob_lbal; +- u8 hob_lbam; +- u8 hob_lbah; ++ __u8 hob_feature; /* additional data */ ++ __u8 hob_nsect; /* to support LBA48 */ ++ __u8 hob_lbal; ++ __u8 hob_lbam; ++ __u8 hob_lbah; + +- u8 feature; +- u8 nsect; +- u8 lbal; +- u8 lbam; +- u8 lbah; ++ __u8 feature; ++ __u8 nsect; ++ __u8 lbal; ++ __u8 lbam; ++ __u8 lbah; + +- u8 device; ++ __u8 device; + +- u8 command; /* IO operation */ ++ __u8 command; /* IO operation */ + }; + + #define ata_id_is_ata(dev) (((dev)->id[0] & (1 << 15)) == 0) +@@ -213,12 +213,12 @@ + #define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 8)) + #define ata_id_removeable(dev) ((dev)->id[0] & (1 << 7)) + #define ata_id_u32(dev,n) \ +- (((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)])) ++ (((__u32) (dev)->id[(n) + 1] << 16) | ((__u32) (dev)->id[(n)])) + #define ata_id_u64(dev,n) \ +- ( ((u64) dev->id[(n) + 3] << 48) | \ +- ((u64) dev->id[(n) + 2] << 32) | \ +- ((u64) dev->id[(n) + 1] << 16) | \ +- ((u64) dev->id[(n) + 0]) ) ++ ( ((__u64) dev->id[(n) + 3] << 48) | \ ++ ((__u64) dev->id[(n) + 2] << 32) | \ ++ ((__u64) dev->id[(n) + 1] << 16) | \ ++ ((__u64) dev->id[(n) + 0]) ) + + static inline int is_atapi_taskfile(struct ata_taskfile *tf) + { +@@ -226,7 +226,7 @@ + (tf->protocol == ATA_PROT_ATAPI_DMA); + } + +-static inline int ata_ok(u8 status) ++static inline int ata_ok(__u8 status) + { + return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) + == ATA_DRDY); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/bitops.h linux-libc-headers-2.6.8.0/include/linux/bitops.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/bitops.h 2004-06-09 07:00:49.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/bitops.h 2004-08-26 05:41:49.000000000 -0500 +@@ -114,7 +114,7 @@ + return generic_hweight32((unsigned int)(w >> 32)) + + generic_hweight32((unsigned int)w); + #else +- u64 res; ++ __u64 res; + res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul); + res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); + res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/compat.h linux-libc-headers-2.6.8.0/include/linux/compat.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/compat.h 2004-06-09 07:00:49.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/compat.h 2004-08-26 05:41:49.000000000 -0500 +@@ -78,9 +78,9 @@ + }; + + struct compat_dirent { +- u32 d_ino; ++ __u32 d_ino; + compat_off_t d_off; +- u16 d_reclen; ++ __u16 d_reclen; + char d_name[256]; + }; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/console.h linux-libc-headers-2.6.8.0/include/linux/console.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/console.h 2004-08-18 13:16:02.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/console.h 2004-08-26 05:41:49.000000000 -0500 +@@ -49,9 +49,9 @@ + int (*con_scrolldelta)(struct vc_data *, int); + int (*con_set_origin)(struct vc_data *); + void (*con_save_screen)(struct vc_data *); +- u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8); +- void (*con_invert_region)(struct vc_data *, u16 *, int); +- u16 *(*con_screen_pos)(struct vc_data *, int); ++ __u8 (*con_build_attr)(struct vc_data *, __u8, __u8, __u8, __u8, __u8); ++ void (*con_invert_region)(struct vc_data *, __u16 *, int); ++ __u16 *(*con_screen_pos)(struct vc_data *, int); + unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *); + }; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/cpufreq.h linux-libc-headers-2.6.8.0/include/linux/cpufreq.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/cpufreq.h 2004-06-23 16:52:53.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/cpufreq.h 2004-08-26 05:41:49.000000000 -0500 +@@ -103,7 +103,7 @@ + unsigned int cpu; /* cpu nr */ + unsigned int old; + unsigned int new; +- u8 flags; /* flags of cpufreq_driver, see below. */ ++ __u8 flags; /* flags of cpufreq_driver, see below. */ + }; + + +@@ -120,13 +120,13 @@ + { + #if BITS_PER_LONG == 32 + +- u64 result = ((u64) old) * ((u64) mult); ++ __u64 result = ((__u64) old) * ((__u64) mult); + do_div(result, div); + return (unsigned long) result; + + #elif BITS_PER_LONG == 64 + +- unsigned long result = old * ((u64) mult); ++ unsigned long result = old * ((__u64) mult); + result /= div; + return result; + +@@ -178,7 +178,7 @@ + struct cpufreq_driver { + struct module *owner; + char name[CPUFREQ_NAME_LEN]; +- u8 flags; ++ __u8 flags; + + /* needed by all drivers */ + int (*init) (struct cpufreq_policy *policy); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/cramfs_fs.h linux-libc-headers-2.6.8.0/include/linux/cramfs_fs.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/cramfs_fs.h 2004-01-05 12:42:27.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/cramfs_fs.h 2004-08-26 05:41:49.000000000 -0500 +@@ -2,9 +2,9 @@ + #define __CRAMFS_H + + +-typedef unsigned char u8; +-typedef unsigned short u16; +-typedef unsigned int u32; ++typedef unsigned char __u8; ++typedef unsigned short __u16; ++typedef unsigned int __u32; + + + #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ +@@ -31,9 +31,9 @@ + * Reasonably terse representation of the inode data. + */ + struct cramfs_inode { +- u32 mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH; ++ __u32 mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH; + /* SIZE for device files is i_rdev */ +- u32 size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH; ++ __u32 size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH; + /* NAMELEN is the length of the file name, divided by 4 and + rounded up. (cramfs doesn't support hard links.) */ + /* OFFSET: For symlinks and non-empty regular files, this +@@ -42,27 +42,27 @@ + see README). For non-empty directories it is the offset + (divided by 4) of the inode of the first file in that + directory. For anything else, offset is zero. */ +- u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH; ++ __u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH; + }; + + struct cramfs_info { +- u32 crc; +- u32 edition; +- u32 blocks; +- u32 files; ++ __u32 crc; ++ __u32 edition; ++ __u32 blocks; ++ __u32 files; + }; + + /* + * Superblock information at the beginning of the FS. + */ + struct cramfs_super { +- u32 magic; /* 0x28cd3d45 - random number */ +- u32 size; /* length in bytes */ +- u32 flags; /* feature flags */ +- u32 future; /* reserved for future use */ +- u8 signature[16]; /* "Compressed ROMFS" */ ++ __u32 magic; /* 0x28cd3d45 - random number */ ++ __u32 size; /* length in bytes */ ++ __u32 flags; /* feature flags */ ++ __u32 future; /* reserved for future use */ ++ __u8 signature[16]; /* "Compressed ROMFS" */ + struct cramfs_info fsid; /* unique filesystem info */ +- u8 name[16]; /* user-defined name */ ++ __u8 name[16]; /* user-defined name */ + struct cramfs_inode root; /* root inode data */ + }; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/crc32.h linux-libc-headers-2.6.8.0/include/linux/crc32.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/crc32.h 2003-12-15 12:46:57.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/crc32.h 2004-08-26 05:41:49.000000000 -0500 +@@ -7,9 +7,9 @@ + + #include + +-extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len); +-extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len); +-extern u32 bitreverse(u32 in); ++extern __u32 crc32_le(__u32 crc, unsigned char const *p, size_t len); ++extern __u32 crc32_be(__u32 crc, unsigned char const *p, size_t len); ++extern __u32 bitreverse(__u32 in); + + #define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length) + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/crypto.h linux-libc-headers-2.6.8.0/include/linux/crypto.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/crypto.h 2004-04-19 16:13:51.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/crypto.h 2004-08-26 05:41:49.000000000 -0500 +@@ -63,28 +63,28 @@ + struct cipher_alg { + unsigned int cia_min_keysize; + unsigned int cia_max_keysize; +- int (*cia_setkey)(void *ctx, const u8 *key, +- unsigned int keylen, u32 *flags); +- void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src); +- void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src); ++ int (*cia_setkey)(void *ctx, const __u8 *key, ++ unsigned int keylen, __u32 *flags); ++ void (*cia_encrypt)(void *ctx, __u8 *dst, const __u8 *src); ++ void (*cia_decrypt)(void *ctx, __u8 *dst, const __u8 *src); + }; + + struct digest_alg { + unsigned int dia_digestsize; + void (*dia_init)(void *ctx); +- void (*dia_update)(void *ctx, const u8 *data, unsigned int len); +- void (*dia_final)(void *ctx, u8 *out); +- int (*dia_setkey)(void *ctx, const u8 *key, +- unsigned int keylen, u32 *flags); ++ void (*dia_update)(void *ctx, const __u8 *data, unsigned int len); ++ void (*dia_final)(void *ctx, __u8 *out); ++ int (*dia_setkey)(void *ctx, const __u8 *key, ++ unsigned int keylen, __u32 *flags); + }; + + struct compress_alg { + int (*coa_init)(void *ctx); + void (*coa_exit)(void *ctx); +- int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen); +- int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen); ++ int (*coa_compress)(void *ctx, const __u8 *src, unsigned int slen, ++ __u8 *dst, unsigned int *dlen); ++ int (*coa_decompress)(void *ctx, const __u8 *src, unsigned int slen, ++ __u8 *dst, unsigned int *dlen); + }; + + #define cra_cipher cra_u.cipher +@@ -93,7 +93,7 @@ + + struct crypto_alg { + struct list_head cra_list; +- u32 cra_flags; ++ __u32 cra_flags; + unsigned int cra_blocksize; + unsigned int cra_ctxsize; + const char cra_name[CRYPTO_MAX_ALG_NAME]; +@@ -116,7 +116,7 @@ + /* + * Algorithm query interface. + */ +-int crypto_alg_available(const char *name, u32 flags); ++int crypto_alg_available(const char *name, __u32 flags); + + /* + * Transforms: user-instantiated objects which encapsulate algorithms +@@ -128,9 +128,9 @@ + struct cipher_tfm { + void *cit_iv; + unsigned int cit_ivsize; +- u32 cit_mode; ++ __u32 cit_mode; + int (*cit_setkey)(struct crypto_tfm *tfm, +- const u8 *key, unsigned int keylen); ++ const __u8 *key, unsigned int keylen); + int (*cit_encrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, +@@ -138,7 +138,7 @@ + int (*cit_encrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, +- unsigned int nbytes, u8 *iv); ++ unsigned int nbytes, __u8 *iv); + int (*cit_decrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, +@@ -146,19 +146,19 @@ + int (*cit_decrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, +- unsigned int nbytes, u8 *iv); +- void (*cit_xor_block)(u8 *dst, const u8 *src); ++ unsigned int nbytes, __u8 *iv); ++ void (*cit_xor_block)(__u8 *dst, const __u8 *src); + }; + + struct digest_tfm { + void (*dit_init)(struct crypto_tfm *tfm); + void (*dit_update)(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); +- void (*dit_final)(struct crypto_tfm *tfm, u8 *out); ++ void (*dit_final)(struct crypto_tfm *tfm, __u8 *out); + void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, +- unsigned int nsg, u8 *out); ++ unsigned int nsg, __u8 *out); + int (*dit_setkey)(struct crypto_tfm *tfm, +- const u8 *key, unsigned int keylen); ++ const __u8 *key, unsigned int keylen); + #ifdef CONFIG_CRYPTO_HMAC + void *dit_hmac_block; + #endif +@@ -166,11 +166,11 @@ + + struct compress_tfm { + int (*cot_compress)(struct crypto_tfm *tfm, +- const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen); ++ const __u8 *src, unsigned int slen, ++ __u8 *dst, unsigned int *dlen); + int (*cot_decompress)(struct crypto_tfm *tfm, +- const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen); ++ const __u8 *src, unsigned int slen, ++ __u8 *dst, unsigned int *dlen); + }; + + #define crt_cipher crt_u.cipher +@@ -179,7 +179,7 @@ + + struct crypto_tfm { + +- u32 crt_flags; ++ __u32 crt_flags; + + union { + struct cipher_tfm cipher; +@@ -203,7 +203,7 @@ + * crypto_free_tfm() frees up the transform and any associated resources, + * then drops the refcount on the associated algorithm. + */ +-struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags); ++struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, __u32 tfm_flags); + void crypto_free_tfm(struct crypto_tfm *tfm); + + /* +@@ -219,7 +219,7 @@ + return module_name(tfm->__crt_alg->cra_module); + } + +-static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) ++static inline __u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) + { + return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; + } +@@ -270,7 +270,7 @@ + tfm->crt_digest.dit_update(tfm, sg, nsg); + } + +-static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) ++static inline void crypto_digest_final(struct crypto_tfm *tfm, __u8 *out) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_final(tfm, out); +@@ -278,14 +278,14 @@ + + static inline void crypto_digest_digest(struct crypto_tfm *tfm, + struct scatterlist *sg, +- unsigned int nsg, u8 *out) ++ unsigned int nsg, __u8 *out) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_digest(tfm, sg, nsg, out); + } + + static inline int crypto_digest_setkey(struct crypto_tfm *tfm, +- const u8 *key, unsigned int keylen) ++ const __u8 *key, unsigned int keylen) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + if (tfm->crt_digest.dit_setkey == NULL) +@@ -294,7 +294,7 @@ + } + + static inline int crypto_cipher_setkey(struct crypto_tfm *tfm, +- const u8 *key, unsigned int keylen) ++ const __u8 *key, unsigned int keylen) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_setkey(tfm, key, keylen); +@@ -312,7 +312,7 @@ + static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, +- unsigned int nbytes, u8 *iv) ++ unsigned int nbytes, __u8 *iv) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); +@@ -331,7 +331,7 @@ + static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, +- unsigned int nbytes, u8 *iv) ++ unsigned int nbytes, __u8 *iv) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); +@@ -339,30 +339,30 @@ + } + + static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, +- const u8 *src, unsigned int len) ++ const __u8 *src, unsigned int len) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + memcpy(tfm->crt_cipher.cit_iv, src, len); + } + + static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, +- u8 *dst, unsigned int len) ++ __u8 *dst, unsigned int len) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + memcpy(dst, tfm->crt_cipher.cit_iv, len); + } + + static inline int crypto_comp_compress(struct crypto_tfm *tfm, +- const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen) ++ const __u8 *src, unsigned int slen, ++ __u8 *dst, unsigned int *dlen) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen); + } + + static inline int crypto_comp_decompress(struct crypto_tfm *tfm, +- const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen) ++ const __u8 *src, unsigned int slen, ++ __u8 *dst, unsigned int *dlen) + { + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen); +@@ -372,13 +372,13 @@ + * HMAC support. + */ + #ifdef CONFIG_CRYPTO_HMAC +-void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen); ++void crypto_hmac_init(struct crypto_tfm *tfm, __u8 *key, unsigned int *keylen); + void crypto_hmac_update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); +-void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, +- unsigned int *keylen, u8 *out); +-void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, +- struct scatterlist *sg, unsigned int nsg, u8 *out); ++void crypto_hmac_final(struct crypto_tfm *tfm, __u8 *key, ++ unsigned int *keylen, __u8 *out); ++void crypto_hmac(struct crypto_tfm *tfm, __u8 *key, unsigned int *keylen, ++ struct scatterlist *sg, unsigned int nsg, __u8 *out); + #endif /* CONFIG_CRYPTO_HMAC */ + + #endif /* _LINUX_CRYPTO_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/cycx_drv.h linux-libc-headers-2.6.8.0/include/linux/cycx_drv.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/cycx_drv.h 2003-12-15 12:46:57.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/cycx_drv.h 2004-08-26 05:41:49.000000000 -0500 +@@ -14,9 +14,9 @@ + * ============================================================================ + * 1999/10/23 acme cycxhw_t cleanup + * 1999/01/03 acme more judicious use of data types... +-* uclong, ucchar, etc deleted, the u8, u16, u32 ++* uclong, ucchar, etc deleted, the __u8, __u16, __u32 + * types are the portable way to go. +-* 1999/01/03 acme judicious use of data types... u16, u32, etc ++* 1999/01/03 acme judicious use of data types... __u16, __u32, etc + * 1998/12/26 acme FIXED_BUFFERS, CONF_OFFSET, + * removal of cy_read{bwl} + * 1998/08/08 acme Initial version. +@@ -46,18 +46,18 @@ + * @reserved - reserved for future use + */ + struct cycx_hw { +- u32 fwid; ++ __u32 fwid; + int irq; + void *dpmbase; +- u32 dpmsize; +- u32 reserved[5]; ++ __u32 dpmsize; ++ __u32 reserved[5]; + }; + + /* Function Prototypes */ +-extern int cycx_setup(struct cycx_hw *hw, void *sfm, u32 len); ++extern int cycx_setup(struct cycx_hw *hw, void *sfm, __u32 len); + extern int cycx_down(struct cycx_hw *hw); +-extern int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len); +-extern int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len); ++extern int cycx_peek(struct cycx_hw *hw, __u32 addr, void *buf, __u32 len); ++extern int cycx_poke(struct cycx_hw *hw, __u32 addr, void *buf, __u32 len); + extern int cycx_exec(void *addr); + + extern void cycx_inten(struct cycx_hw *hw); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/cycx_x25.h linux-libc-headers-2.6.8.0/include/linux/cycx_x25.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/cycx_x25.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/cycx_x25.h 2004-08-26 05:41:49.000000000 -0500 +@@ -38,10 +38,10 @@ + /* Data Structures */ + /* X.25 Command Block. */ + struct cycx_x25_cmd { +- u16 command PACKED; +- u16 link PACKED; /* values: 0 or 1 */ +- u16 len PACKED; /* values: 0 thru 0x205 (517) */ +- u32 buf PACKED; ++ __u16 command PACKED; ++ __u16 link PACKED; /* values: 0 or 1 */ ++ __u16 len PACKED; /* values: 0 thru 0x205 (517) */ ++ __u32 buf PACKED; + }; + + /* Defines for the 'command' field. */ +@@ -92,34 +92,34 @@ + * @flags - see dosx25.doc, in portuguese, for details + */ + struct cycx_x25_config { +- u8 link PACKED; +- u8 speed PACKED; +- u8 clock PACKED; +- u8 n2 PACKED; +- u8 n2win PACKED; +- u8 n3win PACKED; +- u8 nvc PACKED; +- u8 pktlen PACKED; +- u8 locaddr PACKED; +- u8 remaddr PACKED; +- u16 t1 PACKED; +- u16 t2 PACKED; +- u8 t21 PACKED; +- u8 npvc PACKED; +- u8 t23 PACKED; +- u8 flags PACKED; ++ __u8 link PACKED; ++ __u8 speed PACKED; ++ __u8 clock PACKED; ++ __u8 n2 PACKED; ++ __u8 n2win PACKED; ++ __u8 n3win PACKED; ++ __u8 nvc PACKED; ++ __u8 pktlen PACKED; ++ __u8 locaddr PACKED; ++ __u8 remaddr PACKED; ++ __u16 t1 PACKED; ++ __u16 t2 PACKED; ++ __u8 t21 PACKED; ++ __u8 npvc PACKED; ++ __u8 t23 PACKED; ++ __u8 flags PACKED; + }; + + struct cycx_x25_stats { +- u16 rx_crc_errors PACKED; +- u16 rx_over_errors PACKED; +- u16 n2_tx_frames PACKED; +- u16 n2_rx_frames PACKED; +- u16 tx_timeouts PACKED; +- u16 rx_timeouts PACKED; +- u16 n3_tx_packets PACKED; +- u16 n3_rx_packets PACKED; +- u16 tx_aborts PACKED; +- u16 rx_aborts PACKED; ++ __u16 rx_crc_errors PACKED; ++ __u16 rx_over_errors PACKED; ++ __u16 n2_tx_frames PACKED; ++ __u16 n2_rx_frames PACKED; ++ __u16 tx_timeouts PACKED; ++ __u16 rx_timeouts PACKED; ++ __u16 n3_tx_packets PACKED; ++ __u16 n3_rx_packets PACKED; ++ __u16 tx_aborts PACKED; ++ __u16 rx_aborts PACKED; + }; + #endif /* _CYCX_X25_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/device.h linux-libc-headers-2.6.8.0/include/linux/device.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/device.h 2004-08-18 13:16:02.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/device.h 2004-08-26 05:41:49.000000000 -0500 +@@ -57,7 +57,7 @@ + struct device * (*add) (struct device * parent, char * bus_id); + int (*hotplug) (struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); +- int (*suspend)(struct device * dev, u32 state); ++ int (*suspend)(struct device * dev, __u32 state); + int (*resume)(struct device * dev); + }; + +@@ -105,8 +105,8 @@ + int (*probe) (struct device * dev); + int (*remove) (struct device * dev); + void (*shutdown) (struct device * dev); +- int (*suspend) (struct device * dev, u32 state, u32 level); +- int (*resume) (struct device * dev, u32 level); ++ int (*suspend) (struct device * dev, __u32 state, __u32 level); ++ int (*resume) (struct device * dev, __u32 level); + }; + + +@@ -262,17 +262,17 @@ + void *platform_data; /* Platform specific data (e.g. ACPI, + BIOS data relevant to device) */ + struct dev_pm_info power; +- u32 power_state; /* Current operating state. In ++ __u32 power_state; /* Current operating state. In + ACPI-speak, this is D0-D3, D0 + being fully functional, and D3 + being off. */ + + unsigned char *saved_state; /* saved device state */ +- u32 detach_state; /* State to enter when device is ++ __u32 detach_state; /* State to enter when device is + detached from its driver. */ + +- u64 *dma_mask; /* dma mask (if dma'able device) */ +- u64 coherent_dma_mask;/* Like dma_mask, but for ++ __u64 *dma_mask; /* dma mask (if dma'able device) */ ++ __u64 coherent_dma_mask;/* Like dma_mask, but for + alloc_coherent mappings as + not all hardware supports + 64 bit addresses for consistent +@@ -360,9 +360,9 @@ + + struct platform_device { + char * name; +- u32 id; ++ __u32 id; + struct device dev; +- u32 num_resources; ++ __u32 num_resources; + struct resource * resource; + }; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/divert.h linux-libc-headers-2.6.8.0/include/linux/divert.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/divert.h 2004-06-09 07:00:49.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/divert.h 2004-08-26 05:41:49.000000000 -0500 +@@ -27,10 +27,10 @@ + { + int divert; /* are we active */ + unsigned int protos; /* protocols */ +- u16 tcp_dst[MAX_DIVERT_PORTS]; /* specific tcp dst ports to divert */ +- u16 tcp_src[MAX_DIVERT_PORTS]; /* specific tcp src ports to divert */ +- u16 udp_dst[MAX_DIVERT_PORTS]; /* specific udp dst ports to divert */ +- u16 udp_src[MAX_DIVERT_PORTS]; /* specific udp src ports to divert */ ++ __u16 tcp_dst[MAX_DIVERT_PORTS]; /* specific tcp dst ports to divert */ ++ __u16 tcp_src[MAX_DIVERT_PORTS]; /* specific tcp src ports to divert */ ++ __u16 udp_dst[MAX_DIVERT_PORTS]; /* specific udp dst ports to divert */ ++ __u16 udp_src[MAX_DIVERT_PORTS]; /* specific udp src ports to divert */ + }; + + /* +@@ -40,12 +40,12 @@ + + typedef union _divert_cf_arg + { +- s16 int16; +- u16 uint16; +- s32 int32; +- u32 uint32; +- s64 int64; +- u64 uint64; ++ __s16 int16; ++ __u16 uint16; ++ __s32 int32; ++ __u32 uint32; ++ __s64 int64; ++ __u64 uint64; + void *ptr; + } divert_cf_arg; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/eeprom.h linux-libc-headers-2.6.8.0/include/linux/eeprom.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/eeprom.h 2003-12-19 07:05:15.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/eeprom.h 2004-08-26 13:26:38.000000000 -0500 +@@ -26,15 +26,15 @@ + unsigned ee_state; + + spinlock_t *lock; +- u32 *cache; ++ __u32 *cache; + }; + + +-u8 eeprom_readb(struct eeprom *ee, unsigned address); +-void eeprom_read(struct eeprom *ee, unsigned address, u8 *bytes, ++__u8 eeprom_readb(struct eeprom *ee, unsigned address); ++void eeprom_read(struct eeprom *ee, unsigned address, __u8 *bytes, + unsigned count); +-void eeprom_writeb(struct eeprom *ee, unsigned address, u8 data); +-void eeprom_write(struct eeprom *ee, unsigned address, u8 *bytes, ++void eeprom_writeb(struct eeprom *ee, unsigned address, __u8 data); ++void eeprom_write(struct eeprom *ee, unsigned address, __u8 *bytes, + unsigned count); + + /* The EEPROM commands include the alway-set leading bit. */ +@@ -56,10 +56,10 @@ + } + + /* foo. put this in a .c file */ +-static inline void eeprom_update(struct eeprom *ee, u32 mask, int pol) ++static inline void eeprom_update(struct eeprom *ee, __u32 mask, int pol) + { + unsigned long flags; +- u32 data; ++ __u32 data; + + spin_lock_irqsave(ee->lock, flags); + data = *ee->cache; +@@ -106,17 +106,17 @@ + eeprom_update(ee, ee->eedi, pol); + } + +-u16 eeprom_readw(struct eeprom *ee, unsigned address) ++__u16 eeprom_readw(struct eeprom *ee, unsigned address) + { + unsigned i; +- u16 res = 0; ++ __u16 res = 0; + + eeprom_clk_lo(ee); + eeprom_update(ee, ee->eesel, 1 ^ !!(ee->polarity & EEPOL_EESEL)); + eeprom_send_addr(ee, address); + + for (i=0; i<16; i++) { +- u32 data; ++ __u32 data; + eeprom_clk_hi(ee); + res <<= 1; + data = readl(ee->addr); +@@ -130,6 +130,6 @@ + } + + +-void eeprom_writeb(struct eeprom *ee, unsigned address, u8 data) ++void eeprom_writeb(struct eeprom *ee, unsigned address, __u8 data) + { + } +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/efi.h linux-libc-headers-2.6.8.0/include/linux/efi.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/efi.h 2004-08-18 13:16:02.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/efi.h 2004-08-26 05:42:08.000000000 -0500 +@@ -30,12 +30,12 @@ + #define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1))) + + typedef unsigned long efi_status_t; +-typedef u8 efi_bool_t; +-typedef u16 efi_char16_t; /* UNICODE character */ ++typedef __u8 efi_bool_t; ++typedef __u16 efi_char16_t; /* UNICODE character */ + + + typedef struct { +- u8 b[16]; ++ __u8 b[16]; + } efi_guid_t; + + #define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ +@@ -49,11 +49,11 @@ + * Generic EFI table header + */ + typedef struct { +- u64 signature; +- u32 revision; +- u32 headersize; +- u32 crc32; +- u32 reserved; ++ __u64 signature; ++ __u32 revision; ++ __u32 headersize; ++ __u32 crc32; ++ __u32 reserved; + } efi_table_hdr_t; + + /* +@@ -78,14 +78,14 @@ + #define EFI_MAX_MEMORY_TYPE 14 + + /* Attribute values: */ +-#define EFI_MEMORY_UC ((u64)0x0000000000000001ULL) /* uncached */ +-#define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ +-#define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ +-#define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ +-#define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ +-#define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ +-#define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ +-#define EFI_MEMORY_RUNTIME ((u64)0x8000000000000000ULL) /* range requires runtime mapping */ ++#define EFI_MEMORY_UC ((__u64)0x0000000000000001ULL) /* uncached */ ++#define EFI_MEMORY_WC ((__u64)0x0000000000000002ULL) /* write-coalescing */ ++#define EFI_MEMORY_WT ((__u64)0x0000000000000004ULL) /* write-through */ ++#define EFI_MEMORY_WB ((__u64)0x0000000000000008ULL) /* write-back */ ++#define EFI_MEMORY_WP ((__u64)0x0000000000001000ULL) /* write-protect */ ++#define EFI_MEMORY_RP ((__u64)0x0000000000002000ULL) /* read-protect */ ++#define EFI_MEMORY_XP ((__u64)0x0000000000004000ULL) /* execute-protect */ ++#define EFI_MEMORY_RUNTIME ((__u64)0x8000000000000000ULL) /* range requires runtime mapping */ + #define EFI_MEMORY_DESCRIPTOR_VERSION 1 + + #define EFI_PAGE_SHIFT 12 +@@ -96,14 +96,14 @@ + * the case in ia64. Need to have this fixed in the f/w. + */ + typedef struct { +- u32 type; +- u32 pad; +- u64 phys_addr; +- u64 virt_addr; +- u64 num_pages; +- u64 attribute; ++ __u32 type; ++ __u32 pad; ++ __u64 phys_addr; ++ __u64 virt_addr; ++ __u64 num_pages; ++ __u64 attribute; + #if defined (__i386__) +- u64 pad1; ++ __u64 pad1; + #endif + } efi_memory_desc_t; + +@@ -117,23 +117,23 @@ + #define EFI_UNSPECIFIED_TIMEZONE 0x07ff + + typedef struct { +- u16 year; +- u8 month; +- u8 day; +- u8 hour; +- u8 minute; +- u8 second; +- u8 pad1; +- u32 nanosecond; +- s16 timezone; +- u8 daylight; +- u8 pad2; ++ __u16 year; ++ __u8 month; ++ __u8 day; ++ __u8 hour; ++ __u8 minute; ++ __u8 second; ++ __u8 pad1; ++ __u32 nanosecond; ++ __s16 timezone; ++ __u8 daylight; ++ __u8 pad2; + } efi_time_t; + + typedef struct { +- u32 resolution; +- u32 accuracy; +- u8 sets_to_zero; ++ __u32 resolution; ++ __u32 accuracy; ++ __u8 sets_to_zero; + } efi_time_cap_t; + + /* +@@ -146,7 +146,7 @@ + /* + * EFI Runtime Services table + */ +-#define EFI_RUNTIME_SERVICES_SIGNATURE ((u64)0x5652453544e5552ULL) ++#define EFI_RUNTIME_SERVICES_SIGNATURE ((__u64)0x5652453544e5552ULL) + #define EFI_RUNTIME_SERVICES_REVISION 0x00010000 + + typedef struct { +@@ -169,19 +169,19 @@ + typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, + efi_time_t *tm); + typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm); +-typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, ++typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, __u32 *attr, + unsigned long *data_size, void *data); + typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name, + efi_guid_t *vendor); + typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, + unsigned long attr, unsigned long data_size, + void *data); +-typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); ++typedef efi_status_t efi_get_next_high_mono_count_t (__u32 *count); + typedef void efi_reset_system_t (int reset_type, efi_status_t status, + unsigned long data_size, efi_char16_t *data); + typedef efi_status_t efi_set_virtual_address_map_t (unsigned long memory_map_size, + unsigned long descriptor_size, +- u32 descriptor_version, ++ __u32 descriptor_version, + efi_memory_desc_t *virtual_map); + + /* +@@ -219,13 +219,13 @@ + unsigned long table; + } efi_config_table_t; + +-#define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL) ++#define EFI_SYSTEM_TABLE_SIGNATURE ((__u64)0x5453595320494249ULL) + #define EFI_SYSTEM_TABLE_REVISION ((1 << 16) | 00) + + typedef struct { + efi_table_hdr_t hdr; + unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */ +- u32 fw_revision; ++ __u32 fw_revision; + unsigned long con_in_handle; + unsigned long con_in; + unsigned long con_out_handle; +@@ -293,9 +293,9 @@ + extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); + extern void efi_gettimeofday (struct timespec *ts); + extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ +-extern u64 efi_get_iobase (void); +-extern u32 efi_mem_type (unsigned long phys_addr); +-extern u64 efi_mem_attributes (unsigned long phys_addr); ++extern __u64 efi_get_iobase (void); ++extern __u32 efi_mem_type (unsigned long phys_addr); ++extern __u64 efi_mem_attributes (unsigned long phys_addr); + extern int __init efi_uart_console_only (void); + extern void efi_initialize_iomem_resources(struct resource *code_resource, + struct resource *data_resource); +@@ -368,9 +368,9 @@ + #define EFI_DEV_END_ENTIRE 0xFF + + struct efi_generic_dev_path { +- u8 type; +- u8 sub_type; +- u16 length; ++ __u8 type; ++ __u8 sub_type; ++ __u16 length; + } __attribute ((packed)); + + #endif /* _LINUX_EFI_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/eisa.h linux-libc-headers-2.6.8.0/include/linux/eisa.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/eisa.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/eisa.h 2004-08-26 05:42:08.000000000 -0500 +@@ -43,7 +43,7 @@ + int state; + unsigned long base_addr; + struct resource res[EISA_MAX_RESOURCES]; +- u64 dma_mask; ++ __u64 dma_mask; + struct device dev; /* generic device */ + #ifdef CONFIG_EISA_NAMES + char pretty_name[DEVICE_NAME_SIZE]; +@@ -91,7 +91,7 @@ + unsigned long bus_base_addr; + int slots; /* Max slot number */ + int force_probe; /* Probe even when no slot 0 */ +- u64 dma_mask; /* from bridge device */ ++ __u64 dma_mask; /* from bridge device */ + int bus_nr; /* Set by eisa_root_register */ + struct resource eisa_root_res; /* ditto */ + }; +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/ethtool.h linux-libc-headers-2.6.8.0/include/linux/ethtool.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/ethtool.h 2004-06-23 16:52:54.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/ethtool.h 2004-08-26 13:29:11.000000000 -0500 +@@ -15,24 +15,24 @@ + + /* This should work for both 32 and 64 bit userland. */ + struct ethtool_cmd { +- u32 cmd; +- u32 supported; /* Features this interface supports */ +- u32 advertising; /* Features this interface advertises */ +- u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ +- u8 duplex; /* Duplex, half or full */ +- u8 port; /* Which connector port */ +- u8 phy_address; +- u8 transceiver; /* Which transceiver to use */ +- u8 autoneg; /* Enable or disable autonegotiation */ +- u32 maxtxpkt; /* Tx pkts before generating tx int */ +- u32 maxrxpkt; /* Rx pkts before generating rx int */ +- u32 reserved[4]; ++ __u32 cmd; ++ __u32 supported; /* Features this interface supports */ ++ __u32 advertising; /* Features this interface advertises */ ++ __u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ ++ __u8 duplex; /* Duplex, half or full */ ++ __u8 port; /* Which connector port */ ++ __u8 phy_address; ++ __u8 transceiver; /* Which transceiver to use */ ++ __u8 autoneg; /* Enable or disable autonegotiation */ ++ __u32 maxtxpkt; /* Tx pkts before generating tx int */ ++ __u32 maxrxpkt; /* Rx pkts before generating rx int */ ++ __u32 reserved[4]; + }; + + #define ETHTOOL_BUSINFO_LEN 32 + /* these strings are set to whatever the driver author decides... */ + struct ethtool_drvinfo { +- u32 cmd; ++ __u32 cmd; + char driver[32]; /* driver short name, "tulip", "eepro100" */ + char version[32]; /* driver version string */ + char fw_version[32]; /* firmware version string, if applicable */ +@@ -40,53 +40,53 @@ + /* For PCI devices, use pci_name(pci_dev). */ + char reserved1[32]; + char reserved2[16]; +- u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */ +- u32 testinfo_len; +- u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ +- u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ ++ __u32 n_stats; /* number of __u64's from ETHTOOL_GSTATS */ ++ __u32 testinfo_len; ++ __u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ ++ __u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ + }; + + #define SOPASS_MAX 6 + /* wake-on-lan settings */ + struct ethtool_wolinfo { +- u32 cmd; +- u32 supported; +- u32 wolopts; +- u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */ ++ __u32 cmd; ++ __u32 supported; ++ __u32 wolopts; ++ __u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */ + }; + + /* for passing single values */ + struct ethtool_value { +- u32 cmd; +- u32 data; ++ __u32 cmd; ++ __u32 data; + }; + + /* for passing big chunks of data */ + struct ethtool_regs { +- u32 cmd; +- u32 version; /* driver-specific, indicates different chips/revs */ +- u32 len; /* bytes */ +- u8 data[0]; ++ __u32 cmd; ++ __u32 version; /* driver-specific, indicates different chips/revs */ ++ __u32 len; /* bytes */ ++ __u8 data[0]; + }; + + /* for passing EEPROM chunks */ + struct ethtool_eeprom { +- u32 cmd; +- u32 magic; +- u32 offset; /* in bytes */ +- u32 len; /* in bytes */ +- u8 data[0]; ++ __u32 cmd; ++ __u32 magic; ++ __u32 offset; /* in bytes */ ++ __u32 len; /* in bytes */ ++ __u8 data[0]; + }; + + /* for configuring coalescing parameters of chip */ + struct ethtool_coalesce { +- u32 cmd; /* ETHTOOL_{G,S}COALESCE */ ++ __u32 cmd; /* ETHTOOL_{G,S}COALESCE */ + + /* How many usecs to delay an RX interrupt after + * a packet arrives. If 0, only rx_max_coalesced_frames + * is used. + */ +- u32 rx_coalesce_usecs; ++ __u32 rx_coalesce_usecs; + + /* How many packets to delay an RX interrupt after + * a packet arrives. If 0, only rx_coalesce_usecs is +@@ -94,21 +94,21 @@ + * to zero as this would cause RX interrupts to never be + * generated. + */ +- u32 rx_max_coalesced_frames; ++ __u32 rx_max_coalesced_frames; + + /* Same as above two parameters, except that these values + * apply while an IRQ is being serviced by the host. Not + * all cards support this feature and the values are ignored + * in that case. + */ +- u32 rx_coalesce_usecs_irq; +- u32 rx_max_coalesced_frames_irq; ++ __u32 rx_coalesce_usecs_irq; ++ __u32 rx_max_coalesced_frames_irq; + + /* How many usecs to delay a TX interrupt after + * a packet is sent. If 0, only tx_max_coalesced_frames + * is used. + */ +- u32 tx_coalesce_usecs; ++ __u32 tx_coalesce_usecs; + + /* How many packets to delay a TX interrupt after + * a packet is sent. If 0, only tx_coalesce_usecs is +@@ -116,22 +116,22 @@ + * to zero as this would cause TX interrupts to never be + * generated. + */ +- u32 tx_max_coalesced_frames; ++ __u32 tx_max_coalesced_frames; + + /* Same as above two parameters, except that these values + * apply while an IRQ is being serviced by the host. Not + * all cards support this feature and the values are ignored + * in that case. + */ +- u32 tx_coalesce_usecs_irq; +- u32 tx_max_coalesced_frames_irq; ++ __u32 tx_coalesce_usecs_irq; ++ __u32 tx_max_coalesced_frames_irq; + + /* How many usecs to delay in-memory statistics + * block updates. Some drivers do not have an in-memory + * statistic block, and in such cases this value is ignored. + * This value must not be zero. + */ +- u32 stats_block_coalesce_usecs; ++ __u32 stats_block_coalesce_usecs; + + /* Adaptive RX/TX coalescing is an algorithm implemented by + * some drivers to improve latency under low packet rates and +@@ -140,18 +140,18 @@ + * not implemented by the driver causes these values to be + * silently ignored. + */ +- u32 use_adaptive_rx_coalesce; +- u32 use_adaptive_tx_coalesce; ++ __u32 use_adaptive_rx_coalesce; ++ __u32 use_adaptive_tx_coalesce; + + /* When the packet rate (measured in packets per second) + * is below pkt_rate_low, the {rx,tx}_*_low parameters are + * used. + */ +- u32 pkt_rate_low; +- u32 rx_coalesce_usecs_low; +- u32 rx_max_coalesced_frames_low; +- u32 tx_coalesce_usecs_low; +- u32 tx_max_coalesced_frames_low; ++ __u32 pkt_rate_low; ++ __u32 rx_coalesce_usecs_low; ++ __u32 rx_max_coalesced_frames_low; ++ __u32 tx_coalesce_usecs_low; ++ __u32 tx_max_coalesced_frames_low; + + /* When the packet rate is below pkt_rate_high but above + * pkt_rate_low (both measured in packets per second) the +@@ -162,43 +162,43 @@ + * is above pkt_rate_high, the {rx,tx}_*_high parameters are + * used. + */ +- u32 pkt_rate_high; +- u32 rx_coalesce_usecs_high; +- u32 rx_max_coalesced_frames_high; +- u32 tx_coalesce_usecs_high; +- u32 tx_max_coalesced_frames_high; ++ __u32 pkt_rate_high; ++ __u32 rx_coalesce_usecs_high; ++ __u32 rx_max_coalesced_frames_high; ++ __u32 tx_coalesce_usecs_high; ++ __u32 tx_max_coalesced_frames_high; + + /* How often to do adaptive coalescing packet rate sampling, + * measured in seconds. Must not be zero. + */ +- u32 rate_sample_interval; ++ __u32 rate_sample_interval; + }; + + /* for configuring RX/TX ring parameters */ + struct ethtool_ringparam { +- u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */ ++ __u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */ + + /* Read only attributes. These indicate the maximum number + * of pending RX/TX ring entries the driver will allow the + * user to set. + */ +- u32 rx_max_pending; +- u32 rx_mini_max_pending; +- u32 rx_jumbo_max_pending; +- u32 tx_max_pending; ++ __u32 rx_max_pending; ++ __u32 rx_mini_max_pending; ++ __u32 rx_jumbo_max_pending; ++ __u32 tx_max_pending; + + /* Values changeable by the user. The valid values are + * in the range 1 to the "*_max_pending" counterpart above. + */ +- u32 rx_pending; +- u32 rx_mini_pending; +- u32 rx_jumbo_pending; +- u32 tx_pending; ++ __u32 rx_pending; ++ __u32 rx_mini_pending; ++ __u32 rx_jumbo_pending; ++ __u32 tx_pending; + }; + + /* for configuring link flow control parameters */ + struct ethtool_pauseparam { +- u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */ ++ __u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */ + + /* If the link is being auto-negotiated (via ethtool_cmd.autoneg + * being true) the user may set 'autonet' here non-zero to have the +@@ -210,9 +210,9 @@ + * then {rx,tx}_pause force the driver to use/not-use pause + * flow control. + */ +- u32 autoneg; +- u32 rx_pause; +- u32 tx_pause; ++ __u32 autoneg; ++ __u32 rx_pause; ++ __u32 tx_pause; + }; + + #define ETH_GSTRING_LEN 32 +@@ -223,10 +223,10 @@ + + /* for passing string sets for data tagging */ + struct ethtool_gstrings { +- u32 cmd; /* ETHTOOL_GSTRINGS */ +- u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/ +- u32 len; /* number of strings in the string set */ +- u8 data[0]; ++ __u32 cmd; /* ETHTOOL_GSTRINGS */ ++ __u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/ ++ __u32 len; /* number of strings in the string set */ ++ __u8 data[0]; + }; + + enum ethtool_test_flags { +@@ -236,30 +236,30 @@ + + /* for requesting NIC test and getting results*/ + struct ethtool_test { +- u32 cmd; /* ETHTOOL_TEST */ +- u32 flags; /* ETH_TEST_FL_xxx */ +- u32 reserved; +- u32 len; /* result length, in number of u64 elements */ +- u64 data[0]; ++ __u32 cmd; /* ETHTOOL_TEST */ ++ __u32 flags; /* ETH_TEST_FL_xxx */ ++ __u32 reserved; ++ __u32 len; /* result length, in number of __u64 elements */ ++ __u64 data[0]; + }; + + /* for dumping NIC-specific statistics */ + struct ethtool_stats { +- u32 cmd; /* ETHTOOL_GSTATS */ +- u32 n_stats; /* number of u64's being returned */ +- u64 data[0]; ++ __u32 cmd; /* ETHTOOL_GSTATS */ ++ __u32 n_stats; /* number of __u64's being returned */ ++ __u64 data[0]; + }; + + struct net_device; + + /* Some generic methods drivers may use in their ethtool_ops */ +-u32 ethtool_op_get_link(struct net_device *dev); +-u32 ethtool_op_get_tx_csum(struct net_device *dev); +-int ethtool_op_set_tx_csum(struct net_device *dev, u32 data); +-u32 ethtool_op_get_sg(struct net_device *dev); +-int ethtool_op_set_sg(struct net_device *dev, u32 data); +-u32 ethtool_op_get_tso(struct net_device *dev); +-int ethtool_op_set_tso(struct net_device *dev, u32 data); ++__u32 ethtool_op_get_link(struct net_device *dev); ++__u32 ethtool_op_get_tx_csum(struct net_device *dev); ++int ethtool_op_set_tx_csum(struct net_device *dev, __u32 data); ++__u32 ethtool_op_get_sg(struct net_device *dev); ++int ethtool_op_set_sg(struct net_device *dev, __u32 data); ++__u32 ethtool_op_get_tso(struct net_device *dev); ++int ethtool_op_set_tso(struct net_device *dev, __u32 data); + + /** + * ðtool_ops - Alter and report network device settings +@@ -324,33 +324,33 @@ + void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); + void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); + int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); +- u32 (*get_msglevel)(struct net_device *); +- void (*set_msglevel)(struct net_device *, u32); ++ __u32 (*get_msglevel)(struct net_device *); ++ void (*set_msglevel)(struct net_device *, __u32); + int (*nway_reset)(struct net_device *); +- u32 (*get_link)(struct net_device *); ++ __u32 (*get_link)(struct net_device *); + int (*get_eeprom_len)(struct net_device *); +- int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); +- int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); ++ int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, __u8 *); ++ int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, __u8 *); + int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); + int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *); + void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *); + int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *); + void (*get_pauseparam)(struct net_device *, struct ethtool_pauseparam*); + int (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*); +- u32 (*get_rx_csum)(struct net_device *); +- int (*set_rx_csum)(struct net_device *, u32); +- u32 (*get_tx_csum)(struct net_device *); +- int (*set_tx_csum)(struct net_device *, u32); +- u32 (*get_sg)(struct net_device *); +- int (*set_sg)(struct net_device *, u32); +- u32 (*get_tso)(struct net_device *); +- int (*set_tso)(struct net_device *, u32); ++ __u32 (*get_rx_csum)(struct net_device *); ++ int (*set_rx_csum)(struct net_device *, __u32); ++ __u32 (*get_tx_csum)(struct net_device *); ++ int (*set_tx_csum)(struct net_device *, __u32); ++ __u32 (*get_sg)(struct net_device *); ++ int (*set_sg)(struct net_device *, __u32); ++ __u32 (*get_tso)(struct net_device *); ++ int (*set_tso)(struct net_device *, __u32); + int (*self_test_count)(struct net_device *); +- void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); +- void (*get_strings)(struct net_device *, u32 stringset, u8 *); +- int (*phys_id)(struct net_device *, u32); ++ void (*self_test)(struct net_device *, struct ethtool_test *, __u64 *); ++ void (*get_strings)(struct net_device *, __u32 stringset, __u8 *); ++ int (*phys_id)(struct net_device *, __u32); + int (*get_stats_count)(struct net_device *); +- void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); ++ void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, __u64 *); + int (*begin)(struct net_device *); + void (*complete)(struct net_device *); + }; +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/firmware.h linux-libc-headers-2.6.8.0/include/linux/firmware.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/firmware.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/firmware.h 2004-08-26 05:42:08.000000000 -0500 +@@ -5,7 +5,7 @@ + #define FIRMWARE_NAME_MAX 30 + struct firmware { + size_t size; +- u8 *data; ++ __u8 *data; + }; + int request_firmware(const struct firmware **fw, const char *name, + struct device *device); +@@ -15,5 +15,5 @@ + void (*cont)(const struct firmware *fw, void *context)); + + void release_firmware(const struct firmware *fw); +-void register_firmware(const char *name, const u8 *data, size_t size); ++void register_firmware(const char *name, const __u8 *data, size_t size); + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/fs.h linux-libc-headers-2.6.8.0/include/linux/fs.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/fs.h 2004-08-18 13:16:02.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/fs.h 2004-08-26 05:42:08.000000000 -0500 +@@ -198,7 +198,7 @@ + /* A jump here: 108-111 have been used for various private purposes. */ + #define BLKBSZGET _IOR(0x12,112,size_t) + #define BLKBSZSET _IOW(0x12,113,size_t) +-#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ ++#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (__u64 *arg) */ + + #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ + #define FIBMAP _IO(0x00,1) /* bmap access */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/i2c.h linux-libc-headers-2.6.8.0/include/linux/i2c.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/i2c.h 2004-06-23 16:52:54.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/i2c.h 2004-08-26 05:42:08.000000000 -0500 +@@ -70,36 +70,36 @@ + and probably just as fast. + Note that we use i2c_adapter here, because you do not need a specific + smbus adapter to call this function. */ +-extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr, ++extern __s32 i2c_smbus_xfer (struct i2c_adapter * adapter, __u16 addr, + unsigned short flags, +- char read_write, u8 command, int size, ++ char read_write, __u8 command, int size, + union i2c_smbus_data * data); + + /* Now follow the 'nice' access routines. These also document the calling + conventions of smbus_access. */ + +-extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value); +-extern s32 i2c_smbus_read_byte(struct i2c_client * client); +-extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value); +-extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command); +-extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, +- u8 command, u8 value); +-extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command); +-extern s32 i2c_smbus_write_word_data(struct i2c_client * client, +- u8 command, u16 value); +-extern s32 i2c_smbus_process_call(struct i2c_client * client, +- u8 command, u16 value); ++extern __s32 i2c_smbus_write_quick(struct i2c_client * client, __u8 value); ++extern __s32 i2c_smbus_read_byte(struct i2c_client * client); ++extern __s32 i2c_smbus_write_byte(struct i2c_client * client, __u8 value); ++extern __s32 i2c_smbus_read_byte_data(struct i2c_client * client, __u8 command); ++extern __s32 i2c_smbus_write_byte_data(struct i2c_client * client, ++ __u8 command, __u8 value); ++extern __s32 i2c_smbus_read_word_data(struct i2c_client * client, __u8 command); ++extern __s32 i2c_smbus_write_word_data(struct i2c_client * client, ++ __u8 command, __u16 value); ++extern __s32 i2c_smbus_process_call(struct i2c_client * client, ++ __u8 command, __u16 value); + /* Returns the number of read bytes */ +-extern s32 i2c_smbus_read_block_data(struct i2c_client * client, +- u8 command, u8 *values); +-extern s32 i2c_smbus_write_block_data(struct i2c_client * client, +- u8 command, u8 length, +- u8 *values); +-extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, +- u8 command, u8 *values); +-extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, +- u8 command, u8 length, +- u8 *values); ++extern __s32 i2c_smbus_read_block_data(struct i2c_client * client, ++ __u8 command, __u8 *values); ++extern __s32 i2c_smbus_write_block_data(struct i2c_client * client, ++ __u8 command, __u8 length, ++ __u8 *values); ++extern __s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, ++ __u8 command, __u8 *values); ++extern __s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, ++ __u8 command, __u8 length, ++ __u8 *values); + + + /* +@@ -203,9 +203,9 @@ + using common I2C messages */ + int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], + int num); +- int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, ++ int (*smbus_xfer) (struct i2c_adapter *adap, __u16 addr, + unsigned short flags, char read_write, +- u8 command, int size, union i2c_smbus_data * data); ++ __u8 command, int size, union i2c_smbus_data * data); + + /* --- these optional/future use for some adapter types.*/ + int (*slave_send)(struct i2c_adapter *,char*,int); +@@ -215,7 +215,7 @@ + int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long); + + /* To determine what the adapter supports */ +- u32 (*functionality) (struct i2c_adapter *); ++ __u32 (*functionality) (struct i2c_adapter *); + }; + + /* +@@ -381,10 +381,10 @@ + + + /* Return the functionality mask */ +-extern u32 i2c_get_functionality (struct i2c_adapter *adap); ++extern __u32 i2c_get_functionality (struct i2c_adapter *adap); + + /* Return 1 if adapter supports everything we need, 0 if not. */ +-extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func); ++extern int i2c_check_functionality (struct i2c_adapter *adap, __u32 func); + + /* + * I2C Message - used for pure i2c transaction, also from /dev interface +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/i2o-dev.h linux-libc-headers-2.6.8.0/include/linux/i2o-dev.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/i2o-dev.h 2004-06-23 16:52:54.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/i2o-dev.h 2004-08-26 05:42:08.000000000 -0500 +@@ -29,7 +29,7 @@ + * I2O Control IOCTLs and structures + */ + #define I2O_MAGIC_NUMBER 'i' +-#define I2OGETIOPS _IOR(I2O_MAGIC_NUMBER,0,u8[MAX_I2O_CONTROLLERS]) ++#define I2OGETIOPS _IOR(I2O_MAGIC_NUMBER,0,__u8[MAX_I2O_CONTROLLERS]) + #define I2OHRTGET _IOWR(I2O_MAGIC_NUMBER,1,struct i2o_cmd_hrtlct) + #define I2OLCTGET _IOWR(I2O_MAGIC_NUMBER,2,struct i2o_cmd_hrtlct) + #define I2OPARMSET _IOWR(I2O_MAGIC_NUMBER,3,struct i2o_cmd_psetget) +@@ -37,7 +37,7 @@ + #define I2OSWDL _IOWR(I2O_MAGIC_NUMBER,5,struct i2o_sw_xfer) + #define I2OSWUL _IOWR(I2O_MAGIC_NUMBER,6,struct i2o_sw_xfer) + #define I2OSWDEL _IOWR(I2O_MAGIC_NUMBER,7,struct i2o_sw_xfer) +-#define I2OVALIDATE _IOR(I2O_MAGIC_NUMBER,8,u32) ++#define I2OVALIDATE _IOR(I2O_MAGIC_NUMBER,8,__u32) + #define I2OHTML _IOWR(I2O_MAGIC_NUMBER,9,struct i2o_html) + #define I2OEVTREG _IOW(I2O_MAGIC_NUMBER,10,struct i2o_evt_id) + #define I2OEVTGET _IOR(I2O_MAGIC_NUMBER,11,struct i2o_evt_info) +@@ -129,65 +129,65 @@ + #define I2O_BUS_CARDBUS 7 + #define I2O_BUS_UNKNOWN 0x80 + +-typedef unsigned char u8; +-typedef unsigned short u16; +-typedef unsigned int u32; ++typedef unsigned char __u8; ++typedef unsigned short __u16; ++typedef unsigned int __u32; + + typedef struct _i2o_pci_bus + { +- u8 PciFunctionNumber; +- u8 PciDeviceNumber; +- u8 PciBusNumber; +- u8 reserved; +- u16 PciVendorID; +- u16 PciDeviceID; ++ __u8 PciFunctionNumber; ++ __u8 PciDeviceNumber; ++ __u8 PciBusNumber; ++ __u8 reserved; ++ __u16 PciVendorID; ++ __u16 PciDeviceID; + } i2o_pci_bus; + + typedef struct _i2o_local_bus + { +- u16 LbBaseIOPort; +- u16 reserved; +- u32 LbBaseMemoryAddress; ++ __u16 LbBaseIOPort; ++ __u16 reserved; ++ __u32 LbBaseMemoryAddress; + } i2o_local_bus; + + typedef struct _i2o_isa_bus + { +- u16 IsaBaseIOPort; +- u8 CSN; +- u8 reserved; +- u32 IsaBaseMemoryAddress; ++ __u16 IsaBaseIOPort; ++ __u8 CSN; ++ __u8 reserved; ++ __u32 IsaBaseMemoryAddress; + } i2o_isa_bus; + + typedef struct _i2o_eisa_bus_info + { +- u16 EisaBaseIOPort; +- u8 reserved; +- u8 EisaSlotNumber; +- u32 EisaBaseMemoryAddress; ++ __u16 EisaBaseIOPort; ++ __u8 reserved; ++ __u8 EisaSlotNumber; ++ __u32 EisaBaseMemoryAddress; + } i2o_eisa_bus; + + typedef struct _i2o_mca_bus + { +- u16 McaBaseIOPort; +- u8 reserved; +- u8 McaSlotNumber; +- u32 McaBaseMemoryAddress; ++ __u16 McaBaseIOPort; ++ __u8 reserved; ++ __u8 McaSlotNumber; ++ __u32 McaBaseMemoryAddress; + } i2o_mca_bus; + + typedef struct _i2o_other_bus + { +- u16 BaseIOPort; +- u16 reserved; +- u32 BaseMemoryAddress; ++ __u16 BaseIOPort; ++ __u16 reserved; ++ __u32 BaseMemoryAddress; + } i2o_other_bus; + + typedef struct _i2o_hrt_entry + { +- u32 adapter_id; +- u32 parent_tid:12; +- u32 state:4; +- u32 bus_num:8; +- u32 bus_type:8; ++ __u32 adapter_id; ++ __u32 parent_tid:12; ++ __u32 state:4; ++ __u32 bus_num:8; ++ __u32 bus_type:8; + union + { + i2o_pci_bus pci_bus; +@@ -201,69 +201,69 @@ + + typedef struct _i2o_hrt + { +- u16 num_entries; +- u8 entry_len; +- u8 hrt_version; +- u32 change_ind; ++ __u16 num_entries; ++ __u8 entry_len; ++ __u8 hrt_version; ++ __u32 change_ind; + i2o_hrt_entry hrt_entry[1]; + } i2o_hrt; + + typedef struct _i2o_lct_entry + { +- u32 entry_size:16; +- u32 tid:12; +- u32 reserved:4; +- u32 change_ind; +- u32 device_flags; +- u32 class_id:12; +- u32 version:4; +- u32 vendor_id:16; +- u32 sub_class; +- u32 user_tid:12; +- u32 parent_tid:12; +- u32 bios_info:8; +- u8 identity_tag[8]; +- u32 event_capabilities; ++ __u32 entry_size:16; ++ __u32 tid:12; ++ __u32 reserved:4; ++ __u32 change_ind; ++ __u32 device_flags; ++ __u32 class_id:12; ++ __u32 version:4; ++ __u32 vendor_id:16; ++ __u32 sub_class; ++ __u32 user_tid:12; ++ __u32 parent_tid:12; ++ __u32 bios_info:8; ++ __u8 identity_tag[8]; ++ __u32 event_capabilities; + } i2o_lct_entry; + + typedef struct _i2o_lct + { +- u32 table_size:16; +- u32 boot_tid:12; +- u32 lct_ver:4; +- u32 iop_flags; +- u32 change_ind; ++ __u32 table_size:16; ++ __u32 boot_tid:12; ++ __u32 lct_ver:4; ++ __u32 iop_flags; ++ __u32 change_ind; + i2o_lct_entry lct_entry[1]; + } i2o_lct; + + typedef struct _i2o_status_block + { +- u16 org_id; +- u16 reserved; +- u16 iop_id:12; +- u16 reserved1:4; +- u16 host_unit_id; +- u16 segment_number:12; +- u16 i2o_version:4; +- u8 iop_state; +- u8 msg_type; +- u16 inbound_frame_size; +- u8 init_code; +- u8 reserved2; +- u32 max_inbound_frames; +- u32 cur_inbound_frames; +- u32 max_outbound_frames; ++ __u16 org_id; ++ __u16 reserved; ++ __u16 iop_id:12; ++ __u16 reserved1:4; ++ __u16 host_unit_id; ++ __u16 segment_number:12; ++ __u16 i2o_version:4; ++ __u8 iop_state; ++ __u8 msg_type; ++ __u16 inbound_frame_size; ++ __u8 init_code; ++ __u8 reserved2; ++ __u32 max_inbound_frames; ++ __u32 cur_inbound_frames; ++ __u32 max_outbound_frames; + char product_id[24]; +- u32 expected_lct_size; +- u32 iop_capabilities; +- u32 desired_mem_size; +- u32 current_mem_size; +- u32 current_mem_base; +- u32 desired_io_size; +- u32 current_io_size; +- u32 current_io_base; +- u32 reserved3:24; +- u32 cmd_status:8; ++ __u32 expected_lct_size; ++ __u32 iop_capabilities; ++ __u32 desired_mem_size; ++ __u32 current_mem_size; ++ __u32 current_mem_base; ++ __u32 desired_io_size; ++ __u32 current_io_size; ++ __u32 current_io_base; ++ __u32 reserved3:24; ++ __u32 cmd_status:8; + } i2o_status_block; + + /* Event indicator mask flags */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/isdn/capilli.h linux-libc-headers-2.6.8.0/include/linux/isdn/capilli.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/isdn/capilli.h 2004-03-28 07:52:12.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/isdn/capilli.h 2004-08-26 13:26:47.000000000 -0500 +@@ -43,20 +43,20 @@ + char *driver_name; /* name of driver */ + int (*load_firmware)(struct capi_ctr *, capiloaddata *); + void (*reset_ctr)(struct capi_ctr *); +- void (*register_appl)(struct capi_ctr *, u16 appl, ++ void (*register_appl)(struct capi_ctr *, __u16 appl, + capi_register_params *); +- void (*release_appl)(struct capi_ctr *, u16 appl); +- u16 (*send_message)(struct capi_ctr *, struct sk_buff *skb); ++ void (*release_appl)(struct capi_ctr *, __u16 appl); ++ __u16 (*send_message)(struct capi_ctr *, struct sk_buff *skb); + + char *(*procinfo)(struct capi_ctr *); + int (*ctr_read_proc)(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *card); + + /* filled in before calling ready callback */ +- u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */ ++ __u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */ + capi_version version; /* CAPI_GET_VERSION */ + capi_profile profile; /* CAPI_GET_PROFILE */ +- u8 serial[CAPI_SERIAL_LEN]; /* CAPI_GET_SERIAL */ ++ __u8 serial[CAPI_SERIAL_LEN]; /* CAPI_GET_SERIAL */ + + /* management information for kcapi */ + +@@ -81,7 +81,7 @@ + void capi_ctr_reseted(struct capi_ctr * card); + void capi_ctr_suspend_output(struct capi_ctr * card); + void capi_ctr_resume_output(struct capi_ctr * card); +-void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb); ++void capi_ctr_handle_message(struct capi_ctr * card, __u16 appl, struct sk_buff *skb); + + // --------------------------------------------------------------------------- + // needed for AVM capi drivers +@@ -102,11 +102,11 @@ + // --------------------------------------------------------------------------- + // library functions for use by hardware controller drivers + +-void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize); +-void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci); +-void capilib_release_appl(struct list_head *head, u16 applid); ++void capilib_new_ncci(struct list_head *head, __u16 applid, __u32 ncci, __u32 winsize); ++void capilib_free_ncci(struct list_head *head, __u16 applid, __u32 ncci); ++void capilib_release_appl(struct list_head *head, __u16 applid); + void capilib_release(struct list_head *head); +-void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgid); +-u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid); ++void capilib_data_b3_conf(struct list_head *head, __u16 applid, __u32 ncci, __u16 msgid); ++__u16 capilib_data_b3_req(struct list_head *head, __u16 applid, __u32 ncci, __u16 msgid); + + #endif /* __CAPILLI_H__ */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/jhash.h linux-libc-headers-2.6.8.0/include/linux/jhash.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/jhash.h 2004-03-28 07:52:09.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/jhash.h 2004-08-26 05:42:08.000000000 -0500 +@@ -41,19 +41,19 @@ + * of bytes. No alignment or length assumptions are made about + * the input key. + */ +-static inline u32 jhash(const void *key, u32 length, u32 initval) ++static inline __u32 jhash(const void *key, __u32 length, __u32 initval) + { +- u32 a, b, c, len; +- const u8 *k = key; ++ __u32 a, b, c, len; ++ const __u8 *k = key; + + len = length; + a = b = JHASH_GOLDEN_RATIO; + c = initval; + + while (len >= 12) { +- a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); +- b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); +- c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); ++ a += (k[0] +((__u32)k[1]<<8) +((__u32)k[2]<<16) +((__u32)k[3]<<24)); ++ b += (k[4] +((__u32)k[5]<<8) +((__u32)k[6]<<16) +((__u32)k[7]<<24)); ++ c += (k[8] +((__u32)k[9]<<8) +((__u32)k[10]<<16)+((__u32)k[11]<<24)); + + __jhash_mix(a,b,c); + +@@ -63,16 +63,16 @@ + + c += length; + switch (len) { +- case 11: c += ((u32)k[10]<<24); +- case 10: c += ((u32)k[9]<<16); +- case 9 : c += ((u32)k[8]<<8); +- case 8 : b += ((u32)k[7]<<24); +- case 7 : b += ((u32)k[6]<<16); +- case 6 : b += ((u32)k[5]<<8); ++ case 11: c += ((__u32)k[10]<<24); ++ case 10: c += ((__u32)k[9]<<16); ++ case 9 : c += ((__u32)k[8]<<8); ++ case 8 : b += ((__u32)k[7]<<24); ++ case 7 : b += ((__u32)k[6]<<16); ++ case 6 : b += ((__u32)k[5]<<8); + case 5 : b += k[4]; +- case 4 : a += ((u32)k[3]<<24); +- case 3 : a += ((u32)k[2]<<16); +- case 2 : a += ((u32)k[1]<<8); ++ case 4 : a += ((__u32)k[3]<<24); ++ case 3 : a += ((__u32)k[2]<<16); ++ case 2 : a += ((__u32)k[1]<<8); + case 1 : a += k[0]; + }; + +@@ -81,12 +81,12 @@ + return c; + } + +-/* A special optimized version that handles 1 or more of u32s. +- * The length parameter here is the number of u32s in the key. ++/* A special optimized version that handles 1 or more of __u32s. ++ * The length parameter here is the number of __u32s in the key. + */ +-static inline u32 jhash2(u32 *k, u32 length, u32 initval) ++static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval) + { +- u32 a, b, c, len; ++ __u32 a, b, c, len; + + a = b = JHASH_GOLDEN_RATIO; + c = initval; +@@ -119,7 +119,7 @@ + * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally + * done at the end is not done here. + */ +-static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) ++static inline __u32 jhash_3words(__u32 a, __u32 b, __u32 c, __u32 initval) + { + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; +@@ -130,12 +130,12 @@ + return c; + } + +-static inline u32 jhash_2words(u32 a, u32 b, u32 initval) ++static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval) + { + return jhash_3words(a, b, 0, initval); + } + +-static inline u32 jhash_1word(u32 a, u32 initval) ++static inline __u32 jhash_1word(__u32 a, __u32 initval) + { + return jhash_3words(a, 0, 0, initval); + } +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/jiffies.h linux-libc-headers-2.6.8.0/include/linux/jiffies.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/jiffies.h 2004-01-17 17:04:30.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/jiffies.h 2004-08-26 13:26:33.000000000 -0500 +@@ -12,15 +12,15 @@ + * without sampling the sequence number in xtime_lock. + * get_jiffies_64() will do this for you as appropriate. + */ +-extern u64 jiffies_64; ++extern __u64 jiffies_64; + extern unsigned long volatile jiffies; + + #if (BITS_PER_LONG < 64) +-u64 get_jiffies_64(void); ++__u64 get_jiffies_64(void); + #else +-static inline u64 get_jiffies_64(void) ++static inline __u64 get_jiffies_64(void) + { +- return (u64)jiffies; ++ return (__u64)jiffies; + } + #endif + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/kernel_stat.h linux-libc-headers-2.6.8.0/include/linux/kernel_stat.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/kernel_stat.h 2004-04-19 16:13:51.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/kernel_stat.h 2004-08-26 05:42:08.000000000 -0500 +@@ -12,13 +12,13 @@ + */ + + struct cpu_usage_stat { +- u64 user; +- u64 nice; +- u64 system; +- u64 softirq; +- u64 irq; +- u64 idle; +- u64 iowait; ++ __u64 user; ++ __u64 nice; ++ __u64 system; ++ __u64 softirq; ++ __u64 irq; ++ __u64 idle; ++ __u64 iowait; + }; + + struct kernel_stat { +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/libata.h linux-libc-headers-2.6.8.0/include/linux/libata.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/libata.h 2004-08-18 13:16:03.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/libata.h 2004-08-26 05:42:08.000000000 -0500 +@@ -160,7 +160,7 @@ + struct ata_queued_cmd; + + /* typedefs */ +-typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc, u8 drv_stat); ++typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc, __u8 drv_stat); + + struct ata_ioports { + unsigned long cmd_addr; +@@ -246,18 +246,18 @@ + }; + + struct ata_device { +- u64 n_sectors; /* size of device, if ATA */ ++ __u64 n_sectors; /* size of device, if ATA */ + unsigned long flags; /* ATA_DFLAG_xxx */ + unsigned int class; /* ATA_DEV_xxx */ + unsigned int devno; /* 0 or 1 */ +- u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ ++ __u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + unsigned int pio_mode; + unsigned int udma_mode; + + /* cache info about current transfer mode */ +- u8 xfer_protocol; /* taskfile xfer protocol */ +- u8 read_cmd; /* opcode to use on read */ +- u8 write_cmd; /* opcode to use on write */ ++ __u8 xfer_protocol; /* taskfile xfer protocol */ ++ __u8 read_cmd; /* opcode to use on read */ ++ __u8 write_cmd; /* opcode to use on write */ + }; + + struct ata_port { +@@ -272,8 +272,8 @@ + + struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ + +- u8 ctl; /* cache of ATA control register */ +- u8 last_ctl; /* Cache last written value */ ++ __u8 ctl; /* cache of ATA control register */ ++ __u8 last_ctl; /* Cache last written value */ + unsigned int bus_state; + unsigned int port_state; + unsigned int pio_mask; +@@ -312,7 +312,7 @@ + void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); + + void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); +- u8 (*check_status)(struct ata_port *ap); ++ __u8 (*check_status)(struct ata_port *ap); + + void (*phy_reset) (struct ata_port *ap); + void (*post_set_mode) (struct ata_port *ap); +@@ -328,9 +328,9 @@ + irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); + void (*irq_clear) (struct ata_port *); + +- u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); ++ __u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); + void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, +- u32 val); ++ __u32 val); + + int (*port_start) (struct ata_port *ap); + void (*port_stop) (struct ata_port *ap); +@@ -374,10 +374,10 @@ + extern void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); + extern void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf); + extern void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf); +-extern void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp); +-extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf); +-extern u8 ata_check_status_pio(struct ata_port *ap); +-extern u8 ata_check_status_mmio(struct ata_port *ap); ++extern void ata_tf_to_fis(struct ata_taskfile *tf, __u8 *fis, __u8 pmp); ++extern void ata_tf_from_fis(__u8 *fis, struct ata_taskfile *tf); ++extern __u8 ata_check_status_pio(struct ata_port *ap); ++extern __u8 ata_check_status_mmio(struct ata_port *ap); + extern void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf); + extern void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); + extern int ata_port_start (struct ata_port *ap); +@@ -397,7 +397,7 @@ + extern void ata_bmdma_start_pio (struct ata_queued_cmd *qc); + extern void ata_bmdma_irq_clear(struct ata_port *ap); + extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); +-extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat); ++extern void ata_qc_complete(struct ata_queued_cmd *qc, __u8 drv_stat); + extern void ata_eng_timeout(struct ata_port *ap); + extern int ata_std_bios_param(struct scsi_device *sdev, + struct block_device *bdev, +@@ -416,7 +416,7 @@ + (dev->class == ATA_DEV_ATAPI)); + } + +-static inline u8 ata_chk_err(struct ata_port *ap) ++static inline __u8 ata_chk_err(struct ata_port *ap) + { + if (ap->flags & ATA_FLAG_MMIO) { + return readb((void *) ap->ioaddr.error_addr); +@@ -424,12 +424,12 @@ + return inb(ap->ioaddr.error_addr); + } + +-static inline u8 ata_chk_status(struct ata_port *ap) ++static inline __u8 ata_chk_status(struct ata_port *ap) + { + return ap->ops->check_status(ap); + } + +-static inline u8 ata_altstatus(struct ata_port *ap) ++static inline __u8 ata_altstatus(struct ata_port *ap) + { + if (ap->flags & ATA_FLAG_MMIO) + return readb(ap->ioaddr.altstatus_addr); +@@ -442,10 +442,10 @@ + ndelay(400); + } + +-static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, ++static inline __u8 ata_busy_wait(struct ata_port *ap, unsigned int bits, + unsigned int max) + { +- u8 status; ++ __u8 status; + + do { + udelay(10); +@@ -456,9 +456,9 @@ + return status; + } + +-static inline u8 ata_wait_idle(struct ata_port *ap) ++static inline __u8 ata_wait_idle(struct ata_port *ap) + { +- u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); ++ __u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + + if (status & (ATA_BUSY | ATA_DRQ)) { + unsigned long l = ap->ioaddr.status_addr; +@@ -495,10 +495,10 @@ + tf->device = ATA_DEVICE_OBS | ATA_DEV1; + } + +-static inline u8 ata_irq_on(struct ata_port *ap) ++static inline __u8 ata_irq_on(struct ata_port *ap) + { + struct ata_ioports *ioaddr = &ap->ioaddr; +- u8 tmp; ++ __u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; +@@ -514,10 +514,10 @@ + return tmp; + } + +-static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) ++static inline __u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) + { + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; +- u8 host_stat, post_stat, status; ++ __u8 host_stat, post_stat, status; + + status = ata_busy_wait(ap, bits, 1000); + if (status & bits) +@@ -545,12 +545,12 @@ + return status; + } + +-static inline u32 scr_read(struct ata_port *ap, unsigned int reg) ++static inline __u32 scr_read(struct ata_port *ap, unsigned int reg) + { + return ap->ops->scr_read(ap, reg); + } + +-static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val) ++static inline void scr_write(struct ata_port *ap, unsigned int reg, __u32 val) + { + ap->ops->scr_write(ap, reg, val); + } +@@ -589,9 +589,9 @@ + } + } + +-static inline u8 ata_bmdma_status(struct ata_port *ap) ++static inline __u8 ata_bmdma_status(struct ata_port *ap) + { +- u8 host_stat; ++ __u8 host_stat; + if (ap->flags & ATA_FLAG_MMIO) { + void *mmio = (void *) ap->ioaddr.bmdma_addr; + host_stat = readb(mmio + ATA_DMA_STATUS); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/lockd/bind.h linux-libc-headers-2.6.8.0/include/linux/lockd/bind.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/lockd/bind.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/lockd/bind.h 2004-08-26 05:42:08.000000000 -0500 +@@ -18,7 +18,7 @@ + * This is the set of functions for lockd->nfsd communication + */ + struct nlmsvc_binding { +- u32 (*fopen)(struct svc_rqst *, ++ __u32 (*fopen)(struct svc_rqst *, + struct nfs_fh *, + struct file *); + void (*fclose)(struct file *); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/lockd/nlm.h linux-libc-headers-2.6.8.0/include/linux/lockd/nlm.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/lockd/nlm.h 2004-01-17 17:04:34.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/lockd/nlm.h 2004-08-26 05:42:08.000000000 -0500 +@@ -11,8 +11,8 @@ + + + /* Maximum file offset in file_lock.fl_end */ +-# define NLM_OFFSET_MAX ((s32) 0x7fffffff) +-# define NLM4_OFFSET_MAX ((s64) ((~(u64)0) >> 1)) ++# define NLM_OFFSET_MAX ((__s32) 0x7fffffff) ++# define NLM4_OFFSET_MAX ((__s64) ((~(__u64)0) >> 1)) + + /* Return states for NLM */ + enum { +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/lockd/share.h linux-libc-headers-2.6.8.0/include/linux/lockd/share.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/lockd/share.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/lockd/share.h 2004-08-26 13:26:43.000000000 -0500 +@@ -17,13 +17,13 @@ + struct nlm_host * s_host; /* client host */ + struct nlm_file * s_file; /* shared file */ + struct xdr_netobj s_owner; /* owner handle */ +- u32 s_access; /* access mode */ +- u32 s_mode; /* deny mode */ ++ __u32 s_access; /* access mode */ ++ __u32 s_mode; /* deny mode */ + }; + +-u32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *, ++__u32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *, + struct nlm_args *); +-u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *, ++__u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *, + struct nlm_args *); + int nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, int); + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/lockd/sm_inter.h linux-libc-headers-2.6.8.0/include/linux/lockd/sm_inter.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/lockd/sm_inter.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/lockd/sm_inter.h 2004-08-26 05:42:08.000000000 -0500 +@@ -24,23 +24,23 @@ + * Arguments for all calls to statd + */ + struct nsm_args { +- u32 addr; /* remote address */ +- u32 prog; /* RPC callback info */ +- u32 vers; +- u32 proc; +- u32 proto; /* protocol (udp/tcp) plus server/client flag */ ++ __u32 addr; /* remote address */ ++ __u32 prog; /* RPC callback info */ ++ __u32 vers; ++ __u32 proc; ++ __u32 proto; /* protocol (udp/tcp) plus server/client flag */ + }; + + /* + * Result returned by statd + */ + struct nsm_res { +- u32 status; +- u32 state; ++ __u32 status; ++ __u32 state; + }; + + int nsm_monitor(struct nlm_host *); + int nsm_unmonitor(struct nlm_host *); +-extern u32 nsm_local_state; ++extern __u32 nsm_local_state; + + #endif /* LINUX_LOCKD_SM_INTER_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/lockd/xdr.h linux-libc-headers-2.6.8.0/include/linux/lockd/xdr.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/lockd/xdr.h 2004-01-05 12:42:33.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/lockd/xdr.h 2004-08-26 05:42:08.000000000 -0500 +@@ -48,12 +48,12 @@ + struct nlm_args { + struct nlm_cookie cookie; + struct nlm_lock lock; +- u32 block; +- u32 reclaim; +- u32 state; +- u32 monitor; +- u32 fsm_access; +- u32 fsm_mode; ++ __u32 block; ++ __u32 reclaim; ++ __u32 state; ++ __u32 monitor; ++ __u32 fsm_access; ++ __u32 fsm_mode; + }; + + typedef struct nlm_args nlm_args; +@@ -63,7 +63,7 @@ + */ + struct nlm_res { + struct nlm_cookie cookie; +- u32 status; ++ __u32 status; + struct nlm_lock lock; + }; + +@@ -73,10 +73,10 @@ + struct nlm_reboot { + char * mon; + int len; +- u32 state; +- u32 addr; +- u32 vers; +- u32 proto; ++ __u32 state; ++ __u32 addr; ++ __u32 vers; ++ __u32 proto; + }; + + /* +@@ -84,24 +84,24 @@ + */ + #define NLMSVC_XDRSIZE sizeof(struct nlm_args) + +-int nlmsvc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlmsvc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *); +-int nlmsvc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlmsvc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlmsvc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlmsvc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *); +-int nlmsvc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *); +-int nlmsvc_encode_void(struct svc_rqst *, u32 *, void *); +-int nlmsvc_decode_void(struct svc_rqst *, u32 *, void *); +-int nlmsvc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlmsvc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *); +-int nlmsvc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlmsvc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *); ++int nlmsvc_decode_testargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlmsvc_encode_testres(struct svc_rqst *, __u32 *, struct nlm_res *); ++int nlmsvc_decode_lockargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlmsvc_decode_cancargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlmsvc_decode_unlockargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlmsvc_encode_res(struct svc_rqst *, __u32 *, struct nlm_res *); ++int nlmsvc_decode_res(struct svc_rqst *, __u32 *, struct nlm_res *); ++int nlmsvc_encode_void(struct svc_rqst *, __u32 *, void *); ++int nlmsvc_decode_void(struct svc_rqst *, __u32 *, void *); ++int nlmsvc_decode_shareargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlmsvc_encode_shareres(struct svc_rqst *, __u32 *, struct nlm_res *); ++int nlmsvc_decode_notify(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlmsvc_decode_reboot(struct svc_rqst *, __u32 *, struct nlm_reboot *); + /* +-int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); ++int nlmclt_encode_testargs(struct rpc_rqst *, __u32 *, struct nlm_args *); ++int nlmclt_encode_lockargs(struct rpc_rqst *, __u32 *, struct nlm_args *); ++int nlmclt_encode_cancargs(struct rpc_rqst *, __u32 *, struct nlm_args *); ++int nlmclt_encode_unlockargs(struct rpc_rqst *, __u32 *, struct nlm_args *); + */ + + #endif /* LOCKD_XDR_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/lockd/xdr4.h linux-libc-headers-2.6.8.0/include/linux/lockd/xdr4.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/lockd/xdr4.h 2004-01-05 12:42:33.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/lockd/xdr4.h 2004-08-26 05:42:08.000000000 -0500 +@@ -22,24 +22,24 @@ + + + +-int nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *); +-int nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *); +-int nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *); +-int nlm4svc_encode_void(struct svc_rqst *, u32 *, void *); +-int nlm4svc_decode_void(struct svc_rqst *, u32 *, void *); +-int nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *); +-int nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *); +-int nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *); ++int nlm4svc_decode_testargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlm4svc_encode_testres(struct svc_rqst *, __u32 *, struct nlm_res *); ++int nlm4svc_decode_lockargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlm4svc_decode_cancargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlm4svc_decode_unlockargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlm4svc_encode_res(struct svc_rqst *, __u32 *, struct nlm_res *); ++int nlm4svc_decode_res(struct svc_rqst *, __u32 *, struct nlm_res *); ++int nlm4svc_encode_void(struct svc_rqst *, __u32 *, void *); ++int nlm4svc_decode_void(struct svc_rqst *, __u32 *, void *); ++int nlm4svc_decode_shareargs(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlm4svc_encode_shareres(struct svc_rqst *, __u32 *, struct nlm_res *); ++int nlm4svc_decode_notify(struct svc_rqst *, __u32 *, struct nlm_args *); ++int nlm4svc_decode_reboot(struct svc_rqst *, __u32 *, struct nlm_reboot *); + /* +-int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); ++int nlmclt_encode_testargs(struct rpc_rqst *, __u32 *, struct nlm_args *); ++int nlmclt_encode_lockargs(struct rpc_rqst *, __u32 *, struct nlm_args *); ++int nlmclt_encode_cancargs(struct rpc_rqst *, __u32 *, struct nlm_args *); ++int nlmclt_encode_unlockargs(struct rpc_rqst *, __u32 *, struct nlm_args *); + */ + + #endif /* LOCKD_XDR4_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/mca.h linux-libc-headers-2.6.8.0/include/linux/mca.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/mca.h 2004-08-18 13:16:03.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/mca.h 2004-08-26 05:42:08.000000000 -0500 +@@ -50,7 +50,7 @@ + }; + + struct mca_device { +- u64 dma_mask; ++ __u64 dma_mask; + int pos_id; + int slot; + +@@ -91,7 +91,7 @@ + }; + + struct mca_bus { +- u64 default_dma_mask; ++ __u64 default_dma_mask; + int number; + struct mca_bus_accessor_functions f; + struct device dev; +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/mii.h linux-libc-headers-2.6.8.0/include/linux/mii.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/mii.h 2004-06-23 16:52:55.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/mii.h 2004-08-26 05:42:08.000000000 -0500 +@@ -138,10 +138,10 @@ + + /* This structure is used in all SIOCxMIIxxx ioctl calls */ + struct mii_ioctl_data { +- u16 phy_id; +- u16 reg_num; +- u16 val_in; +- u16 val_out; ++ __u16 phy_id; ++ __u16 reg_num; ++ __u16 val_in; ++ __u16 val_out; + }; + + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/mtd/map.h linux-libc-headers-2.6.8.0/include/linux/mtd/map.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/mtd/map.h 2004-08-18 13:16:06.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/mtd/map.h 2004-08-26 05:42:08.000000000 -0500 +@@ -36,20 +36,20 @@ + int buswidth; /* in octets */ + + #ifdef CONFIG_MTD_COMPLEX_MAPPINGS +- u8 (*read8)(struct map_info *, unsigned long); +- u16 (*read16)(struct map_info *, unsigned long); +- u32 (*read32)(struct map_info *, unsigned long); +- u64 (*read64)(struct map_info *, unsigned long); ++ __u8 (*read8)(struct map_info *, unsigned long); ++ __u16 (*read16)(struct map_info *, unsigned long); ++ __u32 (*read32)(struct map_info *, unsigned long); ++ __u64 (*read64)(struct map_info *, unsigned long); + /* If it returned a 'long' I'd call it readl. + * It doesn't. + * I won't. + * dwmw2 */ + + void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); +- void (*write8)(struct map_info *, u8, unsigned long); +- void (*write16)(struct map_info *, u16, unsigned long); +- void (*write32)(struct map_info *, u32, unsigned long); +- void (*write64)(struct map_info *, u64, unsigned long); ++ void (*write8)(struct map_info *, __u8, unsigned long); ++ void (*write16)(struct map_info *, __u16, unsigned long); ++ void (*write32)(struct map_info *, __u32, unsigned long); ++ void (*write64)(struct map_info *, __u64, unsigned long); + void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); + + /* We can perhaps put in 'point' and 'unpoint' methods, if we really +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/mtd/nand.h linux-libc-headers-2.6.8.0/include/linux/mtd/nand.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/mtd/nand.h 2004-08-18 13:16:06.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/mtd/nand.h 2004-08-26 05:42:08.000000000 -0500 +@@ -271,8 +271,8 @@ + + u_char (*read_byte)(struct mtd_info *mtd); + void (*write_byte)(struct mtd_info *mtd, u_char byte); +- u16 (*read_word)(struct mtd_info *mtd); +- void (*write_word)(struct mtd_info *mtd, u16 word); ++ __u16 (*read_word)(struct mtd_info *mtd); ++ void (*write_word)(struct mtd_info *mtd, __u16 word); + + void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); + void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/mtd/pmc551.h linux-libc-headers-2.6.8.0/include/linux/mtd/pmc551.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/mtd/pmc551.h 2004-03-28 07:52:13.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/mtd/pmc551.h 2004-08-26 05:42:08.000000000 -0500 +@@ -25,9 +25,9 @@ + struct mypriv { + struct pci_dev *dev; + u_char *start; +- u32 base_map0; +- u32 curr_map0; +- u32 asize; ++ __u32 base_map0; ++ __u32 curr_map0; ++ __u32 asize; + struct mtd_info *nextpmc551; + }; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/nbd.h linux-libc-headers-2.6.8.0/include/linux/nbd.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/nbd.h 2004-03-28 07:52:09.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/nbd.h 2004-08-26 05:42:08.000000000 -0500 +@@ -45,11 +45,11 @@ + * server. All data are in network byte order. + */ + struct nbd_request { +- u32 magic; +- u32 type; /* == READ || == WRITE */ ++ __u32 magic; ++ __u32 type; /* == READ || == WRITE */ + char handle[8]; +- u64 from; +- u32 len; ++ __u64 from; ++ __u32 len; + } + #ifdef __GNUC__ + __attribute__ ((packed)) +@@ -61,8 +61,8 @@ + * it has completed an I/O request (or an error occurs). + */ + struct nbd_reply { +- u32 magic; +- u32 error; /* 0 = ok, else error */ ++ __u32 magic; ++ __u32 error; /* 0 = ok, else error */ + char handle[8]; /* handle you got from request */ + }; + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/nfs_fs_i.h linux-libc-headers-2.6.8.0/include/linux/nfs_fs_i.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/nfs_fs_i.h 2004-01-17 17:04:31.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/nfs_fs_i.h 2004-08-26 05:42:08.000000000 -0500 +@@ -8,8 +8,8 @@ + * NFS lock info + */ + struct nfs_lock_info { +- u32 state; +- u32 flags; ++ __u32 state; ++ __u32 flags; + struct nlm_host *host; + }; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/nfs_fs_sb.h linux-libc-headers-2.6.8.0/include/linux/nfs_fs_sb.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/nfs_fs_sb.h 2004-06-09 07:00:50.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/nfs_fs_sb.h 2004-08-26 05:42:08.000000000 -0500 +@@ -37,10 +37,10 @@ + struct list_head nfs4_siblings; /* List of other nfs_server structs + * that share the same clientid + */ +- u32 attr_bitmask[2];/* V4 bitmask representing the set ++ __u32 attr_bitmask[2];/* V4 bitmask representing the set + of attributes supported on this + filesystem */ +- u32 acl_bitmask; /* V4 bitmask representing the ACEs ++ __u32 acl_bitmask; /* V4 bitmask representing the ACEs + that are supported on this + filesystem */ + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/nfs_xdr.h linux-libc-headers-2.6.8.0/include/linux/nfs_xdr.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/nfs_xdr.h 2004-06-09 07:00:50.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/nfs_xdr.h 2004-08-26 05:42:08.000000000 -0500 +@@ -90,9 +90,9 @@ + }; + + struct nfs4_change_info { +- u32 atomic; +- u64 before; +- u64 after; ++ __u32 atomic; ++ __u64 before; ++ __u64 after; + }; + + /* +@@ -112,7 +112,7 @@ + } u; + const struct qstr * name; + const struct nfs_server *server; /* Needed for ID mapping */ +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs_openres { +@@ -168,7 +168,7 @@ + * */ + struct nfs_lowner { + __u64 clientid; +- u32 id; ++ __u32 id; + }; + + struct nfs_open_to_lock { +@@ -328,7 +328,7 @@ + nfs4_stateid stateid; + struct iattr * iap; + const struct nfs_server * server; /* Needed for name mapping */ +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs_setattrres { +@@ -482,32 +482,32 @@ + + #ifdef CONFIG_NFS_V4 + +-typedef u64 clientid4; ++typedef __u64 clientid4; + + struct nfs4_accessargs { + const struct nfs_fh * fh; +- u32 access; ++ __u32 access; + }; + + struct nfs4_accessres { +- u32 supported; +- u32 access; ++ __u32 supported; ++ __u32 access; + }; + + struct nfs4_create_arg { +- u32 ftype; ++ __u32 ftype; + union { + struct qstr * symlink; /* NF4LNK */ + struct { +- u32 specdata1; +- u32 specdata2; ++ __u32 specdata1; ++ __u32 specdata2; + } device; /* NF4BLK, NF4CHR */ + } u; + const struct qstr * name; + const struct nfs_server * server; + const struct iattr * attrs; + const struct nfs_fh * dir_fh; +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs4_create_res { +@@ -519,12 +519,12 @@ + + struct nfs4_fsinfo_arg { + const struct nfs_fh * fh; +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs4_getattr_arg { + const struct nfs_fh * fh; +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs4_getattr_res { +@@ -541,7 +541,7 @@ + struct nfs4_lookup_arg { + const struct nfs_fh * dir_fh; + const struct qstr * name; +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs4_lookup_res { +@@ -551,19 +551,19 @@ + }; + + struct nfs4_lookup_root_arg { +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs4_pathconf_arg { + const struct nfs_fh * fh; +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs4_readdir_arg { + const struct nfs_fh * fh; +- u64 cookie; ++ __u64 cookie; + nfs4_verifier verifier; +- u32 count; ++ __u32 count; + struct page ** pages; /* zero-copy data */ + unsigned int pgbase; /* zero-copy data */ + }; +@@ -575,7 +575,7 @@ + + struct nfs4_readlink { + const struct nfs_fh * fh; +- u32 count; /* zero-copy data */ ++ __u32 count; /* zero-copy data */ + struct page ** pages; /* zero-copy data */ + }; + +@@ -599,23 +599,23 @@ + struct nfs4_setclientid { + nfs4_verifier sc_verifier; /* request */ + char * sc_name; /* request */ +- u32 sc_prog; /* request */ ++ __u32 sc_prog; /* request */ + char sc_netid[4]; /* request */ + char sc_uaddr[24]; /* request */ +- u32 sc_cb_ident; /* request */ ++ __u32 sc_cb_ident; /* request */ + struct nfs4_client * sc_state; /* response */ + }; + + struct nfs4_statfs_arg { + const struct nfs_fh * fh; +- const u32 * bitmask; ++ const __u32 * bitmask; + }; + + struct nfs4_server_caps_res { +- u32 attr_bitmask[2]; +- u32 acl_bitmask; +- u32 has_links; +- u32 has_symlinks; ++ __u32 attr_bitmask[2]; ++ __u32 acl_bitmask; ++ __u32 has_links; ++ __u32 has_symlinks; + }; + + #endif /* CONFIG_NFS_V4 */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/nfsd/state.h linux-libc-headers-2.6.8.0/include/linux/nfsd/state.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/nfsd/state.h 2004-08-18 13:16:07.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/nfsd/state.h 2004-08-26 05:42:08.000000000 -0500 +@@ -41,18 +41,18 @@ + + #define NFS4_OPAQUE_LIMIT 1024 + typedef struct { +- u32 cl_boot; +- u32 cl_id; ++ __u32 cl_boot; ++ __u32 cl_id; + } clientid_t; + + typedef struct { +- u32 so_boot; +- u32 so_stateownerid; +- u32 so_fileid; ++ __u32 so_boot; ++ __u32 so_stateownerid; ++ __u32 so_fileid; + } stateid_opaque_t; + + typedef struct { +- u32 si_generation; ++ __u32 si_generation; + stateid_opaque_t si_opaque; + } stateid_t; + #define si_boot si_opaque.so_boot +@@ -68,14 +68,14 @@ + /* client delegation callback info */ + struct nfs4_callback { + /* SETCLIENTID info */ +- u32 cb_parsed; /* addr parsed */ +- u32 cb_addr; ++ __u32 cb_parsed; /* addr parsed */ ++ __u32 cb_addr; + unsigned short cb_port; +- u32 cb_prog; +- u32 cb_ident; ++ __u32 cb_prog; ++ __u32 cb_ident; + struct xdr_netobj cb_netid; + /* RPC client info */ +- u32 cb_set; /* successful CB_NULL call */ ++ __u32 cb_set; /* successful CB_NULL call */ + struct rpc_program cb_program; + struct rpc_stat cb_stat; + struct rpc_clnt * cb_client; +@@ -99,7 +99,7 @@ + struct xdr_netobj cl_name; /* id generated by client */ + nfs4_verifier cl_verifier; /* generated by client */ + time_t cl_time; /* time of last lease renewal */ +- u32 cl_addr; /* client ipaddress */ ++ __u32 cl_addr; /* client ipaddress */ + struct svc_cred cl_cred; /* setclientid principal */ + clientid_t cl_clientid; /* generated by server */ + nfs4_verifier cl_confirm; /* generated by server */ +@@ -116,7 +116,7 @@ + struct list_head cr_strhash; /* hash by cr_name */ + struct xdr_netobj cr_name; /* id generated by client */ + time_t cr_first_state; /* first state aquisition */ +- u32 cr_expired; /* boolean: lease expired? */ ++ __u32 cr_expired; /* boolean: lease expired? */ + }; + + static inline void +@@ -139,7 +139,7 @@ + * is cached. + */ + struct nfs4_replay { +- u32 rp_status; ++ __u32 rp_status; + unsigned int rp_buflen; + char *rp_buf; + unsigned intrp_allocated; +@@ -175,9 +175,9 @@ + struct list_head so_close_lru; /* tail queue */ + time_t so_time; /* time of placement on so_close_lru */ + int so_is_open_owner; /* 1=openowner,0=lockowner */ +- u32 so_id; ++ __u32 so_id; + struct nfs4_client * so_client; +- u32 so_seqid; ++ __u32 so_seqid; + struct xdr_netobj so_owner; /* open owner name */ + int so_confirmed; /* successful OPEN_CONFIRM? */ + struct nfs4_replay so_replay; +@@ -192,7 +192,7 @@ + struct list_head fi_hash; /* hash by "struct inode *" */ + struct list_head fi_perfile; /* list: nfs4_stateid */ + struct inode *fi_inode; +- u32 fi_id; /* used with stateowner->so_id ++ __u32 fi_id; /* used with stateowner->so_id + * for stateid_hashtbl hash */ + }; + +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/nfsd/xdr.h linux-libc-headers-2.6.8.0/include/linux/nfsd/xdr.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/nfsd/xdr.h 2004-08-18 13:16:07.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/nfsd/xdr.h 2004-08-26 05:42:08.000000000 -0500 +@@ -83,7 +83,7 @@ + struct svc_fh fh; + __u32 cookie; + __u32 count; +- u32 * buffer; ++ __u32 * buffer; + }; + + struct nfsd_attrstat { +@@ -107,9 +107,9 @@ + int count; + + struct readdir_cd common; +- u32 * buffer; ++ __u32 * buffer; + int buflen; +- u32 * offset; ++ __u32 * offset; + }; + + struct nfsd_statfsres { +@@ -134,39 +134,39 @@ + #define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore) + + +-int nfssvc_decode_void(struct svc_rqst *, u32 *, void *); +-int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); +-int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_void(struct svc_rqst *, __u32 *, void *); ++int nfssvc_decode_fhandle(struct svc_rqst *, __u32 *, struct nfsd_fhandle *); ++int nfssvc_decode_sattrargs(struct svc_rqst *, __u32 *, + struct nfsd_sattrargs *); +-int nfssvc_decode_diropargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_diropargs(struct svc_rqst *, __u32 *, + struct nfsd_diropargs *); +-int nfssvc_decode_readargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_readargs(struct svc_rqst *, __u32 *, + struct nfsd_readargs *); +-int nfssvc_decode_writeargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_writeargs(struct svc_rqst *, __u32 *, + struct nfsd_writeargs *); +-int nfssvc_decode_createargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_createargs(struct svc_rqst *, __u32 *, + struct nfsd_createargs *); +-int nfssvc_decode_renameargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_renameargs(struct svc_rqst *, __u32 *, + struct nfsd_renameargs *); +-int nfssvc_decode_readlinkargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_readlinkargs(struct svc_rqst *, __u32 *, + struct nfsd_readlinkargs *); +-int nfssvc_decode_linkargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_linkargs(struct svc_rqst *, __u32 *, + struct nfsd_linkargs *); +-int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_symlinkargs(struct svc_rqst *, __u32 *, + struct nfsd_symlinkargs *); +-int nfssvc_decode_readdirargs(struct svc_rqst *, u32 *, ++int nfssvc_decode_readdirargs(struct svc_rqst *, __u32 *, + struct nfsd_readdirargs *); +-int nfssvc_encode_void(struct svc_rqst *, u32 *, void *); +-int nfssvc_encode_attrstat(struct svc_rqst *, u32 *, struct nfsd_attrstat *); +-int nfssvc_encode_diropres(struct svc_rqst *, u32 *, struct nfsd_diropres *); +-int nfssvc_encode_readlinkres(struct svc_rqst *, u32 *, struct nfsd_readlinkres *); +-int nfssvc_encode_readres(struct svc_rqst *, u32 *, struct nfsd_readres *); +-int nfssvc_encode_statfsres(struct svc_rqst *, u32 *, struct nfsd_statfsres *); +-int nfssvc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd_readdirres *); ++int nfssvc_encode_void(struct svc_rqst *, __u32 *, void *); ++int nfssvc_encode_attrstat(struct svc_rqst *, __u32 *, struct nfsd_attrstat *); ++int nfssvc_encode_diropres(struct svc_rqst *, __u32 *, struct nfsd_diropres *); ++int nfssvc_encode_readlinkres(struct svc_rqst *, __u32 *, struct nfsd_readlinkres *); ++int nfssvc_encode_readres(struct svc_rqst *, __u32 *, struct nfsd_readres *); ++int nfssvc_encode_statfsres(struct svc_rqst *, __u32 *, struct nfsd_statfsres *); ++int nfssvc_encode_readdirres(struct svc_rqst *, __u32 *, struct nfsd_readdirres *); + + int nfssvc_encode_entry(struct readdir_cd *, const char *name, + int namlen, loff_t offset, ino_t ino, unsigned int); + +-int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); ++int nfssvc_release_fhandle(struct svc_rqst *, __u32 *, struct nfsd_fhandle *); + + #endif /* LINUX_NFSD_H */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/nfsd/xdr3.h linux-libc-headers-2.6.8.0/include/linux/nfsd/xdr3.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/nfsd/xdr3.h 2004-08-18 13:16:07.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/nfsd/xdr3.h 2004-08-26 05:42:08.000000000 -0500 +@@ -101,7 +101,7 @@ + __u32 dircount; + __u32 count; + __u32 * verf; +- u32 * buffer; ++ __u32 * buffer; + }; + + struct nfsd3_commitargs { +@@ -167,10 +167,10 @@ + __u32 verf[2]; + + struct readdir_cd common; +- u32 * buffer; ++ __u32 * buffer; + int buflen; +- u32 * offset; +- u32 * offset1; ++ __u32 * offset; ++ __u32 * offset1; + struct svc_rqst * rqstp; + + }; +@@ -245,70 +245,70 @@ + + #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) + +-int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); +-int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_fhandle(struct svc_rqst *, __u32 *, struct nfsd_fhandle *); ++int nfs3svc_decode_sattrargs(struct svc_rqst *, __u32 *, + struct nfsd3_sattrargs *); +-int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_diropargs(struct svc_rqst *, __u32 *, + struct nfsd3_diropargs *); +-int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_accessargs(struct svc_rqst *, __u32 *, + struct nfsd3_accessargs *); +-int nfs3svc_decode_readargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_readargs(struct svc_rqst *, __u32 *, + struct nfsd3_readargs *); +-int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_writeargs(struct svc_rqst *, __u32 *, + struct nfsd3_writeargs *); +-int nfs3svc_decode_createargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_createargs(struct svc_rqst *, __u32 *, + struct nfsd3_createargs *); +-int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_mkdirargs(struct svc_rqst *, __u32 *, + struct nfsd3_createargs *); +-int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_mknodargs(struct svc_rqst *, __u32 *, + struct nfsd3_mknodargs *); +-int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_renameargs(struct svc_rqst *, __u32 *, + struct nfsd3_renameargs *); +-int nfs3svc_decode_readlinkargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_readlinkargs(struct svc_rqst *, __u32 *, + struct nfsd3_readlinkargs *); +-int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_linkargs(struct svc_rqst *, __u32 *, + struct nfsd3_linkargs *); +-int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_symlinkargs(struct svc_rqst *, __u32 *, + struct nfsd3_symlinkargs *); +-int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_readdirargs(struct svc_rqst *, __u32 *, + struct nfsd3_readdirargs *); +-int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __u32 *, + struct nfsd3_readdirargs *); +-int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *, ++int nfs3svc_decode_commitargs(struct svc_rqst *, __u32 *, + struct nfsd3_commitargs *); +-int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *); +-int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *, ++int nfs3svc_encode_voidres(struct svc_rqst *, __u32 *, void *); ++int nfs3svc_encode_attrstat(struct svc_rqst *, __u32 *, + struct nfsd3_attrstat *); +-int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *, ++int nfs3svc_encode_wccstat(struct svc_rqst *, __u32 *, + struct nfsd3_attrstat *); +-int nfs3svc_encode_diropres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_diropres(struct svc_rqst *, __u32 *, + struct nfsd3_diropres *); +-int nfs3svc_encode_accessres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_accessres(struct svc_rqst *, __u32 *, + struct nfsd3_accessres *); +-int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_readlinkres(struct svc_rqst *, __u32 *, + struct nfsd3_readlinkres *); +-int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *); +-int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *); +-int nfs3svc_encode_createres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_readres(struct svc_rqst *, __u32 *, struct nfsd3_readres *); ++int nfs3svc_encode_writeres(struct svc_rqst *, __u32 *, struct nfsd3_writeres *); ++int nfs3svc_encode_createres(struct svc_rqst *, __u32 *, + struct nfsd3_diropres *); +-int nfs3svc_encode_renameres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_renameres(struct svc_rqst *, __u32 *, + struct nfsd3_renameres *); +-int nfs3svc_encode_linkres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_linkres(struct svc_rqst *, __u32 *, + struct nfsd3_linkres *); +-int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_readdirres(struct svc_rqst *, __u32 *, + struct nfsd3_readdirres *); +-int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_fsstatres(struct svc_rqst *, __u32 *, + struct nfsd3_fsstatres *); +-int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *, ++int nfs3svc_encode_fsinfores(struct svc_rqst *, __u32 *, + struct nfsd3_fsinfores *); +-int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_pathconfres(struct svc_rqst *, __u32 *, + struct nfsd3_pathconfres *); +-int nfs3svc_encode_commitres(struct svc_rqst *, u32 *, ++int nfs3svc_encode_commitres(struct svc_rqst *, __u32 *, + struct nfsd3_commitres *); + +-int nfs3svc_release_fhandle(struct svc_rqst *, u32 *, ++int nfs3svc_release_fhandle(struct svc_rqst *, __u32 *, + struct nfsd3_attrstat *); +-int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *, ++int nfs3svc_release_fhandle2(struct svc_rqst *, __u32 *, + struct nfsd3_fhandle_pair *); + int nfs3svc_encode_entry(struct readdir_cd *, const char *name, + int namlen, loff_t offset, ino_t ino, +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/nfsd/xdr4.h linux-libc-headers-2.6.8.0/include/linux/nfsd/xdr4.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/nfsd/xdr4.h 2004-08-18 13:16:07.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/nfsd/xdr4.h 2004-08-26 05:42:08.000000000 -0500 +@@ -42,9 +42,9 @@ + #define NFSD4_MAX_TAGLEN 128 + #define XDR_LEN(n) (((n) + 3) & ~3) + +-typedef u32 delegation_zero_t; +-typedef u32 delegation_boot_t; +-typedef u64 delegation_id_t; ++typedef __u32 delegation_zero_t; ++typedef __u32 delegation_boot_t; ++typedef __u64 delegation_id_t; + + typedef struct { + delegation_zero_t ds_zero; +@@ -53,46 +53,46 @@ + } delegation_stateid_t; + + struct nfsd4_change_info { +- u32 atomic; +- u32 before_ctime_sec; +- u32 before_ctime_nsec; +- u32 after_ctime_sec; +- u32 after_ctime_nsec; ++ __u32 atomic; ++ __u32 before_ctime_sec; ++ __u32 before_ctime_nsec; ++ __u32 after_ctime_sec; ++ __u32 after_ctime_nsec; + }; + + struct nfsd4_access { +- u32 ac_req_access; /* request */ +- u32 ac_supported; /* response */ +- u32 ac_resp_access; /* response */ ++ __u32 ac_req_access; /* request */ ++ __u32 ac_supported; /* response */ ++ __u32 ac_resp_access; /* response */ + }; + + struct nfsd4_close { +- u32 cl_seqid; /* request */ ++ __u32 cl_seqid; /* request */ + stateid_t cl_stateid; /* request+response */ + struct nfs4_stateowner * cl_stateowner; /* response */ + }; + + struct nfsd4_commit { +- u64 co_offset; /* request */ +- u32 co_count; /* request */ ++ __u64 co_offset; /* request */ ++ __u32 co_count; /* request */ + nfs4_verifier co_verf; /* response */ + }; + + struct nfsd4_create { +- u32 cr_namelen; /* request */ ++ __u32 cr_namelen; /* request */ + char * cr_name; /* request */ +- u32 cr_type; /* request */ ++ __u32 cr_type; /* request */ + union { /* request */ + struct { +- u32 namelen; ++ __u32 namelen; + char *name; + } link; /* NF4LNK */ + struct { +- u32 specdata1; +- u32 specdata2; ++ __u32 specdata1; ++ __u32 specdata2; + } dev; /* NF4BLK, NF4CHR */ + } u; +- u32 cr_bmval[2]; /* request */ ++ __u32 cr_bmval[2]; /* request */ + struct iattr cr_iattr; /* request */ + struct nfsd4_change_info cr_cinfo; /* response */ + }; +@@ -102,41 +102,41 @@ + #define cr_specdata2 u.dev.specdata2 + + struct nfsd4_getattr { +- u32 ga_bmval[2]; /* request */ ++ __u32 ga_bmval[2]; /* request */ + struct svc_fh *ga_fhp; /* response */ + }; + + struct nfsd4_link { +- u32 li_namelen; /* request */ ++ __u32 li_namelen; /* request */ + char * li_name; /* request */ + struct nfsd4_change_info li_cinfo; /* response */ + }; + + struct nfsd4_lock_denied { + struct nfs4_stateowner *ld_sop; +- u64 ld_start; +- u64 ld_length; +- u32 ld_type; ++ __u64 ld_start; ++ __u64 ld_length; ++ __u32 ld_type; + }; + + struct nfsd4_lock { + /* request */ +- u32 lk_type; +- u32 lk_reclaim; /* boolean */ +- u64 lk_offset; +- u64 lk_length; +- u32 lk_is_new; ++ __u32 lk_type; ++ __u32 lk_reclaim; /* boolean */ ++ __u64 lk_offset; ++ __u64 lk_length; ++ __u32 lk_is_new; + union { + struct { +- u32 open_seqid; ++ __u32 open_seqid; + stateid_t open_stateid; +- u32 lock_seqid; ++ __u32 lock_seqid; + clientid_t clientid; + struct xdr_netobj owner; + } new; + struct { + stateid_t lock_stateid; +- u32 lock_seqid; ++ __u32 lock_seqid; + } old; + } v; + +@@ -164,56 +164,56 @@ + + + struct nfsd4_lockt { +- u32 lt_type; ++ __u32 lt_type; + clientid_t lt_clientid; + struct xdr_netobj lt_owner; +- u64 lt_offset; +- u64 lt_length; ++ __u64 lt_offset; ++ __u64 lt_length; + struct nfs4_stateowner * lt_stateowner; + struct nfsd4_lock_denied lt_denied; + }; + + + struct nfsd4_locku { +- u32 lu_type; +- u32 lu_seqid; ++ __u32 lu_type; ++ __u32 lu_seqid; + stateid_t lu_stateid; +- u64 lu_offset; +- u64 lu_length; ++ __u64 lu_offset; ++ __u64 lu_length; + struct nfs4_stateowner *lu_stateowner; + }; + + + struct nfsd4_lookup { +- u32 lo_len; /* request */ ++ __u32 lo_len; /* request */ + char * lo_name; /* request */ + }; + + struct nfsd4_putfh { +- u32 pf_fhlen; /* request */ ++ __u32 pf_fhlen; /* request */ + char *pf_fhval; /* request */ + }; + + struct nfsd4_open { +- u32 op_claim_type; /* request */ ++ __u32 op_claim_type; /* request */ + struct xdr_netobj op_fname; /* request - everything but CLAIM_PREV */ +- u32 op_delegate_type; /* request - CLAIM_PREV only */ ++ __u32 op_delegate_type; /* request - CLAIM_PREV only */ + delegation_stateid_t op_delegate_stateid; /* request - CLAIM_DELEGATE_CUR only */ +- u32 op_create; /* request */ +- u32 op_createmode; /* request */ +- u32 op_bmval[2]; /* request */ ++ __u32 op_create; /* request */ ++ __u32 op_createmode; /* request */ ++ __u32 op_bmval[2]; /* request */ + union { /* request */ + struct iattr iattr; /* UNCHECKED4,GUARDED4 */ + nfs4_verifier verf; /* EXCLUSIVE4 */ + } u; + clientid_t op_clientid; /* request */ + struct xdr_netobj op_owner; /* request */ +- u32 op_seqid; /* request */ +- u32 op_share_access; /* request */ +- u32 op_share_deny; /* request */ ++ __u32 op_seqid; /* request */ ++ __u32 op_share_access; /* request */ ++ __u32 op_share_deny; /* request */ + stateid_t op_stateid; /* response */ + struct nfsd4_change_info op_cinfo; /* response */ +- u32 op_rflags; /* response */ ++ __u32 op_rflags; /* response */ + int op_truncate; /* used during processing */ + struct nfs4_stateowner *op_stateowner; /* used during processing */ + +@@ -223,24 +223,24 @@ + + struct nfsd4_open_confirm { + stateid_t oc_req_stateid /* request */; +- u32 oc_seqid /* request */; ++ __u32 oc_seqid /* request */; + stateid_t oc_resp_stateid /* response */; + struct nfs4_stateowner * oc_stateowner; /* response */ + }; + + struct nfsd4_open_downgrade { + stateid_t od_stateid; +- u32 od_seqid; +- u32 od_share_access; +- u32 od_share_deny; ++ __u32 od_seqid; ++ __u32 od_share_access; ++ __u32 od_share_deny; + struct nfs4_stateowner *od_stateowner; + }; + + + struct nfsd4_read { + stateid_t rd_stateid; /* request */ +- u64 rd_offset; /* request */ +- u32 rd_length; /* request */ ++ __u64 rd_offset; /* request */ ++ __u32 rd_length; /* request */ + struct kvec rd_iov[RPCSVC_MAXPAGES]; + int rd_vlen; + +@@ -249,18 +249,18 @@ + }; + + struct nfsd4_readdir { +- u64 rd_cookie; /* request */ ++ __u64 rd_cookie; /* request */ + nfs4_verifier rd_verf; /* request */ +- u32 rd_dircount; /* request */ +- u32 rd_maxcount; /* request */ +- u32 rd_bmval[2]; /* request */ ++ __u32 rd_dircount; /* request */ ++ __u32 rd_maxcount; /* request */ ++ __u32 rd_bmval[2]; /* request */ + struct svc_rqst *rd_rqstp; /* response */ + struct svc_fh * rd_fhp; /* response */ + + struct readdir_cd common; +- u32 * buffer; ++ __u32 * buffer; + int buflen; +- u32 * offset; ++ __u32 * offset; + }; + + struct nfsd4_release_lockowner { +@@ -273,15 +273,15 @@ + }; + + struct nfsd4_remove { +- u32 rm_namelen; /* request */ ++ __u32 rm_namelen; /* request */ + char * rm_name; /* request */ + struct nfsd4_change_info rm_cinfo; /* response */ + }; + + struct nfsd4_rename { +- u32 rn_snamelen; /* request */ ++ __u32 rn_snamelen; /* request */ + char * rn_sname; /* request */ +- u32 rn_tnamelen; /* request */ ++ __u32 rn_tnamelen; /* request */ + char * rn_tname; /* request */ + struct nfsd4_change_info rn_sinfo; /* response */ + struct nfsd4_change_info rn_tinfo; /* response */ +@@ -289,20 +289,20 @@ + + struct nfsd4_setattr { + stateid_t sa_stateid; /* request */ +- u32 sa_bmval[2]; /* request */ ++ __u32 sa_bmval[2]; /* request */ + struct iattr sa_iattr; /* request */ + }; + + struct nfsd4_setclientid { + nfs4_verifier se_verf; /* request */ +- u32 se_namelen; /* request */ ++ __u32 se_namelen; /* request */ + char * se_name; /* request */ +- u32 se_callback_prog; /* request */ +- u32 se_callback_netid_len; /* request */ ++ __u32 se_callback_prog; /* request */ ++ __u32 se_callback_netid_len; /* request */ + char * se_callback_netid_val; /* request */ +- u32 se_callback_addr_len; /* request */ ++ __u32 se_callback_addr_len; /* request */ + char * se_callback_addr_val; /* request */ +- u32 se_callback_ident; /* request */ ++ __u32 se_callback_ident; /* request */ + clientid_t se_clientid; /* response */ + nfs4_verifier se_confirm; /* response */ + }; +@@ -314,21 +314,21 @@ + + /* also used for NVERIFY */ + struct nfsd4_verify { +- u32 ve_bmval[2]; /* request */ +- u32 ve_attrlen; /* request */ ++ __u32 ve_bmval[2]; /* request */ ++ __u32 ve_attrlen; /* request */ + char * ve_attrval; /* request */ + }; + + struct nfsd4_write { + stateid_t wr_stateid; /* request */ +- u64 wr_offset; /* request */ +- u32 wr_stable_how; /* request */ +- u32 wr_buflen; /* request */ ++ __u64 wr_offset; /* request */ ++ __u32 wr_stable_how; /* request */ ++ __u32 wr_buflen; /* request */ + struct kvec wr_vec[RPCSVC_MAXPAGES]; /* request */ + int wr_vlen; + +- u32 wr_bytes_written; /* response */ +- u32 wr_how_written; /* response */ ++ __u32 wr_bytes_written; /* response */ ++ __u32 wr_how_written; /* response */ + nfs4_verifier wr_verifier; /* response */ + }; + +@@ -370,12 +370,12 @@ + + struct nfsd4_compoundargs { + /* scratch variables for XDR decode */ +- u32 * p; +- u32 * end; ++ __u32 * p; ++ __u32 * end; + struct page ** pagelist; + int pagelen; +- u32 tmp[8]; +- u32 * tmpp; ++ __u32 tmp[8]; ++ __u32 * tmpp; + struct tmpbuf { + struct tmpbuf *next; + void (*release)(const void *); +@@ -384,25 +384,25 @@ + + struct svc_rqst *rqstp; + +- u32 taglen; ++ __u32 taglen; + char * tag; +- u32 minorversion; +- u32 opcnt; ++ __u32 minorversion; ++ __u32 opcnt; + struct nfsd4_op *ops; + struct nfsd4_op iops[8]; + }; + + struct nfsd4_compoundres { + /* scratch variables for XDR encode */ +- u32 * p; +- u32 * end; ++ __u32 * p; ++ __u32 * end; + struct xdr_buf * xbuf; + struct svc_rqst * rqstp; + +- u32 taglen; ++ __u32 taglen; + char * tag; +- u32 opcnt; +- u32 * tagp; /* where to encode tag and opcount */ ++ __u32 opcnt; ++ __u32 * tagp; /* where to encode tag and opcount */ + }; + + #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) +@@ -418,16 +418,16 @@ + cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec; + } + +-int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *); +-int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *, ++int nfs4svc_encode_voidres(struct svc_rqst *, __u32 *, void *); ++int nfs4svc_decode_compoundargs(struct svc_rqst *, __u32 *, + struct nfsd4_compoundargs *); +-int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *, ++int nfs4svc_encode_compoundres(struct svc_rqst *, __u32 *, + struct nfsd4_compoundres *); + void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); + void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); + int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, +- struct dentry *dentry, u32 *buffer, int *countp, +- u32 *bmval, struct svc_rqst *); ++ struct dentry *dentry, __u32 *buffer, int *countp, ++ __u32 *bmval, struct svc_rqst *); + extern int nfsd4_setclientid(struct svc_rqst *rqstp, + struct nfsd4_setclientid *setclid); + extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp, +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/pmu.h linux-libc-headers-2.6.8.0/include/linux/pmu.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/pmu.h 2004-01-17 17:04:31.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/pmu.h 2004-08-26 05:42:08.000000000 -0500 +@@ -120,15 +120,15 @@ + + /* no param */ + #define PMU_IOC_SLEEP _IO('B', 0) +-/* out param: u32* backlight value: 0 to 15 */ ++/* out param: __u32* backlight value: 0 to 15 */ + #define PMU_IOC_GET_BACKLIGHT _IOR('B', 1, size_t) +-/* in param: u32 backlight value: 0 to 15 */ ++/* in param: __u32 backlight value: 0 to 15 */ + #define PMU_IOC_SET_BACKLIGHT _IOW('B', 2, size_t) +-/* out param: u32* PMU model */ ++/* out param: __u32* PMU model */ + #define PMU_IOC_GET_MODEL _IOR('B', 3, size_t) +-/* out param: u32* has_adb: 0 or 1 */ ++/* out param: __u32* has_adb: 0 or 1 */ + #define PMU_IOC_HAS_ADB _IOR('B', 4, size_t) +-/* out param: u32* can_sleep: 0 or 1 */ ++/* out param: __u32* can_sleep: 0 or 1 */ + #define PMU_IOC_CAN_SLEEP _IOR('B', 5, size_t) + /* no param, but historically was _IOR('B', 6, 0), meaning 4 bytes */ + #define PMU_IOC_GRAB_BACKLIGHT _IOR('B', 6, size_t) +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/reiserfs_fs.h linux-libc-headers-2.6.8.0/include/linux/reiserfs_fs.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/reiserfs_fs.h 2004-08-18 13:16:04.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/reiserfs_fs.h 2004-08-26 13:26:06.000000000 -0500 +@@ -1821,7 +1821,7 @@ + * to use for a new object underneat it. The locality is returned + * in disk byte order (le). + */ +-u32 reiserfs_choose_packing(struct inode *dir); ++__u32 reiserfs_choose_packing(struct inode *dir); + + int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value); + void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/scx200_gpio.h linux-libc-headers-2.6.8.0/include/linux/scx200_gpio.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/scx200_gpio.h 2004-01-17 17:04:32.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/scx200_gpio.h 2004-08-26 13:26:01.000000000 -0500 +@@ -1,5 +1,5 @@ + +-u32 scx200_gpio_configure(int index, u32 set, u32 clear); ++__u32 scx200_gpio_configure(int index, __u32 set, __u32 clear); + void scx200_gpio_dump(unsigned index); + + extern unsigned scx200_gpio_base; +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/sdladrv.h linux-libc-headers-2.6.8.0/include/linux/sdladrv.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/sdladrv.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/sdladrv.h 2004-08-26 05:42:08.000000000 -0500 +@@ -55,8 +55,8 @@ + extern int sdla_inten (sdlahw_t* hw); + extern int sdla_intde (sdlahw_t* hw); + extern int sdla_intack (sdlahw_t* hw); +-extern void S514_intack (sdlahw_t* hw, u32 int_status); +-extern void read_S514_int_stat (sdlahw_t* hw, u32* int_status); ++extern void S514_intack (sdlahw_t* hw, __u32 int_status); ++extern void read_S514_int_stat (sdlahw_t* hw, __u32* int_status); + extern int sdla_intr (sdlahw_t* hw); + extern int sdla_mapmem (sdlahw_t* hw, unsigned long addr); + extern int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/selection.h linux-libc-headers-2.6.8.0/include/linux/selection.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/selection.h 2004-06-23 16:52:56.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/selection.h 2004-08-26 05:42:08.000000000 -0500 +@@ -32,14 +32,14 @@ + extern int default_blu[]; + + extern unsigned short *screen_pos(int currcons, int w_offset, int viewed); +-extern u16 screen_glyph(int currcons, int offset); ++extern __u16 screen_glyph(int currcons, int offset); + extern void complement_pos(int currcons, int offset); + extern void invert_screen(int currcons, int offset, int count, int shift); + + extern void getconsxy(int currcons, unsigned char *p); + extern void putconsxy(int currcons, unsigned char *p); + +-extern u16 vcs_scr_readw(int currcons, const u16 *org); +-extern void vcs_scr_writew(int currcons, u16 val, u16 *org); ++extern __u16 vcs_scr_readw(int currcons, const __u16 *org); ++extern void vcs_scr_writew(int currcons, __u16 val, __u16 *org); + + #endif +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/serialP.h linux-libc-headers-2.6.8.0/include/linux/serialP.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/serialP.h 2004-08-18 13:16:04.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/serialP.h 2004-08-26 05:42:08.000000000 -0500 +@@ -39,8 +39,8 @@ + int xmit_fifo_size; + int custom_divisor; + int count; +- u8 *iomem_base; +- u16 iomem_reg_shift; ++ __u8 *iomem_base; ++ __u16 iomem_reg_shift; + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + struct async_icount icount; +@@ -75,8 +75,8 @@ + int blocked_open; /* # of blocked opens */ + struct circ_buf xmit; + spinlock_t xmit_lock; +- u8 *iomem_base; +- u16 iomem_reg_shift; ++ __u8 *iomem_base; ++ __u16 iomem_reg_shift; + int io_type; + struct work_struct work; + struct tasklet_struct tlet; +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/clnt.h linux-libc-headers-2.6.8.0/include/linux/sunrpc/clnt.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/clnt.h 2004-02-29 10:36:05.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/sunrpc/clnt.h 2004-08-26 05:42:08.000000000 -0500 +@@ -36,7 +36,7 @@ + atomic_t cl_users; /* number of references */ + struct rpc_xprt * cl_xprt; /* transport */ + struct rpc_procinfo * cl_procinfo; /* procedure info */ +- u32 cl_maxproc; /* max procedure number */ ++ __u32 cl_maxproc; /* max procedure number */ + + char * cl_server; /* server machine name */ + char * cl_protname; /* protocol name */ +@@ -75,7 +75,7 @@ + #define RPC_MAXVERSION 4 + struct rpc_program { + char * name; /* protocol name */ +- u32 number; /* program number */ ++ __u32 number; /* program number */ + unsigned int nrvers; /* number of versions */ + struct rpc_version ** version; /* version array */ + struct rpc_stat * stats; /* statistics */ +@@ -83,7 +83,7 @@ + }; + + struct rpc_version { +- u32 number; /* version number */ ++ __u32 number; /* version number */ + unsigned int nrprocs; /* number of procs */ + struct rpc_procinfo * procs; /* procedure array */ + }; +@@ -92,7 +92,7 @@ + * Procedure information + */ + struct rpc_procinfo { +- u32 p_proc; /* RPC procedure number */ ++ __u32 p_proc; /* RPC procedure number */ + kxdrproc_t p_encode; /* XDR encode function */ + kxdrproc_t p_decode; /* XDR decode function */ + unsigned int p_bufsiz; /* req. buffer size */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/gss_asn1.h linux-libc-headers-2.6.8.0/include/linux/sunrpc/gss_asn1.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/gss_asn1.h 2004-06-23 16:52:58.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/sunrpc/gss_asn1.h 2004-08-26 13:26:25.000000000 -0500 +@@ -64,14 +64,14 @@ + (((o1)->len == (o2)->len) && \ + (memcmp((o1)->data,(o2)->data,(int) (o1)->len) == 0)) + +-u32 g_verify_token_header( ++__u32 g_verify_token_header( + struct xdr_netobj *mech, + int *body_size, + unsigned char **buf_in, + int tok_type, + int toksize); + +-u32 g_get_mech_oid(struct xdr_netobj *mech, struct xdr_netobj * in_buf); ++__u32 g_get_mech_oid(struct xdr_netobj *mech, struct xdr_netobj * in_buf); + + int g_token_size( + struct xdr_netobj *mech, +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/gss_krb5.h linux-libc-headers-2.6.8.0/include/linux/sunrpc/gss_krb5.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/gss_krb5.h 2004-06-23 16:52:58.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/sunrpc/gss_krb5.h 2004-08-26 13:26:21.000000000 -0500 +@@ -46,8 +46,8 @@ + int sealalg; + struct crypto_tfm *enc; + struct crypto_tfm *seq; +- s32 endtime; +- u32 seq_send; ++ __s32 endtime; ++ __u32 seq_send; + struct xdr_netobj mech_used; + }; + +@@ -112,35 +112,35 @@ + #define ENCTYPE_DES3_CBC_SHA1 0x0010 + #define ENCTYPE_UNKNOWN 0x01ff + +-s32 +-make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, ++__s32 ++make_checksum(__s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, + struct xdr_netobj *cksum); + +-u32 ++__u32 + krb5_make_token(struct krb5_ctx *context_handle, int qop_req, + struct xdr_buf *input_message_buffer, + struct xdr_netobj *output_message_buffer, int toktype); + +-u32 ++__u32 + krb5_read_token(struct krb5_ctx *context_handle, + struct xdr_netobj *input_token_buffer, + struct xdr_buf *message_buffer, + int *qop_state, int toktype); + +-u32 ++__u32 + krb5_encrypt(struct crypto_tfm * key, + void *iv, void *in, void *out, int length); + +-u32 ++__u32 + krb5_decrypt(struct crypto_tfm * key, + void *iv, void *in, void *out, int length); + +-s32 ++__s32 + krb5_make_seq_num(struct crypto_tfm * key, + int direction, +- s32 seqnum, unsigned char *cksum, unsigned char *buf); ++ __s32 seqnum, unsigned char *cksum, unsigned char *buf); + +-s32 ++__s32 + krb5_get_seq_num(struct crypto_tfm * key, + unsigned char *cksum, +- unsigned char *buf, int *direction, s32 * seqnum); ++ unsigned char *buf, int *direction, __s32 * seqnum); +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/svc.h linux-libc-headers-2.6.8.0/include/linux/sunrpc/svc.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/svc.h 2004-08-18 13:16:07.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/sunrpc/svc.h 2004-08-26 05:42:08.000000000 -0500 +@@ -75,20 +75,20 @@ + */ + #define RPCSVC_MAXPAGES ((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE + 2) + +-static inline u32 svc_getu32(struct kvec *iov) ++static inline __u32 svc_getu32(struct kvec *iov) + { +- u32 val, *vp; ++ __u32 val, *vp; + vp = iov->iov_base; + val = *vp++; + iov->iov_base = (void*)vp; +- iov->iov_len -= sizeof(u32); ++ iov->iov_len -= sizeof(__u32); + return val; + } +-static inline void svc_putu32(struct kvec *iov, u32 val) ++static inline void svc_putu32(struct kvec *iov, __u32 val) + { +- u32 *vp = iov->iov_base + iov->iov_len; ++ __u32 *vp = iov->iov_base + iov->iov_len; + *vp = val; +- iov->iov_len += sizeof(u32); ++ iov->iov_len += sizeof(__u32); + } + + +@@ -119,11 +119,11 @@ + short rq_arghi; /* pages available in argument page list */ + short rq_resused; /* pages used for result */ + +- u32 rq_xid; /* transmission id */ +- u32 rq_prog; /* program number */ +- u32 rq_vers; /* program version */ +- u32 rq_proc; /* procedure number */ +- u32 rq_prot; /* IP protocol */ ++ __u32 rq_xid; /* transmission id */ ++ __u32 rq_prog; /* program number */ ++ __u32 rq_vers; /* program version */ ++ __u32 rq_proc; /* procedure number */ ++ __u32 rq_prot; /* IP protocol */ + unsigned short + rq_secure : 1; /* secure port */ + +@@ -156,7 +156,7 @@ + * Check buffer bounds after decoding arguments + */ + static inline int +-xdr_argsize_check(struct svc_rqst *rqstp, u32 *p) ++xdr_argsize_check(struct svc_rqst *rqstp, __u32 *p) + { + char *cp = (char *)p; + struct kvec *vec = &rqstp->rq_arg.head[0]; +@@ -164,7 +164,7 @@ + } + + static inline int +-xdr_ressize_check(struct svc_rqst *rqstp, u32 *p) ++xdr_ressize_check(struct svc_rqst *rqstp, __u32 *p) + { + struct kvec *vec = &rqstp->rq_res.head[0]; + char *cp = (char*)p; +@@ -220,19 +220,19 @@ + } + + struct svc_deferred_req { +- u32 prot; /* protocol (UDP or TCP) */ ++ __u32 prot; /* protocol (UDP or TCP) */ + struct sockaddr_in addr; + struct svc_sock *svsk; /* where reply must go */ + struct cache_deferred_req handle; + int argslen; +- u32 args[0]; ++ __u32 args[0]; + }; + + /* + * RPC program + */ + struct svc_program { +- u32 pg_prog; /* program number */ ++ __u32 pg_prog; /* program number */ + unsigned int pg_lovers; /* lowest version */ + unsigned int pg_hivers; /* lowest version */ + unsigned int pg_nvers; /* number of versions */ +@@ -246,16 +246,16 @@ + * RPC program version + */ + struct svc_version { +- u32 vs_vers; /* version number */ +- u32 vs_nproc; /* number of procedures */ ++ __u32 vs_vers; /* version number */ ++ __u32 vs_nproc; /* number of procedures */ + struct svc_procedure * vs_proc; /* per-procedure info */ +- u32 vs_xdrsize; /* xdrsize needed for this version */ ++ __u32 vs_xdrsize; /* xdrsize needed for this version */ + + /* Override dispatch function (e.g. when caching replies). + * A return value of 0 means drop the request. + * vs_dispatch == NULL means use default dispatcher. + */ +- int (*vs_dispatch)(struct svc_rqst *, u32 *); ++ int (*vs_dispatch)(struct svc_rqst *, __u32 *); + }; + + /* +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/xprt.h linux-libc-headers-2.6.8.0/include/linux/sunrpc/xprt.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/sunrpc/xprt.h 2004-06-23 16:52:58.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/sunrpc/xprt.h 2004-08-26 05:42:08.000000000 -0500 +@@ -93,7 +93,7 @@ + __u32 rq_xid; /* request XID */ + int rq_cong; /* has incremented xprt->cong */ + int rq_received; /* receive completed */ +- u32 rq_seqno; /* gss seq no. used on req. */ ++ __u32 rq_seqno; /* gss seq no. used on req. */ + + struct list_head rq_list; + +@@ -106,13 +106,13 @@ + /* + * For authentication (e.g. auth_des) + */ +- u32 rq_creddata[2]; ++ __u32 rq_creddata[2]; + + /* + * Partial send handling + */ + +- u32 rq_bytes_sent; /* Bytes we have sent */ ++ __u32 rq_bytes_sent; /* Bytes we have sent */ + + unsigned long rq_xtime; /* when transmitted */ + int rq_ntrans; +@@ -160,7 +160,7 @@ + /* + * State of TCP reply receive stuff + */ +- u32 tcp_recm, /* Fragment header */ ++ __u32 tcp_recm, /* Fragment header */ + tcp_xid, /* Current XID */ + tcp_reclen, /* fragment length */ + tcp_offset; /* fragment offset */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/suspend.h linux-libc-headers-2.6.8.0/include/linux/suspend.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/suspend.h 2004-08-18 13:16:05.000000000 -0500 ++++ linux-libc-headers-2.6.8.0/include/linux/suspend.h 2004-08-26 05:42:08.000000000 -0500 +@@ -23,7 +23,7 @@ + #define SWAP_FILENAME_MAXLENGTH 32 + + struct suspend_header { +- u32 version_code; ++ __u32 version_code; + unsigned long num_physpages; + char machine[8]; + char version[20]; +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/sysdev.h linux-libc-headers-2.6.8.0/include/linux/sysdev.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/sysdev.h 2004-03-28 07:52:11.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/sysdev.h 2004-08-26 05:42:08.000000000 -0500 +@@ -31,7 +31,7 @@ + + /* Default operations for these types of devices */ + int (*shutdown)(struct sys_device *); +- int (*suspend)(struct sys_device *, u32 state); ++ int (*suspend)(struct sys_device *, __u32 state); + int (*resume)(struct sys_device *); + struct kset kset; + }; +@@ -50,7 +50,7 @@ + int (*add)(struct sys_device *); + int (*remove)(struct sys_device *); + int (*shutdown)(struct sys_device *); +- int (*suspend)(struct sys_device *, u32 state); ++ int (*suspend)(struct sys_device *, __u32 state); + int (*resume)(struct sys_device *); + }; + +@@ -65,7 +65,7 @@ + */ + + struct sys_device { +- u32 id; ++ __u32 id; + struct sysdev_class * cls; + struct kobject kobj; + }; +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/sysv_fs.h linux-libc-headers-2.6.8.0/include/linux/sysv_fs.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/sysv_fs.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/sysv_fs.h 2004-08-26 05:42:08.000000000 -0500 +@@ -9,12 +9,12 @@ + + + /* inode numbers are 16 bit */ +-typedef u16 sysv_ino_t; ++typedef __u16 sysv_ino_t; + + /* Block numbers are 24 bit, sometimes stored in 32 bit. + On Coherent FS, they are always stored in PDP-11 manner: the least + significant 16 bits come last. */ +-typedef u32 sysv_zone_t; ++typedef __u32 sysv_zone_t; + + /* 0 is non-existent */ + #define SYSV_BADBL_INO 1 /* inode of bad blocks file */ +@@ -25,29 +25,29 @@ + #define XENIX_NICINOD 100 /* number of inode cache entries */ + #define XENIX_NICFREE 100 /* number of free block list chunk entries */ + struct xenix_super_block { +- u16 s_isize; /* index of first data zone */ +- u32 s_fsize __packed2__; /* total number of zones of this fs */ ++ __u16 s_isize; /* index of first data zone */ ++ __u32 s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ +- u16 s_nfree; /* number of free blocks in s_free, <= XENIX_NICFREE */ +- u32 s_free[XENIX_NICFREE]; /* first free block list chunk */ ++ __u16 s_nfree; /* number of free blocks in s_free, <= XENIX_NICFREE */ ++ __u32 s_free[XENIX_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ +- u16 s_ninode; /* number of free inodes in s_inode, <= XENIX_NICINOD */ ++ __u16 s_ninode; /* number of free inodes in s_inode, <= XENIX_NICINOD */ + sysv_ino_t s_inode[XENIX_NICINOD]; /* some free inodes */ + /* locks, not used by Linux: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ +- u32 s_time __packed2__; /* time of last super block update */ +- u32 s_tfree __packed2__; /* total number of free zones */ +- u16 s_tinode; /* total number of free inodes */ +- s16 s_dinfo[4]; /* device information ?? */ ++ __u32 s_time __packed2__; /* time of last super block update */ ++ __u32 s_tfree __packed2__; /* total number of free zones */ ++ __u16 s_tinode; /* total number of free inodes */ ++ __s16 s_dinfo[4]; /* device information ?? */ + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + char s_clean; /* set to 0x46 when filesystem is properly unmounted */ + char s_fill[371]; +- s32 s_magic; /* version of file system */ +- s32 s_type; /* type of file system: 1 for 512 byte blocks ++ __s32 s_magic; /* version of file system */ ++ __s32 s_type; /* type of file system: 1 for 512 byte blocks + 2 for 1024 byte blocks + 3 for 2048 byte blocks */ + +@@ -63,61 +63,61 @@ + + /* SystemV4 super-block data on disk */ + struct sysv4_super_block { +- u16 s_isize; /* index of first data zone */ +- u16 s_pad0; +- u32 s_fsize; /* total number of zones of this fs */ ++ __u16 s_isize; /* index of first data zone */ ++ __u16 s_pad0; ++ __u32 s_fsize; /* total number of zones of this fs */ + /* the start of the free block list: */ +- u16 s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ +- u16 s_pad1; +- u32 s_free[SYSV_NICFREE]; /* first free block list chunk */ ++ __u16 s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ ++ __u16 s_pad1; ++ __u32 s_free[SYSV_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ +- u16 s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ +- u16 s_pad2; ++ __u16 s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ ++ __u16 s_pad2; + sysv_ino_t s_inode[SYSV_NICINOD]; /* some free inodes */ + /* locks, not used by Linux: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ +- u32 s_time; /* time of last super block update */ +- s16 s_dinfo[4]; /* device information ?? */ +- u32 s_tfree; /* total number of free zones */ +- u16 s_tinode; /* total number of free inodes */ +- u16 s_pad3; ++ __u32 s_time; /* time of last super block update */ ++ __s16 s_dinfo[4]; /* device information ?? */ ++ __u32 s_tfree; /* total number of free zones */ ++ __u16 s_tinode; /* total number of free inodes */ ++ __u16 s_pad3; + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ +- s32 s_fill[12]; +- s32 s_state; /* file system state: 0x7c269d38-s_time means clean */ +- s32 s_magic; /* version of file system */ +- s32 s_type; /* type of file system: 1 for 512 byte blocks ++ __s32 s_fill[12]; ++ __s32 s_state; /* file system state: 0x7c269d38-s_time means clean */ ++ __s32 s_magic; /* version of file system */ ++ __s32 s_type; /* type of file system: 1 for 512 byte blocks + 2 for 1024 byte blocks */ + }; + + /* SystemV2 super-block data on disk */ + struct sysv2_super_block { +- u16 s_isize; /* index of first data zone */ +- u32 s_fsize __packed2__; /* total number of zones of this fs */ ++ __u16 s_isize; /* index of first data zone */ ++ __u32 s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ +- u16 s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ +- u32 s_free[SYSV_NICFREE]; /* first free block list chunk */ ++ __u16 s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ ++ __u32 s_free[SYSV_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ +- u16 s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ ++ __u16 s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ + sysv_ino_t s_inode[SYSV_NICINOD]; /* some free inodes */ + /* locks, not used by Linux: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ +- u32 s_time __packed2__; /* time of last super block update */ +- s16 s_dinfo[4]; /* device information ?? */ +- u32 s_tfree __packed2__; /* total number of free zones */ +- u16 s_tinode; /* total number of free inodes */ ++ __u32 s_time __packed2__; /* time of last super block update */ ++ __s16 s_dinfo[4]; /* device information ?? */ ++ __u32 s_tfree __packed2__; /* total number of free zones */ ++ __u16 s_tinode; /* total number of free inodes */ + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ +- s32 s_fill[14]; +- s32 s_state; /* file system state: 0xcb096f43 means clean */ +- s32 s_magic; /* version of file system */ +- s32 s_type; /* type of file system: 1 for 512 byte blocks ++ __s32 s_fill[14]; ++ __s32 s_state; /* file system state: 0xcb096f43 means clean */ ++ __s32 s_magic; /* version of file system */ ++ __s32 s_type; /* type of file system: 1 for 512 byte blocks + 2 for 1024 byte blocks */ + }; + +@@ -125,25 +125,25 @@ + #define V7_NICINOD 100 /* number of inode cache entries */ + #define V7_NICFREE 50 /* number of free block list chunk entries */ + struct v7_super_block { +- u16 s_isize; /* index of first data zone */ +- u32 s_fsize __packed2__; /* total number of zones of this fs */ ++ __u16 s_isize; /* index of first data zone */ ++ __u32 s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ +- u16 s_nfree; /* number of free blocks in s_free, <= V7_NICFREE */ +- u32 s_free[V7_NICFREE]; /* first free block list chunk */ ++ __u16 s_nfree; /* number of free blocks in s_free, <= V7_NICFREE */ ++ __u32 s_free[V7_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ +- u16 s_ninode; /* number of free inodes in s_inode, <= V7_NICINOD */ ++ __u16 s_ninode; /* number of free inodes in s_inode, <= V7_NICINOD */ + sysv_ino_t s_inode[V7_NICINOD]; /* some free inodes */ + /* locks, not used by Linux or V7: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ +- u32 s_time __packed2__; /* time of last super block update */ ++ __u32 s_time __packed2__; /* time of last super block update */ + /* the following fields are not maintained by V7: */ +- u32 s_tfree __packed2__; /* total number of free zones */ +- u16 s_tinode; /* total number of free inodes */ +- u16 s_m; /* interleave factor */ +- u16 s_n; /* interleave factor */ ++ __u32 s_tfree __packed2__; /* total number of free zones */ ++ __u16 s_tinode; /* total number of free inodes */ ++ __u16 s_m; /* interleave factor */ ++ __u16 s_n; /* interleave factor */ + char s_fname[6]; /* file system name */ + char s_fpack[6]; /* file system pack name */ + }; +@@ -152,41 +152,41 @@ + #define COH_NICINOD 100 /* number of inode cache entries */ + #define COH_NICFREE 64 /* number of free block list chunk entries */ + struct coh_super_block { +- u16 s_isize; /* index of first data zone */ +- u32 s_fsize __packed2__; /* total number of zones of this fs */ ++ __u16 s_isize; /* index of first data zone */ ++ __u32 s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ +- u16 s_nfree; /* number of free blocks in s_free, <= COH_NICFREE */ +- u32 s_free[COH_NICFREE] __packed2__; /* first free block list chunk */ ++ __u16 s_nfree; /* number of free blocks in s_free, <= COH_NICFREE */ ++ __u32 s_free[COH_NICFREE] __packed2__; /* first free block list chunk */ + /* the cache of free inodes: */ +- u16 s_ninode; /* number of free inodes in s_inode, <= COH_NICINOD */ ++ __u16 s_ninode; /* number of free inodes in s_inode, <= COH_NICINOD */ + sysv_ino_t s_inode[COH_NICINOD]; /* some free inodes */ + /* locks, not used by Linux: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ +- u32 s_time __packed2__; /* time of last super block update */ +- u32 s_tfree __packed2__; /* total number of free zones */ +- u16 s_tinode; /* total number of free inodes */ +- u16 s_interleave_m; /* interleave factor */ +- u16 s_interleave_n; ++ __u32 s_time __packed2__; /* time of last super block update */ ++ __u32 s_tfree __packed2__; /* total number of free zones */ ++ __u16 s_tinode; /* total number of free inodes */ ++ __u16 s_interleave_m; /* interleave factor */ ++ __u16 s_interleave_n; + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ +- u32 s_unique; /* zero, not used */ ++ __u32 s_unique; /* zero, not used */ + }; + + /* SystemV/Coherent inode data on disk */ + struct sysv_inode { +- u16 i_mode; +- u16 i_nlink; +- u16 i_uid; +- u16 i_gid; +- u32 i_size; +- u8 i_data[3*(10+1+1+1)]; +- u8 i_gen; +- u32 i_atime; /* time of last access */ +- u32 i_mtime; /* time of last modification */ +- u32 i_ctime; /* time of creation */ ++ __u16 i_mode; ++ __u16 i_nlink; ++ __u16 i_uid; ++ __u16 i_gid; ++ __u32 i_size; ++ __u8 i_data[3*(10+1+1+1)]; ++ __u8 i_gen; ++ __u32 i_atime; /* time of last access */ ++ __u32 i_mtime; /* time of last modification */ ++ __u32 i_ctime; /* time of creation */ + }; + + /* SystemV/Coherent directory entry on disk */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/tiocl.h linux-libc-headers-2.6.8.0/include/linux/tiocl.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/tiocl.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/tiocl.h 2004-08-26 05:42:08.000000000 -0500 +@@ -23,7 +23,7 @@ + + #define TIOCL_SELLOADLUT 5 + /* set characters to be considered alphabetic when selecting */ +- /* u32[8] bit array, 4 bytes-aligned with type */ ++ /* __u32[8] bit array, 4 bytes-aligned with type */ + + /* these two don't return a value: they write it back in the type */ + #define TIOCL_GETSHIFTSTATE 6 /* write shift state */ +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/umem.h linux-libc-headers-2.6.8.0/include/linux/umem.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/umem.h 2003-12-15 12:46:58.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/umem.h 2004-08-26 05:42:08.000000000 -0500 +@@ -110,19 +110,19 @@ + #define DMA_WRITE_TO_HOST 1 + + struct mm_dma_desc { +- u64 pci_addr; +- u64 local_addr; +- u32 transfer_size; +- u32 zero1; +- u64 next_desc_addr; +- u64 sem_addr; +- u32 control_bits; +- u32 zero2; ++ __u64 pci_addr; ++ __u64 local_addr; ++ __u32 transfer_size; ++ __u32 zero1; ++ __u64 next_desc_addr; ++ __u64 sem_addr; ++ __u32 control_bits; ++ __u32 zero2; + + dma_addr_t data_dma_handle; + + /* Copy of the bits */ +- u64 sem_control_bits; ++ __u64 sem_control_bits; + } __attribute__((aligned(8))); + + #define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 +diff -urN linux-libc-headers-2.6.8.0-dist/include/linux/vt_buffer.h linux-libc-headers-2.6.8.0/include/linux/vt_buffer.h +--- linux-libc-headers-2.6.8.0-dist/include/linux/vt_buffer.h 2004-01-17 17:04:33.000000000 -0600 ++++ linux-libc-headers-2.6.8.0/include/linux/vt_buffer.h 2004-08-26 05:42:08.000000000 -0500 +@@ -28,7 +28,7 @@ + #endif + + #ifndef VT_BUF_HAVE_MEMSETW +-static inline void scr_memsetw(u16 *s, u16 c, unsigned int count) ++static inline void scr_memsetw(__u16 *s, __u16 c, unsigned int count) + { + count /= 2; + while (count--) +@@ -37,7 +37,7 @@ + #endif + + #ifndef VT_BUF_HAVE_MEMCPYW +-static inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count) ++static inline void scr_memcpyw(__u16 *d, const __u16 *s, unsigned int count) + { + count /= 2; + while (count--) +@@ -46,7 +46,7 @@ + #endif + + #ifndef VT_BUF_HAVE_MEMMOVEW +-static inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count) ++static inline void scr_memmovew(__u16 *d, const __u16 *s, unsigned int count) + { + if (d < s) + scr_memcpyw(d, s, count); diff --git a/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.9-nios2nommu.patch.conditional b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.9-nios2nommu.patch.conditional new file mode 100644 index 0000000000..b828b3bb3f --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/linux-libc-headers-2.6.9-nios2nommu.patch.conditional @@ -0,0 +1,12925 @@ +--- linux/include/asm-generic/bitops.h ++++ linux/include/asm-generic/bitops.h +@@ -0,0 +1,81 @@ ++#ifndef _ASM_GENERIC_BITOPS_H_ ++#define _ASM_GENERIC_BITOPS_H_ ++ ++/* ++ * For the benefit of those who are trying to port Linux to another ++ * architecture, here are some C-language equivalents. You should ++ * recode these in the native assembly language, if at all possible. ++ * To guarantee atomicity, these routines call cli() and sti() to ++ * disable interrupts while they operate. (You have to provide inline ++ * routines to cli() and sti().) ++ * ++ * Also note, these routines assume that you have 32 bit longs. ++ * You will have to change this if you are trying to port Linux to the ++ * Alpha architecture or to a Cray. :-) ++ * ++ * C language equivalents written by Theodore Ts'o, 9/26/92 ++ */ ++ ++extern __inline__ int set_bit(int nr,long * addr) ++{ ++ int mask, retval; ++ ++ addr += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ cli(); ++ retval = (mask & *addr) != 0; ++ *addr |= mask; ++ sti(); ++ return retval; ++} ++ ++extern __inline__ int clear_bit(int nr, long * addr) ++{ ++ int mask, retval; ++ ++ addr += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ cli(); ++ retval = (mask & *addr) != 0; ++ *addr &= ~mask; ++ sti(); ++ return retval; ++} ++ ++extern __inline__ int test_bit(int nr, const unsigned long * addr) ++{ ++ int mask; ++ ++ addr += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ return ((mask & *addr) != 0); ++} ++ ++/* ++ * fls: find last bit set. ++ */ ++ ++#define fls(x) generic_fls(x) ++ ++#ifdef __KERNEL__ ++ ++/* ++ * ffs: find first bit set. This is defined the same way as ++ * the libc and compiler builtin ffs routines, therefore ++ * differs in spirit from the above ffz (man ffs). ++ */ ++ ++#define ffs(x) generic_ffs(x) ++ ++/* ++ * hweightN: returns the hamming weight (i.e. the number ++ * of bits set) of a N-bit word ++ */ ++ ++#define hweight32(x) generic_hweight32(x) ++#define hweight16(x) generic_hweight16(x) ++#define hweight8(x) generic_hweight8(x) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _ASM_GENERIC_BITOPS_H */ +--- linux/include/asm-generic/bug.h ++++ linux/include/asm-generic/bug.h +@@ -0,0 +1,34 @@ ++#ifndef _ASM_GENERIC_BUG_H ++#define _ASM_GENERIC_BUG_H ++ ++#include ++// #include ++ ++#ifndef HAVE_ARCH_BUG ++#define BUG() do { \ ++ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ ++ panic("BUG!"); \ ++} while (0) ++#endif ++ ++#ifndef HAVE_ARCH_PAGE_BUG ++#define PAGE_BUG(page) do { \ ++ printk("page BUG for page at %p\n", page); \ ++ BUG(); \ ++} while (0) ++#endif ++ ++#ifndef HAVE_ARCH_BUG_ON ++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) ++#endif ++ ++#ifndef HAVE_ARCH_WARN_ON ++#define WARN_ON(condition) do { \ ++ if (unlikely((condition)!=0)) { \ ++ printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ ++ dump_stack(); \ ++ } \ ++} while (0) ++#endif ++ ++#endif +--- linux/include/asm-generic/cpumask.h ++++ linux/include/asm-generic/cpumask.h +@@ -0,0 +1,40 @@ ++#ifndef __ASM_GENERIC_CPUMASK_H ++#define __ASM_GENERIC_CPUMASK_H ++ ++// #include ++#include ++#include ++#include ++#include ++ ++#if NR_CPUS > BITS_PER_LONG && NR_CPUS != 1 ++#define CPU_ARRAY_SIZE BITS_TO_LONGS(NR_CPUS) ++ ++struct cpumask ++{ ++ unsigned long mask[CPU_ARRAY_SIZE]; ++}; ++ ++typedef struct cpumask cpumask_t; ++ ++#else ++typedef unsigned long cpumask_t; ++#endif ++ ++#ifdef CONFIG_SMP ++#if NR_CPUS > BITS_PER_LONG ++#include ++#else ++#include ++#endif ++#else ++#include ++#endif ++ ++#if NR_CPUS <= 4*BITS_PER_LONG ++#include ++#else ++#include ++#endif ++ ++#endif /* __ASM_GENERIC_CPUMASK_H */ +--- linux/include/asm-generic/cpumask_arith.h ++++ linux/include/asm-generic/cpumask_arith.h +@@ -0,0 +1,49 @@ ++#ifndef __ASM_GENERIC_CPUMASK_ARITH_H ++#define __ASM_GENERIC_CPUMASK_ARITH_H ++ ++/* ++ * Arithmetic type -based cpu bitmaps. A single unsigned long is used ++ * to contain the whole cpu bitmap. ++ */ ++ ++#define cpu_set(cpu, map) set_bit(cpu, &(map)) ++#define cpu_clear(cpu, map) clear_bit(cpu, &(map)) ++#define cpu_isset(cpu, map) test_bit(cpu, &(map)) ++#define cpu_test_and_set(cpu, map) test_and_set_bit(cpu, &(map)) ++ ++#define cpus_and(dst,src1,src2) do { dst = (src1) & (src2); } while (0) ++#define cpus_or(dst,src1,src2) do { dst = (src1) | (src2); } while (0) ++#define cpus_clear(map) do { map = 0; } while (0) ++#define cpus_complement(map) do { map = ~(map); } while (0) ++#define cpus_equal(map1, map2) ((map1) == (map2)) ++#define cpus_empty(map) ((map) == 0) ++#define cpus_addr(map) (&(map)) ++ ++#if BITS_PER_LONG == 32 ++#define cpus_weight(map) hweight32(map) ++#elif BITS_PER_LONG == 64 ++#define cpus_weight(map) hweight64(map) ++#endif ++ ++#define cpus_shift_right(dst, src, n) do { dst = (src) >> (n); } while (0) ++#define cpus_shift_left(dst, src, n) do { dst = (src) << (n); } while (0) ++ ++#define any_online_cpu(map) \ ++({ \ ++ cpumask_t __tmp__; \ ++ cpus_and(__tmp__, map, cpu_online_map); \ ++ __tmp__ ? first_cpu(__tmp__) : NR_CPUS; \ ++}) ++ ++#define CPU_MASK_ALL (~((cpumask_t)0) >> (8*sizeof(cpumask_t) - NR_CPUS)) ++#define CPU_MASK_NONE ((cpumask_t)0) ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_coerce(map) ((unsigned long)(map)) ++#define cpus_promote(map) ({ map; }) ++#define cpumask_of_cpu(cpu) ({ ((cpumask_t)1) << (cpu); }) ++ ++#define first_cpu(map) __ffs(map) ++#define next_cpu(cpu, map) find_next_bit(&(map), NR_CPUS, cpu + 1) ++ ++#endif /* __ASM_GENERIC_CPUMASK_ARITH_H */ +--- linux/include/asm-generic/cpumask_array.h ++++ linux/include/asm-generic/cpumask_array.h +@@ -0,0 +1,54 @@ ++#ifndef __ASM_GENERIC_CPUMASK_ARRAY_H ++#define __ASM_GENERIC_CPUMASK_ARRAY_H ++ ++/* ++ * Array-based cpu bitmaps. An array of unsigned longs is used to contain ++ * the bitmap, and then contained in a structure so it may be passed by ++ * value. ++ */ ++ ++#define CPU_ARRAY_SIZE BITS_TO_LONGS(NR_CPUS) ++ ++#define cpu_set(cpu, map) set_bit(cpu, (map).mask) ++#define cpu_clear(cpu, map) clear_bit(cpu, (map).mask) ++#define cpu_isset(cpu, map) test_bit(cpu, (map).mask) ++#define cpu_test_and_set(cpu, map) test_and_set_bit(cpu, (map).mask) ++ ++#define cpus_and(dst,src1,src2) bitmap_and((dst).mask,(src1).mask, (src2).mask, NR_CPUS) ++#define cpus_or(dst,src1,src2) bitmap_or((dst).mask, (src1).mask, (src2).mask, NR_CPUS) ++#define cpus_clear(map) bitmap_clear((map).mask, NR_CPUS) ++#define cpus_complement(map) bitmap_complement((map).mask, NR_CPUS) ++#define cpus_equal(map1, map2) bitmap_equal((map1).mask, (map2).mask, NR_CPUS) ++#define cpus_empty(map) bitmap_empty(map.mask, NR_CPUS) ++#define cpus_addr(map) ((map).mask) ++#define cpus_weight(map) bitmap_weight((map).mask, NR_CPUS) ++#define cpus_shift_right(d, s, n) bitmap_shift_right((d).mask, (s).mask, n, NR_CPUS) ++#define cpus_shift_left(d, s, n) bitmap_shift_left((d).mask, (s).mask, n, NR_CPUS) ++#define first_cpu(map) find_first_bit((map).mask, NR_CPUS) ++#define next_cpu(cpu, map) find_next_bit((map).mask, NR_CPUS, cpu + 1) ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_coerce(map) ((map).mask[0]) ++#define cpus_promote(map) ({ cpumask_t __cpu_mask = CPU_MASK_NONE;\ ++ __cpu_mask.mask[0] = map; \ ++ __cpu_mask; \ ++ }) ++#define cpumask_of_cpu(cpu) ({ cpumask_t __cpu_mask = CPU_MASK_NONE;\ ++ cpu_set(cpu, __cpu_mask); \ ++ __cpu_mask; \ ++ }) ++#define any_online_cpu(map) \ ++({ \ ++ cpumask_t __tmp__; \ ++ cpus_and(__tmp__, map, cpu_online_map); \ ++ find_first_bit(__tmp__.mask, NR_CPUS); \ ++}) ++ ++ ++/* ++ * um, these need to be usable as static initializers ++ */ ++#define CPU_MASK_ALL { {[0 ... CPU_ARRAY_SIZE-1] = ~0UL} } ++#define CPU_MASK_NONE { {[0 ... CPU_ARRAY_SIZE-1] = 0UL} } ++ ++#endif /* __ASM_GENERIC_CPUMASK_ARRAY_H */ +--- linux/include/asm-generic/cpumask_const_reference.h ++++ linux/include/asm-generic/cpumask_const_reference.h +@@ -0,0 +1,29 @@ ++#ifndef __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H ++#define __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H ++ ++struct cpumask_ref { ++ const cpumask_t *val; ++}; ++ ++typedef const struct cpumask_ref cpumask_const_t; ++ ++#define mk_cpumask_const(map) ((cpumask_const_t){ &(map) }) ++#define cpu_isset_const(cpu, map) cpu_isset(cpu, *(map).val) ++ ++#define cpus_and_const(dst,src1,src2) cpus_and(dst,*(src1).val,*(src2).val) ++#define cpus_or_const(dst,src1,src2) cpus_or(dst,*(src1).val,*(src2).val) ++ ++#define cpus_equal_const(map1, map2) cpus_equal(*(map1).val, *(map2).val) ++ ++#define cpus_copy_const(map1, map2) bitmap_copy((map1).mask, (map2).val->mask, NR_CPUS) ++ ++#define cpus_empty_const(map) cpus_empty(*(map).val) ++#define cpus_weight_const(map) cpus_weight(*(map).val) ++#define first_cpu_const(map) first_cpu(*(map).val) ++#define next_cpu_const(cpu, map) next_cpu(cpu, *(map).val) ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_coerce_const(map) cpus_coerce(*(map).val) ++#define any_online_cpu_const(map) any_online_cpu(*(map).val) ++ ++#endif /* __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H */ +--- linux/include/asm-generic/cpumask_const_value.h ++++ linux/include/asm-generic/cpumask_const_value.h +@@ -0,0 +1,21 @@ ++#ifndef __ASM_GENERIC_CPUMASK_CONST_VALUE_H ++#define __ASM_GENERIC_CPUMASK_CONST_VALUE_H ++ ++typedef const cpumask_t cpumask_const_t; ++ ++#define mk_cpumask_const(map) (map) ++#define cpu_isset_const(cpu, map) cpu_isset(cpu, map) ++#define cpus_and_const(dst,src1,src2) cpus_and(dst, src1, src2) ++#define cpus_or_const(dst,src1,src2) cpus_or(dst, src1, src2) ++#define cpus_equal_const(map1, map2) cpus_equal(map1, map2) ++#define cpus_empty_const(map) cpus_empty(map) ++#define cpus_copy_const(map1, map2) do { map1 = (cpumask_t)map2; } while (0) ++#define cpus_weight_const(map) cpus_weight(map) ++#define first_cpu_const(map) first_cpu(map) ++#define next_cpu_const(cpu, map) next_cpu(cpu, map) ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_coerce_const(map) cpus_coerce(map) ++#define any_online_cpu_const(map) any_online_cpu(map) ++ ++#endif /* __ASM_GENERIC_CPUMASK_CONST_VALUE_H */ +--- linux/include/asm-generic/cpumask_up.h ++++ linux/include/asm-generic/cpumask_up.h +@@ -0,0 +1,59 @@ ++#ifndef __ASM_GENERIC_CPUMASK_UP_H ++#define __ASM_GENERIC_CPUMASK_UP_H ++ ++#define cpus_coerce(map) (map) ++ ++#define cpu_set(cpu, map) do { (void)(cpu); cpus_coerce(map) = 1UL; } while (0) ++#define cpu_clear(cpu, map) do { (void)(cpu); cpus_coerce(map) = 0UL; } while (0) ++#define cpu_isset(cpu, map) ((void)(cpu), cpus_coerce(map) != 0UL) ++#define cpu_test_and_set(cpu, map) ((void)(cpu), test_and_set_bit(0, &(map))) ++ ++#define cpus_and(dst, src1, src2) \ ++ do { \ ++ if (cpus_coerce(src1) && cpus_coerce(src2)) \ ++ cpus_coerce(dst) = 1UL; \ ++ else \ ++ cpus_coerce(dst) = 0UL; \ ++ } while (0) ++ ++#define cpus_or(dst, src1, src2) \ ++ do { \ ++ if (cpus_coerce(src1) || cpus_coerce(src2)) \ ++ cpus_coerce(dst) = 1UL; \ ++ else \ ++ cpus_coerce(dst) = 0UL; \ ++ } while (0) ++ ++#define cpus_clear(map) do { cpus_coerce(map) = 0UL; } while (0) ++ ++#define cpus_complement(map) \ ++ do { \ ++ cpus_coerce(map) = !cpus_coerce(map); \ ++ } while (0) ++ ++#define cpus_equal(map1, map2) (cpus_coerce(map1) == cpus_coerce(map2)) ++#define cpus_empty(map) (cpus_coerce(map) == 0UL) ++#define cpus_addr(map) (&(map)) ++#define cpus_weight(map) (cpus_coerce(map) ? 1UL : 0UL) ++#define cpus_shift_right(d, s, n) do { cpus_coerce(d) = 0UL; } while (0) ++#define cpus_shift_left(d, s, n) do { cpus_coerce(d) = 0UL; } while (0) ++#define first_cpu(map) (cpus_coerce(map) ? 0 : 1) ++#define next_cpu(cpu, map) 1 ++ ++/* only ever use this for things that are _never_ used on large boxen */ ++#define cpus_promote(map) \ ++ ({ \ ++ cpumask_t __tmp__; \ ++ cpus_coerce(__tmp__) = map; \ ++ __tmp__; \ ++ }) ++#define cpumask_of_cpu(cpu) ((void)(cpu), cpus_promote(1)) ++#define any_online_cpu(map) (cpus_coerce(map) ? 0 : 1) ++ ++/* ++ * um, these need to be usable as static initializers ++ */ ++#define CPU_MASK_ALL 1UL ++#define CPU_MASK_NONE 0UL ++ ++#endif /* __ASM_GENERIC_CPUMASK_UP_H */ +--- linux/include/asm-generic/div64.h ++++ linux/include/asm-generic/div64.h +@@ -0,0 +1,58 @@ ++#ifndef _ASM_GENERIC_DIV64_H ++#define _ASM_GENERIC_DIV64_H ++/* ++ * Copyright (C) 2003 Bernardo Innocenti ++ * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h ++ * ++ * The semantics of do_div() are: ++ * ++ * uint32_t do_div(uint64_t *n, uint32_t base) ++ * { ++ * uint32_t remainder = *n % base; ++ * *n = *n / base; ++ * return remainder; ++ * } ++ * ++ * NOTE: macro parameter n is evaluated multiple times, ++ * beware of side effects! ++ */ ++ ++#include ++#include ++ ++#if BITS_PER_LONG == 64 ++ ++# define do_div(n,base) ({ \ ++ uint32_t __base = (base); \ ++ uint32_t __rem; \ ++ __rem = ((uint64_t)(n)) % __base; \ ++ (n) = ((uint64_t)(n)) / __base; \ ++ __rem; \ ++ }) ++ ++#elif BITS_PER_LONG == 32 ++ ++extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); ++ ++/* The unnecessary pointer compare is there ++ * to check for type safety (n must be 64bit) ++ */ ++# define do_div(n,base) ({ \ ++ uint32_t __base = (base); \ ++ uint32_t __rem; \ ++ (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ ++ if (likely(((n) >> 32) == 0)) { \ ++ __rem = (uint32_t)(n) % __base; \ ++ (n) = (uint32_t)(n) / __base; \ ++ } else \ ++ __rem = __div64_32(&(n), __base); \ ++ __rem; \ ++ }) ++ ++#else /* BITS_PER_LONG == ?? */ ++ ++# error do_div() does not yet support the C64 ++ ++#endif /* BITS_PER_LONG */ ++ ++#endif /* _ASM_GENERIC_DIV64_H */ +--- linux/include/asm-generic/dma-mapping-broken.h ++++ linux/include/asm-generic/dma-mapping-broken.h +@@ -0,0 +1,22 @@ ++#ifndef _ASM_GENERIC_DMA_MAPPING_H ++#define _ASM_GENERIC_DMA_MAPPING_H ++ ++/* This is used for archs that do not support DMA */ ++ ++ ++static inline void * ++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, ++ int flag) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void ++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t dma_handle) ++{ ++ BUG(); ++} ++ ++#endif /* _ASM_GENERIC_DMA_MAPPING_H */ +--- linux/include/asm-generic/dma-mapping.h ++++ linux/include/asm-generic/dma-mapping.h +@@ -0,0 +1,309 @@ ++/* Copyright (C) 2002 by James.Bottomley@HansenPartnership.com ++ * ++ * Implements the generic device dma API via the existing pci_ one ++ * for unconverted architectures ++ */ ++ ++#ifndef _ASM_GENERIC_DMA_MAPPING_H ++#define _ASM_GENERIC_DMA_MAPPING_H ++ ++// #include ++ ++#ifdef CONFIG_PCI ++ ++/* we implement the API below in terms of the existing PCI one, ++ * so include it */ ++#include ++/* need struct page definitions */ ++#include ++ ++static inline int ++dma_supported(struct device *dev, u64 mask) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_dma_supported(to_pci_dev(dev), mask); ++} ++ ++static inline int ++dma_set_mask(struct device *dev, u64 dma_mask) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_set_dma_mask(to_pci_dev(dev), dma_mask); ++} ++ ++static inline void * ++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, ++ int flag) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); ++} ++ ++static inline void ++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t dma_handle) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); ++} ++ ++static inline dma_addr_t ++dma_map_single(struct device *dev, void *cpu_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); ++} ++ ++static inline void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); ++} ++ ++static inline dma_addr_t ++dma_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); ++} ++ ++static inline void ++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); ++} ++ ++static inline int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); ++} ++ ++static inline void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); ++} ++ ++static inline void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, ++ size, (int)direction); ++} ++ ++static inline void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, ++ size, (int)direction); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(dev->bus != &pci_bus_type); ++ ++ pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); ++} ++ ++static inline int ++dma_mapping_error(dma_addr_t dma_addr) ++{ ++ return pci_dma_mapping_error(dma_addr); ++} ++ ++ ++#else ++ ++static inline int ++dma_supported(struct device *dev, u64 mask) ++{ ++ return 0; ++} ++ ++static inline int ++dma_set_mask(struct device *dev, u64 dma_mask) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void * ++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, ++ int flag) ++{ ++ BUG(); ++ return NULL; ++} ++ ++static inline void ++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t dma_handle) ++{ ++ BUG(); ++} ++ ++static inline dma_addr_t ++dma_map_single(struct device *dev, void *cpu_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline dma_addr_t ++dma_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void ++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ BUG(); ++} ++ ++static inline int ++dma_error(dma_addr_t dma_addr) ++{ ++ return 0; ++} ++ ++#endif ++ ++/* Now for the API extensions over the pci_ one */ ++ ++#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) ++#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) ++#define dma_is_consistent(d) (1) ++ ++static inline int ++dma_get_cache_alignment(void) ++{ ++ /* no easy way to get cache size on all processors, so return ++ * the maximum possible, to be safe */ ++ return (1 << L1_CACHE_SHIFT_MAX); ++} ++ ++static inline void ++dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ /* just sync everything, that's all the pci API can do */ ++ dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction); ++} ++ ++static inline void ++dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ /* just sync everything, that's all the pci API can do */ ++ dma_sync_single_for_device(dev, dma_handle, offset+size, direction); ++} ++ ++static inline void ++dma_cache_sync(void *vaddr, size_t size, ++ enum dma_data_direction direction) ++{ ++ /* could define this in terms of the dma_cache ... operations, ++ * but if you get this on a platform, you should convert the platform ++ * to using the generic device DMA API */ ++ BUG(); ++} ++ ++#endif ++ +--- linux/include/asm-generic/errno-base.h ++++ linux/include/asm-generic/errno-base.h +@@ -0,0 +1,39 @@ ++#ifndef _ASM_GENERIC_ERRNO_BASE_H ++#define _ASM_GENERIC_ERRNO_BASE_H ++ ++#define EPERM 1 /* Operation not permitted */ ++#define ENOENT 2 /* No such file or directory */ ++#define ESRCH 3 /* No such process */ ++#define EINTR 4 /* Interrupted system call */ ++#define EIO 5 /* I/O error */ ++#define ENXIO 6 /* No such device or address */ ++#define E2BIG 7 /* Argument list too long */ ++#define ENOEXEC 8 /* Exec format error */ ++#define EBADF 9 /* Bad file number */ ++#define ECHILD 10 /* No child processes */ ++#define EAGAIN 11 /* Try again */ ++#define ENOMEM 12 /* Out of memory */ ++#define EACCES 13 /* Permission denied */ ++#define EFAULT 14 /* Bad address */ ++#define ENOTBLK 15 /* Block device required */ ++#define EBUSY 16 /* Device or resource busy */ ++#define EEXIST 17 /* File exists */ ++#define EXDEV 18 /* Cross-device link */ ++#define ENODEV 19 /* No such device */ ++#define ENOTDIR 20 /* Not a directory */ ++#define EISDIR 21 /* Is a directory */ ++#define EINVAL 22 /* Invalid argument */ ++#define ENFILE 23 /* File table overflow */ ++#define EMFILE 24 /* Too many open files */ ++#define ENOTTY 25 /* Not a typewriter */ ++#define ETXTBSY 26 /* Text file busy */ ++#define EFBIG 27 /* File too large */ ++#define ENOSPC 28 /* No space left on device */ ++#define ESPIPE 29 /* Illegal seek */ ++#define EROFS 30 /* Read-only file system */ ++#define EMLINK 31 /* Too many links */ ++#define EPIPE 32 /* Broken pipe */ ++#define EDOM 33 /* Math argument out of domain of func */ ++#define ERANGE 34 /* Math result not representable */ ++ ++#endif +--- linux/include/asm-generic/errno.h ++++ linux/include/asm-generic/errno.h +@@ -0,0 +1,100 @@ ++#ifndef _ASM_GENERIC_ERRNO_H ++#define _ASM_GENERIC_ERRNO_H ++ ++#include ++ ++#define EDEADLK 35 /* Resource deadlock would occur */ ++#define ENAMETOOLONG 36 /* File name too long */ ++#define ENOLCK 37 /* No record locks available */ ++#define ENOSYS 38 /* Function not implemented */ ++#define ENOTEMPTY 39 /* Directory not empty */ ++#define ELOOP 40 /* Too many symbolic links encountered */ ++#define EWOULDBLOCK EAGAIN /* Operation would block */ ++#define ENOMSG 42 /* No message of desired type */ ++#define EIDRM 43 /* Identifier removed */ ++#define ECHRNG 44 /* Channel number out of range */ ++#define EL2NSYNC 45 /* Level 2 not synchronized */ ++#define EL3HLT 46 /* Level 3 halted */ ++#define EL3RST 47 /* Level 3 reset */ ++#define ELNRNG 48 /* Link number out of range */ ++#define EUNATCH 49 /* Protocol driver not attached */ ++#define ENOCSI 50 /* No CSI structure available */ ++#define EL2HLT 51 /* Level 2 halted */ ++#define EBADE 52 /* Invalid exchange */ ++#define EBADR 53 /* Invalid request descriptor */ ++#define EXFULL 54 /* Exchange full */ ++#define ENOANO 55 /* No anode */ ++#define EBADRQC 56 /* Invalid request code */ ++#define EBADSLT 57 /* Invalid slot */ ++ ++#define EDEADLOCK EDEADLK ++ ++#define EBFONT 59 /* Bad font file format */ ++#define ENOSTR 60 /* Device not a stream */ ++#define ENODATA 61 /* No data available */ ++#define ETIME 62 /* Timer expired */ ++#define ENOSR 63 /* Out of streams resources */ ++#define ENONET 64 /* Machine is not on the network */ ++#define ENOPKG 65 /* Package not installed */ ++#define EREMOTE 66 /* Object is remote */ ++#define ENOLINK 67 /* Link has been severed */ ++#define EADV 68 /* Advertise error */ ++#define ESRMNT 69 /* Srmount error */ ++#define ECOMM 70 /* Communication error on send */ ++#define EPROTO 71 /* Protocol error */ ++#define EMULTIHOP 72 /* Multihop attempted */ ++#define EDOTDOT 73 /* RFS specific error */ ++#define EBADMSG 74 /* Not a data message */ ++#define EOVERFLOW 75 /* Value too large for defined data type */ ++#define ENOTUNIQ 76 /* Name not unique on network */ ++#define EBADFD 77 /* File descriptor in bad state */ ++#define EREMCHG 78 /* Remote address changed */ ++#define ELIBACC 79 /* Can not access a needed shared library */ ++#define ELIBBAD 80 /* Accessing a corrupted shared library */ ++#define ELIBSCN 81 /* .lib section in a.out corrupted */ ++#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ ++#define ELIBEXEC 83 /* Cannot exec a shared library directly */ ++#define EILSEQ 84 /* Illegal byte sequence */ ++#define ERESTART 85 /* Interrupted system call should be restarted */ ++#define ESTRPIPE 86 /* Streams pipe error */ ++#define EUSERS 87 /* Too many users */ ++#define ENOTSOCK 88 /* Socket operation on non-socket */ ++#define EDESTADDRREQ 89 /* Destination address required */ ++#define EMSGSIZE 90 /* Message too long */ ++#define EPROTOTYPE 91 /* Protocol wrong type for socket */ ++#define ENOPROTOOPT 92 /* Protocol not available */ ++#define EPROTONOSUPPORT 93 /* Protocol not supported */ ++#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ ++#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ ++#define EPFNOSUPPORT 96 /* Protocol family not supported */ ++#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ ++#define EADDRINUSE 98 /* Address already in use */ ++#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ ++#define ENETDOWN 100 /* Network is down */ ++#define ENETUNREACH 101 /* Network is unreachable */ ++#define ENETRESET 102 /* Network dropped connection because of reset */ ++#define ECONNABORTED 103 /* Software caused connection abort */ ++#define ECONNRESET 104 /* Connection reset by peer */ ++#define ENOBUFS 105 /* No buffer space available */ ++#define EISCONN 106 /* Transport endpoint is already connected */ ++#define ENOTCONN 107 /* Transport endpoint is not connected */ ++#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ ++#define ETOOMANYREFS 109 /* Too many references: cannot splice */ ++#define ETIMEDOUT 110 /* Connection timed out */ ++#define ECONNREFUSED 111 /* Connection refused */ ++#define EHOSTDOWN 112 /* Host is down */ ++#define EHOSTUNREACH 113 /* No route to host */ ++#define EALREADY 114 /* Operation already in progress */ ++#define EINPROGRESS 115 /* Operation now in progress */ ++#define ESTALE 116 /* Stale NFS file handle */ ++#define EUCLEAN 117 /* Structure needs cleaning */ ++#define ENOTNAM 118 /* Not a XENIX named type file */ ++#define ENAVAIL 119 /* No XENIX semaphores available */ ++#define EISNAM 120 /* Is a named type file */ ++#define EREMOTEIO 121 /* Remote I/O error */ ++#define EDQUOT 122 /* Quota exceeded */ ++ ++#define ENOMEDIUM 123 /* No medium found */ ++#define EMEDIUMTYPE 124 /* Wrong medium type */ ++ ++#endif +--- linux/include/asm-generic/hdreg.h ++++ linux/include/asm-generic/hdreg.h +@@ -0,0 +1,8 @@ ++#warning is obsolete, please do not use it ++ ++#ifndef __ASM_GENERIC_HDREG_H ++#define __ASM_GENERIC_HDREG_H ++ ++typedef unsigned long ide_ioreg_t; ++ ++#endif /* __ASM_GENERIC_HDREG_H */ +--- linux/include/asm-generic/ide_iops.h ++++ linux/include/asm-generic/ide_iops.h +@@ -0,0 +1,38 @@ ++/* Generic I/O and MEMIO string operations. */ ++ ++#define __ide_insw insw ++#define __ide_insl insl ++#define __ide_outsw outsw ++#define __ide_outsl outsl ++ ++static __inline__ void __ide_mm_insw(void __iomem *port, void *addr, u32 count) ++{ ++ while (count--) { ++ *(u16 *)addr = readw(port); ++ addr += 2; ++ } ++} ++ ++static __inline__ void __ide_mm_insl(void __iomem *port, void *addr, u32 count) ++{ ++ while (count--) { ++ *(u32 *)addr = readl(port); ++ addr += 4; ++ } ++} ++ ++static __inline__ void __ide_mm_outsw(void __iomem *port, void *addr, u32 count) ++{ ++ while (count--) { ++ writew(*(u16 *)addr, port); ++ addr += 2; ++ } ++} ++ ++static __inline__ void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) ++{ ++ while (count--) { ++ writel(*(u32 *)addr, port); ++ addr += 4; ++ } ++} +--- linux/include/asm-generic/iomap.h ++++ linux/include/asm-generic/iomap.h +@@ -0,0 +1,63 @@ ++#ifndef __GENERIC_IO_H ++#define __GENERIC_IO_H ++ ++#include ++ ++/* ++ * These are the "generic" interfaces for doing new-style ++ * memory-mapped or PIO accesses. Architectures may do ++ * their own arch-optimized versions, these just act as ++ * wrappers around the old-style IO register access functions: ++ * read[bwl]/write[bwl]/in[bwl]/out[bwl] ++ * ++ * Don't include this directly, include it from . ++ */ ++ ++/* ++ * Read/write from/to an (offsettable) iomem cookie. It might be a PIO ++ * access or a MMIO access, these functions don't care. The info is ++ * encoded in the hardware mapping set up by the mapping functions ++ * (or the cookie itself, depending on implementation and hw). ++ * ++ * The generic routines just encode the PIO/MMIO as part of the ++ * cookie, and coldly assume that the MMIO IO mappings are not ++ * in the low address range. Architectures for which this is not ++ * true can't use this generic implementation. ++ */ ++extern unsigned int fastcall ioread8(void __iomem *); ++extern unsigned int fastcall ioread16(void __iomem *); ++extern unsigned int fastcall ioread32(void __iomem *); ++ ++extern void fastcall iowrite8(u8, void __iomem *); ++extern void fastcall iowrite16(u16, void __iomem *); ++extern void fastcall iowrite32(u32, void __iomem *); ++ ++/* ++ * "string" versions of the above. Note that they ++ * use native byte ordering for the accesses (on ++ * the assumption that IO and memory agree on a ++ * byte order, and CPU byteorder is irrelevant). ++ * ++ * They do _not_ update the port address. If you ++ * want MMIO that copies stuff laid out in MMIO ++ * memory across multiple ports, use "memcpy_toio()" ++ * and friends. ++ */ ++extern void fastcall ioread8_rep(void __iomem *port, void *buf, unsigned long count); ++extern void fastcall ioread16_rep(void __iomem *port, void *buf, unsigned long count); ++extern void fastcall ioread32_rep(void __iomem *port, void *buf, unsigned long count); ++ ++extern void fastcall iowrite8_rep(void __iomem *port, const void *buf, unsigned long count); ++extern void fastcall iowrite16_rep(void __iomem *port, const void *buf, unsigned long count); ++extern void fastcall iowrite32_rep(void __iomem *port, const void *buf, unsigned long count); ++ ++/* Create a virtual mapping cookie for an IO port range */ ++extern void __iomem *ioport_map(unsigned long port, unsigned int nr); ++extern void ioport_unmap(void __iomem *); ++ ++/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ ++struct pci_dev; ++extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); ++extern void pci_iounmap(struct pci_dev *dev, void __iomem *); ++ ++#endif +--- linux/include/asm-generic/local.h ++++ linux/include/asm-generic/local.h +@@ -0,0 +1,118 @@ ++#ifndef _ASM_GENERIC_LOCAL_H ++#define _ASM_GENERIC_LOCAL_H ++ ++// #include ++#include ++#include ++#include ++ ++/* An unsigned long type for operations which are atomic for a single ++ * CPU. Usually used in combination with per-cpu variables. */ ++ ++#if BITS_PER_LONG == 32 ++/* Implement in terms of atomics. */ ++ ++/* Don't use typedef: don't want them to be mixed with atomic_t's. */ ++typedef struct ++{ ++ atomic_t a; ++} local_t; ++ ++#define LOCAL_INIT(i) { ATOMIC_INIT(i) } ++ ++#define local_read(l) ((unsigned long)atomic_read(&(l)->a)) ++#define local_set(l,i) atomic_set((&(l)->a),(i)) ++#define local_inc(l) atomic_inc(&(l)->a) ++#define local_dec(l) atomic_dec(&(l)->a) ++#define local_add(i,l) atomic_add((i),(&(l)->a)) ++#define local_sub(i,l) atomic_sub((i),(&(l)->a)) ++ ++/* Non-atomic variants, ie. preemption disabled and won't be touched ++ * in interrupt, etc. Some archs can optimize this case well. */ ++#define __local_inc(l) local_set((l), local_read(l) + 1) ++#define __local_dec(l) local_set((l), local_read(l) - 1) ++#define __local_add(i,l) local_set((l), local_read(l) + (i)) ++#define __local_sub(i,l) local_set((l), local_read(l) - (i)) ++ ++#else /* ... can't use atomics. */ ++/* Implement in terms of three variables. ++ Another option would be to use local_irq_save/restore. */ ++ ++typedef struct ++{ ++ /* 0 = in hardirq, 1 = in softirq, 2 = usermode. */ ++ unsigned long v[3]; ++} local_t; ++ ++#define _LOCAL_VAR(l) ((l)->v[!in_interrupt() + !in_irq()]) ++ ++#define LOCAL_INIT(i) { { (i), 0, 0 } } ++ ++static inline unsigned long local_read(local_t *l) ++{ ++ return l->v[0] + l->v[1] + l->v[2]; ++} ++ ++static inline void local_set(local_t *l, unsigned long v) ++{ ++ l->v[0] = v; ++ l->v[1] = l->v[2] = 0; ++} ++ ++static inline void local_inc(local_t *l) ++{ ++ preempt_disable(); ++ _LOCAL_VAR(l)++; ++ preempt_enable(); ++} ++ ++static inline void local_dec(local_t *l) ++{ ++ preempt_disable(); ++ _LOCAL_VAR(l)--; ++ preempt_enable(); ++} ++ ++static inline void local_add(unsigned long v, local_t *l) ++{ ++ preempt_disable(); ++ _LOCAL_VAR(l) += v; ++ preempt_enable(); ++} ++ ++static inline void local_sub(unsigned long v, local_t *l) ++{ ++ preempt_disable(); ++ _LOCAL_VAR(l) -= v; ++ preempt_enable(); ++} ++ ++/* Non-atomic variants, ie. preemption disabled and won't be touched ++ * in interrupt, etc. Some archs can optimize this case well. */ ++#define __local_inc(l) ((l)->v[0]++) ++#define __local_dec(l) ((l)->v[0]--) ++#define __local_add(i,l) ((l)->v[0] += (i)) ++#define __local_sub(i,l) ((l)->v[0] -= (i)) ++ ++#endif /* Non-atomic implementation */ ++ ++/* Use these for per-cpu local_t variables: on some archs they are ++ * much more efficient than these naive implementations. Note they take ++ * a variable (eg. mystruct.foo), not an address. ++ */ ++#define cpu_local_read(v) local_read(&__get_cpu_var(v)) ++#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i)) ++#define cpu_local_inc(v) local_inc(&__get_cpu_var(v)) ++#define cpu_local_dec(v) local_dec(&__get_cpu_var(v)) ++#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v)) ++#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v)) ++ ++/* Non-atomic increments, ie. preemption disabled and won't be touched ++ * in interrupt, etc. Some archs can optimize this case well. ++ */ ++#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v)) ++#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v)) ++#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v)) ++#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v)) ++ ++#endif /* _ASM_GENERIC_LOCAL_H */ +--- linux/include/asm-generic/pci-dma-compat.h ++++ linux/include/asm-generic/pci-dma-compat.h +@@ -0,0 +1,107 @@ ++/* include this file if the platform implements the dma_ DMA Mapping API ++ * and wants to provide the pci_ DMA Mapping API in terms of it */ ++ ++#ifndef _ASM_GENERIC_PCI_DMA_COMPAT_H ++#define _ASM_GENERIC_PCI_DMA_COMPAT_H ++ ++#include ++ ++/* note pci_set_dma_mask isn't here, since it's a public function ++ * exported from drivers/pci, use dma_supported instead */ ++ ++static inline int ++pci_dma_supported(struct pci_dev *hwdev, u64 mask) ++{ ++ return dma_supported(hwdev == NULL ? NULL : &hwdev->dev, mask); ++} ++ ++static inline void * ++pci_alloc_consistent(struct pci_dev *hwdev, size_t size, ++ dma_addr_t *dma_handle) ++{ ++ return dma_alloc_coherent(hwdev == NULL ? NULL : &hwdev->dev, size, dma_handle, GFP_ATOMIC); ++} ++ ++static inline void ++pci_free_consistent(struct pci_dev *hwdev, size_t size, ++ void *vaddr, dma_addr_t dma_handle) ++{ ++ dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev, size, vaddr, dma_handle); ++} ++ ++static inline dma_addr_t ++pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) ++{ ++ return dma_map_single(hwdev == NULL ? NULL : &hwdev->dev, ptr, size, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, ++ size_t size, int direction) ++{ ++ dma_unmap_single(hwdev == NULL ? NULL : &hwdev->dev, dma_addr, size, (enum dma_data_direction)direction); ++} ++ ++static inline dma_addr_t ++pci_map_page(struct pci_dev *hwdev, struct page *page, ++ unsigned long offset, size_t size, int direction) ++{ ++ return dma_map_page(hwdev == NULL ? NULL : &hwdev->dev, page, offset, size, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address, ++ size_t size, int direction) ++{ ++ dma_unmap_page(hwdev == NULL ? NULL : &hwdev->dev, dma_address, size, (enum dma_data_direction)direction); ++} ++ ++static inline int ++pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, ++ int nents, int direction) ++{ ++ return dma_map_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, ++ int nents, int direction) ++{ ++ dma_unmap_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, ++ size_t size, int direction) ++{ ++ dma_sync_single_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, ++ size_t size, int direction) ++{ ++ dma_sync_single_for_device(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, ++ int nelems, int direction) ++{ ++ dma_sync_sg_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); ++} ++ ++static inline void ++pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, ++ int nelems, int direction) ++{ ++ dma_sync_sg_for_device(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); ++} ++ ++static inline int ++pci_dma_mapping_error(dma_addr_t dma_addr) ++{ ++ return dma_mapping_error(dma_addr); ++} ++ ++#endif +--- linux/include/asm-generic/pci.h ++++ linux/include/asm-generic/pci.h +@@ -0,0 +1,27 @@ ++/* ++ * linux/include/asm-generic/pci.h ++ * ++ * Copyright (C) 2003 Russell King ++ */ ++#ifndef _ASM_GENERIC_PCI_H ++#define _ASM_GENERIC_PCI_H ++ ++/** ++ * pcibios_resource_to_bus - convert resource to PCI bus address ++ * @dev: device which owns this resource ++ * @region: converted bus-centric region (start,end) ++ * @res: resource to convert ++ * ++ * Convert a resource to a PCI device bus address or bus window. ++ */ ++static inline void ++pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, ++ struct resource *res) ++{ ++ region->start = res->start; ++ region->end = res->end; ++} ++ ++#define pcibios_scan_all_fns(a, b) 0 ++ ++#endif +--- linux/include/asm-generic/percpu.h ++++ linux/include/asm-generic/percpu.h +@@ -0,0 +1,42 @@ ++#ifndef _ASM_GENERIC_PERCPU_H_ ++#define _ASM_GENERIC_PERCPU_H_ ++#include ++ ++#define __GENERIC_PER_CPU ++#ifdef CONFIG_SMP ++ ++extern unsigned long __per_cpu_offset[NR_CPUS]; ++ ++/* Separate out the type, so (int[3], foo) works. */ ++#define DEFINE_PER_CPU(type, name) \ ++ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name ++ ++/* var is in discarded region: offset to particular copy we want */ ++#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) ++#define __get_cpu_var(var) per_cpu(var, smp_processor_id()) ++ ++/* A macro to avoid #include hell... */ ++#define percpu_modcopy(pcpudst, src, size) \ ++do { \ ++ unsigned int __i; \ ++ for (__i = 0; __i < NR_CPUS; __i++) \ ++ if (cpu_possible(__i)) \ ++ memcpy((pcpudst)+__per_cpu_offset[__i], \ ++ (src), (size)); \ ++} while (0) ++#else /* ! SMP */ ++ ++#define DEFINE_PER_CPU(type, name) \ ++ __typeof__(type) per_cpu__##name ++ ++#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var)) ++#define __get_cpu_var(var) per_cpu__##var ++ ++#endif /* SMP */ ++ ++#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name ++ ++#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var) ++#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var) ++ ++#endif /* _ASM_GENERIC_PERCPU_H_ */ +--- linux/include/asm-generic/pgtable.h ++++ linux/include/asm-generic/pgtable.h +@@ -0,0 +1,137 @@ ++#ifndef _ASM_GENERIC_PGTABLE_H ++#define _ASM_GENERIC_PGTABLE_H ++ ++#ifndef __HAVE_ARCH_PTEP_ESTABLISH ++/* ++ * Establish a new mapping: ++ * - flush the old one ++ * - update the page tables ++ * - inform the TLB about the new one ++ * ++ * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock. ++ * ++ * Note: the old pte is known to not be writable, so we don't need to ++ * worry about dirty bits etc getting lost. ++ */ ++#ifndef __HAVE_ARCH_SET_PTE_ATOMIC ++#define ptep_establish(__vma, __address, __ptep, __entry) \ ++do { \ ++ set_pte(__ptep, __entry); \ ++ flush_tlb_page(__vma, __address); \ ++} while (0) ++#else /* __HAVE_ARCH_SET_PTE_ATOMIC */ ++#define ptep_establish(__vma, __address, __ptep, __entry) \ ++do { \ ++ set_pte_atomic(__ptep, __entry); \ ++ flush_tlb_page(__vma, __address); \ ++} while (0) ++#endif /* __HAVE_ARCH_SET_PTE_ATOMIC */ ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS ++/* ++ * Largely same as above, but only sets the access flags (dirty, ++ * accessed, and writable). Furthermore, we know it always gets set ++ * to a "more permissive" setting, which allows most architectures ++ * to optimize this. ++ */ ++#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ ++do { \ ++ set_pte(__ptep, __entry); \ ++ flush_tlb_page(__vma, __address); \ ++} while (0) ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++static inline int ptep_test_and_clear_young(pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (!pte_young(pte)) ++ return 0; ++ set_pte(ptep, pte_mkold(pte)); ++ return 1; ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH ++#define ptep_clear_flush_young(__vma, __address, __ptep) \ ++({ \ ++ int __young = ptep_test_and_clear_young(__ptep); \ ++ if (__young) \ ++ flush_tlb_page(__vma, __address); \ ++ __young; \ ++}) ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY ++static inline int ptep_test_and_clear_dirty(pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (!pte_dirty(pte)) ++ return 0; ++ set_pte(ptep, pte_mkclean(pte)); ++ return 1; ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH ++#define ptep_clear_flush_dirty(__vma, __address, __ptep) \ ++({ \ ++ int __dirty = ptep_test_and_clear_dirty(__ptep); \ ++ if (__dirty) \ ++ flush_tlb_page(__vma, __address); \ ++ __dirty; \ ++}) ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR ++static inline pte_t ptep_get_and_clear(pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ pte_clear(ptep); ++ return pte; ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH ++#define ptep_clear_flush(__vma, __address, __ptep) \ ++({ \ ++ pte_t __pte = ptep_get_and_clear(__ptep); \ ++ flush_tlb_page(__vma, __address); \ ++ __pte; \ ++}) ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_SET_WRPROTECT ++static inline void ptep_set_wrprotect(pte_t *ptep) ++{ ++ pte_t old_pte = *ptep; ++ set_pte(ptep, pte_wrprotect(old_pte)); ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTEP_MKDIRTY ++static inline void ptep_mkdirty(pte_t *ptep) ++{ ++ pte_t old_pte = *ptep; ++ set_pte(ptep, pte_mkdirty(old_pte)); ++} ++#endif ++ ++#ifndef __HAVE_ARCH_PTE_SAME ++#define pte_same(A,B) (pte_val(A) == pte_val(B)) ++#endif ++ ++#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY ++#define page_test_and_clear_dirty(page) (0) ++#endif ++ ++#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG ++#define page_test_and_clear_young(page) (0) ++#endif ++ ++#ifndef __HAVE_ARCH_PGD_OFFSET_GATE ++#define pgd_offset_gate(mm, addr) pgd_offset(mm, addr) ++#endif ++ ++#endif /* _ASM_GENERIC_PGTABLE_H */ +--- linux/include/asm-generic/rmap.h ++++ linux/include/asm-generic/rmap.h +@@ -0,0 +1,90 @@ ++#ifndef _GENERIC_RMAP_H ++#define _GENERIC_RMAP_H ++/* ++ * linux/include/asm-generic/rmap.h ++ * ++ * Architecture dependent parts of the reverse mapping code, ++ * this version should work for most architectures with a ++ * 'normal' page table layout. ++ * ++ * We use the struct page of the page table page to find out ++ * the process and full address of a page table entry: ++ * - page->mapping points to the process' mm_struct ++ * - page->index has the high bits of the address ++ * - the lower bits of the address are calculated from the ++ * offset of the page table entry within the page table page ++ * ++ * For CONFIG_HIGHPTE, we need to represent the address of a pte in a ++ * scalar pte_addr_t. The pfn of the pte's page is shifted left by PAGE_SIZE ++ * bits and is then ORed with the byte offset of the pte within its page. ++ * ++ * For CONFIG_HIGHMEM4G, the pte_addr_t is 32 bits. 20 for the pfn, 12 for ++ * the offset. ++ * ++ * For CONFIG_HIGHMEM64G, the pte_addr_t is 64 bits. 52 for the pfn, 12 for ++ * the offset. ++ */ ++#include ++ ++static inline void pgtable_add_rmap(struct page * page, struct mm_struct * mm, unsigned long address) ++{ ++#ifdef BROKEN_PPC_PTE_ALLOC_ONE ++ /* OK, so PPC calls pte_alloc() before mem_map[] is setup ... ;( */ ++ extern int mem_init_done; ++ ++ if (!mem_init_done) ++ return; ++#endif ++ page->mapping = (void *)mm; ++ page->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1); ++ inc_page_state(nr_page_table_pages); ++} ++ ++static inline void pgtable_remove_rmap(struct page * page) ++{ ++ page->mapping = NULL; ++ page->index = 0; ++ dec_page_state(nr_page_table_pages); ++} ++ ++static inline struct mm_struct * ptep_to_mm(pte_t * ptep) ++{ ++ struct page * page = kmap_atomic_to_page(ptep); ++ return (struct mm_struct *) page->mapping; ++} ++ ++static inline unsigned long ptep_to_address(pte_t * ptep) ++{ ++ struct page * page = kmap_atomic_to_page(ptep); ++ unsigned long low_bits; ++ low_bits = ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE; ++ return page->index + low_bits; ++} ++ ++#ifdef CONFIG_HIGHPTE ++static inline pte_addr_t ptep_to_paddr(pte_t *ptep) ++{ ++ pte_addr_t paddr; ++ paddr = ((pte_addr_t)page_to_pfn(kmap_atomic_to_page(ptep))) << PAGE_SHIFT; ++ return paddr + (pte_addr_t)((unsigned long)ptep & ~PAGE_MASK); ++} ++#else ++static inline pte_addr_t ptep_to_paddr(pte_t *ptep) ++{ ++ return (pte_addr_t)ptep; ++} ++#endif ++ ++#ifndef CONFIG_HIGHPTE ++static inline pte_t *rmap_ptep_map(pte_addr_t pte_paddr) ++{ ++ return (pte_t *)pte_paddr; ++} ++ ++static inline void rmap_ptep_unmap(pte_t *pte) ++{ ++ return; ++} ++#endif ++ ++#endif /* _GENERIC_RMAP_H */ +--- linux/include/asm-generic/rtc.h ++++ linux/include/asm-generic/rtc.h +@@ -0,0 +1,213 @@ ++/* ++ * inclue/asm-generic/rtc.h ++ * ++ * Author: Tom Rini ++ * ++ * Based on: ++ * drivers/char/rtc.c ++ * ++ * Please read the COPYING file for all license details. ++ */ ++ ++#ifndef __ASM_RTC_H__ ++#define __ASM_RTC_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++#define RTC_PIE 0x40 /* periodic interrupt enable */ ++#define RTC_AIE 0x20 /* alarm interrupt enable */ ++#define RTC_UIE 0x10 /* update-finished interrupt enable */ ++ ++/* some dummy definitions */ ++#define RTC_BATT_BAD 0x100 /* battery bad */ ++#define RTC_SQWE 0x08 /* enable square-wave output */ ++#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ ++#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ ++#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ ++ ++/* ++ * Returns true if a clock update is in progress ++ */ ++static inline unsigned char rtc_is_updating(void) ++{ ++ unsigned char uip; ++ ++ spin_lock_irq(&rtc_lock); ++ uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); ++ spin_unlock_irq(&rtc_lock); ++ return uip; ++} ++ ++static inline unsigned int get_rtc_time(struct rtc_time *time) ++{ ++ unsigned long uip_watchdog = jiffies; ++ unsigned char ctrl; ++#ifdef CONFIG_MACH_DECSTATION ++ unsigned int real_year; ++#endif ++ ++ /* ++ * read RTC once any update in progress is done. The update ++ * can take just over 2ms. We wait 10 to 20ms. There is no need to ++ * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. ++ * If you need to know *exactly* when a second has started, enable ++ * periodic update complete interrupts, (via ioctl) and then ++ * immediately read /dev/rtc which will block until you get the IRQ. ++ * Once the read clears, read the RTC time (again via ioctl). Easy. ++ */ ++ ++ if (rtc_is_updating() != 0) ++ while (jiffies - uip_watchdog < 2*HZ/100) { ++ barrier(); ++ cpu_relax(); ++ } ++ ++ /* ++ * Only the values that we read from the RTC are set. We leave ++ * tm_wday, tm_yday and tm_isdst untouched. Even though the ++ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated ++ * by the RTC when initially set to a non-zero value. ++ */ ++ spin_lock_irq(&rtc_lock); ++ time->tm_sec = CMOS_READ(RTC_SECONDS); ++ time->tm_min = CMOS_READ(RTC_MINUTES); ++ time->tm_hour = CMOS_READ(RTC_HOURS); ++ time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); ++ time->tm_mon = CMOS_READ(RTC_MONTH); ++ time->tm_year = CMOS_READ(RTC_YEAR); ++#ifdef CONFIG_MACH_DECSTATION ++ real_year = CMOS_READ(RTC_DEC_YEAR); ++#endif ++ ctrl = CMOS_READ(RTC_CONTROL); ++ spin_unlock_irq(&rtc_lock); ++ ++ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) ++ { ++ BCD_TO_BIN(time->tm_sec); ++ BCD_TO_BIN(time->tm_min); ++ BCD_TO_BIN(time->tm_hour); ++ BCD_TO_BIN(time->tm_mday); ++ BCD_TO_BIN(time->tm_mon); ++ BCD_TO_BIN(time->tm_year); ++ } ++ ++#ifdef CONFIG_MACH_DECSTATION ++ time->tm_year += real_year - 72; ++#endif ++ ++ /* ++ * Account for differences between how the RTC uses the values ++ * and how they are defined in a struct rtc_time; ++ */ ++ if (time->tm_year <= 69) ++ time->tm_year += 100; ++ ++ time->tm_mon--; ++ ++ return RTC_24H; ++} ++ ++/* Set the current date and time in the real time clock. */ ++static inline int set_rtc_time(struct rtc_time *time) ++{ ++ unsigned char mon, day, hrs, min, sec; ++ unsigned char save_control, save_freq_select; ++ unsigned int yrs; ++#ifdef CONFIG_MACH_DECSTATION ++ unsigned int real_yrs, leap_yr; ++#endif ++ ++ yrs = time->tm_year; ++ mon = time->tm_mon + 1; /* tm_mon starts at zero */ ++ day = time->tm_mday; ++ hrs = time->tm_hour; ++ min = time->tm_min; ++ sec = time->tm_sec; ++ ++ if (yrs > 255) /* They are unsigned */ ++ return -EINVAL; ++ ++ spin_lock_irq(&rtc_lock); ++#ifdef CONFIG_MACH_DECSTATION ++ real_yrs = yrs; ++ leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || ++ !((yrs + 1900) % 400)); ++ yrs = 72; ++ ++ /* ++ * We want to keep the year set to 73 until March ++ * for non-leap years, so that Feb, 29th is handled ++ * correctly. ++ */ ++ if (!leap_yr && mon < 3) { ++ real_yrs--; ++ yrs = 73; ++ } ++#endif ++ /* These limits and adjustments are independent of ++ * whether the chip is in binary mode or not. ++ */ ++ if (yrs > 169) { ++ spin_unlock_irq(&rtc_lock); ++ return -EINVAL; ++ } ++ ++ if (yrs >= 100) ++ yrs -= 100; ++ ++ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ++ || RTC_ALWAYS_BCD) { ++ BIN_TO_BCD(sec); ++ BIN_TO_BCD(min); ++ BIN_TO_BCD(hrs); ++ BIN_TO_BCD(day); ++ BIN_TO_BCD(mon); ++ BIN_TO_BCD(yrs); ++ } ++ ++ save_control = CMOS_READ(RTC_CONTROL); ++ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); ++ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); ++ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); ++ ++#ifdef CONFIG_MACH_DECSTATION ++ CMOS_WRITE(real_yrs, RTC_DEC_YEAR); ++#endif ++ CMOS_WRITE(yrs, RTC_YEAR); ++ CMOS_WRITE(mon, RTC_MONTH); ++ CMOS_WRITE(day, RTC_DAY_OF_MONTH); ++ CMOS_WRITE(hrs, RTC_HOURS); ++ CMOS_WRITE(min, RTC_MINUTES); ++ CMOS_WRITE(sec, RTC_SECONDS); ++ ++ CMOS_WRITE(save_control, RTC_CONTROL); ++ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); ++ ++ spin_unlock_irq(&rtc_lock); ++ ++ return 0; ++} ++ ++static inline unsigned int get_rtc_ss(void) ++{ ++ struct rtc_time h; ++ ++ get_rtc_time(&h); ++ return h.tm_sec; ++} ++ ++static inline int get_rtc_pll(struct rtc_pll_info *pll) ++{ ++ return -EINVAL; ++} ++static inline int set_rtc_pll(struct rtc_pll_info *pll) ++{ ++ return -EINVAL; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASM_RTC_H__ */ +--- linux/include/asm-generic/sections.h ++++ linux/include/asm-generic/sections.h +@@ -0,0 +1,12 @@ ++#ifndef _ASM_GENERIC_SECTIONS_H_ ++#define _ASM_GENERIC_SECTIONS_H_ ++ ++/* References to section boundaries */ ++ ++extern char _text[], _stext[], _etext[]; ++extern char _data[], _sdata[], _edata[]; ++extern char __bss_start[], __bss_stop[]; ++extern char __init_begin[], __init_end[]; ++extern char _sinittext[], _einittext[]; ++ ++#endif /* _ASM_GENERIC_SECTIONS_H_ */ +--- linux/include/asm-generic/siginfo.h ++++ linux/include/asm-generic/siginfo.h +@@ -0,0 +1,295 @@ ++#ifndef _ASM_GENERIC_SIGINFO_H ++#define _ASM_GENERIC_SIGINFO_H ++ ++#include ++#include ++#include ++ ++typedef union sigval { ++ int sival_int; ++ void __user *sival_ptr; ++} sigval_t; ++ ++/* ++ * This is the size (including padding) of the part of the ++ * struct siginfo that is before the union. ++ */ ++#ifndef __ARCH_SI_PREAMBLE_SIZE ++#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int)) ++#endif ++ ++#define SI_MAX_SIZE 128 ++#ifndef SI_PAD_SIZE ++#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int)) ++#endif ++ ++#ifndef __ARCH_SI_UID_T ++#define __ARCH_SI_UID_T uid_t ++#endif ++ ++/* ++ * The default "si_band" type is "long", as specified by POSIX. ++ * However, some architectures want to override this to "int" ++ * for historical compatibility reasons, so we allow that. ++ */ ++#ifndef __ARCH_SI_BAND_T ++#define __ARCH_SI_BAND_T long ++#endif ++ ++#ifndef HAVE_ARCH_SIGINFO_T ++ ++typedef struct siginfo { ++ int si_signo; ++ int si_errno; ++ int si_code; ++ ++ union { ++ int _pad[SI_PAD_SIZE]; ++ ++ /* kill() */ ++ struct { ++ pid_t _pid; /* sender's pid */ ++ __ARCH_SI_UID_T _uid; /* sender's uid */ ++ } _kill; ++ ++ /* POSIX.1b timers */ ++ struct { ++ timer_t _tid; /* timer id */ ++ int _overrun; /* overrun count */ ++ char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)]; ++ sigval_t _sigval; /* same as below */ ++ int _sys_private; /* not to be passed to user */ ++ } _timer; ++ ++ /* POSIX.1b signals */ ++ struct { ++ pid_t _pid; /* sender's pid */ ++ __ARCH_SI_UID_T _uid; /* sender's uid */ ++ sigval_t _sigval; ++ } _rt; ++ ++ /* SIGCHLD */ ++ struct { ++ pid_t _pid; /* which child */ ++ __ARCH_SI_UID_T _uid; /* sender's uid */ ++ int _status; /* exit code */ ++ clock_t _utime; ++ clock_t _stime; ++ } _sigchld; ++ ++ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ ++ struct { ++ void __user *_addr; /* faulting insn/memory ref. */ ++#ifdef __ARCH_SI_TRAPNO ++ int _trapno; /* TRAP # which caused the signal */ ++#endif ++ } _sigfault; ++ ++ /* SIGPOLL */ ++ struct { ++ __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ ++ int _fd; ++ } _sigpoll; ++ } _sifields; ++} siginfo_t; ++ ++#endif ++ ++/* ++ * How these fields are to be accessed. ++ */ ++#define si_pid _sifields._kill._pid ++#define si_uid _sifields._kill._uid ++#define si_tid _sifields._timer._tid ++#define si_overrun _sifields._timer._overrun ++#define si_sys_private _sifields._timer._sys_private ++#define si_status _sifields._sigchld._status ++#define si_utime _sifields._sigchld._utime ++#define si_stime _sifields._sigchld._stime ++#define si_value _sifields._rt._sigval ++#define si_int _sifields._rt._sigval.sival_int ++#define si_ptr _sifields._rt._sigval.sival_ptr ++#define si_addr _sifields._sigfault._addr ++#ifdef __ARCH_SI_TRAPNO ++#define si_trapno _sifields._sigfault._trapno ++#endif ++#define si_band _sifields._sigpoll._band ++#define si_fd _sifields._sigpoll._fd ++ ++#ifdef __KERNEL__ ++#define __SI_MASK 0xffff0000u ++#define __SI_KILL (0 << 16) ++#define __SI_TIMER (1 << 16) ++#define __SI_POLL (2 << 16) ++#define __SI_FAULT (3 << 16) ++#define __SI_CHLD (4 << 16) ++#define __SI_RT (5 << 16) ++#define __SI_MESGQ (6 << 16) ++#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) ++#else ++#define __SI_KILL 0 ++#define __SI_TIMER 0 ++#define __SI_POLL 0 ++#define __SI_FAULT 0 ++#define __SI_CHLD 0 ++#define __SI_RT 0 ++#define __SI_MESGQ 0 ++#define __SI_CODE(T,N) (N) ++#endif ++ ++/* ++ * si_code values ++ * Digital reserves positive values for kernel-generated signals. ++ */ ++#define SI_USER 0 /* sent by kill, sigsend, raise */ ++#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ ++#define SI_QUEUE -1 /* sent by sigqueue */ ++#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */ ++#define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change */ ++#define SI_ASYNCIO -4 /* sent by AIO completion */ ++#define SI_SIGIO -5 /* sent by queued SIGIO */ ++#define SI_TKILL -6 /* sent by tkill system call */ ++#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */ ++ ++#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) ++#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) ++ ++#ifndef HAVE_ARCH_SI_CODES ++/* ++ * SIGILL si_codes ++ */ ++#define ILL_ILLOPC (__SI_FAULT|1) /* illegal opcode */ ++#define ILL_ILLOPN (__SI_FAULT|2) /* illegal operand */ ++#define ILL_ILLADR (__SI_FAULT|3) /* illegal addressing mode */ ++#define ILL_ILLTRP (__SI_FAULT|4) /* illegal trap */ ++#define ILL_PRVOPC (__SI_FAULT|5) /* privileged opcode */ ++#define ILL_PRVREG (__SI_FAULT|6) /* privileged register */ ++#define ILL_COPROC (__SI_FAULT|7) /* coprocessor error */ ++#define ILL_BADSTK (__SI_FAULT|8) /* internal stack error */ ++#define NSIGILL 8 ++ ++/* ++ * SIGFPE si_codes ++ */ ++#define FPE_INTDIV (__SI_FAULT|1) /* integer divide by zero */ ++#define FPE_INTOVF (__SI_FAULT|2) /* integer overflow */ ++#define FPE_FLTDIV (__SI_FAULT|3) /* floating point divide by zero */ ++#define FPE_FLTOVF (__SI_FAULT|4) /* floating point overflow */ ++#define FPE_FLTUND (__SI_FAULT|5) /* floating point underflow */ ++#define FPE_FLTRES (__SI_FAULT|6) /* floating point inexact result */ ++#define FPE_FLTINV (__SI_FAULT|7) /* floating point invalid operation */ ++#define FPE_FLTSUB (__SI_FAULT|8) /* subscript out of range */ ++#define NSIGFPE 8 ++ ++/* ++ * SIGSEGV si_codes ++ */ ++#define SEGV_MAPERR (__SI_FAULT|1) /* address not mapped to object */ ++#define SEGV_ACCERR (__SI_FAULT|2) /* invalid permissions for mapped object */ ++#define NSIGSEGV 2 ++ ++/* ++ * SIGBUS si_codes ++ */ ++#define BUS_ADRALN (__SI_FAULT|1) /* invalid address alignment */ ++#define BUS_ADRERR (__SI_FAULT|2) /* non-existant physical address */ ++#define BUS_OBJERR (__SI_FAULT|3) /* object specific hardware error */ ++#define NSIGBUS 3 ++ ++/* ++ * SIGTRAP si_codes ++ */ ++#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ ++#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ ++#define NSIGTRAP 2 ++ ++/* ++ * SIGCHLD si_codes ++ */ ++#define CLD_EXITED (__SI_CHLD|1) /* child has exited */ ++#define CLD_KILLED (__SI_CHLD|2) /* child was killed */ ++#define CLD_DUMPED (__SI_CHLD|3) /* child terminated abnormally */ ++#define CLD_TRAPPED (__SI_CHLD|4) /* traced child has trapped */ ++#define CLD_STOPPED (__SI_CHLD|5) /* child has stopped */ ++#define CLD_CONTINUED (__SI_CHLD|6) /* stopped child has continued */ ++#define NSIGCHLD 6 ++ ++/* ++ * SIGPOLL si_codes ++ */ ++#define POLL_IN (__SI_POLL|1) /* data input available */ ++#define POLL_OUT (__SI_POLL|2) /* output buffers available */ ++#define POLL_MSG (__SI_POLL|3) /* input message available */ ++#define POLL_ERR (__SI_POLL|4) /* i/o error */ ++#define POLL_PRI (__SI_POLL|5) /* high priority input available */ ++#define POLL_HUP (__SI_POLL|6) /* device disconnected */ ++#define NSIGPOLL 6 ++ ++#endif ++ ++/* ++ * sigevent definitions ++ * ++ * It seems likely that SIGEV_THREAD will have to be handled from ++ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the ++ * thread manager then catches and does the appropriate nonsense. ++ * However, everything is written out here so as to not get lost. ++ */ ++#define SIGEV_SIGNAL 0 /* notify via signal */ ++#define SIGEV_NONE 1 /* other notification: meaningless */ ++#define SIGEV_THREAD 2 /* deliver via thread creation */ ++#define SIGEV_THREAD_ID 4 /* deliver to thread */ ++ ++#define SIGEV_MAX_SIZE 64 ++#ifndef SIGEV_PAD_SIZE ++#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) ++#endif ++ ++#ifndef HAVE_ARCH_SIGEVENT_T ++ ++typedef struct sigevent { ++ sigval_t sigev_value; ++ int sigev_signo; ++ int sigev_notify; ++ union { ++ int _pad[SIGEV_PAD_SIZE]; ++ int _tid; ++ ++ struct { ++ void (*_function)(sigval_t); ++ void *_attribute; /* really pthread_attr_t */ ++ } _sigev_thread; ++ } _sigev_un; ++} sigevent_t; ++ ++#endif ++ ++#define sigev_notify_function _sigev_un._sigev_thread._function ++#define sigev_notify_attributes _sigev_un._sigev_thread._attribute ++#define sigev_notify_thread_id _sigev_un._tid ++ ++#ifdef __KERNEL__ ++ ++struct siginfo; ++void do_schedule_next_timer(struct siginfo *info); ++ ++#ifndef HAVE_ARCH_COPY_SIGINFO ++ ++#include ++ ++static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) ++{ ++ if (from->si_code < 0) ++ memcpy(to, from, sizeof(*to)); ++ else ++ /* _sigchld is currently the largest know union member */ ++ memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld)); ++} ++ ++#endif ++ ++extern int copy_siginfo_to_user(struct siginfo __user *to, struct siginfo *from); ++ ++#endif /* __KERNEL__ */ ++ ++#endif +--- linux/include/asm-generic/statfs.h ++++ linux/include/asm-generic/statfs.h +@@ -0,0 +1,51 @@ ++#ifndef _GENERIC_STATFS_H ++#define _GENERIC_STATFS_H ++ ++#ifndef __KERNEL_STRICT_NAMES ++# include ++typedef __kernel_fsid_t fsid_t; ++#endif ++ ++struct statfs { ++ __u32 f_type; ++ __u32 f_bsize; ++ __u32 f_blocks; ++ __u32 f_bfree; ++ __u32 f_bavail; ++ __u32 f_files; ++ __u32 f_ffree; ++ __kernel_fsid_t f_fsid; ++ __u32 f_namelen; ++ __u32 f_frsize; ++ __u32 f_spare[5]; ++}; ++ ++struct statfs64 { ++ __u32 f_type; ++ __u32 f_bsize; ++ __u64 f_blocks; ++ __u64 f_bfree; ++ __u64 f_bavail; ++ __u64 f_files; ++ __u64 f_ffree; ++ __kernel_fsid_t f_fsid; ++ __u32 f_namelen; ++ __u32 f_frsize; ++ __u32 f_spare[5]; ++}; ++ ++struct compat_statfs64 { ++ __u32 f_type; ++ __u32 f_bsize; ++ __u64 f_blocks; ++ __u64 f_bfree; ++ __u64 f_bavail; ++ __u64 f_files; ++ __u64 f_ffree; ++ __kernel_fsid_t f_fsid; ++ __u32 f_namelen; ++ __u32 f_frsize; ++ __u32 f_spare[5]; ++}; ++ ++#endif +--- linux/include/asm-generic/tlb.h ++++ linux/include/asm-generic/tlb.h +@@ -0,0 +1,152 @@ ++/* asm-generic/tlb.h ++ * ++ * Generic TLB shootdown code ++ * ++ * Copyright 2001 Red Hat, Inc. ++ * Based on code from mm/memory.c Copyright Linus Torvalds and others. ++ * ++ * 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. ++ */ ++#ifndef _ASM_GENERIC__TLB_H ++#define _ASM_GENERIC__TLB_H ++ ++// #include ++#include ++#include ++#include ++ ++/* ++ * For UP we don't need to worry about TLB flush ++ * and page free order so much.. ++ */ ++#ifdef CONFIG_SMP ++ #define FREE_PTE_NR 506 ++ #define tlb_fast_mode(tlb) ((tlb)->nr == ~0U) ++#else ++ #define FREE_PTE_NR 1 ++ #define tlb_fast_mode(tlb) 1 ++#endif ++ ++/* struct mmu_gather is an opaque type used by the mm code for passing around ++ * any data needed by arch specific code for tlb_remove_page. This structure ++ * can be per-CPU or per-MM as the page table lock is held for the duration of ++ * TLB shootdown. ++ */ ++struct mmu_gather { ++ struct mm_struct *mm; ++ unsigned int nr; /* set to ~0U means fast mode */ ++ unsigned int need_flush;/* Really unmapped some ptes? */ ++ unsigned int fullmm; /* non-zero means full mm flush */ ++ unsigned long freed; ++ struct page * pages[FREE_PTE_NR]; ++}; ++ ++/* Users of the generic TLB shootdown code must declare this storage space. */ ++DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); ++ ++/* tlb_gather_mmu ++ * Return a pointer to an initialized struct mmu_gather. ++ */ ++static inline struct mmu_gather * ++tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) ++{ ++ struct mmu_gather *tlb = &per_cpu(mmu_gathers, smp_processor_id()); ++ ++ tlb->mm = mm; ++ ++ /* Use fast mode if only one CPU is online */ ++ tlb->nr = num_online_cpus() > 1 ? 0U : ~0U; ++ ++ tlb->fullmm = full_mm_flush; ++ tlb->freed = 0; ++ ++ return tlb; ++} ++ ++static inline void ++tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) ++{ ++ if (!tlb->need_flush) ++ return; ++ tlb->need_flush = 0; ++ tlb_flush(tlb); ++ if (!tlb_fast_mode(tlb)) { ++ free_pages_and_swap_cache(tlb->pages, tlb->nr); ++ tlb->nr = 0; ++ } ++} ++ ++/* tlb_finish_mmu ++ * Called at the end of the shootdown operation to free up any resources ++ * that were required. The page table lock is still held at this point. ++ */ ++static inline void ++tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) ++{ ++ int freed = tlb->freed; ++ struct mm_struct *mm = tlb->mm; ++ int rss = mm->rss; ++ ++ if (rss < freed) ++ freed = rss; ++ mm->rss = rss - freed; ++ tlb_flush_mmu(tlb, start, end); ++ ++ /* keep the page table cache within bounds */ ++ check_pgt_cache(); ++} ++ ++static inline unsigned int ++tlb_is_full_mm(struct mmu_gather *tlb) ++{ ++ return tlb->fullmm; ++} ++ ++/* tlb_remove_page ++ * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while ++ * handling the additional races in SMP caused by other CPUs caching valid ++ * mappings in their TLBs. ++ */ ++static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) ++{ ++ tlb->need_flush = 1; ++ if (tlb_fast_mode(tlb)) { ++ free_page_and_swap_cache(page); ++ return; ++ } ++ tlb->pages[tlb->nr++] = page; ++ if (tlb->nr >= FREE_PTE_NR) ++ tlb_flush_mmu(tlb, 0, 0); ++} ++ ++/** ++ * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation. ++ * ++ * Record the fact that pte's were really umapped in ->need_flush, so we can ++ * later optimise away the tlb invalidate. This helps when userspace is ++ * unmapping already-unmapped pages, which happens quite a lot. ++ */ ++#define tlb_remove_tlb_entry(tlb, ptep, address) \ ++ do { \ ++ tlb->need_flush = 1; \ ++ __tlb_remove_tlb_entry(tlb, ptep, address); \ ++ } while (0) ++ ++#define pte_free_tlb(tlb, ptep) \ ++ do { \ ++ tlb->need_flush = 1; \ ++ __pte_free_tlb(tlb, ptep); \ ++ } while (0) ++ ++#define pmd_free_tlb(tlb, pmdp) \ ++ do { \ ++ tlb->need_flush = 1; \ ++ __pmd_free_tlb(tlb, pmdp); \ ++ } while (0) ++ ++#define tlb_migrate_finish(mm) do {} while (0) ++ ++#endif /* _ASM_GENERIC__TLB_H */ +--- linux/include/asm-generic/topology.h ++++ linux/include/asm-generic/topology.h +@@ -0,0 +1,53 @@ ++/* ++ * linux/include/asm-generic/topology.h ++ * ++ * Written by: Matthew Dobson, IBM Corporation ++ * ++ * Copyright (C) 2002, IBM Corp. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Send feedback to ++ */ ++#ifndef _ASM_GENERIC_TOPOLOGY_H ++#define _ASM_GENERIC_TOPOLOGY_H ++ ++/* Other architectures wishing to use this simple topology API should fill ++ in the below functions as appropriate in their own file. */ ++#ifndef cpu_to_node ++#define cpu_to_node(cpu) (0) ++#endif ++#ifndef parent_node ++#define parent_node(node) (0) ++#endif ++#ifndef node_to_cpumask ++#define node_to_cpumask(node) (cpu_online_map) ++#endif ++#ifndef node_to_first_cpu ++#define node_to_first_cpu(node) (0) ++#endif ++#ifndef pcibus_to_cpumask ++#define pcibus_to_cpumask(bus) (cpu_online_map) ++#endif ++ ++/* Cross-node load balancing interval. */ ++#ifndef NODE_BALANCE_RATE ++#define NODE_BALANCE_RATE 10 ++#endif ++ ++#endif /* _ASM_GENERIC_TOPOLOGY_H */ +--- linux/include/asm-generic/uaccess.h ++++ linux/include/asm-generic/uaccess.h +@@ -0,0 +1,26 @@ ++#ifndef _ASM_GENERIC_UACCESS_H_ ++#define _ASM_GENERIC_UACCESS_H_ ++ ++/* ++ * This macro should be used instead of __get_user() when accessing ++ * values at locations that are not known to be aligned. ++ */ ++#define __get_user_unaligned(x, ptr) \ ++({ \ ++ __typeof__ (*(ptr)) __x; \ ++ __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0; \ ++ (x) = __x; \ ++}) ++ ++ ++/* ++ * This macro should be used instead of __put_user() when accessing ++ * values at locations that are not known to be aligned. ++ */ ++#define __put_user_unaligned(x, ptr) \ ++({ \ ++ __typeof__ (*(ptr)) __x = (x); \ ++ __copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0; \ ++}) ++ ++#endif /* _ASM_GENERIC_UACCESS_H */ +--- linux/include/asm-generic/unaligned.h ++++ linux/include/asm-generic/unaligned.h +@@ -0,0 +1,20 @@ ++#ifndef _ASM_GENERIC_UNALIGNED_H_ ++#define _ASM_GENERIC_UNALIGNED_H_ ++ ++/* ++ * For the benefit of those who are trying to port Linux to another ++ * architecture, here are some C-language equivalents. ++ */ ++ ++#include ++ ++ ++#define get_unaligned(ptr) \ ++ ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; }) ++ ++#define put_unaligned(val, ptr) \ ++ ({ __typeof__(*(ptr)) __tmp = (val); \ ++ memcpy((ptr), &__tmp, sizeof(*(ptr))); \ ++ (void)0; }) ++ ++#endif /* _ASM_GENERIC_UNALIGNED_H */ +--- linux/include/asm-generic/vmlinux.lds.h ++++ linux/include/asm-generic/vmlinux.lds.h +@@ -0,0 +1,84 @@ ++#ifndef LOAD_OFFSET ++#define LOAD_OFFSET 0 ++#endif ++ ++#ifndef VMLINUX_SYMBOL ++#define VMLINUX_SYMBOL(_sym_) _sym_ ++#endif ++ ++#define RODATA \ ++ .rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \ ++ *(.rodata) *(.rodata.*) \ ++ *(__vermagic) /* Kernel version magic */ \ ++ } \ ++ \ ++ .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ ++ *(.rodata1) \ ++ } \ ++ \ ++ /* PCI quirks */ \ ++ .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ ++ *(.pci_fixup_header) \ ++ VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ ++ VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \ ++ *(.pci_fixup_final) \ ++ VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: Normal symbols */ \ ++ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___ksymtab) = .; \ ++ *(__ksymtab) \ ++ VMLINUX_SYMBOL(__stop___ksymtab) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: GPL-only symbols */ \ ++ __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ ++ *(__ksymtab_gpl) \ ++ VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: Normal symbols */ \ ++ __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___kcrctab) = .; \ ++ *(__kcrctab) \ ++ VMLINUX_SYMBOL(__stop___kcrctab) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: GPL-only symbols */ \ ++ __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ ++ *(__kcrctab_gpl) \ ++ VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ ++ } \ ++ \ ++ /* Kernel symbol table: strings */ \ ++ __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ ++ *(__ksymtab_strings) \ ++ } \ ++ \ ++ /* Built-in module parameters. */ \ ++ __param : AT(ADDR(__param) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start___param) = .; \ ++ *(__param) \ ++ VMLINUX_SYMBOL(__stop___param) = .; \ ++ } ++ ++#define SECURITY_INIT \ ++ .security_initcall.init : { \ ++ VMLINUX_SYMBOL(__security_initcall_start) = .; \ ++ *(.security_initcall.init) \ ++ VMLINUX_SYMBOL(__security_initcall_end) = .; \ ++ } ++ ++#define SCHED_TEXT \ ++ VMLINUX_SYMBOL(__sched_text_start) = .; \ ++ *(.sched.text) \ ++ VMLINUX_SYMBOL(__sched_text_end) = .; ++ ++#define LOCK_TEXT \ ++ VMLINUX_SYMBOL(__lock_text_start) = .; \ ++ *(.spinlock.text) \ ++ VMLINUX_SYMBOL(__lock_text_end) = .; +--- linux/include/asm-generic/xor.h ++++ linux/include/asm-generic/xor.h +@@ -0,0 +1,718 @@ ++/* ++ * include/asm-generic/xor.h ++ * ++ * Generic optimized RAID-5 checksumming functions. ++ * ++ * 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, or (at your option) ++ * any later version. ++ * ++ * You should have received a copy of the GNU General Public License ++ * (for example /usr/src/linux/COPYING); if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++ ++static void ++xor_8regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ p1[0] ^= p2[0]; ++ p1[1] ^= p2[1]; ++ p1[2] ^= p2[2]; ++ p1[3] ^= p2[3]; ++ p1[4] ^= p2[4]; ++ p1[5] ^= p2[5]; ++ p1[6] ^= p2[6]; ++ p1[7] ^= p2[7]; ++ p1 += 8; ++ p2 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_8regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ p1[0] ^= p2[0] ^ p3[0]; ++ p1[1] ^= p2[1] ^ p3[1]; ++ p1[2] ^= p2[2] ^ p3[2]; ++ p1[3] ^= p2[3] ^ p3[3]; ++ p1[4] ^= p2[4] ^ p3[4]; ++ p1[5] ^= p2[5] ^ p3[5]; ++ p1[6] ^= p2[6] ^ p3[6]; ++ p1[7] ^= p2[7] ^ p3[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_8regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ p1[0] ^= p2[0] ^ p3[0] ^ p4[0]; ++ p1[1] ^= p2[1] ^ p3[1] ^ p4[1]; ++ p1[2] ^= p2[2] ^ p3[2] ^ p4[2]; ++ p1[3] ^= p2[3] ^ p3[3] ^ p4[3]; ++ p1[4] ^= p2[4] ^ p3[4] ^ p4[4]; ++ p1[5] ^= p2[5] ^ p3[5] ^ p4[5]; ++ p1[6] ^= p2[6] ^ p3[6] ^ p4[6]; ++ p1[7] ^= p2[7] ^ p3[7] ^ p4[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_8regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0]; ++ p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1]; ++ p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2]; ++ p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3]; ++ p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4]; ++ p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5]; ++ p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6]; ++ p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ p5 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_32regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_32regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_32regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ d0 ^= p4[0]; ++ d1 ^= p4[1]; ++ d2 ^= p4[2]; ++ d3 ^= p4[3]; ++ d4 ^= p4[4]; ++ d5 ^= p4[5]; ++ d6 ^= p4[6]; ++ d7 ^= p4[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_32regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ long lines = bytes / (sizeof (long)) / 8; ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ d0 ^= p4[0]; ++ d1 ^= p4[1]; ++ d2 ^= p4[2]; ++ d3 ^= p4[3]; ++ d4 ^= p4[4]; ++ d5 ^= p4[5]; ++ d6 ^= p4[6]; ++ d7 ^= p4[7]; ++ d0 ^= p5[0]; ++ d1 ^= p5[1]; ++ d2 ^= p5[2]; ++ d3 ^= p5[3]; ++ d4 ^= p5[4]; ++ d5 ^= p5[5]; ++ d6 ^= p5[6]; ++ d7 ^= p5[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ p5 += 8; ++ } while (--lines > 0); ++} ++ ++static void ++xor_8regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ prefetchw(p1); ++ prefetch(p2); ++ ++ do { ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ once_more: ++ p1[0] ^= p2[0]; ++ p1[1] ^= p2[1]; ++ p1[2] ^= p2[2]; ++ p1[3] ^= p2[3]; ++ p1[4] ^= p2[4]; ++ p1[5] ^= p2[5]; ++ p1[6] ^= p2[6]; ++ p1[7] ^= p2[7]; ++ p1 += 8; ++ p2 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_8regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ ++ do { ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ once_more: ++ p1[0] ^= p2[0] ^ p3[0]; ++ p1[1] ^= p2[1] ^ p3[1]; ++ p1[2] ^= p2[2] ^ p3[2]; ++ p1[3] ^= p2[3] ^ p3[3]; ++ p1[4] ^= p2[4] ^ p3[4]; ++ p1[5] ^= p2[5] ^ p3[5]; ++ p1[6] ^= p2[6] ^ p3[6]; ++ p1[7] ^= p2[7] ^ p3[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_8regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ prefetch(p4); ++ ++ do { ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ prefetch(p4+8); ++ once_more: ++ p1[0] ^= p2[0] ^ p3[0] ^ p4[0]; ++ p1[1] ^= p2[1] ^ p3[1] ^ p4[1]; ++ p1[2] ^= p2[2] ^ p3[2] ^ p4[2]; ++ p1[3] ^= p2[3] ^ p3[3] ^ p4[3]; ++ p1[4] ^= p2[4] ^ p3[4] ^ p4[4]; ++ p1[5] ^= p2[5] ^ p3[5] ^ p4[5]; ++ p1[6] ^= p2[6] ^ p3[6] ^ p4[6]; ++ p1[7] ^= p2[7] ^ p3[7] ^ p4[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_8regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ prefetch(p4); ++ prefetch(p5); ++ ++ do { ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ prefetch(p4+8); ++ prefetch(p5+8); ++ once_more: ++ p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0]; ++ p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1]; ++ p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2]; ++ p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3]; ++ p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4]; ++ p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5]; ++ p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6]; ++ p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7]; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ p5 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_32regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ once_more: ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_32regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ once_more: ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_32regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ prefetch(p4); ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ prefetch(p4+8); ++ once_more: ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ d0 ^= p4[0]; ++ d1 ^= p4[1]; ++ d2 ^= p4[2]; ++ d3 ^= p4[3]; ++ d4 ^= p4[4]; ++ d5 ^= p4[5]; ++ d6 ^= p4[6]; ++ d7 ^= p4[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static void ++xor_32regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ long lines = bytes / (sizeof (long)) / 8 - 1; ++ ++ prefetchw(p1); ++ prefetch(p2); ++ prefetch(p3); ++ prefetch(p4); ++ prefetch(p5); ++ ++ do { ++ register long d0, d1, d2, d3, d4, d5, d6, d7; ++ ++ prefetchw(p1+8); ++ prefetch(p2+8); ++ prefetch(p3+8); ++ prefetch(p4+8); ++ prefetch(p5+8); ++ once_more: ++ d0 = p1[0]; /* Pull the stuff into registers */ ++ d1 = p1[1]; /* ... in bursts, if possible. */ ++ d2 = p1[2]; ++ d3 = p1[3]; ++ d4 = p1[4]; ++ d5 = p1[5]; ++ d6 = p1[6]; ++ d7 = p1[7]; ++ d0 ^= p2[0]; ++ d1 ^= p2[1]; ++ d2 ^= p2[2]; ++ d3 ^= p2[3]; ++ d4 ^= p2[4]; ++ d5 ^= p2[5]; ++ d6 ^= p2[6]; ++ d7 ^= p2[7]; ++ d0 ^= p3[0]; ++ d1 ^= p3[1]; ++ d2 ^= p3[2]; ++ d3 ^= p3[3]; ++ d4 ^= p3[4]; ++ d5 ^= p3[5]; ++ d6 ^= p3[6]; ++ d7 ^= p3[7]; ++ d0 ^= p4[0]; ++ d1 ^= p4[1]; ++ d2 ^= p4[2]; ++ d3 ^= p4[3]; ++ d4 ^= p4[4]; ++ d5 ^= p4[5]; ++ d6 ^= p4[6]; ++ d7 ^= p4[7]; ++ d0 ^= p5[0]; ++ d1 ^= p5[1]; ++ d2 ^= p5[2]; ++ d3 ^= p5[3]; ++ d4 ^= p5[4]; ++ d5 ^= p5[5]; ++ d6 ^= p5[6]; ++ d7 ^= p5[7]; ++ p1[0] = d0; /* Store the result (in bursts) */ ++ p1[1] = d1; ++ p1[2] = d2; ++ p1[3] = d3; ++ p1[4] = d4; ++ p1[5] = d5; ++ p1[6] = d6; ++ p1[7] = d7; ++ p1 += 8; ++ p2 += 8; ++ p3 += 8; ++ p4 += 8; ++ p5 += 8; ++ } while (--lines > 0); ++ if (lines == 0) ++ goto once_more; ++} ++ ++static struct xor_block_template xor_block_8regs = { ++ .name = "8regs", ++ .do_2 = xor_8regs_2, ++ .do_3 = xor_8regs_3, ++ .do_4 = xor_8regs_4, ++ .do_5 = xor_8regs_5, ++}; ++ ++static struct xor_block_template xor_block_32regs = { ++ .name = "32regs", ++ .do_2 = xor_32regs_2, ++ .do_3 = xor_32regs_3, ++ .do_4 = xor_32regs_4, ++ .do_5 = xor_32regs_5, ++}; ++ ++static struct xor_block_template xor_block_8regs_p = { ++ .name = "8regs_prefetch", ++ .do_2 = xor_8regs_p_2, ++ .do_3 = xor_8regs_p_3, ++ .do_4 = xor_8regs_p_4, ++ .do_5 = xor_8regs_p_5, ++}; ++ ++static struct xor_block_template xor_block_32regs_p = { ++ .name = "32regs_prefetch", ++ .do_2 = xor_32regs_p_2, ++ .do_3 = xor_32regs_p_3, ++ .do_4 = xor_32regs_p_4, ++ .do_5 = xor_32regs_p_5, ++}; ++ ++#define XOR_TRY_TEMPLATES \ ++ do { \ ++ xor_speed(&xor_block_8regs); \ ++ xor_speed(&xor_block_8regs_p); \ ++ xor_speed(&xor_block_32regs); \ ++ xor_speed(&xor_block_32regs_p); \ ++ } while (0) +--- linux/include/asm-nios2nommu/ChangeLog ++++ linux/include/asm-nios2nommu/ChangeLog +@@ -0,0 +1,14 @@ ++2004-06-29 Ken Hill ++ ++ * bitops.h (find_next_zero_bit): Fix problem with with masking for found_first ++ handling. The masking of the upper bits for size < 32 bits would set all ++ the bits to 1. Removing any zero's there may have been. ++ ++2004-06-02 Ken Hill ++ ++ * processor.h (TASK_SIZE): Change na_sdram_end to nasys_program_mem_end to remove ++ dependancy on quartus memory component name. ++ ++ * page.h (PAGE_OFFSET): Change na_sdram to nasys_program_mem to remove ++ dependancy on quartus memory component name. ++ +--- linux/include/asm-nios2nommu/a.out.h ++++ linux/include/asm-nios2nommu/a.out.h +@@ -0,0 +1,85 @@ ++/* $Id: a.out.h,v 1.4 2004/03/30 19:35:04 ken-h Exp $ */ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2NOMMU_A_OUT_H__ ++#define __NIOS2NOMMU_A_OUT_H__ ++ ++#define SPARC_PGSIZE 0x1000 /* Thanks to the sun4 architecture... */ ++#define SEGMENT_SIZE SPARC_PGSIZE /* whee... */ ++ ++struct exec { ++ unsigned char a_dynamic:1; /* A __DYNAMIC is in this image */ ++ unsigned char a_toolversion:7; ++ unsigned char a_machtype; ++ unsigned short a_info; ++ unsigned long a_text; /* length of text, in bytes */ ++ unsigned long a_data; /* length of data, in bytes */ ++ unsigned long a_bss; /* length of bss, in bytes */ ++ unsigned long a_syms; /* length of symbol table, in bytes */ ++ unsigned long a_entry; /* where program begins */ ++ unsigned long a_trsize; ++ unsigned long a_drsize; ++}; ++ ++#define INIT_EXEC { \ ++ .a_dynamic = 0, \ ++ .a_toolversion = 0, \ ++ .a_machtype = 0, \ ++ .a_info = 0, \ ++ .a_text = 0, \ ++ .a_data = 0, \ ++ .a_bss = 0, \ ++ .a_syms = 0, \ ++ .a_entry = 0, \ ++ .a_trsize = 0, \ ++ .a_drsize = 0, \ ++} ++ ++/* Where in the file does the text information begin? */ ++#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? 0 : sizeof (struct exec)) ++ ++/* Where do the Symbols start? */ ++#define N_SYMOFF(x) (N_TXTOFF(x) + (x).a_text + \ ++ (x).a_data + (x).a_trsize + \ ++ (x).a_drsize) ++ ++/* Where does text segment go in memory after being loaded? */ ++#define N_TXTADDR(x) (((N_MAGIC(x) == ZMAGIC) && \ ++ ((x).a_entry < SPARC_PGSIZE)) ? \ ++ 0 : SPARC_PGSIZE) ++ ++/* And same for the data segment.. */ ++#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC ? \ ++ (N_TXTADDR(x) + (x).a_text) \ ++ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) ++ ++#define N_TRSIZE(a) ((a).a_trsize) ++#define N_DRSIZE(a) ((a).a_drsize) ++#define N_SYMSIZE(a) ((a).a_syms) ++ ++#ifdef __KERNEL__ ++ ++#define STACK_TOP TASK_SIZE ++ ++#endif ++ ++#endif /* __NIOS2NOMMU_A_OUT_H__ */ +--- linux/include/asm-nios2nommu/asm-macros.h ++++ linux/include/asm-nios2nommu/asm-macros.h +@@ -0,0 +1,331 @@ ++/* ++ * Macro used to simplify coding multi-line assembler. ++ * Some of the bit test macro can simplify down to one line ++ * depending on the mask value. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++/* ++ * ANDs reg2 with mask and places the result in reg1. ++ * ++ * You cannnot use the same register for reg1 & reg2. ++ */ ++ ++.macro ANDI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ movhi \reg1,%hi(\mask) ++ movui \reg1,%lo(\mask) ++ and \reg1,\reg1,\reg2 ++ .else ++ andi \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ andhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * ORs reg2 with mask and places the result in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro ORI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ orhi \reg1,\reg2,%hi(\mask) ++ ori \reg1,\reg2,%lo(\mask) ++ .else ++ ori \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ orhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * XORs reg2 with mask and places the result in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro XORI32 reg1,reg2,mask ++ .if \mask & 0xffff ++ .if \mask & 0xffff0000 ++ xorhi \reg1,\reg2,%hi(\mask) ++ xori \reg1,\reg1,%lo(\mask) ++ .else ++ xori \reg1,\reg2,%lo(\mask) ++ .endif ++ .else ++ xorhi \reg1,\reg2,%hi(\mask) ++ .endif ++.endm ++ ++/* ++ * This is a support macro for BTBZ & BTBNZ. It checks ++ * the bit to make sure it is valid 32 value. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BT reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and branches to label if the ++ * bit is zero. The result of the bit test is stored in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTBZ reg1,reg2,bit,label ++ BT \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and branches to label if the ++ * bit is non-zero. The result of the bit test is stored in reg1. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTBNZ reg1,reg2,bit,label ++ BT \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTC reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ xori \reg2,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ xorhi \reg2,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTS reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ ori \reg2,\reg2,(1 << \bit) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ orhi \reg2,\reg2,(1 << (\bit - 16)) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTR reg1,reg2,bit ++.if \bit > 31 ++ .err ++.else ++ .if \bit < 16 ++ andi \reg1,\reg2,(1 << \bit) ++ andi \reg2,\reg2,%lo(~(1 << \bit)) ++ .else ++ andhi \reg1,\reg2,(1 << (\bit - 16)) ++ andhi \reg2,\reg2,%lo(~(1 << (\bit - 16))) ++ .endif ++.endif ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTCBZ reg1,reg2,bit,label ++ BTC \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then compliments the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTCBNZ reg1,reg2,bit,label ++ BTC \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTSBZ reg1,reg2,bit,label ++ BTS \reg1,\reg2,\bit ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then sets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTSBNZ reg1,reg2,bit,label ++ BTS \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTRBZ reg1,reg2,bit,label ++ BTR \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bit in reg2 and then resets the bit in reg2. ++ * The result of the bit test is stored in reg1. If the ++ * original bit was non-zero it branches to label. ++ * ++ * It is NOT safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro BTRBNZ reg1,reg2,bit,label ++ BTR \reg1,\reg2,\bit ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bits in mask against reg2 stores the result in reg1. ++ * If the all the bits in the mask are zero it branches to label. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro TSTBZ reg1,reg2,mask,label ++ ANDI32 \reg1,\reg2,\mask ++ beq \reg1,r0,\label ++.endm ++ ++/* ++ * Tests the bits in mask against reg2 stores the result in reg1. ++ * If the any of the bits in the mask are 1 it branches to label. ++ * ++ * It is safe to use the same register for reg1 & reg2. ++ */ ++ ++.macro TSTBNZ reg1,reg2,mask,label ++ ANDI32 \reg1,\reg2,\mask ++ bne \reg1,r0,\label ++.endm ++ ++/* ++ * Pushes reg onto the stack. ++ */ ++ ++.macro PUSH reg ++ addi sp,sp,-4 ++ stw \reg,0(sp) ++.endm ++ ++/* ++ * Pops the top of the stack into reg. ++ */ ++ ++.macro POP reg ++ ldw \reg,0(sp) ++ addi sp,sp,4 ++.endm ++ ++/* ++ * Clears reg ++ */ ++ ++.macro CLR reg ++ mov \reg,r0 ++.endm ++ ++/* ++ * The preprocessor macro does not work for ++ * the nios2 compiler. Undefine ENTRY and define ++ * a real assembler macro. ++ */ ++#undef ENTRY ++#define ENTRY(name) ASM_ENTRY name ++ ++.macro ASM_ENTRY name ++.globl \name ++__ALIGN ++ \name: ++.endm +--- linux/include/asm-nios2nommu/atomic.h ++++ linux/include/asm-nios2nommu/atomic.h +@@ -0,0 +1,190 @@ ++//vic - add 'atomic_add/sub_return', 'atomic_add_negative' ++//vic from v850 architecture ++ ++/* atomic.h: ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 2001 Vic Phillips (vic@microtronix.com) ++ * ++ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ARCH_NIOS2NOMMU_ATOMIC__ ++#define __ARCH_NIOS2NOMMU_ATOMIC__ ++ ++#include ++ ++typedef struct { int counter; } atomic_t; ++#define ATOMIC_INIT(i) { (i) } ++ ++#define atomic_read(v) ((v)->counter) ++#define atomic_set(v, i) (((v)->counter) = i) ++ ++ ++extern __inline__ void atomic_add(int i, atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter += i; ++ local_irq_restore(flags); ++} ++ ++extern __inline__ int atomic_add_negative(int i, atomic_t *v) ++{ ++ unsigned long flags; ++ int result; ++ ++ local_irq_save(flags); ++ v->counter += i; ++ result = (v->counter < 0); ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ void atomic_sub(int i, atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ local_irq_restore(flags); ++} ++ ++extern __inline__ int atomic_sub_and_test(int i, atomic_t *v) ++{ ++ int result; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ result = (v->counter == 0); ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ void atomic_inc(atomic_t *v) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter += 1; ++ local_irq_restore(flags); ++} ++ ++extern __inline__ int atomic_inc_and_test(atomic_t *v) ++{ ++ unsigned long flags; ++ int result; ++ ++ local_irq_save(flags); ++ v->counter += 1; ++ result = (v->counter == 0); ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ void atomic_dec(atomic_t *v) ++{ ++ int i = 1; /* the compiler optimizes better this way */ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ local_irq_restore(flags); ++} ++ ++extern __inline__ int atomic_dec_and_test(atomic_t *v) ++{ ++ int result; ++ int i = 1; /* the compiler optimizes better this way */ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ result = (v->counter == 0); ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ int atomic_inc_return(atomic_t *v) ++{ ++ int result; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ result = ++v->counter; ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ int atomic_dec_return(atomic_t *v) ++{ ++ int result; ++ int i = 1; /* the compiler optimizes better this way */ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ v->counter -= i; ++ result = v->counter; ++ local_irq_restore(flags); ++ return result; ++} ++ ++extern __inline__ int atomic_add_return (int i, volatile atomic_t *v) ++{ ++ int res; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ res = v->counter + i; ++ v->counter = res; ++ local_irq_restore(flags); ++ ++ return res; ++} ++ ++static __inline__ int atomic_sub_return (int i, volatile atomic_t *v) ++{ ++ int res; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ res = v->counter - i; ++ v->counter = res; ++ local_irq_restore(flags); ++ ++ return res; ++} ++ ++#define atomic_dec_return(v) atomic_sub_return(1,(v)) ++#define atomic_inc_return(v) atomic_add_return(1,(v)) ++ ++/* Atomic operations are already serializing */ ++#define smp_mb__before_atomic_dec() barrier() ++#define smp_mb__after_atomic_dec() barrier() ++#define smp_mb__before_atomic_inc() barrier() ++#define smp_mb__after_atomic_inc() barrier() ++ ++ ++#endif /* !(__ARCH_NIOS2NOMMU_ATOMIC__) */ ++ ++ +--- linux/include/asm-nios2nommu/bitops.h ++++ linux/include/asm-nios2nommu/bitops.h +@@ -0,0 +1,472 @@ ++#ifndef _ASM_NIOS_BITOPS_H_ ++#define _ASM_NIOS_BITOPS_H_ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/bitops.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include /* swab32 */ ++#include ++#endif ++ ++/* ++ * Adapted to NIOS from generic bitops.h: ++ * ++ * For the benefit of those who are trying to port Linux to another ++ * architecture, here are some C-language equivalents. You should ++ * recode these in the native assembly language, if at all possible. ++ * To guarantee atomicity, these routines call cli() and sti() to ++ * disable interrupts while they operate. (You have to provide inline ++ * routines to cli() and sti().) ++ * ++ * Also note, these routines assume that you have 32 bit integers. ++ * You will have to change this if you are trying to port Linux to the ++ * Alpha architecture or to a Cray. :-) ++ * ++ * C language equivalents written by Theodore Ts'o, 9/26/92 ++ */ ++ ++/* ++ * Generic ffs(). ++ */ ++static inline int ffs(int x) ++{ ++ int r = 1; ++ ++ if (!x) ++ return 0; ++ if (!(x & 0xffff)) { ++ x >>= 16; ++ r += 16; ++ } ++ if (!(x & 0xff)) { ++ x >>= 8; ++ r += 8; ++ } ++ if (!(x & 0xf)) { ++ x >>= 4; ++ r += 4; ++ } ++ if (!(x & 3)) { ++ x >>= 2; ++ r += 2; ++ } ++ if (!(x & 1)) { ++ x >>= 1; ++ r += 1; ++ } ++ return r; ++} ++ ++/* ++ * Generic __ffs(). ++ */ ++static inline int __ffs(int x) ++{ ++ int r = 0; ++ ++ if (!x) ++ return 0; ++ if (!(x & 0xffff)) { ++ x >>= 16; ++ r += 16; ++ } ++ if (!(x & 0xff)) { ++ x >>= 8; ++ r += 8; ++ } ++ if (!(x & 0xf)) { ++ x >>= 4; ++ r += 4; ++ } ++ if (!(x & 3)) { ++ x >>= 2; ++ r += 2; ++ } ++ if (!(x & 1)) { ++ x >>= 1; ++ r += 1; ++ } ++ return r; ++} ++ ++/* ++ * fls: find last bit set. ++ */ ++#define fls(x) generic_fls(x) ++ ++ ++/* ++ * Every architecture must define this function. It's the fastest ++ * way of searching a 140-bit bitmap where the first 100 bits are ++ * unlikely to be set. It's guaranteed that at least one of the 140 ++ * bits is cleared. ++ */ ++static inline int sched_find_first_bit(unsigned long *b) ++{ ++ if (unlikely(b[0])) ++ return __ffs(b[0]); ++ if (unlikely(b[1])) ++ return __ffs(b[1]) + 32; ++ if (unlikely(b[2])) ++ return __ffs(b[2]) + 64; ++ if (b[3]) ++ return __ffs(b[3]) + 96; ++ return __ffs(b[4]) + 128; ++} ++ ++/* ++ * ffz = Find First Zero in word. Undefined if no zero exists, ++ * so code should check against ~0UL first.. ++ */ ++static __inline__ unsigned long ffz(unsigned long word) ++{ ++ unsigned long result = 0; ++ ++ while(word & 1) { ++ result++; ++ word >>= 1; ++ } ++ return result; ++} ++ ++ ++static __inline__ void set_bit(int nr, volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ *a |= mask; ++ local_irq_restore(flags); ++} ++ ++static __inline__ void __set_bit(int nr, volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ *a |= mask; ++} ++ ++/* ++ * clear_bit() doesn't provide any barrier for the compiler. ++ */ ++#define smp_mb__before_clear_bit() barrier() ++#define smp_mb__after_clear_bit() barrier() ++ ++static __inline__ void clear_bit(int nr, volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ *a &= ~mask; ++ local_irq_restore(flags); ++} ++ ++static __inline__ void __clear_bit(int nr, volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ *a &= ~mask; ++} ++ ++static __inline__ void change_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, flags; ++ unsigned long *ADDR = (unsigned long *) addr; ++ ++ ADDR += nr >> 5; ++ mask = 1 << (nr & 31); ++ local_irq_save(flags); ++ *ADDR ^= mask; ++ local_irq_restore(flags); ++} ++ ++static __inline__ void __change_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask; ++ unsigned long *ADDR = (unsigned long *) addr; ++ ++ ADDR += nr >> 5; ++ mask = 1 << (nr & 31); ++ *ADDR ^= mask; ++} ++ ++static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ retval = (mask & *a) != 0; ++ *a |= mask; ++ local_irq_restore(flags); ++ ++ return retval; ++} ++ ++static __inline__ int __test_and_set_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ retval = (mask & *a) != 0; ++ *a |= mask; ++ return retval; ++} ++ ++static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ retval = (mask & *a) != 0; ++ *a &= ~mask; ++ local_irq_restore(flags); ++ ++ return retval; ++} ++ ++static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ retval = (mask & *a) != 0; ++ *a &= ~mask; ++ return retval; ++} ++ ++static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ unsigned long flags; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ local_irq_save(flags); ++ retval = (mask & *a) != 0; ++ *a ^= mask; ++ local_irq_restore(flags); ++ ++ return retval; ++} ++ ++static __inline__ int __test_and_change_bit(int nr, volatile unsigned long * addr) ++{ ++ int mask, retval; ++ volatile unsigned int *a = (volatile unsigned int *) addr; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ retval = (mask & *a) != 0; ++ *a ^= mask; ++ return retval; ++} ++ ++/* ++ * This routine doesn't need to be atomic. ++ */ ++static __inline__ int __constant_test_bit(int nr, const volatile unsigned long * addr) ++{ ++ return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; ++} ++ ++static __inline__ int __test_bit(int nr, const volatile unsigned long * addr) ++{ ++ int * a = (int *) addr; ++ int mask; ++ ++ a += nr >> 5; ++ mask = 1 << (nr & 0x1f); ++ return ((mask & *a) != 0); ++} ++ ++#define test_bit(nr,addr) \ ++(__builtin_constant_p(nr) ? \ ++ __constant_test_bit((nr),(unsigned long *)(addr)) : \ ++ __test_bit((nr),(unsigned long *)(addr))) ++ ++ ++/* find_next_zero_bit() finds the first zero bit in a bit string of length ++ * 'size' bits, starting the search at bit 'offset'. This is largely based ++ * on Linus's ALPHA routines, which are pretty portable BTW. ++ */ ++ ++extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) ++{ ++ unsigned long *p = ((unsigned long *) addr) + (offset >> 5); ++ unsigned long result = offset & ~31UL; ++ unsigned long tmp; ++ ++ if (offset >= size) ++ return size; ++ size -= result; ++ offset &= 31UL; ++ if (offset) { ++ tmp = *(p++); ++ tmp |= ~0UL >> (32-offset); ++ if (size < 32) ++ goto found_first; ++ if (~tmp) ++ goto found_middle; ++ size -= 32; ++ result += 32; ++ } ++ while (size & ~31UL) { ++ if (~(tmp = *(p++))) ++ goto found_middle; ++ result += 32; ++ size -= 32; ++ } ++ if (!size) ++ return result; ++ tmp = *p; ++ ++found_first: ++ tmp |= ~0UL << size; ++ if (tmp == ~0UL) ++ return result + size; ++found_middle: ++ return result + ffz(tmp); ++} ++ ++/* ++ * Find next one bit in a bitmap reasonably efficiently. ++ */ ++extern __inline__ unsigned long find_next_bit(const unsigned long *addr, ++ unsigned long size, unsigned long offset) ++{ ++ unsigned int *p = ((unsigned int *) addr) + (offset >> 5); ++ unsigned int result = offset & ~31UL; ++ unsigned int tmp; ++ ++ if (offset >= size) ++ return size; ++ size -= result; ++ offset &= 31UL; ++ if (offset) { ++ tmp = *p++; ++ tmp &= ~0UL << offset; ++ if (size < 32) ++ goto found_first; ++ if (tmp) ++ goto found_middle; ++ size -= 32; ++ result += 32; ++ } ++ while (size >= 32) { ++ if ((tmp = *p++) != 0) ++ goto found_middle; ++ result += 32; ++ size -= 32; ++ } ++ if (!size) ++ return result; ++ tmp = *p; ++ ++found_first: ++ tmp &= ~0UL >> (32 - size); ++ if (tmp == 0UL) /* Are any bits set? */ ++ return result + size; /* Nope. */ ++found_middle: ++ return result + __ffs(tmp); ++} ++ ++/* ++ * hweightN: returns the hamming weight (i.e. the number ++ * of bits set) of a N-bit word ++ */ ++ ++#define hweight32(x) generic_hweight32(x) ++#define hweight16(x) generic_hweight16(x) ++#define hweight8(x) generic_hweight8(x) ++ ++/* Linus sez that gcc can optimize the following correctly, we'll see if this ++ * holds on the Sparc as it does for the ALPHA. ++ */ ++ ++#define find_first_zero_bit(addr, size) \ ++ find_next_zero_bit((addr), (size), 0) ++#define find_first_bit(addr, size) \ ++ find_next_bit((addr), (size), 0) ++ ++/* Now for the ext2 filesystem bit operations and helper routines. ++ * ++ * Both NIOS and ext2 are little endian, so these are the same as above. ++ */ ++ ++#define ext2_set_bit test_and_set_bit ++#define ext2_clear_bit test_and_clear_bit ++#define ext2_test_bit test_bit ++ ++#define ext2_set_bit_atomic(lock, nr, addr) \ ++ ({ \ ++ int ret; \ ++ spin_lock(lock); \ ++ ret = ext2_set_bit((nr),(unsigned long *) (addr)); \ ++ spin_unlock(lock); \ ++ ret; \ ++ }) ++ ++#define ext2_clear_bit_atomic(lock, nr, addr) \ ++ ({ \ ++ int ret; \ ++ spin_lock(lock); \ ++ ret = ext2_clear_bit((nr),(unsigned long *) (addr)); \ ++ spin_unlock(lock); \ ++ ret; \ ++ }) ++ ++#define ext2_find_first_zero_bit find_first_zero_bit ++#define ext2_find_next_zero_bit find_next_zero_bit ++ ++#endif /* _ASM_NIOS_BITOPS_H */ +--- linux/include/asm-nios2nommu/bootinfo.h ++++ linux/include/asm-nios2nommu/bootinfo.h +@@ -0,0 +1,2 @@ ++ ++/* Nothing for nios2nommu */ +--- linux/include/asm-nios2nommu/bug.h ++++ linux/include/asm-nios2nommu/bug.h +@@ -0,0 +1,48 @@ ++#ifndef _NIOS2NOMMU_BUG_H ++#define _NIOS2NOMMU_BUG_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/bug.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define BUG() do { \ ++ printk("%s(%d): kernel BUG!\n", __FILE__, __LINE__); \ ++} while (0) ++ ++#define BUG_ON(condition) do { \ ++ if (unlikely((condition)!=0)) \ ++ BUG(); \ ++} while(0) ++ ++#define PAGE_BUG(page) do { \ ++ BUG(); \ ++} while (0) ++ ++#define WARN_ON(condition) do { \ ++ if (unlikely((condition)!=0)) { \ ++ printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ ++ dump_stack(); \ ++ } \ ++} while (0) ++ ++#endif +--- linux/include/asm-nios2nommu/bugs.h ++++ linux/include/asm-nios2nommu/bugs.h +@@ -0,0 +1,40 @@ ++#ifndef __ASM_NIOS_BUGS_H ++#define __ASM_NIOS_BUGS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/bugs.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 1994 Linus Torvalds ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This is included by init/main.c to check for architecture-dependent bugs. ++ * ++ * Needs: ++ * void check_bugs(void); ++ */ ++ ++static void check_bugs(void) ++{ ++} ++ ++#endif +--- linux/include/asm-nios2nommu/byteorder.h ++++ linux/include/asm-nios2nommu/byteorder.h +@@ -0,0 +1,38 @@ ++#ifndef __ASM_NIOS_BYTEORDER_H ++#define __ASM_NIOS_BYTEORDER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/byteorder.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) ++# define __BYTEORDER_HAS_U64__ ++# define __SWAB_64_THRU_32__ ++#endif ++ ++#include ++ ++#endif ++ +--- linux/include/asm-nios2nommu/cache.h ++++ linux/include/asm-nios2nommu/cache.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __ARCH_NIOS2NOMMU_CACHE_H ++#define __ARCH_NIOS2NOMMU_CACHE_H ++ ++#include ++ ++/* bytes per L1 cache line */ ++#define L1_CACHE_BYTES nasys_icache_line_size /* this need to be at least 1 */ ++ ++ ++#define __cacheline_aligned ++#define ____cacheline_aligned ++ ++#endif +--- linux/include/asm-nios2nommu/cachectl.h ++++ linux/include/asm-nios2nommu/cachectl.h +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_CACHECTL_H ++#define _NIOS2NOMMU_CACHECTL_H ++ ++/* Definitions for the cacheflush system call. */ ++ ++#define FLUSH_SCOPE_LINE 1 /* Flush a cache line */ ++#define FLUSH_SCOPE_PAGE 2 /* Flush a page */ ++#define FLUSH_SCOPE_ALL 3 /* Flush the whole cache -- superuser only */ ++ ++#define FLUSH_CACHE_DATA 1 /* Writeback and flush data cache */ ++#define FLUSH_CACHE_INSN 2 /* Flush instruction cache */ ++#define FLUSH_CACHE_BOTH 3 /* Flush both caches */ ++ ++#endif /* _NIOS2NOMMU_CACHECTL_H */ +--- linux/include/asm-nios2nommu/cacheflush.h ++++ linux/include/asm-nios2nommu/cacheflush.h +@@ -0,0 +1,56 @@ ++#ifndef _NIOS2NOMMU_CACHEFLUSH_H ++#define _NIOS2NOMMU_CACHEFLUSH_H ++ ++/* ++ * Ported from m68knommu. ++ * ++ * (C) Copyright 2003, Microtronix Datacom Ltd. ++ * (C) Copyright 2000-2002, Greg Ungerer ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#include ++ ++extern void cache_push (unsigned long vaddr, int len); ++extern void dcache_push (unsigned long vaddr, int len); ++extern void icache_push (unsigned long vaddr, int len); ++extern void cache_push_all (void); ++ ++#define flush_cache_all() __flush_cache_all() ++#define flush_cache_mm(mm) do { } while (0) ++#define flush_cache_range(vma, start, end) do { } while (0) ++#define flush_cache_page(vma, vmaddr) do { } while (0) ++#define flush_dcache_range(start,end) dcache_push(start, end - start) ++#define flush_dcache_page(page) do { } while (0) ++#define flush_icache_range(start,end) cache_push(start, end - start) ++#define flush_icache_page(vma,pg) do { } while (0) ++#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) ++ ++#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ ++ memcpy(dst, src, len) ++#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ ++ memcpy(dst, src, len) ++ ++ ++extern inline void __flush_cache_all(void) ++{ ++ cache_push_all(); ++} ++ ++#endif /* _NIOS2NOMMU_CACHEFLUSH_H */ +--- linux/include/asm-nios2nommu/checksum.h ++++ linux/include/asm-nios2nommu/checksum.h +@@ -0,0 +1,320 @@ ++#ifndef __NIOS2_CHECKSUM_H ++#define __NIOS2_CHECKSUM_H ++ ++/* checksum.h: IP/UDP/TCP checksum routines on the NIOS. ++ * ++ * Copyright(C) 1995 Linus Torvalds ++ * Copyright(C) 1995 Miguel de Icaza ++ * Copyright(C) 1996 David S. Miller ++ * Copyright(C) 2001 Ken Hill ++ * Copyright(C) 2004 Microtronix Datacom Ltd. ++ * ++ * derived from: ++ * Alpha checksum c-code ++ * ix86 inline assembly ++ * Spar nommu ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++/* ++ * computes the checksum of the TCP/UDP pseudo-header ++ * returns a 16-bit checksum, already complemented ++ */ ++ ++extern inline unsigned short csum_tcpudp_magic(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++" add %0, %3, %0\n" ++" bgeu %0, %3, 1f\n" ++" addi %0, %0, 1\n" ++"1: add %0, %4, %0\n" ++" bgeu %0, %4, 1f\n" ++" addi %0, %0, 1\n" ++"1: add %0, %5, %0\n" ++" bgeu %0, %5, 1f\n" ++" addi %0, %0, 1\n" ++"1:\n" ++/* ++ We need the carry from the addition of 16-bit ++ significant addition, so we zap out the low bits ++ in one half, zap out the high bits in another, ++ shift them both up to the top 16-bits of a word ++ and do the carry producing addition, finally ++ shift the result back down to the low 16-bits. ++ ++ Actually, we can further optimize away two shifts ++ because we know the low bits of the original ++ value will be added to zero-only bits so cannot ++ affect the addition result nor the final carry ++ bit. ++*/ ++" slli %1,%0, 16\n" /* Need a copy to fold with */ ++ /* Bring the LOW 16 bits up */ ++" add %0, %1, %0\n" /* add and set carry, neat eh? */ ++" cmpltu r15, %0, %1\n" /* get remaining carry bit */ ++" srli %0, %0, 16\n" /* shift back down the result */ ++" add %0, %0, r15\n" ++" nor %0, %0, %0\n" /* negate */ ++ : "=&r" (sum), "=&r" (saddr) ++ : "0" (sum), "1" (saddr), "r" (ntohl(len+proto)), "r" (daddr) ++ : "r15"); ++ return ((unsigned short) sum); ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++ extern inline unsigned short from32to16(unsigned long x) ++ { ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r15, %0, %1\n" ++ "srli %0, %0, 16\n" ++ "add %0, %0, r15\n" ++ : "=r" (x) ++ : "r" (x << 16), "0" (x) ++ : "r15"); ++ return x; ++ barrier(); ++ } ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++extern inline unsigned long do_csum(const unsigned char * buff, int len) ++{ ++ int odd, count; ++ unsigned long result = 0; ++ ++ barrier(); ++ if (len <= 0) ++ goto out; ++ odd = 1 & (unsigned long) buff; ++ if (odd) { ++////result = *buff; // dgt: Big endian ++ result = *buff << 8; // dgt: Little endian ++ ++ len--; ++ buff++; ++ } ++ count = len >> 1; /* nr of 16-bit words.. */ ++ if (count) { ++ if (2 & (unsigned long) buff) { ++ result += *(unsigned short *) buff; ++ count--; ++ len -= 2; ++ buff += 2; ++ } ++ count >>= 1; /* nr of 32-bit words.. */ ++ if (count) { ++ unsigned long carry = 0; ++ do { ++ unsigned long w = *(unsigned long *) buff; ++ count--; ++ buff += 4; ++ result += carry; ++ result += w; ++ carry = (w > result); ++ } while (count); ++ result += carry; ++ result = (result & 0xffff) + (result >> 16); ++ } ++ if (len & 2) { ++ result += *(unsigned short *) buff; ++ buff += 2; ++ } ++ } ++ if (len & 1) ++ result += *buff; /* This is little machine, byte is right */ ++ result = from32to16(result); ++ if (odd) ++ result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); ++out: ++ return result; ++ barrier(); ++ } ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++/* ihl is always 5 or greater, almost always is 5, iph is always word ++ * aligned but can fail to be dword aligned very often. ++ */ ++ ++ extern inline unsigned short ip_fast_csum(const unsigned char *iph, unsigned int ihl) ++ { ++ unsigned int sum; ++ ++ barrier(); ++ __asm__ __volatile__( ++" andi r8, %1, 2\n" /* Remember original alignment */ ++" ldw %0, (%1)\n" /* 16 or 32 bit boundary */ ++" beq r8, r0, 1f\n" /* Aligned on 32 bit boundary, go */ ++" srli %0, %0, 16\n" /* Get correct 16 bits */ ++" addi %2, %2, -1\n" /* Take off for 4 bytes, pickup last 2 at end */ ++" addi %1, %1, 2\n" /* Adjust pointer to 32 bit boundary */ ++" br 2f\n" ++"1:\n" ++" addi %2, %2, -1\n" ++" addi %1, %1, 4\n" /* Bump ptr a long word */ ++"2:\n" ++" ldw r9, (%1)\n" ++"1:\n" ++" add %0, r9, %0\n" ++" bgeu %0, r9, 2f\n" ++" addi %0, %0, 1\n" ++"2:\n" ++" addi %1, %1, 4\n" ++" addi %2, %2, -1\n" ++" ldw r9, (%1)\n" ++" bne %2, r0, 1b\n" ++" beq r8, r0, 1f\n" /* 32 bit boundary time to leave */ ++" srli r9, r9, 16\n" /* 16 bit boundary, get correct 16 bits */ ++" add %0, r9, %0\n" ++" bgeu %0, r9, 1f\n" ++" addi %0, %0, 1\n" ++"1:\n" ++" slli %2, %0, 16\n" ++" add %0, %2, %0\n" ++" cmpltu r8, %0, %2\n" ++" srli %0, %0, 16\n" ++" add %0, %0, r8\n" ++" nor %0, %0, %0\n" ++ : "=&r" (sum), "=&r" (iph), "=&r" (ihl) ++ : "1" (iph), "2" (ihl) ++ : "r8", "r9"); ++ return sum; ++ barrier(); ++ } ++ ++/*these 2 functions are now in checksum.c */ ++unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); ++unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++/* ++ * the same as csum_partial_copy, but copies from user space. ++ * ++ * here even more important to align src and dst on a 32-bit (or even ++ * better 64-bit) boundary ++ */ ++extern inline unsigned int ++csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *csum_err) ++{ ++ barrier(); ++ if (csum_err) *csum_err = 0; ++ memcpy(dst, src, len); ++ return csum_partial(dst, len, sum); ++ barrier(); ++} ++ ++#define csum_partial_copy_nocheck(src, dst, len, sum) \ ++ csum_partial_copy ((src), (dst), (len), (sum)) ++ ++ ++/* ++ * this routine is used for miscellaneous IP-like checksums, mainly ++ * in icmp.c ++ */ ++ ++extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) ++{ ++ barrier(); ++ return ~from32to16(do_csum(buff,len)); ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++#define csum_partial_copy_fromuser(s, d, l, w) \ ++ csum_partial_copy((char *) (s), (d), (l), (w)) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++/* ++ * Fold a partial checksum without adding pseudo headers ++ */ ++extern __inline__ unsigned int csum_fold(unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r8, %0, %1\n" ++ "srli %0, %0, 16\n" ++ "add %0, %0, r8\n" ++ "nor %0, %0, %0\n" ++ : "=r" (sum) ++ : "r" (sum << 16), "0" (sum) ++ : "r8"); ++ return sum; ++ barrier(); ++} ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ++ ++ ++extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ barrier(); ++ __asm__ __volatile__( ++ "add %0, %1, %0\n" ++ "cmpltu r8, %0, %1\n" ++ "add %0, %0, r8\n" /* add carry */ ++ "add %0, %2, %0\n" ++ "cmpltu r8, %0, %2\n" ++ "add %0, %0, r8\n" /* add carry */ ++ "add %0, %3, %0\n" ++ "cmpltu r8, %0, %3\n" ++ "add %0, %0, r8\n" /* add carry */ ++ : "=r" (sum), "=r" (saddr) ++ : "r" (daddr), "r" ( (ntohs(len)<<16) + (proto*256) ), ++ "0" (sum), ++ "1" (saddr) ++ : "r8"); ++ ++ return sum; ++ barrier(); ++} ++ ++ ++#endif /* (__NIOS2_CHECKSUM_H) */ +--- linux/include/asm-nios2nommu/cprefix.h ++++ linux/include/asm-nios2nommu/cprefix.h +@@ -0,0 +1,38 @@ ++/* cprefix.h: This file is included by assembly source which needs ++ * to know what the c-label prefixes are. The newer versions ++ * of cpp that come with gcc predefine such things to help ++ * us out. The reason this stuff is needed is to make ++ * solaris compiles of the kernel work. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2_CPREFIX_H ++#define __NIOS2_CPREFIX_H ++ ++#define C_LABEL_PREFIX ++ ++#define CONCAT(a, b) CONCAT2(a, b) ++#define CONCAT2(a, b) a##b ++ ++#define C_LABEL(name) CONCAT(C_LABEL_PREFIX, name) ++ ++#endif /* !(__NIOS2_CPREFIX_H) */ +--- linux/include/asm-nios2nommu/cpumask.h ++++ linux/include/asm-nios2nommu/cpumask.h +@@ -0,0 +1,28 @@ ++/* ++ * All rights reserved. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2NOMMU_CPUMASK_H ++#define _ASM_NIOS2NOMMU_CPUMASK_H ++ ++#include ++ ++#endif /* _ASM_NIOS2NOMMU_CPUMASK_H */ +--- linux/include/asm-nios2nommu/current.h ++++ linux/include/asm-nios2nommu/current.h +@@ -0,0 +1,39 @@ ++#ifndef _NIOS2NOMMU_CURRENT_H ++#define _NIOS2NOMMU_CURRENT_H ++/* ++ * current.h ++ * (C) Copyright 2000, Lineo, David McCullough ++ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) ++ * (C) Copyright 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++ ++struct task_struct; ++ ++static inline struct task_struct *get_current(void) ++{ ++ return(current_thread_info()->task); ++} ++ ++#define current get_current() ++ ++#endif /* _NIOS2NOMMU_CURRENT_H */ +--- linux/include/asm-nios2nommu/delay.h ++++ linux/include/asm-nios2nommu/delay.h +@@ -0,0 +1,96 @@ ++#ifndef _NIOS_DELAY_H ++#define _NIOS_DELAY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/delay.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++extern __inline__ void __delay(unsigned long loops) ++{ ++ int dummy; ++ ++ __asm__ __volatile__( ++ "1: \n\t" ++ " beq %0,zero,2f\n\t" ++ " addi %0, %0, -1\n\t" ++ " br 1b\n\t" ++ "2: \n\t" ++ ++ : "=r" (dummy) /* Need output for optimizer */ ++ ++ : "0" (loops) /* %0 Input */ ++ ); ++} ++ ++/* ++ * Note that 19 * 226 == 4294 ==~ 2^32 / 10^6, so ++ * loops = (4294 * usecs * loops_per_jiffy * HZ) / 2^32. ++ * ++ * The mul instruction gives us loops = (a * b) / 2^32. ++ * We choose a = usecs * 19 * HZ and b = loops_per_jiffy * 226 ++ * because this lets us support a wide range of HZ and ++ * loops_per_jiffy values without either a or b overflowing 2^32. ++ * Thus we need usecs * HZ <= (2^32 - 1) / 19 = 226050910 and ++ * loops_per_jiffy <= (2^32 - 1) / 226 = 19004280 ++ * (which corresponds to ~3800 bogomips at HZ = 100). ++ * -- paulus ++ */ ++#define __MAX_UDELAY (226050910UL/HZ) /* maximum udelay argument */ ++#define __MAX_NDELAY (4294967295UL/HZ) /* maximum ndelay argument */ ++ ++extern unsigned long loops_per_jiffy; ++ ++extern __inline__ void __udelay(unsigned int x) ++{ ++ unsigned int loops; ++ ++ __asm__("mulxuu %0,%1,%2" : "=r" (loops) : ++ "r" (x), "r" (loops_per_jiffy * 226)); ++ __delay(loops); ++} ++ ++extern __inline__ void __ndelay(unsigned int x) ++{ ++ unsigned int loops; ++ ++ __asm__("mulxuu %0,%1,%2" : "=r" (loops) : ++ "r" (x), "r" (loops_per_jiffy * 5)); ++ __delay(loops); ++} ++ ++extern void __bad_udelay(void); /* deliberately undefined */ ++extern void __bad_ndelay(void); /* deliberately undefined */ ++ ++#define udelay(n) (__builtin_constant_p(n)? \ ++ ((n) > __MAX_UDELAY? __bad_udelay(): __udelay((n) * (19 * HZ))) : \ ++ __udelay((n) * (19 * HZ))) ++ ++#define ndelay(n) (__builtin_constant_p(n)? \ ++ ((n) > __MAX_NDELAY? __bad_ndelay(): __ndelay((n) * HZ)) : \ ++ __ndelay((n) * HZ)) ++ ++#define muldiv(a, b, c) (((a)*(b))/(c)) ++ ++#endif /* defined(_NIOS_DELAY_H) */ +--- linux/include/asm-nios2nommu/div64.h ++++ linux/include/asm-nios2nommu/div64.h +@@ -0,0 +1,31 @@ ++#ifndef __ASMNIOS_DIV64_H ++#define __ASMNIOS_DIV64_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/div64.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif ++ +--- linux/include/asm-nios2nommu/dma-mapping.h ++++ linux/include/asm-nios2nommu/dma-mapping.h +@@ -0,0 +1,25 @@ ++/* ++ * include/asm-s390/dma-mapping.h ++ * ++ * S390 version ++ * ++ * This file exists so that #include doesn't break anything. ++ */ ++ ++#ifndef _ASM_DMA_MAPPING_H ++#define _ASM_DMA_MAPPING_H ++ ++static inline void *dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, int flag) ++{ ++ BUG(); ++ return 0; ++} ++ ++static inline void dma_free_coherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle) ++{ ++ BUG(); ++} ++ ++#endif /* _ASM_DMA_MAPPING_H */ +--- linux/include/asm-nios2nommu/dma.h ++++ linux/include/asm-nios2nommu/dma.h +@@ -0,0 +1,40 @@ ++/* $Id: dma.h,v 1.5 2004/03/02 16:05:52 ken-h Exp $ ++ * ++ * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) ++ * Copyright 2004 (C) Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2_DMA_H ++#define _ASM_NIOS2_DMA_H ++ ++#include ++#include ++ ++#define MAX_DMA_CHANNELS 2 ++#define MAX_DMA_ADDRESS (LINUX_SDRAM_START) ++#define DMA_MODE_READ 1 ++#define DMA_MODE_WRITE 2 ++ ++extern int get_dma_list(char *); ++extern int request_dma(unsigned int, const char *); ++extern void free_dma(unsigned int); ++ ++#endif /* !(_ASM_NIOS2_DMA_H) */ +--- linux/include/asm-nios2nommu/elf.h ++++ linux/include/asm-nios2nommu/elf.h +@@ -0,0 +1,141 @@ ++#ifndef __NIOS2_ELF_H ++#define __NIOS2_ELF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/elf.h ++ * ++ * Nio2 ELF relocation types ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * Mar/18/2004 xwt NiosII relocation types added ++ * ++ ---------------------------------------------------------------------*/ ++ ++// #include ++#include ++#include ++ ++#define R_NIOS2_NONE 0 ++#define R_NIOS2_S16 1 ++#define R_NIOS2_U16 2 ++#define R_NIOS2_PCREL16 3 ++#define R_NIOS2_CALL26 4 ++#define R_NIOS2_IMM5 5 ++#define R_NIOS2_CACHE_OPX 6 ++#define R_NIOS2_IMM6 7 ++#define R_NIOS2_IMM8 8 ++#define R_NIOS2_HI16 9 ++#define R_NIOS2_LO16 10 ++#define R_NIOS2_HIADJ16 11 ++#define R_NIOS2_BFD_RELOC_32 12 ++#define R_NIOS2_BFD_RELOC_16 13 ++#define R_NIOS2_BFD_RELOC_8 14 ++#define R_NIOS2_GPREL 15 ++#define R_NIOS2_GNU_VTINHERIT 16 ++#define R_NIOS2_GNU_VTENTRY 17 ++#define R_NIOS2_UJMP 18 ++#define R_NIOS2_CJMP 19 ++#define R_NIOS2_CALLR 20 ++#define R_NIOS2_ALIGN 21 ++/* Keep this the last entry. */ ++#define R_NIOS2_NUM 22 ++ ++typedef unsigned long elf_greg_t; ++ ++#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) ++typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ++ ++typedef unsigned long elf_fpregset_t; ++ ++/* ++ * This is used to ensure we don't load something for the wrong architecture. ++ */ ++#define elf_check_arch(x) \ ++ ((x)->e_machine == EM_ALTERA_NIOS2) ++ ++/* ++ * These are used to set parameters in the core dumps. ++ */ ++#define ELF_CLASS ELFCLASS32 ++#define ELF_DATA ELFDATA2LSB ++#define ELF_ARCH EM_ALTERA_NIOS2 ++ ++#define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 ++ ++#define USE_ELF_CORE_DUMP ++#define ELF_EXEC_PAGESIZE 4096 ++ ++/* This is the location that an ET_DYN program is loaded if exec'ed. Typical ++ use of this is to invoke "./ld.so someprog" to test out a new version of ++ the loader. We need to make sure that it is out of the way of the program ++ that it will "exec", and that there is sufficient room for the brk. */ ++ ++#define ELF_ET_DYN_BASE 0xD0000000UL ++ ++/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is ++ now struct_user_regs, they are different) */ ++ ++#define ELF_CORE_COPY_REGS(pr_reg, regs) \ ++ /* Bleech. */ \ ++ pr_reg[0] = regs->r1; \ ++ pr_reg[1] = regs->r2; \ ++ pr_reg[2] = regs->r3; \ ++ pr_reg[3] = regs->r4; \ ++ pr_reg[4] = regs->r5; \ ++ pr_reg[5] = regs->r6; \ ++ pr_reg[6] = regs->r7; \ ++ pr_reg[7] = regs->r8; \ ++ pr_reg[8] = regs->r9; \ ++ pr_reg[9] = regs->r10; \ ++ pr_reg[10] = regs->r11; \ ++ pr_reg[11] = regs->r12; \ ++ pr_reg[12] = regs->r13; \ ++ pr_reg[13] = regs->r14; \ ++ pr_reg[14] = regs->r15; \ ++ pr_reg[23] = regs->sp; \ ++ pr_reg[26] = regs->estatus; \ ++ { \ ++ struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ ++ pr_reg[15] = sw->r16; \ ++ pr_reg[16] = sw->r17; \ ++ pr_reg[17] = sw->r18; \ ++ pr_reg[18] = sw->r19; \ ++ pr_reg[19] = sw->r20; \ ++ pr_reg[20] = sw->r21; \ ++ pr_reg[21] = sw->r22; \ ++ pr_reg[22] = sw->r23; \ ++ pr_reg[24] = sw->fp; \ ++ pr_reg[25] = sw->gp; \ ++ } ++ ++/* This yields a mask that user programs can use to figure out what ++ instruction set this cpu supports. */ ++ ++#define ELF_HWCAP (0) ++ ++/* This yields a string that ld.so will use to load implementation ++ specific libraries for optimization. This is more specific in ++ intent than poking at uname or /proc/cpuinfo. */ ++ ++#define ELF_PLATFORM (NULL) ++ ++#ifdef __KERNEL__ ++#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) ++#endif ++ ++#endif +--- linux/include/asm-nios2nommu/entry.h ++++ linux/include/asm-nios2nommu/entry.h +@@ -0,0 +1,188 @@ ++/* ++ * Hacked from m68knommu port. ++ * ++ * Copyright(C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_ENTRY_H ++#define __NIOS2NOMMU_ENTRY_H ++ ++#ifdef __ASSEMBLY__ ++ ++// #include ++#include ++#include ++#include ++ ++/* ++ * Stack layout in 'ret_from_exception': ++ * ++ * This allows access to the syscall arguments in registers r4-r8 ++ * ++ * 0(sp) - r8 ++ * 4(sp) - r9 ++ * 8(sp) - r10 ++ * C(sp) - r11 ++ * 10(sp) - r12 ++ * 14(sp) - r13 ++ * 18(sp) - r14 ++ * 1C(sp) - r15 ++ * 20(sp) - r1 ++ * 24(sp) - r2 ++ * 28(sp) - r3 ++ * 2C(sp) - r4 ++ * 30(sp) - r5 ++ * 34(sp) - r6 ++ * 38(sp) - r7 ++ * 3C(sp) - orig_r2 ++ * 40(sp) - ra ++ * 44(sp) - fp ++ * 48(sp) - sp ++ * 4C(sp) - gp ++ * 50(sp) - estatus ++ * 54(sp) - status_extension ++ * 58(sp) - ea ++ * ++ */ ++ ++/* process bits for task_struct.flags */ ++PF_TRACESYS_OFF = 3 ++PF_TRACESYS_BIT = 5 ++PF_PTRACED_OFF = 3 ++PF_PTRACED_BIT = 4 ++PF_DTRACE_OFF = 1 ++PF_DTRACE_BIT = 5 ++ ++LENOSYS = 38 ++ ++/* ++ * This defines the normal kernel pt-regs layout. ++ * ++ */ ++ ++/* ++ * Standard Nios2 interrupt entry and exit macros. ++ * Must be called with interrupts disabled. ++ */ ++.macro SAVE_ALL ++ movia r24,status_extension // Read status extension ++ ldw r24,0(r24) ++ andi r24,r24,PS_S_ASM ++ bne r24,r0,1f // In supervisor mode, already on kernel stack ++ movia r24,_current_thread // Switch to current kernel stack ++ ldw r24,0(r24) // using the thread_info ++ addi r24,r24,THREAD_SIZE_ASM-PT_REGS_SIZE ++ stw sp,PT_SP(r24) // Save user stack before changing ++ mov sp,r24 ++ br 2f ++ ++1: mov r24,sp ++ addi sp,sp,-PT_REGS_SIZE // Backup the kernel stack pointer ++ stw r24,PT_SP(sp) ++2: stw r1,PT_R1(sp) ++ stw r2,PT_R2(sp) ++ stw r3,PT_R3(sp) ++ stw r4,PT_R4(sp) ++ stw r5,PT_R5(sp) ++ stw r6,PT_R6(sp) ++ stw r7,PT_R7(sp) ++ stw r8,PT_R8(sp) ++ stw r9,PT_R9(sp) ++ stw r10,PT_R10(sp) ++ stw r11,PT_R11(sp) ++ stw r12,PT_R12(sp) ++ stw r13,PT_R13(sp) ++ stw r14,PT_R14(sp) ++ stw r15,PT_R15(sp) ++ stw r2,PT_ORIG_R2(sp) ++ stw ra,PT_RA(sp) ++ stw fp,PT_FP(sp) ++ stw gp,PT_GP(sp) ++ rdctl r24,estatus ++ stw r24,PT_ESTATUS(sp) ++ movia r24,status_extension // Read status extension ++ ldw r1,0(r24) ++ stw r1,PT_STATUS_EXTENSION(sp) // Store user/supervisor status ++ ORI32 r1,r1,PS_S_ASM // Set supervisor mode ++ stw r1,0(r24) ++ stw ea,PT_EA(sp) ++.endm ++ ++.macro RESTORE_ALL ++ ldw r1,PT_STATUS_EXTENSION(sp) // Restore user/supervisor status ++ movia r24,status_extension ++ stw r1,0(r24) ++ ldw r1,PT_R1(sp) // Restore registers ++ ldw r2,PT_R2(sp) ++ ldw r3,PT_R3(sp) ++ ldw r4,PT_R4(sp) ++ ldw r5,PT_R5(sp) ++ ldw r6,PT_R6(sp) ++ ldw r7,PT_R7(sp) ++ ldw r8,PT_R8(sp) ++ ldw r9,PT_R9(sp) ++ ldw r10,PT_R10(sp) ++ ldw r11,PT_R11(sp) ++ ldw r12,PT_R12(sp) ++ ldw r13,PT_R13(sp) ++ ldw r14,PT_R14(sp) ++ ldw r15,PT_R15(sp) ++ ldw ra,PT_RA(sp) ++ ldw fp,PT_FP(sp) ++ ldw gp,PT_GP(sp) ++ ldw r24,PT_ESTATUS(sp) ++ wrctl estatus,r24 ++ ldw ea,PT_EA(sp) ++ ldw sp,PT_SP(sp) // Restore sp last ++.endm ++ ++.macro SAVE_SWITCH_STACK ++ addi sp,sp,-SWITCH_STACK_SIZE ++ stw r16,SW_R16(sp) ++ stw r17,SW_R17(sp) ++ stw r18,SW_R18(sp) ++ stw r19,SW_R19(sp) ++ stw r20,SW_R20(sp) ++ stw r21,SW_R21(sp) ++ stw r22,SW_R22(sp) ++ stw r23,SW_R23(sp) ++ stw fp,SW_FP(sp) ++ stw gp,SW_GP(sp) ++ stw ra,SW_RA(sp) ++.endm ++ ++.macro RESTORE_SWITCH_STACK ++ ldw r16,SW_R16(sp) ++ ldw r17,SW_R17(sp) ++ ldw r18,SW_R18(sp) ++ ldw r19,SW_R19(sp) ++ ldw r20,SW_R20(sp) ++ ldw r21,SW_R21(sp) ++ ldw r22,SW_R22(sp) ++ ldw r23,SW_R23(sp) ++ ldw fp,SW_FP(sp) ++ ldw gp,SW_GP(sp) ++ ldw ra,SW_RA(sp) ++ addi sp,sp,SWITCH_STACK_SIZE ++.endm ++ ++#endif /* __ASSEMBLY__ */ ++#endif /* __NIOS2NOMMU_ENTRY_H */ +--- linux/include/asm-nios2nommu/errno.h ++++ linux/include/asm-nios2nommu/errno.h +@@ -0,0 +1,6 @@ ++#ifndef _NIOS2NOMMU_ERRNO_H ++#define _NIOS2NOMMU_ERRNO_H ++ ++#include ++ ++#endif /* _NIOS2NOMMU_ERRNO_H */ +--- linux/include/asm-nios2nommu/fcntl.h ++++ linux/include/asm-nios2nommu/fcntl.h +@@ -0,0 +1,110 @@ ++/* ++ * This file came from the m68k port. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2_FCNTL_H ++#define _NIOS2_FCNTL_H ++ ++/* open/fcntl - O_SYNC is only implemented on blocks devices and on files ++ located on an ext2 file system */ ++#define O_ACCMODE 0003 ++#define O_RDONLY 00 ++#define O_WRONLY 01 ++#define O_RDWR 02 ++#define O_CREAT 0100 /* not fcntl */ ++#define O_EXCL 0200 /* not fcntl */ ++#define O_NOCTTY 0400 /* not fcntl */ ++#define O_TRUNC 01000 /* not fcntl */ ++#define O_APPEND 02000 ++#define O_NONBLOCK 04000 ++#define O_NDELAY O_NONBLOCK ++#define O_SYNC 010000 ++#define FASYNC 020000 /* fcntl, for BSD compatibility */ ++#define O_DIRECTORY 040000 /* must be a directory */ ++#define O_NOFOLLOW 0100000 /* don't follow links */ ++#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ ++#define O_LARGEFILE 0400000 ++#define O_NOATIME 01000000 ++ ++#define F_DUPFD 0 /* dup */ ++#define F_GETFD 1 /* get close_on_exec */ ++#define F_SETFD 2 /* set/clear close_on_exec */ ++#define F_GETFL 3 /* get file->f_flags */ ++#define F_SETFL 4 /* set file->f_flags */ ++#define F_GETLK 5 ++#define F_SETLK 6 ++#define F_SETLKW 7 ++ ++#define F_SETOWN 8 /* for sockets. */ ++#define F_GETOWN 9 /* for sockets. */ ++#define F_SETSIG 10 /* for sockets. */ ++#define F_GETSIG 11 /* for sockets. */ ++ ++#define F_GETLK64 12 /* using 'struct flock64' */ ++#define F_SETLK64 13 ++#define F_SETLKW64 14 ++ ++/* for F_[GET|SET]FL */ ++#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ ++ ++/* for posix fcntl() and lockf() */ ++#define F_RDLCK 0 ++#define F_WRLCK 1 ++#define F_UNLCK 2 ++ ++/* for old implementation of bsd flock () */ ++#define F_EXLCK 4 /* or 3 */ ++#define F_SHLCK 8 /* or 4 */ ++ ++/* for leases */ ++#define F_INPROGRESS 16 ++ ++/* operations for bsd flock(), also used by the kernel implementation */ ++#define LOCK_SH 1 /* shared lock */ ++#define LOCK_EX 2 /* exclusive lock */ ++#define LOCK_NB 4 /* or'd with one of the above to prevent ++ blocking */ ++#define LOCK_UN 8 /* remove lock */ ++ ++#define LOCK_MAND 32 /* This is a mandatory flock */ ++#define LOCK_READ 64 /* ... Which allows concurrent read operations */ ++#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ ++#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ ++ ++struct flock { ++ short l_type; ++ short l_whence; ++ off_t l_start; ++ off_t l_len; ++ pid_t l_pid; ++}; ++ ++struct flock64 { ++ short l_type; ++ short l_whence; ++ loff_t l_start; ++ loff_t l_len; ++ pid_t l_pid; ++}; ++ ++#define F_LINUX_SPECIFIC_BASE 1024 ++#endif /* _NIOS2_FCNTL_H */ +--- linux/include/asm-nios2nommu/flat.h ++++ linux/include/asm-nios2nommu/flat.h +@@ -0,0 +1,126 @@ ++/* ++ * include/asm-nios2nommu/flat.h -- uClinux bFLT relocations ++ * ++ * Copyright (C) 2004,05 Microtronix Datacom Ltd ++ * ++ * This file is subject to the terms and conditions of the GNU General ++ * Public License. See the file COPYING in the main directory of this ++ * archive for more details. ++ * ++ * Written by Wentao Xu ++ */ ++ ++#ifndef __NIOS2_FLAT_H__ ++#define __NIOS2_FLAT_H__ ++ ++#define flat_reloc_valid(reloc, size) ((reloc) <= (size + 0x8000)) ++ ++/* The stack is 64-bit aligned for Nios II, so (sp - 1) shall ++ * be 64-bit aligned, where -1 is for argc ++ */ ++#define flat_stack_align(sp) (sp = (unsigned long *)(((unsigned long)sp - 1) & (-8))) ++ ++/* The uClibc port for Nios II expects the argc is followed by argv and envp */ ++#define flat_argvp_envp_on_stack() 1 ++ ++#define flat_old_ram_flag(flags) (flags) ++ ++/* We store the type of relocation in the top 4 bits of the `relval.' */ ++ ++/* Convert a relocation entry into an address. */ ++static inline unsigned long ++flat_get_relocate_addr (unsigned long relval) ++{ ++ return relval & 0x0fffffff; /* Mask out top 4-bits */ ++} ++ ++#define FLAT_NIOS2_RELOC_TYPE(relval) ((relval) >> 28) ++ ++#define FLAT_NIOS2_R_32 0 /* Normal 32-bit reloc */ ++#define FLAT_NIOS2_R_HI_LO 1 /* High 16-bits + low 16-bits field */ ++#define FLAT_NIOS2_R_HIADJ_LO 2 /* High 16-bits adjust + low 16-bits field */ ++#define FLAT_NIOS2_R_CALL26 4 /* Call imm26 */ ++ ++/* Extract the address to be relocated from the symbol reference at rp; ++ * relval is the raw relocation-table entry from which RP is derived. ++ * rp shall always be 32-bit aligned ++ */ ++static inline unsigned long flat_get_addr_from_rp (unsigned long *rp, ++ unsigned long relval, ++ unsigned long flags) ++{ ++ switch (FLAT_NIOS2_RELOC_TYPE(relval)) ++ { ++ case FLAT_NIOS2_R_32: ++ /* Simple 32-bit address. The loader expect it in bigger endian */ ++ return htonl(*rp); ++ ++ case FLAT_NIOS2_R_HI_LO: ++ /* get the two 16-bit immediate value from instructions, then ++ * construct a 32-bit value. Again the loader expect bigger endian ++ */ ++ return htonl ((((rp[0] >> 6) & 0xFFFF) << 16 ) | ++ ((rp[1] >> 6) & 0xFFFF)); ++ ++ case FLAT_NIOS2_R_HIADJ_LO: ++ { ++ /* get the two 16-bit immediate value from instructions, then ++ * construct a 32-bit value. Again the loader expect bigger endian ++ */ ++ unsigned int low, high; ++ high = (rp[0] >> 6) & 0xFFFF; ++ low = (rp[1] >> 6) & 0xFFFF; ++ ++ if ((low >> 15) & 1) high--; ++ ++ return htonl ((high << 16 ) | low ); ++ } ++ case FLAT_NIOS2_R_CALL26: ++ /* the 26-bit immediate value is actually 28-bit */ ++ return htonl(((*rp) >> 6) << 2); ++ ++ default: ++ return ~0; /* bogus value */ ++ } ++} ++ ++/* Insert the address addr into the symbol reference at rp; ++ * relval is the raw relocation-table entry from which rp is derived. ++ * rp shall always be 32-bit aligned ++ */ ++static inline void flat_put_addr_at_rp (unsigned long *rp, unsigned long addr, ++ unsigned long relval) ++{ ++ unsigned long exist_val; ++ switch (FLAT_NIOS2_RELOC_TYPE (relval)) { ++ case FLAT_NIOS2_R_32: ++ /* Simple 32-bit address. */ ++ *rp = addr; ++ break; ++ ++ case FLAT_NIOS2_R_HI_LO: ++ exist_val = rp[0]; ++ rp[0] = ((((exist_val >> 22) << 16) | (addr >> 16)) << 6) | (exist_val & 0x3F); ++ exist_val = rp[1]; ++ rp[1] = ((((exist_val >> 22) << 16) | (addr & 0xFFFF)) << 6) | (exist_val & 0x3F); ++ break; ++ ++ case FLAT_NIOS2_R_HIADJ_LO: ++ { ++ unsigned int high = (addr >> 16); ++ if ((addr >> 15) & 1) ++ high = (high + 1) & 0xFFFF; ++ exist_val = rp[0]; ++ rp[0] = ((((exist_val >> 22) << 16) | high) << 6) | (exist_val & 0x3F); ++ exist_val = rp[1]; ++ rp[1] = ((((exist_val >> 22) << 16) | (addr & 0xFFFF)) << 6) | (exist_val & 0x3F); ++ break; ++ } ++ case FLAT_NIOS2_R_CALL26: ++ /* the opcode of CALL is 0, so just store the value */ ++ *rp = ((addr >> 2) << 6); ++ break; ++ } ++} ++ ++#endif /* __NIOS2_FLAT_H__ */ +--- linux/include/asm-nios2nommu/hardirq.h ++++ linux/include/asm-nios2nommu/hardirq.h +@@ -0,0 +1,85 @@ ++/* ++ * Ported from m68knommu ++ * ++ * Copyright (C) 2003, Microtronix Datacom Ltd. ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __NIOS2_HARDIRQ_H ++#define __NIOS2_HARDIRQ_H ++ ++// #include ++#include ++#include ++ ++typedef struct { ++ unsigned int __softirq_pending; ++ unsigned int __syscall_count; ++ struct task_struct * __ksoftirqd_task; ++} ____cacheline_aligned irq_cpustat_t; ++ ++#include /* Standard mappings for irq_cpustat_t above */ ++ ++/* ++ * We put the hardirq and softirq counter into the preemption ++ * counter. The bitmask has the following meaning: ++ * ++ * - bits 0-7 are the preemption count (max preemption depth: 256) ++ * - bits 8-15 are the softirq count (max # of softirqs: 256) ++ * - bits 16-23 are the hardirq count (max # of hardirqs: 256) ++ * ++ * - ( bit 26 is the PREEMPT_ACTIVE flag. ) ++ * ++ * PREEMPT_MASK: 0x000000ff ++ * HARDIRQ_MASK: 0x0000ff00 ++ * SOFTIRQ_MASK: 0x00ff0000 ++ */ ++ ++#define PREEMPT_BITS 8 ++#define SOFTIRQ_BITS 8 ++#define HARDIRQ_BITS 8 ++ ++#define PREEMPT_SHIFT 0 ++#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) ++#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) ++ ++/* ++ * The hardirq mask has to be large enough to have ++ * space for potentially all IRQ sources in the system ++ * nesting on a single CPU: ++ */ ++#if (1 << HARDIRQ_BITS) < NR_IRQS ++# error HARDIRQ_BITS is too low! ++#endif ++ ++#define irq_enter() (preempt_count() += HARDIRQ_OFFSET) ++#define irq_exit() \ ++do { \ ++ preempt_count() -= IRQ_EXIT_OFFSET; \ ++ if (!in_interrupt() && softirq_pending(smp_processor_id())) \ ++ do_softirq(); \ ++ preempt_enable_no_resched(); \ ++} while (0) ++ ++#ifdef CONFIG_SMP ++# error nios2nommu SMP is not available ++#endif /* CONFIG_SMP */ ++ ++#endif /* __NIOS2_HARDIRQ_H */ +--- linux/include/asm-nios2nommu/hdreg.h ++++ linux/include/asm-nios2nommu/hdreg.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 1994-1996 Linus Torvalds & authors ++ * Copyright (C) 2002 Wentau Xu (www.microtronix.com) ++ * copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_HDREG_H ++#define __NIOS2_HDREG_H ++ ++typedef unsigned long ide_ioreg_t; ++ ++#endif /* __NIOS2_HDREG_H */ +--- linux/include/asm-nios2nommu/hw_irq.h ++++ linux/include/asm-nios2nommu/hw_irq.h +@@ -0,0 +1,16 @@ ++#ifndef _ASM_HW_IRQ_H ++#define _ASM_HW_IRQ_H ++ ++/* ++ * linux/include/asm/hw_irq.h ++ * ++ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar ++ * ++ * moved some of the old arch/i386/kernel/irq.h to here. VY ++ * ++ * IRQ/IPI changes taken from work by Thomas Radke ++ * ++ */ ++ ++ ++#endif /* _ASM_HW_IRQ_H */ +--- linux/include/asm-nios2nommu/ide.h ++++ linux/include/asm-nios2nommu/ide.h +@@ -0,0 +1,47 @@ ++/* ++ * linux/include/asm-niosnommu2/ide.h ++ * ++ * Copyright (C) 1994-1996 Linus Torvalds & authors ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ASMNIOS2_IDE_H ++#define __ASMNIOS2_IDE_H ++ ++#ifdef __KERNEL__ ++#undef MAX_HWIFS /* we're going to force it */ ++ ++#ifndef MAX_HWIFS ++#define MAX_HWIFS 1 ++#endif ++ ++#define IDE_ARCH_OBSOLETE_INIT ++#define IDE_ARCH_OBSOLETE_DEFAULTS ++#define ide_default_io_base(i) ((unsigned long)na_ide_ide) ++#define ide_default_irq(b) (na_ide_ide_irq) ++#define ide_init_default_irq(base) ide_default_irq(base) ++#define ide_default_io_ctl(base) ((base) + (0xE*4)) ++ ++#include ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* __ASMNIOS2_IDE_H */ +--- linux/include/asm-nios2nommu/init.h ++++ linux/include/asm-nios2nommu/init.h +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#error " should never be used - use instead" +--- linux/include/asm-nios2nommu/io.h ++++ linux/include/asm-nios2nommu/io.h +@@ -0,0 +1,239 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_IO_H ++#define __NIOS2_IO_H ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#include /* IO address mapping routines need this */ ++#include ++#include ++ ++extern void insw(unsigned long port, void *dst, unsigned long count); ++extern void outsw(unsigned long port, void *src, unsigned long count); ++extern void insl(unsigned long port, void *dst, unsigned long count); ++extern void outsl(unsigned long port, void *src, unsigned long count); ++ ++ ++/* ++ * readX/writeX() are used to access memory mapped devices. On some ++ * architectures the memory mapped IO stuff needs to be accessed ++ * differently. On the Nios architecture, we just read/write the ++ * memory location directly. ++ */ ++ ++#define readb(addr) \ ++({ \ ++ unsigned char __res;\ ++ __asm__ __volatile__( \ ++ "ldbuio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define readw(addr) \ ++({ \ ++ unsigned short __res;\ ++ __asm__ __volatile__( \ ++ "ldhuio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define readl(addr) \ ++({ \ ++ unsigned int __res;\ ++ __asm__ __volatile__( \ ++ "ldwio %0, 0(%1)" \ ++ : "=r"(__res) \ ++ : "r" (addr)); \ ++ __res; \ ++}) ++ ++#define writeb(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "stbio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define writew(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "sthio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define writel(b,addr) \ ++({ \ ++ __asm__ __volatile__( \ ++ "stwio %0, 0(%1)" \ ++ : : "r"(b), "r" (addr)); \ ++}) ++ ++#define __raw_readb readb ++#define __raw_readw readw ++#define __raw_readl readl ++#define __raw_writeb writeb ++#define __raw_writew writew ++#define __raw_writel writel ++ ++ ++/* ++ * make the short names macros so specific devices ++ * can override them as required ++ */ ++ ++#define memset_io(addr,c,len) memset((void *)(((unsigned int)(addr)) | 0x80000000),(c),(len)) ++#define memcpy_fromio(to,from,len) memcpy((to),(void *)(((unsigned int)(from)) | 0x80000000),(len)) ++#define memcpy_toio(to,from,len) memcpy((void *)(((unsigned int)(to)) | 0x80000000),(from),(len)) ++ ++#define inb(addr) readb(addr) ++#define inw(addr) readw(addr) ++#define inl(addr) readl(addr) ++ ++#define outb(x,addr) ((void) writeb(x,addr)) ++#define outw(x,addr) ((void) writew(x,addr)) ++#define outl(x,addr) ((void) writel(x,addr)) ++ ++#define inb_p(addr) inb(addr) ++#define inw_p(addr) inw(addr) ++#define inl_p(addr) inl(addr) ++ ++#define outb_p(x,addr) outb(x,addr) ++#define outw_p(x,addr) outw(x,addr) ++#define outl_p(x,addr) outl(x,addr) ++ ++ ++ ++extern inline void insb(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned char *p=(unsigned char*)dst; ++ while (count--) ++ *p++ = inb(port); ++} ++ ++/* See arch/niosnommu/io.c for optimized version */ ++extern inline void _insw(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned short *p=(unsigned short*)dst; ++ while (count--) ++ *p++ = inw(port); ++} ++ ++/* See arch/niosnommu/kernel/io.c for unaligned destination pointer */ ++extern inline void _insl(unsigned long port, void *dst, unsigned long count) ++{ ++ unsigned long *p=(unsigned long*)dst; ++ while (count--) ++ *p++ = inl(port); ++} ++ ++extern inline void outsb(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned char *p=(unsigned char*)src; ++ while (count--) ++ outb( *p++, port ); ++} ++ ++/* See arch/niosnommu/io.c for optimized version */ ++extern inline void _outsw(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned short *p=(unsigned short*)src; ++ while (count--) ++ outw( *p++, port ); ++} ++ ++/* See arch/niosnommu/kernel/io.c for unaligned source pointer */ ++extern inline void _outsl(unsigned long port, void *src, unsigned long count) ++{ ++ unsigned long *p=(unsigned long*)src; ++ while (count--) ++ outl( *p++, port ); ++} ++ ++ ++ ++extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr, ++ int bus, int rdonly) ++{ ++ return; ++} ++ ++//vic - copied from m68knommu ++ ++/* Values for nocacheflag and cmode */ ++#define IOMAP_FULL_CACHING 0 ++#define IOMAP_NOCACHE_SER 1 ++#define IOMAP_NOCACHE_NONSER 2 ++#define IOMAP_WRITETHROUGH 3 ++ ++extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); ++extern void __iounmap(void *addr, unsigned long size); ++ ++extern inline void *ioremap(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); ++} ++extern inline void *ioremap_nocache(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); ++} ++extern inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); ++} ++extern inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size) ++{ ++ return __ioremap(physaddr, size, IOMAP_FULL_CACHING); ++} ++ ++extern void iounmap(void *addr); ++ ++ ++#define IO_SPACE_LIMIT 0xffffffff ++ ++#define dma_cache_inv(_start,_size) do { } while (0) ++#define dma_cache_wback(_start,_size) do { } while (0) ++#define dma_cache_wback_inv(_start,_size) do { } while (0) ++ ++/* Pages to physical address... */ ++#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) ++#define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT) ++ ++#define mm_ptov(vaddr) ((void *) (vaddr)) ++#define mm_vtop(vaddr) ((unsigned long) (vaddr)) ++#define phys_to_virt(vaddr) ((void *) (vaddr)) ++#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) ++ ++#define virt_to_bus virt_to_phys ++#define bus_to_virt phys_to_virt ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* !(__NIOS2_IO_H) */ ++ +--- linux/include/asm-nios2nommu/ioctl.h ++++ linux/include/asm-nios2nommu/ioctl.h +@@ -0,0 +1,100 @@ ++/* $Id: ioctl.h,v 1.3 2004/02/12 23:06:40 ken-h Exp $ ++ * ++ * linux/ioctl.h for Linux by H.H. Bergman. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_IOCTL_H ++#define _NIOS2_IOCTL_H ++ ++/* ioctl command encoding: 32 bits total, command in lower 16 bits, ++ * size of the parameter structure in the lower 14 bits of the ++ * upper 16 bits. ++ * Encoding the size of the parameter structure in the ioctl request ++ * is useful for catching programs compiled with old versions ++ * and to avoid overwriting user space outside the user buffer area. ++ * The highest 2 bits are reserved for indicating the ``access mode''. ++ * NOTE: This limits the max parameter size to 16kB -1 ! ++ */ ++ ++/* ++ * I don't really have any idea about what this should look like, so ++ * for the time being, this is heavily based on the PC definitions. ++ */ ++ ++/* ++ * The following is for compatibility across the various Linux ++ * platforms. The i386 ioctl numbering scheme doesn't really enforce ++ * a type field. De facto, however, the top 8 bits of the lower 16 ++ * bits are indeed used as a type field, so we might just as well make ++ * this explicit here. Please be sure to use the decoding macros ++ * below from now on. ++ */ ++#define _IOC_NRBITS 8 ++#define _IOC_TYPEBITS 8 ++#define _IOC_SIZEBITS 14 ++#define _IOC_DIRBITS 2 ++ ++#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) ++#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) ++#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) ++#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) ++ ++#define _IOC_NRSHIFT 0 ++#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) ++#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) ++#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) ++ ++/* ++ * Direction bits. ++ */ ++#define _IOC_NONE 0U ++#define _IOC_WRITE 1U ++#define _IOC_READ 2U ++ ++#define _IOC(dir,type,nr,size) \ ++ (((dir) << _IOC_DIRSHIFT) | \ ++ ((type) << _IOC_TYPESHIFT) | \ ++ ((nr) << _IOC_NRSHIFT) | \ ++ ((size) << _IOC_SIZESHIFT)) ++ ++/* used to create numbers */ ++#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) ++#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) ++#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) ++#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) ++ ++/* used to decode ioctl numbers.. */ ++#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) ++#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) ++#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) ++#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) ++ ++/* ...and for the drivers/sound files... */ ++ ++#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) ++#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) ++#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) ++#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) ++#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) ++ ++#endif /* _NIOS2_IOCTL_H */ +--- linux/include/asm-nios2nommu/ioctls.h ++++ linux/include/asm-nios2nommu/ioctls.h +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ARCH_NIOS2_IOCTLS_H__ ++#define __ARCH_NIOS2_IOCTLS_H__ ++ ++#include ++ ++/* 0x54 is just a magic number to make these relatively unique ('T') */ ++ ++#define TCGETS 0x5401 ++#define TCSETS 0x5402 ++#define TCSETSW 0x5403 ++#define TCSETSF 0x5404 ++#define TCGETA 0x5405 ++#define TCSETA 0x5406 ++#define TCSETAW 0x5407 ++#define TCSETAF 0x5408 ++#define TCSBRK 0x5409 ++#define TCXONC 0x540A ++#define TCFLSH 0x540B ++#define TIOCEXCL 0x540C ++#define TIOCNXCL 0x540D ++#define TIOCSCTTY 0x540E ++#define TIOCGPGRP 0x540F ++#define TIOCSPGRP 0x5410 ++#define TIOCOUTQ 0x5411 ++#define TIOCSTI 0x5412 ++#define TIOCGWINSZ 0x5413 ++#define TIOCSWINSZ 0x5414 ++#define TIOCMGET 0x5415 ++#define TIOCMBIS 0x5416 ++#define TIOCMBIC 0x5417 ++#define TIOCMSET 0x5418 ++#define TIOCGSOFTCAR 0x5419 ++#define TIOCSSOFTCAR 0x541A ++#define FIONREAD 0x541B ++#define TIOCINQ FIONREAD ++#define TIOCLINUX 0x541C ++#define TIOCCONS 0x541D ++#define TIOCGSERIAL 0x541E ++#define TIOCSSERIAL 0x541F ++#define TIOCPKT 0x5420 ++#define FIONBIO 0x5421 ++#define TIOCNOTTY 0x5422 ++#define TIOCSETD 0x5423 ++#define TIOCGETD 0x5424 ++#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ ++#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ ++#define TIOCSBRK 0x5427 /* BSD compatibility */ ++#define TIOCCBRK 0x5428 /* BSD compatibility */ ++#define TIOCGSID 0x5429 /* Return the session ID of FD */ ++#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ ++#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ ++ ++#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ ++#define FIOCLEX 0x5451 ++#define FIOASYNC 0x5452 ++#define TIOCSERCONFIG 0x5453 ++#define TIOCSERGWILD 0x5454 ++#define TIOCSERSWILD 0x5455 ++#define TIOCGLCKTRMIOS 0x5456 ++#define TIOCSLCKTRMIOS 0x5457 ++#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ ++#define TIOCSERGETLSR 0x5459 /* Get line status register */ ++#define TIOCSERGETMULTI 0x545A /* Get multiport config */ ++#define TIOCSERSETMULTI 0x545B /* Set multiport config */ ++ ++#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ ++#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ ++#define FIOQSIZE 0x545E ++ ++/* Used for packet mode */ ++#define TIOCPKT_DATA 0 ++#define TIOCPKT_FLUSHREAD 1 ++#define TIOCPKT_FLUSHWRITE 2 ++#define TIOCPKT_STOP 4 ++#define TIOCPKT_START 8 ++#define TIOCPKT_NOSTOP 16 ++#define TIOCPKT_DOSTOP 32 ++ ++#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ ++ ++#endif /* __ARCH_NIOS2_IOCTLS_H__ */ +--- linux/include/asm-nios2nommu/ipc.h ++++ linux/include/asm-nios2nommu/ipc.h +@@ -0,0 +1,51 @@ ++#ifndef __NIOS2_IPC_H__ ++#define __NIOS2_IPC_H__ ++ ++/* Copied from sparc version ++ * These are used to wrap system calls on the Nios. ++ * ++ * See arch/niosnommu/kernel/sys_nios.c for ugly details.. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++struct ipc_kludge { ++ struct msgbuf *msgp; ++ long msgtyp; ++}; ++ ++#define SEMOP 1 ++#define SEMGET 2 ++#define SEMCTL 3 ++#define MSGSND 11 ++#define MSGRCV 12 ++#define MSGGET 13 ++#define MSGCTL 14 ++#define SHMAT 21 ++#define SHMDT 22 ++#define SHMGET 23 ++#define SHMCTL 24 ++ ++/* Used by the DIPC package, try and avoid reusing it */ ++#define DIPC 25 ++ ++#define IPCCALL(version,op) ((version)<<16 | (op)) ++ ++#endif +--- linux/include/asm-nios2nommu/ipcbuf.h ++++ linux/include/asm-nios2nommu/ipcbuf.h +@@ -0,0 +1,49 @@ ++#ifndef __NIOS2_IPCBUF_H__ ++#define __NIOS2_IPCBUF_H__ ++ ++/* Copied from asm-m68k/ipcbuf.h ++ * The user_ipc_perm structure for Nios architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 32-bit mode_t and seq ++ * - 2 miscellaneous 32-bit values ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++struct ipc64_perm ++{ ++ __kernel_key_t key; ++ __kernel_uid32_t uid; ++ __kernel_gid32_t gid; ++ __kernel_uid32_t cuid; ++ __kernel_gid32_t cgid; ++ __kernel_mode_t mode; ++ unsigned short __pad1; ++ unsigned short seq; ++ unsigned short __pad2; ++ unsigned long __unused1; ++ unsigned long __unused2; ++}; ++ ++#endif /* __NIOS2_IPCBUF_H__ */ +--- linux/include/asm-nios2nommu/irq.h ++++ linux/include/asm-nios2nommu/irq.h +@@ -0,0 +1,182 @@ ++/* ++ * 21Mar2001 1.1 dgt/microtronix ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++ ++#ifndef _NIOS2NOMMU_IRQ_H_ ++#define _NIOS2NOMMU_IRQ_H_ ++ ++extern void disable_irq(unsigned int); ++extern void enable_irq(unsigned int); ++ ++// #include ++#include ++ ++#define SYS_IRQS 32 ++#define NR_IRQS SYS_IRQS ++ ++/* ++ * Interrupt source definitions ++ * General interrupt sources are the level 1-7. ++ * Adding an interrupt service routine for one of these sources ++ * results in the addition of that routine to a chain of routines. ++ * Each one is called in succession. Each individual interrupt ++ * service routine should determine if the device associated with ++ * that routine requires service. ++ */ ++ ++#define IRQ01 (1) /* level 1 interrupt */ ++#define IRQ02 (2) /* level 2 interrupt */ ++#define IRQ03 (3) /* level 3 interrupt */ ++#define IRQ04 (4) /* level 4 interrupt */ ++#define IRQ05 (5) /* level 5 interrupt */ ++#define IRQ06 (6) /* level 6 interrupt */ ++#define IRQ07 (7) /* level 7 interrupt */ ++#define IRQ08 (8) /* level 8 interrupt */ ++#define IRQ09 (9) /* level 9 interrupt */ ++#define IRQ0A (10) /* level 10 interrupt */ ++#define IRQ0B (11) /* level 11 interrupt */ ++#define IRQ0C (12) /* level 12 interrupt */ ++#define IRQ0D (13) /* level 13 interrupt */ ++#define IRQ0E (14) /* level 14 interrupt */ ++#define IRQ0F (15) /* level 15 interrupt */ ++#define IRQ10 (16) /* level 16 interrupt */ ++#define IRQ12 (17) /* level 17 interrupt */ ++#define IRQ13 (18) /* level 18 interrupt */ ++#define IRQ14 (19) /* level 19 interrupt */ ++#define IRQ15 (20) /* level 20 interrupt */ ++#define IRQ16 (21) /* level 21 interrupt */ ++#define IRQ17 (22) /* level 22 interrupt */ ++#define IRQ18 (23) /* level 23 interrupt */ ++#define IRQ19 (24) /* level 24 interrupt */ ++#define IRQ1A (25) /* level 25 interrupt */ ++#define IRQ1B (26) /* level 26 interrupt */ ++#define IRQ1C (27) /* level 27 interrupt */ ++#define IRQ1D (28) /* level 28 interrupt */ ++#define IRQ1E (29) /* level 29 interrupt */ ++#define IRQ1F (30) /* level 30 interrupt */ ++#define IRQ20 (31) /* level 31 interrupt */ ++#define IRQ21 (32) /* level 32 interrupt */ ++ ++#define IRQMAX IRQ21 ++ ++/* ++ * "Generic" interrupt sources ++ */ ++ ++/* ++ * Machine specific interrupt sources. ++ * ++ * Adding an interrupt service routine for a source with this bit ++ * set indicates a special machine specific interrupt source. ++ * The machine specific files define these sources. ++ * ++ * Removed, they are not used by any one. ++ */ ++ ++/* ++ * various flags for request_irq() ++ */ ++#define IRQ_FLG_LOCK (0x0001) /* handler is not replaceable */ ++#define IRQ_FLG_REPLACE (0x0002) /* replace existing handler */ ++#define IRQ_FLG_FAST (0x0004) ++#define IRQ_FLG_SLOW (0x0008) ++#define IRQ_FLG_STD (0x8000) /* internally used */ ++ ++/* ++ * Functions to set and clear the interrupt mask. ++ */ ++ ++/* ++ * Use a zero to clean the bit. ++ */ ++static inline void clrimr(int mask) ++{ ++ int flags; ++ ++ local_irq_save(flags); ++ __asm__ __volatile__( ++ "rdctl r8, ienable\n" ++ "and r8,r8,%0\n" ++ "wrctl ienable, r8\n" ++ : /* No output */ ++ : "r" (mask) ++ : "r8"); ++ local_irq_restore(flags); ++} ++ ++/* ++ * Use a one to set the bit. ++ */ ++static inline void setimr(int mask) ++{ ++ int flags; ++ ++ local_irq_save(flags); ++ __asm__ __volatile__( ++ "rdctl r8, ienable\n" ++ "or r8,r8,%0\n" ++ "wrctl ienable, r8\n" ++ : /* No output */ ++ : "r" (mask) ++ : "r8"); ++ local_irq_restore(flags); ++} ++ ++/* ++ * This structure is used to chain together the ISRs for a particular ++ * interrupt source (if it supports chaining). ++ */ ++typedef struct irq_node { ++ irqreturn_t (*handler)(int, void *, struct pt_regs *); ++ unsigned long flags; ++ void *dev_id; ++ const char *devname; ++ struct irq_node *next; ++} irq_node_t; ++ ++/* ++ * This function returns a new irq_node_t ++ */ ++extern irq_node_t *new_irq_node(void); ++ ++/* ++ * This structure has only 4 elements for speed reasons ++ */ ++typedef struct irq_handler { ++ irqreturn_t (*handler)(int, void *, struct pt_regs *); ++ unsigned long flags; ++ void *dev_id; ++ const char *devname; ++} irq_handler_t; ++ ++/* count of spurious interrupts */ ++extern volatile unsigned int num_spurious; ++ ++#define disable_irq_nosync(i) disable_irq(i) ++ ++#ifndef irq_canonicalize ++#define irq_canonicalize(i) (i) ++#endif ++ ++#endif /* _NIOS2NOMMU_IRQ_H_ */ +--- linux/include/asm-nios2nommu/kmap_types.h ++++ linux/include/asm-nios2nommu/kmap_types.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_KMAP_TYPES_H ++#define _ASM_KMAP_TYPES_H ++ ++enum km_type { ++ KM_BOUNCE_READ, ++ KM_SKB_SUNRPC_DATA, ++ KM_SKB_DATA_SOFTIRQ, ++ KM_USER0, ++ KM_USER1, ++ KM_BIO_SRC_IRQ, ++ KM_BIO_DST_IRQ, ++ KM_PTE0, ++ KM_PTE1, ++ KM_IRQ0, ++ KM_IRQ1, ++ KM_SOFTIRQ0, ++ KM_SOFTIRQ1, ++ KM_TYPE_NR ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/linkage.h ++++ linux/include/asm-nios2nommu/linkage.h +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __ASM_LINKAGE_H ++#define __ASM_LINKAGE_H ++ ++#define __ALIGN .align 3 ++#define __ALIGN_STR ".align 3" ++ ++#endif +--- linux/include/asm-nios2nommu/linux_logo.h ++++ linux/include/asm-nios2nommu/linux_logo.h +@@ -0,0 +1,953 @@ ++/* $Id: linux_logo.h,v 1.3 2004/02/12 23:06:40 ken-h Exp $ ++ * include/asm-nios/linux_logo.h: This is a linux logo ++ * to be displayed on boot. ++ * ++ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu) ++ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) ++ * Copyright (C) 2004 Micrtronix Datacom Ltd. ++ * ++ * You can put anything here, but: ++ * LINUX_LOGO_COLORS has to be less than 224 ++ * image size has to be 80x80 ++ * values have to start from 0x20 ++ * (i.e. RGB(linux_logo_red[0], ++ * linux_logo_green[0], ++ * linux_logo_blue[0]) is color 0x20) ++ * BW image has to be 80x80 as well, with MS bit ++ * on the left ++ * Serial_console ascii image can be any size, ++ * but should contain %s to display the version ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++ ++#define linux_logo_banner "Linux/NIOS2 version " UTS_RELEASE ++ ++#define __HAVE_ARCH_LINUX_LOGO ++#define __HAVE_ARCH_LINUX_LOGO16 ++ ++#define LINUX_LOGO_COLORS 221 ++ ++#ifdef INCLUDE_LINUX_LOGO_DATA ++ ++unsigned char linux_logo_red[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79, ++ 0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7, ++ 0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8, ++ 0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6, ++ 0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee, ++ 0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c, ++ 0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e, ++ 0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c, ++ 0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfe, ++ 0xf6, 0xec, 0xfe, 0xd2, 0xea, 0xf5, 0xf2, 0xf2, ++ 0xe9, 0xee, 0xf6, 0xf2, 0xee, 0xf6, 0xda, 0xd4, ++ 0xfa, 0xca, 0xf2, 0xf6, 0xfe, 0xf2, 0xda, 0xe4, ++ 0xf6, 0xdd, 0xf2, 0xee, 0xfa, 0xf0, 0x12, 0x4a, ++ 0xd6, 0xf2, 0x8e, 0xf2, 0xf6, 0xf6, 0xb5, 0xf1, ++ 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16, 0x9a, ++ 0x2e, 0xd2, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62, ++ 0xda, 0xee, 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xe0, ++ 0xae, 0xbe, 0xce, 0xe2, 0xa3, 0x8e, 0x6d, 0x8e, ++ 0x32, 0xaf, 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, ++ 0x7a, 0x82, 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, ++ 0x6a, 0x52, 0x59, 0x64, 0x5e, ++}; ++ ++unsigned char linux_logo_green[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c, ++ 0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae, ++ 0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8, ++ 0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda, ++ 0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca, ++ 0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76, ++ 0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46, ++ 0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b, ++ 0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfa, ++ 0xea, 0xd7, 0xf6, 0xbc, 0xda, 0xde, 0xda, 0xe6, ++ 0xca, 0xd8, 0xea, 0xe0, 0xcc, 0xf2, 0xce, 0xb2, ++ 0xee, 0xa2, 0xd6, 0xe6, 0xf6, 0xd7, 0xc5, 0xb8, ++ 0xc6, 0xb9, 0xce, 0xde, 0xce, 0xc6, 0x0e, 0x36, ++ 0xae, 0xbe, 0x86, 0xba, 0xbe, 0xe6, 0x8e, 0xc4, ++ 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12, 0x7a, ++ 0x20, 0xc6, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46, ++ 0xce, 0xd6, 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa6, ++ 0x87, 0x96, 0xa2, 0xd6, 0x85, 0x7a, 0x6a, 0x6e, ++ 0x22, 0x76, 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, ++ 0x66, 0x62, 0x42, 0x50, 0x56, 0x42, 0x56, 0x56, ++ 0x56, 0x3e, 0x51, 0x52, 0x56, ++}; ++ ++unsigned char linux_logo_blue[] __initdata = { ++ 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, ++ 0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, ++ 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65, ++ 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, ++ 0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, ++ 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, ++ 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08, ++ 0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f, ++ 0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e, ++ 0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c, ++ 0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f, ++ 0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a, ++ 0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e, ++ 0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b, ++ 0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c, ++ 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xea, ++ 0xb6, 0x7c, 0xda, 0x8e, 0xa6, 0x87, 0x66, 0xb6, ++ 0x81, 0x6a, 0xc6, 0x9a, 0x5b, 0xd2, 0xb6, 0x6a, ++ 0xca, 0x45, 0x92, 0xb2, 0xca, 0x52, 0x8a, 0x3e, ++ 0x2e, 0x66, 0x66, 0xae, 0x3e, 0x47, 0x06, 0x0e, ++ 0x52, 0x36, 0x6a, 0x0e, 0x0e, 0xbe, 0x2c, 0x0e, ++ 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06, 0x2e, ++ 0x06, 0x9e, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06, ++ 0x9e, 0xae, 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x0a, ++ 0x32, 0x2e, 0x2a, 0xb2, 0x43, 0x48, 0x5f, 0x2e, ++ 0x06, 0x06, 0x07, 0x24, 0x06, 0x32, 0x06, 0x06, ++ 0x46, 0x2e, 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, ++ 0x3a, 0x22, 0x42, 0x34, 0x42, ++}; ++ ++unsigned char linux_logo[] __initdata = { ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, ++ 0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d, ++ 0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24, ++ 0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25, ++ 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, ++ 0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c, ++ 0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, ++ 0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31, ++ 0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34, ++ 0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36, ++ 0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22, ++ 0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25, ++ 0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22, ++ 0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36, ++ 0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, ++ 0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36, ++ 0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, ++ 0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36, ++ 0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23, ++ 0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21, ++ 0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b, ++ 0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26, ++ 0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d, ++ 0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32, ++ 0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a, ++ 0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b, ++ 0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37, ++ 0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58, ++ 0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35, ++ 0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, ++ 0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22, ++ 0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67, ++ 0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36, ++ 0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e, ++ 0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73, ++ 0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78, ++ 0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21, ++ 0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79, ++ 0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c, ++ 0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24, ++ 0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71, ++ 0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36, ++ 0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21, ++ 0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89, ++ 0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36, ++ 0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21, ++ 0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e, ++ 0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23, ++ 0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22, ++ 0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63, ++ 0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c, ++ 0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51, ++ 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21, ++ 0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97, ++ 0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98, ++ 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, ++ 0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32, ++ 0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50, ++ 0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48, ++ 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23, ++ 0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98, ++ 0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50, ++ 0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b, ++ 0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b, ++ 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48, ++ 0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, ++ 0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, ++ 0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34, ++ 0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52, ++ 0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c, ++ 0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c, ++ 0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b, ++ 0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93, ++ 0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28, ++ 0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99, ++ 0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93, ++ 0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36, ++ 0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x99, 0x9f, 0x52, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, ++ 0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30, ++ 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, ++ 0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36, ++ 0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48, ++ 0x47, 0x9f, 0x48, 0x48, 0x48, 0xa0, 0xa1, 0xa2, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36, ++ 0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f, ++ 0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36, ++ 0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48, ++ 0xa3, 0xa4, 0x48, 0x48, 0x9f, 0xa5, 0xa6, 0x9f, ++ 0x48, 0x48, 0x48, 0xa2, 0xa7, 0x47, 0x48, 0x48, ++ 0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23, ++ 0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d, ++ 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25, ++ 0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0xa8, 0xa1, 0x48, 0x48, 0x9f, 0xa9, 0xa6, 0x9f, ++ 0x48, 0x48, 0xaa, 0xa1, 0xa5, 0x9f, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30, ++ 0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32, ++ 0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a, ++ 0x36, 0x24, 0x4f, 0x48, 0x52, 0x52, 0x48, 0x48, ++ 0xab, 0xac, 0xa0, 0x48, 0xad, 0xa6, 0xa6, 0x9f, ++ 0x48, 0xa2, 0xa9, 0xa6, 0xa2, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30, ++ 0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21, ++ 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25, ++ 0x36, 0x3a, 0x48, 0x48, 0xae, 0xaf, 0x48, 0x48, ++ 0xad, 0xac, 0xa1, 0x9f, 0xa2, 0xa9, 0xa9, 0xa2, ++ 0x48, 0xab, 0x78, 0xa7, 0x48, 0x48, 0x48, 0x48, ++ 0x9f, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21, ++ 0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36, ++ 0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21, ++ 0x23, 0x43, 0x48, 0x48, 0xb0, 0xb1, 0xb2, 0x9f, ++ 0x48, 0xb3, 0xa5, 0xb3, 0xab, 0xa9, 0xa9, 0xb3, ++ 0xb4, 0xa9, 0xb5, 0xb0, 0x48, 0x48, 0xa0, 0xa5, ++ 0xa1, 0xad, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36, ++ 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, ++ 0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36, ++ 0x2e, 0x9b, 0x48, 0x48, 0x48, 0xb6, 0xb7, 0xa4, ++ 0xa2, 0xa7, 0xb5, 0x78, 0x6f, 0x6f, 0x6e, 0x6f, ++ 0xa9, 0xb5, 0xab, 0x48, 0x9f, 0xab, 0xa9, 0xa1, ++ 0xaa, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36, ++ 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, ++ 0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36, ++ 0x54, 0x48, 0x48, 0x48, 0x48, 0xa2, 0xa8, 0xa1, ++ 0xa5, 0xa6, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, ++ 0x6f, 0x78, 0xa5, 0xa0, 0xa0, 0x78, 0xa6, 0xa2, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, ++ 0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36, ++ 0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21, ++ 0x43, 0x48, 0x4b, 0xa2, 0x9f, 0x48, 0xa2, 0xa1, ++ 0xb8, 0x6e, 0x6e, 0xb5, 0x78, 0x6f, 0x78, 0x78, ++ 0x6e, 0x6f, 0x78, 0xb5, 0xa6, 0xa1, 0xa0, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21, ++ 0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25, ++ 0x52, 0x48, 0xa3, 0xb1, 0xb6, 0xb3, 0xaa, 0xac, ++ 0x68, 0x68, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, ++ 0x78, 0x6f, 0x6f, 0xb5, 0xa6, 0xb4, 0x48, 0x9f, ++ 0xb4, 0xb4, 0xa2, 0x9f, 0x48, 0x48, 0x4f, 0x21, ++ 0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a, ++ 0x47, 0x48, 0xa2, 0xb6, 0xaf, 0xb9, 0xba, 0x68, ++ 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x78, ++ 0x6f, 0x6f, 0xa6, 0x6f, 0xb5, 0xa0, 0xaa, 0xa6, ++ 0xa6, 0xa9, 0xb2, 0xb3, 0x48, 0x48, 0x4c, 0x22, ++ 0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39, ++ 0x9b, 0x48, 0x48, 0x48, 0xb0, 0xb0, 0xba, 0xb8, ++ 0x68, 0x68, 0x69, 0x78, 0x6f, 0xb5, 0x6f, 0xb5, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0xa5, 0xbb, 0xa9, ++ 0xa5, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23, ++ 0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31, ++ 0x9b, 0x48, 0x48, 0x48, 0x48, 0x9f, 0xac, 0x68, ++ 0xbc, 0x6e, 0x6e, 0x6e, 0xb5, 0x6f, 0x6e, 0x6f, ++ 0x6f, 0x78, 0x78, 0xb5, 0xb5, 0xa5, 0x9f, 0x9f, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22, ++ 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d, ++ 0x9b, 0x48, 0x48, 0xb0, 0xaa, 0xb3, 0xbd, 0xb8, ++ 0xb8, 0x68, 0x6e, 0x6e, 0xb5, 0x6f, 0x78, 0x6e, ++ 0x78, 0x6f, 0x78, 0x78, 0xb5, 0xa9, 0xa2, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, ++ 0x24, 0x27, 0xbe, 0x24, 0x25, 0x28, 0x21, 0x36, ++ 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25, ++ 0x39, 0x4d, 0xbf, 0x84, 0x81, 0x57, 0x21, 0x39, ++ 0x52, 0x48, 0x48, 0x62, 0xb1, 0xc0, 0xc1, 0xc1, ++ 0xb8, 0xb8, 0x68, 0xbc, 0x6e, 0x6e, 0x6e, 0x78, ++ 0x78, 0x78, 0x78, 0x6e, 0x78, 0xa9, 0xa0, 0xab, ++ 0xb3, 0xa2, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28, ++ 0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30, ++ 0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30, ++ 0x2d, 0xc2, 0x7a, 0xc3, 0xc4, 0xc4, 0x7f, 0x22, ++ 0x51, 0x52, 0x48, 0x48, 0xb0, 0xaa, 0xa8, 0xbd, ++ 0x68, 0xb8, 0xb8, 0x68, 0x68, 0x6e, 0x6e, 0x6f, ++ 0x6e, 0x6e, 0xb5, 0x6e, 0x78, 0xab, 0xab, 0xb5, ++ 0x78, 0xa6, 0xb3, 0xc5, 0xac, 0xac, 0xc6, 0x61, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32, ++ 0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31, ++ 0x4d, 0x91, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0x5a, ++ 0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0xb0, 0x64, ++ 0xc1, 0xb8, 0xb8, 0xb8, 0x68, 0x71, 0x6e, 0x6e, ++ 0x6f, 0x71, 0x6f, 0x6f, 0xa6, 0xa0, 0x9f, 0xb4, ++ 0xb4, 0xa0, 0xa1, 0xb7, 0xc7, 0x69, 0x66, 0xc8, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25, ++ 0x83, 0xc9, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a, ++ 0x60, 0x85, 0xca, 0xcb, 0xc4, 0xc4, 0xc4, 0x82, ++ 0x86, 0x36, 0x32, 0x3f, 0xa2, 0xa4, 0xa8, 0xa9, ++ 0xb8, 0xb8, 0xb8, 0xb8, 0x68, 0x6e, 0x6e, 0x6e, ++ 0x6e, 0x71, 0x6f, 0x71, 0xa6, 0xb4, 0x9f, 0x9f, ++ 0x48, 0x48, 0x48, 0xcc, 0xc3, 0xc7, 0xcd, 0xce, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57, ++ 0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x23, 0x30, 0x31, 0xcf, 0x91, 0x7e, 0x90, 0x90, ++ 0x8b, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0x5d, 0xd0, 0x36, 0x24, 0xd1, 0xb1, 0xaf, 0xaa, ++ 0xba, 0xb8, 0x68, 0x68, 0x68, 0x71, 0x6e, 0x6e, ++ 0x6e, 0x6f, 0x6e, 0x78, 0xa1, 0xa9, 0xa1, 0xb0, ++ 0x9f, 0x9b, 0x99, 0xcc, 0x64, 0x5c, 0x8b, 0xd0, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d, ++ 0x82, 0x5c, 0xd2, 0x2a, 0x23, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x24, 0x2b, 0xcf, 0x8b, 0x5b, 0x76, 0x5b, 0x5b, ++ 0x7b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc7, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48, ++ 0xa2, 0xa8, 0xb7, 0xc1, 0xb8, 0x68, 0x68, 0xbc, ++ 0x68, 0x6e, 0xb5, 0xb4, 0xb4, 0xab, 0xb5, 0xa1, ++ 0xb0, 0x4f, 0x3f, 0xd3, 0x7b, 0x7b, 0x85, 0x80, ++ 0xbe, 0x36, 0x36, 0x36, 0x21, 0xd4, 0x7e, 0x7b, ++ 0x64, 0x64, 0xd5, 0x35, 0x24, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x31, 0xd6, 0x5b, 0x64, 0xc3, 0xc3, 0xcb, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0x66, 0xd7, 0x36, 0x36, 0x36, 0x2c, 0x4b, ++ 0xd8, 0xd9, 0xb3, 0xa8, 0xbd, 0xbd, 0xbd, 0xbd, ++ 0xa9, 0xab, 0xb3, 0xa5, 0xa2, 0x9f, 0xa2, 0xa1, ++ 0x6a, 0x9a, 0x3f, 0xda, 0x76, 0x76, 0x7a, 0x63, ++ 0xdb, 0xdc, 0x86, 0xdc, 0xdd, 0x90, 0x5b, 0x64, ++ 0xc3, 0xc3, 0xde, 0x2d, 0x27, 0x23, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x26, 0x2d, 0x91, 0x5b, 0x64, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc7, 0x83, 0xce, 0x36, 0x36, 0x36, 0x30, ++ 0xb1, 0xd9, 0x48, 0xa1, 0xb2, 0xb0, 0xb0, 0xb3, ++ 0xa2, 0x48, 0xa7, 0xbd, 0xa9, 0xa2, 0x48, 0x9f, ++ 0xaa, 0x9a, 0x3f, 0xb1, 0x5b, 0x7b, 0xdf, 0x85, ++ 0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xc3, 0xc4, ++ 0xc4, 0xcb, 0x5d, 0xd5, 0x39, 0x26, 0x23, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2d, 0xe0, 0xdf, 0x64, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc7, 0x88, 0x36, 0x36, 0x36, 0x36, ++ 0x2d, 0x9b, 0x48, 0xb9, 0xaf, 0xa2, 0xa2, 0xb9, ++ 0xa8, 0x9f, 0x48, 0xa7, 0xb7, 0xd9, 0x48, 0x48, ++ 0x9b, 0x45, 0x3f, 0xe1, 0x6d, 0x7b, 0xca, 0xdf, ++ 0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc3, 0xe2, 0x37, 0x35, 0x26, 0x23, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2e, 0xe0, 0x7a, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc7, 0x72, 0x73, 0x36, 0x36, 0x36, ++ 0x24, 0x52, 0x48, 0xa3, 0xaf, 0x9f, 0x48, 0xb6, ++ 0xaf, 0xa2, 0x48, 0x9f, 0xe3, 0xd8, 0x48, 0x48, ++ 0x48, 0x46, 0x42, 0xd6, 0x7a, 0x7b, 0x64, 0x7b, ++ 0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xc3, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xcb, 0x64, 0xe2, 0x4d, 0x2c, 0x27, ++ 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x25, 0x31, 0xe4, 0x8b, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc7, 0x89, 0xbe, 0x36, 0x36, ++ 0x32, 0x47, 0x48, 0x4f, 0xa0, 0x48, 0x48, 0xe3, ++ 0x92, 0x9f, 0x48, 0x9f, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xc3, 0xcb, ++ 0xc3, 0x64, 0x64, 0xc3, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x5d, 0xe5, 0x2c, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x25, 0x31, 0xe4, 0x85, 0x7b, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x57, 0x27, 0x4d, ++ 0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x99, 0x34, 0xbe, 0xdb, 0x7a, 0x7b, 0xc3, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0xe4, ++ 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, ++ 0x26, 0x2d, 0xe4, 0x85, 0x7b, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc7, 0x5f, 0x92, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44, ++ 0x35, 0x36, 0xce, 0xdd, 0x7a, 0x7b, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0xc3, 0xe1, ++ 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x30, 0x2f, 0xd6, 0x8b, 0x7b, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x89, 0x45, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25, ++ 0x36, 0x36, 0x61, 0xdb, 0x6d, 0x64, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0xdf, 0xe5, ++ 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0xe6, 0x63, 0xdf, 0xc3, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x72, 0x81, 0xe7, ++ 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, ++ 0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36, ++ 0x36, 0x36, 0xe8, 0x8f, 0x6d, 0x64, 0xcb, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc3, 0xca, 0x8b, 0xcf, 0x2c, ++ 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x35, 0x96, 0x75, 0xca, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0x81, 0xdb, ++ 0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b, ++ 0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x73, 0xdb, 0x7a, 0x7b, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0x64, 0x76, 0x7a, 0x91, 0xd5, 0x31, 0x30, ++ 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, ++ 0x39, 0x97, 0x75, 0xdf, 0x7b, 0x64, 0xc3, 0xc3, ++ 0xcb, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x7b, 0x7a, 0xe9, ++ 0xea, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30, ++ 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xea, 0xdd, 0x8b, 0x7b, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x64, 0x64, ++ 0x76, 0x85, 0xe0, 0xd5, 0x34, 0x2b, 0x27, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, ++ 0x33, 0xeb, 0x63, 0x7e, 0x7a, 0x6d, 0xdf, 0x5b, ++ 0x76, 0x7b, 0x64, 0x64, 0xc3, 0xcb, 0xc4, 0xc4, ++ 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x76, 0x85, 0xdb, ++ 0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xec, 0xdd, 0x75, 0x76, 0xc3, 0xc4, ++ 0xc4, 0xc4, 0xcb, 0xc3, 0x64, 0x76, 0xdf, 0x8b, ++ 0xd6, 0xd5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, ++ 0x27, 0x31, 0xed, 0xeb, 0xdd, 0x74, 0x63, 0x90, ++ 0x7e, 0x75, 0x8b, 0x6d, 0xdf, 0x76, 0x64, 0xc3, ++ 0xcb, 0xcb, 0xcb, 0xcb, 0x64, 0x7a, 0x84, 0xee, ++ 0x79, 0xbe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x21, 0xea, 0xee, 0x63, 0x6d, 0x7b, 0x64, ++ 0xcb, 0xc3, 0x64, 0x7b, 0xdf, 0x75, 0x63, 0x96, ++ 0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x28, 0x27, 0x35, 0x2d, 0x41, 0xd5, 0xe7, 0x8f, ++ 0xdb, 0xdd, 0xe9, 0x74, 0x84, 0x90, 0x85, 0x6d, ++ 0x5b, 0x7b, 0x7b, 0xca, 0x6d, 0x90, 0xdb, 0xef, ++ 0xec, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36, ++ 0x36, 0x21, 0xd4, 0x80, 0xe9, 0x7e, 0x6d, 0x76, ++ 0xca, 0x76, 0x6d, 0x85, 0x63, 0xdb, 0xd5, 0x34, ++ 0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f, ++ 0x41, 0xf0, 0xf1, 0x6c, 0x80, 0xee, 0xdb, 0x74, ++ 0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xef, 0x79, ++ 0xe8, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d, ++ 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38, ++ 0x4d, 0x37, 0xf2, 0xf3, 0x8f, 0x74, 0x63, 0x7e, ++ 0x75, 0x7e, 0x63, 0xe9, 0x88, 0xe6, 0x31, 0x2a, ++ 0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30, ++ 0x33, 0x39, 0x2e, 0x51, 0x41, 0xd2, 0x6c, 0xf3, ++ 0x80, 0xee, 0xee, 0xee, 0xf4, 0xf3, 0xd7, 0xf5, ++ 0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27, ++ 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a, ++ 0x2b, 0x34, 0xf6, 0xec, 0xf7, 0x8f, 0xdd, 0xe9, ++ 0xe9, 0xdd, 0xee, 0x6c, 0x41, 0x39, 0x27, 0x28, ++ 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, ++ 0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41, ++ 0xf8, 0xd7, 0x79, 0x79, 0x79, 0xec, 0xf9, 0x51, ++ 0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22, ++ 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, ++ 0x24, 0x2a, 0x31, 0xfa, 0xea, 0x79, 0xf3, 0x80, ++ 0xf7, 0xdc, 0xfb, 0x2f, 0x35, 0x26, 0x23, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b, ++ 0x31, 0x2f, 0xf6, 0xfa, 0xfa, 0x2f, 0x2e, 0x33, ++ 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x21, 0x28, 0x27, 0x35, 0x34, 0xfa, 0xfa, 0xfa, ++ 0xfc, 0xf6, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28, ++ 0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28, ++ 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35, ++ 0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, ++ 0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24, ++ 0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++}; ++ ++unsigned char linux_logo16[1]; ++ ++#endif /* INCLUDE_LINUX_LOGO_DATA */ ++ ++#include ++ +--- linux/include/asm-nios2nommu/local.h ++++ linux/include/asm-nios2nommu/local.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_LOCAL_H ++#define __NIOS2NOMMU_LOCAL_H ++ ++#include ++ ++#endif /* __NIOS2NOMMU_LOCAL_H */ +--- linux/include/asm-nios2nommu/mc146818rtc.h ++++ linux/include/asm-nios2nommu/mc146818rtc.h +@@ -0,0 +1,29 @@ ++/* ++ * Machine dependent access functions for RTC registers. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2_MC146818RTC_H ++#define _NIOS2_MC146818RTC_H ++ ++/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */ ++ ++#endif /* _NIOS2_MC146818RTC_H */ +--- linux/include/asm-nios2nommu/mman.h ++++ linux/include/asm-nios2nommu/mman.h +@@ -0,0 +1,68 @@ ++/* ++ * Copied from the m68k port. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_MMAN_H__ ++#define __NIOS2_MMAN_H__ ++ ++#define PROT_READ 0x1 /* page can be read */ ++#define PROT_WRITE 0x2 /* page can be written */ ++#define PROT_EXEC 0x4 /* page can be executed */ ++#define PROT_SEM 0x8 /* page may be used for atomic ops */ ++#define PROT_NONE 0x0 /* page can not be accessed */ ++#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ ++#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */ ++ ++#define MAP_SHARED 0x01 /* Share changes */ ++#define MAP_PRIVATE 0x02 /* Changes are private */ ++#define MAP_TYPE 0x0f /* Mask for type of mapping */ ++#define MAP_FIXED 0x10 /* Interpret addr exactly */ ++#define MAP_ANONYMOUS 0x20 /* don't use a file */ ++ ++#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ ++#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ ++#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ ++#define MAP_LOCKED 0x2000 /* pages are locked */ ++#define MAP_NORESERVE 0x4000 /* don't check for reservations */ ++#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ ++#define MAP_NONBLOCK 0x10000 /* do not block on IO */ ++ ++#define MS_ASYNC 1 /* sync memory asynchronously */ ++#define MS_INVALIDATE 2 /* invalidate the caches */ ++#define MS_SYNC 4 /* synchronous memory sync */ ++ ++#define MCL_CURRENT 1 /* lock all current mappings */ ++#define MCL_FUTURE 2 /* lock all future mappings */ ++ ++#define MADV_NORMAL 0x0 /* default page-in behavior */ ++#define MADV_RANDOM 0x1 /* page-in minimum required */ ++#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */ ++#define MADV_WILLNEED 0x3 /* pre-fault pages */ ++#define MADV_DONTNEED 0x4 /* discard these pages */ ++ ++/* compatibility flags */ ++#define MAP_ANON MAP_ANONYMOUS ++#define MAP_FILE 0 ++ ++#endif /* __NIOS2_MMAN_H__ */ ++ +--- linux/include/asm-nios2nommu/mmu.h ++++ linux/include/asm-nios2nommu/mmu.h +@@ -0,0 +1,47 @@ ++/* ++ * ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_MMU_H ++#define __NIOS2NOMMU_MMU_H ++ ++/* Copyright (C) 2002, David McCullough */ ++ ++struct mm_rblock_struct { ++ int size; ++ int refcount; ++ void *kblock; ++}; ++ ++struct mm_tblock_struct { ++ struct mm_rblock_struct *rblock; ++ struct mm_tblock_struct *next; ++}; ++ ++typedef struct { ++ struct mm_tblock_struct tblock; ++ unsigned long end_brk; ++} mm_context_t; ++ ++#endif /* __NIOS2NOMMU_MMU_H */ +--- linux/include/asm-nios2nommu/mmu_context.h ++++ linux/include/asm-nios2nommu/mmu_context.h +@@ -0,0 +1,58 @@ ++/* ++ * ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2NOMMU_MMU_CONTEXT_H ++#define __NIOS2NOMMU_MMU_CONTEXT_H ++ ++// #include ++#include ++#include ++#include ++ ++static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) ++{ ++} ++ ++extern inline int ++init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ // mm->context = virt_to_phys(mm->pgd); ++ return(0); ++} ++ ++#define destroy_context(mm) do { } while(0) ++ ++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) ++{ ++} ++ ++#define deactivate_mm(tsk,mm) do { } while (0) ++ ++extern inline void activate_mm(struct mm_struct *prev_mm, ++ struct mm_struct *next_mm) ++{ ++} ++ ++#endif +--- linux/include/asm-nios2nommu/module.h ++++ linux/include/asm-nios2nommu/module.h +@@ -0,0 +1,36 @@ ++#ifndef _NIOS2_MODULE_H ++#define _NIOS2_MODULE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/module.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++struct mod_arch_specific ++{ ++}; ++ ++#define Elf_Shdr Elf32_Shdr ++#define Elf_Sym Elf32_Sym ++#define Elf_Ehdr Elf32_Ehdr ++ ++#endif /* _NIOS_MODULE_H */ +--- linux/include/asm-nios2nommu/msgbuf.h ++++ linux/include/asm-nios2nommu/msgbuf.h +@@ -0,0 +1,56 @@ ++/* ++ * Taken from the m68k. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_MSGBUF_H ++#define _NIOS2_MSGBUF_H ++ ++/* ++ * The msqid64_ds structure for nios2 architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct msqid64_ds { ++ struct ipc64_perm msg_perm; ++ __kernel_time_t msg_stime; /* last msgsnd time */ ++ unsigned long __unused1; ++ __kernel_time_t msg_rtime; /* last msgrcv time */ ++ unsigned long __unused2; ++ __kernel_time_t msg_ctime; /* last change time */ ++ unsigned long __unused3; ++ unsigned long msg_cbytes; /* current number of bytes on queue */ ++ unsigned long msg_qnum; /* number of messages in queue */ ++ unsigned long msg_qbytes; /* max number of bytes on queue */ ++ __kernel_pid_t msg_lspid; /* pid of last msgsnd */ ++ __kernel_pid_t msg_lrpid; /* last receive pid */ ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++#endif /* _NIOS2_MSGBUF_H */ ++ +--- linux/include/asm-nios2nommu/namei.h ++++ linux/include/asm-nios2nommu/namei.h +@@ -0,0 +1,36 @@ ++/* ++ * linux/include/asm-nios/namei.h ++ * Moved from m68k version ++ * Included from linux/fs/namei.c ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef __NIOS2_NAMEI_H ++#define __NIOS2_NAMEI_H ++ ++/* This dummy routine maybe changed to something useful ++ * for /usr/gnemul/ emulation stuff. ++ * Look at asm-sparc/namei.h for details. ++ */ ++ ++#define __emul_prefix() NULL ++ ++#endif +--- linux/include/asm-nios2nommu/ndma.h ++++ linux/include/asm-nios2nommu/ndma.h +@@ -0,0 +1,64 @@ ++#ifndef __NDMA_H__ ++ #define __NDMA_H__ ++ ++ #ifndef __ASSEMBLY__ ++ ++// DMA Registers ++typedef volatile struct ++{ ++ int np_dmastatus; // status register ++ int np_dmareadaddress; // read address ++ int np_dmawriteaddress; // write address ++ int np_dmalength; // length in bytes ++ int np_dmareserved1; // reserved ++ int np_dmareserved2; // reserved ++ int np_dmacontrol; // control register ++ int np_dmareserved3; // control register alternate ++} np_dma; ++ ++// DMA Register Bits ++enum ++{ ++ np_dmacontrol_byte_bit = 0, // Byte transaction ++ np_dmacontrol_hw_bit = 1, // Half-word transaction ++ np_dmacontrol_word_bit = 2, // Word transaction ++ np_dmacontrol_go_bit = 3, // enable execution ++ np_dmacontrol_i_en_bit = 4, // enable interrupt ++ np_dmacontrol_reen_bit = 5, // Enable read end-of-packet ++ np_dmacontrol_ween_bit = 6, // Enable write end-of-packet ++ np_dmacontrol_leen_bit = 7, // Enable length=0 transaction end ++ np_dmacontrol_rcon_bit = 8, // Read from a fixed address ++ np_dmacontrol_wcon_bit = 9, // Write to a fixed address ++ np_dmacontrol_doubleword_bit = 10, // Double-word transaction ++ np_dmacontrol_quadword_bit = 11, // Quad-word transaction ++ ++ np_dmastatus_done_bit = 0, // 1 when done. Status write clears. ++ np_dmastatus_busy_bit = 1, // 1 when busy. ++ np_dmastatus_reop_bit = 2, // read-eop received ++ np_dmastatus_weop_bit = 3, // write-eop received ++ np_dmastatus_len_bit = 4, // requested length transacted ++ ++ np_dmacontrol_byte_mask = (1 << 0), // Byte transaction ++ np_dmacontrol_hw_mask = (1 << 1), // Half-word transaction ++ np_dmacontrol_word_mask = (1 << 2), // Word transaction ++ np_dmacontrol_go_mask = (1 << 3), // enable execution ++ np_dmacontrol_i_en_mask = (1 << 4), // enable interrupt ++ np_dmacontrol_reen_mask = (1 << 5), // Enable read end-of-packet ++ np_dmacontrol_ween_mask = (1 << 6), // Enable write end-of-packet ++ np_dmacontrol_leen_mask = (1 << 7), // Enable length=0 transaction end ++ np_dmacontrol_rcon_mask = (1 << 8), // Read from a fixed address ++ np_dmacontrol_wcon_mask = (1 << 9), // Write to a fixed address ++ np_dmacontrol_doubleword_mask = (1 << 10), // Double-word transaction ++ np_dmacontrol_quadword_mask = (1 << 11), // Quad-word transaction ++ ++ np_dmastatus_done_mask = (1 << 0), // 1 when done. Status write clears. ++ np_dmastatus_busy_mask = (1 << 1), // 1 when busy. ++ np_dmastatus_reop_mask = (1 << 2), // read-eop received ++ np_dmastatus_weop_mask = (1 << 3), // write-eop received ++ np_dmastatus_len_mask = (1 << 4), // requested length transacted ++}; ++ ++ #endif /* __ASSEMBLY__ */ ++ ++#endif ++/* End of File */ +--- linux/include/asm-nios2nommu/nios.h ++++ linux/include/asm-nios2nommu/nios.h +@@ -0,0 +1,7 @@ ++#ifndef __NIOS_H__ ++#define __NIOS_H__ ++ ++#include "nios2_system.h" ++ ++#endif ++ +--- linux/include/asm-nios2nommu/page.h ++++ linux/include/asm-nios2nommu/page.h +@@ -0,0 +1,135 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_PAGE_H ++#define _NIOS2_PAGE_H ++ ++/* copied from m68knommu arch */ ++// #include ++ ++/* PAGE_SHIFT determines the page size */ ++ ++#define PAGE_SHIFT (12) ++#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#define PAGE_MASK (~(PAGE_SIZE-1)) ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#if PAGE_SHIFT < 13 ++#define THREAD_SIZE (8192) ++#else ++#define THREAD_SIZE PAGE_SIZE ++#endif ++ ++#ifndef __ASSEMBLY__ ++ ++#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) ++#define free_user_page(page, addr) free_page(addr) ++ ++#define clear_page(page) memset((page), 0, PAGE_SIZE) ++#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) ++ ++#define clear_user_page(page, vaddr, pg) clear_page(page) ++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) ++ ++/* ++ * These are used to make use of C type-checking.. ++ */ ++typedef struct { unsigned long pte; } pte_t; ++typedef struct { unsigned long pmd[16]; } pmd_t; ++typedef struct { unsigned long pgd; } pgd_t; ++typedef struct { unsigned long pgprot; } pgprot_t; ++ ++#define pte_val(x) ((x).pte) ++#define pmd_val(x) ((&x)->pmd[0]) ++#define pgd_val(x) ((x).pgd) ++#define pgprot_val(x) ((x).pgprot) ++ ++#define __pte(x) ((pte_t) { (x) } ) ++#define __pmd(x) ((pmd_t) { (x) } ) ++#define __pgd(x) ((pgd_t) { (x) } ) ++#define __pgprot(x) ((pgprot_t) { (x) } ) ++ ++/* to align the pointer to the (next) page boundary */ ++#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) ++ ++/* Pure 2^n version of get_order */ ++extern __inline__ int get_order(unsigned long size) ++{ ++ int order; ++ ++ size = (size-1) >> (PAGE_SHIFT-1); ++ order = -1; ++ do { ++ size >>= 1; ++ order++; ++ } while (size); ++ return order; ++} ++ ++extern unsigned long memory_start; ++extern unsigned long memory_end; ++ ++#endif /* !__ASSEMBLY__ */ ++#include ++#define PAGE_OFFSET ((int)(nasys_program_mem)) ++ ++#ifndef __ASSEMBLY__ ++ ++#define __pa(vaddr) virt_to_phys((void *)vaddr) ++#define __va(paddr) phys_to_virt((unsigned long)paddr) ++ ++#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) ++ ++#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) ++#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) ++ ++#define virt_to_page(addr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) ++#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) ++#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) ++ ++#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) ++#define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) ++ ++#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ ++ ((void *)(kaddr) < (void *)memory_end)) ++ ++#ifdef CONFIG_NO_KERNEL_MSG ++#define BUG_PRINT() ++#else ++#define BUG_PRINT() printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__) ++#endif ++ ++#ifdef na_cpu_oci_core ++#define BUG_PANIC() asm volatile ("break") /* drop to debugger */ ++#else ++// #define BUG_PANIC() while(1) ++#define BUG_PANIC() panic("BUG!") ++#endif ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS2_PAGE_H */ +--- linux/include/asm-nios2nommu/param.h ++++ linux/include/asm-nios2nommu/param.h +@@ -0,0 +1,49 @@ ++#ifndef _NIOS_PARAM_H ++#define _NIOS_PARAM_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/param.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifndef HZ ++#define HZ 100 ++#endif ++ ++#ifdef __KERNEL__ ++#define USER_HZ HZ ++#define CLOCKS_PER_SEC (USER_HZ) ++#endif ++ ++#define EXEC_PAGESIZE 4096 ++ ++#ifndef NGROUPS ++#define NGROUPS 32 ++#endif ++ ++#ifndef NOGROUP ++#define NOGROUP (-1) ++#endif ++ ++#define MAXHOSTNAMELEN 64 /* max length of hostname */ ++ ++#endif +--- linux/include/asm-nios2nommu/pci.h ++++ linux/include/asm-nios2nommu/pci.h +@@ -0,0 +1,75 @@ ++#ifndef _ASM_NIOS2NOMMU_PCI_H ++#define _ASM_NIOS2NOMMU_PCI_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/pci.h ++ * ++ * Derived from asm-m68k/pci_m68k.h ++ * - m68k specific PCI declarations, by Wout Klaren. ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++struct pci_ops; ++ ++/* ++ * Structure with hardware dependent information and functions of the ++ * PCI bus. ++ */ ++ ++struct pci_bus_info ++{ ++ /* ++ * Resources of the PCI bus. ++ */ ++ ++ struct resource mem_space; ++ struct resource io_space; ++ ++ /* ++ * System dependent functions. ++ */ ++ ++ struct pci_ops *m68k_pci_ops; ++ ++ void (*fixup)(int pci_modify); ++ void (*conf_device)(struct pci_dev *dev); ++}; ++ ++#define pcibios_assign_all_busses() 0 ++ ++extern inline void pcibios_set_master(struct pci_dev *dev) ++{ ++ /* No special bus mastering setup handling */ ++} ++ ++extern inline void pcibios_penalize_isa_irq(int irq) ++{ ++ /* We don't do dynamic PCI IRQ allocation */ ++} ++ ++/* The PCI address space does equal the physical memory ++ * address space. The networking and block device layers use ++ * this boolean for bounce buffer decisions. ++ */ ++#define PCI_DMA_BUS_IS_PHYS (1) ++ ++#endif /* _ASM_NIOS2NOMMU_PCI_H */ +--- linux/include/asm-nios2nommu/percpu.h ++++ linux/include/asm-nios2nommu/percpu.h +@@ -0,0 +1,30 @@ ++#ifndef __ARCH_NIOS2NOMMU_PERCPU__ ++#define __ARCH_NIOS2NOMMU_PERCPU__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/percpu.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* __ARCH_NIOS2NOMMU_PERCPU__ */ +--- linux/include/asm-nios2nommu/pgalloc.h ++++ linux/include/asm-nios2nommu/pgalloc.h +@@ -0,0 +1,32 @@ ++#ifndef _NIOS2NOMMU_PGALLOC_H ++#define _NIOS2NOMMU_PGALLOC_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/pgalloc.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#define check_pgt_cache() do { } while (0) ++ ++#endif /* _NIOS2NOMMU_PGALLOC_H */ +--- linux/include/asm-nios2nommu/pgtable.h ++++ linux/include/asm-nios2nommu/pgtable.h +@@ -0,0 +1,100 @@ ++#ifndef _NIOS_PGTABLE_H ++#define _NIOS_PGTABLE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/pgtable.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++//vic - this bit copied from m68knommu version ++// #include ++#include ++#include ++ ++typedef pte_t *pte_addr_t; ++ ++#define pgd_present(pgd) (1) /* pages are always present on NO_MM */ ++#define pgd_none(pgd) (0) ++#define pgd_bad(pgd) (0) ++#define pgd_clear(pgdp) ++#define kern_addr_valid(addr) (1) ++#define pmd_offset(a, b) ((void *)0) ++ ++#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */ ++#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */ ++//vic - this bit copied from m68knommu version ++ ++extern void paging_init(void); ++#define swapper_pg_dir ((pgd_t *) 0) ++ ++#define __swp_type(x) (0) ++#define __swp_offset(x) (0) ++#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) ++#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) ++#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) ++ ++static inline int pte_file(pte_t pte) { return 0; } ++ ++/* ++ * ZERO_PAGE is a global shared page that is always zero: used ++ * for zero-mapped memory areas etc.. ++ */ ++#define ZERO_PAGE(vaddr) (virt_to_page(0)) ++ ++extern unsigned int kobjsize(const void *objp); ++ ++/* ++ * No page table caches to initialise ++ */ ++#define pgtable_cache_init() do { } while (0) ++ ++extern inline void flush_cache_mm(struct mm_struct *mm) ++{ ++} ++ ++extern inline void flush_cache_range(struct mm_struct *mm, ++ unsigned long start, ++ unsigned long end) ++{ ++} ++ ++/* Push the page at kernel virtual address and clear the icache */ ++extern inline void flush_page_to_ram (unsigned long address) ++{ ++} ++ ++/* Push n pages at kernel virtual address and clear the icache */ ++extern inline void flush_pages_to_ram (unsigned long address, int n) ++{ ++} ++ ++/* ++ * All 32bit addresses are effectively valid for vmalloc... ++ * Sort of meaningless for non-VM targets. ++ */ ++#define VMALLOC_START 0 ++#define VMALLOC_END 0xffffffff ++ ++#endif /* _NIOS_PGTABLE_H */ +--- linux/include/asm-nios2nommu/pio_struct.h ++++ linux/include/asm-nios2nommu/pio_struct.h +@@ -0,0 +1,14 @@ ++// PIO Peripheral ++ ++// PIO Registers ++typedef volatile struct ++ { ++ int np_piodata; // read/write, up to 32 bits ++ int np_piodirection; // write/readable, up to 32 bits, 1->output bit ++ int np_piointerruptmask; // write/readable, up to 32 bits, 1->enable interrupt ++ int np_pioedgecapture; // read, up to 32 bits, cleared by any write ++ } np_pio; ++ ++// PIO Routines ++void nr_pio_showhex(int value); // shows low byte on pio named na_seven_seg_pio ++ +--- linux/include/asm-nios2nommu/poll.h ++++ linux/include/asm-nios2nommu/poll.h +@@ -0,0 +1,46 @@ ++#ifndef __NIOS2_POLL_H ++#define __NIOS2_POLL_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/poll.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define POLLIN 1 ++#define POLLPRI 2 ++#define POLLOUT 4 ++#define POLLERR 8 ++#define POLLHUP 16 ++#define POLLNVAL 32 ++#define POLLRDNORM 64 ++#define POLLWRNORM POLLOUT ++#define POLLRDBAND 128 ++#define POLLWRBAND 256 ++#define POLLMSG 0x0400 ++ ++struct pollfd { ++ int fd; ++ short events; ++ short revents; ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/posix_types.h ++++ linux/include/asm-nios2nommu/posix_types.h +@@ -0,0 +1,89 @@ ++#ifndef __ARCH_NIOS2_POSIX_TYPES_H ++#define __ARCH_NIOS2_POSIX_TYPES_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/posix_types.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This file is generally used by user-level software, so you need to ++ * be a little careful about namespace pollution etc. Also, we cannot ++ * assume GCC is being used. ++ */ ++ ++typedef unsigned long __kernel_ino_t; ++typedef unsigned short __kernel_mode_t; ++typedef unsigned short __kernel_nlink_t; ++typedef long __kernel_off_t; ++typedef int __kernel_pid_t; ++typedef unsigned short __kernel_ipc_pid_t; ++typedef unsigned short __kernel_uid_t; ++typedef unsigned short __kernel_gid_t; ++typedef unsigned int __kernel_size_t; ++typedef int __kernel_ssize_t; ++typedef int __kernel_ptrdiff_t; ++typedef long __kernel_time_t; ++typedef long __kernel_suseconds_t; ++typedef long __kernel_clock_t; ++typedef int __kernel_timer_t; ++typedef int __kernel_clockid_t; ++typedef int __kernel_daddr_t; ++typedef char * __kernel_caddr_t; ++typedef unsigned short __kernel_uid16_t; ++typedef unsigned short __kernel_gid16_t; ++typedef unsigned int __kernel_uid32_t; ++typedef unsigned int __kernel_gid32_t; ++ ++typedef unsigned short __kernel_old_uid_t; ++typedef unsigned short __kernel_old_gid_t; ++typedef unsigned short __kernel_old_dev_t; ++ ++#ifdef __GNUC__ ++typedef long long __kernel_loff_t; ++#endif ++ ++typedef struct { ++#if defined(__KERNEL__) || defined(__USE_ALL) ++ int val[2]; ++#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ ++ int __val[2]; ++#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ ++} __kernel_fsid_t; ++ ++#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) ++ ++#undef __FD_SET ++#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) ++ ++#undef __FD_CLR ++#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) ++ ++#undef __FD_ISSET ++#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) ++ ++#undef __FD_ZERO ++#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) ++ ++#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ ++ ++#endif +--- linux/include/asm-nios2nommu/preem_latency.h ++++ linux/include/asm-nios2nommu/preem_latency.h +@@ -0,0 +1,39 @@ ++#ifndef _ASM_PREEM_LATENCY_H ++#define _ASM_PREEM_LATENCY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/preem_latency.h ++ * ++ * timing support for preempt-stats patch ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#define readclock(low) \ ++do {\ ++ *(volatile unsigned long *)na_Counter_64_bit=1; \ ++ low=*(volatile unsigned long *)na_Counter_64_bit; \ ++} while (0) ++#define readclock_init() ++ ++#endif /* _ASM_PREEM_LATENCY_H */ +--- linux/include/asm-nios2nommu/processor.h ++++ linux/include/asm-nios2nommu/processor.h +@@ -0,0 +1,148 @@ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/processor.h ++ * ++ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) ++ * Copyright (C) 2001 Ken Hill (khill@microtronix.com) ++ * Vic Phillips (vic@microtronix.com) ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * hacked from: ++ * include/asm-sparc/processor.h ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * Nov/02/2003 dgt Fix task_size ++ * ++ ---------------------------------------------------------------------*/ ++ ++#ifndef __ASM_NIOS_PROCESSOR_H ++#define __ASM_NIOS_PROCESSOR_H ++ ++#define NIOS2_FLAG_KTHREAD 0x00000001 /* task is a kernel thread */ ++#define NIOS2_FLAG_COPROC 0x00000002 /* Thread used coprocess */ ++#define NIOS2_FLAG_DEBUG 0x00000004 /* task is being debugged */ ++ ++#define NIOS2_OP_NOP 0x1883a ++#define NIOS2_OP_BREAK 0x3da03a ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * Default implementation of macro that returns current ++ * instruction pointer ("program counter"). ++ */ ++#define current_text_addr() ({ __label__ _l; _l: &&_l;}) ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include /* for get_hi_limit */ ++ ++/* ++ * Bus types ++ */ ++#define EISA_bus 0 ++#define EISA_bus__is_a_macro /* for versions in ksyms.c */ ++#define MCA_bus 0 ++#define MCA_bus__is_a_macro /* for versions in ksyms.c */ ++ ++/* ++ * The nios has no problems with write protection ++ */ ++#define wp_works_ok 1 ++#define wp_works_ok__is_a_macro /* for versions in ksyms.c */ ++ ++/* Whee, this is STACK_TOP and the lowest kernel address too... */ ++#if 0 ++#define KERNBASE 0x00000000 /* First address the kernel will eventually be */ ++#define TASK_SIZE (KERNBASE) ++#define MAX_USER_ADDR TASK_SIZE ++#define MMAP_SEARCH_START (TASK_SIZE/3) ++#endif ++ ++#define TASK_SIZE ((unsigned int) nasys_program_mem_end) //...this is better... ++ ++/* ++ * This decides where the kernel will search for a free chunk of vm ++ * space during mmap's. We won't be using it ++ */ ++#define TASK_UNMAPPED_BASE 0 ++ ++/* The Nios processor specific thread struct. */ ++struct thread_struct { ++ struct pt_regs *kregs; ++ ++ /* For signal handling */ ++ unsigned long sig_address; ++ unsigned long sig_desc; ++ ++ /* Context switch saved kernel state. */ ++ unsigned long ksp; ++ unsigned long kpsr; ++ unsigned long kesr; ++ ++ /* Flags are defined below */ ++ ++ unsigned long flags; ++ int current_ds; ++ struct exec core_exec; /* just what it says. */ ++}; ++ ++#define INIT_MMAP { &init_mm, (0), (0), \ ++ __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC } ++ ++#define INIT_THREAD { \ ++ .kregs = 0, \ ++ .sig_address = 0, \ ++ .sig_desc = 0, \ ++ .ksp = 0, \ ++ .kpsr = 0, \ ++ .kesr = PS_S, \ ++ .flags = NIOS2_FLAG_KTHREAD, \ ++ .current_ds = __KERNEL_DS, \ ++ .core_exec = INIT_EXEC \ ++} ++ ++/* Free all resources held by a thread. */ ++extern void release_thread(struct task_struct *); ++ ++extern unsigned long thread_saved_pc(struct task_struct *t); ++ ++extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); ++ ++/* Prepare to copy thread state - unlazy all lazy status */ ++#define prepare_to_copy(tsk) do { } while (0) ++ ++extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); ++ ++unsigned long get_wchan(struct task_struct *p); ++ ++#define KSTK_EIP(tsk) ((tsk)->thread.kregs->ea) ++#define KSTK_ESP(tsk) ((tsk)->thread.kregs->sp) ++ ++#ifdef __KERNEL__ ++/* Allocation and freeing of basic task resources. */ ++ ++//;dgt2;#define alloc_task_struct() ((struct task_struct *) xx..see..linux..fork..xx __get_free_pages(GFP_KERNEL,1)) ++//;dgt2;#define get_task_struct(tsk) xx..see..linux..sched.h...atomic_inc(&mem_map[MAP_NR(tsk)].count) ++ ++#endif ++ ++#define cpu_relax() do { } while (0) ++#endif /* __ASSEMBLY__ */ ++#endif /* __ASM_NIOS_PROCESSOR_H */ +--- linux/include/asm-nios2nommu/ptrace.h ++++ linux/include/asm-nios2nommu/ptrace.h +@@ -0,0 +1,141 @@ ++/* ++ * Taken from the m68k port. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2NOMMU_PTRACE_H ++#define _NIOS2NOMMU_PTRACE_H ++ ++#ifndef __ASSEMBLY__ ++ ++#define PTR_R0 0 ++#define PTR_R1 1 ++#define PTR_R2 2 ++#define PTR_R3 3 ++#define PTR_R4 4 ++#define PTR_R5 5 ++#define PTR_R6 6 ++#define PTR_R7 7 ++#define PTR_R8 8 ++#define PTR_R9 9 ++#define PTR_R10 10 ++#define PTR_R11 11 ++#define PTR_R12 12 ++#define PTR_R13 13 ++#define PTR_R14 14 ++#define PTR_R15 15 ++#define PTR_R16 16 ++#define PTR_R17 17 ++#define PTR_R18 18 ++#define PTR_R19 19 ++#define PTR_R20 20 ++#define PTR_R21 21 ++#define PTR_R22 22 ++#define PTR_R23 23 ++#define PTR_R24 24 ++#define PTR_R25 25 ++#define PTR_GP 26 ++#define PTR_SP 27 ++#define PTR_FP 28 ++#define PTR_EA 29 ++#define PTR_BA 30 ++#define PTR_RA 31 ++#define PTR_STATUS 32 ++#define PTR_ESTATUS 33 ++#define PTR_BSTATUS 34 ++#define PTR_IENABLE 35 ++#define PTR_IPENDING 36 ++ ++/* this struct defines the way the registers are stored on the ++ stack during a system call. ++ ++ There is a fake_regs in setup.c that has to match pt_regs.*/ ++ ++struct pt_regs { ++ unsigned long r8; ++ unsigned long r9; ++ unsigned long r10; ++ unsigned long r11; ++ unsigned long r12; ++ unsigned long r13; ++ unsigned long r14; ++ unsigned long r15; ++ unsigned long r1; ++ unsigned long r2; ++ unsigned long r3; ++ unsigned long r4; ++ unsigned long r5; ++ unsigned long r6; ++ unsigned long r7; ++ unsigned long orig_r2; ++ unsigned long ra; ++ unsigned long fp; ++ unsigned long sp; ++ unsigned long gp; ++ unsigned long estatus; ++ unsigned long status_extension; ++ unsigned long ea; ++}; ++ ++ ++/* ++ * This is the extended stack used by signal handlers and the context ++ * switcher: it's pushed after the normal "struct pt_regs". ++ */ ++struct switch_stack { ++ unsigned long r16; ++ unsigned long r17; ++ unsigned long r18; ++ unsigned long r19; ++ unsigned long r20; ++ unsigned long r21; ++ unsigned long r22; ++ unsigned long r23; ++ unsigned long fp; ++ unsigned long gp; ++ unsigned long ra; ++}; ++ ++/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ ++#define PTRACE_GETREGS 12 ++#define PTRACE_SETREGS 13 ++#ifdef CONFIG_FPU ++#define PTRACE_GETFPREGS 14 ++#define PTRACE_SETFPREGS 15 ++#endif ++ ++#ifdef __KERNEL__ ++ ++#ifndef PS_S ++#define PS_S (0x00000001) ++#endif ++#ifndef PS_T ++#define PS_T (0x00000002) ++#endif ++ ++#define user_mode(regs) (!((regs)->status_extension & PS_S)) ++#define instruction_pointer(regs) ((regs)->ra) ++#define profile_pc(regs) instruction_pointer(regs) ++extern void show_regs(struct pt_regs *); ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASSEMBLY__ */ ++#endif /* _NIOS2NOMMU_PTRACE_H */ +--- linux/include/asm-nios2nommu/resource.h ++++ linux/include/asm-nios2nommu/resource.h +@@ -0,0 +1,73 @@ ++#ifndef _NIOS2NOMMU_RESOURCE_H ++#define _NIOS2NOMMU_RESOURCE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * Resource limits ++ * ++ * include/asm-nios2nommu/resource.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define RLIMIT_CPU 0 /* CPU time in ms */ ++#define RLIMIT_FSIZE 1 /* Maximum filesize */ ++#define RLIMIT_DATA 2 /* max data size */ ++#define RLIMIT_STACK 3 /* max stack size */ ++#define RLIMIT_CORE 4 /* max core file size */ ++#define RLIMIT_RSS 5 /* max resident set size */ ++#define RLIMIT_NPROC 6 /* max number of processes */ ++#define RLIMIT_NOFILE 7 /* max number of open files */ ++#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ ++#define RLIMIT_AS 9 /* address space limit */ ++#define RLIMIT_LOCKS 10 /* maximum file locks held */ ++#define RLIMIT_SIGPENDING 11 /* max number of pending signals */ ++#define RLIMIT_MSGQUEUE 12 /* maximum bytes in POSIX mqueues */ ++ ++#define RLIM_NLIMITS 13 ++ ++/* ++ * SuS says limits have to be unsigned. ++ * Which makes a ton more sense anyway. ++ */ ++#define RLIM_INFINITY (~0UL) ++ ++#ifdef __KERNEL__ ++ ++#define INIT_RLIMITS \ ++{ \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { _STK_LIM, RLIM_INFINITY }, \ ++ { 0, RLIM_INFINITY }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { 0, 0 }, \ ++ { INR_OPEN, INR_OPEN }, \ ++ { MLOCK_LIMIT, MLOCK_LIMIT }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { RLIM_INFINITY, RLIM_INFINITY }, \ ++ { MAX_SIGPENDING, MAX_SIGPENDING }, \ ++ { MQ_BYTES_MAX, MQ_BYTES_MAX }, \ ++} ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS2NOMMU_RESOURCE_H */ +--- linux/include/asm-nios2nommu/rmap.h ++++ linux/include/asm-nios2nommu/rmap.h +@@ -0,0 +1,2 @@ ++/* Do not need anything here */ ++ +--- linux/include/asm-nios2nommu/scatterlist.h ++++ linux/include/asm-nios2nommu/scatterlist.h +@@ -0,0 +1,40 @@ ++#ifndef _NIOS2NOMMU_SCATTERLIST_H ++#define _NIOS2NOMMU_SCATTERLIST_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/scatterlist.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++struct scatterlist { ++ struct page *page; ++ unsigned int offset; ++ dma_addr_t dma_address; ++ unsigned int length; ++}; ++ ++#define sg_dma_address(sg) ((sg)->dma_address) ++#define sg_dma_len(sg) ((sg)->length) ++ ++#define ISA_DMA_THRESHOLD (0xffffffff) ++ ++#endif /* !(_NIOS2NOMMU_SCATTERLIST_H) */ +--- linux/include/asm-nios2nommu/sections.h ++++ linux/include/asm-nios2nommu/sections.h +@@ -0,0 +1,30 @@ ++#ifndef _NIOS2NOMMU_SECTIONS_H ++#define _NIOS2NOMMU_SECTIONS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sections.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _NIOS2NOMMU_SECTIONS_H */ +--- linux/include/asm-nios2nommu/segment.h ++++ linux/include/asm-nios2nommu/segment.h +@@ -0,0 +1,75 @@ ++#ifndef _NIOS2NOMMU_SEGMENT_H ++#define _NIOS2NOMMU_SEGMENT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/segment.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* define constants */ ++/* Address spaces (FC0-FC2) */ ++#define USER_DATA (1) ++#ifndef __USER_DS ++#define __USER_DS (USER_DATA) ++#endif ++#define USER_PROGRAM (2) ++#define SUPER_DATA (5) ++#ifndef __KERNEL_DS ++#define __KERNEL_DS (SUPER_DATA) ++#endif ++#define SUPER_PROGRAM (6) ++#define CPU_SPACE (7) ++ ++#ifndef __ASSEMBLY__ ++ ++typedef struct { ++ unsigned long seg; ++} mm_segment_t; ++ ++#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) ++#define USER_DS MAKE_MM_SEG(__USER_DS) ++#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS) ++ ++/* ++ * Get/set the SFC/DFC registers for MOVES instructions ++ */ ++ ++static inline mm_segment_t get_fs(void) ++{ ++ return USER_DS; ++} ++ ++static inline mm_segment_t get_ds(void) ++{ ++ /* return the supervisor data space code */ ++ return KERNEL_DS; ++} ++ ++static inline void set_fs(mm_segment_t val) ++{ ++} ++ ++#define segment_eq(a,b) ((a).seg == (b).seg) ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* _NIOS2NOMMU_SEGMENT_H */ +--- linux/include/asm-nios2nommu/semaphore-helper.h ++++ linux/include/asm-nios2nommu/semaphore-helper.h +@@ -0,0 +1,101 @@ ++#ifndef _NIOS2NOMMU_SEMAPHORE_HELPER_H ++#define _NIOS2NOMMU_SEMAPHORE_HELPER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/semaphore.h ++ * ++ * SMP- and interrupt-safe semaphores helper functions. ++ * ++ * Derived from M68knommu ++ * ++ * (C) Copyright 1996 Linus Torvalds ++ * m68k version by Andreas Schwab ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++// #include ++ ++/* ++ * These two _must_ execute atomically wrt each other. ++ */ ++static inline void wake_one_more(struct semaphore * sem) ++{ ++ atomic_inc(&sem->waking); ++} ++ ++static inline int waking_non_zero(struct semaphore *sem) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 0; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 1; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++/* ++ * waking_non_zero_interruptible: ++ * 1 got the lock ++ * 0 go to sleep ++ * -EINTR interrupted ++ */ ++static inline int waking_non_zero_interruptible(struct semaphore *sem, ++ struct task_struct *tsk) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 0; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 1; ++ } else if (signal_pending(tsk)) { ++ atomic_inc(&sem->count); ++ ret = -EINTR; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++/* ++ * waking_non_zero_trylock: ++ * 1 failed to lock ++ * 0 got the lock ++ */ ++static inline int waking_non_zero_trylock(struct semaphore *sem) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ ret = 1; ++ if (atomic_read(&sem->waking) > 0) { ++ atomic_dec(&sem->waking); ++ ret = 0; ++ } else ++ atomic_inc(&sem->count); ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++#endif +--- linux/include/asm-nios2nommu/semaphore.h ++++ linux/include/asm-nios2nommu/semaphore.h +@@ -0,0 +1,155 @@ ++#ifndef _NIOS2NOMMU_SEMAPHORE_H ++#define _NIOS2NOMMU_SEMAPHORE_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/semaphore.h ++ * ++ * Interrupt-safe semaphores.. ++ * ++ * Derived from M68knommu ++ * ++ * (C) Copyright 1996 Linus Torvalds ++ * m68k version by Andreas Schwab ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#define RW_LOCK_BIAS 0x01000000 ++ ++#ifndef __ASSEMBLY__ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct semaphore { ++ atomic_t count; ++ atomic_t waking; ++ wait_queue_head_t wait; ++}; ++ ++#define __SEMAPHORE_INITIALIZER(name, n) \ ++{ \ ++ .count = ATOMIC_INIT(n), \ ++ .waking = ATOMIC_INIT(0), \ ++ .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ ++} ++ ++#define __MUTEX_INITIALIZER(name) \ ++ __SEMAPHORE_INITIALIZER(name,1) ++ ++#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ ++ struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) ++ ++#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) ++#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) ++ ++extern inline void sema_init (struct semaphore *sem, int val) ++{ ++ *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); ++} ++ ++static inline void init_MUTEX (struct semaphore *sem) ++{ ++ sema_init(sem, 1); ++} ++ ++static inline void init_MUTEX_LOCKED (struct semaphore *sem) ++{ ++ sema_init(sem, 0); ++} ++ ++asmlinkage void __down(struct semaphore * sem); ++asmlinkage int __down_interruptible(struct semaphore * sem); ++asmlinkage int __down_trylock(struct semaphore * sem); ++asmlinkage void __up(struct semaphore * sem); ++ ++asmlinkage void __down_failed(void /* special register calling convention */); ++asmlinkage int __down_failed_interruptible(void /* params in registers */); ++asmlinkage int __down_failed_trylock(void /* params in registers */); ++asmlinkage void __up_wakeup(void /* special register calling convention */); ++ ++extern spinlock_t semaphore_wake_lock; ++ ++/* ++ * This is ugly, but we want the default case to fall through. ++ * "down_failed" is a special asm handler that calls the C ++ * routine that actually waits. ++ */ ++extern inline void down(struct semaphore * sem) ++{ ++ might_sleep(); ++ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ if (atomic_dec_return(&sem->count) < 0) ++ __down(sem); ++ #endif ++} ++ ++extern inline int down_interruptible(struct semaphore * sem) ++{ ++ int ret = 0; ++ ++ ++ might_sleep(); ++ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ if(atomic_dec_return(&sem->count) < 0) ++ ret = __down_interruptible(sem); ++ return ret; ++ #endif ++} ++ ++extern inline int down_trylock(struct semaphore * sem) ++{ ++ #if 0 ++ ...Nios2 has no atomic "decrement memory".... ++ #else ++ int ret = 0; ++ ++ if (atomic_dec_return (&sem->count) < 0) ++ ret = __down_trylock(sem); ++ return ret; ++ #endif ++} ++ ++/* ++ * Note! This is subtle. We jump to wake people up only if ++ * the semaphore was negative (== somebody was waiting on it). ++ * The default case (no contention) will result in NO ++ * jumps for both down() and up(). ++ */ ++extern inline void up(struct semaphore * sem) ++{ ++ #if 0 ++ ...Nios2 has no atomic "increment memory".... ++ #else ++ if (atomic_inc_return(&sem->count) <= 0) ++ __up(sem); ++ #endif ++} ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif +--- linux/include/asm-nios2nommu/sembuf.h ++++ linux/include/asm-nios2nommu/sembuf.h +@@ -0,0 +1,48 @@ ++#ifndef _NIOS_SEMBUF_H ++#define _NIOS_SEMBUF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sembuf.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct semid64_ds { ++ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ ++ __kernel_time_t sem_otime; /* last semop time */ ++ unsigned long __unused1; ++ __kernel_time_t sem_ctime; /* last change time */ ++ unsigned long __unused2; ++ unsigned long sem_nsems; /* no. of semaphores in array */ ++ unsigned long __unused3; ++ unsigned long __unused4; ++}; ++ ++#endif /* _NIOS_SEMBUF_H */ +--- linux/include/asm-nios2nommu/setup.h ++++ linux/include/asm-nios2nommu/setup.h +@@ -0,0 +1,31 @@ ++/* Copied from i386 port. ++ * Just a place holder. We don't want to have to test x86 before ++ * we include stuff ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_SETUP_H ++#define _NIOS2_SETUP_H ++ ++#define COMMAND_LINE_SIZE 512 ++ ++#endif /* _NIOS2_SETUP_H */ +--- linux/include/asm-nios2nommu/shmbuf.h ++++ linux/include/asm-nios2nommu/shmbuf.h +@@ -0,0 +1,64 @@ ++#ifndef _NIOS_SHMBUF_H ++#define _NIOS_SHMBUF_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/shmbuf.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct shmid64_ds { ++ struct ipc64_perm shm_perm; /* operation perms */ ++ size_t shm_segsz; /* size of segment (bytes) */ ++ __kernel_time_t shm_atime; /* last attach time */ ++ unsigned long __unused1; ++ __kernel_time_t shm_dtime; /* last detach time */ ++ unsigned long __unused2; ++ __kernel_time_t shm_ctime; /* last change time */ ++ unsigned long __unused3; ++ __kernel_pid_t shm_cpid; /* pid of creator */ ++ __kernel_pid_t shm_lpid; /* pid of last operator */ ++ unsigned long shm_nattch; /* no. of current attaches */ ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++struct shminfo64 { ++ unsigned long shmmax; ++ unsigned long shmmin; ++ unsigned long shmmni; ++ unsigned long shmseg; ++ unsigned long shmall; ++ unsigned long __unused1; ++ unsigned long __unused2; ++ unsigned long __unused3; ++ unsigned long __unused4; ++}; ++ ++#endif /* _NIOS_SHMBUF_H */ +--- linux/include/asm-nios2nommu/shmparam.h ++++ linux/include/asm-nios2nommu/shmparam.h +@@ -0,0 +1,30 @@ ++#ifndef __NIOS2NOMMU_SHMPARAM_H__ ++#define __NIOS2NOMMU_SHMPARAM_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/shmparam.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ ++ ++#endif /* __NIOS2NOMMU_SHMPARAM_H__ */ +--- linux/include/asm-nios2nommu/sigcontext.h ++++ linux/include/asm-nios2nommu/sigcontext.h +@@ -0,0 +1,35 @@ ++/* ++ * Taken from the m68knommu. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_NIOS2NOMMU_SIGCONTEXT_H ++#define _ASM_NIOS2NOMMU_SIGCONTEXT_H ++ ++#include ++ ++struct sigcontext { ++ struct pt_regs regs; ++ unsigned long sc_mask; /* old sigmask */ ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/siginfo.h ++++ linux/include/asm-nios2nommu/siginfo.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_SIGINFO_H ++#define _NIOS2NOMMU_SIGINFO_H ++ ++#include ++ ++#endif +--- linux/include/asm-nios2nommu/signal.h ++++ linux/include/asm-nios2nommu/signal.h +@@ -0,0 +1,207 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2_SIGNAL_H ++#define _NIOS2_SIGNAL_H ++ ++#include ++ ++/* Avoid too many header ordering problems. */ ++struct siginfo; ++ ++#ifdef __KERNEL__ ++/* Most things should be clean enough to redefine this at will, if care ++ is taken to make libc match. */ ++ ++#define _NSIG 64 ++#define _NSIG_BPW 32 ++#define _NSIG_WORDS (_NSIG / _NSIG_BPW) ++ ++typedef unsigned long old_sigset_t; /* at least 32 bits */ ++ ++typedef struct { ++ unsigned long sig[_NSIG_WORDS]; ++} sigset_t; ++ ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++#define NSIG 32 ++typedef unsigned long sigset_t; ++ ++#endif /* __KERNEL__ */ ++ ++#define SIGHUP 1 ++#define SIGINT 2 ++#define SIGQUIT 3 ++#define SIGILL 4 ++#define SIGTRAP 5 ++#define SIGABRT 6 ++#define SIGIOT 6 ++#define SIGBUS 7 ++#define SIGFPE 8 ++#define SIGKILL 9 ++#define SIGUSR1 10 ++#define SIGSEGV 11 ++#define SIGUSR2 12 ++#define SIGPIPE 13 ++#define SIGALRM 14 ++#define SIGTERM 15 ++#define SIGSTKFLT 16 ++#define SIGCHLD 17 ++#define SIGCONT 18 ++#define SIGSTOP 19 ++#define SIGTSTP 20 ++#define SIGTTIN 21 ++#define SIGTTOU 22 ++#define SIGURG 23 ++#define SIGXCPU 24 ++#define SIGXFSZ 25 ++#define SIGVTALRM 26 ++#define SIGPROF 27 ++#define SIGWINCH 28 ++#define SIGIO 29 ++#define SIGPOLL SIGIO ++/* ++#define SIGLOST 29 ++*/ ++#define SIGPWR 30 ++#define SIGSYS 31 ++#define SIGUNUSED 31 ++ ++/* These should not be considered constants from userland. */ ++#define SIGRTMIN 32 ++#define SIGRTMAX _NSIG-1 ++ ++/* ++ * SA_FLAGS values: ++ * ++ * SA_ONSTACK indicates that a registered stack_t will be used. ++ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the ++ * SA_RESTART flag to get restarting signals (which were the default long ago) ++ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. ++ * SA_RESETHAND clears the handler when the signal is delivered. ++ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. ++ * SA_NODEFER prevents the current signal from being masked in the handler. ++ * ++ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single ++ * Unix names RESETHAND and NODEFER respectively. ++ */ ++#define SA_NOCLDSTOP 0x00000001 ++#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ ++#define SA_SIGINFO 0x00000004 ++#define SA_ONSTACK 0x08000000 ++#define SA_RESTART 0x10000000 ++#define SA_NODEFER 0x40000000 ++#define SA_RESETHAND 0x80000000 ++ ++#define SA_NOMASK SA_NODEFER ++#define SA_ONESHOT SA_RESETHAND ++#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ ++ ++#define SA_RESTORER 0x04000000 ++ ++/* ++ * sigaltstack controls ++ */ ++#define SS_ONSTACK 1 ++#define SS_DISABLE 2 ++ ++#define MINSIGSTKSZ 2048 ++#define SIGSTKSZ 8192 ++ ++#ifdef __KERNEL__ ++/* ++ * These values of sa_flags are used only by the kernel as part of the ++ * irq handling routines. ++ * ++ * SA_INTERRUPT is also used by the irq handling routines. ++ * SA_SHIRQ is for shared interrupt support on PCI and EISA. ++ */ ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#endif ++ ++#define SIG_BLOCK 0 /* for blocking signals */ ++#define SIG_UNBLOCK 1 /* for unblocking signals */ ++#define SIG_SETMASK 2 /* for setting the signal mask */ ++ ++/* Type of a signal handler. */ ++typedef void (*__sighandler_t)(int); ++ ++#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ ++#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ ++#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ ++ ++#ifdef __KERNEL__ ++struct old_sigaction { ++ __sighandler_t sa_handler; ++ old_sigset_t sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++}; ++ ++struct sigaction { ++ __sighandler_t sa_handler; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++ sigset_t sa_mask; /* mask last for extensibility */ ++}; ++ ++struct k_sigaction { ++ struct sigaction sa; ++}; ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++struct sigaction { ++ union { ++ __sighandler_t _sa_handler; ++ void (*_sa_sigaction)(int, struct siginfo *, void *); ++ } _u; ++ sigset_t sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++}; ++ ++#define sa_handler _u._sa_handler ++#define sa_sigaction _u._sa_sigaction ++ ++#endif /* __KERNEL__ */ ++ ++typedef struct sigaltstack { ++ void *ss_sp; ++ int ss_flags; ++ size_t ss_size; ++} stack_t; ++ ++#ifdef __KERNEL__ ++ ++#include ++#undef __HAVE_ARCH_SIG_BITOPS ++ ++#define ptrace_signal_deliver(regs, cookie) do { } while (0) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS2_SIGNAL_H */ +--- linux/include/asm-nios2nommu/smp.h ++++ linux/include/asm-nios2nommu/smp.h +@@ -0,0 +1,34 @@ ++#ifndef __ASM_SMP_H ++#define __ASM_SMP_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/smp.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++// #include ++ ++#ifdef CONFIG_SMP ++#error SMP not supported ++#endif ++ ++#endif +--- linux/include/asm-nios2nommu/socket.h ++++ linux/include/asm-nios2nommu/socket.h +@@ -0,0 +1,74 @@ ++#ifndef _ASM_SOCKET_H ++#define _ASM_SOCKET_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/socket.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* For setsockopt(2) */ ++#define SOL_SOCKET 1 ++ ++#define SO_DEBUG 1 ++#define SO_REUSEADDR 2 ++#define SO_TYPE 3 ++#define SO_ERROR 4 ++#define SO_DONTROUTE 5 ++#define SO_BROADCAST 6 ++#define SO_SNDBUF 7 ++#define SO_RCVBUF 8 ++#define SO_KEEPALIVE 9 ++#define SO_OOBINLINE 10 ++#define SO_NO_CHECK 11 ++#define SO_PRIORITY 12 ++#define SO_LINGER 13 ++#define SO_BSDCOMPAT 14 ++/* To add :#define SO_REUSEPORT 15 */ ++#define SO_PASSCRED 16 ++#define SO_PEERCRED 17 ++#define SO_RCVLOWAT 18 ++#define SO_SNDLOWAT 19 ++#define SO_RCVTIMEO 20 ++#define SO_SNDTIMEO 21 ++ ++/* Security levels - as per NRL IPv6 - don't actually do anything */ ++#define SO_SECURITY_AUTHENTICATION 22 ++#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 ++#define SO_SECURITY_ENCRYPTION_NETWORK 24 ++ ++#define SO_BINDTODEVICE 25 ++ ++/* Socket filtering */ ++#define SO_ATTACH_FILTER 26 ++#define SO_DETACH_FILTER 27 ++ ++#define SO_PEERNAME 28 ++#define SO_TIMESTAMP 29 ++#define SCM_TIMESTAMP SO_TIMESTAMP ++ ++#define SO_ACCEPTCONN 30 ++ ++#define SO_PEERSEC 31 /* ;dgt2;tmp; */ ++ ++#endif /* _ASM_SOCKET_H */ +--- linux/include/asm-nios2nommu/sockios.h ++++ linux/include/asm-nios2nommu/sockios.h +@@ -0,0 +1,38 @@ ++#ifndef _ASM_NIOS_SOCKIOS_H ++#define _ASM_NIOS_SOCKIOS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/sockios.h ++ * ++ * Socket-level I/O control calls. ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#define FIOSETOWN 0x8901 ++#define SIOCSPGRP 0x8902 ++#define FIOGETOWN 0x8903 ++#define SIOCGPGRP 0x8904 ++#define SIOCATMARK 0x8905 ++#define SIOCGSTAMP 0x8906 /* Get stamp */ ++ ++#endif /* !(_ASM_NIOS_SOCKIOS_H) */ ++ +--- linux/include/asm-nios2nommu/spi.h ++++ linux/include/asm-nios2nommu/spi.h +@@ -0,0 +1,92 @@ ++#ifndef _ASM_SPI_H_ ++#define _ASM_SPI_H_ 1 ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/spi.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++int register_NIOS_SPI( void ); ++void unregister_NIOS_SPI( void ); ++ ++#if defined(MODULE) ++void cleanup_module( void ); ++int init_module( void ); ++#endif ++ ++#if defined(__KERNEL__) ++int spi_reset ( void ); ++#endif ++ ++ ++#define clockCS 0x01 ++#define temperatureCS 0x02 ++ ++#define clock_read_base 0x00 ++#define clock_write_base 0x80 ++#define clock_read_control 0x0F ++#define clock_read_trickle 0x11 ++ ++#define clock_read_sec 0x00 ++#define clock_read_min 0x01 ++#define clock_read_hour 0x02 ++#define clock_read_day 0x03 ++#define clock_read_date 0x04 ++#define clock_read_month 0x05 ++#define clock_read_year 0x06 ++ ++#define clock_write_control 0x8F ++#define clock_write_trickle 0x91 ++#define clock_write_sec 0x80 ++#define clock_write_min 0x81 ++#define clock_write_hour 0x82 ++#define clock_write_day 0x83 ++#define clock_write_date 0x84 ++#define clock_write_month 0x85 ++#define clock_write_year 0x86 ++ ++#define clock_write_ram_start 0xA0 ++#define clock_write_ram_end 0x100 ++#define clock_read_ram_start 0x20 ++#define clock_read_ram_end 0x80 ++ ++ ++#define clock_sec_def 0x11 ++#define clock_min_def 0x59 ++#define clock_hour_def 0x71 ++#define clock_day_def 0x00 ++#define clock_date_def 0x20 ++#define clock_month_def 0x12 ++#define clock_year_def 0x34 ++ ++#define temp_read_base 0x00 ++#define temp_write_base 0x80 ++#define temp_read_control 0x00 ++#define temp_write_control 0x80 ++#define temp_read_msb 0x02 ++#define temp_read_lsb 0x01 ++ ++#define MAX_TEMP_VAR 10 ++ ++#endif /*_ASM_SPI_H_*/ +--- linux/include/asm-nios2nommu/spinlock.h ++++ linux/include/asm-nios2nommu/spinlock.h +@@ -0,0 +1,30 @@ ++#ifndef __NIOS_SPINLOCK_H ++#define __NIOS_SPINLOCK_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/spinlock.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#error "Nios doesn't do SMP yet" ++ ++#endif +--- linux/include/asm-nios2nommu/stat.h ++++ linux/include/asm-nios2nommu/stat.h +@@ -0,0 +1,102 @@ ++#ifndef _ASMNIOS2NOMMU_STAT_H ++#define _ASMNIOS2NOMMU_STAT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/stat.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++struct __old_kernel_stat { ++ unsigned short st_dev; ++ unsigned short st_ino; ++ unsigned short st_mode; ++ unsigned short st_nlink; ++ unsigned short st_uid; ++ unsigned short st_gid; ++ unsigned short st_rdev; ++ unsigned long st_size; ++ unsigned long st_atime; ++ unsigned long st_mtime; ++ unsigned long st_ctime; ++}; ++ ++struct stat { ++ unsigned short st_dev; ++ unsigned short __pad1; ++ unsigned long st_ino; ++ unsigned short st_mode; ++ unsigned short st_nlink; ++ unsigned short st_uid; ++ unsigned short st_gid; ++ unsigned short st_rdev; ++ unsigned short __pad2; ++ unsigned long st_size; ++ unsigned long st_blksize; ++ unsigned long st_blocks; ++ unsigned long st_atime; ++ unsigned long __unused1; ++ unsigned long st_mtime; ++ unsigned long __unused2; ++ unsigned long st_ctime; ++ unsigned long __unused3; ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++/* This matches struct stat64 in glibc2.1, hence the absolutely ++ * insane amounts of padding around dev_t's. ++ */ ++struct stat64 { ++ unsigned long long st_dev; ++ unsigned char __pad1[4]; ++ ++#define STAT64_HAS_BROKEN_ST_INO 1 ++ unsigned long __st_ino; ++ ++ unsigned int st_mode; ++ unsigned int st_nlink; ++ ++ unsigned long st_uid; ++ unsigned long st_gid; ++ ++ unsigned long long st_rdev; ++ unsigned char __pad3[4]; ++ ++ long long st_size; ++ unsigned long st_blksize; ++ ++ unsigned long __pad4; /* future possible st_blocks high bits */ ++ unsigned long st_blocks; /* Number 512-byte blocks allocated. */ ++ ++ unsigned long st_atime; ++ unsigned long st_atime_nsec; ++ ++ unsigned long st_mtime; ++ unsigned long st_mtime_nsec; ++ ++ unsigned long st_ctime; ++ unsigned long st_ctime_nsec; ++ ++ unsigned long long st_ino; ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/statfs.h ++++ linux/include/asm-nios2nommu/statfs.h +@@ -0,0 +1,30 @@ ++#ifndef _NIOS2NOMMU_STATFS_H ++#define _NIOS2NOMMU_STATFS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/statfs.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _NIOS2NOMMU_STATFS_H */ +--- linux/include/asm-nios2nommu/string.h ++++ linux/include/asm-nios2nommu/string.h +@@ -0,0 +1,45 @@ ++#ifndef __NIOS_STRING_H__ ++#define __NIOS_STRING_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/string.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#ifdef __KERNEL__ /* only set these up for kernel code */ ++ ++#define __HAVE_ARCH_MEMMOVE ++void * memmove(void * d, const void * s, size_t count); ++#define __HAVE_ARCH_MEMCPY ++extern void * memcpy(void *d, const void *s, size_t count); ++#define __HAVE_ARCH_MEMSET ++extern void * memset(void * s,int c,size_t count); ++ ++#if 0 ++#define __HAVE_ARCH_BCOPY ++#define __HAVE_ARCH_STRLEN ++#endif ++ ++#endif /* KERNEL */ ++ ++#endif /* !(__NIOS_STRING_H__) */ +--- linux/include/asm-nios2nommu/system.h ++++ linux/include/asm-nios2nommu/system.h +@@ -0,0 +1,172 @@ ++/* ++ * Taken from the m68k. ++ * ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _NIOS2NOMMU_SYSTEM_H ++#define _NIOS2NOMMU_SYSTEM_H ++ ++// #include /* get configuration macros */ ++#include ++#include ++#include ++#include ++ ++/* ++ * switch_to(n) should switch tasks to task ptr, first checking that ++ * ptr isn't the current task, in which case it does nothing. This ++ * also clears the TS-flag if the task we switched to has used the ++ * math co-processor latest. ++ */ ++ ++/* ++ */ ++asmlinkage void resume(void); ++#define switch_to(prev,next,last) \ ++{ \ ++ void *_last; \ ++ __asm__ __volatile__( \ ++ "mov r4, %1\n" \ ++ "mov r5, %2\n" \ ++ "call resume\n" \ ++ "mov %0,r4\n" \ ++ : "=r" (_last) \ ++ : "r" (prev), "r" (next) \ ++ : "r4","r5","r7","r8","ra"); \ ++ (last) = _last; \ ++} ++ ++#define local_irq_enable() __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "ori r8, r8, 1\n" \ ++ "wrctl status, r8\n" \ ++ : : : "r8") ++ ++#define local_irq_disable() __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "andi r8, r8, 0xfffe\n" \ ++ "wrctl status, r8\n" \ ++ : : : "r8") ++ ++#define local_save_flags(x) __asm__ __volatile__ ( \ ++ "rdctl r8, status\n" \ ++ "mov %0, r8\n" \ ++ :"=r" (x) : : "r8", "memory") ++ ++#define local_irq_restore(x) __asm__ __volatile__ ( \ ++ "mov r8, %0\n" \ ++ "wrctl status, r8\n" \ ++ : :"r" (x) : "memory") ++ ++/* For spinlocks etc */ ++#define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } while (0) ++ ++#define irqs_disabled() \ ++({ \ ++ unsigned long flags; \ ++ local_save_flags(flags); \ ++ ((flags & NIOS2_STATUS_PIE_MSK) == 0x0); \ ++}) ++ ++#define iret() __asm__ __volatile__ ("eret": : :"memory", "ea") ++ ++/* ++ * Force strict CPU ordering. ++ * Not really required on m68k... ++ */ ++#define nop() asm volatile ("nop"::) ++#define mb() asm volatile ("" : : :"memory") ++#define rmb() asm volatile ("" : : :"memory") ++#define wmb() asm volatile ("" : : :"memory") ++#define set_rmb(var, value) do { xchg(&var, value); } while (0) ++#define set_mb(var, value) set_rmb(var, value) ++#define set_wmb(var, value) do { var = value; wmb(); } while (0) ++ ++#ifdef CONFIG_SMP ++#define smp_mb() mb() ++#define smp_rmb() rmb() ++#define smp_wmb() wmb() ++#define smp_read_barrier_depends() read_barrier_depends() ++#else ++#define smp_mb() barrier() ++#define smp_rmb() barrier() ++#define smp_wmb() barrier() ++#define smp_read_barrier_depends() do { } while(0) ++#endif ++ ++#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) ++#define tas(ptr) (xchg((ptr),1)) ++ ++struct __xchg_dummy { unsigned long a[100]; }; ++#define __xg(x) ((volatile struct __xchg_dummy *)(x)) ++ ++static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) ++{ ++ unsigned long tmp, flags; ++ ++ local_irq_save(flags); ++ ++ switch (size) { ++ case 1: ++ __asm__ __volatile__( \ ++ "ldb %0, %2\n" \ ++ "stb %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ case 2: ++ __asm__ __volatile__( \ ++ "ldh %0, %2\n" \ ++ "sth %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ case 4: ++ __asm__ __volatile__( \ ++ "ldw %0, %2\n" \ ++ "stw %1, %2\n" \ ++ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); ++ break; ++ } ++ local_irq_restore(flags); ++ return tmp; ++} ++ ++/* ++ * Atomic compare and exchange. Compare OLD with MEM, if identical, ++ * store NEW in MEM. Return the initial value in MEM. Success is ++ * indicated by comparing RETURN with OLD. ++ */ ++#define __HAVE_ARCH_CMPXCHG 1 ++ ++static __inline__ unsigned long ++cmpxchg(volatile int *p, int old, int new) ++{ ++ unsigned long flags; ++ int prev; ++ ++ local_irq_save(flags); ++ if ((prev = *p) == old) ++ *p = new; ++ local_irq_restore(flags); ++ return(prev); ++} ++ ++#endif /* _NIOS2NOMMU_SYSTEM_H */ +--- linux/include/asm-nios2nommu/termbits.h ++++ linux/include/asm-nios2nommu/termbits.h +@@ -0,0 +1,199 @@ ++#ifndef __ARCH_NIOS_TERMBITS_H__ ++#define __ARCH_NIOS_TERMBITS_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/termbits.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++typedef unsigned char cc_t; ++typedef unsigned int speed_t; ++typedef unsigned int tcflag_t; ++ ++#define NCCS 19 ++struct termios { ++ tcflag_t c_iflag; /* input mode flags */ ++ tcflag_t c_oflag; /* output mode flags */ ++ tcflag_t c_cflag; /* control mode flags */ ++ tcflag_t c_lflag; /* local mode flags */ ++ cc_t c_line; /* line discipline */ ++ cc_t c_cc[NCCS]; /* control characters */ ++}; ++ ++/* c_cc characters */ ++#define VINTR 0 ++#define VQUIT 1 ++#define VERASE 2 ++#define VKILL 3 ++#define VEOF 4 ++#define VTIME 5 ++#define VMIN 6 ++#define VSWTC 7 ++#define VSTART 8 ++#define VSTOP 9 ++#define VSUSP 10 ++#define VEOL 11 ++#define VREPRINT 12 ++#define VDISCARD 13 ++#define VWERASE 14 ++#define VLNEXT 15 ++#define VEOL2 16 ++ ++ ++/* c_iflag bits */ ++#define IGNBRK 0000001 ++#define BRKINT 0000002 ++#define IGNPAR 0000004 ++#define PARMRK 0000010 ++#define INPCK 0000020 ++#define ISTRIP 0000040 ++#define INLCR 0000100 ++#define IGNCR 0000200 ++#define ICRNL 0000400 ++#define IUCLC 0001000 ++#define IXON 0002000 ++#define IXANY 0004000 ++#define IXOFF 0010000 ++#define IMAXBEL 0020000 ++#define IUTF8 0040000 ++ ++/* c_oflag bits */ ++#define OPOST 0000001 ++#define OLCUC 0000002 ++#define ONLCR 0000004 ++#define OCRNL 0000010 ++#define ONOCR 0000020 ++#define ONLRET 0000040 ++#define OFILL 0000100 ++#define OFDEL 0000200 ++#define NLDLY 0000400 ++#define NL0 0000000 ++#define NL1 0000400 ++#define CRDLY 0003000 ++#define CR0 0000000 ++#define CR1 0001000 ++#define CR2 0002000 ++#define CR3 0003000 ++#define TABDLY 0014000 ++#define TAB0 0000000 ++#define TAB1 0004000 ++#define TAB2 0010000 ++#define TAB3 0014000 ++#define XTABS 0014000 ++#define BSDLY 0020000 ++#define BS0 0000000 ++#define BS1 0020000 ++#define VTDLY 0040000 ++#define VT0 0000000 ++#define VT1 0040000 ++#define FFDLY 0100000 ++#define FF0 0000000 ++#define FF1 0100000 ++ ++/* c_cflag bit meaning */ ++#define CBAUD 0010017 ++#define B0 0000000 /* hang up */ ++#define B50 0000001 ++#define B75 0000002 ++#define B110 0000003 ++#define B134 0000004 ++#define B150 0000005 ++#define B200 0000006 ++#define B300 0000007 ++#define B600 0000010 ++#define B1200 0000011 ++#define B1800 0000012 ++#define B2400 0000013 ++#define B4800 0000014 ++#define B9600 0000015 ++#define B19200 0000016 ++#define B38400 0000017 ++#define EXTA B19200 ++#define EXTB B38400 ++#define CSIZE 0000060 ++#define CS5 0000000 ++#define CS6 0000020 ++#define CS7 0000040 ++#define CS8 0000060 ++#define CSTOPB 0000100 ++#define CREAD 0000200 ++#define PARENB 0000400 ++#define PARODD 0001000 ++#define HUPCL 0002000 ++#define CLOCAL 0004000 ++#define CBAUDEX 0010000 ++#define B57600 0010001 ++#define B115200 0010002 ++#define B230400 0010003 ++#define B460800 0010004 ++#define B500000 0010005 ++#define B576000 0010006 ++#define B921600 0010007 ++#define B1000000 0010010 ++#define B1152000 0010011 ++#define B1500000 0010012 ++#define B2000000 0010013 ++#define B2500000 0010014 ++#define B3000000 0010015 ++#define B3500000 0010016 ++#define B4000000 0010017 ++#define CIBAUD 002003600000 /* input baud rate (not used) */ ++#define CMSPAR 010000000000 /* mark or space (stick) parity */ ++#define CRTSCTS 020000000000 /* flow control */ ++ ++/* c_lflag bits */ ++#define ISIG 0000001 ++#define ICANON 0000002 ++#define XCASE 0000004 ++#define ECHO 0000010 ++#define ECHOE 0000020 ++#define ECHOK 0000040 ++#define ECHONL 0000100 ++#define NOFLSH 0000200 ++#define TOSTOP 0000400 ++#define ECHOCTL 0001000 ++#define ECHOPRT 0002000 ++#define ECHOKE 0004000 ++#define FLUSHO 0010000 ++#define PENDIN 0040000 ++#define IEXTEN 0100000 ++ ++ ++/* tcflow() and TCXONC use these */ ++#define TCOOFF 0 ++#define TCOON 1 ++#define TCIOFF 2 ++#define TCION 3 ++ ++/* tcflush() and TCFLSH use these */ ++#define TCIFLUSH 0 ++#define TCOFLUSH 1 ++#define TCIOFLUSH 2 ++ ++/* tcsetattr uses these */ ++#define TCSANOW 0 ++#define TCSADRAIN 1 ++#define TCSAFLUSH 2 ++ ++#endif /* __ARCH_NIOS_TERMBITS_H__ */ +--- linux/include/asm-nios2nommu/termios.h ++++ linux/include/asm-nios2nommu/termios.h +@@ -0,0 +1,132 @@ ++#ifndef _NIOS_TERMIOS_H ++#define _NIOS_TERMIOS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/termios.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++#include ++ ++struct winsize { ++ unsigned short ws_row; ++ unsigned short ws_col; ++ unsigned short ws_xpixel; ++ unsigned short ws_ypixel; ++}; ++ ++#define NCC 8 ++struct termio { ++ unsigned short c_iflag; /* input mode flags */ ++ unsigned short c_oflag; /* output mode flags */ ++ unsigned short c_cflag; /* control mode flags */ ++ unsigned short c_lflag; /* local mode flags */ ++ unsigned char c_line; /* line discipline */ ++ unsigned char c_cc[NCC]; /* control characters */ ++}; ++ ++#ifdef __KERNEL__ ++/* intr=^C quit=^| erase=del kill=^U ++ eof=^D vtime=\0 vmin=\1 sxtc=\0 ++ start=^Q stop=^S susp=^Z eol=\0 ++ reprint=^R discard=^U werase=^W lnext=^V ++ eol2=\0 ++*/ ++#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" ++#endif ++ ++/* modem lines */ ++#define TIOCM_LE 0x001 ++#define TIOCM_DTR 0x002 ++#define TIOCM_RTS 0x004 ++#define TIOCM_ST 0x008 ++#define TIOCM_SR 0x010 ++#define TIOCM_CTS 0x020 ++#define TIOCM_CAR 0x040 ++#define TIOCM_RNG 0x080 ++#define TIOCM_DSR 0x100 ++#define TIOCM_CD TIOCM_CAR ++#define TIOCM_RI TIOCM_RNG ++#define TIOCM_OUT1 0x2000 ++#define TIOCM_OUT2 0x4000 ++#define TIOCM_LOOP 0x8000 ++ ++/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ ++ ++/* line disciplines */ ++#define N_TTY 0 ++#define N_SLIP 1 ++#define N_MOUSE 2 ++#define N_PPP 3 ++#define N_STRIP 4 ++#define N_AX25 5 ++#define N_X25 6 /* X.25 async */ ++#define N_6PACK 7 ++#define N_MASC 8 /* Reserved for Mobitex module */ ++#define N_R3964 9 /* Reserved for Simatic R3964 module */ ++#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ ++#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */ ++#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ ++#define N_HDLC 13 /* synchronous HDLC */ ++#define N_SYNC_PPP 14 ++#define N_HCI 15 /* Bluetooth HCI UART */ ++ ++#ifdef __KERNEL__ ++ ++/* ++ * Translate a "termio" structure into a "termios". Ugh. ++ */ ++#define user_termio_to_kernel_termios(termios, termio) \ ++({ \ ++ unsigned short tmp; \ ++ get_user(tmp, &(termio)->c_iflag); \ ++ (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_oflag); \ ++ (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_cflag); \ ++ (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ ++ get_user(tmp, &(termio)->c_lflag); \ ++ (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ ++ get_user((termios)->c_line, &(termio)->c_line); \ ++ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ ++}) ++ ++/* ++ * Translate a "termios" structure into a "termio". Ugh. ++ */ ++#define kernel_termios_to_user_termio(termio, termios) \ ++({ \ ++ put_user((termios)->c_iflag, &(termio)->c_iflag); \ ++ put_user((termios)->c_oflag, &(termio)->c_oflag); \ ++ put_user((termios)->c_cflag, &(termio)->c_cflag); \ ++ put_user((termios)->c_lflag, &(termio)->c_lflag); \ ++ put_user((termios)->c_line, &(termio)->c_line); \ ++ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ ++}) ++ ++#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) ++#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS_TERMIOS_H */ +--- linux/include/asm-nios2nommu/thread_info.h ++++ linux/include/asm-nios2nommu/thread_info.h +@@ -0,0 +1,126 @@ ++/* thread_info.h: niosnommu low-level thread information ++ * adapted from the m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd. ++ * Copyright (C) 2002 Microtronix Datacom ++ * ++ * - Incorporating suggestions made by Linus Torvalds and Dave Miller ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#ifndef _ASM_THREAD_INFO_H ++#define _ASM_THREAD_INFO_H ++ ++#include ++ ++#ifdef __KERNEL__ ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * low level task data. ++ */ ++struct thread_info { ++ struct task_struct *task; /* main task structure */ ++ struct exec_domain *exec_domain; /* execution domain */ ++ unsigned long flags; /* low level flags */ ++ int cpu; /* cpu we're on */ ++ int preempt_count; /* 0 => preemptable, <0 => BUG*/ ++ struct restart_block restart_block; ++}; ++ ++/* ++ * macros/functions for gaining access to the thread information structure ++ */ ++#define INIT_THREAD_INFO(tsk) \ ++{ \ ++ .task = &tsk, \ ++ .exec_domain = &default_exec_domain, \ ++ .flags = 0, \ ++ .cpu = 0, \ ++ .preempt_count = 1, \ ++ .restart_block = { \ ++ .fn = do_no_restart_syscall, \ ++ }, \ ++} ++ ++#define init_thread_info (init_thread_union.thread_info) ++#define init_stack (init_thread_union.stack) ++ ++ ++/* how to get the thread information struct from C ++ usable only in supervisor mode */ ++static inline struct thread_info *current_thread_info(void) ++{ ++ struct thread_info *ti; ++ __asm__ __volatile__( ++ "mov %0, sp\n" ++ "and %0, %0, %1\n" ++ : "=&r"(ti) ++ : "r" (~(THREAD_SIZE-1)) ++ ); ++ return ti; ++} ++ ++/* thread information allocation */ ++#define alloc_thread_info(tsk) ((struct thread_info *) \ ++ __get_free_pages(GFP_KERNEL, 1)) ++#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) ++#define put_thread_info(ti) put_task_struct((ti)->task) ++ ++#define PREEMPT_ACTIVE 0x4000000 ++ ++/* ++ * thread information flag bit numbers ++ */ ++#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ ++#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ ++#define TIF_SIGPENDING 2 /* signal pending */ ++#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ ++#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling ++ TIF_NEED_RESCHED */ ++ ++/* as above, but as bit values */ ++#define _TIF_SYSCALL_TRACE (1< ++ ++ ++#define CLOCK_TICK_RATE nasys_clock_freq /* Underlying HZ */ ++ ++#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ ++ ++#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ ++ (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ ++ << (SHIFT_SCALE-SHIFT_HZ)) / HZ) ++ ++typedef unsigned long cycles_t; ++ ++static inline cycles_t get_cycles(void) ++{ ++ return 0; ++} ++ ++#endif +--- linux/include/asm-nios2nommu/tlb.h ++++ linux/include/asm-nios2nommu/tlb.h +@@ -0,0 +1,35 @@ ++#ifndef __NIOS_TLB_H__ ++#define __NIOS_TLB_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/tlb.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2003 Microtronix Datacom Ltd ++ * Copyright (C) 2002 NEC Corporation ++ * Copyright (C) 2002 Miles Bader ++ * ++ * 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. ++ * ++ * ++ * Written by Miles Bader ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#define tlb_flush(tlb) ((void)0) ++ ++#include ++ ++#endif /* __NIOS_TLB_H__ */ ++ +--- linux/include/asm-nios2nommu/tlbflush.h ++++ linux/include/asm-nios2nommu/tlbflush.h +@@ -0,0 +1,86 @@ ++#ifndef _NIOS2NOMMU_TLBFLUSH_H ++#define _NIOS2NOMMU_TLBFLUSH_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/tlbflush.h ++ * ++ * Ported from m68knommu. ++ * ++ * Copyright (C) 2003 Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++#include ++ ++/* ++ * flush all user-space atc entries. ++ */ ++static inline void __flush_tlb(void) ++{ ++ BUG(); ++} ++ ++static inline void __flush_tlb_one(unsigned long addr) ++{ ++ BUG(); ++} ++ ++#define flush_tlb() __flush_tlb() ++ ++/* ++ * flush all atc entries (both kernel and user-space entries). ++ */ ++static inline void flush_tlb_all(void) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_mm(struct mm_struct *mm) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) ++{ ++ BUG(); ++} ++ ++static inline void flush_tlb_range(struct mm_struct *mm, ++ unsigned long start, unsigned long end) ++{ ++ BUG(); ++} ++ ++extern inline void flush_tlb_kernel_page(unsigned long addr) ++{ ++ BUG(); ++} ++ ++extern inline void flush_tlb_pgtables(struct mm_struct *mm, ++ unsigned long start, unsigned long end) ++{ ++ BUG(); ++} ++ ++#endif /* _NIOS2NOMMU_TLBFLUSH_H */ +--- linux/include/asm-nios2nommu/topology.h ++++ linux/include/asm-nios2nommu/topology.h +@@ -0,0 +1,30 @@ ++#ifndef _ASM_NIOS2NOMMU_TOPOLOGY_H ++#define _ASM_NIOS2NOMMU_TOPOLOGY_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/topology.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++#endif /* _ASM_NIOS2NOMMU_TOPOLOGY_H */ +--- linux/include/asm-nios2nommu/traps.h ++++ linux/include/asm-nios2nommu/traps.h +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2004, Microtronix Datacom Ltd. ++ * ++ * 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; 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, GOOD TITLE or ++ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef _NIOS2_TRAPS_H ++#define _NIOS2_TRAPS_H ++ ++#define TRAP_ID_SYSCALL 0 ++#define TRAP_ID_APPDEBUG 1 ++#endif /* !(_NIOS2_TRAPS_H) */ +--- linux/include/asm-nios2nommu/types.h ++++ linux/include/asm-nios2nommu/types.h +@@ -0,0 +1,93 @@ ++#ifndef _NIOS_TYPES_H ++#define _NIOS_TYPES_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/types.h ++ * ++ * Derived from m68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * This file is never included by application software unless ++ * explicitly requested (e.g., via linux/types.h) in which case the ++ * application is Linux specific so (user-) name space pollution is ++ * not a major issue. However, for interoperability, libraries still ++ * need to be careful to avoid a name clashes. ++ */ ++ ++#ifndef __ASSEMBLY__ ++ ++typedef unsigned short umode_t; ++ ++/* ++ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the ++ * header files exported to user space ++ */ ++ ++typedef __signed__ char __s8; ++typedef unsigned char __u8; ++ ++typedef __signed__ short __s16; ++typedef unsigned short __u16; ++ ++typedef __signed__ int __s32; ++typedef unsigned int __u32; ++ ++#if defined(__GNUC__) && !defined(__STRICT_ANSI__) ++typedef __signed__ long long __s64; ++typedef unsigned long long __u64; ++#endif ++ ++#endif /* __ASSEMBLY__ */ ++ ++/* ++ * These aren't exported outside the kernel to avoid name space clashes ++ */ ++#ifdef __KERNEL__ ++ ++#define BITS_PER_LONG 32 ++ ++#ifndef __ASSEMBLY__ ++ ++typedef signed char s8; ++typedef unsigned char u8; ++ ++typedef signed short s16; ++typedef unsigned short u16; ++ ++typedef signed int s32; ++typedef unsigned int u32; ++ ++typedef signed long long s64; ++typedef unsigned long long u64; ++ ++/* DMA addresses are always 32-bits wide */ ++ ++typedef u32 dma_addr_t; ++typedef u32 dma64_addr_t; ++ ++typedef unsigned short kmem_bufctl_t; ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NIOS_TYPES_H */ +--- linux/include/asm-nios2nommu/uaccess.h ++++ linux/include/asm-nios2nommu/uaccess.h +@@ -0,0 +1,183 @@ ++#ifndef __NIOS2NOMMU_UACCESS_H ++#define __NIOS2NOMMU_UACCESS_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * asm-nios2nommu/uaccess.h ++ * ++ * User space memory access functions ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Ported from asm-m68knommu/uaccess.h --wentao ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++#include ++#include ++#include ++ ++#define VERIFY_READ 0 ++#define VERIFY_WRITE 1 ++ ++#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size)) ++ ++static inline int _access_ok(unsigned long addr, unsigned long size) ++{ ++ return (((unsigned long)addr < (unsigned long)nasys_program_mem_end) && ++ (((unsigned long)addr >= (unsigned long)nasys_program_mem))); ++} ++ ++extern inline int verify_area(int type, const void * addr, unsigned long size) ++{ ++ return access_ok(type,addr,size)?0:-EFAULT; ++} ++ ++/* ++ * The exception table consists of pairs of addresses: the first is the ++ * address of an instruction that is allowed to fault, and the second is ++ * the address at which the program should continue. No registers are ++ * modified, so it is entirely up to the continuation code to figure out ++ * what to do. ++ * ++ * All the routines below use bits of fixup code that are out of line ++ * with the main instruction path. This means when everything is well, ++ * we don't even have to jump over them. Further, they do not intrude ++ * on our cache or tlb entries. ++ */ ++ ++#define ARCH_HAS_SEARCH_EXTABLE ++//;dgt2;tmp; ++ ++struct exception_table_entry ++{ ++ unsigned long insn, fixup; ++}; ++ ++/* Returns 0 if exception not found and fixup otherwise. */ ++extern unsigned long search_exception_table(unsigned long); ++ ++ ++/* ++ * These are the main single-value transfer routines. They automatically ++ * use the right size if we just have the right pointer type. ++ */ ++ ++#define put_user(x, ptr) \ ++({ \ ++ int __pu_err = 0; \ ++ typeof(*(ptr)) __pu_val = (x); \ ++ switch (sizeof (*(ptr))) { \ ++ case 1: \ ++ case 2: \ ++ case 4: \ ++ case 8: \ ++ memcpy(ptr, &__pu_val, sizeof (*(ptr))); \ ++ break; \ ++ default: \ ++ __pu_err = __put_user_bad(); \ ++ break; \ ++ } \ ++ __pu_err; \ ++}) ++#define __put_user(x, ptr) put_user(x, ptr) ++ ++extern int __put_user_bad(void); ++ ++/* ++ * Tell gcc we read from memory instead of writing: this is because ++ * we do not write to any memory gcc knows about, so there are no ++ * aliasing issues. ++ */ ++ ++#define __ptr(x) ((unsigned long *)(x)) ++ ++#define get_user(x, ptr) \ ++({ \ ++ int __gu_err = 0; \ ++ typeof(*(ptr)) __gu_val = 0; \ ++ switch (sizeof(*(ptr))) { \ ++ case 1: \ ++ case 2: \ ++ case 4: \ ++ case 8: \ ++ memcpy(&__gu_val, ptr, sizeof (*(ptr))); \ ++ break; \ ++ default: \ ++ __gu_val = 0; \ ++ __gu_err = __get_user_bad(); \ ++ break; \ ++ } \ ++ (x) = __gu_val; \ ++ __gu_err; \ ++}) ++#define __get_user(x, ptr) get_user(x, ptr) ++ ++extern int __get_user_bad(void); ++ ++#define copy_from_user(to, from, n) (memcpy(to, from, n), 0) ++#define copy_to_user(to, from, n) (memcpy(to, from, n), 0) ++ ++#define __copy_from_user(to, from, n) copy_from_user(to, from, n) ++#define __copy_to_user(to, from, n) copy_to_user(to, from, n) ++#define __copy_to_user_inatomic __copy_to_user ++#define __copy_from_user_inatomic __copy_from_user ++ ++#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) ++ ++#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) ++ ++/* ++ * Copy a null terminated string from userspace. ++ */ ++ ++static inline long ++strncpy_from_user(char *dst, const char *src, long count) ++{ ++ char *tmp; ++ strncpy(dst, src, count); ++ for (tmp = dst; *tmp && count > 0; tmp++, count--) ++ ; ++ return(tmp - dst); /* DAVIDM should we count a NUL ? check getname */ ++} ++ ++/* ++ * Return the size of a string (including the ending 0) ++ * ++ * Return 0 on exception, a value greater than N if too long ++ */ ++static inline long strnlen_user(const char *src, long n) ++{ ++ return(strlen(src) + 1); /* DAVIDM make safer */ ++} ++ ++#define strlen_user(str) strnlen_user(str, 32767) ++ ++/* ++ * Zero Userspace ++ */ ++ ++static inline unsigned long ++clear_user(void *to, unsigned long n) ++{ ++ memset(to, 0, n); ++ return(0); ++} ++ ++#endif /* _NIOS2NOMMU_UACCESS_H */ +--- linux/include/asm-nios2nommu/uart_struct.h ++++ linux/include/asm-nios2nommu/uart_struct.h +@@ -0,0 +1,83 @@ ++ ++// UART Registers ++typedef volatile struct ++ { ++ int np_uartrxdata; // Read-only, 8-bit ++ int np_uarttxdata; // Write-only, 8-bit ++ int np_uartstatus; // Read-only, 8-bit ++ int np_uartcontrol; // Read/Write, 9-bit ++ int np_uartdivisor; // Read/Write, 16-bit, optional ++ int np_uartendofpacket; // Read/Write, end-of-packet character ++ } np_uart; ++ ++// UART Status Register Bits ++enum ++ { ++ np_uartstatus_eop_bit = 12, ++ np_uartstatus_cts_bit = 11, ++ np_uartstatus_dcts_bit = 10, ++ np_uartstatus_e_bit = 8, ++ np_uartstatus_rrdy_bit = 7, ++ np_uartstatus_trdy_bit = 6, ++ np_uartstatus_tmt_bit = 5, ++ np_uartstatus_toe_bit = 4, ++ np_uartstatus_roe_bit = 3, ++ np_uartstatus_brk_bit = 2, ++ np_uartstatus_fe_bit = 1, ++ np_uartstatus_pe_bit = 0, ++ ++ np_uartstatus_eop_mask = (1<<12), ++ np_uartstatus_cts_mask = (1<<11), ++ np_uartstatus_dcts_mask = (1<<10), ++ np_uartstatus_e_mask = (1<<8), ++ np_uartstatus_rrdy_mask = (1<<7), ++ np_uartstatus_trdy_mask = (1<<6), ++ np_uartstatus_tmt_mask = (1<<5), ++ np_uartstatus_toe_mask = (1<<4), ++ np_uartstatus_roe_mask = (1<<3), ++ np_uartstatus_brk_mask = (1<<2), ++ np_uartstatus_fe_mask = (1<<1), ++ np_uartstatus_pe_mask = (1<<0) ++ }; ++ ++// UART Control Register Bits ++enum ++ { ++ np_uartcontrol_ieop_bit = 12, ++ np_uartcontrol_rts_bit = 11, ++ np_uartcontrol_idcts_bit = 10, ++ np_uartcontrol_tbrk_bit = 9, ++ np_uartcontrol_ie_bit = 8, ++ np_uartcontrol_irrdy_bit = 7, ++ np_uartcontrol_itrdy_bit = 6, ++ np_uartcontrol_itmt_bit = 5, ++ np_uartcontrol_itoe_bit = 4, ++ np_uartcontrol_iroe_bit = 3, ++ np_uartcontrol_ibrk_bit = 2, ++ np_uartcontrol_ife_bit = 1, ++ np_uartcontrol_ipe_bit = 0, ++ ++ np_uartcontrol_ieop_mask = (1<<12), ++ np_uartcontrol_rts_mask = (1<<11), ++ np_uartcontrol_idcts_mask = (1<<10), ++ np_uartcontrol_tbrk_mask = (1<<9), ++ np_uartcontrol_ie_mask = (1<<8), ++ np_uartcontrol_irrdy_mask = (1<<7), ++ np_uartcontrol_itrdy_mask = (1<<6), ++ np_uartcontrol_itmt_mask = (1<<5), ++ np_uartcontrol_itoe_mask = (1<<4), ++ np_uartcontrol_iroe_mask = (1<<3), ++ np_uartcontrol_ibrk_mask = (1<<2), ++ np_uartcontrol_ife_mask = (1<<1), ++ np_uartcontrol_ipe_mask = (1<<0) ++ }; ++ ++// UART Routines ++int nr_uart_rxchar(np_uart *uartBase); // 0 for default UART ++void nr_uart_txcr(void); ++void nr_uart_txchar(int c,np_uart *uartBase); // 0 for default UART ++void nr_uart_txhex(int x); // 16 or 32 bits ++void nr_uart_txhex16(short x); ++void nr_uart_txhex32(long x); ++void nr_uart_txstring(char *s); ++ +--- linux/include/asm-nios2nommu/ucontext.h ++++ linux/include/asm-nios2nommu/ucontext.h +@@ -0,0 +1,63 @@ ++#ifndef _NIOSKNOMMU_UCONTEXT_H ++#define _NIOSKNOMMU_UCONTEXT_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/ucontext.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++typedef int greg_t; ++#define NGREG 32 ++typedef greg_t gregset_t[NGREG]; ++ ++#ifdef CONFIG_FPU ++typedef struct fpregset { ++ int f_pcr; ++ int f_psr; ++ int f_fpiaddr; ++ int f_fpregs[8][3]; ++} fpregset_t; ++#endif ++ ++struct mcontext { ++ int version; ++ int status_extension; ++ gregset_t gregs; ++#ifdef CONFIG_FPU ++ fpregset_t fpregs; ++#endif ++}; ++ ++#define MCONTEXT_VERSION 2 ++ ++struct ucontext { ++ unsigned long uc_flags; ++ struct ucontext *uc_link; ++ stack_t uc_stack; ++ struct mcontext uc_mcontext; ++#ifdef CONFIG_FPU ++ unsigned long uc_filler[80]; ++#endif ++ sigset_t uc_sigmask; /* mask last for extensibility */ ++}; ++ ++#endif +--- linux/include/asm-nios2nommu/unaligned.h ++++ linux/include/asm-nios2nommu/unaligned.h +@@ -0,0 +1,43 @@ ++#ifndef __NIOS_UNALIGNED_H ++#define __NIOS_UNALIGNED_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/unaligned.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * The nios cannot do unaligned accesses itself. ++ */ ++ ++#define get_unaligned(ptr) ({ \ ++ typeof((*(ptr))) x; \ ++ memcpy(&x, (void*)ptr, sizeof(*(ptr))); \ ++ x; \ ++}) ++ ++#define put_unaligned(val, ptr) ({ \ ++ typeof((*(ptr))) x = val; \ ++ memcpy((void*)ptr, &x, sizeof(*(ptr))); \ ++}) ++ ++#endif /* __NIOS_UNALIGNED_H */ +--- linux/include/asm-nios2nommu/unistd.h ++++ linux/include/asm-nios2nommu/unistd.h +@@ -0,0 +1,686 @@ ++#ifndef _ASM_NIOS_UNISTD_H_ ++#define _ASM_NIOS_UNISTD_H_ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/unistd.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * //vic - kernel_thread moved to process.c ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* TRAP isr expects the trap# (syscall=#TRAP_ID_SYSCALL) in r2, ++ * the syscall # in r3, and arguments in r4, r5, ... ++ * Return argument expected in r2. ++ */ ++ ++#define __NR_restart_syscall 0 ++#define __NR_exit 1 ++#define __NR_fork 2 ++#define __NR_read 3 ++#define __NR_write 4 ++#define __NR_open 5 ++#define __NR_close 6 ++#define __NR_waitpid 7 ++#define __NR_creat 8 ++#define __NR_link 9 ++#define __NR_unlink 10 ++#define __NR_execve 11 ++#define __NR_chdir 12 ++#define __NR_time 13 ++#define __NR_mknod 14 ++#define __NR_chmod 15 ++#define __NR_chown 16 ++#define __NR_break 17 ++#define __NR_oldstat 18 ++#define __NR_lseek 19 ++#define __NR_getpid 20 ++#define __NR_mount 21 ++#define __NR_umount 22 ++#define __NR_setuid 23 ++#define __NR_getuid 24 ++#define __NR_stime 25 ++#define __NR_ptrace 26 ++#define __NR_alarm 27 ++#define __NR_oldfstat 28 ++#define __NR_pause 29 ++#define __NR_utime 30 ++#define __NR_stty 31 ++#define __NR_gtty 32 ++#define __NR_access 33 ++#define __NR_nice 34 ++#define __NR_ftime 35 ++#define __NR_sync 36 ++#define __NR_kill 37 ++#define __NR_rename 38 ++#define __NR_mkdir 39 ++#define __NR_rmdir 40 ++#define __NR_dup 41 ++#define __NR_pipe 42 ++#define __NR_times 43 ++#define __NR_prof 44 ++#define __NR_brk 45 ++#define __NR_setgid 46 ++#define __NR_getgid 47 ++#define __NR_signal 48 ++#define __NR_geteuid 49 ++#define __NR_getegid 50 ++#define __NR_acct 51 ++#define __NR_umount2 52 //vic #define __NR_phys 52 ++#define __NR_lock 53 ++#define __NR_ioctl 54 ++#define __NR_fcntl 55 ++#define __NR_mpx 56 ++#define __NR_setpgid 57 ++#define __NR_ulimit 58 ++#define __NR_oldolduname 59 ++#define __NR_umask 60 ++#define __NR_chroot 61 ++#define __NR_ustat 62 ++#define __NR_dup2 63 ++#define __NR_getppid 64 ++#define __NR_getpgrp 65 ++#define __NR_setsid 66 ++#define __NR_sigaction 67 ++#define __NR_sgetmask 68 ++#define __NR_ssetmask 69 ++#define __NR_setreuid 70 ++#define __NR_setregid 71 ++#define __NR_sigsuspend 72 ++#define __NR_sigpending 73 ++#define __NR_sethostname 74 ++#define __NR_setrlimit 75 ++#define __NR_getrlimit 76 ++#define __NR_getrusage 77 ++#define __NR_gettimeofday 78 ++#define __NR_settimeofday 79 ++#define __NR_getgroups 80 ++#define __NR_setgroups 81 ++#define __NR_select 82 ++#define __NR_symlink 83 ++#define __NR_oldlstat 84 ++#define __NR_readlink 85 ++#define __NR_uselib 86 ++#define __NR_swapon 87 ++#define __NR_reboot 88 ++#define __NR_readdir 89 ++#define __NR_mmap 90 ++#define __NR_munmap 91 ++#define __NR_truncate 92 ++#define __NR_ftruncate 93 ++#define __NR_fchmod 94 ++#define __NR_fchown 95 ++#define __NR_getpriority 96 ++#define __NR_setpriority 97 ++#define __NR_profil 98 ++#define __NR_statfs 99 ++#define __NR_fstatfs 100 ++#define __NR_ioperm 101 ++#define __NR_socketcall 102 ++#define __NR_syslog 103 ++#define __NR_setitimer 104 ++#define __NR_getitimer 105 ++#define __NR_stat 106 ++#define __NR_lstat 107 ++#define __NR_fstat 108 ++#define __NR_olduname 109 ++#define __NR_iopl /* 110 */ not supported ++#define __NR_vhangup 111 ++#define __NR_idle /* 112 */ Obsolete ++#define __NR_vm86 /* 113 */ not supported ++#define __NR_wait4 114 ++#define __NR_swapoff 115 ++#define __NR_sysinfo 116 ++#define __NR_ipc 117 ++#define __NR_fsync 118 ++#define __NR_sigreturn 119 ++#define __NR_clone 120 ++#define __NR_setdomainname 121 ++#define __NR_uname 122 ++#define __NR_cacheflush 123 ++#define __NR_adjtimex 124 ++#define __NR_mprotect 125 ++#define __NR_sigprocmask 126 ++#define __NR_create_module 127 ++#define __NR_init_module 128 ++#define __NR_delete_module 129 ++#define __NR_get_kernel_syms 130 ++#define __NR_quotactl 131 ++#define __NR_getpgid 132 ++#define __NR_fchdir 133 ++#define __NR_bdflush 134 ++#define __NR_sysfs 135 ++#define __NR_personality 136 ++#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ ++#define __NR_setfsuid 138 ++#define __NR_setfsgid 139 ++#define __NR__llseek 140 ++#define __NR_getdents 141 ++#define __NR__newselect 142 ++#define __NR_flock 143 ++#define __NR_msync 144 ++#define __NR_readv 145 ++#define __NR_writev 146 ++#define __NR_getsid 147 ++#define __NR_fdatasync 148 ++#define __NR__sysctl 149 ++#define __NR_mlock 150 ++#define __NR_munlock 151 ++#define __NR_mlockall 152 ++#define __NR_munlockall 153 ++#define __NR_sched_setparam 154 ++#define __NR_sched_getparam 155 ++#define __NR_sched_setscheduler 156 ++#define __NR_sched_getscheduler 157 ++#define __NR_sched_yield 158 ++#define __NR_sched_get_priority_max 159 ++#define __NR_sched_get_priority_min 160 ++#define __NR_sched_rr_get_interval 161 ++#define __NR_nanosleep 162 ++#define __NR_mremap 163 ++#define __NR_setresuid 164 ++#define __NR_getresuid 165 ++#define __NR_getpagesize 166 ++#define __NR_query_module 167 ++#define __NR_poll 168 ++#define __NR_nfsservctl 169 ++#define __NR_setresgid 170 ++#define __NR_getresgid 171 ++#define __NR_prctl 172 ++#define __NR_rt_sigreturn 173 ++#define __NR_rt_sigaction 174 ++#define __NR_rt_sigprocmask 175 ++#define __NR_rt_sigpending 176 ++#define __NR_rt_sigtimedwait 177 ++#define __NR_rt_sigqueueinfo 178 ++#define __NR_rt_sigsuspend 179 ++#define __NR_pread 180 ++#define __NR_pwrite 181 ++#define __NR_lchown 182 ++#define __NR_getcwd 183 ++#define __NR_capget 184 ++#define __NR_capset 185 ++#define __NR_sigaltstack 186 ++#define __NR_sendfile 187 ++#define __NR_getpmsg 188 /* some people actually want streams */ ++#define __NR_putpmsg 189 /* some people actually want streams */ ++#define __NR_vfork 190 ++#define __NR_ugetrlimit 191 ++#define __NR_mmap2 192 ++#define __NR_truncate64 193 ++#define __NR_ftruncate64 194 ++#define __NR_stat64 195 ++#define __NR_lstat64 196 ++#define __NR_fstat64 197 ++#define __NR_chown32 198 ++#define __NR_getuid32 199 ++#define __NR_getgid32 200 ++#define __NR_geteuid32 201 ++#define __NR_getegid32 202 ++#define __NR_setreuid32 203 ++#define __NR_setregid32 204 ++#define __NR_getgroups32 205 ++#define __NR_setgroups32 206 ++#define __NR_fchown32 207 ++#define __NR_setresuid32 208 ++#define __NR_getresuid32 209 ++#define __NR_setresgid32 210 ++#define __NR_getresgid32 211 ++#define __NR_lchown32 212 ++#define __NR_setuid32 213 ++#define __NR_setgid32 214 ++#define __NR_setfsuid32 215 ++#define __NR_setfsgid32 216 ++#define __NR_pivot_root 217 ++/* 218 unused */ ++/* 219 unused */ ++#define __NR_getdents64 220 ++#define __NR_gettid 221 ++#define __NR_tkill 222 ++#define __NR_setxattr 223 ++#define __NR_lsetxattr 224 ++#define __NR_fsetxattr 225 ++#define __NR_getxattr 226 ++#define __NR_lgetxattr 227 ++#define __NR_fgetxattr 228 ++#define __NR_listxattr 229 ++#define __NR_llistxattr 230 ++#define __NR_flistxattr 231 ++#define __NR_removexattr 232 ++#define __NR_lremovexattr 233 ++#define __NR_fremovexattr 234 ++#define __NR_futex 235 ++#define __NR_sendfile64 236 ++#define __NR_mincore 237 ++#define __NR_madvise 238 ++#define __NR_fcntl64 239 ++#define __NR_readahead 240 ++#define __NR_io_setup 241 ++#define __NR_io_destroy 242 ++#define __NR_io_getevents 243 ++#define __NR_io_submit 244 ++#define __NR_io_cancel 245 ++#define __NR_fadvise64 246 ++#define __NR_exit_group 247 ++#define __NR_lookup_dcookie 248 ++#define __NR_epoll_create 249 ++#define __NR_epoll_ctl 250 ++#define __NR_epoll_wait 251 ++#define __NR_remap_file_pages 252 ++#define __NR_set_tid_address 253 ++#define __NR_timer_create 254 ++#define __NR_timer_settime 255 ++#define __NR_timer_gettime 256 ++#define __NR_timer_getoverrun 257 ++#define __NR_timer_delete 258 ++#define __NR_clock_settime 259 ++#define __NR_clock_gettime 260 ++#define __NR_clock_getres 261 ++#define __NR_clock_nanosleep 262 ++#define __NR_statfs64 263 ++#define __NR_fstatfs64 264 ++#define __NR_tgkill 265 ++#define __NR_utimes 266 ++#define __NR_fadvise64_64 267 ++#define __NR_mbind 268 ++#define __NR_get_mempolicy 269 ++#define __NR_set_mempolicy 270 ++#define __NR_mq_open 271 ++#define __NR_mq_unlink 272 ++#define __NR_mq_timedsend 273 ++#define __NR_mq_timedreceive 274 ++#define __NR_mq_notify 275 ++#define __NR_mq_getsetattr 276 ++#define __NR_waitid 277 ++#define __NR_sys_setaltroot 278 ++#define __NR_add_key 279 ++#define __NR_request_key 280 ++#define __NR_keyctl 281 ++ ++#define NR_syscalls 282 ++ ++/* user-visible error numbers are in the range -1 - -122: see ++ */ ++ ++#define __syscall_return(type, res) \ ++do { \ ++ if ((unsigned long)(res) >= (unsigned long)(-125)) { \ ++ \ ++ /* avoid using res which is declared to be in \ ++ register r2; errno might expand to a function \ ++ call and clobber it. */ \ ++ \ ++ int __err = -(res); \ ++ errno = __err; \ ++ res = -1; \ ++ } \ ++ return (type) (res); \ ++} while (0) ++ ++#define _syscall0(type,name) \ ++type name(void) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall1 arg a ++//;dgt2;tmp; already being in r4 ? ++#define _syscall1(type,name,atype,a) \ ++type name(atype a) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall2 args a,b ++//;dgt2;tmp; already being in r4,r5 ? ++#define _syscall2(type,name,atype,a,btype,b) \ ++type name(atype a,btype b) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall3 args a,b,c ++//;dgt2;tmp; already being in r4,r5,r6 ? ++#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ ++type name(atype a,btype b,ctype c) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ " mov r6, %5\n\t" /* (long) c */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ , "r" ((long) c) /* %5 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ , "r6" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall4 args a,b,c,d ++//;dgt2;tmp; already being in r4,r5,r6,r7 ? ++#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ ++type name (atype a, btype b, ctype c, dtype d) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ " mov r6, %5\n\t" /* (long) c */ \ ++ " mov r7, %6\n\t" /* (long) d */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ , "r" ((long) c) /* %5 */ \ ++ , "r" ((long) d) /* %6 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ , "r6" /* Clobbered */ \ ++ , "r7" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall5 args a,b,c,d ++//;dgt2;tmp; already being in r4,r5,r6,r7 ? ++#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ ++type name (atype a,btype b,ctype c,dtype d,etype e) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ " mov r6, %5\n\t" /* (long) c */ \ ++ " mov r7, %6\n\t" /* (long) c */ \ ++ " mov r8, %7\n\t" /* (long) e */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ , "r" ((long) c) /* %5 */ \ ++ , "r" ((long) d) /* %6 */ \ ++ , "r" ((long) e) /* %7 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ , "r6" /* Clobbered */ \ ++ , "r7" /* Clobbered */ \ ++ , "r8" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++//;dgt2;tmp;can we RELY on syscall6 args a,b,c,d ++//;dgt2;tmp; already being in r4,r5,r6,r7 ? ++#define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \ ++type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ ++{ \ ++ long __res; \ ++ \ ++ __asm__ __volatile__ ( \ ++ \ ++ " \n\t" \ ++ \ ++ " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ ++ " movi r3, %1\n\t" /* __NR_##name */ \ ++ " mov r4, %3\n\t" /* (long) a */ \ ++ " mov r5, %4\n\t" /* (long) b */ \ ++ " mov r6, %5\n\t" /* (long) c */ \ ++ " mov r7, %6\n\t" /* (long) c */ \ ++ " mov r8, %7\n\t" /* (long) e */ \ ++ " mov r9, %8\n\t" /* (long) f */ \ ++ \ ++ " trap\n\t" \ ++ " mov %0, r2\n\t" /* syscall rtn */ \ ++ \ ++ " \n\t" \ ++ \ ++ : "=r" (__res) /* %0 */ \ ++ \ ++ : "i" (__NR_##name) /* %1 */ \ ++ , "i" (TRAP_ID_SYSCALL) /* %2 */ \ ++ , "r" ((long) a) /* %3 */ \ ++ , "r" ((long) b) /* %4 */ \ ++ , "r" ((long) c) /* %5 */ \ ++ , "r" ((long) d) /* %6 */ \ ++ , "r" ((long) e) /* %7 */ \ ++ , "r" ((long) f) /* %8 */ \ ++ \ ++ : "r2" /* Clobbered */ \ ++ , "r3" /* Clobbered */ \ ++ , "r4" /* Clobbered */ \ ++ , "r5" /* Clobbered */ \ ++ , "r6" /* Clobbered */ \ ++ , "r7" /* Clobbered */ \ ++ , "r8" /* Clobbered */ \ ++ , "r9" /* Clobbered */ \ ++ ); \ ++ \ ++__syscall_return(type,__res); \ ++} ++ ++#ifdef __KERNEL__ ++#define __ARCH_WANT_IPC_PARSE_VERSION ++#define __ARCH_WANT_OLD_READDIR ++#define __ARCH_WANT_OLD_STAT ++#define __ARCH_WANT_STAT64 ++#define __ARCH_WANT_SYS_ALARM ++#define __ARCH_WANT_SYS_GETHOSTNAME ++#define __ARCH_WANT_SYS_PAUSE ++#define __ARCH_WANT_SYS_SGETMASK ++#define __ARCH_WANT_SYS_SIGNAL ++#define __ARCH_WANT_SYS_TIME ++#define __ARCH_WANT_SYS_UTIME ++#define __ARCH_WANT_SYS_WAITPID ++#define __ARCH_WANT_SYS_SOCKETCALL ++#define __ARCH_WANT_SYS_FADVISE64 ++#define __ARCH_WANT_SYS_GETPGRP ++#define __ARCH_WANT_SYS_LLSEEK ++#define __ARCH_WANT_SYS_NICE ++#define __ARCH_WANT_SYS_OLD_GETRLIMIT ++#define __ARCH_WANT_SYS_OLDUMOUNT ++#define __ARCH_WANT_SYS_SIGPENDING ++#define __ARCH_WANT_SYS_SIGPROCMASK ++#define __ARCH_WANT_SYS_RT_SIGACTION ++#endif ++ ++#ifdef __KERNEL_SYSCALLS__ ++ ++/* ++ * we need this inline - forking from kernel space will result ++ * in NO COPY ON WRITE (!!!), until an execve is executed. This ++ * is no problem, but for the stack. This is handled by not letting ++ * main() use the stack at all after fork(). Thus, no function ++ * calls - which means inline code for fork too, as otherwise we ++ * would use the stack upon exit from 'fork()'. ++ * ++ * Actually only pause and fork are needed inline, so that there ++ * won't be any messing with the stack from main(), but we define ++ * some others too. ++ */ ++#define __NR__exit __NR_exit ++static inline _syscall0(int,pause) ++static inline _syscall0(int,sync) ++static inline _syscall0(pid_t,setsid) ++static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) ++static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) ++static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) ++static inline _syscall1(int,dup,int,fd) ++static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) ++static inline _syscall3(int,open,const char *,file,int,flag,int,mode) ++static inline _syscall1(int,close,int,fd) ++static inline _syscall1(int,_exit,int,exitcode) ++static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) ++static inline _syscall1(int,delete_module,const char *,name) ++ ++static inline pid_t wait(int * wait_stat) ++{ ++ return waitpid(-1,wait_stat,0); ++} ++ ++#endif ++ ++/* ++ * "Conditional" syscalls ++ * ++ * What we want is __attribute__((weak,alias("sys_ni_syscall"))), ++ * but it doesn't work on all toolchains, so we just do it by hand ++ */ ++#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); ++ ++#endif /* _ASM_NIOS_UNISTD_H_ */ +--- linux/include/asm-nios2nommu/user.h ++++ linux/include/asm-nios2nommu/user.h +@@ -0,0 +1,112 @@ ++#ifndef _NIOS2NOMMU_USER_H ++#define _NIOS2NOMMU_USER_H ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/user.h ++ * ++ * Derived from M68knommu ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++#include ++ ++/* Core file format: The core file is written in such a way that gdb ++ can understand it and provide useful information to the user (under ++ linux we use the 'trad-core' bfd). There are quite a number of ++ obstacles to being able to view the contents of the floating point ++ registers, and until these are solved you will not be able to view the ++ contents of them. Actually, you can read in the core file and look at ++ the contents of the user struct to find out what the floating point ++ registers contain. ++ The actual file contents are as follows: ++ UPAGE: 1 page consisting of a user struct that tells gdb what is present ++ in the file. Directly after this is a copy of the task_struct, which ++ is currently not used by gdb, but it may come in useful at some point. ++ All of the registers are stored as part of the upage. The upage should ++ always be only one page. ++ DATA: The data area is stored. We use current->end_text to ++ current->brk to pick up all of the user variables, plus any memory ++ that may have been malloced. No attempt is made to determine if a page ++ is demand-zero or if a page is totally unused, we just cover the entire ++ range. All of the addresses are rounded in such a way that an integral ++ number of pages is written. ++ STACK: We need the stack information in order to get a meaningful ++ backtrace. We need to write the data from (esp) to ++ current->start_stack, so we round each of these off in order to be able ++ to write an integer number of pages. ++ The minimum core file size is 3 pages, or 12288 bytes. ++*/ ++ ++struct user_m68kfp_struct { ++ unsigned long fpregs[8*3]; /* fp0-fp7 registers */ ++ unsigned long fpcntl[3]; /* fp control regs */ ++}; ++ ++/* This is needs more work, probably should look like gdb useage */ ++struct user_regs_struct { ++ long r1,r2,r3,r4,r5,r6,r7,r8; ++ long r9,r10,r11,r12,r13,r14,r15; ++ long r16,r17,r18,r19,r20,r21,r22,r23; ++ long gp; ++ long sp; ++ long ra; ++ long fp; ++ long orig_r2; ++ long estatus; ++ long status_extension; ++ long ea; ++}; ++ ++ ++/* When the kernel dumps core, it starts by dumping the user struct - ++ this will be used by gdb to figure out where the data and stack segments ++ are within the file, and what virtual addresses to use. */ ++struct user{ ++/* We start with the registers, to mimic the way that "memory" is returned ++ from the ptrace(3,...) function. */ ++ struct user_regs_struct regs; /* Where the registers are actually stored */ ++/* ptrace does not yet supply these. Someday.... */ ++ int u_fpvalid; /* True if math co-processor being used. */ ++ /* for this mess. Not yet used. */ ++ struct user_m68kfp_struct m68kfp; /* Math Co-processor registers. */ ++/* The rest of this junk is to help gdb figure out what goes where */ ++ unsigned long int u_tsize; /* Text segment size (pages). */ ++ unsigned long int u_dsize; /* Data segment size (pages). */ ++ unsigned long int u_ssize; /* Stack segment size (pages). */ ++ unsigned long start_code; /* Starting virtual address of text. */ ++ unsigned long start_stack; /* Starting virtual address of stack area. ++ This is actually the bottom of the stack, ++ the top of the stack is always found in the ++ esp register. */ ++ long int signal; /* Signal that caused the core dump. */ ++ int reserved; /* No longer used */ ++ struct user_regs_struct *u_ar0; ++ /* Used by gdb to help find the values for */ ++ /* the registers. */ ++ struct user_m68kfp_struct* u_fpstate; /* Math Co-processor pointer. */ ++ unsigned long magic; /* To uniquely identify a core file */ ++ char u_comm[32]; /* User command that was responsible */ ++}; ++#define NBPG PAGE_SIZE ++#define UPAGES 1 ++#define HOST_TEXT_START_ADDR (u.start_code) ++#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) ++ ++#endif +--- linux/include/asm-nios2nommu/virtconvert.h ++++ linux/include/asm-nios2nommu/virtconvert.h +@@ -0,0 +1,47 @@ ++#ifndef __NIOS_VIRT_CONVERT__ ++#define __NIOS_VIRT_CONVERT__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * include/asm-nios2nommu/virtconvert.h ++ * ++ * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al ++ * ++ * Copyright (C) 2004 Microtronix Datacom Ltd ++ * ++ * 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. ++ * ++ * ++ * Jan/20/2004 dgt NiosII ++ * ++ ---------------------------------------------------------------------*/ ++ ++ ++/* ++ * Macros used for converting between virtual and physical mappings. ++ */ ++ ++#ifdef __KERNEL__ ++ ++// #include ++#include ++#include ++ ++#define mm_ptov(vaddr) ((void *) (vaddr)) ++#define mm_vtop(vaddr) ((unsigned long) (vaddr)) ++#define phys_to_virt(vaddr) ((void *) (vaddr)) ++#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) ++ ++#define virt_to_bus virt_to_phys ++#define bus_to_virt phys_to_virt ++ ++#endif /*__KERNEL__ */ ++#endif /*__NIOS_VIRT_CONVERT__*/ diff --git a/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.21.5-001-lzma-vmlinuz.00.patch b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.21.5-001-lzma-vmlinuz.00.patch new file mode 100644 index 0000000000..87e50f8be7 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.21.5-001-lzma-vmlinuz.00.patch @@ -0,0 +1,27017 @@ +diff --git a/.miniconfig b/.miniconfig +new file mode 100644 +index 0000000..5686e53 +--- /dev/null ++++ b/.miniconfig +@@ -0,0 +1,89 @@ ++#make allnoconfig KCONFIG_ALLCONFIG=miniconfig ++CONFIG_X86_32=y ++CONFIG_CLOCKSOURCE_WATCHDOG=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_SEMAPHORE_SLEEPERS=y ++CONFIG_MMU=y ++CONFIG_GENERIC_ISA_DMA=y ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_DMI=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_SYSFS_DEPRECATED=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_SYSCTL=y ++CONFIG_EMBEDDED=y ++CONFIG_PRINTK=y ++CONFIG_BASE_SMALL=1 ++CONFIG_BLOCK=y ++CONFIG_IOSCHED_NOOP=y ++CONFIG_DEFAULT_IOSCHED="noop" ++CONFIG_X86_GENERIC=y ++CONFIG_X86_L1_CACHE_SHIFT=7 ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_X86_WP_WORKS_OK=y ++CONFIG_X86_BSWAP=y ++CONFIG_X86_CMPXCHG64=y ++CONFIG_X86_INTEL_USERCOPY=y ++CONFIG_X86_TSC=y ++CONFIG_PREEMPT_NONE=y ++CONFIG_VM86=y ++CONFIG_HIGHMEM=y ++CONFIG_FLATMEM=y ++CONFIG_MTRR=y ++CONFIG_HZ_250=y ++CONFIG_PHYSICAL_ALIGN=0x100000 ++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y ++CONFIG_PM=y ++CONFIG_ACPI=y ++CONFIG_ACPI_SLEEP=y ++CONFIG_ACPI_BLACKLIST_YEAR=0 ++CONFIG_ACPI_EC=y ++CONFIG_ACPI_SYSTEM=y ++CONFIG_PCI=y ++CONFIG_PCI_GOANY=y ++CONFIG_PCI_DIRECT=y ++CONFIG_BINFMT_ELF=y ++CONFIG_STANDALONE=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_IDE=y ++CONFIG_IDE_MAX_HWIFS=2 ++CONFIG_BLK_DEV_IDE=y ++CONFIG_BLK_DEV_IDEDISK=y ++CONFIG_IDEDISK_MULTI_MODE=y ++CONFIG_BLK_DEV_IDECD=y ++CONFIG_IDE_GENERIC=y ++CONFIG_INPUT_MOUSEDEV=y ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 ++CONFIG_INPUT_KEYBOARD=y ++CONFIG_KEYBOARD_ATKBD=y ++CONFIG_SERIO=y ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_UNIX98_PTYS=y ++CONFIG_VGA_CONSOLE=y ++CONFIG_USB_ARCH_HAS_HCD=y ++CONFIG_USB_ARCH_HAS_EHCI=y ++CONFIG_EXT2_FS=y ++CONFIG_DNOTIFY=y ++CONFIG_ISO9660_FS=y ++CONFIG_FAT_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++CONFIG_PROC_FS=y ++CONFIG_PROC_SYSCTL=y ++CONFIG_SYSFS=y ++CONFIG_RAMFS=y ++CONFIG_SQUASHFS=y ++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 ++CONFIG_MSDOS_PARTITION=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_AUFS=y ++CONFIG_AUFS_FAKE_DM=y ++CONFIG_EARLY_PRINTK=y ++CONFIG_DOUBLEFAULT=y ++CONFIG_ZLIB_INFLATE=y ++CONFIG_HAS_IOPORT=y ++CONFIG_GENERIC_IRQ_PROBE=y ++CONFIG_KTIME_SCALAR=y +diff --git a/Makefile b/Makefile +index d970cb1..a369204 100644 +--- a/Makefile ++++ b/Makefile +@@ -188,7 +188,7 @@ CROSS_COMPILE ?= + # Architecture as present in compile.h + UTS_MACHINE := $(ARCH) + +-KCONFIG_CONFIG ?= .config ++KCONFIG_CONFIG ?= .miniconfig + + # SHELL used by kbuild + CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ +diff --git a/arch/i386/boot/compressed/LzmaDecode.c b/arch/i386/boot/compressed/LzmaDecode.c +new file mode 100644 +index 0000000..21bf40b +--- /dev/null ++++ b/arch/i386/boot/compressed/LzmaDecode.c +@@ -0,0 +1,588 @@ ++/* ++ LzmaDecode.c ++ LZMA Decoder (optimized for Speed version) ++ ++ LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this Code, expressly permits you to ++ statically or dynamically link your Code (or bind by name) to the ++ interfaces of this file without subjecting your linked Code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#include "LzmaDecode.h" ++ ++#ifndef Byte ++#define Byte unsigned char ++#endif ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_READ_BYTE (*Buffer++) ++ ++#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ ++ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} ++ ++#ifdef _LZMA_IN_CB ++ ++#define RC_TEST { if (Buffer == BufferLim) \ ++ { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \ ++ BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }} ++ ++#define RC_INIT Buffer = BufferLim = 0; RC_INIT2 ++ ++#else ++ ++#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } ++ ++#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 ++ ++#endif ++ ++#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } ++ ++#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) ++#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; ++#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; ++ ++#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ ++ { UpdateBit0(p); mi <<= 1; A0; } else \ ++ { UpdateBit1(p); mi = (mi + mi) + 1; A1; } ++ ++#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) ++ ++#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ ++ { int i = numLevels; res = 1; \ ++ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \ ++ res -= (1 << numLevels); } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) ++{ ++ unsigned char prop0; ++ if (size < LZMA_PROPERTIES_SIZE) ++ return LZMA_RESULT_DATA_ERROR; ++ prop0 = propsData[0]; ++ if (prop0 >= (9 * 5 * 5)) ++ return LZMA_RESULT_DATA_ERROR; ++ { ++ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); ++ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); ++ propsRes->lc = prop0; ++ /* ++ unsigned char remainder = (unsigned char)(prop0 / 9); ++ propsRes->lc = prop0 % 9; ++ propsRes->pb = remainder / 5; ++ propsRes->lp = remainder % 5; ++ */ ++ } ++ ++ #ifdef _LZMA_OUT_READ ++ { ++ int i; ++ propsRes->DictionarySize = 0; ++ for (i = 0; i < 4; i++) ++ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); ++ if (propsRes->DictionarySize == 0) ++ propsRes->DictionarySize = 1; ++ } ++ #endif ++ return LZMA_RESULT_OK; ++} ++ ++#define kLzmaStreamWasFinishedId (-1) ++ ++int LzmaDecode(CLzmaDecoderState *vs, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *InCallback, ++ #else ++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, ++ #endif ++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) ++{ ++ CProb *p = vs->Probs; ++ SizeT nowPos = 0; ++ Byte previousByte = 0; ++ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; ++ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; ++ int lc = vs->Properties.lc; ++ ++ #ifdef _LZMA_OUT_READ ++ ++ UInt32 Range = vs->Range; ++ UInt32 Code = vs->Code; ++ #ifdef _LZMA_IN_CB ++ const Byte *Buffer = vs->Buffer; ++ const Byte *BufferLim = vs->BufferLim; ++ #else ++ const Byte *Buffer = inStream; ++ const Byte *BufferLim = inStream + inSize; ++ #endif ++ int state = vs->State; ++ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; ++ int len = vs->RemainLen; ++ UInt32 globalPos = vs->GlobalPos; ++ UInt32 distanceLimit = vs->DistanceLimit; ++ ++ Byte *dictionary = vs->Dictionary; ++ UInt32 dictionarySize = vs->Properties.DictionarySize; ++ UInt32 dictionaryPos = vs->DictionaryPos; ++ ++ Byte tempDictionary[4]; ++ ++ #ifndef _LZMA_IN_CB ++ *inSizeProcessed = 0; ++ #endif ++ *outSizeProcessed = 0; ++ if (len == kLzmaStreamWasFinishedId) ++ return LZMA_RESULT_OK; ++ ++ if (dictionarySize == 0) ++ { ++ dictionary = tempDictionary; ++ dictionarySize = 1; ++ tempDictionary[0] = vs->TempDictionary[0]; ++ } ++ ++ if (len == kLzmaNeedInitId) ++ { ++ { ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); ++ UInt32 i; ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ rep0 = rep1 = rep2 = rep3 = 1; ++ state = 0; ++ globalPos = 0; ++ distanceLimit = 0; ++ dictionaryPos = 0; ++ dictionary[dictionarySize - 1] = 0; ++ #ifdef _LZMA_IN_CB ++ RC_INIT; ++ #else ++ RC_INIT(inStream, inSize); ++ #endif ++ } ++ len = 0; ++ } ++ while(len != 0 && nowPos < outSize) ++ { ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ len--; ++ } ++ if (dictionaryPos == 0) ++ previousByte = dictionary[dictionarySize - 1]; ++ else ++ previousByte = dictionary[dictionaryPos - 1]; ++ ++ #else /* if !_LZMA_OUT_READ */ ++ ++ int state = 0; ++ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; ++ int len = 0; ++ const Byte *Buffer; ++ const Byte *BufferLim; ++ UInt32 Range; ++ UInt32 Code; ++ ++ #ifndef _LZMA_IN_CB ++ *inSizeProcessed = 0; ++ #endif ++ *outSizeProcessed = 0; ++ ++ { ++ UInt32 i; ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ } ++ ++ #ifdef _LZMA_IN_CB ++ RC_INIT; ++ #else ++ RC_INIT(inStream, inSize); ++ #endif ++ ++ #endif /* _LZMA_OUT_READ */ ++ ++ while(nowPos < outSize) ++ { ++ CProb *prob; ++ UInt32 bound; ++ int posState = (int)( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & posStateMask); ++ ++ prob = p + IsMatch + (state << kNumPosBitsMax) + posState; ++ IfBit0(prob) ++ { ++ int symbol = 1; ++ UpdateBit0(prob) ++ prob = p + Literal + (LZMA_LIT_SIZE * ++ ((( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & literalPosMask) << lc) + (previousByte >> (8 - lc)))); ++ ++ if (state >= kNumLitStates) ++ { ++ int matchByte; ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ matchByte = dictionary[pos]; ++ #else ++ matchByte = outStream[nowPos - rep0]; ++ #endif ++ do ++ { ++ int bit; ++ CProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & 0x100); ++ probLit = prob + 0x100 + bit + symbol; ++ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) ++ } ++ while (symbol < 0x100); ++ } ++ while (symbol < 0x100) ++ { ++ CProb *probLit = prob + symbol; ++ RC_GET_BIT(probLit, symbol) ++ } ++ previousByte = (Byte)symbol; ++ ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit < dictionarySize) ++ distanceLimit++; ++ ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #endif ++ if (state < 4) state = 0; ++ else if (state < 10) state -= 3; ++ else state -= 6; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRep + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ state = state < kNumLitStates ? 0 : 3; ++ prob = p + LenCoder; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRepG0 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IfBit0(prob) ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos; ++ #endif ++ UpdateBit0(prob); ++ ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit == 0) ++ #else ++ if (nowPos == 0) ++ #endif ++ return LZMA_RESULT_DATA_ERROR; ++ ++ state = state < kNumLitStates ? 9 : 11; ++ #ifdef _LZMA_OUT_READ ++ pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit < dictionarySize) ++ distanceLimit++; ++ #endif ++ ++ continue; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ } ++ } ++ else ++ { ++ UInt32 distance; ++ UpdateBit1(prob); ++ prob = p + IsRepG1 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRepG2 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = p + RepLenCoder; ++ } ++ { ++ int numBits, offset; ++ CProb *probLen = prob + LenChoice; ++ IfBit0(probLen) ++ { ++ UpdateBit0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ numBits = kLenNumLowBits; ++ } ++ else ++ { ++ UpdateBit1(probLen); ++ probLen = prob + LenChoice2; ++ IfBit0(probLen) ++ { ++ UpdateBit0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ numBits = kLenNumMidBits; ++ } ++ else ++ { ++ UpdateBit1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ numBits = kLenNumHighBits; ++ } ++ } ++ RangeDecoderBitTreeDecode(probLen, numBits, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ int posSlot; ++ state += kNumLitStates; ++ prob = p + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ rep0 = (2 | ((UInt32)posSlot & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ rep0 <<= numDirectBits; ++ prob = p + SpecPos + rep0 - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ RC_NORMALIZE ++ Range >>= 1; ++ rep0 <<= 1; ++ if (Code >= Range) ++ { ++ Code -= Range; ++ rep0 |= 1; ++ } ++ } ++ while (--numDirectBits != 0); ++ prob = p + Align; ++ rep0 <<= kNumAlignBits; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ int i = 1; ++ int mi = 1; ++ do ++ { ++ CProb *prob3 = prob + mi; ++ RC_GET_BIT2(prob3, mi, ; , rep0 |= i); ++ i <<= 1; ++ } ++ while(--numDirectBits != 0); ++ } ++ } ++ else ++ rep0 = posSlot; ++ if (++rep0 == (UInt32)(0)) ++ { ++ /* it's for stream version */ ++ len = kLzmaStreamWasFinishedId; ++ break; ++ } ++ } ++ ++ len += kMatchMinLen; ++ #ifdef _LZMA_OUT_READ ++ if (rep0 > distanceLimit) ++ #else ++ if (rep0 > nowPos) ++ #endif ++ return LZMA_RESULT_DATA_ERROR; ++ ++ #ifdef _LZMA_OUT_READ ++ if (dictionarySize - distanceLimit > (UInt32)len) ++ distanceLimit += len; ++ else ++ distanceLimit = dictionarySize; ++ #endif ++ ++ do ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ len--; ++ outStream[nowPos++] = previousByte; ++ } ++ while(len != 0 && nowPos < outSize); ++ } ++ } ++ RC_NORMALIZE; ++ ++ #ifdef _LZMA_OUT_READ ++ vs->Range = Range; ++ vs->Code = Code; ++ vs->DictionaryPos = dictionaryPos; ++ vs->GlobalPos = globalPos + (UInt32)nowPos; ++ vs->DistanceLimit = distanceLimit; ++ vs->Reps[0] = rep0; ++ vs->Reps[1] = rep1; ++ vs->Reps[2] = rep2; ++ vs->Reps[3] = rep3; ++ vs->State = state; ++ vs->RemainLen = len; ++ vs->TempDictionary[0] = tempDictionary[0]; ++ #endif ++ ++ #ifdef _LZMA_IN_CB ++ vs->Buffer = Buffer; ++ vs->BufferLim = BufferLim; ++ #else ++ *inSizeProcessed = (SizeT)(Buffer - inStream); ++ #endif ++ *outSizeProcessed = nowPos; ++ return LZMA_RESULT_OK; ++} +diff --git a/arch/i386/boot/compressed/LzmaDecode.h b/arch/i386/boot/compressed/LzmaDecode.h +new file mode 100644 +index 0000000..213062a +--- /dev/null ++++ b/arch/i386/boot/compressed/LzmaDecode.h +@@ -0,0 +1,131 @@ ++/* ++ LzmaDecode.h ++ LZMA Decoder interface ++ ++ LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this code, expressly permits you to ++ statically or dynamically link your code (or bind by name) to the ++ interfaces of this file without subjecting your linked code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#ifndef __LZMADECODE_H ++#define __LZMADECODE_H ++ ++/* #define _LZMA_IN_CB */ ++/* Use callback for input data */ ++ ++/* #define _LZMA_OUT_READ */ ++/* Use read function for output data */ ++ ++/* #define _LZMA_PROB32 */ ++/* It can increase speed on some 32-bit CPUs, ++ but memory usage will be doubled in that case */ ++ ++/* #define _LZMA_LOC_OPT */ ++/* Enable local speed optimizations inside code */ ++ ++/* #define _LZMA_SYSTEM_SIZE_T */ ++/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/ ++ ++#ifndef UInt32 ++#ifdef _LZMA_UINT32_IS_ULONG ++#define UInt32 unsigned long ++#else ++#define UInt32 unsigned int ++#endif ++#endif ++ ++#ifndef SizeT ++#ifdef _LZMA_SYSTEM_SIZE_T ++#include ++#define SizeT size_t ++#else ++#define SizeT UInt32 ++#endif ++#endif ++ ++#ifdef _LZMA_PROB32 ++#define CProb UInt32 ++#else ++#define CProb unsigned short ++#endif ++ ++#define LZMA_RESULT_OK 0 ++#define LZMA_RESULT_DATA_ERROR 1 ++ ++#ifdef _LZMA_IN_CB ++typedef struct _ILzmaInCallback ++{ ++ int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize); ++} ILzmaInCallback; ++#endif ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LZMA_PROPERTIES_SIZE 5 ++ ++typedef struct _CLzmaProperties ++{ ++ int lc; ++ int lp; ++ int pb; ++ #ifdef _LZMA_OUT_READ ++ UInt32 DictionarySize; ++ #endif ++}CLzmaProperties; ++ ++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); ++ ++#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) ++ ++#define kLzmaNeedInitId (-2) ++ ++typedef struct _CLzmaDecoderState ++{ ++ CLzmaProperties Properties; ++ CProb *Probs; ++ ++ #ifdef _LZMA_IN_CB ++ const unsigned char *Buffer; ++ const unsigned char *BufferLim; ++ #endif ++ ++ #ifdef _LZMA_OUT_READ ++ unsigned char *Dictionary; ++ UInt32 Range; ++ UInt32 Code; ++ UInt32 DictionaryPos; ++ UInt32 GlobalPos; ++ UInt32 DistanceLimit; ++ UInt32 Reps[4]; ++ int State; ++ int RemainLen; ++ unsigned char TempDictionary[4]; ++ #endif ++} CLzmaDecoderState; ++ ++#ifdef _LZMA_OUT_READ ++#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; } ++#endif ++ ++int LzmaDecode(CLzmaDecoderState *vs, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback, ++ #else ++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, ++ #endif ++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); ++ ++#endif +diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile +index a661217..fb40869 100644 +--- a/arch/i386/boot/compressed/Makefile ++++ b/arch/i386/boot/compressed/Makefile +@@ -4,15 +4,16 @@ + # create a compressed vmlinux image from the original vmlinux + # + +-targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o \ +- vmlinux.bin.all vmlinux.relocs ++tragets := head.o lzma_misc.o piggy.o \ ++ vmlinux.bin.all vmlinux.relocs \ ++ vmlinux vmlinux.bin vmlinux.bin.gz + EXTRA_AFLAGS := -traditional + + LDFLAGS_vmlinux := -T +-CFLAGS_misc.o += -fPIC ++CFLAGS_lzma_misc.o += -fPIC + hostprogs-y := relocs + +-$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE ++$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/lzma_misc.o $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +@@ -33,10 +34,10 @@ $(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE + + ifdef CONFIG_RELOCATABLE + $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE +- $(call if_changed,gzip) ++ $(call if_changed,lzma) + else + $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE +- $(call if_changed,gzip) ++ $(call if_changed,lzma) + endif + + LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T +diff --git a/arch/i386/boot/compressed/lzma_misc.c b/arch/i386/boot/compressed/lzma_misc.c +new file mode 100644 +index 0000000..4f5f7f9 +--- /dev/null ++++ b/arch/i386/boot/compressed/lzma_misc.c +@@ -0,0 +1,290 @@ ++/* ++ * lzma_misc.c ++ * ++ * Decompress LZMA compressed vmlinuz ++ * Version 0.9 Copyright (c) Ming-Ching Tiew mctiew@yahoo.com ++ * Program adapted from misc.c for 2.6.20.1 kernel ++ * Please refer to misc.c for authorship and copyright. ++ * Date: 25 March 2007 ++ * Source released under GPL ++ */ ++ ++#undef CONFIG_PARAVIRT ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* WARNING!! ++ * This code is compiled with -fPIC and it is relocated dynamically ++ * at run time, but no relocation processing is performed. ++ * This means that it is not safe to place pointers in static structures. ++ */ ++ ++#define OF(args) args ++#define STATIC static ++ ++#undef memset ++#undef memcpy ++ ++typedef unsigned char uch; ++typedef unsigned short ush; ++typedef unsigned long ulg; ++ ++#define WSIZE 0x80000000 /* Window size must be at least 32k, ++ * and a power of two ++ * We don't actually have a window just ++ * a huge output buffer so I report ++ * a 2G windows size, as that should ++ * always be larger than our output buffer. ++ */ ++ ++static uch *inbuf; /* input buffer */ ++static uch *window; /* Sliding window buffer, (and final output buffer) */ ++ ++static unsigned insize; /* valid bytes in inbuf */ ++static unsigned inptr; /* index of next byte to be processed in inbuf */ ++ ++/* gzip flag byte */ ++#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ ++#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ ++#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ ++#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ ++#define COMMENT 0x10 /* bit 4 set: file comment present */ ++#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ ++#define RESERVED 0xC0 /* bit 6,7: reserved */ ++ ++#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) ++ ++/* Diagnostic functions */ ++#ifdef DEBUG ++# define Assert(cond,msg) {if(!(cond)) error(msg);} ++# define Trace(x) fprintf x ++# define Tracev(x) {if (verbose) fprintf x ;} ++# define Tracevv(x) {if (verbose>1) fprintf x ;} ++# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} ++# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} ++#else ++# define Assert(cond,msg) ++# define Trace(x) ++# define Tracev(x) ++# define Tracevv(x) ++# define Tracec(c,x) ++# define Tracecv(c,x) ++#endif ++ ++static int fill_inbuf(void); ++static void error(char *m); ++ ++/* ++ * This is set up by the setup-routine at boot-time ++ */ ++static unsigned char *real_mode; /* Pointer to real-mode data */ ++ ++#define RM_EXT_MEM_K (*(unsigned short *)(real_mode + 0x2)) ++#ifndef STANDARD_MEMORY_BIOS_CALL ++#define RM_ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0)) ++#endif ++#define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0)) ++ ++extern unsigned char input_data[]; ++extern int input_len; ++ ++static long bytes_out = 0; ++ ++static void *memcpy(void *dest, const void *src, unsigned n); ++ ++static void putstr(const char *); ++ ++static unsigned long free_mem_ptr; ++static unsigned long free_mem_end_ptr; ++ ++#define HEAP_SIZE 0x3000 ++ ++static char *vidmem = (char *)0xb8000; ++static int vidport; ++static int lines, cols; ++ ++#ifdef CONFIG_X86_NUMAQ ++void *xquad_portio; ++#endif ++ ++static void scroll(void) ++{ ++ int i; ++ ++ memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); ++ for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) ++ vidmem[i] = ' '; ++} ++ ++static void putstr(const char *s) ++{ ++ int x,y,pos; ++ char c; ++ ++ x = RM_SCREEN_INFO.orig_x; ++ y = RM_SCREEN_INFO.orig_y; ++ ++ while ( ( c = *s++ ) != '\0' ) { ++ if ( c == '\n' ) { ++ x = 0; ++ if ( ++y >= lines ) { ++ scroll(); ++ y--; ++ } ++ } else { ++ vidmem [ ( x + cols * y ) * 2 ] = c; ++ if ( ++x >= cols ) { ++ x = 0; ++ if ( ++y >= lines ) { ++ scroll(); ++ y--; ++ } ++ } ++ } ++ } ++ ++ RM_SCREEN_INFO.orig_x = x; ++ RM_SCREEN_INFO.orig_y = y; ++ ++ pos = (x + cols * y) * 2; /* Update cursor position */ ++ outb_p(14, vidport); ++ outb_p(0xff & (pos >> 9), vidport+1); ++ outb_p(15, vidport); ++ outb_p(0xff & (pos >> 1), vidport+1); ++} ++ ++static void* memcpy(void* dest, const void* src, unsigned n) ++{ ++ int i; ++ char *d = (char *)dest, *s = (char *)src; ++ ++ for (i=0;i ((-__PAGE_OFFSET-(512 <<20)-1) & 0x7fffffff)) ++ error("Destination address too large"); ++#ifndef CONFIG_RELOCATABLE ++ if ((u32)output != LOAD_PHYSICAL_ADDR) ++ error("Wrong destination address"); ++#endif ++ if( lzma_unzip(output) != 0 ) ++ { ++ error("inflate error\n"); ++ } ++ putstr("Ok, booting the kernel.\n"); ++ ++ return; ++} +diff --git a/arch/i386/boot/compressed/vmlinux.scr b/arch/i386/boot/compressed/vmlinux.scr +index 707a88f..9d67263 100644 +--- a/arch/i386/boot/compressed/vmlinux.scr ++++ b/arch/i386/boot/compressed/vmlinux.scr +@@ -3,8 +3,8 @@ SECTIONS + .data.compressed : { + input_len = .; + LONG(input_data_end - input_data) input_data = .; ++ output_len = . + 5; + *(.data) +- output_len = . - 4; + input_data_end = .; + } + } +diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig +index 17ee97f..64b7bda 100644 +--- a/drivers/block/Kconfig ++++ b/drivers/block/Kconfig +@@ -406,6 +406,47 @@ config BLK_DEV_RAM_BLOCKSIZE + setups function - apparently needed by the rd_load_image routine + that supposes the filesystem in the image uses a 1024 blocksize. + ++config LZMA_INITRD ++ boolean "Allow LZMA compression on initrd" ++ depends on BLK_DEV_INITRD=y ++ default "y" ++ help ++ Use lzma compression on initrd, example 'lzma e initrd initrd.7z -d16'. ++ If you have sufficient memory, you could compress using bigger dictionary size, ++ 'lzma e initrd initrd.7z'. ++ ++config LZMA_INITRD_KMALLOC_ONLY ++ boolean "Use only kmalloc, do not use vmalloc on lzma initrd" ++ depends on LZMA_INITRD=y ++ default "n" ++ help ++ Set to y if you do not want to use vmalloc, ie use only kmalloc. ++ ++config LZMA_INITRAM_FS ++ boolean "Allow LZMA compression on initramfs" ++ depends on BLK_DEV_RAM=y ++ default "y" ++ help ++ Use lzma compression on initramfs, example 'lzma e initramfs.cpio initramfs.cpio.lzma'. ++ ++config LZMA_INITRAM_FS_SMALLMEM ++ boolean "Use lzma compression with small dictonary size." ++ depends on LZMA_INITRAM_FS=y ++ default "y" ++ help ++ Use lzma compression on initramfs with small dictionary size, example ++ 'lzma e initramfs.cpio initramfs.cpio.lzma -d16'. ++ Affects only the initramfs.cpio in the ~usr directory, which is compiled into ++ the kernel. If you prepared initramfs.cpio for use with bootloader, you would ++ need to specify the commandline options (-d16) yourself. ++ ++config LZMA_INITRAM_FS_KMALLOC_ONLY ++ boolean "Use only kmalloc, do not use vmalloc on lzma initramfs" ++ depends on LZMA_INITRAM_FS=y ++ default "n" ++ help ++ Set to y if you do not want to use vmalloc, ie use only kmalloc. ++ + config CDROM_PKTCDVD + tristate "Packet writing on CD/DVD media" + depends on !UML +diff --git a/fs/Kconfig b/fs/Kconfig +index 3c4886b..bdcc6fb 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -1371,6 +1371,71 @@ config CRAMFS + + If unsure, say N. + ++config SQUASHFS ++ tristate "SquashFS 3.2 - Squashed file system support" ++ select ZLIB_INFLATE ++ help ++ Saying Y here includes support for SquashFS 3.2 (a Compressed Read-Only File ++ System). Squashfs is a highly compressed read-only filesystem for Linux. ++ It uses zlib compression to compress both files, inodes and directories. ++ Inodes in the system are very small and all blocks are packed to minimise ++ data overhead. Block sizes greater than 4K are supported up to a maximum of 64K. ++ SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full ++ uid/gid information, hard links and timestamps. ++ ++ Squashfs is intended for general read-only filesystem use, for archival ++ use (i.e. in cases where a .tar.gz file may be used), and in embedded ++ systems where low overhead is needed. Further information and filesystem tools ++ are available from http://squashfs.sourceforge.net. ++ ++ If you want to compile this as a module ( = code which can be ++ inserted in and removed from the running kernel whenever you want), ++ say M here and read . The module ++ will be called squashfs. Note that the root file system (the one ++ containing the directory /) cannot be compiled as a module. ++ ++ If unsure, say N. ++ ++config SQUASHFS_EMBEDDED ++ ++ bool "Additional options for memory-constrained systems" ++ depends on SQUASHFS ++ default n ++ help ++ Saying Y here allows you to specify cache sizes and how Squashfs ++ allocates memory. This is only intended for memory constrained ++ systems. ++ ++ If unsure, say N. ++ ++config SQUASHFS_FRAGMENT_CACHE_SIZE ++ int "Number of fragments cached" if SQUASHFS_EMBEDDED ++ depends on SQUASHFS ++ default "3" ++ help ++ By default SquashFS caches the last 3 fragments read from ++ the filesystem. Increasing this amount may mean SquashFS ++ has to re-read fragments less often from disk, at the expense ++ of extra system memory. Decreasing this amount will mean ++ SquashFS uses less memory at the expense of extra reads from disk. ++ ++ Note there must be at least one cached fragment. Anything ++ much more than three will probably not make much difference. ++ ++config SQUASHFS_VMALLOC ++ bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED ++ depends on SQUASHFS ++ default n ++ help ++ By default SquashFS uses kmalloc to obtain fragment cache memory. ++ Kmalloc memory is the standard kernel allocator, but it can fail ++ on memory constrained systems. Because of the way Vmalloc works, ++ Vmalloc can succeed when kmalloc fails. Specifying this option ++ will make SquashFS always use Vmalloc to allocate the ++ fragment cache memory. ++ ++ If unsure, say N. ++ + config VXFS_FS + tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" + depends on BLOCK +@@ -2057,3 +2122,4 @@ source "fs/dlm/Kconfig" + + endmenu + ++source "fs/aufs/Kconfig" +diff --git a/fs/Makefile b/fs/Makefile +index 9edf411..557766f 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -68,6 +68,7 @@ obj-$(CONFIG_JBD) += jbd/ + obj-$(CONFIG_JBD2) += jbd2/ + obj-$(CONFIG_EXT2_FS) += ext2/ + obj-$(CONFIG_CRAMFS) += cramfs/ ++obj-$(CONFIG_SQUASHFS) += squashfs/ + obj-$(CONFIG_RAMFS) += ramfs/ + obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ + obj-$(CONFIG_CODA_FS) += coda/ +@@ -114,3 +115,4 @@ obj-$(CONFIG_HPPFS) += hppfs/ + obj-$(CONFIG_DEBUG_FS) += debugfs/ + obj-$(CONFIG_OCFS2_FS) += ocfs2/ + obj-$(CONFIG_GFS2_FS) += gfs2/ ++obj-$(CONFIG_AUFS) += aufs/ +diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig +new file mode 100644 +index 0000000..3a2121c +--- /dev/null ++++ b/fs/aufs/Kconfig +@@ -0,0 +1,73 @@ ++config AUFS ++ tristate "Another unionfs" ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. After many original ++ ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ See Unionfs for the basic features. ++ ++if AUFS ++comment "These options are generated automatically for "#UTS_RELEASE ++ ++config AUFS_FAKE_DM ++ bool "Use simplified (fake) nameidata" ++ depends on AUFS ++ default y ++ help ++ Faking nameidata (VFS internal data), you can get better performance ++ in some cases. ++ ++choice ++ prompt "Maximum number of branches" ++ depends on AUFS ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++ ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++endchoice ++config AUFS_DEBUG ++ bool "Debug aufs" ++ depends on AUFS ++ default y ++ help ++ Enable this to compile aufs internal debug code. ++ The performance will be damaged. ++ ++config AUFS_COMPAT ++ bool "Compatibility with Unionfs (obsolete)" ++ depends on AUFS ++ default n ++ help ++ This makes aufs compatible with unionfs-style mount options and some ++ behaviours. ++ The dirs= mount option and =nfsro branch permission flag are always ++ interpreted as br: mount option and =ro flag respectively. The ++ 'debug', 'delete' and 'imap' mount options are ignored. ++ If you disable this option, you will get, ++ - aufs issues a warning about the ignored mount options ++ - the default branch permission flag is set. RW for the first branch, ++ and RO for the rests. ++ - the name of a internal file which represents the directory is ++ 'opaque', becomes '.wh..wh..opq' ++ - the 'diropq=w' mount option is set by default ++endif +diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile +new file mode 100755 +index 0000000..0ee3cd0 +--- /dev/null ++++ b/fs/aufs/Makefile +@@ -0,0 +1,18 @@ ++# AUFS Makefile for the Linux 2.6.16 and later ++# $Id: Makefile,v 1.29 2007/04/23 00:59:50 sfjro Exp $ ++ ++obj-$(CONFIG_AUFS) += aufs.o ++aufs-y := module.o super.o sbinfo.o xino.o \ ++ branch.o cpup.o whout.o plink.o wkq.o dcsub.o vfsub.o \ ++ opts.o \ ++ dentry.o dinfo.o \ ++ file.o f_op.o finfo.o \ ++ dir.o vdir.o \ ++ inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o iinfo.o \ ++ misc.o ++#xattr.o ++aufs-$(CONFIG_AUFS_SYSAUFS) += sysaufs.o ++aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++#aufs-$(CONFIG_DEBUGFS) += dbgfs.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o +diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h +new file mode 100755 +index 0000000..79b3b87 +--- /dev/null ++++ b/fs/aufs/aufs.h +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: aufs.h,v 1.24 2007/05/14 03:41:51 sfjro Exp $ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* limited support before 2.6.16, curretly 2.6.15 only. */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++#define atomic_long_t atomic_t ++#define atomic_long_set atomic_set ++#define timespec_to_ns(ts) ({(long long)(ts)->tv_sec;}) ++#define D_CHILD d_child ++#else ++#define D_CHILD d_u.d_child ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "inode.h" ++#include "misc.h" ++#include "module.h" ++#include "opts.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++//#include "xattr.h" ++ ++#if defined(CONFIG_AUFS_MODULE) && !defined(CONFIG_AUFS_KSIZE_PATCH) ++#define ksize(p) (-1U) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c +new file mode 100755 +index 0000000..f1ce008 +--- /dev/null ++++ b/fs/aufs/branch.c +@@ -0,0 +1,818 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: branch.c,v 1.49 2007/05/14 03:38:23 sfjro Exp $ */ ++ ++//#include ++//#include ++#include "aufs.h" ++ ++static void free_branch(struct aufs_branch *br) ++{ ++ TraceEnter(); ++ ++ if (br->br_xino) ++ fput(br->br_xino); ++ dput(br->br_wh); ++ dput(br->br_plink); ++ mntput(br->br_mnt); ++ DEBUG_ON(br_count(br) || atomic_read(&br->br_wh_running)); ++ kfree(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void free_branches(struct aufs_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct aufs_branch **br; ++ ++ TraceEnter(); ++ bmax = sbinfo->si_bend + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ free_branch(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int find_brindex(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ TraceEnter(); ++ ++ bend = sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ++ * test if the @br is readonly or not. ++ */ ++int br_rdonly(struct aufs_branch *br) ++{ ++ return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY) ++ || !br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++/* ++ * returns writable branch index, otherwise an error. ++ * todo: customizable writable-branch-policy ++ */ ++static int find_rw_parent(struct dentry *dentry, aufs_bindex_t bend) ++{ ++ int err; ++ aufs_bindex_t bindex, candidate; ++ struct super_block *sb; ++ struct dentry *parent, *hidden_parent; ++ ++ err = bend; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++#if 1 // branch policy ++ hidden_parent = au_h_dptr_i(parent, bend); ++ if (hidden_parent && !br_rdonly(stobr(sb, bend))) ++ goto out; /* success */ ++#endif ++ ++ candidate = -1; ++ for (bindex = dbstart(parent); bindex <= bend; bindex++) { ++ hidden_parent = au_h_dptr_i(parent, bindex); ++ if (hidden_parent && !br_rdonly(stobr(sb, bindex))) { ++#if 0 // branch policy ++ if (candidate == -1) ++ candidate = bindex; ++ if (!au_test_perm(hidden_parent->d_inode, MAY_WRITE)) ++ return bindex; ++#endif ++ err = bindex; ++ goto out; /* success */ ++ } ++ } ++#if 0 // branch policy ++ err = candidate; ++ if (candidate != -1) ++ goto out; /* success */ ++#endif ++ err = -EROFS; ++ ++ out: ++ dput(parent); ++ return err; ++} ++ ++int find_rw_br(struct super_block *sb, aufs_bindex_t bend) ++{ ++ aufs_bindex_t bindex; ++ ++ for (bindex = bend; bindex >= 0; bindex--) ++ if (!br_rdonly(stobr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++int find_rw_parent_br(struct dentry *dentry, aufs_bindex_t bend) ++{ ++ int err; ++ ++ err = find_rw_parent(dentry, bend); ++ if (err >= 0) ++ return err; ++ return find_rw_br(dentry->d_sb, bend); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if two hidden_dentries have overlapping branches. ++ */ ++//todo: try is_subdir() ++static int do_is_overlap(struct super_block *sb, struct dentry *hidden_d1, ++ struct dentry *hidden_d2) ++{ ++ struct dentry *d; ++ ++ d = hidden_d1; ++ do { ++ if (unlikely(d == hidden_d2)) ++ return 1; ++ d = d->d_parent; // dget_parent() ++ } while (!IS_ROOT(d)); ++ ++ return (d == hidden_d2); ++} ++ ++#if defined(CONFIG_BLK_DEV_LOOP) || defined(CONFIG_BLK_DEV_LOOP_MODULE) ++#include ++static int is_overlap_loopback(struct super_block *sb, struct dentry *hidden_d1, ++ struct dentry *hidden_d2) ++{ ++ struct inode *hidden_inode; ++ struct loop_device *l; ++ ++ hidden_inode = hidden_d1->d_inode; ++ if (MAJOR(hidden_inode->i_sb->s_dev) != LOOP_MAJOR) ++ return 0; ++ ++ l = hidden_inode->i_sb->s_bdev->bd_disk->private_data; ++ hidden_d1 = l->lo_backing_file->f_dentry; ++ if (unlikely(hidden_d1->d_sb == sb)) ++ return 1; ++ return do_is_overlap(sb, hidden_d1, hidden_d2); ++} ++#else ++#define is_overlap_loopback(sb, hidden_d1, hidden_d2) 0 ++#endif ++ ++static int is_overlap(struct super_block *sb, struct dentry *hidden_d1, ++ struct dentry *hidden_d2) ++{ ++ LKTRTrace("d1 %.*s, d2 %.*s\n", DLNPair(hidden_d1), DLNPair(hidden_d2)); ++ if (unlikely(hidden_d1 == hidden_d2)) ++ return 1; ++ return do_is_overlap(sb, hidden_d1, hidden_d2) ++ || do_is_overlap(sb, hidden_d2, hidden_d1) ++ || is_overlap_loopback(sb, hidden_d1, hidden_d2) ++ || is_overlap_loopback(sb, hidden_d2, hidden_d1); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int init_br_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_branch *br, int new_perm, ++ struct dentry *h_root, struct vfsmount *h_mnt) ++{ ++ int err, old_perm; ++ struct inode *dir = sb->s_root->d_inode, ++ *h_dir = h_root->d_inode; ++ const int new = (bindex < 0); ++ ++ LKTRTrace("b%d, new_perm %d\n", bindex, new_perm); ++ ++ if (new) ++ hi_lock_parent(h_dir); ++ else ++ hdir_lock(h_dir, dir, bindex); ++ ++ br_wh_write_lock(br); ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ err = init_wh(h_root, br, au_do_nfsmnt(h_mnt), sb); ++ br->br_perm = old_perm; ++ br_wh_write_unlock(br); ++ ++ if (new) ++ i_unlock(h_dir); ++ else ++ hdir_unlock(h_dir, dir, bindex); ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct aufs_branch *alloc_addbr(struct super_block *sb, int new_nbranch) ++{ ++ struct aufs_branch **branchp, *add_branch; ++ int sz; ++ void *p; ++ struct dentry *root; ++ struct inode *inode; ++ struct aufs_hinode *hinodep; ++ struct aufs_hdentry *hdentryp; ++ ++ LKTRTrace("new_nbranch %d\n", new_nbranch); ++ SiMustWriteLock(sb); ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ inode = root->d_inode; ++ IiMustWriteLock(inode); ++ ++ add_branch = kmalloc(sizeof(*add_branch), GFP_KERNEL); ++ //if (LktrCond) {kfree(add_branch); add_branch = NULL;} ++ if (unlikely(!add_branch)) ++ goto out; ++ ++ sz = sizeof(*branchp) * (new_nbranch - 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*branchp); ++ p = stosi(sb)->si_branch; ++ branchp = au_kzrealloc(p, sz, sizeof(*branchp) * new_nbranch, ++ GFP_KERNEL); ++ //if (LktrCond) branchp = NULL; ++ if (unlikely(!branchp)) ++ goto out; ++ stosi(sb)->si_branch = branchp; ++ ++ sz = sizeof(*hdentryp) * (new_nbranch - 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*hdentryp); ++ p = dtodi(root)->di_hdentry; ++ hdentryp = au_kzrealloc(p, sz, sizeof(*hdentryp) * new_nbranch, ++ GFP_KERNEL); ++ //if (LktrCond) hdentryp = NULL; ++ if (unlikely(!hdentryp)) ++ goto out; ++ dtodi(root)->di_hdentry = hdentryp; ++ ++ sz = sizeof(*hinodep) * (new_nbranch - 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*hinodep); ++ p = itoii(inode)->ii_hinode; ++ hinodep = au_kzrealloc(p, sz, sizeof(*hinodep) * new_nbranch, ++ GFP_KERNEL); ++ //if (LktrCond) hinodep = NULL; // unavailable test ++ if (unlikely(!hinodep)) ++ goto out; ++ itoii(inode)->ii_hinode = hinodep; ++ return add_branch; /* success */ ++ ++ out: ++ kfree(add_branch); ++ TraceErr(-ENOMEM); ++ return ERR_PTR(-ENOMEM); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct super_block *sb, struct inode *inode, int brperm, ++ char *path) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(br_writable(brperm) && IS_RDONLY(inode))) { ++ Err("write permission for readonly fs or inode, %s\n", path); ++ err = -EINVAL; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * retunrs,,, ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct opt_add *add, int remount) ++{ ++ int err; ++ struct dentry *root; ++ struct inode *inode, *hidden_inode; ++ aufs_bindex_t bend, bindex; ++ ++ LKTRTrace("%s, remo%d\n", add->path, remount); ++ ++ root = sb->s_root; ++ if (unlikely(au_find_dbindex(root, add->nd.dentry) != -1)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ Err("%s duplicated\n", add->path); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; //-E2BIG; ++ bend = sbend(sb); ++ //if (LktrCond) bend = AUFS_BRANCH_MAX; ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bend)) { ++ Err("number of branches exceeded %s\n", add->path); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { ++ Err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = add->nd.dentry->d_inode; ++ DEBUG_ON(!inode || !S_ISDIR(inode->i_mode)); ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ Err("no existence %s\n", add->path); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ Err("%s must be outside\n", add->path); ++ goto out; ++ } ++ ++#if 1 //ndef CONFIG_AUFS_ROBR ++ if (unlikely(au_is_aufs(inode->i_sb) ++ || !strcmp(au_sbtype(inode->i_sb), "unionfs"))) { ++ Err("nested " AUFS_NAME " %s\n", add->path); ++ goto out; ++ } ++#endif ++ ++#ifdef AuNoNfsBranch ++ if (unlikely(au_is_nfs(inode->i_sb))) { ++ Err(AuNoNfsBranchMsg ". %s\n", add->path); ++ goto out; ++ } ++#endif ++ ++ err = test_br(sb, add->nd.dentry->d_inode, add->perm, add->path); ++ if (unlikely(err)) ++ goto out; ++ ++ if (unlikely(bend == -1)) ++ return 0; /* success */ ++ ++ hidden_inode = au_h_dptr(root)->d_inode; ++ if (unlikely(au_flag_test(sb, AuFlag_WARN_PERM) ++ && ((hidden_inode->i_mode & S_IALLUGO) ++ != (inode->i_mode & S_IALLUGO) ++ || hidden_inode->i_uid != inode->i_uid ++ || hidden_inode->i_gid != inode->i_gid))) ++ Warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->path, ++ inode->i_uid, inode->i_gid, (inode->i_mode & S_IALLUGO), ++ hidden_inode->i_uid, hidden_inode->i_gid, ++ (hidden_inode->i_mode & S_IALLUGO)); ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (unlikely(is_overlap(sb, add->nd.dentry, ++ au_h_dptr_i(root, bindex)))) { ++ Err("%s is overlapped\n", add->path); ++ goto out; ++ } ++ err = 0; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++int br_add(struct super_block *sb, struct opt_add *add, int remount) ++{ ++ int err, sz; ++ aufs_bindex_t bend, add_bindex; ++ struct dentry *root; ++ struct aufs_iinfo *iinfo; ++ struct aufs_sbinfo *sbinfo; ++ struct aufs_dinfo *dinfo; ++ struct inode *root_inode; ++ unsigned long long maxb; ++ struct aufs_branch **branchp, *add_branch; ++ struct aufs_hdentry *hdentryp; ++ struct aufs_hinode *hinodep; ++ ++ LKTRTrace("b%d, %s, 0x%x, %.*s\n", add->bindex, add->path, ++ add->perm, DLNPair(add->nd.dentry)); ++ SiMustWriteLock(sb); ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ root_inode = root->d_inode; ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (unlikely(err)) ++ return 0; /* success */ ++ ++ bend = sbend(sb); ++ add_branch = alloc_addbr(sb, bend + 2); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = 0; ++ rw_init_nolock(&add_branch->br_wh_rwsem); ++ add_branch->br_wh = add_branch->br_plink = NULL; ++ if (unlikely(br_writable(add->perm))) { ++ err = init_br_wh(sb, /*bindex*/-1, add_branch, add->perm, ++ add->nd.dentry, add->nd.mnt); ++ if (unlikely(err)) { ++ kfree(add_branch); ++ goto out; ++ } ++ } ++ add_branch->br_xino = NULL; ++ add_branch->br_mnt = mntget(add->nd.mnt); ++ atomic_set(&add_branch->br_wh_running, 0); ++ add_branch->br_id = new_br_id(sb); ++ add_branch->br_perm = add->perm; ++ atomic_set(&add_branch->br_count, 0); ++ ++ sbinfo = stosi(sb); ++ dinfo = dtodi(root); ++ iinfo = itoii(root_inode); ++ ++ add_bindex = add->bindex; ++ sz = sizeof(*(sbinfo->si_branch)) * (bend + 1 - add_bindex); ++ branchp = sbinfo->si_branch + add_bindex; ++ memmove(branchp + 1, branchp, sz); ++ *branchp = add_branch; ++ sz = sizeof(*hdentryp) * (bend + 1 - add_bindex); ++ hdentryp = dinfo->di_hdentry + add_bindex; ++ memmove(hdentryp + 1, hdentryp, sz); ++ hdentryp->hd_dentry = NULL; ++ sz = sizeof(*hinodep) * (bend + 1 - add_bindex); ++ hinodep = iinfo->ii_hinode + add_bindex; ++ memmove(hinodep + 1, hinodep, sz); ++ hinodep->hi_inode = NULL; ++ hinodep->hi_notify = NULL; ++ ++ sbinfo->si_bend++; ++ dinfo->di_bend++; ++ iinfo->ii_bend++; ++ if (unlikely(bend == -1)) { ++ dinfo->di_bstart = 0; ++ iinfo->ii_bstart = 0; ++ } ++ set_h_dptr(root, add_bindex, dget(add->nd.dentry)); ++ set_h_iptr(root_inode, add_bindex, igrab(add->nd.dentry->d_inode), 0); ++ if (!add_bindex) ++ au_cpup_attr_all(root_inode); ++ else ++ au_add_nlink(root_inode, add->nd.dentry->d_inode); ++ maxb = add->nd.dentry->d_sb->s_maxbytes; ++ if (sb->s_maxbytes < maxb) ++ sb->s_maxbytes = maxb; ++ ++ if (au_flag_test(sb, AuFlag_XINO)) { ++ struct file *base_file = stobr(sb, 0)->br_xino; ++ if (!add_bindex) ++ base_file = stobr(sb, 1)->br_xino; ++ err = xino_init(sb, add_bindex, base_file, /*do_test*/1); ++ if (unlikely(err)) { ++ DEBUG_ON(add_branch->br_xino); ++ Err("ignored xino err %d, force noxino\n", err); ++ err = 0; ++ au_flag_clr(sb, AuFlag_XINO); ++ } ++ } ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) ++{ ++ int err, i, j, sigen; ++ struct au_dcsub_pages dpages; ++ ++ LKTRTrace("b%d\n", bindex); ++ SiMustWriteLock(root->d_sb); ++ DiMustWriteLock(root); ++ ++ err = au_dpages_init(&dpages, GFP_KERNEL); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ struct au_dpage *dpage; ++ dpage = dpages.dpages + i; ++ for (j = 0; !err && j < dpage->ndentry; j++) { ++ struct dentry *d; ++ ++ d = dpage->dentries[j]; ++ if (au_digen(d) == sigen) ++ di_read_lock_child(d, AUFS_I_RLOCK); ++ else { ++ di_write_lock_child(d); ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AUFS_I_RLOCK); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ if (au_h_dptr_i(d, bindex) ++ && (!S_ISDIR(d->d_inode->i_mode) ++ || dbstart(d) == dbend(d))) ++ err = -EBUSY; ++ di_read_unlock(d, AUFS_I_RLOCK); ++ if (err) ++ LKTRTrace("%.*s\n", DLNPair(d)); ++ } ++ } ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++int br_del(struct super_block *sb, struct opt_del *del, int remount) ++{ ++ int err, do_wh, rerr; ++ struct dentry *root; ++ struct inode *inode, *hidden_dir; ++ aufs_bindex_t bindex, bend, br_id; ++ struct aufs_sbinfo *sbinfo; ++ struct aufs_dinfo *dinfo; ++ struct aufs_iinfo *iinfo; ++ struct aufs_branch *br; ++ ++ LKTRTrace("%s, %.*s\n", del->path, DLNPair(del->h_root)); ++ SiMustWriteLock(sb); ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ inode = root->d_inode; ++ IiMustWriteLock(inode); ++ ++ bindex = au_find_dbindex(root, del->h_root); ++ if (unlikely(bindex < 0)) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ Err("%s no such branch\n", del->path); ++ goto out; ++ } ++ LKTRTrace("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ bend = sbend(sb); ++ br = stobr(sb, bindex); ++ if (unlikely(!bend || br_count(br))) { ++ LKTRTrace("bend %d, br_count %d\n", bend, br_count(br)); ++ goto out; ++ } ++ ++ do_wh = 0; ++ hidden_dir = del->h_root->d_inode; ++ if (unlikely(br->br_wh || br->br_plink)) { ++#if 0 ++ /* remove whiteout base */ ++ err = init_br_wh(sb, bindex, br, AuBr_RO, del->h_root, ++ br->br_mnt); ++ if (unlikely(err)) ++ goto out; ++#else ++ dput(br->br_wh); ++ dput(br->br_plink); ++ br->br_wh = br->br_plink = NULL; ++#endif ++ do_wh = 1; ++ } ++ ++ err = test_children_busy(root, bindex); ++ if (unlikely(err)) { ++ if (unlikely(do_wh)) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ sbinfo = stosi(sb); ++ dinfo = dtodi(root); ++ iinfo = itoii(inode); ++ ++ dput(au_h_dptr_i(root, bindex)); ++ aufs_hiput(iinfo->ii_hinode + bindex); ++ br_id = br->br_id; ++ free_branch(br); ++ ++ //todo: realloc and shrink memeory ++ if (bindex < bend) { ++ const aufs_bindex_t n = bend - bindex; ++ struct aufs_branch **brp; ++ struct aufs_hdentry *hdp; ++ struct aufs_hinode *hip; ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp, brp + 1, sizeof(*brp) * n); ++ hdp = dinfo->di_hdentry + bindex; ++ memmove(hdp, hdp + 1, sizeof(*hdp) * n); ++ hip = iinfo->ii_hinode + bindex; ++ memmove(hip, hip + 1, sizeof(*hip) * n); ++ } ++ sbinfo->si_branch[0 + bend] = NULL; ++ dinfo->di_hdentry[0 + bend].hd_dentry = NULL; ++ iinfo->ii_hinode[0 + bend].hi_inode = NULL; ++ iinfo->ii_hinode[0 + bend].hi_notify = NULL; ++ ++ sbinfo->si_bend--; ++ dinfo->di_bend--; ++ iinfo->ii_bend--; ++ if (!bindex) ++ au_cpup_attr_all(inode); ++ else ++ au_sub_nlink(inode, del->h_root->d_inode); ++ if (au_flag_test(sb, AuFlag_PLINK)) ++ half_refresh_plink(sb, br_id); ++ ++ if (sb->s_maxbytes == del->h_root->d_sb->s_maxbytes) { ++ bend--; ++ sb->s_maxbytes = 0; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ unsigned long long maxb; ++ maxb = sbr_sb(sb, bindex)->s_maxbytes; ++ if (sb->s_maxbytes < maxb) ++ sb->s_maxbytes = maxb; ++ } ++ } ++ goto out; /* success */ ++ ++ out_wh: ++ /* revert */ ++ rerr = init_br_wh(sb, bindex, br, br->br_perm, del->h_root, br->br_mnt); ++ if (rerr) ++ Warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->path, rerr); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return (br_whable(a) && !br_whable(b)); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return (do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old)); ++} ++ ++int br_mod(struct super_block *sb, struct opt_mod *mod, int remount, ++ int *do_update) ++{ ++ int err; ++ struct dentry *root; ++ aufs_bindex_t bindex; ++ struct aufs_branch *br; ++ struct inode *hidden_dir; ++ ++ LKTRTrace("%s, %.*s, 0x%x\n", ++ mod->path, DLNPair(mod->h_root), mod->perm); ++ SiMustWriteLock(sb); ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ IiMustWriteLock(root->d_inode); ++ ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (unlikely(bindex < 0)) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ Err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ LKTRTrace("bindex b%d\n", bindex); ++ ++ hidden_dir = mod->h_root->d_inode; ++ err = test_br(sb, hidden_dir, mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = stobr(sb, bindex); ++ if (unlikely(br->br_perm == mod->perm)) ++ return 0; /* success */ ++ ++ if (br_writable(br->br_perm)) { ++#if 1 ++ /* remove whiteout base */ ++ //todo: mod->perm? ++ err = init_br_wh(sb, bindex, br, AuBr_RO, mod->h_root, ++ br->br_mnt); ++ if (unlikely(err)) ++ goto out; ++#else ++ dput(br->br_wh); ++ dput(br->br_plink); ++ br->br_wh = br->br_plink = NULL; ++#endif ++ ++ if (!br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ struct file *file, *hf; ++ ++#if 1 // test here ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ ++ // no need file_list_lock() since sbinfo is locked ++ //file_list_lock(); ++ list_for_each_entry(file, &sb->s_files, f_u.fu_list) { ++ LKTRTrace("%.*s\n", DLNPair(file->f_dentry)); ++ fi_read_lock(file); ++ if (!S_ISREG(file->f_dentry->d_inode->i_mode) ++ || !(file->f_mode & FMODE_WRITE) ++ || fbstart(file) != bindex) { ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ continue; ++ } ++ ++ // todo: already flushed? ++ hf = au_h_fptr(file); ++ hf->f_flags = au_file_roflags(hf->f_flags); ++ hf->f_mode &= ~FMODE_WRITE; ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ } ++ //file_list_unlock(); ++ ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++#endif ++ } ++ } ++ ++ *do_update |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ return err; /* success */ ++ ++ out: ++ TraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h +new file mode 100755 +index 0000000..2557836 +--- /dev/null ++++ b/fs/aufs/branch.h +@@ -0,0 +1,235 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: branch.h,v 1.30 2007/05/14 03:41:51 sfjro Exp $ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "misc.h" ++#include "super.h" ++ ++/* protected by superblock rwsem */ ++struct aufs_branch { ++ struct file *br_xino; ++ readf_t br_xino_read; ++ writef_t br_xino_write; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct vfsmount *br_mnt; ++ atomic_t br_count; ++ ++ /* whiteout base */ ++ struct aufs_rwsem br_wh_rwsem; ++ struct dentry *br_wh; ++ atomic_t br_wh_running; ++ ++ /* pseudo-link dir */ ++ struct dentry *br_plink; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch permission and attribute */ ++enum { ++ AuBr_RW, /* writable, linkable wh */ ++ AuBr_RO, /* readonly, no wh */ ++ AuBr_RR, /* natively readonly, no wh */ ++ ++ AuBr_RWNoLinkWH, /* un-linkable whiteouts */ ++ ++ AuBr_ROWH, ++ AuBr_RRWH, /* whiteout-able */ ++ ++ AuBr_Last ++}; ++ ++static inline int br_writable(int brperm) ++{ ++ return (brperm == AuBr_RW ++ || brperm == AuBr_RWNoLinkWH); ++} ++ ++static inline int br_whable(int brperm) ++{ ++ return (brperm == AuBr_RW ++ || brperm == AuBr_ROWH ++ || brperm == AuBr_RRWH); ++} ++ ++static inline int br_linkable_wh(int brperm) ++{ ++ return (brperm == AuBr_RW); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define _AuNoNfsBranchMsg "NFS branch is not supported" ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,15) ++#define AuNoNfsBranch ++#define AuNoNfsBranchMsg _AuNoNfsBranchMsg ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) \ ++ && !defined(CONFIG_AUFS_LHASH_PATCH) ++#define AuNoNfsBranch ++#define AuNoNfsBranchMsg _AuNoNfsBranchMsg \ ++ ", try lhash.patch and CONFIG_AUFS_LHASH_PATCH" ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_sbinfo; ++void free_branches(struct aufs_sbinfo *sinfo); ++int br_rdonly(struct aufs_branch *br); ++int find_brindex(struct super_block *sb, aufs_bindex_t br_id); ++int find_rw_br(struct super_block *sb, aufs_bindex_t bend); ++int find_rw_parent_br(struct dentry *dentry, aufs_bindex_t bend); ++struct opt_add; ++int br_add(struct super_block *sb, struct opt_add *add, int remount); ++struct opt_del; ++int br_del(struct super_block *sb, struct opt_del *del, int remount); ++struct opt_mod; ++int br_mod(struct super_block *sb, struct opt_mod *mod, int remount, ++ int *do_update); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int br_count(struct aufs_branch *br) ++{ ++ return atomic_read(&br->br_count); ++} ++ ++static inline void br_get(struct aufs_branch *br) ++{ ++ atomic_inc(&br->br_count); ++} ++ ++static inline void br_put(struct aufs_branch *br) ++{ ++ atomic_dec(&br->br_count); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Superblock to branch */ ++static inline aufs_bindex_t sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return stobr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return stobr(sb, bindex)->br_mnt; ++} ++ ++static inline ++struct super_block *sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return sbr_mnt(sb, bindex)->mnt_sb; ++} ++ ++#if 0 ++static inline int sbr_count(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return br_count(stobr(sb, bindex)); ++} ++ ++static inline void sbr_get(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ br_get(stobr(sb, bindex)); ++} ++#endif ++ ++static inline void sbr_put(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ br_put(stobr(sb, bindex)); ++} ++ ++static inline int sbr_perm(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return stobr(sb, bindex)->br_perm; ++} ++ ++static inline int sbr_is_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return br_whable(sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_LHASH_PATCH ++static inline struct vfsmount *au_do_nfsmnt(struct vfsmount *h_mnt) ++{ ++ if (!au_is_nfs(h_mnt->mnt_sb)) ++ return NULL; ++ return h_mnt; ++} ++ ++/* it doesn't mntget() */ ++static inline ++struct vfsmount *au_nfsmnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_do_nfsmnt(sbr_mnt(sb, bindex)); ++} ++#else ++static inline struct vfsmount *au_do_nfsmnt(struct vfsmount *h_mnt) ++{ ++ return NULL; ++} ++ ++static inline ++struct vfsmount *au_nfsmnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return NULL; ++} ++#endif /* CONFIG_AUFS_LHASH_PATCH */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * br_wh_read_lock, br_wh_write_lock ++ * br_wh_read_unlock, br_wh_write_unlock, br_wh_downgrade_lock ++ */ ++SimpleRwsemFuncs(br_wh, struct aufs_branch *br, br->br_wh_rwsem); ++ ++/* to debug easier, do not make them inlined functions */ ++#define BrWhMustReadLock(br) do { \ ++ /* SiMustAnyLock(sb); */ \ ++ RwMustReadLock(&(br)->br_wh_rwsem); \ ++} while (0) ++ ++#define BrWhMustWriteLock(br) do { \ ++ /* SiMustAnyLock(sb); */ \ ++ RwMustWriteLock(&(br)->br_wh_rwsem); \ ++} while (0) ++ ++#define BrWhMustAnyLock(br) do { \ ++ /* SiMustAnyLock(sb); */ \ ++ RwMustAnyLock(&(br)->br_wh_rwsem); \ ++} while (0) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c +new file mode 100755 +index 0000000..6636f40 +--- /dev/null ++++ b/fs/aufs/cpup.c +@@ -0,0 +1,773 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: cpup.c,v 1.37 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#include ++#include "aufs.h" ++ ++/* violent cpup_attr_*() functions don't care inode lock */ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *hidden_inode; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ //IMustLock(inode); ++ hidden_inode = au_h_iptr(inode); ++ DEBUG_ON(!hidden_inode); ++ //IMustLock(!hidden_inode); ++ ++ inode->i_atime = hidden_inode->i_atime; ++ inode->i_mtime = hidden_inode->i_mtime; ++ inode->i_ctime = hidden_inode->i_ctime; ++ spin_lock(&inode->i_lock); ++ i_size_write(inode, i_size_read(hidden_inode)); ++ inode->i_blocks = hidden_inode->i_blocks; ++ spin_unlock(&inode->i_lock); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ //IMustLock(inode); ++ DEBUG_ON(!inode->i_mode); ++ ++ h_inode = au_h_iptr(inode); ++ inode->i_nlink = h_inode->i_nlink; ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (unlikely(S_ISDIR(h_inode->i_mode))) { ++ aufs_bindex_t bindex, bend; ++ bend = ibend(inode); ++ for (bindex = ibstart(inode) + 1; bindex <= bend; bindex++) { ++ h_inode = au_h_iptr_i(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changable(struct inode *inode) ++{ ++ struct inode *hidden_inode; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ //IMustLock(inode); ++ hidden_inode = au_h_iptr(inode); ++ DEBUG_ON(!hidden_inode); ++ ++ inode->i_mode = hidden_inode->i_mode; ++ inode->i_uid = hidden_inode->i_uid; ++ inode->i_gid = hidden_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ ++ //?? ++ inode->i_flags = hidden_inode->i_flags; ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ inode->i_generation = h_inode->i_generation; ++ itoii(inode)->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode) ++{ ++ struct inode *hidden_inode; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ //IMustLock(inode); ++ hidden_inode = au_h_iptr(inode); ++ DEBUG_ON(!hidden_inode); ++ ++ au_cpup_attr_changable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode); ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFBLK: ++ case S_IFCHR: ++ inode->i_rdev = hidden_inode->i_rdev; ++ } ++ inode->i_blkbits = hidden_inode->i_blkbits; ++ au_cpup_attr_blksize(inode, hidden_inode); ++ au_cpup_igen(inode, hidden_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_hidden_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void dtime_store(struct dtime *dt, struct dentry *dentry, ++ struct dentry *hidden_dentry) ++{ ++ struct inode *inode; ++ ++ TraceEnter(); ++ DEBUG_ON(!dentry || !hidden_dentry || !hidden_dentry->d_inode); ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_dentry = hidden_dentry; ++ inode = hidden_dentry->d_inode; ++ dt->dt_atime = inode->i_atime; ++ dt->dt_mtime = inode->i_mtime; ++ //smp_mb(); ++} ++ ++// todo: remove extra parameter ++void dtime_revert(struct dtime *dt, int h_parent_is_locked) ++{ ++ struct iattr attr; ++ int err; ++ struct dentry *dentry; ++ ++ LKTRTrace("h_parent locked %d\n", h_parent_is_locked); ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ //smp_mb(); ++ dentry = NULL; ++ if (!h_parent_is_locked /* && !IS_ROOT(dt->dt_dentry) */) ++ dentry = dt->dt_dentry; ++ err = vfsub_notify_change(dt->dt_h_dentry, &attr, ++ need_dlgt(dt->dt_dentry->d_sb)); ++ if (unlikely(err)) ++ Warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int cpup_iattr(struct dentry *hidden_dst, struct dentry *hidden_src, ++ int dlgt) ++{ ++ int err; ++ struct iattr ia; ++ struct inode *hidden_isrc, *hidden_idst; ++ ++ LKTRTrace("%.*s\n", DLNPair(hidden_dst)); ++ hidden_idst = hidden_dst->d_inode; ++ //IMustLock(hidden_idst); ++ hidden_isrc = hidden_src->d_inode; ++ //IMustLock(hidden_isrc); ++ ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ ia.ia_mode = hidden_isrc->i_mode; ++ ia.ia_uid = hidden_isrc->i_uid; ++ ia.ia_gid = hidden_isrc->i_gid; ++ ia.ia_atime = hidden_isrc->i_atime; ++ ia.ia_mtime = hidden_isrc->i_mtime; ++ err = vfsub_notify_change(hidden_dst, &ia, dlgt); ++ //if (LktrCond) err = -1; ++ if (!err) ++ hidden_idst->i_flags = hidden_isrc->i_flags; //?? ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int cpup_regular(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len) ++{ ++ int err, i, sparse; ++ struct super_block *sb; ++ struct inode *hidden_inode; ++ enum {SRC, DST}; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ struct file *file; ++ void *label, *label_file; ++ } *h, hidden[] = { ++ { ++ .bindex = bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ .file = NULL, ++ .label = &&out, ++ .label_file = &&out_src_file ++ }, ++ { ++ .bindex = bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .file = NULL, ++ .label = &&out_src_file, ++ .label_file = &&out_dst_file ++ } ++ }; ++ ++ LKTRTrace("dentry %.*s, bdst %d, bsrc %d, len %lld\n", ++ DLNPair(dentry), bdst, bsrc, len); ++ DEBUG_ON(bsrc <= bdst); ++ DEBUG_ON(!len); ++ sb = dentry->d_sb; ++ DEBUG_ON(test_ro(sb, bdst, dentry->d_inode)); ++ // bsrc branch can be ro/rw. ++ ++ h = hidden; ++ for (i = 0; i < 2; i++, h++) { ++ h->dentry = au_h_dptr_i(dentry, h->bindex); ++ DEBUG_ON(!h->dentry); ++ hidden_inode = h->dentry->d_inode; ++ DEBUG_ON(!hidden_inode || !S_ISREG(hidden_inode->i_mode)); ++ h->file = hidden_open(dentry, h->bindex, h->flags); ++ //if (LktrCond) ++ //{fput(h->file); sbr_put(sb, h->bindex); h->file = ERR_PTR(-1);} ++ err = PTR_ERR(h->file); ++ if (IS_ERR(h->file)) ++ goto *h->label; ++ err = -EINVAL; ++ if (unlikely(!h->file->f_op)) ++ goto *h->label_file; ++ } ++ ++ /* stop updating while we copyup */ ++ IMustLock(hidden[SRC].dentry->d_inode); ++ sparse = 0; ++ err = au_copy_file(hidden[DST].file, hidden[SRC].file, len, sb, ++ &sparse); ++ ++ /* sparse file: update i_blocks next time */ ++ if (unlikely(!err && sparse)) ++ d_drop(dentry); ++ ++ out_dst_file: ++ fput(hidden[DST].file); ++ sbr_put(sb, hidden[DST].bindex); ++ out_src_file: ++ fput(hidden[SRC].file); ++ sbr_put(sb, hidden[SRC].bindex); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++// unnecessary? ++unsigned int au_flags_cpup(unsigned int init, struct dentry *parent) ++{ ++ if (unlikely(parent && IS_ROOT(parent))) ++ init |= CPUP_LOCKED_GHDIR; ++ return init; ++} ++ ++/* return with hidden dst inode is locked */ ++static int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags, ++ int dlgt) ++{ ++ int err, isdir, symlen; ++ struct dentry *hidden_src, *hidden_dst, *hidden_parent, *parent; ++ struct inode *hidden_inode, *hidden_dir, *dir; ++ struct dtime dt; ++ umode_t mode; ++ char *sym; ++ mm_segment_t old_fs; ++ const int do_dt = flags & CPUP_DTIME; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, ++ flags); ++ sb = dentry->d_sb; ++ DEBUG_ON(bdst >= bsrc || test_ro(sb, bdst, NULL)); ++ // bsrc branch can be ro/rw. ++ ++ hidden_src = au_h_dptr_i(dentry, bsrc); ++ DEBUG_ON(!hidden_src); ++ hidden_inode = hidden_src->d_inode; ++ DEBUG_ON(!hidden_inode); ++ ++ /* stop refrencing while we are creating */ ++ //parent = dget_parent(dentry); ++ parent = dentry->d_parent; ++ dir = parent->d_inode; ++ hidden_dst = au_h_dptr_i(dentry, bdst); ++ DEBUG_ON(hidden_dst && hidden_dst->d_inode); ++ //hidden_parent = dget_parent(hidden_dst); ++ hidden_parent = hidden_dst->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ if (do_dt) ++ dtime_store(&dt, parent, hidden_parent); ++ ++ isdir = 0; ++ mode = hidden_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* stop updating while we are referencing */ ++ IMustLock(hidden_inode); ++ err = vfsub_create(hidden_dir, hidden_dst, mode | S_IWUSR, NULL, ++ dlgt); ++ //if (LktrCond) {vfs_unlink(hidden_dir, hidden_dst); err = -1;} ++ if (!err) { ++ loff_t l = i_size_read(hidden_inode); ++ if (len == -1 || l < len) ++ len = l; ++ if (len) { ++ err = cpup_regular(dentry, bdst, bsrc, len); ++ //if (LktrCond) err = -1; ++ } ++ if (unlikely(err)) { ++ int rerr; ++ rerr = vfsub_unlink(hidden_dir, hidden_dst, ++ dlgt); ++ if (rerr) { ++ IOErr("failed unlinking cpup-ed %.*s" ++ "(%d, %d)\n", ++ DLNPair(hidden_dst), err, rerr); ++ err = -EIO; ++ } ++ } ++ } ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(hidden_dir, hidden_dst, mode, dlgt); ++ //if (LktrCond) {vfs_rmdir(hidden_dir, hidden_dst); err = -1;} ++ if (!err) { ++ /* setattr case: dir is not locked */ ++ if (0 && ibstart(dir) == bdst) ++ au_cpup_attr_nlink(dir); ++ au_cpup_attr_nlink(dentry->d_inode); ++ } ++ break; ++ case S_IFLNK: ++ err = -ENOMEM; ++ sym = __getname(); ++ //if (LktrCond) {__putname(sym); sym = NULL;} ++ if (unlikely(!sym)) ++ break; ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = symlen = hidden_inode->i_op->readlink ++ (hidden_src, (char __user*)sym, PATH_MAX); ++ //if (LktrCond) err = symlen = -1; ++ set_fs(old_fs); ++ if (symlen > 0) { ++ sym[symlen] = 0; ++ err = vfsub_symlink(hidden_dir, hidden_dst, sym, mode, ++ dlgt); ++ //if (LktrCond) ++ //{vfs_unlink(hidden_dir, hidden_dst); err = -1;} ++ } ++ __putname(sym); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ DEBUG_ON(!capable(CAP_MKNOD)); ++ /*FALLTHROUGH*/ ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(hidden_dir, hidden_dst, mode, ++ hidden_inode->i_rdev, dlgt); ++ //if (LktrCond) {vfs_unlink(hidden_dir, hidden_dst); err = -1;} ++ break; ++ default: ++ IOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ ++ if (do_dt) ++ dtime_revert(&dt, flags & CPUP_LOCKED_GHDIR); ++ //dput(parent); ++ //dput(hidden_parent); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of hidden dentries. ++ * @len is for trucating when it is -1 copyup the entire file. ++ */ ++int cpup_single(struct dentry *dentry, aufs_bindex_t bdst, aufs_bindex_t bsrc, ++ loff_t len, unsigned int flags) ++{ ++ int err, rerr, isdir, dlgt; ++ struct dentry *hidden_src, *hidden_dst, *parent;//, *h_parent; ++ struct inode *dst_inode, *hidden_dir, *inode, *src_inode; ++ struct super_block *sb; ++ aufs_bindex_t old_ibstart; ++ struct dtime dt; ++ ++ LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, ++ flags); ++ sb = dentry->d_sb; ++ DEBUG_ON(bsrc <= bdst); ++ hidden_dst = au_h_dptr_i(dentry, bdst); ++ DEBUG_ON(!hidden_dst || hidden_dst->d_inode); ++ //h_parent = dget_parent(hidden_dst); ++ //hidden_dir = h_parent->d_inode; ++ hidden_dir = hidden_dst->d_parent->d_inode; ++ IMustLock(hidden_dir); ++ hidden_src = au_h_dptr_i(dentry, bsrc); ++ DEBUG_ON(!hidden_src || !hidden_src->d_inode); ++ inode = dentry->d_inode; ++ IiMustWriteLock(inode); ++ ++ dlgt = need_dlgt(sb); ++ dst_inode = au_h_iptr_i(inode, bdst); ++ if (unlikely(dst_inode)) { ++ if (unlikely(!au_flag_test(sb, AuFlag_PLINK))) { ++ err = -EIO; ++ IOErr("i%lu exists on a upper branch " ++ "but plink is disabled\n", inode->i_ino); ++ goto out; ++ } ++ ++ if (dst_inode->i_nlink) { ++ hidden_src = lkup_plink(sb, bdst, inode); ++ err = PTR_ERR(hidden_src); ++ if (IS_ERR(hidden_src)) ++ goto out; ++ DEBUG_ON(!hidden_src->d_inode); ++ // vfs_link() does lock the inode ++ err = vfsub_link(hidden_src, hidden_dir, hidden_dst, dlgt); ++ dput(hidden_src); ++ goto out; ++ } else ++ /* udba work */ ++ au_update_brange(inode, 1); ++ } ++ ++ old_ibstart = ibstart(inode); ++ err = cpup_entry(dentry, bdst, bsrc, len, flags, dlgt); ++ if (unlikely(err)) ++ goto out; ++ dst_inode = hidden_dst->d_inode; ++ hi_lock_child2(dst_inode); ++ ++ //todo: test dlgt ++ err = cpup_iattr(hidden_dst, hidden_src, dlgt); ++ //if (LktrCond) err = -1; ++#if 0 // xattr ++ if (0 && !err) ++ err = cpup_xattrs(hidden_src, hidden_dst); ++#endif ++ isdir = S_ISDIR(dst_inode->i_mode); ++ if (!err) { ++ if (bdst < old_ibstart) ++ set_ibstart(inode, bdst); ++ set_h_iptr(inode, bdst, igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ i_unlock(dst_inode); ++ src_inode = hidden_src->d_inode; ++ if (!isdir) { ++ if (src_inode->i_nlink > 1 ++ && au_flag_test(sb, AuFlag_PLINK)) ++ append_plink(sb, inode, hidden_dst, bdst); ++ else { ++ /* braces are added to stop a warning */ ++ ;//xino_write0(sb, bsrc, src_inode->i_ino); ++ /* ignore this error */ ++ } ++ } ++ //goto out; /* success */ ++ return 0; /* success */ ++ } ++ ++ /* revert */ ++ i_unlock(dst_inode); ++ parent = dget_parent(dentry); ++ //dtime_store(&dt, parent, h_parent); ++ dtime_store(&dt, parent, hidden_dst->d_parent); ++ dput(parent); ++ if (!isdir) ++ rerr = vfsub_unlink(hidden_dir, hidden_dst, dlgt); ++ else ++ rerr = vfsub_rmdir(hidden_dir, hidden_dst, dlgt); ++ //rerr = -1; ++ dtime_revert(&dt, flags & CPUP_LOCKED_GHDIR); ++ if (rerr) { ++ IOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++ ++ out: ++ //dput(h_parent); ++ TraceErr(err); ++ return err; ++} ++ ++struct cpup_single_args { ++ int *errp; ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ unsigned int flags; ++}; ++ ++static void call_cpup_single(void *args) ++{ ++ struct cpup_single_args *a = args; ++ *a->errp = cpup_single(a->dentry, a->bdst, a->bsrc, a->len, a->flags); ++} ++ ++int sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags) ++{ ++ int err; ++ struct dentry *hidden_dentry; ++ umode_t mode; ++ ++ LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, ++ flags); ++ ++ hidden_dentry = au_h_dptr_i(dentry, bsrc); ++ mode = hidden_dentry->d_inode->i_mode & S_IFMT; ++ if ((mode != S_IFCHR && mode != S_IFBLK) ++ || capable(CAP_MKNOD)) ++ err = cpup_single(dentry, bdst, bsrc, len, flags); ++ else { ++ struct cpup_single_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = bsrc, ++ .len = len, ++ .flags = flags ++ }; ++ au_wkq_wait(call_cpup_single, &args, /*dlgt*/0); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * copyup the @dentry from the first active hidden branch to @bdst, ++ * using cpup_single(). ++ */ ++int cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags) ++{ ++ int err; ++ struct inode *inode; ++ aufs_bindex_t bsrc, bend; ++ ++ LKTRTrace("%.*s, bdst %d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), bdst, len, flags); ++ inode = dentry->d_inode; ++ DEBUG_ON(!S_ISDIR(inode->i_mode) && dbstart(dentry) < bdst); ++ ++ bend = dbend(dentry); ++ for (bsrc = bdst + 1; bsrc <= bend; bsrc++) ++ if (au_h_dptr_i(dentry, bsrc)) ++ break; ++ DEBUG_ON(!au_h_dptr_i(dentry, bsrc)); ++ ++ err = lkup_neg(dentry, bdst); ++ //err = -1; ++ if (!err) { ++ err = cpup_single(dentry, bdst, bsrc, len, flags); ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ set_h_dptr(dentry, bdst, NULL); ++ set_dbstart(dentry, bsrc); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++struct cpup_simple_args { ++ int *errp; ++ struct dentry *dentry; ++ aufs_bindex_t bdst; ++ loff_t len; ++ unsigned int flags; ++}; ++ ++static void call_cpup_simple(void *args) ++{ ++ struct cpup_simple_args *a = args; ++ *a->errp = cpup_simple(a->dentry, a->bdst, a->len, a->flags); ++} ++ ++int sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags) ++{ ++ int err, do_sio, dlgt; ++ //struct dentry *parent; ++ struct inode *hidden_dir, *dir; ++ ++ LKTRTrace("%.*s, b%d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), bdst, len, flags); ++ ++ //parent = dget_parent(dentry); ++ //dir = parent->d_inode; ++ dir = dentry->d_parent->d_inode; ++ hidden_dir = au_h_iptr_i(dir, bdst); ++ dlgt = need_dlgt(dir->i_sb); ++ do_sio = au_test_perm(hidden_dir, MAY_EXEC | MAY_WRITE, dlgt); ++ if (!do_sio) { ++ umode_t mode = dentry->d_inode->i_mode & S_IFMT; ++ do_sio = ((mode == S_IFCHR || mode == S_IFBLK) ++ && !capable(CAP_MKNOD)); ++ } ++ if (!do_sio) ++ err = cpup_simple(dentry, bdst, len, flags); ++ else { ++ struct cpup_simple_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bdst, ++ .len = len, ++ .flags = flags ++ }; ++ au_wkq_wait(call_cpup_simple, &args, /*dlgt*/0); ++ } ++ ++ //dput(parent); ++ TraceErr(err); ++ return err; ++} ++ ++//todo: dcsub ++/* cf. revalidate function in file.c */ ++int cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst, struct dentry *locked) ++{ ++ int err; ++ struct super_block *sb; ++ struct dentry *d, *parent, *hidden_parent; ++ unsigned int udba; ++ ++ LKTRTrace("%.*s, b%d, parent i%lu, locked %p\n", ++ DLNPair(dentry), bdst, parent_ino(dentry), locked); ++ sb = dentry->d_sb; ++ DEBUG_ON(test_ro(sb, bdst, NULL)); ++ parent = dentry->d_parent; ++ IiMustWriteLock(parent->d_inode); ++ if (unlikely(IS_ROOT(parent))) ++ return 0; ++ if (locked) { ++ DiMustAnyLock(locked); ++ IiMustAnyLock(locked->d_inode); ++ } ++ ++ /* slow loop, keep it simple and stupid */ ++ err = 0; ++ udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY); ++ while (1) { ++ parent = dentry->d_parent; // dget_parent() ++ hidden_parent = au_h_dptr_i(parent, bdst); ++ if (hidden_parent) ++ return 0; /* success */ ++ ++ /* find top dir which is needed to cpup */ ++ do { ++ d = parent; ++ parent = d->d_parent; // dget_parent() ++ if (parent != locked) ++ di_read_lock_parent3(parent, !AUFS_I_RLOCK); ++ hidden_parent = au_h_dptr_i(parent, bdst); ++ if (parent != locked) ++ di_read_unlock(parent, !AUFS_I_RLOCK); ++ } while (!hidden_parent); ++ ++ if (d != dentry->d_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ if (!au_h_dptr_i(d, bdst) || !au_h_dptr_i(d, bdst)->d_inode) { ++ struct inode *h_dir = hidden_parent->d_inode, ++ *dir = parent->d_inode, ++ *h_gdir, *gdir; ++ ++ if (au_h_dptr_i(d, bdst)) ++ au_update_dbstart(d); ++ //DEBUG_ON(dbstart(d) <= bdst); ++ if (parent != locked) ++ di_read_lock_parent3(parent, AUFS_I_RLOCK); ++ h_gdir = gdir = NULL; ++ if (unlikely(udba && !IS_ROOT(parent))) { ++ gdir = parent->d_parent->d_inode; ++ h_gdir = hidden_parent->d_parent->d_inode; ++ hgdir_lock(h_gdir, gdir, bdst); ++ } ++ hdir_lock(h_dir, dir, bdst); ++ err = sio_cpup_simple(d, bdst, -1, ++ au_flags_cpup(CPUP_DTIME, ++ parent)); ++ //if (LktrCond) err = -1; ++ hdir_unlock(h_dir, dir, bdst); ++ if (unlikely(gdir)) ++ hdir_unlock(h_gdir, gdir, bdst); ++ if (parent != locked) ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ } ++ ++ if (d != dentry->d_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++// out: ++ TraceErr(err); ++ return err; ++} ++ ++int test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *locked) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dentry->d_parent; ++ dir = parent->d_inode; ++ LKTRTrace("%.*s, b%d, parent i%lu, locked %p\n", ++ DLNPair(dentry), bdst, dir->i_ino, locked); ++ DiMustReadLock(parent); ++ IiMustReadLock(dir); ++ ++ if (au_h_iptr_i(dir, bdst)) ++ return 0; ++ ++ err = 0; ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ di_write_lock_parent(parent); ++ if (au_h_iptr_i(dir, bdst)) ++ goto out; ++ ++ err = cpup_dirs(dentry, bdst, locked); ++ ++ out: ++ di_downgrade_lock(parent, AUFS_I_RLOCK); ++ TraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h +new file mode 100755 +index 0000000..86557aa +--- /dev/null ++++ b/fs/aufs/cpup.h +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: cpup.h,v 1.15 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++static inline ++void au_cpup_attr_blksize(struct inode *inode, struct inode *h_inode) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ++ inode->i_blksize = h_inode->i_blksize; ++#endif ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode); ++void au_cpup_attr_changable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode); ++ ++#define CPUP_DTIME 1 // do dtime_store/revert ++// todo: remove this ++#define CPUP_LOCKED_GHDIR 2 // grand parent hidden dir is locked ++unsigned int au_flags_cpup(unsigned int init, struct dentry *parent); ++ ++int cpup_single(struct dentry *dentry, aufs_bindex_t bdst, aufs_bindex_t bsrc, ++ loff_t len, unsigned int flags); ++int sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags); ++int cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags); ++int sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags); ++ ++int cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst, struct dentry *locked); ++int test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *locked); ++ ++/* keep timestamps when copyup */ ++struct dtime { ++ struct dentry *dt_dentry, *dt_h_dentry; ++ struct timespec dt_atime, dt_mtime; ++}; ++void dtime_store(struct dtime *dt, struct dentry *dentry, ++ struct dentry *h_dentry); ++void dtime_revert(struct dtime *dt, int h_parent_is_locked); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c +new file mode 100755 +index 0000000..6ec29d3 +--- /dev/null ++++ b/fs/aufs/dcsub.c +@@ -0,0 +1,175 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dcsub.c,v 1.3 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ ++ TraceEnter(); ++ DEBUG_ON(!dpage); ++ ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(dpage->dentries[i]); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ TraceEnter(); ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ p = (void*)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++ out_dpages: ++ kfree(dpages->dpages); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(dpages->dpages + i); ++ kfree(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ //TraceEnter(); ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ DEBUG_ON(!dpage); ++ sz = PAGE_SIZE/sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ LKTRLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp); ++ if (unlikely(!p)) ++ goto out; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void*)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ dpage->dentries[dpage->ndentry++] = dget(dentry); ++ return 0; /* success */ ++ ++ out: ++ //TraceErr(err); ++ return err; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ int err; ++ struct dentry *this_parent = root; ++ struct list_head *next; ++ struct super_block *sb = root->d_sb; ++ ++ TraceEnter(); ++ ++ err = 0; ++ spin_lock(&dcache_lock); ++ repeat: ++ next = this_parent->d_subdirs.next; ++ resume: ++ if (this_parent->d_sb == sb ++ && !IS_ROOT(this_parent) ++ && atomic_read(&this_parent->d_count) ++ && this_parent->d_inode ++ && (!test || test(this_parent, arg))) { ++ err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ while (next != &this_parent->d_subdirs) { ++ struct list_head *tmp = next; ++ struct dentry *dentry = list_entry(tmp, struct dentry, D_CHILD); ++ next = tmp->next; ++ if (unlikely(/*d_unhashed(dentry) || */!dentry->d_inode)) ++ continue; ++ if (!list_empty(&dentry->d_subdirs)) { ++ this_parent = dentry; ++ goto repeat; ++ } ++ if (dentry->d_sb == sb ++ && atomic_read(&dentry->d_count) ++ && (!test || test(dentry, arg))) { ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ if (unlikely(err)) ++ goto out; ++ } ++ } ++ ++ if (this_parent != root) { ++ next = this_parent->D_CHILD.next; ++ this_parent = this_parent->d_parent; ++ goto resume; ++ } ++ out: ++ spin_unlock(&dcache_lock); ++#if 0 ++ if (!err) { ++ int i, j; ++ j = 0; ++ for (i = 0; i < dpages->ndpage; i++) { ++ if ((dpages->dpages + i)->ndentry) ++ Dbg("%d: %d\n", i, (dpages->dpages + i)->ndentry); ++ j += (dpages->dpages + i)->ndentry; ++ } ++ if (j) ++ Dbg("ndpage %d, %d\n", dpages->ndpage, j); ++ } ++#endif ++ TraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h +new file mode 100755 +index 0000000..0ba034b +--- /dev/null ++++ b/fs/aufs/dcsub.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dcsub.h,v 1.2 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c +new file mode 100755 +index 0000000..99d158b +--- /dev/null ++++ b/fs/aufs/debug.c +@@ -0,0 +1,262 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: debug.c,v 1.27 2007/04/30 05:48:23 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++atomic_t aufs_cond = ATOMIC_INIT(0); ++ ++#if defined(CONFIG_LKTR) || defined(CONFIG_LKTR_MODULE) ++#define dpri(fmt, arg...) \ ++ do {if (LktrCond) printk(KERN_DEBUG fmt, ##arg);} while (0) ++#else ++#define dpri(fmt, arg...) printk(KERN_DEBUG fmt, ##arg) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct aufs_nhash *whlist) ++{ ++ int i; ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos; ++ ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ head = whlist->heads + i; ++ hlist_for_each_entry(tpos, pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ tpos->wh_bindex, ++ tpos->wh_str.len, tpos->wh_str.name, ++ tpos->wh_str.len); ++ } ++} ++ ++void au_dpri_vdir(struct aufs_vdir *vdir) ++{ ++ int i; ++ union aufs_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("nblk %d, deblk %p %d, last{%d, %p}, ver %lu\n", ++ vdir->vd_nblk, vdir->vd_deblk, ksize(vdir->vd_deblk), ++ vdir->vd_last.i, vdir->vd_last.p.p, vdir->vd_version); ++ for (i = 0; i < vdir->vd_nblk; i++) { ++ p.deblk = vdir->vd_deblk[i]; ++ o = p.p; ++ dpri("[%d]: %p %d\n", i, o, ksize(o)); ++#if 0 // verbose ++ int j; ++ for (j = 0; j < 8; j++) { ++ dpri("%p(+%d) {%02x %02x %02x %02x %02x %02x %02x %02x " ++ "%02x %02x %02x %02x %02x %02x %02x %02x}\n", ++ p.p, p.p - o, ++ p.p[0], p.p[1], p.p[2], p.p[3], ++ p.p[4], p.p[5], p.p[6], p.p[7], ++ p.p[8], p.p[9], p.p[10], p.p[11], ++ p.p[12], p.p[13], p.p[14], p.p[15]); ++ p.p += 16; ++ } ++#endif ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode) ++{ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LSF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, sz %Lu, blk %Lu," ++ " ct %Ld, np %lu, st 0x%lx, g %x\n", ++ bindex, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (u64)inode->i_blocks, ++ timespec_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_generation); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct aufs_iinfo *iinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_inode(-1, inode); ++ if (err || !au_is_aufs(inode->i_sb)) ++ return; ++ ++ iinfo = itoii(inode); ++ if (!iinfo) ++ return; ++ dpri("i-1: bstart %d, bend %d, gen %d\n", ++ iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode)); ++ if (iinfo->ii_bstart < 0) ++ return; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) ++ do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ dpri("d%d: %.*s/%.*s, %s, cnt %d, flags 0x%x\n", ++ bindex, ++ DLNPair(dentry->d_parent), DLNPair(dentry), ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ atomic_read(&dentry->d_count), dentry->d_flags); ++ do_pri_inode(bindex, dentry->d_inode); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct aufs_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_is_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = dtodi(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n", ++ dinfo->di_bstart, dinfo->di_bend, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry)); ++ if (dinfo->di_bstart < 0) ++ return; ++ for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) ++ do_pri_dentry(bindex, dinfo->di_hdentry[0 + bindex].hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex == -1 && ftofi(file)) ++ snprintf(a, sizeof(a), ", mmapped %d", au_is_mmapped(file)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %d, pos %Lu%s\n", ++ bindex, file->f_mode, file->f_flags, file_count(file), ++ file->f_pos, a); ++ do_pri_dentry(bindex, file->f_dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct aufs_finfo *finfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err || !file->f_dentry || !au_is_aufs(file->f_dentry->d_sb)) ++ return; ++ ++ finfo = ftofi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_bstart < 0) ++ return; ++ for (bindex = finfo->fi_bstart; bindex <= finfo->fi_bend; bindex++) { ++ struct aufs_hfile *hf; ++ //dpri("bindex %d\n", bindex); ++ hf = finfo->fi_hfile + bindex; ++ do_pri_file(bindex, hf ? hf->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct aufs_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br) ++ || !(mnt = br->br_mnt) || IS_ERR(mnt) ++ || !(sb = mnt->mnt_sb) || IS_ERR(sb)) { ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++ } ++ ++ dpri("s%d: {perm 0x%x, cnt %d}, " ++ "%s, flags 0x%lx, cnt(BIAS) %d, active %d, xino %p %p\n", ++ bindex, br->br_perm, br_count(br), ++ au_sbtype(sb), sb->s_flags, sb->s_count - S_BIAS, ++ atomic_read(&sb->s_active), br->br_xino, ++ br->br_xino ? br->br_xino->f_dentry : NULL); ++ return 0; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ struct vfsmount mnt = {.mnt_sb = sb}; ++ struct aufs_branch fake = { ++ .br_perm = 0, ++ .br_mnt = &mnt, ++ .br_count = ATOMIC_INIT(0), ++ .br_xino = NULL ++ }; ++ ++ atomic_set(&fake.br_count, 0); ++ err = do_pri_br(-1, &fake); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_is_aufs(sb)) ++ return; ++ ++ sbinfo = stosi(sb); ++ if (!sbinfo) ++ return; ++ for (bindex = 0; bindex <= sbinfo->si_bend; bindex++) { ++ //dpri("bindex %d\n", bindex); ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void DbgSleep(int sec) ++{ ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ Dbg("sleep %d sec\n", sec); ++ wait_event_timeout(wq, 0, sec * HZ); ++} +diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h +new file mode 100755 +index 0000000..53f5f6a +--- /dev/null ++++ b/fs/aufs/debug.h +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: debug.h,v 1.31 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DEBUG_ON(a) BUG_ON(a) ++extern atomic_t aufs_cond; ++#define au_debug_on() atomic_inc(&aufs_cond) ++#define au_debug_off() atomic_dec(&aufs_cond) ++#define au_is_debug() atomic_read(&aufs_cond) ++#else ++#define DEBUG_ON(a) /* */ ++#define au_debug_on() /* */ ++#define au_debug_off() /* */ ++#define au_is_debug() 0 ++#endif ++ ++#define MtxMustLock(mtx) DEBUG_ON(!mutex_is_locked(mtx)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++#if defined(CONFIG_LKTR) || defined(CONFIG_LKTR_MODULE) ++#include ++#ifdef CONFIG_AUFS_DEBUG ++#undef LktrCond ++#define LktrCond unlikely((lktr_cond && lktr_cond()) || au_is_debug()) ++#endif ++#else ++#define LktrCond au_is_debug() ++#define LKTRDumpVma(pre, vma, suf) /* */ ++#define LKTRDumpStack() /* */ ++#define LKTRTrace(fmt, args...) do { \ ++ if (LktrCond) \ ++ Dbg(fmt, ##args); \ ++} while (0) ++#define LKTRLabel(label) LKTRTrace("%s\n", #label) ++#endif /* CONFIG_LKTR */ ++ ++#define TraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ LKTRTrace("err %d\n", (int)(e)); \ ++} while (0) ++#define TraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ LKTRTrace("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++#define TraceEnter() LKTRLabel(enter) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define LNPair(qstr) (qstr)->len,(qstr)->name ++#define DLNPair(d) LNPair(&(d)->d_name) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define Dpri(lvl, fmt, arg...) \ ++ printk(lvl AUFS_NAME " %s:%d:%s[%d]: " fmt, \ ++ __func__, __LINE__, current->comm, current->pid, ##arg) ++#define Dbg(fmt, arg...) Dpri(KERN_DEBUG, fmt, ##arg) ++#define Warn(fmt, arg...) Dpri(KERN_WARNING, fmt, ##arg) ++#define Warn1(fmt, arg...) do { \ ++ static unsigned char c; \ ++ if (!c++) Warn(fmt, ##arg); \ ++ } while (0) ++#define Err(fmt, arg...) Dpri(KERN_ERR, fmt, ##arg) ++#define Err1(fmt, arg...) do { \ ++ static unsigned char c; \ ++ if (!c++) Err(fmt, ##arg); \ ++ } while (0) ++#define IOErr(fmt, arg...) Err("I/O Error, " fmt, ##arg) ++#define IOErr1(fmt, arg...) do { \ ++ static unsigned char c; \ ++ if (!c++) IOErr(fmt, ##arg); \ ++ } while (0) ++#define IOErrWhck(fmt, arg...) Err("I/O Error, try whck. " fmt, ##arg) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++struct aufs_nhash; ++void au_dpri_whlist(struct aufs_nhash *whlist); ++struct aufs_vdir; ++void au_dpri_vdir(struct aufs_vdir *vdir); ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++void au_dpri_file(struct file *filp); ++void au_dpri_sb(struct super_block *sb); ++#define DbgWhlist(w) do{LKTRTrace(#w "\n"); au_dpri_whlist(w);}while(0) ++#define DbgVdir(v) do{LKTRTrace(#v "\n"); au_dpri_vdir(v);}while(0) ++#define DbgInode(i) do{LKTRTrace(#i "\n"); au_dpri_inode(i);}while(0) ++#define DbgDentry(d) do{LKTRTrace(#d "\n"); au_dpri_dentry(d);}while(0) ++#define DbgFile(f) do{LKTRTrace(#f "\n"); au_dpri_file(f);}while(0) ++#define DbgSb(sb) do{LKTRTrace(#sb "\n"); au_dpri_sb(sb);}while(0) ++void DbgSleep(int sec); ++#else ++#define DbgWhlist(w) /* */ ++#define DbgVdir(v) /* */ ++#define DbgInode(i) /* */ ++#define DbgDentry(d) /* */ ++#define DbgFile(f) /* */ ++#define DbgSb(sb) /* */ ++#define DbgSleep(sec) /* */ ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c +new file mode 100755 +index 0000000..2acb89b +--- /dev/null ++++ b/fs/aufs/dentry.c +@@ -0,0 +1,946 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dentry.c,v 1.41 2007/05/14 03:38:38 sfjro Exp $ */ ++ ++//#include ++//#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_LHASH_PATCH ++ ++#ifdef CONFIG_AUFS_DLGT ++struct lookup_hash_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct dentry *base; ++ struct nameidata *nd; ++}; ++ ++static void call_lookup_hash(void *args) ++{ ++ struct lookup_hash_args *a = args; ++ *a->errp = __lookup_hash(a->name, a->base, a->nd); ++} ++#endif /* CONFIG_AUFS_DLGT */ ++ ++static struct dentry *lkup_hash(const char *name, struct dentry *parent, ++ int len, struct lkup_args *lkup) ++{ ++ struct dentry *dentry; ++ char *p; ++ unsigned long hash; ++ struct qstr this; ++ unsigned int c; ++ struct nameidata tmp_nd; ++ ++ dentry = ERR_PTR(-EACCES); ++ this.name = name; ++ this.len = len; ++ if (unlikely(!len)) ++ goto out; ++ ++ p = (void*)name; ++ hash = init_name_hash(); ++ while (len--) { ++ c = *p++; ++ if (unlikely(c == '/' || c == '\0')) ++ goto out; ++ hash = partial_name_hash(c, hash); ++ } ++ this.hash = end_name_hash(hash); ++ ++ memset(&tmp_nd, 0, sizeof(tmp_nd)); ++ tmp_nd.dentry = dget(parent); ++ tmp_nd.mnt = mntget(lkup->nfsmnt); ++#ifndef CONFIG_AUFS_DLGT ++ dentry = __lookup_hash(&this, parent, &tmp_nd); ++#else ++ if (!lkup->dlgt) ++ dentry = __lookup_hash(&this, parent, &tmp_nd); ++ else { ++ struct lookup_hash_args args = { ++ .errp = &dentry, ++ .name = &this, ++ .base = parent, ++ .nd = &tmp_nd ++ }; ++ au_wkq_wait(call_lookup_hash, &args, /*dlgt*/1); ++ } ++#endif ++ path_release(&tmp_nd); ++ ++ out: ++ TraceErrPtr(dentry); ++ return dentry; ++} ++#elif defined(CONFIG_AUFS_DLGT) ++static struct dentry *lkup_hash(const char *name, struct dentry *parent, ++ int len, struct lkup_args *lkup) ++{ ++ return ERR_PTR(-ENOSYS); ++} ++#endif ++ ++#ifdef CONFIG_AUFS_DLGT ++struct lookup_one_len_args { ++ struct dentry **errp; ++ const char *name; ++ struct dentry *parent; ++ int len; ++}; ++ ++static void call_lookup_one_len(void *args) ++{ ++ struct lookup_one_len_args *a = args; ++ *a->errp = lookup_one_len(a->name, a->parent, a->len); ++} ++#endif /* CONFIG_AUFS_DLGT */ ++ ++#if defined(CONFIG_AUFS_LHASH_PATCH) || defined(CONFIG_AUFS_DLGT) ++/* cf. lookup_one_len() in linux/fs/namei.c */ ++struct dentry *lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup) ++{ ++ struct dentry *dentry; ++ ++ LKTRTrace("%.*s/%.*s, lkup{%p, %d}\n", ++ DLNPair(parent), len, name, lkup->nfsmnt, lkup->dlgt); ++ ++ if (!lkup->nfsmnt) { ++#ifndef CONFIG_AUFS_DLGT ++ dentry = lookup_one_len(name, parent, len); ++#else ++ if (!lkup->dlgt) ++ dentry = lookup_one_len(name, parent, len); ++ else { ++ struct lookup_one_len_args args = { ++ .errp = &dentry, ++ .name = name, ++ .parent = parent, ++ .len = len ++ }; ++ au_wkq_wait(call_lookup_one_len, &args, /*dlgt*/1); ++ } ++#endif ++ } else ++ dentry = lkup_hash(name, parent, len, lkup); ++ ++ TraceErrPtr(dentry); ++ return dentry; ++} ++#endif ++ ++struct lkup_one_args { ++ struct dentry **errp; ++ const char *name; ++ struct dentry *parent; ++ int len; ++ struct lkup_args *lkup; ++}; ++ ++static void call_lkup_one(void *args) ++{ ++ struct lkup_one_args *a = args; ++ *a->errp = lkup_one(a->name, a->parent, a->len, a->lkup); ++} ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry *do_lookup(struct dentry *hidden_parent, ++ struct dentry *dentry, aufs_bindex_t bindex, ++ struct qstr *wh_name, int allow_neg, ++ mode_t type, int dlgt) ++{ ++ struct dentry *hidden_dentry; ++ int wh_found, wh_able, opq; ++ struct inode *hidden_dir, *hidden_inode; ++ struct qstr *name; ++ struct super_block *sb; ++ struct lkup_args lkup = {.dlgt = dlgt}; ++ ++ LKTRTrace("%.*s/%.*s, b%d, allow_neg %d, type 0%o, dlgt %d\n", ++ DLNPair(hidden_parent), DLNPair(dentry), bindex, allow_neg, ++ type, dlgt); ++ DEBUG_ON(IS_ROOT(dentry)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ wh_found = 0; ++ sb = dentry->d_sb; ++ wh_able = sbr_is_whable(sb, bindex); ++ lkup.nfsmnt = au_nfsmnt(sb, bindex); ++ name = &dentry->d_name; ++ if (unlikely(wh_able)) { ++#if 0 //def CONFIG_AUFS_ROBR ++ if (strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ wh_found = is_wh(hidden_parent, wh_name, /*try_sio*/0, ++ &lkup); ++ else ++ wh_found = -EPERM; ++#else ++ wh_found = is_wh(hidden_parent, wh_name, /*try_sio*/0, &lkup); ++#endif ++ } ++ //if (LktrCond) wh_found = -1; ++ hidden_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ //set_dbend(dentry, bindex); ++ set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++ real_lookup: ++ // do not superio. ++ hidden_dentry = lkup_one(name->name, hidden_parent, name->len, &lkup); ++ //if (LktrCond) {dput(hidden_dentry); hidden_dentry = ERR_PTR(-1);} ++ if (IS_ERR(hidden_dentry)) ++ goto out; ++ DEBUG_ON(d_unhashed(hidden_dentry)); ++ hidden_inode = hidden_dentry->d_inode; ++ if (!hidden_inode) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (type && type != (hidden_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ ++ if (dbend(dentry) <= bindex) ++ set_dbend(dentry, bindex); ++ if (dbstart(dentry) == -1 || bindex < dbstart(dentry)) ++ set_dbstart(dentry, bindex); ++ set_h_dptr(dentry, bindex, hidden_dentry); ++ ++ if (!hidden_inode || !S_ISDIR(hidden_inode->i_mode) || !wh_able) ++ return hidden_dentry; /* success */ ++ ++ hi_lock_child(hidden_inode); ++ opq = is_diropq(hidden_dentry, &lkup); ++ //if (LktrCond) opq = -1; ++ i_unlock(hidden_inode); ++ if (opq > 0) ++ set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ set_h_dptr(dentry, bindex, NULL); ++ hidden_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++ out_neg: ++ dput(hidden_dentry); ++ hidden_dentry = NULL; ++ out: ++ TraceErrPtr(hidden_dentry); ++ return hidden_dentry; ++} ++ ++/* ++ * returns the number of hidden positive dentries, ++ * otherwise an error. ++ */ ++int lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type) ++{ ++ int npositive, err, allow_neg, dlgt; ++ struct dentry *parent; ++ aufs_bindex_t bindex, btail; ++ const struct qstr *name = &dentry->d_name; ++ struct qstr whname; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, b%d, type 0%o\n", LNPair(name), bstart, type); ++ DEBUG_ON(bstart < 0 || IS_ROOT(dentry)); ++ parent = dget_parent(dentry); ++ ++#if 1 //ndef CONFIG_AUFS_ROBR ++ err = -EPERM; ++ if (unlikely(!strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ goto out; ++#endif ++ ++ err = au_alloc_whname(name->name, name->len, &whname); ++ //if (LktrCond) {au_free_whname(&whname); err = -1;} ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ dlgt = need_dlgt(sb); ++ allow_neg = !type; ++ npositive = 0; ++ btail = dbtaildir(parent); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ struct dentry *hidden_parent, *hidden_dentry; ++ struct inode *hidden_inode; ++ struct inode *hidden_dir; ++ ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (hidden_dentry) { ++ if (hidden_dentry->d_inode) ++ npositive++; ++ if (type != S_IFDIR) ++ break; ++ continue; ++ } ++ hidden_parent = au_h_dptr_i(parent, bindex); ++ if (!hidden_parent) ++ continue; ++ hidden_dir = hidden_parent->d_inode; ++ if (!hidden_dir || !S_ISDIR(hidden_dir->i_mode)) ++ continue; ++ ++ hi_lock_parent(hidden_dir); ++ hidden_dentry = do_lookup(hidden_parent, dentry, bindex, ++ &whname, allow_neg, type, dlgt); ++ // do not dput for testing ++ //if (LktrCond) {hidden_dentry = ERR_PTR(-1);} ++ i_unlock(hidden_dir); ++ err = PTR_ERR(hidden_dentry); ++ if (IS_ERR(hidden_dentry)) ++ goto out_wh; ++ allow_neg = 0; ++ ++ if (dbwh(dentry) != -1) ++ break; ++ if (!hidden_dentry) ++ continue; ++ hidden_inode = hidden_dentry->d_inode; ++ if (!hidden_inode) ++ continue; ++ npositive++; ++ if (!type) ++ type = hidden_inode->i_mode & S_IFMT; ++ if (type != S_IFDIR) ++ break; ++ else if (dbdiropq(dentry) != -1) ++ break; ++ } ++ ++ if (npositive) { ++ LKTRLabel(positive); ++ au_update_dbstart(dentry); ++ } ++ err = npositive; ++ ++ out_wh: ++ au_free_whname(&whname); ++ out: ++ dput(parent); ++ TraceErr(err); ++ return err; ++} ++ ++struct dentry *sio_lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup) ++{ ++ struct dentry *dentry; ++ ++ LKTRTrace("%.*s/%.*s\n", DLNPair(parent), len, name); ++ IMustLock(parent->d_inode); ++ ++ if (!au_test_perm(parent->d_inode, MAY_EXEC, lkup->dlgt)) ++ dentry = lkup_one(name, parent, len, lkup); ++ else { ++ // ugly ++ int dlgt = lkup->dlgt; ++ struct lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .parent = parent, ++ .len = len, ++ .lkup = lkup ++ }; ++ ++ lkup->dlgt = 0; ++ au_wkq_wait(call_lkup_one, &args, /*dlgt*/0); ++ lkup->dlgt = dlgt; ++ } ++ ++ TraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int lkup_neg(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err; ++ struct dentry *parent, *hidden_parent, *hidden_dentry; ++ struct inode *hidden_dir; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, b%d\n", DLNPair(dentry), bindex); ++ parent = dget_parent(dentry); ++ DEBUG_ON(!parent || !parent->d_inode ++ || !S_ISDIR(parent->d_inode->i_mode)); ++ hidden_parent = au_h_dptr_i(parent, bindex); ++ DEBUG_ON(!hidden_parent); ++ hidden_dir = hidden_parent->d_inode; ++ DEBUG_ON(!hidden_dir || !S_ISDIR(hidden_dir->i_mode)); ++ IMustLock(hidden_dir); ++ ++ lkup.nfsmnt = au_nfsmnt(dentry->d_sb, bindex); ++ lkup.dlgt = need_dlgt(dentry->d_sb); ++ hidden_dentry = sio_lkup_one(dentry->d_name.name, hidden_parent, ++ dentry->d_name.len, &lkup); ++ //if (LktrCond) {dput(hidden_dentry); hidden_dentry = ERR_PTR(-1);} ++ err = PTR_ERR(hidden_dentry); ++ if (IS_ERR(hidden_dentry)) ++ goto out; ++ if (unlikely(hidden_dentry->d_inode)) { ++ err = -EIO; ++ IOErr("b%d %.*s should be negative.%s\n", ++ bindex, DLNPair(hidden_dentry), ++ au_flag_test(dentry->d_sb, AuFlag_UDBA_INOTIFY) ? "" : ++ " Try udba=inotify."); ++ dput(hidden_dentry); ++ goto out; ++ } ++ ++ if (bindex < dbstart(dentry)) ++ set_dbstart(dentry, bindex); ++ if (dbend(dentry) < bindex) ++ set_dbend(dentry, bindex); ++ set_h_dptr(dentry, bindex, hidden_dentry); ++ err = 0; ++ ++ out: ++ dput(parent); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * returns the number of found hidden positive dentries, ++ * otherwise an error. ++ */ ++int au_refresh_hdentry(struct dentry *dentry, mode_t type) ++{ ++ int npositive, pgen, new_sz, sgen, dgen; ++ struct aufs_dinfo *dinfo; ++ struct super_block *sb; ++ struct dentry *parent; ++ aufs_bindex_t bindex, parent_bend, parent_bstart, bwh, bdiropq, bend; ++ struct aufs_hdentry *p; ++ //struct nameidata nd; ++ ++ LKTRTrace("%.*s, type 0%o\n", DLNPair(dentry), type); ++ DiMustWriteLock(dentry); ++ sb = dentry->d_sb; ++ DEBUG_ON(IS_ROOT(dentry)); ++ parent = dget_parent(dentry); ++ pgen = au_digen(parent); ++ sgen = au_sigen(sb); ++ dgen = au_digen(dentry); ++ DEBUG_ON(pgen != sgen); ++ ++ npositive = -ENOMEM; ++ new_sz = sizeof(*dinfo->di_hdentry) * (sbend(sb) + 1); ++ dinfo = dtodi(dentry); ++ p = au_kzrealloc(dinfo->di_hdentry, sizeof(*p) * (dinfo->di_bend + 1), ++ new_sz, GFP_KERNEL); ++ //p = NULL; ++ if (unlikely(!p)) ++ goto out; ++ dinfo->di_hdentry = p; ++ ++ bend = dinfo->di_bend; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ p += dinfo->di_bstart; ++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { ++ struct dentry *hd, *hdp; ++ struct aufs_hdentry tmp, *q; ++ aufs_bindex_t new_bindex; ++ ++ hd = p->hd_dentry; ++ if (!hd) ++ continue; ++ hdp = dget_parent(hd); ++ if (hdp == au_h_dptr_i(parent, bindex)) { ++ dput(hdp); ++ continue; ++ } ++ ++ new_bindex = au_find_dbindex(parent, hdp); ++ dput(hdp); ++ DEBUG_ON(new_bindex == bindex); ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { // test here ++ hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ /* swap two hidden dentries, and loop again */ ++ q = dinfo->di_hdentry + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ // test here ++ dinfo->di_bwh = -1; ++ if (unlikely(bwh != -1 && bwh <= sbend(sb) && sbr_is_whable(sb, bwh))) ++ dinfo->di_bwh = bwh; ++ dinfo->di_bdiropq = -1; ++ if (unlikely(bdiropq != -1 && bdiropq <= sbend(sb) ++ && sbr_is_whable(sb, bdiropq))) ++ dinfo->di_bdiropq = bdiropq; ++ parent_bend = dbend(parent); ++ p = dinfo->di_hdentry; ++ for (bindex = 0; bindex <= parent_bend; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_bstart = bindex; ++ break; ++ } ++ p = dinfo->di_hdentry + parent_bend; ++ //for (bindex = parent_bend; bindex > dinfo->di_bstart; bindex--, p--) ++ for (bindex = parent_bend; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bend = bindex; ++ break; ++ } ++ ++ npositive = 0; ++ parent_bstart = dbstart(parent); ++ if (type != S_IFDIR && dinfo->di_bstart == parent_bstart) ++ goto out_dgen; /* success */ ++ ++#if 0 ++ nd.last_type = LAST_ROOT; ++ nd.flags = LOOKUP_FOLLOW; ++ nd.depth = 0; ++ nd.mnt = mntget(??); ++ nd.dentry = dget(parent); ++#endif ++ npositive = lkup_dentry(dentry, parent_bstart, type); ++ //if (LktrCond) npositive = -1; ++ if (npositive < 0) ++ goto out; ++ ++ out_dgen: ++ au_update_digen(dentry); ++ out: ++ dput(parent); ++ TraceErr(npositive); ++ return npositive; ++} ++ ++static int h_d_revalidate(struct dentry *dentry, struct nameidata *nd, ++ int do_udba) ++{ ++ int err, plus, locked, unhashed, is_root, h_plus, is_nfs; ++ struct nameidata fake_nd, *p; ++ aufs_bindex_t bindex, btail, bstart, ibs, ibe; ++ struct super_block *sb; ++ struct inode *inode, *first, *h_inode, *h_cached_inode; ++ umode_t mode, h_mode; ++ struct dentry *h_dentry; ++ int (*reval)(struct dentry *, struct nameidata *); ++ struct qstr *name; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(inode && au_digen(dentry) != au_iigen(inode)); ++ //DbgDentry(dentry); ++ //DbgInode(inode); ++ ++ err = 0; ++ sb = dentry->d_sb; ++ plus = 0; ++ mode = 0; ++ first = NULL; ++ ibs = ibe = -1; ++ unhashed = d_unhashed(dentry); ++ is_root = IS_ROOT(dentry); ++ name = &dentry->d_name; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of INOTIFY. ++ * But inotify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * IN_DELETE for NFS dentry ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ first = au_h_iptr(inode); ++ ibs = ibstart(inode); ++ ibe = ibend(inode); ++ } ++ ++ btail = bstart = dbstart(dentry); ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = dbtaildir(dentry); ++ locked = 0; ++ if (nd) { ++ fake_nd = *nd; ++#ifndef CONFIG_AUFS_FAKE_DM ++ if (dentry != nd->dentry) { ++ di_read_lock_parent(nd->dentry, 0); ++ locked = 1; ++ } ++#endif ++ } ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr_i(dentry, bindex); ++ if (unlikely(!h_dentry)) ++ continue; ++ if (unlikely(do_udba ++ && !is_root ++ && (unhashed != d_unhashed(h_dentry) ++#if 1 ++ || name->len != h_dentry->d_name.len ++ || memcmp(name->name, h_dentry->d_name.name, ++ name->len) ++#endif ++ ))) { ++ LKTRTrace("unhash 0x%x 0x%x, %.*s %.*s\n", ++ unhashed, d_unhashed(h_dentry), ++ DLNPair(dentry), DLNPair(h_dentry)); ++ goto err; ++ } ++ ++ reval = NULL; ++ if (h_dentry->d_op) ++ reval = h_dentry->d_op->d_revalidate; ++ if (unlikely(reval)) { ++ //LKTRLabel(hidden reval); ++ p = fake_dm(&fake_nd, nd, sb, bindex); ++ DEBUG_ON(IS_ERR(p)); ++ err = !reval(h_dentry, p); ++ fake_dm_release(p); ++ if (unlikely(err)) { ++ //Dbg("here\n"); ++ goto err; ++ } ++ } ++ ++ if (unlikely(!do_udba)) ++ continue; ++ ++ /* UDBA tests */ ++ h_inode = h_dentry->d_inode; ++ if (unlikely(!!inode != !!h_inode)) { ++ //Dbg("here\n"); ++ goto err; ++ } ++ ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ is_nfs = 0; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) { ++ h_cached_inode = au_h_iptr_i(inode, bindex); ++ //is_nfs = au_is_nfs(h_cached_inode->i_sb); ++ } ++ ++ LKTRTrace("{%d, 0%o, %p}, h{%d, 0%o, %p}\n", ++ plus, mode, h_cached_inode, ++ h_plus, h_mode, h_inode); ++ if (unlikely(plus != h_plus || mode != h_mode ++ || (h_cached_inode != h_inode /* && !is_nfs */))) { ++ //Dbg("here\n"); ++ goto err; ++ } ++ continue; ++ ++ err: ++ err = -EINVAL; ++ break; ++ } ++#ifndef CONFIG_AUFS_FAKE_DM ++ if (unlikely(locked)) ++ di_read_unlock(nd->dentry, 0); ++#endif ++ ++#if 0 ++ // some filesystem uses CURRENT_TIME_SEC instead of CURRENT_TIME. ++ // NFS may stop IN_DELETE because of DCACHE_NFSFS_RENAMED. ++#if 0 ++ && (!timespec_equal(&inode->i_ctime, &first->i_ctime) ++ || !timespec_equal(&inode->i_atime, &first->i_atime)) ++#endif ++ if (unlikely(!err && udba && first)) ++ au_cpup_attr_all(inode); ++#endif ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int simple_reval_dpath(struct dentry *dentry, int sgen) ++{ ++ int err; ++ mode_t type; ++ struct dentry *parent; ++ struct inode *inode; ++ ++ LKTRTrace("%.*s, sgen %d\n", DLNPair(dentry), sgen); ++ SiMustAnyLock(dentry->d_sb); ++ DiMustWriteLock(dentry); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode); ++ ++ if (au_digen(dentry) == sgen) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ DEBUG_ON(au_digen(parent) != sgen); ++#ifdef CONFIG_AUFS_DEBUG ++ { ++ struct dentry *d = parent; ++ while (!IS_ROOT(d)) { ++ DEBUG_ON(au_digen(d) != sgen); ++ d = d->d_parent; ++ } ++ } ++#endif ++ type = (inode->i_mode & S_IFMT); ++ /* returns a number of positive dentries */ ++ err = au_refresh_hdentry(dentry, type); ++ if (err >= 0) ++ err = au_refresh_hinode(inode, dentry); ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ dput(parent); ++ TraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, int sgen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ struct inode *inode; ++ ++ LKTRTrace("%.*s, sgen %d\n", DLNPair(dentry), sgen); ++ DEBUG_ON(!dentry->d_inode); ++ DiMustWriteLock(dentry); ++ ++ if (!stosi(dentry->d_sb)->si_failed_refresh_dirs) ++ return simple_reval_dpath(dentry, sgen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: cpup_dirs() */ ++ err = 0; ++ while (au_digen(dentry) != sgen) { ++ d = dentry; ++ while (1) { ++ parent = d->d_parent; // dget_parent() ++ if (au_digen(parent) == sgen) ++ break; ++ d = parent; ++ } ++ ++ inode = d->d_inode; ++ if (d != dentry) { ++ //i_lock(inode); ++ di_write_lock_child(d); ++ } ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen(d) != sgen) { ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ /* returns a number of positive dentries */ ++ err = au_refresh_hdentry(d, inode->i_mode & S_IFMT); ++ //err = -1; ++ if (err >= 0) ++ err = au_refresh_hinode(inode, d); ++ //err = -1; ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ } ++ ++ if (d != dentry) { ++ di_write_unlock(d); ++ //i_unlock(inode); ++ } ++ if (unlikely(err)) ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * THIS IS A BOOLEAN FUNCTION: returns 1 if valid, 0 otherwise. ++ * nfsd passes NULL as nameidata. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd) ++{ ++ int valid, sgen, err, do_udba; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ LKTRTrace("dentry %.*s\n", DLNPair(dentry)); ++ if (nd && nd->dentry) ++ LKTRTrace("nd %.*s\n", DLNPair(nd->dentry)); ++ //dir case: DEBUG_ON(dentry->d_parent != nd->dentry); ++ //remove failure case: DEBUG_ON(!IS_ROOT(dentry) && d_unhashed(dentry)); ++ DEBUG_ON(!dentry->d_fsdata); ++ //DbgDentry(dentry); ++ ++ err = -EINVAL; ++ inode = dentry->d_inode; ++ //DbgInode(inode); ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ sgen = au_sigen(sb); ++ if (au_digen(dentry) == sgen) ++ di_read_lock_child(dentry, !AUFS_I_RLOCK); ++ else { ++ DEBUG_ON(IS_ROOT(dentry)); ++#ifdef ForceInotify ++ Dbg("UDBA or digen, %.*s\n", DLNPair(dentry)); ++#endif ++ //i_lock(inode); ++ di_write_lock_child(dentry); ++ if (inode) ++ err = au_reval_dpath(dentry, sgen); ++ //err = -1; ++ di_downgrade_lock(dentry, AUFS_I_RLOCK); ++ //i_unlock(inode); ++ if (unlikely(err)) ++ goto out; ++ ii_read_unlock(inode); ++ DEBUG_ON(au_iigen(inode) != sgen); ++ } ++ ++ if (inode) { ++ if (au_iigen(inode) == sgen) ++ ii_read_lock_child(inode); ++ else { ++ DEBUG_ON(IS_ROOT(dentry)); ++#ifdef ForceInotify ++ Dbg("UDBA or survived, %.*s\n", DLNPair(dentry)); ++#endif ++ ii_write_lock_child(inode); ++ err = au_refresh_hinode(inode, dentry); ++ ii_downgrade_lock(inode); ++ if (unlikely(err)) ++ goto out; ++ DEBUG_ON(au_iigen(inode) != sgen); ++ } ++ } ++ ++#if 0 // fix it ++ /* parent dir i_nlink is not updated in the case of setattr */ ++ if (S_ISDIR(inode->i_mode)) { ++ i_lock(inode); ++ ii_write_lock(inode); ++ au_cpup_attr_nlink(inode); ++ ii_write_unlock(inode); ++ i_unlock(inode); ++ } ++#endif ++ ++ err = -EINVAL; ++ do_udba = !au_flag_test(sb, AuFlag_UDBA_NONE); ++ if (do_udba && inode && ibstart(inode) >= 0 ++ && au_test_higen(inode, au_h_iptr(inode))) ++ goto out; ++ err = h_d_revalidate(dentry, nd, do_udba); ++ //err = -1; ++ ++ out: ++ aufs_read_unlock(dentry, AUFS_I_RLOCK); ++ TraceErr(err); ++ valid = !err; ++ //au_debug_on(); ++ if (!valid) ++ LKTRTrace("%.*s invalid\n", DLNPair(dentry)); ++ //au_debug_off(); ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ struct aufs_dinfo *dinfo; ++ aufs_bindex_t bend, bindex; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(!d_unhashed(dentry)); ++ ++ dinfo = dentry->d_fsdata; ++ if (unlikely(!dinfo)) ++ return; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_bstart; ++ if (bindex >= 0) { ++ struct aufs_hdentry *p; ++ bend = dinfo->di_bend; ++ DEBUG_ON(bend < bindex); ++ p = dinfo->di_hdentry + bindex; ++ while (bindex++ <= bend) { ++ if (p->hd_dentry) ++ hdput(p); ++ p++; ++ } ++ } ++ kfree(dinfo->di_hdentry); ++ cache_free_dinfo(dinfo); ++} ++ ++#if 0 ++/* it may be called at remount time, too */ ++static void aufs_d_iput(struct dentry *dentry, struct inode *inode) ++{ ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, i%lu\n", DLNPair(dentry), inode->i_ino); ++ ++ sb = dentry->d_sb; ++#if 0 ++ si_read_lock(sb); ++ if (unlikely(au_flag_test(sb, AuFlag_PLINK) ++ && au_is_plinked(sb, inode))) { ++ ii_write_lock(inode); ++ au_update_brange(inode, 1); ++ ii_write_unlock(inode); ++ } ++ si_read_unlock(sb); ++#endif ++ iput(inode); ++} ++#endif ++ ++struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++ //.d_iput = aufs_d_iput ++}; +diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h +new file mode 100755 +index 0000000..78049e3 +--- /dev/null ++++ b/fs/aufs/dentry.h +@@ -0,0 +1,183 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dentry.h,v 1.25 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "misc.h" ++ ++struct aufs_hdentry { ++ struct dentry *hd_dentry; ++}; ++ ++struct aufs_dinfo { ++ atomic_t di_generation; ++ ++ struct aufs_rwsem di_rwsem; ++ aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq; ++ struct aufs_hdentry *di_hdentry; ++}; ++ ++struct lkup_args { ++ struct vfsmount *nfsmnt; ++ int dlgt; ++ //struct super_block *sb; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++#if defined(CONFIG_AUFS_LHASH_PATCH) || defined(CONFIG_AUFS_DLGT) ++struct dentry *lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup); ++#else ++static inline ++struct dentry *lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup) ++{ ++ return lookup_one_len(name, parent, len); ++} ++#endif ++ ++extern struct dentry_operations aufs_dop; ++struct dentry *sio_lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup); ++int lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type); ++int lkup_neg(struct dentry *dentry, aufs_bindex_t bindex); ++int au_refresh_hdentry(struct dentry *dentry, mode_t type); ++int au_reval_dpath(struct dentry *dentry, int sgen); ++ ++/* dinfo.c */ ++int au_alloc_dinfo(struct dentry *dentry); ++struct aufs_dinfo *dtodi(struct dentry *dentry); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++aufs_bindex_t dbstart(struct dentry *dentry); ++aufs_bindex_t dbend(struct dentry *dentry); ++aufs_bindex_t dbwh(struct dentry *dentry); ++aufs_bindex_t dbdiropq(struct dentry *dentry); ++struct dentry *au_h_dptr_i(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_dptr(struct dentry *dentry); ++ ++aufs_bindex_t dbtail(struct dentry *dentry); ++aufs_bindex_t dbtaildir(struct dentry *dentry); ++aufs_bindex_t dbtail_generic(struct dentry *dentry); ++ ++void set_dbstart(struct dentry *dentry, aufs_bindex_t bindex); ++void set_dbend(struct dentry *dentry, aufs_bindex_t bindex); ++void set_dbwh(struct dentry *dentry, aufs_bindex_t bindex); ++void set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex); ++void hdput(struct aufs_hdentry *hdentry); ++void set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++ ++void au_update_digen(struct dentry *dentry); ++void au_update_dbstart(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_digen(struct dentry *d) ++{ ++ return atomic_read(&dtodi(d)->di_generation); ++} ++ ++#ifdef CONFIG_AUFS_HINOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&dtodi(d)->di_generation); ++} ++#endif /* CONFIG_AUFS_HINOTIFY */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hinotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3 ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define ReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{di_read_lock(d, flags, AuLsc_DI_##lsc);} ++ ++#define WriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{di_write_lock(d, AuLsc_DI_##lsc);} ++ ++#define RWLockFuncs(name, lsc) \ ++ ReadLockFunc(name, lsc); \ ++ WriteLockFunc(name, lsc) ++ ++RWLockFuncs(child, CHILD); ++RWLockFuncs(child2, CHILD2); ++RWLockFuncs(child3, CHILD3); ++RWLockFuncs(parent, PARENT); ++RWLockFuncs(parent2, PARENT2); ++RWLockFuncs(parent3, PARENT3); ++ ++#undef ReadLockFunc ++#undef WriteLockFunc ++#undef RWLockFunc ++ ++/* to debug easier, do not make them inlined functions */ ++#define DiMustReadLock(d) do { \ ++ SiMustAnyLock((d)->d_sb); \ ++ RwMustReadLock(&dtodi(d)->di_rwsem); \ ++} while (0) ++ ++#define DiMustWriteLock(d) do { \ ++ SiMustAnyLock((d)->d_sb); \ ++ RwMustWriteLock(&dtodi(d)->di_rwsem); \ ++} while (0) ++ ++#define DiMustAnyLock(d) do { \ ++ SiMustAnyLock((d)->d_sb); \ ++ RwMustAnyLock(&dtodi(d)->di_rwsem); \ ++} while (0) ++ ++#define DiMustNoWaiters(d) RwMustNoWaiters(&dtodi(d)->di_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c +new file mode 100755 +index 0000000..6082149 +--- /dev/null ++++ b/fs/aufs/dinfo.c +@@ -0,0 +1,419 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dinfo.c,v 1.23 2007/05/07 03:43:36 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++int au_alloc_dinfo(struct dentry *dentry) ++{ ++ struct aufs_dinfo *dinfo; ++ struct super_block *sb; ++ int nbr; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(dentry->d_fsdata); ++ ++ dinfo = cache_alloc_dinfo(); ++ //if (LktrCond) {cache_free_dinfo(dinfo); dinfo = NULL;} ++ if (dinfo) { ++ sb = dentry->d_sb; ++ nbr = sbend(sb) + 1; ++ if (unlikely(!nbr)) ++ nbr++; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), ++ GFP_KERNEL); ++ //if (LktrCond) ++ //{kfree(dinfo->di_hdentry); dinfo->di_hdentry = NULL;} ++ if (dinfo->di_hdentry) { ++ rw_init_wlock_nested(&dinfo->di_rwsem, AuLsc_DI_PARENT); ++ dinfo->di_bstart = dinfo->di_bend = -1; ++ dinfo->di_bwh = dinfo->di_bdiropq = -1; ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ ++ dentry->d_fsdata = dinfo; ++ dentry->d_op = &aufs_dop; ++ return 0; /* success */ ++ } ++ cache_free_dinfo(dinfo); ++ } ++ TraceErr(-ENOMEM); ++ return -ENOMEM; ++} ++ ++struct aufs_dinfo *dtodi(struct dentry *dentry) ++{ ++ struct aufs_dinfo *dinfo = dentry->d_fsdata; ++ DEBUG_ON(!dinfo ++ || !dinfo->di_hdentry ++ /* || stosi(dentry->d_sb)->si_bend < dinfo->di_bend */ ++ || dinfo->di_bend < dinfo->di_bstart ++ /* dbwh can be outside of this range */ ++ || (0 <= dinfo->di_bdiropq ++ && (dinfo->di_bdiropq < dinfo->di_bstart ++ /* || dinfo->di_bend < dinfo->di_bdiropq */)) ++ ); ++ return dinfo; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ SiMustAnyLock(d->d_sb); ++ // todo: always nested? ++ rw_read_lock_nested(&dtodi(d)->di_rwsem, lsc); ++ if (d->d_inode) { ++ if (flags & AUFS_I_WLOCK) ++ do_ii_write_lock(d->d_inode, lsc); ++ else if (flags & AUFS_I_RLOCK) ++ do_ii_read_lock(d->d_inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ SiMustAnyLock(d->d_sb); ++ if (d->d_inode) { ++ if (flags & AUFS_I_WLOCK) ++ ii_write_unlock(d->d_inode); ++ else if (flags & AUFS_I_RLOCK) ++ ii_read_unlock(d->d_inode); ++ } ++ rw_read_unlock(&dtodi(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ SiMustAnyLock(d->d_sb); ++ rw_dgrade_lock(&dtodi(d)->di_rwsem); ++ if (d->d_inode && (flags & AUFS_I_RLOCK)) ++ ii_downgrade_lock(d->d_inode); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ SiMustAnyLock(d->d_sb); ++ // todo: always nested? ++ rw_write_lock_nested(&dtodi(d)->di_rwsem, lsc); ++ if (d->d_inode) ++ do_ii_write_lock(d->d_inode, lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ SiMustAnyLock(d->d_sb); ++ if (d->d_inode) ++ ii_write_unlock(d->d_inode); ++ rw_write_unlock(&dtodi(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ struct dentry *d; ++ ++ TraceEnter(); ++ DEBUG_ON(d1 == d2 ++ || d1->d_inode == d2->d_inode ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir) ++ for (d = d1; d->d_parent != d; d = d->d_parent) // dget_parent() ++ if (d->d_parent == d2) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ return; ++ } ++ ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ struct dentry *d; ++ ++ TraceEnter(); ++ DEBUG_ON(d1 == d2 ++ || d1->d_inode == d2->d_inode ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir) ++ for (d = d1; d->d_parent != d; d = d->d_parent) // dget_parent() ++ if (d->d_parent == d2) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ return; ++ } ++ ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d1->d_inode == d2->d_inode) ++ rw_write_unlock(&dtodi(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++aufs_bindex_t dbstart(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return dtodi(dentry)->di_bstart; ++} ++ ++aufs_bindex_t dbend(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return dtodi(dentry)->di_bend; ++} ++ ++aufs_bindex_t dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return dtodi(dentry)->di_bwh; ++} ++ ++aufs_bindex_t dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ DEBUG_ON(dentry->d_inode ++ && dentry->d_inode->i_mode ++ && !S_ISDIR(dentry->d_inode->i_mode)); ++ return dtodi(dentry)->di_bdiropq; ++} ++ ++struct dentry *au_h_dptr_i(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ if (dbstart(dentry) < 0 || bindex < dbstart(dentry)) ++ return NULL; ++ DEBUG_ON(bindex < 0 ++ /* || bindex > sbend(dentry->d_sb) */); ++ d = dtodi(dentry)->di_hdentry[0 + bindex].hd_dentry; ++ DEBUG_ON(d && (atomic_read(&d->d_count) <= 0)); ++ return d; ++} ++ ++struct dentry *au_h_dptr(struct dentry *dentry) ++{ ++ return au_h_dptr_i(dentry, dbstart(dentry)); ++} ++ ++aufs_bindex_t dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bend, bwh; ++ ++ bend = dbend(dentry); ++ if (0 <= bend) { ++ bwh = dbwh(dentry); ++ //DEBUG_ON(bend < bwh); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bend) ++ return bwh - 1; ++ } ++ return bend; ++} ++ ++aufs_bindex_t dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bend, bopq; ++ ++ DEBUG_ON(dentry->d_inode ++ && dentry->d_inode->i_mode ++ && !S_ISDIR(dentry->d_inode->i_mode)); ++ ++ bend = dbtail(dentry); ++ if (0 <= bend) { ++ bopq = dbdiropq(dentry); ++ DEBUG_ON(bend < bopq); ++ if (0 <= bopq && bopq < bend) ++ bend = bopq; ++ } ++ return bend; ++} ++ ++aufs_bindex_t dbtail_generic(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ if (inode && S_ISDIR(inode->i_mode)) ++ return dbtaildir(dentry); ++ else ++ return dbtail(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++// hard/soft set ++void set_dbstart(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ DEBUG_ON(sbend(dentry->d_sb) < bindex); ++ /* */ ++ dtodi(dentry)->di_bstart = bindex; ++} ++ ++void set_dbend(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ DEBUG_ON(sbend(dentry->d_sb) < bindex ++ || bindex < dbstart(dentry)); ++ dtodi(dentry)->di_bend = bindex; ++} ++ ++void set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ DEBUG_ON(sbend(dentry->d_sb) < bindex); ++ /* dbwh can be outside of bstart - bend range */ ++ dtodi(dentry)->di_bwh = bindex; ++} ++ ++void set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ DEBUG_ON(sbend(dentry->d_sb) < bindex); ++ DEBUG_ON((bindex != -1 ++ && (bindex < dbstart(dentry) || dbend(dentry) < bindex)) ++ || (dentry->d_inode ++ && dentry->d_inode->i_mode ++ && !S_ISDIR(dentry->d_inode->i_mode))); ++ dtodi(dentry)->di_bdiropq = bindex; ++} ++ ++void hdput(struct aufs_hdentry *hd) ++{ ++ dput(hd->hd_dentry); ++} ++ ++void set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct aufs_hdentry *hd = dtodi(dentry)->di_hdentry + bindex; ++ DiMustWriteLock(dentry); ++ DEBUG_ON(bindex < dtodi(dentry)->di_bstart ++ || bindex > dtodi(dentry)->di_bend ++ || (h_dentry && atomic_read(&h_dentry->d_count) <= 0) ++ || (h_dentry && hd->hd_dentry) ++ ); ++ if (hd->hd_dentry) ++ hdput(hd); ++ hd->hd_dentry = h_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ //DiMustWriteLock(dentry); ++ DEBUG_ON(!dentry->d_sb); ++ atomic_set(&dtodi(dentry)->di_generation, au_sigen(dentry->d_sb)); ++} ++ ++void au_update_dbstart(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bstart = dbstart(dentry), bend = dbend(dentry); ++ struct dentry *hidden_dentry; ++ ++ DiMustWriteLock(dentry); ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!hidden_dentry) ++ continue; ++ if (hidden_dentry->d_inode) { ++ set_dbstart(dentry, bindex); ++ return; ++ } ++ set_h_dptr(dentry, bindex, NULL); ++ } ++ //set_dbstart(dentry, -1); ++ //set_dbend(dentry, -1); ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *hidden_dentry) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); bindex <= bend; bindex++) ++ if (au_h_dptr_i(dentry, bindex) == hidden_dentry) ++ return bindex; ++ return -1; ++} +diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c +new file mode 100755 +index 0000000..9afb1a9 +--- /dev/null ++++ b/fs/aufs/dir.c +@@ -0,0 +1,564 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dir.c,v 1.36 2007/05/14 03:38:52 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ struct dentry *dentry, *hidden_dentry; ++ aufs_bindex_t bindex, btail, bstart; ++ struct file *hidden_file; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(!S_ISDIR(dentry->d_inode->i_mode)); ++ ++ /* open all hidden dirs */ ++ bstart = dbstart(dentry); ++#if 1 ++ for (bindex = fbstart(file); bindex < bstart; bindex++) ++ set_h_fptr(file, bindex, NULL); ++#endif ++ set_fbstart(file, bstart); ++ btail = dbtaildir(dentry); ++#if 1 ++ for (bindex = fbend(file); btail < bindex; bindex--) ++ set_h_fptr(file, bindex, NULL); ++#endif ++ set_fbend(file, btail); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!hidden_dentry) ++ continue; ++ hidden_file = au_h_fptr_i(file, bindex); ++ if (hidden_file) { ++ DEBUG_ON(hidden_file->f_dentry != hidden_dentry); ++ continue; ++ } ++ ++ hidden_file = hidden_open(dentry, bindex, file->f_flags); ++ // unavailable ++ //if (LktrCond) {fput(hidden_file); ++ //br_put(stobr(dentry->d_sb, bindex));hidden_file=ERR_PTR(-1);} ++ err = PTR_ERR(hidden_file); ++ if (IS_ERR(hidden_file)) ++ goto out; // close all? ++ //cpup_file_flags(hidden_file, file); ++ set_h_fptr(file, bindex, hidden_file); ++ } ++ err = 0; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *hidden_dentry; ++ struct file *hidden_file; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, 0x%x\n", DLNPair(dentry), flags); ++ DEBUG_ON(!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)); ++ ++ err = 0; ++ set_fvdir_cache(file, NULL); ++ file->f_version = dentry->d_inode->i_version; ++ bindex = dbstart(dentry); ++ set_fbstart(file, bindex); ++ btail = dbtaildir(dentry); ++ set_fbend(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!hidden_dentry) ++ continue; ++ ++ hidden_file = hidden_open(dentry, bindex, flags); ++ //if (LktrCond) {fput(hidden_file); ++ //br_put(stobr(dentry->d_sb, bindex));hidden_file=ERR_PTR(-1);} ++ if (!IS_ERR(hidden_file)) { ++ set_h_fptr(file, bindex, hidden_file); ++ continue; ++ } ++ err = PTR_ERR(hidden_file); ++ } ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = fbstart(file); !err && bindex <= btail; bindex++) ++ set_h_fptr(file, bindex, NULL); ++ set_fbstart(file, -1); ++ set_fbend(file, -1); ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode, struct file *file) ++{ ++ return au_do_open(inode, file, do_open_dir); ++} ++ ++static int aufs_release_dir(struct inode *inode, struct file *file) ++{ ++ struct aufs_vdir *vdir_cache; ++ struct super_block *sb; ++ ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(file->f_dentry)); ++ ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb); ++ fi_write_lock(file); ++ vdir_cache = fvdir_cache(file); ++ if (vdir_cache) ++ free_vdir(vdir_cache); ++ fi_write_unlock(file); ++ au_fin_finfo(file); ++ si_read_unlock(sb); ++ return 0; ++} ++ ++static int fsync_dir(struct dentry *dentry, int datasync) ++{ ++ int err; ++ struct inode *inode; ++ struct super_block *sb; ++ aufs_bindex_t bend, bindex; ++ ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), datasync); ++ DiMustAnyLock(dentry); ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ IiMustAnyLock(inode); ++ ++ err = 0; ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); !err && bindex <= bend; bindex++) { ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct file_operations *fop; ++ ++ if (test_ro(sb, bindex, inode)) ++ continue; ++ h_dentry = au_h_dptr_i(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = h_dentry->d_inode; ++ if (!h_inode) ++ continue; ++ ++ /* cf. fs/nsfd/vfs.c and fs/nfsd/nfs4recover.c */ ++ //hdir_lock(h_inode, inode, bindex); ++ i_lock(h_inode); ++ fop = (void*)h_inode->i_fop; ++ err = filemap_fdatawrite(h_inode->i_mapping); ++ if (!err && fop && fop->fsync) ++ err = fop->fsync(NULL, h_dentry, datasync); ++ if (!err) ++ err = filemap_fdatawrite(h_inode->i_mapping); ++ //hdir_unlock(h_inode, inode, bindex); ++ i_unlock(h_inode); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, struct dentry *dentry, ++ int datasync) ++{ ++ int err; ++ struct inode *inode; ++ struct file *hidden_file; ++ struct super_block *sb; ++ aufs_bindex_t bend, bindex; ++ ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), datasync); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ err = 0; ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ if (file) { ++ err = au_reval_and_lock_finfo(file, reopen_dir, /*wlock*/1, ++ /*locked*/1); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ } else ++ di_read_lock_child(dentry, !AUFS_I_WLOCK); ++ ++ ii_write_lock_child(inode); ++ if (file) { ++ bend = fbend(file); ++ for (bindex = fbstart(file); !err && bindex <= bend; bindex++) { ++ hidden_file = au_h_fptr_i(file, bindex); ++ if (!hidden_file || test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = -EINVAL; ++ if (hidden_file->f_op && hidden_file->f_op->fsync) { ++ // todo: try do_fsync() in fs/sync.c ++#if 0 ++ DEBUG_ON(hidden_file->f_dentry->d_inode ++ != au_h_iptr_i(inode, bindex)); ++ hdir_lock(hidden_file->f_dentry->d_inode, inode, ++ bindex); ++#else ++ i_lock(hidden_file->f_dentry->d_inode); ++#endif ++ err = hidden_file->f_op->fsync ++ (hidden_file, hidden_file->f_dentry, ++ datasync); ++ //err = -1; ++#if 0 ++ hdir_unlock(hidden_file->f_dentry->d_inode, ++ inode, bindex); ++#else ++ i_unlock(hidden_file->f_dentry->d_inode); ++#endif ++ } ++ } ++ } else ++ err = fsync_dir(dentry, datasync); ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ if (file) ++ fi_write_unlock(file); ++ else ++ di_read_unlock(dentry, !AUFS_I_WLOCK); ++ ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld\n", DLNPair(dentry), file->f_pos); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ au_nfsd_lockdep_off(); ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, reopen_dir, /*wlock*/1, ++ /*locked*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ ii_write_lock_child(inode); ++ err = au_init_vdir(file); ++ if (unlikely(err)) { ++ ii_write_unlock(inode); ++ goto out_unlock; ++ } ++ //DbgVdir(fvdir_cache(file));// goto out_unlock; ++ ++ /* nfsd filldir calls lookup_one_len(). */ ++ ii_downgrade_lock(inode); ++ err = au_fill_de(file, dirent, filldir); ++ //DbgVdir(fvdir_cache(file));// goto out_unlock; ++ ++ inode->i_atime = au_h_iptr(inode)->i_atime; ++ ii_read_unlock(inode); ++ ++ out_unlock: ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ au_nfsd_lockdep_on(); ++#if 0 // debug ++ if (LktrCond) ++ igrab(inode); ++#endif ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct test_empty_arg { ++ struct aufs_nhash *whlist; ++ int whonly; ++ aufs_bindex_t bindex; ++ int err, called; ++}; ++ ++static int test_empty_cb(void *__arg, const char *__name, int namelen, ++ loff_t offset, filldir_ino_t ino, unsigned int d_type) ++{ ++ struct test_empty_arg *arg = __arg; ++ char *name = (void*)__name; ++ ++ LKTRTrace("%.*s\n", namelen, name); ++ ++ arg->err = 0; ++ arg->called++; ++ //smp_mb(); ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ return 0; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (arg->whonly && !test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!test_known_wh(arg->whlist, name, namelen)) ++ arg->err = append_wh(arg->whlist, name, namelen, arg->bindex); ++ ++ out: ++ //smp_mb(); ++ TraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, dlgt; ++ struct file *hidden_file; ++ ++ LKTRTrace("%.*s, {%p, %d, %d}\n", ++ DLNPair(dentry), arg->whlist, arg->whonly, arg->bindex); ++ ++ hidden_file = hidden_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY ++ | O_LARGEFILE); ++ err = PTR_ERR(hidden_file); ++ if (IS_ERR(hidden_file)) ++ goto out; ++ ++ dlgt = need_dlgt(dentry->d_sb); ++ //hidden_file->f_pos = 0; ++ do { ++ arg->err = 0; ++ arg->called = 0; ++ //smp_mb(); ++ err = vfsub_readdir(hidden_file, test_empty_cb, arg, dlgt); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && arg->called); ++ fput(hidden_file); ++ sbr_put(dentry->d_sb, arg->bindex); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct dentry *hidden_dentry; ++ struct inode *hidden_inode; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ hidden_dentry = au_h_dptr_i(dentry, arg->bindex); ++ DEBUG_ON(!hidden_dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode || !S_ISDIR(hidden_inode->i_mode)); ++ ++ hi_lock_child(hidden_inode); ++ err = au_test_perm(hidden_inode, MAY_EXEC | MAY_READ, ++ need_dlgt(dentry->d_sb)); ++ i_unlock(hidden_inode); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ au_wkq_wait(call_do_test_empty, &args, /*dlgt*/0); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ struct inode *inode; ++ struct test_empty_arg arg; ++ struct aufs_nhash *whlist; ++ aufs_bindex_t bindex, bstart, btail; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode || !S_ISDIR(inode->i_mode)); ++ ++ whlist = nhash_new(GFP_KERNEL); ++ err = PTR_ERR(whlist); ++ if (IS_ERR(whlist)) ++ goto out; ++ ++ bstart = dbstart(dentry); ++ arg.whlist = whlist; ++ arg.whonly = 0; ++ arg.bindex = bstart; ++ err = do_test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ arg.whonly = 1; ++ btail = dbtaildir(dentry); ++ for (bindex = bstart + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *hidden_dentry; ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (hidden_dentry && hidden_dentry->d_inode) { ++ DEBUG_ON(!S_ISDIR(hidden_dentry->d_inode->i_mode)); ++ arg.bindex = bindex; ++ err = do_test_empty(dentry, &arg); ++ } ++ } ++ ++ out_whlist: ++ nhash_del(whlist); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++int test_empty(struct dentry *dentry, struct aufs_nhash *whlist) ++{ ++ int err; ++ struct inode *inode; ++ struct test_empty_arg arg; ++ aufs_bindex_t bindex, btail; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode || !S_ISDIR(inode->i_mode)); ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.whonly = 1; ++ btail = dbtaildir(dentry); ++ for (bindex = dbstart(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *hidden_dentry; ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (hidden_dentry && hidden_dentry->d_inode) { ++ DEBUG_ON(!S_ISDIR(hidden_dentry->d_inode->i_mode)); ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ DEBUG_ON(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ dir->i_nlink += h_dir->i_nlink - 2; ++ if (unlikely(h_dir->i_nlink < 2)) ++ dir->i_nlink += 2; ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ DEBUG_ON(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ dir->i_nlink -= h_dir->i_nlink - 2; ++ if (unlikely(h_dir->i_nlink < 2)) ++ dir->i_nlink -= 2; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 // comment ++struct file_operations { ++ struct module *owner; ++ loff_t (*llseek) (struct file *, loff_t, int); ++ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ++ ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); ++ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ++ ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); ++ int (*readdir) (struct file *, void *, filldir_t); ++ unsigned int (*poll) (struct file *, struct poll_table_struct *); ++ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); ++ long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); ++ long (*compat_ioctl) (struct file *, unsigned int, unsigned long); ++ int (*mmap) (struct file *, struct vm_area_struct *); ++ int (*open) (struct inode *, struct file *); ++ int (*flush) (struct file *); ++ int (*release) (struct inode *, struct file *); ++ int (*fsync) (struct file *, struct dentry *, int datasync); ++ int (*aio_fsync) (struct kiocb *, int datasync); ++ int (*fasync) (int, struct file *, int); ++ int (*lock) (struct file *, int, struct file_lock *); ++ ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ++ ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ++ ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); ++ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); ++ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); ++ int (*check_flags)(int); ++ int (*dir_notify)(struct file *file, unsigned long arg); ++ int (*flock) (struct file *, int, struct file_lock *); ++}; ++#endif ++ ++struct file_operations aufs_dir_fop = { ++ .read = generic_read_dir, ++ .readdir = aufs_readdir, ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush, ++ .fsync = aufs_fsync_dir, ++}; +diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h +new file mode 100755 +index 0000000..3ddf309 +--- /dev/null ++++ b/fs/aufs/dir.h +@@ -0,0 +1,125 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dir.h,v 1.18 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++#define filldir_ino_t u64 ++#else ++#define filldir_ino_t ino_t ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++#define AUFS_DEBLK_SIZE 512 // todo: changable ++#define AUFS_NHASH_SIZE 32 // todo: changable ++#if AUFS_DEBLK_SIZE < NAME_MAX || PAGE_SIZE < AUFS_DEBLK_SIZE ++#error invalid size AUFS_DEBLK_SIZE ++#endif ++ ++typedef char aufs_deblk_t[AUFS_DEBLK_SIZE]; ++ ++struct aufs_nhash { ++ struct hlist_head heads[AUFS_NHASH_SIZE]; ++}; ++ ++struct aufs_destr { ++ unsigned char len; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct aufs_dehstr { ++ struct hlist_node hash; ++ struct aufs_destr *str; ++}; ++ ++struct aufs_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ //caution: packed ++ struct aufs_destr de_str; ++} __attribute__ ((packed)); ++ ++struct aufs_wh { ++ struct hlist_node wh_hash; ++ aufs_bindex_t wh_bindex; ++ struct aufs_destr wh_str; ++} __attribute__ ((packed)); ++ ++union aufs_deblk_p { ++ unsigned char *p; ++ aufs_deblk_t *deblk; ++ struct aufs_de *de; ++}; ++ ++struct aufs_vdir { ++ aufs_deblk_t **vd_deblk; ++ int vd_nblk; ++ struct { ++ int i; ++ union aufs_deblk_p p; ++ } vd_last; ++ ++ unsigned long vd_version; ++ unsigned long vd_jiffy; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern struct file_operations aufs_dir_fop; ++int au_test_empty_lower(struct dentry *dentry); ++int test_empty(struct dentry *dentry, struct aufs_nhash *whlist); ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++ ++/* vdir.c */ ++struct aufs_nhash *nhash_new(gfp_t gfp); ++void nhash_del(struct aufs_nhash *nhash); ++void nhash_init(struct aufs_nhash *nhash); ++void nhash_move(struct aufs_nhash *dst, struct aufs_nhash *src); ++void nhash_fin(struct aufs_nhash *nhash); ++int is_longer_wh(struct aufs_nhash *whlist, aufs_bindex_t btgt, int limit); ++int test_known_wh(struct aufs_nhash *whlist, char *name, int namelen); ++int append_wh(struct aufs_nhash *whlist, char *name, int namelen, ++ aufs_bindex_t bindex); ++void free_vdir(struct aufs_vdir *vdir); ++int au_init_vdir(struct file *file); ++int au_fill_de(struct file *file, void *dirent, filldir_t filldir); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++unsigned int au_name_hash(const unsigned char *name, unsigned int len) ++{ ++ return (full_name_hash(name, len) % AUFS_NHASH_SIZE); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff --git a/fs/aufs/export.c b/fs/aufs/export.c +new file mode 100755 +index 0000000..7b1c6ac +--- /dev/null ++++ b/fs/aufs/export.c +@@ -0,0 +1,585 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: export.c,v 1.7 2007/05/14 03:38:24 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++extern struct export_operations export_op_default; ++#define CALL(ops, func) (((ops)->func) ? ((ops)->func) : export_op_default.func) ++#define is_anon(d) ((d)->d_flags & DCACHE_DISCONNECTED) ++ ++union conv { ++#if BITS_PER_LONG == 32 ++ __u32 a[1]; ++#else ++ __u32 a[2]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ u.a[0] = a[0]; ++#if BITS_PER_LONG == 64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ u.ino = ino; ++ a[0] = u.a[0]; ++#if BITS_PER_LONG == 64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++static void decode_br_id_sigen(__u32 a, aufs_bindex_t *br_id, ++ aufs_bindex_t *sigen) ++{ ++ BUILD_BUG_ON((sizeof(*br_id) + sizeof(*sigen)) > sizeof(a)); ++ *br_id = a >> 16; ++ DEBUG_ON(*br_id < 0); ++ *sigen = a; ++ DEBUG_ON(*sigen < 0); ++} ++ ++static __u32 encode_br_id_sigen(aufs_bindex_t br_id, aufs_bindex_t sigen) ++{ ++ DEBUG_ON(br_id < 0 || sigen < 0); ++ return (br_id << 16) | sigen; ++} ++ ++/* NFS file handle */ ++enum { ++ /* support 64bit inode number */ ++ /* but untested */ ++ Fh_br_id_sigen, ++ Fh_ino1, ++#if BITS_PER_LONG == 64 ++ Fh_ino2, ++#endif ++ Fh_dir_ino1, ++#if BITS_PER_LONG == 64 ++ Fh_dir_ino2, ++#endif ++ Fh_h_ino1, ++#if BITS_PER_LONG == 64 ++ Fh_h_ino2, ++#endif ++ Fh_h_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1, ++ Fh_h_ino = Fh_h_ino1, ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ LKTRTrace("i%lu, diri%lu\n", ino, dir_ino); ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (unlikely(!inode)) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ if (unlikely(is_bad_inode(inode))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!S_ISDIR(inode->i_mode)) { ++ struct dentry *d; ++ spin_lock(&dcache_lock); ++ list_for_each_entry(d, &inode->i_dentry, d_alias) ++ if (!is_anon(d) ++ && d->d_parent->d_inode->i_ino == dir_ino) { ++ dentry = dget_locked(d); ++ break; ++ } ++ spin_unlock(&dcache_lock); ++ } else { ++ dentry = d_find_alias(inode); ++ if (dentry ++ && !is_anon(dentry) ++ && dentry->d_parent->d_inode->i_ino == dir_ino) ++ goto out_iput; /* success */ ++ ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++ out_iput: ++ iput(inode); ++ out: ++ TraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct find_name_by_ino { ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset, ++ filldir_ino_t ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = arg; ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *parent; ++ struct inode *dir; ++ struct find_name_by_ino arg; ++ struct file *file; ++ int err; ++ ++ LKTRTrace("i%lu, diri%lu\n", ino, dir_ino); ++ ++ dentry = NULL; ++ dir = ilookup(sb, dir_ino); ++ if (unlikely(!dir)) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ if (unlikely(is_bad_inode(dir))) ++ goto out_iput; ++ ++ dentry = NULL; ++ parent = d_find_alias(dir); ++ if (parent) { ++ if (unlikely(is_anon(parent))) { ++ dput(parent); ++ goto out_iput; ++ } ++ } else ++ goto out_iput; ++ ++ file = dentry_open(parent, NULL, au_dir_roflags); ++ dentry = (void*)file; ++ if (IS_ERR(file)) ++ goto out_iput; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = __getname(); ++ if (unlikely(!arg.name)) ++ goto out_fput; ++ arg.ino = ino; ++ arg.found = 0; ++ ++ do { ++ arg.called = 0; ++ //smp_mb(); ++ err = vfsub_readdir(file, find_name_by_ino, &arg, /*dlgt*/0); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (arg.found) { ++ /* do not call lkup_one(), nor dlgt */ ++ i_lock(dir); ++ dentry = lookup_one_len(arg.name, parent, arg.namelen); ++ i_unlock(dir); ++ TraceErrPtr(dentry); ++ } ++ ++ //out_putname: ++ __putname(arg.name); ++ out_fput: ++ fput(file); ++ out_iput: ++ iput(dir); ++ out: ++ TraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct append_name { ++ int found, called, len; ++ char *h_path; ++ ino_t h_ino; ++}; ++ ++static int append_name(void *arg, const char *name, int len, loff_t pos, ++ filldir_ino_t ino, unsigned int d_type) ++{ ++ struct append_name *a = arg; ++ char *p; ++ ++ a->called++; ++ if (ino != a->h_ino) ++ return 0; ++ ++ DEBUG_ON(len == 1 && *name == '.'); ++ DEBUG_ON(len == 2 && name[0] == '.' && name[1] == '.'); ++ a->len = strlen(a->h_path); ++ memmove(a->h_path - a->len - 1, a->h_path, a->len); ++ a->h_path -= a->len + 1; ++ p = a->h_path + a->len; ++ *p++ = '/'; ++ memcpy(p, name, a->len); ++ a->len += 1 + len; ++ a->found++; ++ return 1; ++} ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static struct dentry* ++decode_by_path(struct super_block *sb, aufs_bindex_t bindex, __u32 *fh, ++ int fh_len, void *context) ++{ ++ struct dentry *dentry, *h_parent, *root, *h_root; ++ struct super_block *h_sb; ++ char *path, *p; ++ struct vfsmount *h_mnt; ++ struct append_name arg; ++ int len, err; ++ struct file *h_file; ++ struct nameidata nd; ++ struct aufs_branch *br; ++ ++ LKTRTrace("b%d\n", bindex); ++ SiMustAnyLock(sb); ++ ++ br = stobr(sb, bindex); ++ //br_get(br); ++ h_mnt = br->br_mnt; ++ h_sb = h_mnt->mnt_sb; ++ LKTRTrace("%s, h_decode_fh\n", au_sbtype(h_sb)); ++ h_parent = CALL(h_sb->s_export_op, decode_fh) ++ (h_sb, fh + Fh_tail, fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ Warn1("%s decode_fh failed\n", au_sbtype(h_sb)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(is_anon(h_parent))) { ++ Warn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ dput(h_parent); ++ goto out; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ path = __getname(); ++ if (unlikely(!path)) { ++ dput(h_parent); ++ goto out; ++ } ++ ++ root = sb->s_root; ++ di_read_lock_parent(root, !AUFS_I_RLOCK); ++ h_root = au_h_dptr_i(root, bindex); ++ di_read_unlock(root, !AUFS_I_RLOCK); ++ arg.h_path = d_path(h_root, h_mnt, path, PATH_MAX); ++ dentry = (void*)arg.h_path; ++ if (unlikely(!arg.h_path || IS_ERR(arg.h_path))) ++ goto out_putname; ++ len = strlen(arg.h_path); ++ arg.h_path = d_path(h_parent, h_mnt, path, PATH_MAX); ++ dentry = (void*)arg.h_path; ++ if (unlikely(!arg.h_path || IS_ERR(arg.h_path))) ++ goto out_putname; ++ LKTRTrace("%s\n", arg.h_path); ++ if (len != 1) ++ arg.h_path += len; ++ LKTRTrace("%s\n", arg.h_path); ++ ++ /* cf. fs/exportfs/expfs.c */ ++ h_file = dentry_open(h_parent, NULL, au_dir_roflags); ++ dentry = (void*)h_file; ++ if (IS_ERR(h_file)) ++ goto out_putname; ++ ++ arg.found = 0; ++ arg.h_ino = decode_ino(fh + Fh_h_ino); ++ do { ++ arg.called = 0; ++ err = vfsub_readdir(h_file, append_name, &arg, /*dlgt*/0); ++ } while (!err && !arg.found && arg.called); ++ LKTRTrace("%s, %d\n", arg.h_path, arg.len); ++ ++ p = d_path(root, stosi(sb)->si_mnt, path, PATH_MAX - arg.len - 2); ++ dentry = (void*)p; ++ if (unlikely(!p || IS_ERR(p))) ++ goto out_fput; ++ p[strlen(p)] = '/'; ++ LKTRTrace("%s\n", p); ++ ++ err = path_lookup(p, LOOKUP_FOLLOW, &nd); ++ dentry = ERR_PTR(err); ++ if (!err) { ++ dentry = dget(nd.dentry); ++ if (unlikely(is_anon(dentry))) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ path_release(&nd); ++ } ++ ++ out_fput: ++ fput(h_file); ++ out_putname: ++ __putname(path); ++ out: ++ //br_put(br); ++ TraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry* ++aufs_decode_fh(struct super_block *sb, __u32 *fh, int fh_len, int fh_type, ++ int (*acceptable)(void *context, struct dentry *de), ++ void *context) ++{ ++ struct dentry *dentry; ++ ino_t ino, dir_ino; ++ aufs_bindex_t bindex, br_id, sigen_v; ++ struct inode *inode, *h_inode; ++ ++ //au_debug_on(); ++ LKTRTrace("%d, fh{i%u, br_id_sigen 0x%x, hi%u}\n", ++ fh_type, fh[Fh_ino], fh[Fh_br_id_sigen], fh[Fh_h_ino]); ++ DEBUG_ON(fh_len < Fh_tail); ++ ++ si_read_lock(sb); ++ lockdep_off(); ++ ++ /* branch id may be wrapped around */ ++ dentry = ERR_PTR(-ESTALE); ++ decode_br_id_sigen(fh[Fh_br_id_sigen], &br_id, &sigen_v); ++ bindex = find_brindex(sb, br_id); ++ if (unlikely(bindex < 0 || au_sigen(sb) < sigen_v)) ++ goto out; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ dentry = decode_by_dir_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, bindex, fh, fh_len, context); ++ if (IS_ERR(dentry)) ++ goto out; ++ if (unlikely(!dentry)) ++ goto out_stale; ++ if (unlikely(dentry->d_inode->i_ino != ino)) ++ goto out_dput; ++ ++ accept: ++ inode = dentry->d_inode; ++ h_inode = NULL; ++ ii_read_lock_child(inode); ++ if (ibstart(inode) <= bindex && bindex <= ibend(inode)) ++ h_inode = au_h_iptr_i(inode, bindex); ++ ii_read_unlock(inode); ++ if (h_inode ++ && h_inode->i_generation == fh[Fh_h_igen] ++ && acceptable(context, dentry)) ++ goto out; /* success */ ++ out_dput: ++ dput(dentry); ++ out_stale: ++ dentry = ERR_PTR(-ESTALE); ++ out: ++ lockdep_on(); ++ si_read_unlock(sb); ++ TraceErrPtr(dentry); ++ //au_debug_off(); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, ++ int connectable) ++{ ++ int err; ++ struct super_block *sb, *h_sb; ++ struct inode *inode, *h_inode, *dir; ++ aufs_bindex_t bindex; ++ union conv u; ++ struct dentry *parent, *h_parent; ++ ++ //au_debug_on(); ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ LKTRTrace("%.*s, max %d, conn %d\n", ++ DLNPair(dentry), *max_len, connectable); ++ DEBUG_ON(is_anon(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode); ++ parent = dentry->d_parent; ++ DEBUG_ON(is_anon(parent)); ++ ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ Warn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ di_read_lock_child(dentry, AUFS_I_RLOCK); ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_flag_test(sb, AuFlag_XINO))) ++ Warn1("NFS-exporting requires xino\n"); ++#if 0 ++ if (unlikely(au_flag_test(sb, AuFlag_UDBA_INOTIFY))) ++ Warn1("udba=inotify is not recommended when exporting\n"); ++#endif ++#endif ++ ++ err = -EPERM; ++ bindex = ibstart(inode); ++ h_sb = sbr_sb(sb, bindex); ++ if (unlikely(!h_sb->s_export_op)) { ++ Err1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_unlock; ++ } ++ ++#if 0 //def CONFIG_AUFS_ROBR ++ if (unlikely(SB_AUFS(h_sb))) { ++ Err1("aufs branch is not supported\n"); ++ goto out_unlock; ++ } ++#endif ++ ++ /* doesn't support pseudo-link */ ++ if (unlikely(bindex < dbstart(dentry) ++ || dbend(dentry) < bindex ++ || !au_h_dptr_i(dentry, bindex))) { ++ Err("%.*s/%.*s, b%d, pseudo-link?\n", ++ DLNPair(dentry->d_parent), DLNPair(dentry), bindex); ++ goto out_unlock; ++ } ++ ++ fh[Fh_br_id_sigen] = encode_br_id_sigen(sbr_id(sb, bindex), ++ au_sigen(sb)); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ dir = parent->d_inode; ++ encode_ino(fh + Fh_dir_ino, dir->i_ino); ++ h_inode = au_h_iptr(inode); ++ encode_ino(fh + Fh_h_ino, h_inode->i_ino); ++ fh[Fh_h_igen] = h_inode->i_generation; ++ ++ /* it should be set at exporting time */ ++ if (unlikely(!h_sb->s_export_op->find_exported_dentry)) { ++ Warn("set default find_exported_dentry for %s\n", ++ au_sbtype(h_sb)); ++ h_sb->s_export_op->find_exported_dentry = find_exported_dentry; ++ } ++ ++ *max_len -= Fh_tail; ++ //LKTRTrace("Fh_tail %d, max_len %d\n", Fh_tail, *max_len); ++ h_parent = au_h_dptr_i(parent, bindex); ++ DEBUG_ON(is_anon(h_parent)); ++ err = fh[Fh_h_type] = CALL(h_sb->s_export_op, encode_fh) ++ (h_parent, fh + Fh_tail, max_len, connectable); ++ *max_len += Fh_tail; ++ if (err != 255) ++ err = 2; //?? ++ else ++ Warn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++ out_unlock: ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ aufs_read_unlock(dentry, AUFS_I_RLOCK); ++ out: ++ TraceErr(err); ++ //au_debug_off(); ++ if (unlikely(err < 0)) ++ err = 255; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 ++struct export_operations { ++ struct dentry *(*decode_fh)(struct super_block *sb, __u32 *fh, int fh_len, int fh_type, ++ int (*acceptable)(void *context, struct dentry *de), ++ void *context); ++ int (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len, ++ int connectable); ++ ++ /* the following are only called from the filesystem itself */ ++ int (*get_name)(struct dentry *parent, char *name, ++ struct dentry *child); ++ struct dentry * (*get_parent)(struct dentry *child); ++ struct dentry * (*get_dentry)(struct super_block *sb, void *inump); ++ ++ /* This is set by the exporting module to a standard helper */ ++ struct dentry * (*find_exported_dentry)( ++ struct super_block *sb, void *obj, void *parent, ++ int (*acceptable)(void *context, struct dentry *de), ++ void *context); ++}; ++#endif ++ ++struct export_operations aufs_export_op = { ++ .decode_fh = aufs_decode_fh, ++ .encode_fh = aufs_encode_fh ++}; +diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c +new file mode 100755 +index 0000000..3cd1081 +--- /dev/null ++++ b/fs/aufs/f_op.c +@@ -0,0 +1,684 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: f_op.c,v 1.27 2007/05/14 03:38:24 sfjro Exp $ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* common function to regular file and dir */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++#define FlushArgs hidden_file, id ++int aufs_flush(struct file *file, fl_owner_t id) ++#else ++#define FlushArgs hidden_file ++int aufs_flush(struct file *file) ++#endif ++{ ++ int err; ++ struct dentry *dentry; ++ aufs_bindex_t bindex, bend; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ ++ // aufs_read_lock_file() ++ si_read_lock(dentry->d_sb); ++ fi_read_lock(file); ++ di_read_lock_child(dentry, !AUFS_I_RLOCK); ++ ++ err = 0; ++ bend = fbend(file); ++ for (bindex = fbstart(file); !err && bindex <= bend; bindex++) { ++ struct file *hidden_file; ++ hidden_file = au_h_fptr_i(file, bindex); ++ if (hidden_file && hidden_file->f_op ++ && hidden_file->f_op->flush) ++ err = hidden_file->f_op->flush(FlushArgs); ++ } ++ ++ di_read_unlock(dentry, !AUFS_I_RLOCK); ++ fi_read_unlock(file); ++ si_read_unlock(dentry->d_sb); ++ TraceErr(err); ++ return err; ++} ++#undef FlushArgs ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int do_open_nondir(struct file *file, int flags) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct file *hidden_file; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct aufs_finfo *finfo; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, flags 0%o\n", DLNPair(dentry), flags); ++ FiMustWriteLock(file); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode || S_ISDIR(inode->i_mode)); ++ ++ err = 0; ++ finfo = ftofi(file); ++ finfo->fi_h_vm_ops = NULL; ++ sb = dentry->d_sb; ++ bindex = dbstart(dentry); ++ DEBUG_ON(!au_h_dptr(dentry)->d_inode); ++ /* O_TRUNC is processed already */ ++ BUG_ON(test_ro(sb, bindex, inode) && (flags & O_TRUNC)); ++ ++ hidden_file = hidden_open(dentry, bindex, flags); ++ //if (LktrCond) {fput(hidden_file); br_put(stobr(dentry->d_sb, bindex)); ++ //hidden_file = ERR_PTR(-1);} ++ if (!IS_ERR(hidden_file)) { ++ set_fbstart(file, bindex); ++ set_fbend(file, bindex); ++ set_h_fptr(file, bindex, hidden_file); ++ return 0; /* success */ ++ } ++ err = PTR_ERR(hidden_file); ++ TraceErr(err); ++ return err; ++} ++ ++static int aufs_open_nondir(struct inode *inode, struct file *file) ++{ ++ return au_do_open(inode, file, do_open_nondir); ++} ++ ++static int aufs_release_nondir(struct inode *inode, struct file *file) ++{ ++ struct super_block *sb = file->f_dentry->d_sb; ++ ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(file->f_dentry)); ++ ++ si_read_lock(sb); ++ au_fin_finfo(file); ++ si_read_unlock(sb); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ struct dentry *dentry; ++ struct file *hidden_file; ++ struct super_block *sb; ++ struct inode *h_inode; ++ int dlgt; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(dentry), (unsigned long)count, *ppos); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/0, ++ /*locked*/0); ++ //if (LktrCond) {fi_read_unlock(file); err = -1;} ++ if (unlikely(err)) ++ goto out; ++ ++ /* support LSM and notify */ ++ dlgt = need_dlgt(sb); ++ hidden_file = au_h_fptr(file); ++ h_inode = hidden_file->f_dentry->d_inode; ++ if (!au_flag_test(sb, AuFlag_UDBA_INOTIFY)) ++ err = vfsub_read_u(hidden_file, buf, count, ppos, dlgt); ++ else { ++ struct inode *dir = dentry->d_parent->d_inode, ++ *h_dir = hidden_file->f_dentry->d_parent->d_inode; ++ aufs_bindex_t bstart = fbstart(file); ++ hdir_lock(h_dir, dir, bstart); ++ err = vfsub_read_u(hidden_file, buf, count, ppos, dlgt); ++ hdir_unlock(h_dir, dir, bstart); ++ } ++ memcpy(&file->f_ra, &hidden_file->f_ra, sizeof(file->f_ra)); //?? ++ dentry->d_inode->i_atime = hidden_file->f_dentry->d_inode->i_atime; ++ ++ fi_read_unlock(file); ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++static ssize_t aufs_write(struct file *file, const char __user *__buf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *hidden_file; ++ char __user *buf = (char __user*)__buf; ++ struct inode *h_inode; ++ int dlgt; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(dentry), (unsigned long)count, *ppos); ++ ++ inode = dentry->d_inode; ++ i_lock(inode); ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/1, ++ /*locked*/1); ++ //if (LktrCond) {fi_write_unlock(file); err = -1;} ++ if (unlikely(err)) ++ goto out; ++ err = au_ready_to_write(file, -1); ++ //if (LktrCond) err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* support LSM and notify */ ++ dlgt = need_dlgt(sb); ++ hidden_file = au_h_fptr(file); ++ h_inode = hidden_file->f_dentry->d_inode; ++ if (!au_flag_test(sb, AuFlag_UDBA_INOTIFY)) ++ err = vfsub_write_u(hidden_file, buf, count, ppos, dlgt); ++ else { ++ struct inode *dir = dentry->d_parent->d_inode, ++ *h_dir = hidden_file->f_dentry->d_parent->d_inode; ++ aufs_bindex_t bstart = fbstart(file); ++ hdir_lock(h_dir, dir, bstart); ++ err = vfsub_write_u(hidden_file, buf, count, ppos, dlgt); ++ hdir_unlock(h_dir, dir, bstart); ++ } ++ ii_write_lock_child(inode); ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ ++ out_unlock: ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ i_unlock(inode); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 //def CONFIG_AUFS_ROBR ++struct lvma { ++ struct list_head list; ++ struct vm_area_struct *vma; ++}; ++ ++static struct file *safe_file(struct vm_area_struct *vma) ++{ ++ struct file *file = vma->vm_file; ++ struct super_block *sb = file->f_dentry->d_sb; ++ struct lvma *lvma, *entry; ++ struct aufs_sbinfo *sbinfo; ++ int found, warn; ++ ++ TraceEnter(); ++ DEBUG_ON(!SB_AUFS(sb)); ++ ++ warn = 0; ++ found = 0; ++ sbinfo = stosi(sb); ++ spin_lock(&sbinfo->si_lvma_lock); ++ list_for_each_entry(entry, &sbinfo->si_lvma, list) { ++ found = (entry->vma == vma); ++ if (unlikely(found)) ++ break; ++ } ++ if (!found) { ++ lvma = kmalloc(sizeof(*lvma), GFP_ATOMIC); ++ if (lvma) { ++ lvma->vma = vma; ++ list_add(&lvma->list, &sbinfo->si_lvma); ++ } else { ++ warn = 1; ++ file = NULL; ++ } ++ } else ++ file = NULL; ++ spin_unlock(&sbinfo->si_lvma_lock); ++ ++ if (unlikely(warn)) ++ Warn1("no memory for lvma\n"); ++ return file; ++} ++ ++static void reset_file(struct vm_area_struct *vma, struct file *file) ++{ ++ struct super_block *sb = file->f_dentry->d_sb; ++ struct lvma *entry, *found; ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ DEBUG_ON(!SB_AUFS(sb)); ++ ++ vma->vm_file = file; ++ ++ found = NULL; ++ sbinfo = stosi(sb); ++ spin_lock(&sbinfo->si_lvma_lock); ++ list_for_each_entry(entry, &sbinfo->si_lvma, list) ++ if (entry->vma == vma){ ++ found = entry; ++ break; ++ } ++ DEBUG_ON(!found); ++ list_del(&found->list); ++ spin_unlock(&sbinfo->si_lvma_lock); ++ kfree(found); ++} ++ ++#else ++ ++static struct file *safe_file(struct vm_area_struct *vma) ++{ ++ struct file *file; ++ ++ file = vma->vm_file; ++ if (file->private_data && au_is_aufs(file->f_dentry->d_sb)) ++ return file; ++ return NULL; ++} ++ ++static void reset_file(struct vm_area_struct *vma, struct file *file) ++{ ++ vma->vm_file = file; ++ smp_mb(); ++} ++#endif /* CONFIG_AUFS_ROBR */ ++ ++static struct page *aufs_nopage(struct vm_area_struct *vma, unsigned long addr, ++ int *type) ++{ ++ struct page *page; ++ struct dentry *dentry; ++ struct file *file, *hidden_file; ++ struct inode *inode; ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ struct aufs_finfo *finfo; ++ ++ TraceEnter(); ++ DEBUG_ON(!vma || !vma->vm_file); ++ wait_event(wq, (file = safe_file(vma))); ++ DEBUG_ON(!au_is_aufs(file->f_dentry->d_sb)); ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, addr %lx\n", DLNPair(dentry), addr); ++ inode = dentry->d_inode; ++ DEBUG_ON(!S_ISREG(inode->i_mode)); ++ ++ // do not revalidate, nor lock ++ finfo = ftofi(file); ++ hidden_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; ++ DEBUG_ON(!hidden_file || !au_is_mmapped(file)); ++ vma->vm_file = hidden_file; ++ //smp_mb(); ++ page = finfo->fi_h_vm_ops->nopage(vma, addr, type); ++ reset_file(vma, file); ++#if 0 //def CONFIG_SMP ++ //wake_up_nr(&wq, online_cpu - 1); ++ wake_up_all(&wq); ++#else ++ wake_up(&wq); ++#endif ++ if (!IS_ERR(page)) { ++ //page->mapping = file->f_mapping; ++ //get_page(page); ++ //file->f_mapping = hidden_file->f_mapping; ++ //touch_atime(NULL, dentry); ++ //inode->i_atime = hidden_file->f_dentry->d_inode->i_atime; ++ } ++ TraceErrPtr(page); ++ return page; ++} ++ ++static int aufs_populate(struct vm_area_struct *vma, unsigned long addr, ++ unsigned long len, pgprot_t prot, unsigned long pgoff, ++ int nonblock) ++{ ++ Err("please report me this application\n"); ++ BUG(); ++ return ftofi(vma->vm_file)->fi_h_vm_ops->populate ++ (vma, addr, len, prot, pgoff, nonblock); ++} ++ ++static struct vm_operations_struct aufs_vm_ops = { ++ //.open = aufs_vmaopen, ++ //.close = aufs_vmaclose, ++ .nopage = aufs_nopage, ++ .populate = aufs_populate, ++ //page_mkwrite(struct vm_area_struct *vma, struct page *page) ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err, wlock, mmapped; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct file *h_file; ++ struct vm_operations_struct *vm_ops; ++ unsigned long flags; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, %lx, len %lu\n", ++ DLNPair(dentry), vma->vm_start, vma->vm_end - vma->vm_start); ++ DEBUG_ON(!S_ISREG(dentry->d_inode->i_mode)); ++ DEBUG_ON(down_write_trylock(&vma->vm_mm->mmap_sem)); ++ ++ mmapped = au_is_mmapped(file); ++ wlock = 0; ++ if (file->f_mode & FMODE_WRITE) { ++ flags = VM_SHARED | VM_WRITE; ++ wlock = ((flags & vma->vm_flags) == flags); ++ } ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, ++ wlock | !mmapped, /*locked*/0); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ ++ if (wlock) { ++ err = au_ready_to_write(file, -1); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ h_file = au_h_fptr(file); ++ vm_ops = ftofi(file)->fi_h_vm_ops; ++ if (unlikely(!mmapped)) { ++ // nfs uses some locks ++ lockdep_off(); ++ err = h_file->f_op->mmap(h_file, vma); ++ lockdep_on(); ++ if (unlikely(err)) ++ goto out_unlock; ++ vm_ops = vma->vm_ops; ++ DEBUG_ON(!vm_ops); ++ err = do_munmap(current->mm, vma->vm_start, ++ vma->vm_end - vma->vm_start); ++ if (unlikely(err)) { ++ IOErr("failed internal unmapping %.*s, %d\n", ++ DLNPair(h_file->f_dentry), err); ++ err = -EIO; ++ goto out_unlock; ++ } ++ } ++ DEBUG_ON(!vm_ops); ++ ++ err = generic_file_mmap(file, vma); ++ if (!err) { ++ file_accessed(h_file); ++ dentry->d_inode->i_atime = h_file->f_dentry->d_inode->i_atime; ++ vma->vm_ops = &aufs_vm_ops; ++ if (unlikely(!mmapped)) ++ ftofi(file)->fi_h_vm_ops = vm_ops; ++ } ++ ++ out_unlock: ++ if (!wlock && mmapped) ++ fi_read_unlock(file); ++ else ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++// todo: try do_sendfile() in fs/read_write.c ++static ssize_t aufs_sendfile(struct file *file, loff_t *ppos, ++ size_t count, read_actor_t actor, void *target) ++{ ++ ssize_t err; ++ struct file *h_file; ++ const char c = current->comm[4]; ++ /* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++ const int loopback = (current->mm == NULL ++ && '0' <= c && c <= '9' ++ && strncmp(current->comm, "loop", 4) == 0); ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld, cnt %lu, loopback %d\n", ++ DLNPair(dentry), *ppos, (unsigned long)count, loopback); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/0, ++ /*locked*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -EINVAL; ++ h_file = au_h_fptr(file); ++ if (h_file->f_op && h_file->f_op->sendfile) { ++ if (/* unlikely */(loopback)) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); //?? ++ } ++ // nfs uses some locks ++ lockdep_off(); ++ err = h_file->f_op->sendfile ++ (h_file, ppos, count, actor, target); ++ lockdep_on(); ++ dentry->d_inode->i_atime = h_file->f_dentry->d_inode->i_atime; ++ } ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* copied from linux/fs/select.h, must match */ ++#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) ++ ++static unsigned int aufs_poll(struct file *file, poll_table *wait) ++{ ++ unsigned int mask; ++ struct file *hidden_file; ++ int err; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, wait %p\n", DLNPair(dentry), wait); ++ DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode)); ++ ++ /* We should pretend an error happend. */ ++ mask = POLLERR /* | POLLIN | POLLOUT */; ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/0, ++ /*locked*/0); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ ++ /* it is not an error of hidden_file has no operation */ ++ mask = DEFAULT_POLLMASK; ++ hidden_file = au_h_fptr(file); ++ if (hidden_file->f_op && hidden_file->f_op->poll) ++ mask = hidden_file->f_op->poll(hidden_file, wait); ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ TraceErr((int)mask); ++ return mask; ++} ++ ++static int aufs_fsync_nondir(struct file *file, struct dentry *dentry, ++ int datasync) ++{ ++ int err, my_lock; ++ struct inode *inode; ++ struct file *hidden_file; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), datasync); ++ inode = dentry->d_inode; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) ++ IMustLock(inode); ++ my_lock = 0; ++#else ++ /* before 2.6.17, ++ * msync(2) calls me without locking i_sem/i_mutex, but fsync(2). ++ */ ++ my_lock = !i_trylock(inode); ++#endif ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = 0; //-EBADF; // posix? ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/1, ++ /*locked*/1); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ err = au_ready_to_write(file, -1); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -EINVAL; ++ hidden_file = au_h_fptr(file); ++ if (hidden_file->f_op && hidden_file->f_op->fsync) { ++ // todo: apparmor thread? ++ //file->f_mapping->host->i_mutex ++ ii_write_lock_child(inode); ++ hi_lock_child(hidden_file->f_dentry->d_inode); ++ err = hidden_file->f_op->fsync ++ (hidden_file, hidden_file->f_dentry, datasync); ++ //err = -1; ++ au_cpup_attr_timesizes(inode); ++ i_unlock(hidden_file->f_dentry->d_inode); ++ ii_write_unlock(inode); ++ } ++ ++ out_unlock: ++ fi_write_unlock(file); ++ out: ++ if (unlikely(my_lock)) ++ i_unlock(inode); ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *hidden_file; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), flag); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/0, ++ /*locked*/0); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ ++ hidden_file = au_h_fptr(file); ++ if (hidden_file->f_op && hidden_file->f_op->fasync) ++ err = hidden_file->f_op->fasync(fd, hidden_file, flag); ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 // comment ++struct file_operations { ++ struct module *owner; ++ loff_t (*llseek) (struct file *, loff_t, int); ++ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ++ ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); ++ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ++ ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); ++ int (*readdir) (struct file *, void *, filldir_t); ++ unsigned int (*poll) (struct file *, struct poll_table_struct *); ++ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); ++ long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); ++ long (*compat_ioctl) (struct file *, unsigned int, unsigned long); ++ int (*mmap) (struct file *, struct vm_area_struct *); ++ int (*open) (struct inode *, struct file *); ++ int (*flush) (struct file *); ++ int (*release) (struct inode *, struct file *); ++ int (*fsync) (struct file *, struct dentry *, int datasync); ++ int (*aio_fsync) (struct kiocb *, int datasync); ++ int (*fasync) (int, struct file *, int); ++ int (*lock) (struct file *, int, struct file_lock *); ++ ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ++ ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ++ ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); ++ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); ++ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); ++ int (*check_flags)(int); ++ int (*dir_notify)(struct file *file, unsigned long arg); ++ int (*flock) (struct file *, int, struct file_lock *); ++}; ++#endif ++ ++struct file_operations aufs_file_fop = { ++ .read = aufs_read, ++ .write = aufs_write, ++ .poll = aufs_poll, ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ .fasync = aufs_fasync, ++ .sendfile = aufs_sendfile, ++}; +diff --git a/fs/aufs/file.c b/fs/aufs/file.c +new file mode 100755 +index 0000000..857a4e8 +--- /dev/null ++++ b/fs/aufs/file.c +@@ -0,0 +1,832 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: file.c,v 1.42 2007/05/14 03:39:09 sfjro Exp $ */ ++ ++//#include ++#include ++//#include ++//#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *hidden_open(struct dentry *dentry, aufs_bindex_t bindex, int flags) ++{ ++ struct dentry *hidden_dentry; ++ struct inode *hidden_inode; ++ struct super_block *sb; ++ struct vfsmount *hidden_mnt; ++ struct file *hidden_file; ++ struct aufs_branch *br; ++ loff_t old_size; ++ int udba; ++ ++ LKTRTrace("%.*s, b%d, flags 0%o\n", DLNPair(dentry), bindex, flags); ++ DEBUG_ON(!dentry); ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ DEBUG_ON(!hidden_dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode); ++ ++ sb = dentry->d_sb; ++ udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY); ++ if (unlikely(udba)) { ++ // test here? ++ } ++ ++ br = stobr(sb, bindex); ++ br_get(br); ++ /* drop flags for writing */ ++ if (test_ro(sb, bindex, dentry->d_inode)) ++ flags = au_file_roflags(flags); ++ flags &= ~O_CREAT; ++ spin_lock(&hidden_inode->i_lock); ++ old_size = i_size_read(hidden_inode); ++ spin_unlock(&hidden_inode->i_lock); ++ ++ //DbgSleep(3); ++ ++ dget(hidden_dentry); ++ hidden_mnt = mntget(br->br_mnt); ++ hidden_file = dentry_open(hidden_dentry, hidden_mnt, flags); ++ //if (LktrCond) {fput(hidden_file); hidden_file = ERR_PTR(-1);} ++ ++ if (!IS_ERR(hidden_file)) { ++#if 0 // remove this ++ if (/* old_size && */ (flags & O_TRUNC)) { ++ au_direval_dec(dentry); ++ if (!IS_ROOT(dentry)) ++ au_direval_dec(dentry->d_parent); ++ } ++#endif ++ return hidden_file; ++ } ++ ++ br_put(br); ++ TraceErrPtr(hidden_file); ++ return hidden_file; ++} ++ ++static int do_coo(struct dentry *dentry, aufs_bindex_t bstart) ++{ ++ int err; ++ struct dentry *parent, *h_parent, *h_dentry; ++ aufs_bindex_t bcpup; ++ struct inode *h_dir, *h_inode, *dir; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(IS_ROOT(dentry)); ++ DiMustWriteLock(dentry); ++ ++ parent = dentry->d_parent; // dget_parent() ++ di_write_lock_parent(parent); ++ bcpup = err = find_rw_parent_br(dentry, bstart); ++ //bcpup = err = find_rw_br(sb, bstart); ++ if (unlikely(err < 0)) { ++ err = 0; // stop copyup, it is not an error ++ goto out; ++ } ++ err = 0; ++ ++ h_parent = au_h_dptr_i(parent, bcpup); ++ if (!h_parent) { ++ err = cpup_dirs(dentry, bcpup, NULL); ++ if (unlikely(err)) ++ goto out; ++ h_parent = au_h_dptr_i(parent, bcpup); ++ } ++ ++ h_dir = h_parent->d_inode; ++ h_dentry = au_h_dptr_i(dentry, bstart); ++ h_inode = h_dentry->d_inode; ++ dir = parent->d_inode; ++ hdir_lock(h_dir, dir, bcpup); ++ hi_lock_child(h_inode); ++ DEBUG_ON(au_h_dptr_i(dentry, bcpup)); ++ err = sio_cpup_simple(dentry, bcpup, -1, ++ au_flags_cpup(CPUP_DTIME, parent)); ++ TraceErr(err); ++ i_unlock(h_inode); ++ hdir_unlock(h_dir, dir, bcpup); ++ ++ out: ++ di_write_unlock(parent); ++ TraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct inode *inode, struct file *file, ++ int (*open)(struct file *file, int flags)) ++{ ++ int err, coo; ++ struct dentry *dentry; ++ struct super_block *sb; ++ aufs_bindex_t bstart; ++ struct inode *h_dir, *dir; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(dentry)); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ coo = 0; ++#if 0 ++ switch (au_flag_test_coo(sb)) { ++ case AuFlag_COO_LEAF: ++ coo = !S_ISDIR(inode->i_mode); ++ break; ++ case AuFlag_COO_ALL: ++ coo = 1; ++ break; ++ } ++#endif ++ err = au_init_finfo(file); ++ //if (LktrCond) {fi_write_unlock(file); fin_finfo(file); err = -1;} ++ if (unlikely(err)) ++ goto out; ++ ++ if (!coo) { ++ di_read_lock_child(dentry, AUFS_I_RLOCK); ++ bstart = dbstart(dentry); ++ } else { ++ di_write_lock_child(dentry); ++ bstart = dbstart(dentry); ++ if (test_ro(sb, bstart, dentry->d_inode)) { ++ err = do_coo(dentry, bstart); ++ if (err) { ++ di_write_unlock(dentry); ++ goto out_finfo; ++ } ++ bstart = dbstart(dentry); ++ } ++ di_downgrade_lock(dentry, AUFS_I_RLOCK); ++ } ++ ++ // todo: remove this extra locks ++ dir = dentry->d_parent->d_inode; ++ if (!IS_ROOT(dentry)) ++ ii_read_lock_parent(dir); ++ h_dir = au_h_iptr_i(dir, bstart); ++ hdir_lock(h_dir, dir, bstart); ++ err = open(file, file->f_flags); ++ //if (LktrCond) err = -1; ++ hdir_unlock(h_dir, dir, bstart); ++ if (!IS_ROOT(dentry)) ++ ii_read_unlock(dir); ++ di_read_unlock(dentry, AUFS_I_RLOCK); ++ ++ out_finfo: ++ fi_write_unlock(file); ++ if (unlikely(err)) ++ au_fin_finfo(file); ++ //DbgFile(file); ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ struct dentry *dentry; ++ aufs_bindex_t bstart, bindex, bend; ++ struct file *hidden_file, *h_file_tmp; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode) ++ || !au_h_dptr(dentry)->d_inode); ++ bstart = dbstart(dentry); ++ ++ h_file_tmp = NULL; ++ if (fbstart(file) == bstart) { ++ hidden_file = au_h_fptr(file); ++ if (file->f_mode == hidden_file->f_mode) ++ return 0; /* success */ ++ h_file_tmp = hidden_file; ++ get_file(h_file_tmp); ++ set_h_fptr(file, bstart, NULL); ++ } ++ DEBUG_ON(fbstart(file) < bstart ++ || ftofi(file)->fi_hfile[0 + bstart].hf_file); ++ ++ hidden_file = hidden_open(dentry, bstart, file->f_flags & ~O_TRUNC); ++ //if (LktrCond) {fput(hidden_file); br_put(stobr(dentry->d_sb, bstart)); ++ //hidden_file = ERR_PTR(-1);} ++ err = PTR_ERR(hidden_file); ++ if (IS_ERR(hidden_file)) ++ goto out; // close all? ++ err = 0; ++ //cpup_file_flags(hidden_file, file); ++ set_fbstart(file, bstart); ++ set_h_fptr(file, bstart, hidden_file); ++ memcpy(&hidden_file->f_ra, &file->f_ra, sizeof(file->f_ra)); //?? ++ ++ /* close lower files */ ++ bend = fbend(file); ++ for (bindex = bstart + 1; bindex <= bend; bindex++) ++ set_h_fptr(file, bindex, NULL); ++ set_fbend(file, bstart); ++ ++ out: ++ if (h_file_tmp) ++ fput(h_file_tmp); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int cpup_wh_file(struct file *file, aufs_bindex_t bdst, loff_t len) ++{ ++ int err; ++ struct dentry *dentry, *parent, *hidden_parent, *tmp_dentry; ++ struct dentry *hidden_dentry_bstart, *hidden_dentry_bdst; ++ struct inode *hidden_dir; ++ aufs_bindex_t bstart; ++ struct aufs_dinfo *dinfo; ++ struct dtime dt; ++ struct lkup_args lkup; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, bdst %d, len %Lu\n", DLNPair(dentry), bdst, len); ++ DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode) ++ || !(file->f_mode & FMODE_WRITE)); ++ DiMustWriteLock(dentry); ++ parent = dentry->d_parent; ++ IiMustAnyLock(parent->d_inode); ++ hidden_parent = au_h_dptr_i(parent, bdst); ++ DEBUG_ON(!hidden_parent); ++ hidden_dir = hidden_parent->d_inode; ++ DEBUG_ON(!hidden_dir); ++ IMustLock(hidden_dir); ++ ++ sb = parent->d_sb; ++ lkup.nfsmnt = au_nfsmnt(sb, bdst); ++ lkup.dlgt = need_dlgt(sb); ++ tmp_dentry = lkup_whtmp(hidden_parent, &dentry->d_name, &lkup); ++ //if (LktrCond) {dput(tmp_dentry); tmp_dentry = ERR_PTR(-1);} ++ err = PTR_ERR(tmp_dentry); ++ if (IS_ERR(tmp_dentry)) ++ goto out; ++ ++ dtime_store(&dt, parent, hidden_parent); ++ dinfo = dtodi(dentry); ++ bstart = dinfo->di_bstart; ++ hidden_dentry_bdst = dinfo->di_hdentry[0 + bdst].hd_dentry; ++ hidden_dentry_bstart = dinfo->di_hdentry[0 + bstart].hd_dentry; ++ dinfo->di_bstart = bdst; ++ dinfo->di_hdentry[0 + bdst].hd_dentry = tmp_dentry; ++ dinfo->di_hdentry[0 + bstart].hd_dentry = au_h_fptr(file)->f_dentry; ++ err = cpup_single(dentry, bdst, bstart, len, ++ au_flags_cpup(!CPUP_DTIME, parent)); ++ //if (LktrCond) err = -1; ++ if (!err) ++ err = au_reopen_nondir(file); ++ //err = -1; ++ dinfo->di_hdentry[0 + bstart].hd_dentry = hidden_dentry_bstart; ++ dinfo->di_hdentry[0 + bdst].hd_dentry = hidden_dentry_bdst; ++ dinfo->di_bstart = bstart; ++ if (unlikely(err)) ++ goto out_tmp; ++ ++ DEBUG_ON(!d_unhashed(dentry)); ++ err = vfsub_unlink(hidden_dir, tmp_dentry, lkup.dlgt); ++ //if (LktrCond) err = -1; ++ if (unlikely(err)) { ++ IOErr("failed remove copied-up tmp file %.*s(%d)\n", ++ DLNPair(tmp_dentry), err); ++ err = -EIO; ++ } ++ dtime_revert(&dt, !CPUP_LOCKED_GHDIR); ++ ++ out_tmp: ++ dput(tmp_dentry); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct cpup_wh_file_args { ++ int *errp; ++ struct file *file; ++ aufs_bindex_t bdst; ++ loff_t len; ++}; ++ ++static void call_cpup_wh_file(void *args) ++{ ++ struct cpup_wh_file_args *a = args; ++ *a->errp = cpup_wh_file(a->file, a->bdst, a->len); ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len) ++{ ++ int err; ++ struct dentry *dentry, *parent, *hidden_dentry, *hidden_parent; ++ struct inode *hidden_inode, *hidden_dir, *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bstart, bcpup; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, len %Ld\n", DLNPair(dentry), len); ++ FiMustWriteLock(file); ++ ++ sb = dentry->d_sb; ++ bstart = fbstart(file); ++ DEBUG_ON(ftobr(file, bstart) != stobr(sb, bstart)); ++ ++ inode = dentry->d_inode; ++ ii_read_lock_child(inode); ++ LKTRTrace("rdonly %d, bstart %d\n", test_ro(sb, bstart, inode), bstart); ++ err = test_ro(sb, bstart, inode); ++ ii_read_unlock(inode); ++ if (!err && (au_h_fptr(file)->f_mode & FMODE_WRITE)) ++ return 0; ++ ++ /* need to cpup */ ++ parent = dentry->d_parent; // dget_parent() ++ di_write_lock_child(dentry); ++ di_write_lock_parent(parent); ++ bcpup = err = find_rw_parent_br(dentry, bstart); ++ //bcpup = err = find_rw_br(sb, bstart); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ err = 0; ++ ++ hidden_parent = au_h_dptr_i(parent, bcpup); ++ if (!hidden_parent) { ++ err = cpup_dirs(dentry, bcpup, NULL); ++ //if (LktrCond) err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ hidden_parent = au_h_dptr_i(parent, bcpup); ++ } ++ ++ hidden_dir = hidden_parent->d_inode; ++ hidden_dentry = au_h_fptr(file)->f_dentry; ++ hidden_inode = hidden_dentry->d_inode; ++ dir = parent->d_inode; ++ hdir_lock(hidden_dir, dir, bcpup); ++ hi_lock_child(hidden_inode); ++ if (d_unhashed(dentry) || d_unhashed(hidden_dentry) ++ /* || !hidden_inode->i_nlink */) { ++ if (!au_test_perm(hidden_dir, MAY_EXEC | MAY_WRITE, ++ need_dlgt(sb))) ++ err = cpup_wh_file(file, bcpup, len); ++ else { ++ struct cpup_wh_file_args args = { ++ .errp = &err, ++ .file = file, ++ .bdst = bcpup, ++ .len = len ++ }; ++ au_wkq_wait(call_cpup_wh_file, &args, /*dlgt*/0); ++ } ++ //if (LktrCond) err = -1; ++ TraceErr(err); ++ } else { ++ if (!au_h_dptr_i(dentry, bcpup)) ++ err = sio_cpup_simple(dentry, bcpup, len, ++ au_flags_cpup(CPUP_DTIME, ++ parent)); ++ //if (LktrCond) err = -1; ++ TraceErr(err); ++ if (!err) ++ err = au_reopen_nondir(file); ++ //if (LktrCond) err = -1; ++ TraceErr(err); ++ } ++ i_unlock(hidden_inode); ++ hdir_unlock(hidden_dir, dir, bcpup); ++ ++ out_unlock: ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++// out: ++ TraceErr(err); ++ return err; ++ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, new_sz; ++ struct dentry *dentry; ++ aufs_bindex_t bend, bindex, bstart, brid; ++ struct aufs_hfile *p; ++ struct aufs_finfo *finfo; ++ struct super_block *sb; ++ struct inode *inode; ++ struct file *hidden_file; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ FiMustWriteLock(file); ++ DiMustReadLock(dentry); ++ inode = dentry->d_inode; ++ IiMustReadLock(inode); ++ //au_debug_on(); ++ //DbgDentry(dentry); ++ //DbgFile(file); ++ //au_debug_off(); ++ ++ err = -ENOMEM; ++ sb = dentry->d_sb; ++ finfo = ftofi(file); ++ bstart = finfo->fi_bstart; ++ bend = finfo->fi_bstart; ++ new_sz = sizeof(*finfo->fi_hfile) * (sbend(sb) + 1); ++ p = au_kzrealloc(finfo->fi_hfile, sizeof(*p) * (finfo->fi_bend + 1), ++ new_sz, GFP_KERNEL); ++ //p = NULL; ++ if (unlikely(!p)) ++ goto out; ++ finfo->fi_hfile = p; ++ hidden_file = p[0 + bstart].hf_file; ++ ++ p = finfo->fi_hfile + finfo->fi_bstart; ++ brid = p->hf_br->br_id; ++ bend = finfo->fi_bend; ++ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++, p++) { ++ struct aufs_hfile tmp, *q; ++ aufs_bindex_t new_bindex; ++ ++ if (!p->hf_file) ++ continue; ++ new_bindex = find_bindex(sb, p->hf_br); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { // test here ++ set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two hidden inode, and loop again */ ++ q = finfo->fi_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ { ++ aufs_bindex_t s = finfo->fi_bstart, e = finfo->fi_bend; ++ finfo->fi_bstart = 0; ++ finfo->fi_bend = sbend(sb); ++ //au_debug_on(); ++ //DbgFile(file); ++ //au_debug_off(); ++ finfo->fi_bstart = s; ++ finfo->fi_bend = e; ++ } ++ ++ p = finfo->fi_hfile; ++ if (!au_is_mmapped(file) && !d_unhashed(dentry)) { ++ bend = sbend(sb); ++ for (finfo->fi_bstart = 0; finfo->fi_bstart <= bend; ++ finfo->fi_bstart++, p++) ++ if (p->hf_file) { ++ if (p->hf_file->f_dentry ++ && p->hf_file->f_dentry->d_inode) ++ break; ++ else ++ au_hfput(p); ++ } ++ } else { ++ bend = find_brindex(sb, brid); ++ //LKTRTrace("%d\n", bend); ++ for (finfo->fi_bstart = 0; finfo->fi_bstart < bend; ++ finfo->fi_bstart++, p++) ++ if (p->hf_file) ++ au_hfput(p); ++ //LKTRTrace("%d\n", finfo->fi_bstart); ++ bend = sbend(sb); ++ } ++ ++ p = finfo->fi_hfile + bend; ++ for (finfo->fi_bend = bend; finfo->fi_bend >= finfo->fi_bstart; ++ finfo->fi_bend--, p--) ++ if (p->hf_file) { ++ if (p->hf_file->f_dentry ++ && p->hf_file->f_dentry->d_inode) ++ break; ++ else ++ au_hfput(p); ++ } ++ //Dbg("%d, %d\n", finfo->fi_bstart, finfo->fi_bend); ++ DEBUG_ON(finfo->fi_bend < finfo->fi_bstart); ++ //DbgFile(file); ++ //DbgDentry(file->f_dentry); ++ ++ err = 0; ++#if 0 // todo: ++ if (!au_h_dptr(dentry)->d_inode) { ++ au_update_figen(file); ++ goto out; /* success */ ++ } ++#endif ++ ++ if (unlikely(au_is_mmapped(file) || d_unhashed(dentry))) ++ goto out_update; /* success */ ++ ++ again: ++ bstart = ibstart(inode); ++ if (bstart < finfo->fi_bstart ++ && au_flag_test(sb, AuFlag_PLINK) ++ && au_is_plinked(sb, inode)) { ++ struct dentry *parent = dentry->d_parent; // dget_parent() ++ struct inode *dir = parent->d_inode, *h_dir; ++ ++ if (test_ro(sb, bstart, inode)) { ++ di_read_lock_parent(parent, !AUFS_I_RLOCK); ++ bstart = err = find_rw_parent_br(dentry, bstart); ++ //bstart = err = find_rw_br(sb, bstart); ++ di_read_unlock(parent, !AUFS_I_RLOCK); ++ //todo: err = -1; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ di_read_unlock(dentry, AUFS_I_RLOCK); ++ di_write_lock_child(dentry); ++ if (bstart != ibstart(inode)) { // todo ++ /* someone changed our inode while we were sleeping */ ++ di_downgrade_lock(dentry, AUFS_I_RLOCK); ++ goto again; ++ } ++ ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ err = test_and_cpup_dirs(dentry, bstart, NULL); ++ ++ // always superio. ++#if 1 ++ h_dir = au_h_dptr_i(parent, bstart)->d_inode; ++ hdir_lock(h_dir, dir, bstart); ++ err = sio_cpup_simple(dentry, bstart, -1, ++ au_flags_cpup(CPUP_DTIME, parent)); ++ hdir_unlock(h_dir, dir, bstart); ++ di_read_unlock(parent, AUFS_I_RLOCK); ++#else ++ if (!is_au_wkq(current)) { ++ struct cpup_pseudo_link_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bstart, ++ .do_lock = 1 ++ }; ++ au_wkq_wait(call_cpup_pseudo_link, &args); ++ } else ++ err = cpup_pseudo_link(dentry, bstart, /*do_lock*/1); ++#endif ++ di_downgrade_lock(dentry, AUFS_I_RLOCK); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = reopen(file); ++ //err = -1; ++ out_update: ++ if (!err) { ++ au_update_figen(file); ++ //DbgFile(file); ++ return 0; /* success */ ++ } ++ ++ /* error, close all hidden files */ ++ bend = fbend(file); ++ for (bindex = fbstart(file); bindex <= bend; bindex++) ++ set_h_fptr(file, bindex, NULL); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_finfo(struct file *file, int (*reopen)(struct file *file), ++ int wlock, int locked) ++{ ++ int err, sgen, fgen, pseudo_link; ++ struct dentry *dentry; ++ struct super_block *sb; ++ aufs_bindex_t bstart; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, w %d, l %d\n", DLNPair(dentry), wlock, locked); ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ sgen = au_sigen(sb); ++ fi_write_lock(file); ++ fgen = au_figen(file); ++ di_read_lock_child(dentry, AUFS_I_RLOCK); ++ bstart = dbstart(dentry); ++ pseudo_link = (bstart != ibstart(dentry->d_inode)); ++ di_read_unlock(dentry, AUFS_I_RLOCK); ++ if (sgen == fgen && !pseudo_link && fbstart(file) == bstart) { ++ if (!wlock) ++ fi_downgrade_lock(file); ++ return 0; /* success */ ++ } ++ ++ LKTRTrace("sgen %d, fgen %d\n", sgen, fgen); ++ if (sgen != au_digen(dentry)) { ++ /* ++ * d_path() and path_lookup() is a simple and good approach ++ * to revalidate. but si_rwsem in DEBUG_RWSEM will cause a ++ * deadlock. removed the code. ++ */ ++ di_write_lock_child(dentry); ++ err = au_reval_dpath(dentry, sgen); ++ //if (LktrCond) err = -1; ++ di_write_unlock(dentry); ++ if (unlikely(err < 0)) ++ goto out; ++ DEBUG_ON(au_digen(dentry) != sgen); ++ } ++ ++ di_read_lock_child(dentry, AUFS_I_RLOCK); ++ err = refresh_file(file, reopen); ++ //if (LktrCond) err = -1; ++ di_read_unlock(dentry, AUFS_I_RLOCK); ++ if (!err) { ++ if (!wlock) ++ fi_downgrade_lock(file); ++ } else ++ fi_write_unlock(file); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++// cf. aufs_nopage() ++// for madvise(2) ++static int aufs_readpage(struct file *file, struct page *page) ++{ ++ TraceEnter(); ++ unlock_page(page); ++ return 0; ++} ++ ++// they will never be called. ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_prepare_write(struct file *file, struct page *page, ++ unsigned from, unsigned to) ++{BUG();return 0;} ++static int aufs_commit_write(struct file *file, struct page *page, ++ unsigned from, unsigned to) ++{BUG();return 0;} ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{BUG();return 0;} ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) ++static void aufs_sync_page(struct page *page) ++{BUG();} ++#else ++static int aufs_sync_page(struct page *page) ++{BUG(); return 0;} ++#endif ++ ++#if 0 // comment ++static int aufs_writepages(struct address_space *mapping, ++ struct writeback_control *wbc) ++{BUG();return 0;} ++static int aufs_readpages(struct file *filp, struct address_space *mapping, ++ struct list_head *pages, unsigned nr_pages) ++{BUG();return 0;} ++static sector_t aufs_bmap(struct address_space *mapping, sector_t block) ++{BUG();return 0;} ++#endif ++ ++static int aufs_set_page_dirty(struct page *page) ++{BUG();return 0;} ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) ++static void aufs_invalidatepage (struct page *page, unsigned long offset) ++{BUG();} ++#else ++static int aufs_invalidatepage (struct page *page, unsigned long offset) ++{BUG(); return 0;} ++#endif ++static int aufs_releasepage (struct page *page, gfp_t gfp) ++{BUG();return 0;} ++static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, ++ const struct iovec *iov, loff_t offset, ++ unsigned long nr_segs) ++{BUG();return 0;} ++static struct page* aufs_get_xip_page(struct address_space *mapping, ++ sector_t offset, int create) ++{BUG();return NULL;} ++//static int aufs_migratepage (struct page *newpage, struct page *page) ++//{BUG();return 0;} ++#endif ++ ++#if 0 // comment ++struct address_space { ++ struct inode *host; /* owner: inode, block_device */ ++ struct radix_tree_root page_tree; /* radix tree of all pages */ ++ rwlock_t tree_lock; /* and rwlock protecting it */ ++ unsigned int i_mmap_writable;/* count VM_SHARED mappings */ ++ struct prio_tree_root i_mmap; /* tree of private and shared mappings */ ++ struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */ ++ spinlock_t i_mmap_lock; /* protect tree, count, list */ ++ unsigned int truncate_count; /* Cover race condition with truncate */ ++ unsigned long nrpages; /* number of total pages */ ++ pgoff_t writeback_index;/* writeback starts here */ ++ struct address_space_operations *a_ops; /* methods */ ++ unsigned long flags; /* error bits/gfp mask */ ++ struct backing_dev_info *backing_dev_info; /* device readahead, etc */ ++ spinlock_t private_lock; /* for use by the address_space */ ++ struct list_head private_list; /* ditto */ ++ struct address_space *assoc_mapping; /* ditto */ ++} __attribute__((aligned(sizeof(long)))); ++ ++struct address_space_operations { ++ int (*writepage)(struct page *page, struct writeback_control *wbc); ++ int (*readpage)(struct file *, struct page *); ++ void (*sync_page)(struct page *); ++ ++ /* Write back some dirty pages from this mapping. */ ++ int (*writepages)(struct address_space *, struct writeback_control *); ++ ++ /* Set a page dirty. Return true if this dirtied it */ ++ int (*set_page_dirty)(struct page *page); ++ ++ int (*readpages)(struct file *filp, struct address_space *mapping, ++ struct list_head *pages, unsigned nr_pages); ++ ++ /* ++ * ext3 requires that a successful prepare_write() call be followed ++ * by a commit_write() call - they must be balanced ++ */ ++ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); ++ int (*commit_write)(struct file *, struct page *, unsigned, unsigned); ++ /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ ++ sector_t (*bmap)(struct address_space *, sector_t); ++ void (*invalidatepage) (struct page *, unsigned long); ++ int (*releasepage) (struct page *, gfp_t); ++ ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, ++ loff_t offset, unsigned long nr_segs); ++ struct page* (*get_xip_page)(struct address_space *, sector_t, ++ int); ++ /* migrate the contents of a page to the specified target */ ++ int (*migratepage) (struct page *, struct page *); ++}; ++#endif ++ ++struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ .sync_page = aufs_sync_page, ++ //.writepages = aufs_writepages, ++ .set_page_dirty = aufs_set_page_dirty, ++ //.readpages = aufs_readpages, ++ .prepare_write = aufs_prepare_write, ++ .commit_write = aufs_commit_write, ++ //.bmap = aufs_bmap, ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ .direct_IO = aufs_direct_IO, ++ .get_xip_page = aufs_get_xip_page, ++ //.migratepage = aufs_migratepage ++#endif ++}; +diff --git a/fs/aufs/file.h b/fs/aufs/file.h +new file mode 100755 +index 0000000..f0fa448 +--- /dev/null ++++ b/fs/aufs/file.h +@@ -0,0 +1,140 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: file.h,v 1.25 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "misc.h" ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++// SEEK_xxx are defined in linux/fs.h ++#else ++enum {SEEK_SET, SEEK_CUR, SEEK_END}; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_branch; ++struct aufs_hfile { ++ struct file *hf_file; ++ struct aufs_branch *hf_br; ++}; ++ ++struct aufs_vdir; ++struct aufs_finfo { ++ atomic_t fi_generation; ++ ++ struct aufs_rwsem fi_rwsem; ++ struct aufs_hfile *fi_hfile; ++ aufs_bindex_t fi_bstart, fi_bend; ++ ++ union { ++ struct vm_operations_struct *fi_h_vm_ops; ++ struct aufs_vdir *fi_vdir_cache; ++ }; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *hidden_open(struct dentry *dentry, aufs_bindex_t bindex, ++ int flags); ++int au_do_open(struct inode *inode, struct file *file, ++ int (*open)(struct file *file, int flags)); ++int au_reopen_nondir(struct file *file); ++int au_ready_to_write(struct file *file, loff_t len); ++int au_reval_and_lock_finfo(struct file *file, int (*reopen)(struct file *file), ++ int wlock, int locked); ++ ++/* f_op.c */ ++extern struct file_operations aufs_file_fop; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++int aufs_flush(struct file *file, fl_owner_t id); ++#else ++int aufs_flush(struct file *file); ++#endif ++ ++/* finfo.c */ ++struct aufs_finfo *ftofi(struct file *file); ++aufs_bindex_t fbstart(struct file *file); ++aufs_bindex_t fbend(struct file *file); ++struct aufs_vdir *fvdir_cache(struct file *file); ++struct aufs_branch *ftobr(struct file *file, aufs_bindex_t bindex); ++struct file *au_h_fptr_i(struct file *file, aufs_bindex_t bindex); ++struct file *au_h_fptr(struct file *file); ++ ++void set_fbstart(struct file *file, aufs_bindex_t bindex); ++void set_fbend(struct file *file, aufs_bindex_t bindex); ++void set_fvdir_cache(struct file *file, struct aufs_vdir *vdir_cache); ++void au_hfput(struct aufs_hfile *hf); ++void set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *h_file); ++void au_update_figen(struct file *file); ++ ++void au_fin_finfo(struct file *file); ++int au_init_finfo(struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_figen(struct file *f) ++{ ++ return atomic_read(&ftofi(f)->fi_generation); ++} ++ ++static inline int au_is_mmapped(struct file *f) ++{ ++ return !!(ftofi(f)->fi_h_vm_ops); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * fi_read_lock, fi_write_lock, ++ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock ++ */ ++SimpleRwsemFuncs(fi, struct file *f, ftofi(f)->fi_rwsem); ++ ++/* to debug easier, do not make them inlined functions */ ++#define FiMustReadLock(f) do {\ ++ SiMustAnyLock((f)->f_dentry->d_sb); \ ++ RwMustReadLock(&ftofi(f)->fi_rwsem); \ ++} while (0) ++ ++#define FiMustWriteLock(f) do { \ ++ SiMustAnyLock((f)->f_dentry->d_sb); \ ++ RwMustWriteLock(&ftofi(f)->fi_rwsem); \ ++} while (0) ++ ++#define FiMustAnyLock(f) do { \ ++ SiMustAnyLock((f)->f_dentry->d_sb); \ ++ RwMustAnyLock(&ftofi(f)->fi_rwsem); \ ++} while (0) ++ ++#define FiMustNoWaiters(f) RwMustNoWaiters(&ftofi(f)->fi_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c +new file mode 100755 +index 0000000..1e09da8 +--- /dev/null ++++ b/fs/aufs/finfo.c +@@ -0,0 +1,211 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: finfo.c,v 1.23 2007/04/30 05:45:21 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++struct aufs_finfo *ftofi(struct file *file) ++{ ++ struct aufs_finfo *finfo = file->private_data; ++ DEBUG_ON(!finfo ++ || !finfo->fi_hfile ++ || (0 < finfo->fi_bend ++ && (/* stosi(file->f_dentry->d_sb)->si_bend ++ < finfo->fi_bend ++ || */ finfo->fi_bend < finfo->fi_bstart))); ++ return finfo; ++} ++ ++// hard/soft set ++aufs_bindex_t fbstart(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return ftofi(file)->fi_bstart; ++} ++ ++aufs_bindex_t fbend(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return ftofi(file)->fi_bend; ++} ++ ++struct aufs_vdir *fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return ftofi(file)->fi_vdir_cache; ++} ++ ++struct aufs_branch *ftobr(struct file *file, aufs_bindex_t bindex) ++{ ++ struct aufs_finfo *finfo = ftofi(file); ++ struct aufs_hfile *hf; ++ ++ FiMustAnyLock(file); ++ DEBUG_ON(!finfo ++ || finfo->fi_bstart < 0 ++ || bindex < finfo->fi_bstart ++ || finfo->fi_bend < bindex); ++ hf = finfo->fi_hfile + bindex; ++ DEBUG_ON(hf->hf_br && br_count(hf->hf_br) <= 0); ++ return hf->hf_br; ++} ++ ++struct file *au_h_fptr_i(struct file *file, aufs_bindex_t bindex) ++{ ++ struct aufs_finfo *finfo = ftofi(file); ++ struct aufs_hfile *hf; ++ ++ FiMustAnyLock(file); ++ DEBUG_ON(!finfo ++ || finfo->fi_bstart < 0 ++ || bindex < finfo->fi_bstart ++ || finfo->fi_bend < bindex); ++ hf = finfo->fi_hfile + bindex; ++ DEBUG_ON(hf->hf_file ++ && file_count(hf->hf_file) <= 0 ++ && br_count(hf->hf_br) <= 0); ++ return hf->hf_file; ++} ++ ++struct file *au_h_fptr(struct file *file) ++{ ++ return au_h_fptr_i(file, fbstart(file)); ++} ++ ++void set_fbstart(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ DEBUG_ON(sbend(file->f_dentry->d_sb) < bindex); ++ ftofi(file)->fi_bstart = bindex; ++} ++ ++void set_fbend(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ DEBUG_ON(sbend(file->f_dentry->d_sb) < bindex ++ || bindex < fbstart(file)); ++ ftofi(file)->fi_bend = bindex; ++} ++ ++void set_fvdir_cache(struct file *file, struct aufs_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ DEBUG_ON(!S_ISDIR(file->f_dentry->d_inode->i_mode) ++ || (ftofi(file)->fi_vdir_cache && vdir_cache)); ++ ftofi(file)->fi_vdir_cache = vdir_cache; ++} ++ ++void au_hfput(struct aufs_hfile *hf) ++{ ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ DEBUG_ON(!hf->hf_br); ++ br_put(hf->hf_br); ++ hf->hf_br = NULL; ++} ++ ++void set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct aufs_finfo *finfo = ftofi(file); ++ struct aufs_hfile *hf; ++ ++ FiMustWriteLock(file); ++ DEBUG_ON(!finfo ++ || finfo->fi_bstart < 0 ++ || bindex < finfo->fi_bstart ++ || finfo->fi_bend < bindex); ++ DEBUG_ON(val && file_count(val) <= 0); ++ hf = finfo->fi_hfile + bindex; ++ DEBUG_ON(val && hf->hf_file); ++ if (hf->hf_file) ++ au_hfput(hf); ++ if (val) { ++ hf->hf_file = val; ++ hf->hf_br = stobr(file->f_dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&ftofi(file)->fi_generation, au_digen(file->f_dentry)); ++} ++ ++void au_fin_finfo(struct file *file) ++{ ++ struct aufs_finfo *finfo; ++ struct dentry *dentry; ++ aufs_bindex_t bindex, bend; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ SiMustAnyLock(dentry->d_sb); ++ ++ fi_write_lock(file); ++ bend = fbend(file); ++ bindex = fbstart(file); ++ if (bindex >= 0) ++ for (; bindex <= bend; bindex++) ++ set_h_fptr(file, bindex, NULL); ++ ++ finfo = ftofi(file); ++#ifdef CONFIG_AUFS_DEBUG ++ if (finfo->fi_bstart >= 0) { ++ bend = fbend(file); ++ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++) { ++ struct aufs_hfile *hf; ++ hf = finfo->fi_hfile + bindex; ++ DEBUG_ON(hf->hf_file || hf->hf_br); ++ } ++ } ++#endif ++ ++ kfree(finfo->fi_hfile); ++ fi_write_unlock(file); ++ cache_free_finfo(finfo); ++ //file->private_data = NULL; ++} ++ ++int au_init_finfo(struct file *file) ++{ ++ struct aufs_finfo *finfo; ++ struct dentry *dentry; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(!dentry->d_inode); ++ ++ finfo = cache_alloc_finfo(); ++ if (finfo) { ++ finfo->fi_hfile = kcalloc(sbend(dentry->d_sb) + 1, ++ sizeof(*finfo->fi_hfile), GFP_KERNEL); ++ if (finfo->fi_hfile) { ++ rw_init_wlock(&finfo->fi_rwsem); ++ finfo->fi_bstart = -1; ++ finfo->fi_bend = -1; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ ++ file->private_data = finfo; ++ return 0; /* success */ ++ } ++ cache_free_finfo(finfo); ++ } ++ ++ TraceErr(-ENOMEM); ++ return -ENOMEM; ++} +diff --git a/fs/aufs/hinotify.c b/fs/aufs/hinotify.c +new file mode 100755 +index 0000000..3bad3f7 +--- /dev/null ++++ b/fs/aufs/hinotify.c +@@ -0,0 +1,536 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: hinotify.c,v 1.19 2007/05/14 03:39:21 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++static struct inotify_handle *in_handle; ++static const __u32 in_mask = (IN_MOVE | IN_DELETE | IN_CREATE /* | IN_ACCESS */ ++ | IN_MODIFY | IN_ATTRIB ++ | IN_DELETE_SELF | IN_MOVE_SELF); ++ ++int alloc_hinotify(struct aufs_hinode *hinode, struct inode *inode, ++ struct inode *hidden_inode) ++{ ++ int err; ++ struct aufs_hinotify *hin; ++ s32 wd; ++ ++ LKTRTrace("i%lu, hi%lu\n", inode->i_ino, hidden_inode->i_ino); ++ ++ err = -ENOMEM; ++ hin = cache_alloc_hinotify(); ++ if (hin) { ++ DEBUG_ON(hinode->hi_notify); ++ hinode->hi_notify = hin; ++ hin->hin_aufs_inode = inode; ++ inotify_init_watch(&hin->hin_watch); ++ wd = inotify_add_watch(in_handle, &hin->hin_watch, hidden_inode, ++ in_mask); ++ if (wd >= 0) ++ return 0; /* success */ ++ ++ err = wd; ++ put_inotify_watch(&hin->hin_watch); ++ cache_free_hinotify(hin); ++ hinode->hi_notify = NULL; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++void do_free_hinotify(struct aufs_hinode *hinode) ++{ ++ int err; ++ struct aufs_hinotify *hin; ++ ++ TraceEnter(); ++ ++ hin = hinode->hi_notify; ++ if (hin) { ++ err = 0; ++ if (atomic_read(&hin->hin_watch.count)) ++ err = inotify_rm_watch(in_handle, &hin->hin_watch); ++ ++ if (!err) { ++ cache_free_hinotify(hin); ++ hinode->hi_notify = NULL; ++ } else ++ IOErr1("failed inotify_rm_watch() %d\n", err); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void ctl_hinotify(struct aufs_hinode *hinode, const __u32 mask) ++{ ++ struct inode *hi; ++ struct inotify_watch *watch; ++ ++ hi = hinode->hi_inode; ++ LKTRTrace("hi%lu, sb %p, 0x%x\n", hi->i_ino, hi->i_sb, mask); ++ if (0 && !strcmp(current->comm, "link")) ++ dump_stack(); ++ IMustLock(hi); ++ if (!hinode->hi_notify) ++ return; ++ ++ watch = &hinode->hi_notify->hin_watch; ++#if 0 ++ { ++ u32 wd; ++ wd = inotify_find_update_watch(in_handle, hi, mask); ++ TraceErr(wd); ++ // ignore an err; ++ } ++#else ++ watch->mask = mask; ++ smp_mb(); ++#endif ++ LKTRTrace("watch %p, mask %u\n", watch, watch->mask); ++} ++ ++#define suspend_hinotify(hi) ctl_hinotify(hi, 0) ++#define resume_hinotify(hi) ctl_hinotify(hi, in_mask) ++ ++void do_hdir_lock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex, ++ unsigned int lsc) ++{ ++ struct aufs_hinode *hinode; ++ ++ LKTRTrace("i%lu, b%d, lsc %d\n", dir->i_ino, bindex, lsc); ++ DEBUG_ON(!S_ISDIR(dir->i_mode)); ++ hinode = itoii(dir)->ii_hinode + bindex; ++ DEBUG_ON(h_dir != hinode->hi_inode); ++ ++ hi_lock(h_dir, lsc); ++ if (1 /* unlikely(au_flag_test(dir->i_sb, AuFlag_UDBA_HINOTIFY) */) ++ suspend_hinotify(hinode); ++} ++ ++void hdir_unlock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex) ++{ ++ struct aufs_hinode *hinode; ++ ++ LKTRTrace("i%lu, b%d\n", dir->i_ino, bindex); ++ DEBUG_ON(!S_ISDIR(dir->i_mode)); ++ hinode = itoii(dir)->ii_hinode + bindex; ++ DEBUG_ON(h_dir != hinode->hi_inode); ++ ++ if (1 /* unlikely(au_flag_test(dir->i_sb, AuFlag_UDBA_HINOTIFY) */) ++ resume_hinotify(hinode); ++ i_unlock(h_dir); ++} ++ ++void hdir_lock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir) ++{ ++ struct aufs_hinode *hinode; ++ ++ LKTRTrace("%.*s, %.*s\n", DLNPair(h_parents[0]), DLNPair(h_parents[1])); ++ ++ vfsub_lock_rename(h_parents[0], h_parents[1]); ++ hinode = itoii(dirs[0])->ii_hinode + bindex; ++ DEBUG_ON(h_parents[0]->d_inode != hinode->hi_inode); ++ suspend_hinotify(hinode); ++ if (issamedir) ++ return; ++ hinode = itoii(dirs[1])->ii_hinode + bindex; ++ DEBUG_ON(h_parents[1]->d_inode != hinode->hi_inode); ++ suspend_hinotify(hinode); ++} ++ ++void hdir_unlock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir) ++{ ++ struct aufs_hinode *hinode; ++ ++ LKTRTrace("%.*s, %.*s\n", DLNPair(h_parents[0]), DLNPair(h_parents[1])); ++ ++ hinode = itoii(dirs[0])->ii_hinode + bindex; ++ DEBUG_ON(h_parents[0]->d_inode != hinode->hi_inode); ++ resume_hinotify(hinode); ++ if (!issamedir) { ++ hinode = itoii(dirs[1])->ii_hinode + bindex; ++ DEBUG_ON(h_parents[1]->d_inode != hinode->hi_inode); ++ resume_hinotify(hinode); ++ } ++ vfsub_unlock_rename(h_parents[0], h_parents[1]); ++} ++ ++void au_reset_hinotify(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bend; ++ struct inode *hi; ++ ++ LKTRTrace("i%lu, 0x%x\n", inode->i_ino, flags); ++ ++ bend = ibend(inode); ++ for (bindex = ibstart(inode); bindex <= bend; bindex++) { ++ hi = au_h_iptr_i(inode, bindex); ++ if (hi) { ++ //hi_lock(hi, AUFS_LSC_H_CHILD); ++ igrab(hi); ++ set_h_iptr(inode, bindex, NULL, 0); ++ set_h_iptr(inode, bindex, igrab(hi), flags); ++ iput(hi); ++ //i_unlock(hi); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++static char *in_name(u32 mask) ++{ ++#define test_ret(flag) if (mask & flag) return #flag; ++ test_ret(IN_ACCESS); ++ test_ret(IN_MODIFY); ++ test_ret(IN_ATTRIB); ++ test_ret(IN_CLOSE_WRITE); ++ test_ret(IN_CLOSE_NOWRITE); ++ test_ret(IN_OPEN); ++ test_ret(IN_MOVED_FROM); ++ test_ret(IN_MOVED_TO); ++ test_ret(IN_CREATE); ++ test_ret(IN_DELETE); ++ test_ret(IN_DELETE_SELF); ++ test_ret(IN_MOVE_SELF); ++ test_ret(IN_UNMOUNT); ++ test_ret(IN_Q_OVERFLOW); ++ test_ret(IN_IGNORED); ++ return ""; ++#undef test_ret ++} ++#else ++#define in_name(m) "??" ++#endif ++ ++static int dec_gen_by_name(struct inode *dir, const char *_name, u32 mask) ++{ ++ int err; ++ struct dentry *parent, *child; ++ struct inode *inode; ++ struct qstr *dname; ++ char *name = (void*)_name; ++ unsigned int len; ++ ++ LKTRTrace("i%lu, %s, 0x%x %s\n", ++ dir->i_ino, name, mask, in_name(mask)); ++ ++ err = -1; ++ parent = d_find_alias(dir); ++ if (unlikely(!parent)) ++ goto out; ++ ++#if 0 ++ if (unlikely(!memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ name += AUFS_WH_PFX_LEN; ++#endif ++ len = strlen(name); ++ spin_lock(&dcache_lock); ++ list_for_each_entry(child, &parent->d_subdirs, d_u.d_child) { ++ dname = &child->d_name; ++ if (len == dname->len && !memcmp(dname->name, name, len)) { ++ au_digen_dec(child); ++#if 1 ++ //todo: why both are needed ++ if (mask & IN_MOVE) { ++ spin_lock(&child->d_lock); ++ __d_drop(child); ++ spin_unlock(&child->d_lock); ++ } ++#endif ++ ++ inode = child->d_inode; ++ if (inode) ++ au_iigen_dec(inode); ++ err = !!inode; ++ ++ // todo: the i_nlink of newly created name by link(2) ++ // should be updated ++ // todo: some nfs dentry doesn't notified at deleteing ++ break; ++ } ++ } ++ spin_unlock(&dcache_lock); ++ dput(parent); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct postproc_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ char *h_child_name; ++ u32 mask; ++}; ++ ++static void dec_gen_by_ino(struct postproc_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend, bfound; ++ struct xino xino; ++ struct inode *cinode; ++ ++ TraceEnter(); ++ ++ sb = a->dir->i_sb; ++ DEBUG_ON(!au_flag_test(sb, AuFlag_XINO)); ++ ++ bfound = -1; ++ bend = ibend(a->dir); ++ for (bindex = ibstart(a->dir); bfound == -1 && bindex <= bend; bindex++) ++ if (au_h_iptr_i(a->dir, bindex) == a->h_dir) ++ bfound = bindex; ++ if (bfound < 0) ++ return; ++ ++ bindex = find_brindex(sb, itoii(a->dir)->ii_hinode[bfound + 0].hi_id); ++ if (bindex < 0) ++ return; ++ if (unlikely(xino_read(sb, bindex, a->h_child_inode->i_ino, &xino))) ++ return; ++ cinode = NULL; ++ if (xino.ino) ++ cinode = ilookup(sb, xino.ino); ++ if (cinode) { ++#if 1 ++ if (1 || a->mask & IN_MOVE) { ++ struct dentry *child; ++ spin_lock(&dcache_lock); ++ list_for_each_entry(child, &cinode->i_dentry, d_alias) ++ au_digen_dec(child); ++ spin_unlock(&dcache_lock); ++ } ++#endif ++ au_iigen_dec(cinode); ++ iput(cinode); ++ } ++} ++ ++static void reset_ino(struct postproc_args *a) ++{ ++ aufs_bindex_t bindex, bend; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ sb = a->dir->i_sb; ++ bend = ibend(a->dir); ++ for (bindex = ibstart(a->dir); bindex <= bend; bindex++) { ++ h_dir = au_h_iptr_i(a->dir, bindex); ++ if (h_dir && h_dir != a->h_dir) ++ xino_write0(sb, bindex, h_dir->i_ino); ++ /* ignore this error */ ++ } ++} ++ ++static void postproc(void *args) ++{ ++ struct postproc_args *a = args; ++ struct super_block *sb; ++ struct aufs_vdir *vdir; ++ ++ //au_debug_on(); ++ LKTRTrace("mask 0x%x %s, i%lu, hi%lu, hci%lu\n", ++ a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ DEBUG_ON(!a->dir); ++#if 0//def ForceInotify ++ Dbg("mask 0x%x %s, i%lu, hi%lu, hci%lu\n", ++ a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++#endif ++ ++ i_lock(a->dir); ++ sb = a->dir->i_sb; ++ si_read_lock(sb); // consider write_lock ++ ii_write_lock_parent(a->dir); ++ ++ /* make dir entries obsolete */ ++ vdir = ivdir(a->dir); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ a->dir->i_version++; ++ ++ /* ++ * special handling root directory, ++ * sine d_revalidate may not be called later. ++ * main purpose is maintaining i_nlink. ++ */ ++ if (unlikely(a->dir->i_ino == AUFS_ROOT_INO)) ++ au_cpup_attr_all(a->dir); ++ ++ if (a->h_child_inode && au_flag_test(sb, AuFlag_XINO)) ++ dec_gen_by_ino(a); ++ else if (a->mask & (IN_MOVE_SELF | IN_DELETE_SELF)) ++ reset_ino(a); ++ ++ ii_write_unlock(a->dir); ++ si_read_unlock(sb); ++ i_unlock(a->dir); ++ ++ au_mntput(a->dir->i_sb); ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++#if 0 ++ if (atomic_dec_and_test(&stosi(sb)->si_hinotify)) ++ wake_up_all(&stosi(sb)->si_hinotify_wq); ++#endif ++ kfree(a); ++ //au_debug_off(); ++} ++ ++static void aufs_inotify(struct inotify_watch *watch, u32 wd, u32 mask, ++ u32 cookie, const char *h_child_name, ++ struct inode *h_child_inode) ++{ ++ struct aufs_hinotify *hinotify; ++ struct postproc_args *args; ++ int len; ++ char *p; ++ struct inode *dir; ++ //static DECLARE_WAIT_QUEUE_HEAD(wq); ++ ++ //au_debug_on(); ++ LKTRTrace("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s, hi%lu\n", ++ watch->inode->i_ino, wd, mask, in_name(mask), cookie, ++ h_child_name ? h_child_name : "", ++ h_child_inode ? h_child_inode->i_ino : 0); ++ //au_debug_off(); ++ //IMustLock(h_dir); ++#if 0 //defined(ForceInotify) || defined(DbgInotify) ++ Dbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s, hi%lu\n", ++ watch->inode->i_ino, wd, mask, in_name(mask), cookie, ++ h_child_name ? h_child_name : "", ++ h_child_inode ? h_child_inode->i_ino : 0); ++#endif ++ /* if IN_UNMOUNT happens, there must be another bug */ ++ if (mask & (IN_IGNORED | IN_UNMOUNT)) { ++ put_inotify_watch(watch); ++ return; ++ } ++ ++ switch (mask & IN_ALL_EVENTS) { ++ case IN_MODIFY: ++ case IN_ATTRIB: ++ if (h_child_name) ++ return; ++ break; ++ ++ case IN_MOVED_FROM: ++ case IN_MOVED_TO: ++ case IN_CREATE: ++ DEBUG_ON(!h_child_name || !h_child_inode); ++ break; ++ case IN_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalide() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ DEBUG_ON(!h_child_name); ++ break; ++ ++ case IN_DELETE_SELF: ++ case IN_MOVE_SELF: ++ DEBUG_ON(h_child_name || h_child_inode); ++ break; ++ ++ case IN_ACCESS: ++ default: ++ DEBUG_ON(1); ++ } ++ ++#ifdef DbgInotify ++ WARN_ON(1); ++#endif ++ ++ /* iput() will be called in postproc() */ ++ hinotify = container_of(watch, struct aufs_hinotify, hin_watch); ++ DEBUG_ON(!hinotify || !hinotify->hin_aufs_inode); ++ dir = hinotify->hin_aufs_inode; ++ ++ /* force re-lookup in next d_revalidate() */ ++ if (dir->i_ino != AUFS_ROOT_INO) ++ au_iigen_dec(dir); ++ len = 0; ++ if (h_child_name && dec_gen_by_name(dir, h_child_name, mask)) ++ len = strlen(h_child_name); ++ ++ //wait_event(wq, (args = kmalloc(sizeof(*args), GFP_KERNEL))); ++ args = kmalloc(sizeof(*args) + len + 1, GFP_KERNEL); ++ if (unlikely(!args)) { ++ Err("no memory\n"); ++ return; ++ } ++ args->mask = mask; ++ args->dir = igrab(dir); ++ args->h_dir = igrab(watch->inode); ++ args->h_child_inode = NULL; ++ if (len) { ++ if (h_child_inode) ++ args->h_child_inode = igrab(h_child_inode); ++ p = (void*)args; ++ args->h_child_name = p + sizeof(*args); ++ memcpy(args->h_child_name, h_child_name, len + 1); ++ } ++ //atomic_inc(&stosi(args->dir->i_sb)->si_hinotify); ++ /* prohibit umount */ ++ au_mntget(args->dir->i_sb); ++ au_wkq_nowait(postproc, args, /*dlgt*/0); ++} ++ ++#if 0 ++void hinotify_flush(struct super_block *sb) ++{ ++ atomic_t *p = &stosi(sb)->si_hinotify; ++ wait_event(stosi(sb)->si_hinotify_wq, !atomic_read(p)); ++} ++#endif ++ ++static void aufs_inotify_destroy(struct inotify_watch *watch) ++{ ++ return; ++} ++ ++static struct inotify_operations aufs_inotify_ops = { ++ .handle_event = aufs_inotify, ++ .destroy_watch = aufs_inotify_destroy ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_inotify_init(void) ++{ ++ in_handle = inotify_init(&aufs_inotify_ops); ++ if (!IS_ERR(in_handle)) ++ return 0; ++ TraceErrPtr(in_handle); ++ return PTR_ERR(in_handle); ++} ++ ++void au_inotify_fin(void) ++{ ++ inotify_destroy(in_handle); ++} +diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c +new file mode 100755 +index 0000000..1cd0453 +--- /dev/null ++++ b/fs/aufs/i_op.c +@@ -0,0 +1,641 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: i_op.c,v 1.30 2007/04/23 00:55:05 sfjro Exp $ */ ++ ++//#include ++//#include ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_DLGT ++struct security_inode_permission_args { ++ int *errp; ++ struct inode *h_inode; ++ int mask; ++ struct nameidata *fake_nd; ++}; ++ ++static void call_security_inode_permission(void *args) ++{ ++ struct security_inode_permission_args *a = args; ++ LKTRTrace("fsuid %d\n", current->fsuid); ++ *a->errp = security_inode_permission(a->h_inode, a->mask, a->fake_nd); ++} ++#endif ++ ++static int hidden_permission(struct inode *hidden_inode, int mask, ++ struct nameidata *fake_nd, int brperm, int dlgt) ++{ ++ int err, submask; ++ const int write_mask = (mask & (MAY_WRITE | MAY_APPEND)); ++ ++ LKTRTrace("ino %lu, mask 0x%x, brperm 0x%x\n", ++ hidden_inode->i_ino, mask, brperm); ++ ++ err = -EACCES; ++ if (unlikely(write_mask && IS_IMMUTABLE(hidden_inode))) ++ goto out; ++ ++ /* skip hidden fs test in the case of write to ro branch */ ++ submask = mask & ~MAY_APPEND; ++ if (unlikely((write_mask && !br_writable(brperm)) ++ || !hidden_inode->i_op ++ || !hidden_inode->i_op->permission)) { ++ //LKTRLabel(generic_permission); ++ err = generic_permission(hidden_inode, submask, NULL); ++ } else { ++ //LKTRLabel(h_inode->permission); ++ err = hidden_inode->i_op->permission(hidden_inode, submask, ++ fake_nd); ++ TraceErr(err); ++ } ++ ++#if 1 ++ if (!err) { ++#ifndef CONFIG_AUFS_DLGT ++ err = security_inode_permission(hidden_inode, mask, fake_nd); ++#else ++ if (!dlgt) ++ err = security_inode_permission(hidden_inode, mask, ++ fake_nd); ++ else { ++ struct security_inode_permission_args args = { ++ .errp = &err, ++ .h_inode = hidden_inode, ++ .mask = mask, ++ .fake_nd = fake_nd ++ }; ++ au_wkq_wait(call_security_inode_permission, &args, ++ /*dlgt*/1); ++ } ++#endif ++ } ++#endif ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static int silly_lock(struct inode *inode, struct nameidata *nd) ++{ ++ int locked = 0; ++ struct super_block *sb = inode->i_sb; ++ ++ LKTRTrace("i%lu, nd %p\n", inode->i_ino, nd); ++ ++#ifdef CONFIG_AUFS_FAKE_DM ++ si_read_lock(sb); ++ ii_read_lock_child(inode); ++#else ++ if (!nd || !nd->dentry) { ++ si_read_lock(sb); ++ ii_read_lock_child(inode); ++ } else if (nd->dentry->d_inode != inode) { ++ locked = 1; ++ /* lock child first, then parent */ ++ si_read_lock(sb); ++ ii_read_lock_child(inode); ++ di_read_lock_parent(nd->dentry, 0); ++ } else { ++ locked = 2; ++ aufs_read_lock(nd->dentry, AUFS_I_RLOCK); ++ } ++#endif ++ return locked; ++} ++ ++static void silly_unlock(int locked, struct inode *inode, struct nameidata *nd) ++{ ++ struct super_block *sb = inode->i_sb; ++ ++ LKTRTrace("locked %d, i%lu, nd %p\n", locked, inode->i_ino, nd); ++ ++#ifdef CONFIG_AUFS_FAKE_DM ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++#else ++ switch (locked) { ++ case 0: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ break; ++ case 1: ++ di_read_unlock(nd->dentry, 0); ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ break; ++ case 2: ++ aufs_read_unlock(nd->dentry, AUFS_I_RLOCK); ++ break; ++ default: ++ BUG(); ++ } ++#endif ++} ++ ++static int aufs_permission(struct inode *inode, int mask, struct nameidata *nd) ++{ ++ int err, locked, dlgt; ++ aufs_bindex_t bindex, bend; ++ struct inode *hidden_inode; ++ struct super_block *sb; ++ struct nameidata fake_nd, *p; ++ const int write_mask = (mask & (MAY_WRITE | MAY_APPEND)); ++ const int nondir = !S_ISDIR(inode->i_mode); ++ ++ LKTRTrace("ino %lu, mask 0x%x, nondir %d, write_mask %d, " ++ "nd %p{%p, %p}\n", ++ inode->i_ino, mask, nondir, write_mask, ++ nd, nd ? nd->dentry : NULL, nd ? nd->mnt : NULL); ++ ++ sb = inode->i_sb; ++ locked = silly_lock(inode, nd); ++ dlgt = need_dlgt(sb); ++ ++ if (nd) ++ fake_nd = *nd; ++ if (/* unlikely */(nondir || write_mask)) { ++ hidden_inode = au_h_iptr(inode); ++ DEBUG_ON(!hidden_inode ++ || ((hidden_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))); ++ err = 0; ++ bindex = ibstart(inode); ++ p = fake_dm(&fake_nd, nd, sb, bindex); ++ /* actual test will be delegated to LSM */ ++ if (IS_ERR(p)) ++ DEBUG_ON(PTR_ERR(p) != -ENOENT); ++ else { ++ err = hidden_permission(hidden_inode, mask, p, ++ sbr_perm(sb, bindex), dlgt); ++ fake_dm_release(p); ++ } ++ if (write_mask && !err) { ++ err = find_rw_br(sb, bindex); ++ if (err >= 0) ++ err = 0; ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bend = ibend(inode); ++ for (bindex = ibstart(inode); !err && bindex <= bend; bindex++) { ++ hidden_inode = au_h_iptr_i(inode, bindex); ++ if (!hidden_inode) ++ continue; ++ DEBUG_ON(!S_ISDIR(hidden_inode->i_mode)); ++ ++ p = fake_dm(&fake_nd, nd, sb, bindex); ++ /* actual test will be delegated to LSM */ ++ if (IS_ERR(p)) ++ DEBUG_ON(PTR_ERR(p) != -ENOENT); ++ else { ++ err = hidden_permission(hidden_inode, mask, p, ++ sbr_perm(sb, bindex), dlgt); ++ fake_dm_release(p); ++ } ++ } ++ ++ out: ++ silly_unlock(locked, inode, nd); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ struct dentry *ret, *parent; ++ int err, npositive; ++ struct inode *inode; ++ ++ LKTRTrace("dir %lu, %.*s\n", dir->i_ino, DLNPair(dentry)); ++ DEBUG_ON(IS_ROOT(dentry)); ++ IMustLock(dir); ++ ++ parent = dentry->d_parent; // dget_parent() ++ aufs_read_lock(parent, !AUFS_I_RLOCK); ++ err = au_alloc_dinfo(dentry); ++ //if (LktrCond) err = -1; ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = npositive = lkup_dentry(dentry, dbstart(parent), /*type*/0); ++ //err = -1; ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ inode = NULL; ++ if (npositive) { ++ inode = au_new_inode(dentry); ++ ret = (void*)inode; ++ } ++ if (!IS_ERR(inode)) { ++#if 1 ++ /* d_splice_alias() also supports d_add() */ ++ ret = d_splice_alias(inode, dentry); ++ if (unlikely(IS_ERR(ret) && inode)) ++ ii_write_unlock(inode); ++#else ++ d_add(dentry, inode); ++#endif ++ } ++ ++ out_unlock: ++ di_write_unlock(dentry); ++ out: ++ aufs_read_unlock(parent, !AUFS_I_RLOCK); ++ TraceErrPtr(ret); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int wr_dir(struct dentry *dentry, int add_entry, struct dentry *src_dentry, ++ aufs_bindex_t force_btgt, int do_lock_srcdir) ++{ ++ int err; ++ aufs_bindex_t bcpup, bstart, src_bstart; ++ struct dentry *hidden_parent; ++ struct super_block *sb; ++ struct dentry *parent, *src_parent = NULL; ++ struct inode *dir, *src_dir = NULL; ++ ++ LKTRTrace("%.*s, add %d, src %p, force %d, lock_srcdir %d\n", ++ DLNPair(dentry), add_entry, src_dentry, force_btgt, ++ do_lock_srcdir); ++ ++ sb = dentry->d_sb; ++ parent = dentry->d_parent; // dget_parent() ++ bcpup = bstart = dbstart(dentry); ++ if (force_btgt < 0) { ++ if (src_dentry) { ++ src_bstart = dbstart(src_dentry); ++ if (src_bstart < bstart) ++ bcpup = src_bstart; ++ } ++ if (test_ro(sb, bcpup, dentry->d_inode)) { ++ if (!add_entry) ++ di_read_lock_parent(parent, !AUFS_I_RLOCK); ++ bcpup = err = find_rw_parent_br(dentry, bcpup); ++ //bcpup = err = find_rw_br(sb, bcpup); ++ if (!add_entry) ++ di_read_unlock(parent, !AUFS_I_RLOCK); ++ //err = -1; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ DEBUG_ON(bstart <= force_btgt ++ || test_ro(sb, force_btgt, dentry->d_inode)); ++ bcpup = force_btgt; ++ } ++ LKTRTrace("bstart %d, bcpup %d\n", bstart, bcpup); ++ ++ err = bcpup; ++ if (bcpup == bstart) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ hidden_parent = au_h_dptr(dentry)->d_parent; // dget_parent() ++ if (src_dentry) { ++ src_parent = src_dentry->d_parent; // dget_parent() ++ src_dir = src_parent->d_inode; ++ if (do_lock_srcdir) ++ di_write_lock_parent2(src_parent); ++ } ++ ++ dir = parent->d_inode; ++ if (add_entry) { ++ au_update_dbstart(dentry); ++ IMustLock(dir); ++ DiMustWriteLock(parent); ++ IiMustWriteLock(dir); ++ } else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr_i(parent, bcpup)) ++ err = cpup_dirs(dentry, bcpup, src_parent); ++ //err = -1; ++ if (!err && add_entry) { ++ hidden_parent = au_h_dptr_i(parent, bcpup); ++ DEBUG_ON(!hidden_parent || !hidden_parent->d_inode); ++ hi_lock_parent(hidden_parent->d_inode); ++ err = lkup_neg(dentry, bcpup); ++ //err = -1; ++ i_unlock(hidden_parent->d_inode); ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (do_lock_srcdir) ++ di_write_unlock(src_parent); ++ if (!err) ++ err = bcpup; /* success */ ++ //err = -EPERM; ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_setattr(struct dentry *dentry, struct iattr *ia) ++{ ++ int err, isdir; ++ aufs_bindex_t bstart, bcpup; ++ struct inode *hidden_inode, *inode, *dir, *h_dir, *gh_dir, *gdir; ++ struct dentry *hidden_dentry, *parent; ++ unsigned int udba; ++ ++ LKTRTrace("%.*s, ia_valid 0x%x\n", DLNPair(dentry), ia->ia_valid); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ bstart = dbstart(dentry); ++ bcpup = err = wr_dir(dentry, /*add*/0, /*src_dentry*/NULL, ++ /*force_btgt*/-1, /*do_lock_srcdir*/0); ++ //err = -1; ++ if (unlikely(err < 0)) ++ goto out; ++ ++ /* crazy udba locks */ ++ udba = au_flag_test(dentry->d_sb, AuFlag_UDBA_INOTIFY); ++ parent = NULL; ++ gdir = gh_dir = dir = h_dir = NULL; ++ if ((udba || bstart != bcpup) && !IS_ROOT(dentry)) { ++ parent = dentry->d_parent; // dget_parent() ++ dir = parent->d_inode; ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ h_dir = au_h_iptr_i(dir, bcpup); ++ } ++ if (parent) { ++ if (unlikely(udba && !IS_ROOT(parent))) { ++ gdir = parent->d_parent->d_inode; // dget_parent() ++ ii_read_lock_parent2(gdir); ++ gh_dir = au_h_iptr_i(gdir, bcpup); ++ hgdir_lock(gh_dir, gdir, bcpup); ++ } ++ hdir_lock(h_dir, dir, bcpup); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ hidden_dentry = au_h_dptr(dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode); ++ ++#define HiLock(bindex) do {\ ++ if (!isdir) \ ++ hi_lock_child(hidden_inode); \ ++ else \ ++ hdir2_lock(hidden_inode, inode, bindex); \ ++ } while (0) ++#define HiUnlock(bindex) do {\ ++ if (!isdir) \ ++ i_unlock(hidden_inode); \ ++ else \ ++ hdir_unlock(hidden_inode, inode, bindex); \ ++ } while (0) ++ ++ if (bstart != bcpup) { ++ loff_t size = -1; ++ ++ if ((ia->ia_valid & ATTR_SIZE) ++ && ia->ia_size < i_size_read(inode)) { ++ size = ia->ia_size; ++ ia->ia_valid &= ~ATTR_SIZE; ++ } ++ HiLock(bstart); ++ err = sio_cpup_simple(dentry, bcpup, size, ++ au_flags_cpup(CPUP_DTIME, parent)); ++ //err = -1; ++ HiUnlock(bstart); ++ if (unlikely(err || !ia->ia_valid)) ++ goto out_unlock; ++ ++ hidden_dentry = au_h_dptr(dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode); ++ } ++ ++ HiLock(bcpup); ++ err = vfsub_notify_change(hidden_dentry, ia, need_dlgt(dentry->d_sb)); ++ //err = -1; ++ if (!err) ++ au_cpup_attr_changable(inode); ++ HiUnlock(bcpup); ++#undef HiLock ++#undef HiUnlock ++ ++ out_unlock: ++ if (parent) { ++ hdir_unlock(h_dir, dir, bcpup); ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ } ++ if (unlikely(gdir)) { ++ hdir_unlock(gh_dir, gdir, bcpup); ++ ii_read_unlock(gdir); ++ } ++ out: ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hidden_readlink(struct dentry *dentry, int bindex, ++ char __user * buf, int bufsiz) ++{ ++ struct super_block *sb; ++ struct dentry *hidden_dentry; ++ ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (unlikely(!hidden_dentry->d_inode->i_op ++ || !hidden_dentry->d_inode->i_op->readlink)) ++ return -EINVAL; ++ ++ sb = dentry->d_sb; ++ if (!test_ro(sb, bindex, dentry->d_inode)) { ++ touch_atime(sbr_mnt(sb, bindex), hidden_dentry); ++ dentry->d_inode->i_atime = hidden_dentry->d_inode->i_atime; ++ } ++ return hidden_dentry->d_inode->i_op->readlink ++ (hidden_dentry, buf, bufsiz); ++} ++ ++static int aufs_readlink(struct dentry *dentry, char __user * buf, int bufsiz) ++{ ++ int err; ++ ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), bufsiz); ++ ++ aufs_read_lock(dentry, AUFS_I_RLOCK); ++ err = hidden_readlink(dentry, dbstart(dentry), buf, bufsiz); ++ //err = -1; ++ aufs_read_unlock(dentry, AUFS_I_RLOCK); ++ TraceErr(err); ++ return err; ++} ++ ++static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ int err; ++ char *buf; ++ mm_segment_t old_fs; ++ ++ LKTRTrace("%.*s, nd %.*s\n", DLNPair(dentry), DLNPair(nd->dentry)); ++ ++ err = -ENOMEM; ++ buf = __getname(); ++ //buf = NULL; ++ if (unlikely(!buf)) ++ goto out; ++ ++ aufs_read_lock(dentry, AUFS_I_RLOCK); ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = hidden_readlink(dentry, dbstart(dentry), (char __user *)buf, ++ PATH_MAX); ++ //err = -1; ++ set_fs(old_fs); ++ aufs_read_unlock(dentry, AUFS_I_RLOCK); ++ ++ if (err >= 0) { ++ buf[err] = 0; ++ /* will be freed by put_link */ ++ nd_set_link(nd, buf); ++ return NULL; /* success */ ++ } ++ __putname(buf); ++ ++ out: ++ path_release(nd); ++ TraceErr(err); ++ return ERR_PTR(err); ++} ++ ++static void aufs_put_link(struct dentry *dentry, struct nameidata *nd, ++ void *cookie) ++{ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ __putname(nd_get_link(nd)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++#if 0 // comment ++struct inode_operations { ++ int (*create) (struct inode *,struct dentry *,int, struct nameidata *); ++ struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); ++ int (*link) (struct dentry *,struct inode *,struct dentry *); ++ int (*unlink) (struct inode *,struct dentry *); ++ int (*symlink) (struct inode *,struct dentry *,const char *); ++ int (*mkdir) (struct inode *,struct dentry *,int); ++ int (*rmdir) (struct inode *,struct dentry *); ++ int (*mknod) (struct inode *,struct dentry *,int,dev_t); ++ int (*rename) (struct inode *, struct dentry *, ++ struct inode *, struct dentry *); ++ int (*readlink) (struct dentry *, char __user *,int); ++ void * (*follow_link) (struct dentry *, struct nameidata *); ++ void (*put_link) (struct dentry *, struct nameidata *, void *); ++ void (*truncate) (struct inode *); ++ int (*permission) (struct inode *, int, struct nameidata *); ++ int (*setattr) (struct dentry *, struct iattr *); ++ int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); ++ int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); ++ ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); ++ ssize_t (*listxattr) (struct dentry *, char *, size_t); ++ int (*removexattr) (struct dentry *, const char *); ++ void (*truncate_range)(struct inode *, loff_t, loff_t); ++}; ++#endif ++ ++struct inode_operations aufs_symlink_iop = { ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ ++ .readlink = aufs_readlink, ++ .follow_link = aufs_follow_link, ++ .put_link = aufs_put_link ++}; ++ ++//i_op_add.c ++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev); ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); ++int aufs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode); ++ ++//i_op_del.c ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++// i_op_ren.c ++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry); ++ ++struct inode_operations aufs_dir_iop = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ ++#if 0 // xattr ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr ++#endif ++}; ++ ++struct inode_operations aufs_iop = { ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ ++#if 0 // xattr ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr ++#endif ++}; +diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c +new file mode 100755 +index 0000000..977d773 +--- /dev/null ++++ b/fs/aufs/i_op_add.c +@@ -0,0 +1,621 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: i_op_add.c,v 1.37 2007/05/07 03:46:08 sfjro Exp $ */ ++ ++//#include ++//#include ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct inode *inode, *dir; ++ struct dentry *wh; ++ struct lkup_args lkup; ++ ++ LKTRTrace("wh %p, %.*s\n", wh_dentry, DLNPair(dentry)); ++ ++ lkup.dlgt = need_dlgt(dentry->d_sb); ++ bwh = -1; ++ if (wh_dentry) { ++ bwh = dbwh(dentry); ++ err = au_unlink_wh_dentry(wh_dentry->d_parent->d_inode, ++ wh_dentry, dentry, lkup.dlgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry); ++ //inode = ERR_PTR(-1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = dentry->d_parent->d_inode; ++ /* or always cpup dir mtime? */ ++ if (ibstart(dir) == dbstart(dentry)) ++ au_cpup_attr_timesizes(dir); ++ dir->i_version++; ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ lkup.nfsmnt = au_nfsmnt(dentry->d_sb, bwh); ++ wh = simple_create_wh(dentry, bwh, wh_dentry->d_parent, &lkup); ++ //wh = ERR_PTR(-1); ++ rerr = PTR_ERR(wh); ++ if (!IS_ERR(wh)) { ++ dput(wh); ++ goto out; ++ } ++ IOErr("%.*s reverting whiteout failed(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ err = -EIO; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * lookup whiteout for the new entry. ++ */ ++static struct dentry * ++lock_hdir_lkup_wh(struct dentry *dentry, struct dtime *dt, ++ struct dentry *src_dentry, int do_lock_srcdir) ++{ ++ struct dentry *wh_dentry, *parent, *hidden_parent; ++ int err; ++ aufs_bindex_t bstart, bcpup; ++ struct inode *dir, *h_dir; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, src %p\n", DLNPair(dentry), src_dentry); ++ ++ parent = dentry->d_parent; ++ bstart = dbstart(dentry); ++ bcpup = err = wr_dir(dentry, 1, src_dentry, -1, do_lock_srcdir); ++ //err = -1; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ dir = parent->d_inode; ++ hidden_parent = au_h_dptr_i(parent, bcpup); ++ h_dir = hidden_parent->d_inode; ++ hdir_lock(h_dir, dir, bcpup); ++ if (dt) ++ dtime_store(dt, parent, hidden_parent); ++ if (/* bcpup != bstart || */ bcpup != dbwh(dentry)) ++ return NULL; /* success */ ++ ++ lkup.nfsmnt = au_nfsmnt(parent->d_sb, bcpup); ++ lkup.dlgt = need_dlgt(parent->d_sb); ++ wh_dentry = lkup_wh(hidden_parent, &dentry->d_name, &lkup); ++ //wh_dentry = ERR_PTR(-1); ++ if (IS_ERR(wh_dentry)) ++ hdir_unlock(h_dir, dir, bcpup); ++ ++ out: ++ TraceErrPtr(wh_dentry); ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum {Mknod, Symlink, Creat}; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ int mode; ++ struct nameidata *nd; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ int mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, dlgt; ++ struct dentry *hidden_dentry, *hidden_parent, *wh_dentry, *parent; ++ struct inode *hidden_dir; ++ struct dtime dt; ++ ++ LKTRTrace("type %d, %.*s\n", arg->type, DLNPair(dentry)); ++ IMustLock(dir); ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ parent = dentry->d_parent; ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, ++ /*do_lock_srcdir*/0); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ hidden_dentry = au_h_dptr(dentry); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ dlgt = need_dlgt(dir->i_sb); ++ ++#if 1 // partial testing ++ switch (arg->type) { ++ case Creat: ++#if 0 ++ if (arg->u.c.nd) { ++ struct nameidata fake_nd; ++ fake_nd = *arg->u.c.nd; ++ fake_nd.dentry = dget(hidden_parent); ++ fake_nd.mnt = sbr_mnt(dentry->d_sb, dbstart(dentry)); ++ mntget(fake_nd.mnt); ++ err = vfsub_create(hidden_dir, hidden_dentry, ++ arg->u.c.mode, &fake_nd, dlgt); ++ path_release(&fake_nd); ++ } else ++#endif ++ err = vfsub_create(hidden_dir, hidden_dentry, ++ arg->u.c.mode, NULL, dlgt); ++ break; ++ case Symlink: ++ err = vfsub_symlink(hidden_dir, hidden_dentry, ++ arg->u.s.symname, S_IALLUGO, dlgt); ++ break; ++ case Mknod: ++ err = vfsub_mknod(hidden_dir, hidden_dentry, ++ arg->u.m.mode, arg->u.m.dev, dlgt); ++ break; ++ default: ++ BUG(); ++ } ++#else ++ err = -1; ++#endif ++ if (!err) ++ err = epilog(wh_dentry, dentry); ++ //err = -1; ++ ++ /* revert */ ++ if (unlikely(err && hidden_dentry->d_inode)) { ++ int rerr; ++ rerr = vfsub_unlink(hidden_dir, hidden_dentry, dlgt); ++ //rerr = -1; ++ if (rerr) { ++ IOErr("%.*s revert failure(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ dtime_revert(&dt, !CPUP_LOCKED_GHDIR); ++ d_drop(dentry); ++ } ++ ++ hdir_unlock(hidden_dir, dir, dbstart(dentry)); ++ dput(wh_dentry); ++ ++ out: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = {.mode = mode, .dev = dev} ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = {.mode = mode, .nd = nd} ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct link_arg { ++ aufs_bindex_t bdst, bsrc; ++ int issamedir, dlgt; ++ struct dentry *src_parent, *parent, *hidden_dentry; ++ struct inode *hidden_dir, *inode; ++}; ++ ++static int cpup_before_link(struct dentry *src_dentry, struct inode *dir, ++ struct link_arg *a) ++{ ++ int err; ++ unsigned int flags; ++ struct inode *hi, *hdir = NULL, *src_dir; ++ ++ TraceEnter(); ++ ++ err = 0; ++ flags = au_flags_cpup(CPUP_DTIME, a->parent); ++ src_dir = a->src_parent->d_inode; ++ if (!a->issamedir) { ++ // todo: dead lock? ++ di_read_lock_parent2(a->src_parent, AUFS_I_RLOCK); ++ // this temporary unlock/lock is safe ++ hdir_unlock(a->hidden_dir, dir, a->bdst); ++ err = test_and_cpup_dirs(src_dentry, a->bdst, a->parent); ++ //err = -1; ++ if (!err) { ++ hdir = au_h_iptr_i(src_dir, a->bdst); ++ hdir_lock(hdir, src_dir, a->bdst); ++ flags = au_flags_cpup(CPUP_DTIME, a->src_parent); ++ } ++ } ++ ++ if (!err) { ++ hi = au_h_dptr(src_dentry)->d_inode; ++ hi_lock_child(hi); ++ err = sio_cpup_simple(src_dentry, a->bdst, -1, flags); ++ //err = -1; ++ i_unlock(hi); ++ } ++ ++ if (!a->issamedir) { ++ if (hdir) ++ hdir_unlock(hdir, src_dir, a->bdst); ++ hdir_lock(a->hidden_dir, dir, a->bdst); ++ di_read_unlock(a->src_parent, AUFS_I_RLOCK); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int cpup_or_link(struct dentry *src_dentry, struct link_arg *a) ++{ ++ int err; ++ struct inode *inode, *h_inode, *h_dst_inode; ++ struct dentry *h_dentry; ++ aufs_bindex_t bstart; ++ struct super_block *sb; ++ ++ TraceEnter(); ++ ++ sb = src_dentry->d_sb; ++ inode = src_dentry->d_inode; ++ h_dentry = au_h_dptr(src_dentry); ++ h_inode = h_dentry->d_inode; ++ bstart = ibstart(inode); ++ h_dst_inode = NULL; ++ if (bstart <= a->bdst) ++ h_dst_inode = au_h_iptr_i(inode, a->bdst); ++ ++ if (!h_dst_inode) { ++ /* copyup src_dentry as the name of dentry. */ ++ set_dbstart(src_dentry, a->bdst); ++ set_h_dptr(src_dentry, a->bdst, dget(a->hidden_dentry)); ++ hi_lock_child(h_inode); ++ err = sio_cpup_single(src_dentry, a->bdst, a->bsrc, -1, ++ au_flags_cpup(!CPUP_DTIME, a->parent)); ++ //err = -1; ++ i_unlock(h_inode); ++ set_h_dptr(src_dentry, a->bdst, NULL); ++ set_dbstart(src_dentry, a->bsrc); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_dentry = d_find_alias(h_dst_inode); ++ if (h_dentry) { ++ err = vfsub_link(h_dentry, a->hidden_dir, ++ a->hidden_dentry, a->dlgt); ++ dput(h_dentry); ++ } else { ++ IOErr("no dentry found for i%lu on b%d\n", ++ h_dst_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err) ++ append_plink(sb, a->inode, a->hidden_dentry, a->bdst); ++ ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct dentry *hidden_parent, *wh_dentry, *hidden_src_dentry; ++ struct dtime dt; ++ struct link_arg a; ++ struct super_block *sb; ++ ++ LKTRTrace("src %.*s, i%lu, dst %.*s\n", ++ DLNPair(src_dentry), dir->i_ino, DLNPair(dentry)); ++ IMustLock(dir); ++ IMustLock(src_dentry->d_inode); ++ ++ aufs_read_and_write_lock2(dentry, src_dentry, /*isdir*/0); ++ a.src_parent = src_dentry->d_parent; ++ a.parent = dentry->d_parent; ++ a.issamedir = (a.src_parent == a.parent); ++ di_write_lock_parent(a.parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, !a.issamedir); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ a.inode = src_dentry->d_inode; ++ a.hidden_dentry = au_h_dptr(dentry); ++ hidden_parent = a.hidden_dentry->d_parent; ++ a.hidden_dir = hidden_parent->d_inode; ++ IMustLock(a.hidden_dir); ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a.dlgt = need_dlgt(sb); ++ ++ //todo: minor optimize, their sb may be same while their bindex differs. ++ a.bsrc = dbstart(src_dentry); ++ a.bdst = dbstart(dentry); ++ hidden_src_dentry = au_h_dptr(src_dentry); ++ if (unlikely(!au_flag_test(sb, AuFlag_PLINK))) { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ * gave up 'pseudo link by cpup' approach, ++ * since nlink may be one and some applications will not work. ++ */ ++ if (a.bdst < a.bsrc ++ /* && hidden_src_dentry->d_sb != a.hidden_dentry->d_sb */) ++ err = cpup_before_link(src_dentry, dir, &a); ++ if (!err) { ++ hidden_src_dentry = au_h_dptr(src_dentry); ++ err = vfsub_link(hidden_src_dentry, a.hidden_dir, ++ a.hidden_dentry, a.dlgt); ++ //err = -1; ++ } ++ } else { ++ if (a.bdst < a.bsrc ++ /* && hidden_src_dentry->d_sb != a.hidden_dentry->d_sb */) ++ err = cpup_or_link(src_dentry, &a); ++ else { ++ hidden_src_dentry = au_h_dptr(src_dentry); ++ err = vfsub_link(hidden_src_dentry, a.hidden_dir, ++ a.hidden_dentry, a.dlgt); ++ //err = -1; ++ } ++ } ++ if (unlikely(err)) ++ goto out_unlock; ++ if (wh_dentry) { ++ err = au_unlink_wh_dentry(a.hidden_dir, wh_dentry, dentry, ++ a.dlgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ dir->i_version++; ++ if (ibstart(dir) == dbstart(dentry)) ++ au_cpup_attr_timesizes(dir); ++ if (!d_unhashed(a.hidden_dentry) ++ /* || hidden_old_inode->i_nlink <= nlink */ ++ /* || SB_NFS(hidden_src_dentry->d_sb) */) { ++ dentry->d_inode = igrab(a.inode); ++ d_instantiate(dentry, a.inode); ++ a.inode->i_nlink++; ++ a.inode->i_ctime = dir->i_ctime; ++ } else ++ /* nfs case (< 2.6.15) */ ++ d_drop(dentry); ++#if 0 ++ au_debug_on(); ++ DbgInode(a.inode); ++ au_debug_off(); ++ { ++ aufs_bindex_t i; ++ for (i = ibstart(a.inode); i <= ibend(a.inode); i++) { ++ struct xino xino; ++ struct inode *hi; ++ hi = au_h_iptr_i(a.inode, i); ++ if (hi) { ++ xino_read(sb, i, hi->i_ino, &xino); ++ Dbg("hi%lu, i%lu\n", hi->i_ino, xino.ino); ++ } ++ } ++ } ++#endif ++ goto out_unlock; /* success */ ++ ++ out_revert: ++#if 0 // remove ++ if (d_unhashed(a.hidden_dentry)) { ++ /* hardlink on nfs (< 2.6.15) */ ++ struct dentry *d; ++ const struct qstr *name = &a.hidden_dentry->d_name; ++ DEBUG_ON(a.hidden_dentry->d_parent->d_inode != a.hidden_dir); ++ // do not superio. ++ d = lkup_one(name->name, a.hidden_dentry->d_parent, name->len, ++ au_nfsmnt(sb, a.bdst)??, need_dlgt(sb)); ++ rerr = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out_rerr; ++ dput(a.hidden_dentry); ++ a.hidden_dentry = d; ++ DEBUG_ON(!d->d_inode); ++ } ++#endif ++ rerr = vfsub_unlink(a.hidden_dir, a.hidden_dentry, a.dlgt); ++ //rerr = -1; ++ if (!rerr) ++ goto out_dt; ++// out_rerr: ++ IOErr("%.*s reverting failed(%d, %d)\n", DLNPair(dentry), err, rerr); ++ err = -EIO; ++ out_dt: ++ d_drop(dentry); ++ dtime_revert(&dt, !CPUP_LOCKED_GHDIR); ++ out_unlock: ++ hdir_unlock(a.hidden_dir, dir, a.bdst); ++ dput(wh_dentry); ++ out: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(a.parent); ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ int err, rerr, diropq, dlgt; ++ struct dentry *hidden_dentry, *hidden_parent, *wh_dentry, *parent, ++ *opq_dentry; ++ struct inode *hidden_dir, *hidden_inode; ++ struct dtime dt; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ ++ LKTRTrace("i%lu, %.*s, mode 0%o\n", dir->i_ino, DLNPair(dentry), mode); ++ IMustLock(dir); ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ parent = dentry->d_parent; ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, ++ /*do_lock_srcdir*/0); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ bindex = dbstart(dentry); ++ hidden_dentry = au_h_dptr(dentry); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ dlgt = need_dlgt(sb); ++ ++ err = vfsub_mkdir(hidden_dir, hidden_dentry, mode, dlgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ hidden_inode = hidden_dentry->d_inode; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ if (unlikely(wh_dentry || au_flag_test(sb, AuFlag_ALWAYS_DIROPQ))) { ++ hi_lock_child(hidden_inode); ++ opq_dentry = create_diropq(dentry, bindex, dlgt); ++ //opq_dentry = ERR_PTR(-1); ++ i_unlock(hidden_inode); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(wh_dentry, dentry); ++ //err = -1; ++ if (!err) { ++ dir->i_nlink++; ++ goto out_unlock; /* success */ ++ } ++ ++ /* revert */ ++ if (unlikely(diropq)) { ++ LKTRLabel(revert opq); ++ hi_lock_child(hidden_inode); ++ rerr = remove_diropq(dentry, bindex, dlgt); ++ //rerr = -1; ++ i_unlock(hidden_inode); ++ if (rerr) { ++ IOErr("%.*s reverting diropq failed(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ } ++ ++ out_dir: ++ LKTRLabel(revert dir); ++ rerr = vfsub_rmdir(hidden_dir, hidden_dentry, dlgt); ++ //rerr = -1; ++ if (rerr) { ++ IOErr("%.*s reverting dir failed(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ d_drop(dentry); ++ dtime_revert(&dt, /*fake flag*/CPUP_LOCKED_GHDIR); ++ out_unlock: ++ hdir_unlock(hidden_dir, dir, bindex); ++ dput(wh_dentry); ++ out: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ TraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c +new file mode 100755 +index 0000000..f29b204 +--- /dev/null ++++ b/fs/aufs/i_op_del.c +@@ -0,0 +1,414 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: i_op_del.c,v 1.35 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++/* returns, ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup, ++ struct dentry *locked) ++{ ++ int need_wh, err; ++ aufs_bindex_t bstart; ++ struct dentry *hidden_dentry; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, isdir %d, *bcpup %d, locked %p\n", ++ DLNPair(dentry), isdir, *bcpup, locked); ++ sb = dentry->d_sb; ++ ++ bstart = dbstart(dentry); ++ LKTRTrace("bcpup %d, bstart %d\n", *bcpup, bstart); ++ hidden_dentry = au_h_dptr(dentry); ++ if (*bcpup < 0) { ++ *bcpup = bstart; ++ if (test_ro(sb, bstart, dentry->d_inode)) { ++ *bcpup = err = find_rw_parent_br(dentry, bstart); ++ //*bcpup = err = find_rw_br(sb, bstart); ++ //err = -1; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ /* braces are added to stop a warning */ ++ DEBUG_ON(bstart < *bcpup ++ || test_ro(sb, *bcpup, dentry->d_inode)); ++ } ++ LKTRTrace("bcpup %d, bstart %d\n", *bcpup, bstart); ++ ++ if (*bcpup != bstart) { ++ err = cpup_dirs(dentry, *bcpup, locked); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ //struct nameidata nd; ++ aufs_bindex_t old_bend, new_bend, bdiropq = -1; ++ old_bend = dbend(dentry); ++ if (isdir) { ++ bdiropq = dbdiropq(dentry); ++ set_dbdiropq(dentry, -1); ++ } ++ err = need_wh = lkup_dentry(dentry, bstart + 1, /*type*/0); ++ //err = -1; ++ if (isdir) ++ set_dbdiropq(dentry, bdiropq); ++ if (unlikely(err < 0)) ++ goto out; ++ new_bend = dbend(dentry); ++ if (!need_wh && old_bend != new_bend) { ++ set_h_dptr(dentry, new_bend, NULL); ++ set_dbend(dentry, old_bend); ++#if 0 ++ } else if (!au_h_dptr_i(dentry, new_bend)->d_inode) { ++ LKTRTrace("negative\n"); ++ set_h_dptr(dentry, new_bend, NULL); ++ set_dbend(dentry, old_bend); ++ need_wh = 0; ++#endif ++ } ++ } ++ LKTRTrace("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static struct dentry * ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup, ++ struct dtime *dt) ++{ ++ struct dentry *wh_dentry; ++ int err, need_wh; ++ struct dentry *hidden_parent, *parent; ++ struct inode *dir, *h_dir; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, isdir %d\n", DLNPair(dentry), isdir); ++ ++ err = need_wh = wr_dir_need_wh(dentry, isdir, bcpup, NULL); ++ //err = -1; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ parent = dentry->d_parent; ++ dir = parent->d_inode; ++ hidden_parent = au_h_dptr_i(parent, *bcpup); ++ h_dir = hidden_parent->d_inode; ++ hdir_lock(h_dir, dir, *bcpup); ++ dtime_store(dt, parent, hidden_parent); ++ if (!need_wh) ++ return NULL; /* success, no need to create whiteout */ ++ ++ lkup.nfsmnt = au_nfsmnt(dentry->d_sb, *bcpup); ++ lkup.dlgt = need_dlgt(dentry->d_sb); ++ wh_dentry = simple_create_wh(dentry, *bcpup, hidden_parent, &lkup); ++ //wh_dentry = ERR_PTR(-1); ++ if (!IS_ERR(wh_dentry)) ++ goto out; /* success */ ++ /* returns with the parent is locked and wh_dentry is DGETed */ ++ ++ hdir_unlock(h_dir, dir, *bcpup); ++ ++ out: ++ TraceErrPtr(wh_dentry); ++ return wh_dentry; ++} ++ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct aufs_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err; ++ struct dentry *hidden_dentry; ++ ++ LKTRTrace("%.*s, b%d\n", DLNPair(dentry), bindex); ++ ++ err = rename_whtmp(dentry, bindex); ++ //err = -1; ++#if 0 ++ //todo: bug ++ if (unlikely(err)) { ++ au_direval_inc(dentry->d_parent); ++ return err; ++ } ++#endif ++ ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!au_is_nfs(hidden_dentry->d_sb)) { ++ const int dirwh = stosi(dentry->d_sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = is_longer_wh(whlist, bindex, dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = rmdir_whtmp(hidden_dentry, whlist, bindex, dir, dentry->d_inode); ++ //err = -1; ++ if (unlikely(err)) { ++ IOErr("rmdir %.*s, b%d failed, %d. ignored\n", ++ DLNPair(hidden_dentry), bindex, err); ++ err = 0; ++ } ++ TraceErr(err); ++ return err; ++} ++ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ d_drop(dentry); ++ dentry->d_inode->i_ctime = dir->i_ctime; ++ if (atomic_read(&dentry->d_count) == 1) { ++ set_h_dptr(dentry, dbstart(dentry), NULL); ++ au_update_dbstart(dentry); ++ } ++ if (ibstart(dir) == bindex) ++ au_cpup_attr_timesizes(dir); ++ dir->i_version++; ++} ++ ++static int do_revert(int err, struct dentry *wh_dentry, struct dentry *dentry, ++ aufs_bindex_t bwh, struct dtime *dt, int dlgt) ++{ ++ int rerr; ++ ++ rerr = au_unlink_wh_dentry(wh_dentry->d_parent->d_inode, wh_dentry, ++ dentry, dlgt); ++ //rerr = -1; ++ if (!rerr) { ++ set_dbwh(dentry, bwh); ++ dtime_revert(dt, !CPUP_LOCKED_GHDIR); ++ return 0; ++ } ++ ++ IOErr("%.*s reverting whiteout failed(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err, dlgt; ++ struct inode *inode, *hidden_dir; ++ struct dentry *parent, *wh_dentry, *hidden_dentry, *hidden_parent; ++ struct dtime dt; ++ aufs_bindex_t bwh, bindex, bstart; ++ struct super_block *sb; ++ ++ LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry)); ++ IMustLock(dir); ++ inode = dentry->d_inode; ++ if (unlikely(!inode)) ++ return -ENOENT; // possible? ++ IMustLock(inode); ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ parent = dentry->d_parent; ++ di_write_lock_parent(parent); ++ ++ bstart = dbstart(dentry); ++ bwh = dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ sb = dir->i_sb; ++ dlgt = need_dlgt(sb); ++ hidden_dentry = au_h_dptr(dentry); ++ dget(hidden_dentry); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ ++ if (bindex == bstart) { ++ err = vfsub_unlink(hidden_dir, hidden_dentry, dlgt); ++ //err = -1; ++ } else { ++ DEBUG_ON(!wh_dentry); ++ hidden_parent = wh_dentry->d_parent; ++ DEBUG_ON(hidden_parent != au_h_dptr_i(parent, bindex)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ inode->i_nlink--; ++ epilog(dir, dentry, bindex); ++#if 0 ++ xino_write0(sb, bstart, hidden_dentry->d_inode->i_ino); ++ /* ignore this error */ ++#endif ++ goto out_unlock; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ rerr = do_revert(err, wh_dentry, dentry, bwh, &dt, dlgt); ++ if (rerr) ++ err = rerr; ++ } ++ ++ out_unlock: ++ hdir_unlock(hidden_dir, dir, bindex); ++ dput(wh_dentry); ++ dput(hidden_dentry); ++ out: ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ struct inode *inode, *hidden_dir; ++ struct dentry *parent, *wh_dentry, *hidden_dentry, *hidden_parent; ++ struct dtime dt; ++ aufs_bindex_t bwh, bindex, bstart; ++ struct rmdir_whtmp_arg *arg; ++ struct aufs_nhash *whlist; ++ struct super_block *sb; ++ ++ LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry)); ++ IMustLock(dir); ++ inode = dentry->d_inode; ++ if (unlikely(!inode)) ++ return -ENOENT; // possible? ++ IMustLock(inode); ++ ++ whlist = nhash_new(GFP_KERNEL); ++ err = PTR_ERR(whlist); ++ if (IS_ERR(whlist)) ++ goto out; ++ ++ err = -ENOMEM; ++ arg = kmalloc(sizeof(*arg), GFP_KERNEL); ++ //arg = NULL; ++ if (unlikely(!arg)) ++ goto out_whlist; ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ parent = dentry->d_parent; ++ di_write_lock_parent(parent); ++ err = test_empty(dentry, whlist); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_arg; ++ ++ bstart = dbstart(dentry); ++ bwh = dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/ 1, &bindex, &dt); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_arg; ++ ++ hidden_dentry = au_h_dptr(dentry); ++ dget(hidden_dentry); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ ++ rmdir_later = 0; ++ if (bindex == bstart) { ++ IMustLock(hidden_dir); ++ err = renwh_and_rmdir(dentry, bstart, whlist, dir); ++ //err = -1; ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ DEBUG_ON(!wh_dentry); ++ hidden_parent = wh_dentry->d_parent; ++ DEBUG_ON(hidden_parent != au_h_dptr_i(parent, bindex)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ err = 0; ++ } ++ ++ sb = dentry->d_sb; ++ if (!err) { ++ //aufs_bindex_t bi, bend; ++ ++ au_reset_hinotify(inode, /*flags*/0); ++ inode->i_nlink = 0; ++ set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ kick_rmdir_whtmp(hidden_dentry, whlist, bstart, dir, ++ inode, arg); ++ arg = NULL; ++ } ++ ++#if 0 ++ bend = dbend(dentry); ++ for (bi = bstart; bi <= bend; bi++) { ++ struct dentry *hd; ++ hd = au_h_dptr_i(dentry, bi); ++ if (hd && hd->d_inode) ++ xino_write0(sb, bi, hd->d_inode->i_ino); ++ /* ignore this error */ ++ } ++#endif ++ ++ goto out_unlock; /* success */ ++ } ++ ++ /* revert */ ++ LKTRLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ rerr = do_revert(err, wh_dentry, dentry, bwh, &dt, ++ need_dlgt(sb)); ++ if (rerr) ++ err = rerr; ++ } ++ ++ out_unlock: ++ hdir_unlock(hidden_dir, dir, bindex); ++ dput(wh_dentry); ++ dput(hidden_dentry); ++ out_arg: ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ kfree(arg); ++ out_whlist: ++ nhash_del(whlist); ++ out: ++ TraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c +new file mode 100755 +index 0000000..08137f9 +--- /dev/null ++++ b/fs/aufs/i_op_ren.c +@@ -0,0 +1,637 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: i_op_ren.c,v 1.39 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++//#include ++//#include ++#include "aufs.h" ++ ++enum {SRC, DST}; ++struct rename_args { ++ struct dentry *hidden_dentry[2], *parent[2], *hidden_parent[2]; ++ struct aufs_nhash whlist; ++ aufs_bindex_t btgt, bstart[2]; ++ struct super_block *sb; ++ ++ unsigned int isdir:1; ++ unsigned int issamedir:1; ++ unsigned int whsrc:1; ++ unsigned int whdst:1; ++ unsigned int dlgt:1; ++} __attribute__((aligned(sizeof(long)))); ++ ++static int do_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, ++ struct rename_args *a) ++{ ++ int err, need_diropq, bycpup, rerr; ++ struct rmdir_whtmp_arg *tharg; ++ struct dentry *wh_dentry[2], *hidden_dst, *hg_parent; ++ struct inode *hidden_dir[2]; ++ aufs_bindex_t bindex, bend; ++ unsigned int flags; ++ struct lkup_args lkup = {.dlgt = a->dlgt}; ++ ++ LKTRTrace("%.*s/%.*s, %.*s/%.*s, " ++ "hd{%p, %p}, hp{%p, %p}, wh %p, btgt %d, bstart{%d, %d}, " ++ "flags{%d, %d, %d, %d}\n", ++ DLNPair(a->parent[SRC]), DLNPair(src_dentry), ++ DLNPair(a->parent[DST]), DLNPair(dentry), ++ a->hidden_dentry[SRC], a->hidden_dentry[DST], ++ a->hidden_parent[SRC], a->hidden_parent[DST], ++ &a->whlist, a->btgt, ++ a->bstart[SRC], a->bstart[DST], ++ a->isdir, a->issamedir, a->whsrc, a->whdst); ++ hidden_dir[SRC] = a->hidden_parent[SRC]->d_inode; ++ hidden_dir[DST] = a->hidden_parent[DST]->d_inode; ++ IMustLock(hidden_dir[SRC]); ++ IMustLock(hidden_dir[DST]); ++ ++ /* prepare workqueue arg */ ++ hidden_dst = NULL; ++ tharg = NULL; ++ if (a->isdir && a->hidden_dentry[DST]->d_inode) { ++ err = -ENOMEM; ++ tharg = kmalloc(sizeof(*tharg), GFP_KERNEL); ++ //tharg = NULL; ++ if (unlikely(!tharg)) ++ goto out; ++ hidden_dst = dget(a->hidden_dentry[DST]); ++ } ++ ++ wh_dentry[SRC] = wh_dentry[DST] = NULL; ++ lkup.nfsmnt = au_nfsmnt(a->sb, a->btgt); ++ /* create whiteout for src_dentry */ ++ if (a->whsrc) { ++ wh_dentry[SRC] = simple_create_wh(src_dentry, a->btgt, ++ a->hidden_parent[SRC], &lkup); ++ //wh_dentry[SRC] = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry[SRC]); ++ if (IS_ERR(wh_dentry[SRC])) ++ goto out_tharg; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (a->whdst) { ++ struct dentry *d; ++ d = lkup_wh(a->hidden_parent[DST], &dentry->d_name, &lkup); ++ //d = ERR_PTR(-1); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out_whsrc; ++ if (!d->d_inode) ++ dput(d); ++ else ++ wh_dentry[DST] = d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (tharg) { ++ err = rename_whtmp(dentry, a->btgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_whdst; ++ set_h_dptr(dentry, a->btgt, NULL); ++ err = lkup_neg(dentry, a->btgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->hidden_dentry[DST] = au_h_dptr_i(dentry, a->btgt); ++ } ++ ++ /* cpup src */ ++ if (a->hidden_dentry[DST]->d_inode && a->bstart[SRC] != a->btgt) { ++ flags = au_flags_cpup(!CPUP_DTIME, a->parent[SRC]); ++ hg_parent = a->hidden_parent[SRC]->d_parent; ++ if (!(flags & CPUP_LOCKED_GHDIR) ++ && hg_parent == a->hidden_parent[DST]) ++ flags |= CPUP_LOCKED_GHDIR; ++ ++ hi_lock_child(a->hidden_dentry[SRC]->d_inode); ++ err = sio_cpup_simple(src_dentry, a->btgt, -1, flags); ++ //err = -1; // untested dir ++ i_unlock(a->hidden_dentry[SRC]->d_inode); ++ if (unlikely(err)) ++ goto out_whtmp; ++ } ++ ++#if 0 ++ /* clear the target ino in xino */ ++ LKTRTrace("dir %d, dst inode %p\n", a->isdir, a->hidden_dentry[DST]->d_inode); ++ if (a->isdir && a->hidden_dentry[DST]->d_inode) { ++ Dbg("here\n"); ++ err = xino_write(a->sb, a->btgt, ++ a->hidden_dentry[DST]->d_inode->i_ino, 0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ } ++#endif ++ ++ /* rename by vfs_rename or cpup */ ++ need_diropq = a->isdir ++ && (wh_dentry[DST] ++ || dbdiropq(dentry) == a->btgt ++ || au_flag_test(a->sb, AuFlag_ALWAYS_DIROPQ)); ++ bycpup = 0; ++ if (dbstart(src_dentry) == a->btgt) { ++ if (need_diropq && dbdiropq(src_dentry) == a->btgt) ++ need_diropq = 0; ++ err = vfsub_rename(hidden_dir[SRC], au_h_dptr(src_dentry), ++ hidden_dir[DST], a->hidden_dentry[DST], ++ a->dlgt); ++ //err = -1; ++ } else { ++ bycpup = 1; ++ flags = au_flags_cpup(!CPUP_DTIME, a->parent[DST]); ++ hg_parent = a->hidden_parent[DST]->d_parent; ++ if (!(flags & CPUP_LOCKED_GHDIR) ++ && hg_parent == a->hidden_parent[SRC]) ++ flags |= CPUP_LOCKED_GHDIR; ++ ++ hi_lock_child(a->hidden_dentry[SRC]->d_inode); ++ set_dbstart(src_dentry, a->btgt); ++ set_h_dptr(src_dentry, a->btgt, dget(a->hidden_dentry[DST])); ++ //DbgDentry(src_dentry); ++ //DbgInode(src_dentry->d_inode); ++ err = sio_cpup_single(src_dentry, a->btgt, a->bstart[SRC], -1, ++ flags); ++ //err = -1; // untested dir ++ if (unlikely(err)) { ++ set_h_dptr(src_dentry, a->btgt, NULL); ++ set_dbstart(src_dentry, a->bstart[SRC]); ++ } ++ i_unlock(a->hidden_dentry[SRC]->d_inode); ++ } ++ if (unlikely(err)) ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ if (need_diropq) { ++ struct dentry *diropq; ++ struct inode *h_inode; ++ ++ h_inode = au_h_dptr_i(src_dentry, a->btgt)->d_inode; ++ hdir_lock(h_inode, src_dentry->d_inode, a->btgt); ++ diropq = create_diropq(src_dentry, a->btgt, a->dlgt); ++ //diropq = ERR_PTR(-1); ++ hdir_unlock(h_inode, src_dentry->d_inode, a->btgt); ++ err = PTR_ERR(diropq); ++ if (IS_ERR(diropq)) ++ goto out_rename; ++ dput(diropq); ++ } ++ ++ /* remove whiteout for dentry */ ++ if (wh_dentry[DST]) { ++ err = au_unlink_wh_dentry(hidden_dir[DST], wh_dentry[DST], ++ dentry, a->dlgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (tharg) { ++ if (au_is_nfs(hidden_dst->d_sb) ++ || !is_longer_wh(&a->whlist, a->btgt, ++ stosi(a->sb)->si_dirwh)) { ++ err = rmdir_whtmp(hidden_dst, &a->whlist, a->btgt, dir, ++ dentry->d_inode); ++ if (unlikely(err)) ++ Warn("failed removing whtmp dir %.*s (%d), " ++ "ignored.\n", DLNPair(hidden_dst), err); ++ } else { ++ kick_rmdir_whtmp(hidden_dst, &a->whlist, a->btgt, dir, ++ dentry->d_inode, tharg); ++ dput(hidden_dst); ++ tharg = NULL; ++ } ++ } ++ err = 0; ++ goto out_success; ++ ++#define RevertFailure(fmt, args...) do { \ ++ IOErrWhck("revert failure: " fmt " (%d, %d)\n", \ ++ ##args, err, rerr); \ ++ err = -EIO; \ ++ } while(0) ++ ++ out_diropq: ++ if (need_diropq) { ++ struct inode *h_inode; ++ ++ h_inode = au_h_dptr_i(src_dentry, a->btgt)->d_inode; ++ // i_lock simplly since inotify is not set to h_inode. ++ hi_lock_parent(h_inode); ++ //hdir_lock(h_inode, src_dentry->d_inode, a->btgt); ++ rerr = remove_diropq(src_dentry, a->btgt, a->dlgt); ++ //rerr = -1; ++ //hdir_unlock(h_inode, src_dentry->d_inode, a->btgt); ++ i_unlock(h_inode); ++ if (rerr) ++ RevertFailure("remove diropq %.*s", ++ DLNPair(src_dentry)); ++ } ++ out_rename: ++ if (!bycpup) { ++ struct dentry *d; ++ struct qstr *name = &src_dentry->d_name; ++ d = lkup_one(name->name, a->hidden_parent[SRC], name->len, ++ &lkup); ++ //d = ERR_PTR(-1); ++ rerr = PTR_ERR(d); ++ if (IS_ERR(d)) { ++ RevertFailure("lkup_one %.*s", DLNPair(src_dentry)); ++ goto out_whtmp; ++ } ++ DEBUG_ON(d->d_inode); ++ rerr = vfsub_rename ++ (hidden_dir[DST], au_h_dptr_i(src_dentry, a->btgt), ++ hidden_dir[SRC], d, a->dlgt); ++ //rerr = -1; ++ d_drop(d); ++ dput(d); ++ //set_h_dptr(src_dentry, a->btgt, NULL); ++ if (rerr) ++ RevertFailure("rename %.*s", DLNPair(src_dentry)); ++ } else { ++ rerr = vfsub_unlink(hidden_dir[DST], a->hidden_dentry[DST], ++ a->dlgt); ++ //rerr = -1; ++ set_h_dptr(src_dentry, a->btgt, NULL); ++ set_dbstart(src_dentry, a->bstart[SRC]); ++ if (rerr) ++ RevertFailure("unlink %.*s", ++ DLNPair(a->hidden_dentry[DST])); ++ } ++ out_whtmp: ++ if (tharg) { ++ struct dentry *d; ++ struct qstr *name = &dentry->d_name; ++ LKTRLabel(here); ++ d = lkup_one(name->name, a->hidden_parent[DST], name->len, ++ &lkup); ++ //d = ERR_PTR(-1); ++ rerr = PTR_ERR(d); ++ if (IS_ERR(d)) { ++ RevertFailure("lookup %.*s", LNPair(name)); ++ goto out_whdst; ++ } ++ if (d->d_inode) { ++ d_drop(d); ++ dput(d); ++ goto out_whdst; ++ } ++ DEBUG_ON(d->d_inode); ++ rerr = vfsub_rename(hidden_dir[DST], hidden_dst, ++ hidden_dir[DST], d, a->dlgt); ++ //rerr = -1; ++ d_drop(d); ++ dput(d); ++ if (rerr) { ++ RevertFailure("rename %.*s", DLNPair(hidden_dst)); ++ goto out_whdst; ++ } ++ set_h_dptr(dentry, a->btgt, NULL); ++ set_h_dptr(dentry, a->btgt, dget(hidden_dst)); ++ } ++ out_whdst: ++ dput(wh_dentry[DST]); ++ wh_dentry[DST] = NULL; ++ out_whsrc: ++ if (wh_dentry[SRC]) { ++ LKTRLabel(here); ++ rerr = au_unlink_wh_dentry(hidden_dir[SRC], wh_dentry[SRC], ++ src_dentry, a->dlgt); ++ //rerr = -1; ++ if (rerr) ++ RevertFailure("unlink %.*s", DLNPair(wh_dentry[SRC])); ++ } ++#undef RevertFailure ++ d_drop(src_dentry); ++ bend = dbend(src_dentry); ++ for (bindex = dbstart(src_dentry); bindex <= bend; bindex++) { ++ struct dentry *hd; ++ hd = au_h_dptr_i(src_dentry, bindex); ++ if (hd) ++ d_drop(hd); ++ } ++ d_drop(dentry); ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); bindex <= bend; bindex++) { ++ struct dentry *hd; ++ hd = au_h_dptr_i(dentry, bindex); ++ if (hd) ++ d_drop(hd); ++ } ++ au_update_dbstart(dentry); ++ if (tharg) ++ d_drop(hidden_dst); ++ out_success: ++ dput(wh_dentry[SRC]); ++ dput(wh_dentry[DST]); ++ out_tharg: ++ if (tharg) { ++ dput(hidden_dst); ++ kfree(tharg); ++ } ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, aufs_bindex_t btgt, ++ struct aufs_nhash *whlist) ++{ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ ++ return test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @dentry dir can be rename source or not. ++ * if it can, return 0 and @children is filled. ++ * success means, ++ * - or, it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch. ++ */ ++static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ ++ bstart = dbstart(dentry); ++ if (bstart != btgt) { ++ struct aufs_nhash *whlist; ++ ++ whlist = nhash_new(GFP_KERNEL); ++ err = PTR_ERR(whlist); ++ if (IS_ERR(whlist)) ++ goto out; ++ err = test_empty(dentry, whlist); ++ nhash_del(whlist); ++ goto out; ++ } ++ ++ if (bstart == dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++ out: ++ if (/* unlikely */(err == -ENOTEMPTY)) ++ err = -EXDEV; ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry) ++{ ++ int err, do_dt_dstdir; ++ aufs_bindex_t bend, bindex; ++ struct inode *inode, *dirs[2]; ++ enum {PARENT, CHILD}; ++ /* reduce stack space */ ++ struct { ++ struct rename_args a; ++ struct dtime dt[2][2]; ++ } *p; ++ ++ LKTRTrace("i%lu, %.*s, i%lu, %.*s\n", ++ src_dir->i_ino, DLNPair(src_dentry), ++ dir->i_ino, DLNPair(dentry)); ++ IMustLock(src_dir); ++ IMustLock(dir); ++ /* braces are added to stop a warning */ ++ if (dentry->d_inode) { ++ IMustLock(dentry->d_inode); ++ } ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*p) > PAGE_SIZE); ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -ENOTDIR; ++ p->a.sb = src_dentry->d_sb; ++ inode = src_dentry->d_inode; ++ p->a.isdir = !!S_ISDIR(inode->i_mode); ++ if (unlikely(p->a.isdir && dentry->d_inode ++ && !S_ISDIR(dentry->d_inode->i_mode))) ++ goto out_free; ++ ++ aufs_read_and_write_lock2(dentry, src_dentry, p->a.isdir); ++ p->a.dlgt = !!need_dlgt(p->a.sb); ++ p->a.parent[SRC] = p->a.parent[DST] = dentry->d_parent; ++ p->a.issamedir = (src_dir == dir); ++ if (p->a.issamedir) ++ di_write_lock_parent(p->a.parent[DST]); ++ else { ++ p->a.parent[SRC] = src_dentry->d_parent; ++ di_write_lock2_parent(p->a.parent[SRC], p->a.parent[DST], ++ /*isdir*/1); ++ } ++ ++ /* which branch we process */ ++ p->a.bstart[DST] = dbstart(dentry); ++ p->a.btgt = err = wr_dir(dentry, 1, src_dentry, /*force_btgt*/-1, ++ /*do_lock_srcdir*/0); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ /* are they available to be renamed */ ++ err = 0; ++ nhash_init(&p->a.whlist); ++ if (p->a.isdir && dentry->d_inode) { ++ set_dbstart(dentry, p->a.bstart[DST]); ++ err = may_rename_dstdir(dentry, p->a.btgt, &p->a.whlist); ++ set_dbstart(dentry, p->a.btgt); ++ } ++ p->a.hidden_dentry[DST] = au_h_dptr(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ //todo: minor optimize, their sb may be same while their bindex differs. ++ p->a.bstart[SRC] = dbstart(src_dentry); ++ p->a.hidden_dentry[SRC] = au_h_dptr(src_dentry); ++ if (p->a.isdir) { ++ err = may_rename_srcdir(src_dentry, p->a.btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ /* prepare the writable parent dir on the same branch */ ++ err = wr_dir_need_wh(src_dentry, p->a.isdir, &p->a.btgt, ++ p->a.issamedir ? NULL : p->a.parent[DST]); ++ if (unlikely(err < 0)) ++ goto out_children; ++ p->a.whsrc = !!err; ++ p->a.whdst = (p->a.bstart[DST] == p->a.btgt); ++ if (!p->a.whdst) { ++ err = cpup_dirs(dentry, p->a.btgt, ++ p->a.issamedir ? NULL : p->a.parent[SRC]); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ p->a.hidden_parent[SRC] = au_h_dptr_i(p->a.parent[SRC], p->a.btgt); ++ p->a.hidden_parent[DST] = au_h_dptr_i(p->a.parent[DST], p->a.btgt); ++ dirs[0] = src_dir; ++ dirs[1] = dir; ++ hdir_lock_rename(p->a.hidden_parent, dirs, p->a.btgt, p->a.issamedir); ++ ++ /* store timestamps to be revertible */ ++ dtime_store(p->dt[PARENT] + SRC, p->a.parent[SRC], ++ p->a.hidden_parent[SRC]); ++ if (!p->a.issamedir) ++ dtime_store(p->dt[PARENT] + DST, p->a.parent[DST], ++ p->a.hidden_parent[DST]); ++ do_dt_dstdir = 0; ++ if (p->a.isdir) { ++ dtime_store(p->dt[CHILD] + SRC, src_dentry, ++ p->a.hidden_dentry[SRC]); ++ if (p->a.hidden_dentry[DST]->d_inode) { ++ do_dt_dstdir = 1; ++ dtime_store(p->dt[CHILD] + DST, dentry, ++ p->a.hidden_dentry[DST]); ++ } ++ } ++ ++ err = do_rename(src_dir, src_dentry, dir, dentry, &p->a); ++ if (unlikely(err)) ++ goto out_dt; ++ hdir_unlock_rename(p->a.hidden_parent, dirs, p->a.btgt, p->a.issamedir); ++ ++ /* update dir attributes */ ++ dir->i_version++; ++ if (p->a.isdir) ++ au_cpup_attr_nlink(dir); ++ if (ibstart(dir) == p->a.btgt) ++ au_cpup_attr_timesizes(dir); ++ ++ if (!p->a.issamedir) { ++ src_dir->i_version++; ++ if (p->a.isdir) ++ au_cpup_attr_nlink(src_dir); ++ if (ibstart(src_dir) == p->a.btgt) ++ au_cpup_attr_timesizes(src_dir); ++ } ++ ++ // is this updating defined in POSIX? ++ if (unlikely(p->a.isdir)) { ++ //i_lock(inode); ++ au_cpup_attr_timesizes(inode); ++ //i_unlock(inode); ++ } ++ ++#if 0 ++ d_drop(src_dentry); ++#else ++ /* dput/iput all lower dentries */ ++ set_dbwh(src_dentry, -1); ++ bend = dbend(src_dentry); ++ for (bindex = p->a.btgt + 1; bindex <= bend; bindex++) { ++ struct dentry *hd; ++ hd = au_h_dptr_i(src_dentry, bindex); ++ if (hd) ++ set_h_dptr(src_dentry, bindex, NULL); ++ } ++ set_dbend(src_dentry, p->a.btgt); ++ ++ bend = ibend(inode); ++ for (bindex = p->a.btgt + 1; bindex <= bend; bindex++) { ++ struct inode *hi; ++ hi = au_h_iptr_i(inode, bindex); ++ if (hi) ++ set_h_iptr(inode, bindex, NULL, 0); ++ } ++ set_ibend(inode, p->a.btgt); ++#endif ++ ++#if 0 ++ //au_debug_on(); ++ //DbgDentry(dentry); ++ //DbgInode(dentry->d_inode); ++ //au_debug_off(); ++ inode = dentry->d_inode; ++ if (inode) { ++ aufs_bindex_t bindex, bend; ++ struct dentry *hd; ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); bindex <= bend; bindex++) { ++ hd = au_h_dptr_i(dentry, bindex); ++ if (hd && hd->d_inode) ++ xino_write0(p->a.sb, bindex, hd->d_inode->i_ino); ++ /* ignore this error */ ++ } ++ } ++#endif ++ ++ goto out_children; /* success */ ++ ++ out_dt: ++ dtime_revert(p->dt[PARENT] + SRC, ++ p->a.hidden_parent[SRC]->d_parent ++ == p->a.hidden_parent[DST]); ++ if (!p->a.issamedir) ++ dtime_revert(p->dt[PARENT] + DST, ++ p->a.hidden_parent[DST]->d_parent ++ == p->a.hidden_parent[SRC]); ++ if (p->a.isdir && err != -EIO) { ++ struct dentry *hd; ++ ++ hd = p->dt[CHILD][SRC].dt_h_dentry; ++ hi_lock_child(hd->d_inode); ++ dtime_revert(p->dt[CHILD] + SRC, 1); ++ i_unlock(hd->d_inode); ++ if (do_dt_dstdir) { ++ hd = p->dt[CHILD][DST].dt_h_dentry; ++ hi_lock_child(hd->d_inode); ++ dtime_revert(p->dt[CHILD] + DST, 1); ++ i_unlock(hd->d_inode); ++ } ++ } ++ hdir_unlock_rename(p->a.hidden_parent, dirs, p->a.btgt, p->a.issamedir); ++ out_children: ++ nhash_fin(&p->a.whlist); ++ out_unlock: ++ //if (unlikely(err /* && p->a.isdir */)) { ++ if (unlikely(err && p->a.isdir)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ if (p->a.issamedir) ++ di_write_unlock(p->a.parent[DST]); ++ else ++ di_write_unlock2(p->a.parent[SRC], p->a.parent[DST]); ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++ out_free: ++ kfree(p); ++ out: ++ TraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c +new file mode 100755 +index 0000000..9efbd38 +--- /dev/null ++++ b/fs/aufs/iinfo.c +@@ -0,0 +1,286 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: iinfo.c,v 1.31 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++//#include ++#include "aufs.h" ++ ++struct aufs_iinfo *itoii(struct inode *inode) ++{ ++ struct aufs_iinfo *iinfo; ++ ++ iinfo = &(container_of(inode, struct aufs_icntnr, vfs_inode)->iinfo); ++ /* bad_inode case */ ++ if (unlikely(!iinfo->ii_hinode)) ++ return NULL; ++ DEBUG_ON(!iinfo->ii_hinode ++ /* || stosi(inode->i_sb)->si_bend < iinfo->ii_bend */ ++ || iinfo->ii_bend < iinfo->ii_bstart); ++ return iinfo; ++} ++ ++aufs_bindex_t ibstart(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return itoii(inode)->ii_bstart; ++} ++ ++aufs_bindex_t ibend(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return itoii(inode)->ii_bend; ++} ++ ++struct aufs_vdir *ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ DEBUG_ON(!S_ISDIR(inode->i_mode)); ++ return itoii(inode)->ii_vdir; ++} ++ ++struct inode *au_h_iptr_i(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *hidden_inode; ++ ++ IiMustAnyLock(inode); ++ DEBUG_ON(bindex < 0 || ibend(inode) < bindex); ++ hidden_inode = itoii(inode)->ii_hinode[0 + bindex].hi_inode; ++ DEBUG_ON(hidden_inode && atomic_read(&hidden_inode->i_count) <= 0); ++ return hidden_inode; ++} ++ ++struct inode *au_h_iptr(struct inode *inode) ++{ ++ return au_h_iptr_i(inode, ibstart(inode)); ++} ++ ++aufs_bindex_t itoid_index(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ DEBUG_ON(bindex < 0 ++ || ibend(inode) < bindex ++ || !itoii(inode)->ii_hinode[0 + bindex].hi_inode); ++ return itoii(inode)->ii_hinode[0 + bindex].hi_id; ++} ++ ++// hard/soft set ++void set_ibstart(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct aufs_iinfo *iinfo = itoii(inode); ++ struct inode *h_inode; ++ ++ IiMustWriteLock(inode); ++ DEBUG_ON(sbend(inode->i_sb) < bindex); ++ iinfo->ii_bstart = bindex; ++ h_inode = iinfo->ii_hinode[bindex + 0].hi_inode; ++ if (h_inode) ++ au_cpup_igen(inode, h_inode); ++} ++ ++void set_ibend(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ DEBUG_ON(sbend(inode->i_sb) < bindex ++ || bindex < ibstart(inode)); ++ itoii(inode)->ii_bend = bindex; ++} ++ ++void set_ivdir(struct inode *inode, struct aufs_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ DEBUG_ON(!S_ISDIR(inode->i_mode) ++ || (itoii(inode)->ii_vdir && vdir)); ++ itoii(inode)->ii_vdir = vdir; ++} ++ ++void aufs_hiput(struct aufs_hinode *hinode) ++{ ++ if (unlikely(hinode->hi_notify)) ++ do_free_hinotify(hinode); ++ if (hinode->hi_inode) ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ struct super_block *sb = inode->i_sb; ++ ++ flags = 0; ++ if (au_flag_test(sb, AuFlag_XINO)) ++ flags = AUFS_HI_XINO; ++ if (unlikely(isdir && au_flag_test(sb, AuFlag_UDBA_INOTIFY))) ++ flags |= AUFS_HI_NOTIFY; ++ return flags; ++} ++ ++void set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct aufs_hinode *hinode; ++ struct inode *hi; ++ struct aufs_iinfo *iinfo = itoii(inode); ++ ++ LKTRTrace("i%lu, b%d, hi%lu, flags 0x%x\n", ++ inode->i_ino, bindex, h_inode ? h_inode->i_ino : 0, flags); ++ IiMustWriteLock(inode); ++ hinode = iinfo->ii_hinode + bindex; ++ hi = hinode->hi_inode; ++ DEBUG_ON(bindex < ibstart(inode) || ibend(inode) < bindex ++ || (h_inode && atomic_read(&h_inode->i_count) <= 0) ++ || (h_inode && hi)); ++ ++ if (hi) ++ aufs_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ ++ if (bindex == iinfo->ii_bstart) ++ au_cpup_igen(inode, h_inode); ++ hinode->hi_id = sbr_id(sb, bindex); ++ if (flags & AUFS_HI_XINO) { ++ struct xino xino = { ++ .ino = inode->i_ino, ++ //.h_gen = h_inode->i_generation ++ }; ++ //WARN_ON(xino.h_gen == AuXino_INVALID_HGEN); ++ err = xino_write(sb, bindex, h_inode->i_ino, &xino); ++ if (unlikely(err)) { ++ IOErr1("failed xino_write() %d, force noxino\n", ++ err); ++ au_flag_clr(sb, AuFlag_XINO); ++ } ++ } ++ if (flags & AUFS_HI_NOTIFY) { ++ err = alloc_hinotify(hinode, inode, h_inode); ++ if (unlikely(err)) ++ IOErr1("alloc_hinotify() %d\n", err); ++ else { ++ /* braces are added to stop a warning */ ++ DEBUG_ON(!hinode->hi_notify); ++ } ++ } ++ } ++} ++ ++void au_update_iigen(struct inode *inode) ++{ ++ //IiMustWriteLock(inode); ++ DEBUG_ON(!inode->i_sb); ++ atomic_set(&itoii(inode)->ii_generation, au_sigen(inode->i_sb)); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_brange(struct inode *inode, int do_put_zero) ++{ ++ struct aufs_iinfo *iinfo; ++ ++ LKTRTrace("i%lu, %d\n", inode->i_ino, do_put_zero); ++ IiMustWriteLock(inode); ++ ++ iinfo = itoii(inode); ++ if (unlikely(!iinfo) || iinfo->ii_bstart < 0) ++ return; ++ ++ if (do_put_zero) { ++ aufs_bindex_t bindex; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++) { ++ struct inode *h_i; ++ h_i = iinfo->ii_hinode[0 + bindex].hi_inode; ++ if (h_i && !h_i->i_nlink) ++ set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_bstart = -1; ++ while (++iinfo->ii_bstart <= iinfo->ii_bend) ++ if (iinfo->ii_hinode[0 + iinfo->ii_bstart].hi_inode) ++ break; ++ if (iinfo->ii_bstart > iinfo->ii_bend) { ++ iinfo->ii_bend = iinfo->ii_bstart = -1; ++ return; ++ } ++ ++ iinfo->ii_bend++; ++ while (0 <= --iinfo->ii_bend) ++ if (iinfo->ii_hinode[0 + iinfo->ii_bend].hi_inode) ++ break; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct aufs_iinfo *iinfo; ++ struct super_block *sb; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ DEBUG_ON(!sb); ++ iinfo = &(container_of(inode, struct aufs_icntnr, vfs_inode)->iinfo); ++ DEBUG_ON(iinfo->ii_hinode); ++ nbr = sbend(sb) + 1; ++ if (unlikely(!nbr)) ++ nbr++; ++ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_KERNEL); ++ //iinfo->ii_hinode = NULL; ++ if (iinfo->ii_hinode) { ++ for (i = 0; i < nbr; i++) ++ iinfo->ii_hinode[i].hi_id = -1; ++ atomic_set(&iinfo->ii_generation, au_sigen(sb)); ++ rw_init_nolock(&iinfo->ii_rwsem); ++ iinfo->ii_bstart = -1; ++ iinfo->ii_bend = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct aufs_iinfo *iinfo; ++ ++ iinfo = itoii(inode); ++ /* bad_inode case */ ++ if (unlikely(!iinfo)) ++ return; ++ ++ if (unlikely(iinfo->ii_vdir)) ++ free_vdir(iinfo->ii_vdir); ++ ++ if (iinfo->ii_bstart >= 0) { ++ aufs_bindex_t bend; ++ struct aufs_hinode *hi; ++ hi = iinfo->ii_hinode + iinfo->ii_bstart; ++ bend = iinfo->ii_bend; ++ while (iinfo->ii_bstart++ <= bend) { ++ if (hi->hi_inode) ++ aufs_hiput(hi); ++ hi++; ++ } ++ //iinfo->ii_bstart = iinfo->ii_bend = -1; ++ } ++ ++ kfree(iinfo->ii_hinode); ++ //iinfo->ii_hinode = NULL; ++} +diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c +new file mode 100755 +index 0000000..f18b5d8 +--- /dev/null ++++ b/fs/aufs/inode.c +@@ -0,0 +1,339 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: inode.c,v 1.22 2007/05/07 03:44:35 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, new_sz, update, isdir; ++ struct inode *first; ++ struct aufs_hinode *p, *q, tmp; ++ struct super_block *sb; ++ struct aufs_iinfo *iinfo; ++ aufs_bindex_t bindex, bend, new_bindex; ++ unsigned int flags; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ IiMustWriteLock(inode); ++ ++ err = -ENOMEM; ++ sb = dentry->d_sb; ++ bend = sbend(sb); ++ new_sz = sizeof(*iinfo->ii_hinode) * (bend + 1); ++ iinfo = itoii(inode); ++ p = au_kzrealloc(iinfo->ii_hinode, sizeof(*p) * (iinfo->ii_bend + 1), ++ new_sz, GFP_KERNEL); ++ //p = NULL; ++ if (unlikely(!p)) ++ goto out; ++ ++ iinfo->ii_hinode = p; ++ err = 0; ++ update = 0; ++ p = iinfo->ii_hinode + iinfo->ii_bstart; ++ first = p->hi_inode; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++, p++) { ++ if (unlikely(!p->hi_inode)) ++ continue; ++ ++ new_bindex = find_brindex(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ update++; ++ aufs_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = new_bindex; ++ if (iinfo->ii_bend < new_bindex) ++ iinfo->ii_bend = new_bindex; ++ /* swap two hidden inode, and loop again */ ++ q = iinfo->ii_hinode + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ flags = au_hi_flags(inode, isdir); ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); bindex <= bend; bindex++) { ++ struct inode *hi; ++ struct dentry *hd; ++ ++ hd = au_h_dptr_i(dentry, bindex); ++ if (!hd || !hd->d_inode) ++ continue; ++ ++ if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { ++ hi = au_h_iptr_i(inode, bindex); ++ if (hi) { ++ if (hi == hd->d_inode) ++ continue; ++ //Dbg("here\n"); ++ err = -ESTALE; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = bindex; ++ if (iinfo->ii_bend < bindex) ++ iinfo->ii_bend = bindex; ++ set_h_iptr(inode, bindex, igrab(hd->d_inode), flags); ++ update++; ++ } ++ ++ bend = iinfo->ii_bend; ++ p = iinfo->ii_hinode; ++ for (bindex = 0; bindex <= bend; bindex++, p++) ++ if (p->hi_inode) { ++ iinfo->ii_bstart = bindex; ++ break; ++ } ++ p = iinfo->ii_hinode + bend; ++ for (bindex = bend; bindex > iinfo->ii_bstart; bindex--, p--) ++ if (p->hi_inode) { ++ iinfo->ii_bend = bindex; ++ break; ++ } ++ DEBUG_ON(iinfo->ii_bstart > bend || iinfo->ii_bend < 0); ++ ++ if (unlikely(err)) ++ goto out; ++ ++ if (1 || first != au_h_iptr(inode)) ++ au_cpup_attr_all(inode); ++ if (update && isdir) ++ inode->i_version++; ++ au_update_iigen(inode); ++ ++ out: ++ //au_debug_on(); ++ TraceErr(err); ++ //au_debug_off(); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, isdir; ++ struct dentry *hidden_dentry; ++ struct inode *hidden_inode; ++ umode_t mode; ++ aufs_bindex_t bindex, bstart, btail; ++ struct aufs_iinfo *iinfo; ++ unsigned int flags; ++ ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(dentry)); ++ DEBUG_ON(!(inode->i_state & I_NEW)); ++ IiMustWriteLock(inode); ++ hidden_dentry = au_h_dptr(dentry); ++ DEBUG_ON(!hidden_dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode); ++ ++ err = 0; ++ isdir = 0; ++ bstart = dbstart(dentry); ++ mode = hidden_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = dbtail(dentry); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = dbtaildir(dentry); ++ inode->i_op = &aufs_dir_iop; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = dbtail(dentry); ++ inode->i_op = &aufs_symlink_iop; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = dbtail(dentry); ++ init_special_inode(inode, mode, hidden_inode->i_rdev); ++ break; ++ default: ++ IOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ flags = au_hi_flags(inode, isdir); ++ iinfo = itoii(inode); ++ iinfo->ii_bstart = bstart; ++ iinfo->ii_bend = btail; ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!hidden_dentry) ++ continue; ++ DEBUG_ON(!hidden_dentry->d_inode); ++ set_h_iptr(inode, bindex, igrab(hidden_dentry->d_inode), flags); ++ } ++ au_cpup_attr_all(inode); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++//todo: return with unlocked? ++static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched) ++{ ++ int err; ++ struct inode *h_inode, *h_dinode; ++ aufs_bindex_t bindex, bend; ++ //const int udba = !au_flag_test(inode->i_sb, AuFlag_UDBA_NONE); ++ ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(dentry)); ++ ++ *matched = 0; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ h_dinode = au_h_dptr(dentry)->d_inode; ++ hi_lock_child(inode); // bad name, this is not a hidden inode. ++ ii_write_lock_new(inode); ++ bend = ibend(inode); ++ for (bindex = ibstart(inode); bindex <= bend; bindex++) { ++ h_inode = au_h_iptr_i(inode, bindex); ++ if (h_inode && h_inode == h_dinode) { ++ //&& (ibs != bstart || !au_test_higen(inode, h_inode))); ++ *matched = 1; ++ err = 0; ++ if (unlikely(au_iigen(inode) != au_digen(dentry))) ++ err = au_refresh_hinode(inode, dentry); ++ break; ++ } ++ } ++ i_unlock(inode); ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++//todo: return with unlocked? ++struct inode *au_new_inode(struct dentry *dentry) ++{ ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ino_t h_ino; ++ struct super_block *sb; ++ int err, match; ++ aufs_bindex_t bstart; ++ struct xino xino; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ sb = dentry->d_sb; ++ h_dentry = au_h_dptr(dentry); ++ DEBUG_ON(!h_dentry); ++ h_inode = h_dentry->d_inode; ++ DEBUG_ON(!h_inode); ++ ++ bstart = dbstart(dentry); ++ h_ino = h_inode->i_ino; ++ err = xino_read(sb, bstart, h_ino, &xino); ++ //err = -1; ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ new_ino: ++ if (!xino.ino) { ++ xino.ino = xino_new_ino(sb); ++ if (!xino.ino) { ++ inode = ERR_PTR(-EIO); ++ goto out; ++ } ++ } ++ ++ LKTRTrace("i%lu\n", xino.ino); ++ err = -ENOMEM; ++ inode = iget_locked(sb, xino.ino); ++ if (unlikely(!inode)) ++ goto out; ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ err = -ENOMEM; ++ if (unlikely(is_bad_inode(inode))) ++ goto out_iput; ++ ++ LKTRTrace("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ sb->s_op->read_inode(inode); ++ if (!is_bad_inode(inode)) { ++ ii_write_lock_new(inode); ++ err = set_inode(inode, dentry); ++ //err = -1; ++ } ++ unlock_new_inode(inode); ++ if (!err) ++ goto out; /* success */ ++ ii_write_unlock(inode); ++ goto out_iput; ++ } else { ++ err = reval_inode(inode, dentry, &match); ++ if (!err) ++ goto out; /* success */ ++ else if (match) ++ goto out_iput; ++ } ++ ++ Warn1("broken ino, b%d, %.*s/%.*s, hi%lu, i%lu. Try udba=inotify.\n", ++ bstart, DLNPair(dentry->d_parent), DLNPair(dentry), h_ino, ++ xino.ino); ++ xino.ino = 0; ++ err = xino_write0(sb, bstart, h_ino); ++ if (!err) { ++ iput(inode); ++ goto new_ino; ++ } ++ ++ out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++ out: ++ TraceErrPtr(inode); ++ return inode; ++} +diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h +new file mode 100755 +index 0000000..b001ac3 +--- /dev/null ++++ b/fs/aufs/inode.h +@@ -0,0 +1,377 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: inode.h,v 1.32 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "misc.h" ++#include "vfsub.h" ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++#else ++struct inotify_watch {}; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_hinotify { ++ struct inotify_watch hin_watch; ++ struct inode *hin_aufs_inode; /* no get/put */ ++}; ++ ++struct aufs_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++ struct aufs_hinotify *hi_notify; ++}; ++ ++struct aufs_vdir; ++struct aufs_iinfo { ++ atomic_t ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct aufs_rwsem ii_rwsem; ++ aufs_bindex_t ii_bstart, ii_bend; ++ struct aufs_hinode *ii_hinode; ++ struct aufs_vdir *ii_vdir; ++}; ++ ++struct aufs_icntnr { ++ struct aufs_iinfo iinfo; ++ struct inode vfs_inode; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++struct inode *au_new_inode(struct dentry *dentry); ++ ++/* i_op.c */ ++extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop; ++int wr_dir(struct dentry *dentry, int negative, struct dentry *src_dentry, ++ aufs_bindex_t force_btgt, int do_lock_srcdir); ++ ++/* i_op_del.c */ ++int wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup, ++ struct dentry *locked); ++ ++/* iinfo.c */ ++struct aufs_iinfo *itoii(struct inode *inode); ++aufs_bindex_t ibstart(struct inode *inode); ++aufs_bindex_t ibend(struct inode *inode); ++struct aufs_vdir *ivdir(struct inode *inode); ++struct inode *au_h_iptr_i(struct inode *inode, aufs_bindex_t bindex); ++struct inode *au_h_iptr(struct inode *inode); ++aufs_bindex_t itoid_index(struct inode *inode, aufs_bindex_t bindex); ++ ++void set_ibstart(struct inode *inode, aufs_bindex_t bindex); ++void set_ibend(struct inode *inode, aufs_bindex_t bindex); ++void set_ivdir(struct inode *inode, struct aufs_vdir *vdir); ++void aufs_hiput(struct aufs_hinode *hinode); ++#define AUFS_HI_XINO 1 ++#define AUFS_HI_NOTIFY 2 ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++void set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++void au_update_iigen(struct inode *inode); ++void au_update_brange(struct inode *inode, int do_put_zero); ++ ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++ ++/* plink.c */ ++#ifdef CONFIG_AUFS_DEBUG ++void au_list_plink(struct super_block *sb); ++#else ++static inline void au_list_plink(struct super_block *sb) ++{ ++ /* nothing */ ++} ++#endif ++int au_is_plinked(struct super_block *sb, struct inode *inode); ++struct dentry *lkup_plink(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++void append_plink(struct super_block *sb, struct inode *inode, ++ struct dentry *h_dentry, aufs_bindex_t bindex); ++void au_put_plink(struct super_block *sb); ++void half_refresh_plink(struct super_block *sb, aufs_bindex_t br_id); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for hidden inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++// todo: reduce it by dcsub. ++enum { ++ AuLsc_Begin = I_MUTEX_QUOTA, ++ AuLsc_HI_GPARENT, /* setattr with inotify */ ++ AuLsc_HI_PARENT, /* hidden inode, parent first */ ++ AuLsc_HI_CHILD, ++ AuLsc_HI_PARENT2, /* copyup dirs */ ++ AuLsc_HI_CHILD2, ++ AuLsc_End ++}; ++ ++/* simple abstraction */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++static inline void i_lock(struct inode *i) ++{ ++ down(&i->i_sem); ++} ++ ++static inline void i_unlock(struct inode *i) ++{ ++ up(&i->i_sem); ++} ++ ++static inline int i_trylock(struct inode *i) ++{ ++ return down_trylock(&i->i_sem); ++} ++ ++static inline void hi_lock(struct inode *i, unsigned int lsc) ++{ ++ i_lock(i); ++} ++ ++#define IMustLock(i) DEBUG_ON(!down_trylock(&(i)->i_sem)) ++#else ++static inline void i_lock(struct inode *i) ++{ ++ mutex_lock(&i->i_mutex); ++} ++ ++static inline void i_unlock(struct inode *i) ++{ ++ mutex_unlock(&i->i_mutex); ++} ++ ++static inline int i_trylock(struct inode *i) ++{ ++ return mutex_trylock(&i->i_mutex); ++} ++ ++static inline void hi_lock(struct inode *i, unsigned int lsc) ++{ ++ mutex_lock_nested(&i->i_mutex, lsc); ++} ++ ++#define IMustLock(i) MtxMustLock(&(i)->i_mutex) ++#endif ++ ++/* ++ * hi_lock_gparent, hi_lock_parent, hi_lock_parent2, hi_lock_child, ++ * hi_lock_child2, hi_lock_whplink ++ */ ++#define LockFunc(name, lsc) \ ++static inline void hi_lock_##name(struct inode *h_i) \ ++{hi_lock(h_i, AuLsc_HI_##lsc);} ++ ++LockFunc(gparent, GPARENT); ++LockFunc(parent, PARENT); ++LockFunc(parent2, PARENT2); ++LockFunc(child, CHILD); ++LockFunc(child2, CHILD2); ++LockFunc(whplink, CHILD2); /* sharing lock-subclass */ ++ ++#undef LockFunc ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ //IiMustAnyLock(inode); ++ return !(itoii(inode)->ii_hsb1 == h_inode->i_sb ++ && inode->i_generation == h_inode->i_generation); ++} ++ ++static inline int au_iigen(struct inode *inode) ++{ ++ return atomic_read(&itoii(inode)->ii_generation); ++} ++ ++#ifdef CONFIG_AUFS_HINOTIFY ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ //Dbg("i%lu\n", inode->i_ino); ++ atomic_dec(&itoii(inode)->ii_generation); ++} ++ ++/* hinotify.c */ ++int alloc_hinotify(struct aufs_hinode *hinode, struct inode *inode, ++ struct inode *h_inode); ++void do_free_hinotify(struct aufs_hinode *hinode); ++void do_hdir_lock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex, ++ unsigned int lsc); ++void hdir_unlock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex); ++void hdir_lock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir); ++void hdir_unlock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir); ++void au_reset_hinotify(struct inode *inode, unsigned int flags); ++int __init au_inotify_init(void); ++void au_inotify_fin(void); ++#else ++static inline ++int alloc_hinotify(struct aufs_hinode *hinode, struct inode *inode, ++ struct inode *h_inode) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline void do_free_hinotify(struct aufs_hinode *hinode) ++{ ++ /* nothing */ ++} ++ ++static inline ++void do_hdir_lock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex, ++ unsigned int lsc) ++{ ++ hi_lock(h_dir, lsc); ++} ++ ++static inline ++void hdir_unlock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex) ++{ ++ i_unlock(h_dir); ++} ++ ++static inline ++void hdir_lock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir) ++{ ++ vfsub_lock_rename(h_parents[0], h_parents[1]); ++} ++ ++static inline ++void hdir_unlock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir) ++{ ++ vfsub_unlock_rename(h_parents[0], h_parents[1]); ++} ++ ++static inline void au_reset_hinotify(struct inode *inode, unsigned int flags) ++{ ++ /* nothing */ ++} ++ ++#define au_inotify_init() 0 ++#define au_inotify_fin() /* */ ++#endif /* CONFIG_AUFS_HINOTIFY */ ++ ++static inline void free_hinotify(struct inode *inode, aufs_bindex_t bindex) ++{ ++ do_free_hinotify(itoii(inode)->ii_hinode + bindex); ++} ++ ++/* ++ * hgdir_lock, hdir_lock, hdir2_lock ++ */ ++#define LockFunc(name, lsc) \ ++static inline \ ++void name##_lock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex) \ ++{do_hdir_lock(h_dir, dir, bindex, AuLsc_HI_##lsc);} ++ ++LockFunc(hgdir, GPARENT); ++LockFunc(hdir, PARENT); ++LockFunc(hdir2, PARENT2); ++ ++#undef LockFunc ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hinotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, ++ AuLsc_II_NEW /* new inode */ ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new, ii_write_lock_new ++ */ ++#define ReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{rw_read_lock_nested(&itoii(i)->ii_rwsem, AuLsc_II_##lsc);} ++ ++#define WriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{rw_write_lock_nested(&itoii(i)->ii_rwsem, AuLsc_II_##lsc);} ++ ++#define RWLockFuncs(name, lsc) \ ++ ReadLockFunc(name, lsc); \ ++ WriteLockFunc(name, lsc) ++ ++RWLockFuncs(child, CHILD); ++RWLockFuncs(child2, CHILD2); ++RWLockFuncs(child3, CHILD3); ++RWLockFuncs(parent, PARENT); ++RWLockFuncs(parent2, PARENT2); ++RWLockFuncs(parent3, PARENT3); ++RWLockFuncs(new, NEW); ++ ++#undef ReadLockFunc ++#undef WriteLockFunc ++#undef RWLockFunc ++ ++/* ++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock ++ */ ++SimpleUnlockRwsemFuncs(ii, struct inode *i, itoii(i)->ii_rwsem); ++ ++/* to debug easier, do not make them inlined functions */ ++#define IiMustReadLock(i) do { \ ++ SiMustAnyLock((i)->i_sb); \ ++ RwMustReadLock(&itoii(i)->ii_rwsem); \ ++} while (0) ++ ++#define IiMustWriteLock(i) do { \ ++ SiMustAnyLock((i)->i_sb); \ ++ RwMustWriteLock(&itoii(i)->ii_rwsem); \ ++} while (0) ++ ++#define IiMustAnyLock(i) do { \ ++ SiMustAnyLock((i)->i_sb); \ ++ RwMustAnyLock(&itoii(i)->ii_rwsem); \ ++} while (0) ++ ++#define IiMustNoWaiters(i) RwMustNoWaiters(&itoii(i)->ii_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff --git a/fs/aufs/misc.c b/fs/aufs/misc.c +new file mode 100755 +index 0000000..32e0549 +--- /dev/null ++++ b/fs/aufs/misc.c +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: misc.c,v 1.31 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++//#include ++//#include ++//#include ++//#include ++#include "aufs.h" ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) ++{ ++ void *q; ++ ++ LKTRTrace("p %p, nused %d, sz %d, ksize %d\n", ++ p, nused, new_sz, ksize(p)); ++ DEBUG_ON(new_sz <= 0); ++ if (new_sz <= nused) ++ return p; ++ if (new_sz <= ksize(p)) { ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++ } ++ ++ q = kmalloc(new_sz, gfp); ++ //q = NULL; ++ if (unlikely(!q)) ++ return NULL; ++ memcpy(q, p, nused); ++ memset(q + nused, 0, new_sz - nused); ++ //smp_mb(); ++ kfree(p); ++ return q; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++// todo: make it inline ++struct nameidata *fake_dm(struct nameidata *fake_nd, struct nameidata *nd, ++ struct super_block *sb, aufs_bindex_t bindex) ++{ ++ LKTRTrace("nd %p, b%d\n", nd, bindex); ++ ++ if (!nd) ++ return NULL; ++ ++ fake_nd->dentry = NULL; ++ fake_nd->mnt = NULL; ++ ++#ifndef CONFIG_AUFS_FAKE_DM ++ DiMustAnyLock(nd->dentry); ++ ++ if (bindex <= dbend(nd->dentry)) ++ fake_nd->dentry = au_h_dptr_i(nd->dentry, bindex); ++ if (fake_nd->dentry) { ++ dget(fake_nd->dentry); ++ fake_nd->mnt = sbr_mnt(sb, bindex); ++ DEBUG_ON(!fake_nd->mnt); ++ mntget(fake_nd->mnt); ++ } else ++ fake_nd = ERR_PTR(-ENOENT); ++#endif ++ ++ TraceErrPtr(fake_nd); ++ return fake_nd; ++} ++ ++void fake_dm_release(struct nameidata *fake_nd) ++{ ++#ifndef CONFIG_AUFS_FAKE_DM ++ if (fake_nd) { ++ mntput(fake_nd->mnt); ++ dput(fake_nd->dentry); ++ } ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len, ++ struct super_block *sb, int *sparse) ++{ ++ int err, all_zero, dlgt; ++ unsigned long blksize; ++ char *buf; ++ /* reduce stack space */ ++ struct iattr *ia; ++ ++ LKTRTrace("%.*s, %.*s\n", ++ DLNPair(dst->f_dentry), DLNPair(src->f_dentry)); ++ DEBUG_ON(!(dst->f_mode & FMODE_WRITE)); ++ IMustLock(dst->f_dentry->d_parent->d_inode); ++ ++ err = -ENOMEM; ++ blksize = dst->f_dentry->d_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ LKTRTrace("blksize %lu\n", blksize); ++ buf = kmalloc(blksize, GFP_KERNEL); ++ //buf = NULL; ++ if (unlikely(!buf)) ++ goto out; ++ ia = kmalloc(sizeof(*ia), GFP_KERNEL); ++ if (unlikely(!ia)) ++ goto out_buf; ++ ++ dlgt = need_dlgt(sb); ++ err = all_zero = 0; ++ dst->f_pos = src->f_pos = 0; ++ while (len) { ++ size_t sz, rbytes, wbytes, i; ++ char *p; ++ ++ LKTRTrace("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ /* support LSM and notify */ ++ rbytes = 0; ++ while (!rbytes || err == -EAGAIN || err == -EINTR) ++ err = rbytes = vfsub_read_k(src, buf, sz, &src->f_pos, ++ dlgt); ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) { ++ all_zero = 1; ++ p = buf; ++ for (i = 0; all_zero && i < rbytes; i++) ++ all_zero = !*p++; ++ } ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ /* support LSM and notify */ ++ err = b = vfsub_write_k(dst, p, wbytes, ++ &dst->f_pos, dlgt); ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ } else { ++ loff_t res; ++ LKTRLabel(hole); ++ *sparse = 1; ++ err = res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (unlikely(!err && all_zero)) { ++ struct dentry *h_d = dst->f_dentry; ++ struct inode *h_i = h_d->d_inode; ++ ++ LKTRLabel(last hole); ++ do { ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos, dlgt); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) { ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ hi_lock_child2(h_i); ++ err = vfsub_notify_change(h_d, ia, dlgt); ++ i_unlock(h_i); ++ } ++ } ++ ++ kfree(ia); ++ out_buf: ++ kfree(buf); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int test_ro(struct super_block *sb, aufs_bindex_t bindex, struct inode *inode) ++{ ++ int err; ++ ++ err = br_rdonly(stobr(sb, bindex)); ++ if (!err && inode) { ++ struct inode *hi = au_h_iptr_i(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ return err; ++} ++ ++int au_test_perm(struct inode *hidden_inode, int mask, int dlgt) ++{ ++ if (!current->fsuid) ++ return 0; ++ if (unlikely(au_is_nfs(hidden_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(hidden_inode->i_mode))) ++ mask |= MAY_READ; /* force permission check */ ++ return vfsub_permission(hidden_inode, mask, NULL, dlgt); ++} +diff --git a/fs/aufs/misc.h b/fs/aufs/misc.h +new file mode 100755 +index 0000000..fea4a2c +--- /dev/null ++++ b/fs/aufs/misc.h +@@ -0,0 +1,187 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: misc.h,v 1.25 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_MISC_H__ ++#define __AUFS_MISC_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#define I_MUTEX_QUOTA 0 ++#define lockdep_off() /* */ ++#define lockdep_on() /* */ ++#define mutex_lock_nested(mtx, lsc) mutex_lock(mtx) ++#define down_write_nested(rw, lsc) down_write(rw) ++#define down_read_nested(rw, lsc) down_read(rw) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_rwsem { ++ struct rw_semaphore rwsem; ++#ifdef CONFIG_AUFS_DEBUG ++ atomic_t rcnt; ++#endif ++}; ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DbgRcntInit(rw) atomic_set(&(rw)->rcnt, 0) ++#define DbgRcntInc(rw) atomic_inc(&(rw)->rcnt) ++#define DbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0) ++#else ++#define DbgRcntInit(rw) /* */ ++#define DbgRcntInc(rw) /* */ ++#define DbgRcntDec(rw) /* */ ++#endif ++ ++static inline void rw_init_nolock(struct aufs_rwsem *rw) ++{ ++ DbgRcntInit(rw); ++ init_rwsem(&rw->rwsem); ++} ++ ++static inline void rw_init_wlock(struct aufs_rwsem *rw) ++{ ++ rw_init_nolock(rw); ++ down_write(&rw->rwsem); ++} ++ ++static inline void rw_init_wlock_nested(struct aufs_rwsem *rw, unsigned int lsc) ++{ ++ rw_init_nolock(rw); ++ down_write_nested(&rw->rwsem, lsc); ++} ++ ++static inline void rw_read_lock(struct aufs_rwsem *rw) ++{ ++ down_read(&rw->rwsem); ++ DbgRcntInc(rw); ++} ++ ++static inline void rw_read_lock_nested(struct aufs_rwsem *rw, unsigned int lsc) ++{ ++ down_read_nested(&rw->rwsem, lsc); ++ DbgRcntInc(rw); ++} ++ ++static inline void rw_read_unlock(struct aufs_rwsem *rw) ++{ ++ DbgRcntDec(rw); ++ up_read(&rw->rwsem); ++} ++ ++static inline void rw_dgrade_lock(struct aufs_rwsem *rw) ++{ ++ DbgRcntInc(rw); ++ downgrade_write(&rw->rwsem); ++} ++ ++static inline void rw_write_lock(struct aufs_rwsem *rw) ++{ ++ down_write(&rw->rwsem); ++} ++ ++static inline void rw_write_lock_nested(struct aufs_rwsem *rw, unsigned int lsc) ++{ ++ down_write_nested(&rw->rwsem, lsc); ++} ++ ++static inline void rw_write_unlock(struct aufs_rwsem *rw) ++{ ++ up_write(&rw->rwsem); ++} ++ ++#if 0 // why is not _nested version defined ++static inline int rw_read_trylock(struct aufs_rwsem *rw) ++{ ++ int ret = down_read_trylock(&rw->rwsem); ++ if (ret) ++ DbgRcntInc(rw); ++ return ret; ++} ++ ++static inline int rw_write_trylock(struct aufs_rwsem *rw) ++{ ++ return down_write_trylock(&rw->rwsem); ++} ++#endif ++ ++#undef DbgRcntInit ++#undef DbgRcntInc ++#undef DbgRcntDec ++ ++/* to debug easier, do not make them inlined functions */ ++#define RwMustNoWaiters(rw) DEBUG_ON(!list_empty(&(rw)->rwsem.wait_list)) ++#define RwMustAnyLock(rw) DEBUG_ON(down_write_trylock(&(rw)->rwsem)) ++#ifdef CONFIG_AUFS_DEBUG ++#define RwMustReadLock(rw) do { \ ++ RwMustAnyLock(rw); \ ++ DEBUG_ON(!atomic_read(&(rw)->rcnt)); \ ++} while (0) ++#define RwMustWriteLock(rw) do { \ ++ RwMustAnyLock(rw); \ ++ DEBUG_ON(atomic_read(&(rw)->rcnt)); \ ++} while (0) ++#else ++#define RwMustReadLock(rw) RwMustAnyLock(rw) ++#define RwMustWriteLock(rw) RwMustAnyLock(rw) ++#endif ++ ++#define SimpleLockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_lock(param) {rw_read_lock(&(rwsem));} \ ++static inline void prefix##_write_lock(param) {rw_write_lock(&(rwsem));} ++//static inline void prefix##_read_trylock(param) {rw_read_trylock(&(rwsem));} ++//static inline void prefix##_write_trylock(param) {rw_write_trylock(&(rwsem));} ++//static inline void prefix##_read_trylock_nested(param, lsc) ++//{rw_read_trylock_nested(&(rwsem, lsc));} ++//static inline void prefix##_write_trylock_nestd(param, lsc) ++//{rw_write_trylock_nested(&(rwsem), nested);} ++ ++#define SimpleUnlockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_unlock(param) {rw_read_unlock(&(rwsem));} \ ++static inline void prefix##_write_unlock(param) {rw_write_unlock(&(rwsem));} \ ++static inline void prefix##_downgrade_lock(param) {rw_dgrade_lock(&(rwsem));} ++ ++#define SimpleRwsemFuncs(prefix, param, rwsem) \ ++ SimpleLockRwsemFuncs(prefix, param, rwsem); \ ++ SimpleUnlockRwsemFuncs(prefix, param, rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef ssize_t (*readf_t)(struct file*, char __user*, size_t, loff_t*); ++typedef ssize_t (*writef_t)(struct file*, const char __user*, size_t, loff_t*); ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); ++struct nameidata *fake_dm(struct nameidata *fake_nd, struct nameidata *nd, ++ struct super_block *sb, aufs_bindex_t bindex); ++void fake_dm_release(struct nameidata *fake_nd); ++int au_copy_file(struct file *dst, struct file *src, loff_t len, ++ struct super_block *sb, int *sparse); ++int test_ro(struct super_block *sb, aufs_bindex_t bindex, struct inode *inode); ++int au_test_perm(struct inode *h_inode, int mask, int dlgt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MISC_H__ */ +diff --git a/fs/aufs/module.c b/fs/aufs/module.c +new file mode 100755 +index 0000000..06c563e +--- /dev/null ++++ b/fs/aufs/module.c +@@ -0,0 +1,334 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: module.c,v 1.9 2007/04/30 05:46:32 sfjro Exp $ */ ++ ++//#include ++//#include ++#include ++//#include ++//#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *aufs_cachep[AuCache_Last]; ++static int __init create_cache(void) ++{ ++#define Cache(type) kmem_cache_create(#type, sizeof(struct type), 0, \ ++ SLAB_RECLAIM_ACCOUNT, NULL, NULL) ++ ++ if ((aufs_cachep[AuCache_DINFO] = Cache(aufs_dinfo)) ++ && (aufs_cachep[AuCache_ICNTNR] = Cache(aufs_icntnr)) ++ && (aufs_cachep[AuCache_FINFO] = Cache(aufs_finfo)) ++ //&& (aufs_cachep[AuCache_FINFO] = NULL) ++ && (aufs_cachep[AuCache_VDIR] = Cache(aufs_vdir)) ++ && (aufs_cachep[AuCache_DEHSTR] = Cache(aufs_dehstr)) ++ && (aufs_cachep[AuCache_HINOTIFY] = Cache(aufs_hinotify))) ++ return 0; ++ return -ENOMEM; ++ ++#undef Cache ++} ++ ++static void destroy_cache(void) ++{ ++ int i; ++ for (i = 0; i < AuCache_Last; i++) ++ if (aufs_cachep[i]) ++ kmem_cache_destroy(aufs_cachep[i]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++int au_dir_roflags; ++extern struct file_system_type aufs_fs_type; ++ ++#ifdef DbgDlgt ++#include ++#include "dbg_dlgt.c" ++#else ++#define dbg_dlgt_init() 0 ++#define dbg_dlgt_fin() /* */ ++#endif ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Junjiro Okajima"); ++MODULE_DESCRIPTION(AUFS_NAME " -- Another unionfs"); ++MODULE_VERSION(AUFS_VERSION); ++ ++/* it should be 'byte', but param_set_byte() prints by "%c" */ ++short aufs_nwkq = AUFS_NWKQ_DEF; ++MODULE_PARM_DESC(nwkq, "the number of workqueue thread, " AUFS_WKQ_NAME); ++module_param_named(nwkq, aufs_nwkq, short, 0444); ++ ++int sysaufs_brs = 0; ++MODULE_PARM_DESC(brs, "use /fs/aufs/brs"); ++module_param_named(brs, sysaufs_brs, int, 0444); ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ //sbinfo->si_xino is atomic_long_t ++ BUILD_BUG_ON(sizeof(ino_t) != sizeof(long)); ++ ++#ifdef CONFIG_AUFS_DEBUG ++ { ++ struct aufs_destr destr; ++ destr.len = -1; ++ DEBUG_ON(destr.len < NAME_MAX); ++ } ++ ++#ifdef CONFIG_4KSTACKS ++ printk("CONFIG_4KSTACKS is defined.\n"); ++#endif ++#if 0 // verbose debug ++ { ++ union { ++ struct aufs_branch *br; ++ struct aufs_dinfo *di; ++ struct aufs_finfo *fi; ++ struct aufs_iinfo *ii; ++ struct aufs_hinode *hi; ++ struct aufs_sbinfo *si; ++ struct aufs_destr *destr; ++ struct aufs_de *de; ++ struct aufs_wh *wh; ++ struct aufs_vdir *vd; ++ } u; ++ ++ printk("br{" ++ "xino %d, readf %d, writef %d, " ++ "id %d, perm %d, mnt %d, count %d, " ++ "wh_sem %d, wh %d, run %d} %d\n", ++ offsetof(typeof(*u.br), br_xino), ++ offsetof(typeof(*u.br), br_xino_read), ++ offsetof(typeof(*u.br), br_xino_write), ++ offsetof(typeof(*u.br), br_id), ++ offsetof(typeof(*u.br), br_perm), ++ offsetof(typeof(*u.br), br_mnt), ++ offsetof(typeof(*u.br), br_count), ++ offsetof(typeof(*u.br), br_wh_rwsem), ++ offsetof(typeof(*u.br), br_wh), ++ offsetof(typeof(*u.br), br_wh_running), ++ sizeof(*u.br)); ++ printk("di{gen %d, rwsem %d, bstart %d, bend %d, bwh %d, " ++ "bdiropq %d, hdentry %d, reval %d} %d\n", ++ offsetof(typeof(*u.di), di_generation), ++ offsetof(typeof(*u.di), di_rwsem), ++ offsetof(typeof(*u.di), di_bstart), ++ offsetof(typeof(*u.di), di_bend), ++ offsetof(typeof(*u.di), di_bwh), ++ offsetof(typeof(*u.di), di_bdiropq), ++ offsetof(typeof(*u.di), di_hdentry), ++ offsetof(typeof(*u.di), di_reval), ++ sizeof(*u.di)); ++ printk("fi{gen %d, rwsem %d, hfile %d, bstart %d, bend %d, " ++ "h_vm_ops %d, vdir_cach %d} %d\n", ++ offsetof(typeof(*u.fi), fi_generation), ++ offsetof(typeof(*u.fi), fi_rwsem), ++ offsetof(typeof(*u.fi), fi_hfile), ++ offsetof(typeof(*u.fi), fi_bstart), ++ offsetof(typeof(*u.fi), fi_bend), ++ offsetof(typeof(*u.fi), fi_h_vm_ops), ++ offsetof(typeof(*u.fi), fi_vdir_cache), ++ sizeof(*u.fi)); ++ printk("ii{rwsem %d, bstart %d, bend %d, hinode %d, vdir %d} " ++ "%d\n", ++ offsetof(typeof(*u.ii), ii_rwsem), ++ offsetof(typeof(*u.ii), ii_bstart), ++ offsetof(typeof(*u.ii), ii_bend), ++ offsetof(typeof(*u.ii), ii_hinode), ++ offsetof(typeof(*u.ii), ii_vdir), ++ sizeof(*u.ii)); ++ printk("hi{inode %d, id %d, notify %d} %d\n", ++ offsetof(typeof(*u.hi), hi_inode), ++ offsetof(typeof(*u.hi), hi_id), ++ offsetof(typeof(*u.hi), hi_notify), ++ sizeof(*u.hi)); ++ printk("si{rwsem %d, gen %d, " ++ "failed_refresh %d, " ++ "bend %d, last id %d, br %d, " ++ "flags %d, " ++ "xino %d, " ++ "rdcache %d, " ++ "dirwh %d, " ++ "pl_lock %d, pl %d, " ++ "kobj %d} %d\n", ++ offsetof(typeof(*u.si), si_rwsem), ++ offsetof(typeof(*u.si), si_generation), ++ -1,//offsetof(typeof(*u.si), si_failed_refresh_dirs), ++ offsetof(typeof(*u.si), si_bend), ++ offsetof(typeof(*u.si), si_last_br_id), ++ offsetof(typeof(*u.si), si_branch), ++ offsetof(typeof(*u.si), si_flags), ++ offsetof(typeof(*u.si), si_xino), ++ offsetof(typeof(*u.si), si_rdcache), ++ offsetof(typeof(*u.si), si_dirwh), ++ offsetof(typeof(*u.si), si_plink_lock), ++ offsetof(typeof(*u.si), si_plink), ++ offsetof(typeof(*u.si), si_kobj), ++ sizeof(*u.si)); ++ printk("destr{len %d, name %d} %d\n", ++ offsetof(typeof(*u.destr), len), ++ offsetof(typeof(*u.destr), name), ++ sizeof(*u.destr)); ++ printk("de{ino %d, type %d, str %d} %d\n", ++ offsetof(typeof(*u.de), de_ino), ++ offsetof(typeof(*u.de), de_type), ++ offsetof(typeof(*u.de), de_str), ++ sizeof(*u.de)); ++ printk("wh{hash %d, bindex %d, str %d} %d\n", ++ offsetof(typeof(*u.wh), wh_hash), ++ offsetof(typeof(*u.wh), wh_bindex), ++ offsetof(typeof(*u.wh), wh_str), ++ sizeof(*u.wh)); ++ printk("vd{deblk %d, nblk %d, last %d, ver %d, jiffy %d} %d\n", ++ offsetof(typeof(*u.vd), vd_deblk), ++ offsetof(typeof(*u.vd), vd_nblk), ++ offsetof(typeof(*u.vd), vd_last), ++ offsetof(typeof(*u.vd), vd_version), ++ offsetof(typeof(*u.vd), vd_jiffy), ++ sizeof(*u.vd)); ++ } ++#endif ++#endif ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++#ifndef CONFIG_AUFS_SYSAUFS ++ sysaufs_brs = 0; ++#endif ++ ++ err = -EINVAL; ++ if (unlikely(aufs_nwkq <= 0)) ++ goto out; ++ err = create_cache(); ++ if (unlikely(err)) ++ goto out; ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out_cache; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_kobj; ++ err = au_inotify_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = dbg_dlgt_init(); ++ if (unlikely(err)) ++ goto out_inotify; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_dlgt; ++ printk(AUFS_NAME " " AUFS_VERSION "\n"); ++ return 0; /* success */ ++ ++ out_dlgt: ++ dbg_dlgt_fin(); ++ out_inotify: ++ au_inotify_fin(); ++ out_wkq: ++ au_wkq_fin(); ++ out_kobj: ++ sysaufs_fin(); ++ out_cache: ++ destroy_cache(); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ dbg_dlgt_fin(); ++ au_inotify_fin(); ++ au_wkq_fin(); ++ sysaufs_fin(); ++ destroy_cache(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); ++ ++/* ---------------------------------------------------------------------- */ ++ ++// fake Kconfig ++#if 1 ++#ifdef CONFIG_AUFS_HINOTIFY ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#error CONFIG_AUFS_HINOTIFY is supported in linux-2.6.18 and later. ++#endif ++#ifndef CONFIG_INOTIFY ++#error enable CONFIG_INOTIFY to use CONFIG_AUFS_HINOTIFY. ++#endif ++#endif ++ ++#if AUFS_BRANCH_MAX > 511 && BITS_PER_LONG == 64 && PAGE_SIZE == 4096 ++#warning For 4k pagesize and 64bit environment, \ ++ CONFIG_AUFS_BRANCH_MAX_511 or smaller is recommended. ++#endif ++ ++#ifdef CONFIG_AUFS_SYSAUFS ++#ifndef CONFIG_SYSFS ++#error CONFIG_AUFS_SYSAUFS requires CONFIG_SYSFS. ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#error CONFIG_AUFS_SYSAUFS requires linux-2.6.18 and later. ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_EXPORT ++#if !defined(CONFIG_EXPORTFS) && !defined(CONFIG_EXPORTFS_MODULE) ++#error CONFIG_AUFS_EXPORT requires CONFIG_EXPORTFS ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#error CONFIG_AUFS_EXPORT requires linux-2.6.18 and later. ++#endif ++#if defined(CONFIG_EXPORTFS_MODULE) && defined(CONFIG_AUFS) ++#error need CONFIG_EXPORTFS=y to link aufs statically with CONFIG_AUFS_EXPORT ++#endif ++#endif ++ ++#ifdef CONFIG_DEBUG_PROVE_LOCKING ++#if MAX_LOCKDEP_SUBCLASSES < AuLsc_End ++#warning lockdep will not work since aufs uses deeper locks. ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_COMPAT ++#warning CONFIG_AUFS_COMPAT will be removed in the near future. ++#endif ++ ++#endif +diff --git a/fs/aufs/module.h b/fs/aufs/module.h +new file mode 100755 +index 0000000..3769861 +--- /dev/null ++++ b/fs/aufs/module.h +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: module.h,v 1.8 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameters */ ++extern short aufs_nwkq; ++extern int sysaufs_brs; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern char au_esc_chars[]; ++extern int au_dir_roflags; ++ ++/* kmem cache */ ++enum {AuCache_DINFO, AuCache_ICNTNR, AuCache_FINFO, AuCache_VDIR, ++ AuCache_DEHSTR, AuCache_HINOTIFY, AuCache_Last}; ++extern struct kmem_cache *aufs_cachep[]; ++ ++#define CacheFuncs(name, index) \ ++static inline void *cache_alloc_##name(void) \ ++{return kmem_cache_alloc(aufs_cachep[index], GFP_KERNEL);} \ ++static inline void cache_free_##name(void *p) \ ++{kmem_cache_free(aufs_cachep[index], p);} ++ ++CacheFuncs(dinfo, AuCache_DINFO); ++CacheFuncs(icntnr, AuCache_ICNTNR); ++CacheFuncs(finfo, AuCache_FINFO); ++CacheFuncs(vdir, AuCache_VDIR); ++CacheFuncs(dehstr, AuCache_DEHSTR); ++CacheFuncs(hinotify, AuCache_HINOTIFY); ++ ++#undef CacheFuncs ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c +new file mode 100755 +index 0000000..c1a9445 +--- /dev/null ++++ b/fs/aufs/opts.c +@@ -0,0 +1,1043 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: opts.c,v 1.34 2007/05/14 03:40:27 sfjro Exp $ */ ++ ++#include // a distribution requires ++#include ++#include "aufs.h" ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_deblk, Opt_nhash, ++ Opt_xino, Opt_zxino, Opt_noxino, ++ Opt_plink, Opt_noplink, Opt_list_plink, Opt_clean_plink, ++ Opt_udba, ++ Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, Opt_nowarn_perm, ++ Opt_findrw_dir, Opt_findrw_br, ++ Opt_coo, ++ Opt_dlgt, Opt_nodlgt, ++ Opt_tail, Opt_ignore, Opt_err ++}; ++ ++static match_table_t options = { ++ {Opt_br, "br=%s"}, ++ {Opt_br, "br:%s"}, ++ ++ {Opt_add, "add=%d:%s"}, ++ {Opt_add, "add:%d:%s"}, ++ {Opt_add, "ins=%d:%s"}, ++ {Opt_add, "ins:%d:%s"}, ++ {Opt_append, "append=%s"}, ++ {Opt_append, "append:%s"}, ++ {Opt_prepend, "prepend=%s"}, ++ {Opt_prepend, "prepend:%s"}, ++ ++ {Opt_del, "del=%s"}, ++ {Opt_del, "del:%s"}, ++ //{Opt_idel, "idel:%d"}, ++ {Opt_mod, "mod=%s"}, ++ {Opt_mod, "mod:%s"}, ++ //{Opt_imod, "imod:%d:%s"}, ++ ++ {Opt_dirwh, "dirwh=%d"}, ++ {Opt_dirwh, "dirwh:%d"}, ++ ++ {Opt_xino, "xino=%s"}, ++ {Opt_xino, "xino:%s"}, ++ {Opt_noxino, "noxino"}, ++ //{Opt_zxino, "zxino=%s"}, ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++ {Opt_plink, "plink"}, ++ {Opt_noplink, "noplink"}, ++#ifdef CONFIG_AUFS_DEBUG ++ {Opt_list_plink, "list_plink"}, ++#endif ++ {Opt_clean_plink, "clean_plink"}, ++#endif ++ ++ {Opt_udba, "udba=%s"}, ++ ++ {Opt_diropq_a, "diropq=always"}, ++ {Opt_diropq_a, "diropq=a"}, ++ {Opt_diropq_w, "diropq=whiteouted"}, ++ {Opt_diropq_w, "diropq=w"}, ++ ++ {Opt_warn_perm, "warn_perm"}, ++ {Opt_nowarn_perm, "nowarn_perm"}, ++ ++#ifdef CONFIG_AUFS_DLGT ++ {Opt_dlgt, "dlgt"}, ++ {Opt_nodlgt, "nodlgt"}, ++#endif ++ ++ {Opt_rdcache, "rdcache=%d"}, ++ {Opt_rdcache, "rdcache:%d"}, ++#if 0 ++ {Opt_findrw_dir, "findrw=dir"}, ++ {Opt_findrw_br, "findrw=br"}, ++ ++ {Opt_coo, "coo=%s"}, ++ ++ {Opt_deblk, "deblk=%d"}, ++ {Opt_deblk, "deblk:%d"}, ++ {Opt_nhash, "nhash=%d"}, ++ {Opt_nhash, "nhash:%d"}, ++#endif ++ ++ {Opt_br, "dirs=%s"}, ++ {Opt_ignore, "debug=%d"}, ++ {Opt_ignore, "delete=whiteout"}, ++ {Opt_ignore, "delete=all"}, ++ {Opt_ignore, "imap=%s"}, ++ ++ {Opt_err, NULL} ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define RW "rw" ++#define RO "ro" ++#define WH "wh" ++#define RR "rr" ++#define NoLinkWH "nolwh" ++ ++static match_table_t brperms = { ++ {AuBr_RR, RR}, ++ {AuBr_RO, RO}, ++ {AuBr_RW, RW}, ++ ++ {AuBr_RRWH, RR "+" WH}, ++ {AuBr_ROWH, RO "+" WH}, ++ {AuBr_RWNoLinkWH, RW "+" NoLinkWH}, ++ ++ {AuBr_ROWH, "nfsro"}, ++ {AuBr_RO, NULL} ++}; ++ ++static int br_perm_val(char *perm) ++{ ++ int val; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ DEBUG_ON(!perm || !*perm); ++ LKTRTrace("perm %s\n", perm); ++ val = match_token(perm, brperms, args); ++ TraceErr(val); ++ return val; ++} ++ ++int br_perm_str(char *p, unsigned int len, int brperm) ++{ ++ struct match_token *bp = brperms; ++ ++ LKTRTrace("len %d, 0x%x\n", len, brperm); ++ ++ while (bp->pattern) { ++ if (bp->token == brperm) { ++ if (strlen(bp->pattern) < len) { ++ strcpy(p, bp->pattern); ++ return 0; ++ } else ++ return -E2BIG; ++ } ++ bp++; ++ } ++ ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuFlag_UDBA_REVAL, "reval"}, ++#ifdef CONFIG_AUFS_HINOTIFY ++ {AuFlag_UDBA_INOTIFY, "inotify"}, ++#endif ++ {AuFlag_UDBA_NONE, "none"}, ++ {-1, NULL} ++}; ++ ++static int udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ return match_token(str, udbalevel, args); ++} ++ ++au_parser_pattern_t udba_str(int udba) ++{ ++ struct match_token *p = udbalevel; ++ while (p->pattern) { ++ if (p->token == udba) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++void udba_set(struct super_block *sb, unsigned int flg) ++{ ++ au_flag_clr(sb, AuMask_UDBA); ++ au_flag_set(sb, flg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t coolevel = { ++ {AuFlag_COO_LEAF, "leaf"}, ++ {AuFlag_COO_ALL, "all"}, ++ {AuFlag_COO_NONE, "none"}, ++ {-1, NULL} ++}; ++ ++#if 0 ++static int coo_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ return match_token(str, coolevel, args); ++} ++#endif ++ ++au_parser_pattern_t coo_str(int coo) ++{ ++ struct match_token *p = coolevel; ++ while (p->pattern) { ++ if (p->token == coo) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++static void coo_set(struct super_block *sb, unsigned int flg) ++{ ++ au_flag_clr(sb, AuMask_COO); ++ au_flag_set(sb, flg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; ++ ++#ifdef CONFIG_AUFS_DEBUG ++static void dump_opts(struct opts *opts) ++{ ++ /* reduce stack space */ ++ union { ++ struct opt_add *add; ++ struct opt_del *del; ++ struct opt_mod *mod; ++ struct opt_xino *xino; ++ } u; ++ struct opt *opt; ++ ++ TraceEnter(); ++ ++ opt = opts->opt; ++ while (/* opt < opts_tail && */ opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ LKTRTrace("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->path, u.add->perm, ++ u.add->nd.dentry); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ u.del = &opt->del; ++ LKTRTrace("del {%s, %p}\n", u.del->path, u.del->h_root); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ u.mod = &opt->mod; ++ LKTRTrace("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ LKTRTrace("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->path, u.add->perm, ++ u.add->nd.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ LKTRTrace("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->path, u.add->perm, ++ u.add->nd.dentry); ++ break; ++ case Opt_dirwh: ++ LKTRTrace("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ LKTRTrace("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_xino: ++ u.xino = &opt->xino; ++ LKTRTrace("xino {%s %.*s}\n", ++ u.xino->path, DLNPair(u.xino->file->f_dentry)); ++ break; ++ case Opt_noxino: ++ LKTRLabel(noxino); ++ break; ++ case Opt_plink: ++ LKTRLabel(plink); ++ break; ++ case Opt_noplink: ++ LKTRLabel(noplink); ++ break; ++ case Opt_list_plink: ++ LKTRLabel(list_plink); ++ break; ++ case Opt_clean_plink: ++ LKTRLabel(clean_plink); ++ break; ++ case Opt_udba: ++ LKTRTrace("udba %d, %s\n", ++ opt->udba, udba_str(opt->udba)); ++ break; ++ case Opt_diropq_a: ++ LKTRLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ LKTRLabel(diropq_w); ++ break; ++ case Opt_warn_perm: ++ LKTRLabel(warn_perm); ++ break; ++ case Opt_nowarn_perm: ++ LKTRLabel(nowarn_perm); ++ break; ++ case Opt_dlgt: ++ LKTRLabel(dlgt); ++ break; ++ case Opt_nodlgt: ++ LKTRLabel(nodlgt); ++ break; ++ case Opt_coo: ++ LKTRTrace("coo %d, %s\n", opt->coo, coo_str(opt->coo)); ++ break; ++ default: ++ BUG(); ++ } ++ opt++; ++ } ++} ++#else ++#define dump_opts(opts) /* */ ++#endif ++ ++void au_free_opts(struct opts *opts) ++{ ++ struct opt *opt; ++ ++ TraceEnter(); ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ case Opt_append: ++ case Opt_prepend: ++ path_release(&opt->add.nd); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ dput(opt->del.h_root); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static int opt_add(struct opt *opt, char *opt_str, struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct opt_add *add = &opt->add; ++ char *p; ++ ++ LKTRTrace("%s, b%d\n", opt_str, bindex); ++ ++ add->bindex = bindex; ++ add->perm = AuBr_RO; ++ if (!bindex && !(sb->s_flags & MS_RDONLY)) ++ add->perm = AuBr_RW; ++#ifdef CONFIG_AUFS_COMPAT ++ add->perm = AuBr_RW; ++#endif ++ add->path = opt_str; ++ p = strchr(opt_str, '='); ++ if (unlikely(p)) { ++ *p++ = 0; ++ if (*p) ++ add->perm = br_perm_val(p); ++ } ++ ++ // LSM may detect it ++ // do not superio. ++ err = path_lookup(add->path, lkup_dirflags, &add->nd); ++ //err = -1; ++ if (!err) { ++ opt->type = Opt_add; ++ goto out; ++ } ++ Err("lookup failed %s (%d)\n", add->path, err); ++ err = -EINVAL; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* called without aufs lock */ ++int au_parse_opts(struct super_block *sb, char *str, struct opts *opts) ++{ ++ int err, n; ++ struct dentry *root; ++ struct opt *opt, *opt_tail; ++ char *opt_str; ++ substring_t args[MAX_OPT_ARGS]; ++ aufs_bindex_t bindex; ++ struct nameidata nd; ++ /* reduce stack space */ ++ union { ++ struct opt_del *del; ++ struct opt_mod *mod; ++ struct opt_xino *xino; ++ } u; ++ struct file *file; ++ ++ LKTRTrace("%s, nopts %d\n", str, opts->max_opt); ++ ++ root = sb->s_root; ++ err = 0; ++ bindex = 0; ++ opt = opts->opt; ++ opt_tail = opt + opts->max_opt - 1; ++ opt->type = Opt_tail; ++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { ++ int token, skipped; ++ char *p; ++ err = -EINVAL; ++ token = match_token(opt_str, options, args); ++ LKTRTrace("%s, token %d, args[0]{%p, %p}\n", ++ opt_str, token, args[0].from, args[0].to); ++ ++ skipped = 0; ++ switch (token) { ++ case Opt_br: ++ err = 0; ++ while (!err && (opt_str = strsep(&args[0].from, ":")) ++ && *opt_str) { ++ err = opt_add(opt, opt_str, sb, bindex++); ++ //if (LktrCond) err = -1; ++ if (unlikely(!err && ++opt > opt_tail)) { ++ err = -E2BIG; ++ break; ++ } ++ opt->type = Opt_tail; ++ skipped = 1; ++ } ++ break; ++ case Opt_add: ++ if (unlikely(match_int(&args[0], &n))) { ++ Err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ err = opt_add(opt, args[1].from, sb, bindex); ++ break; ++ case Opt_append: ++ case Opt_prepend: ++ err = opt_add(opt, args[0].from, sb, /*dummy bindex*/1); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_del: ++ u.del = &opt->del; ++ u.del->path = args[0].from; ++ LKTRTrace("del path %s\n", u.del->path); ++ // LSM may detect it ++ // do not superio. ++ err = path_lookup(u.del->path, lkup_dirflags, &nd); ++ if (unlikely(err)) { ++ Err("lookup failed %s (%d)\n", u.del->path, err); ++ break; ++ } ++ u.del->h_root = dget(nd.dentry); ++ path_release(&nd); ++ opt->type = token; ++ break; ++#if 0 ++ case Opt_idel: ++ u.del = &opt->del; ++ u.del->path = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ Err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ aufs_read_lock(root, !AUFS_I_RLOCK); ++ if (bindex < 0 || sbend(sb) < bindex) { ++ Err("out of bounds, %d\n", bindex); ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ break; ++ } ++ err = 0; ++ u.del->h_root = dget(au_h_dptr_i(root, bindex)); ++ opt->type = token; ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ break; ++#endif ++ ++ case Opt_mod: ++ u.mod = &opt->mod; ++ u.mod->path = args[0].from; ++ p = strchr(u.mod->path, '='); ++ if (unlikely(!p)) { ++ Err("no permssion %s\n", opt_str); ++ break; ++ } ++ *p++ = 0; ++ u.mod->perm = br_perm_val(p); ++ LKTRTrace("mod path %s, perm 0x%x, %s\n", ++ u.mod->path, u.mod->perm, p); ++ // LSM may detect it ++ // do not superio. ++ err = path_lookup(u.mod->path, lkup_dirflags, &nd); ++ if (unlikely(err)) { ++ Err("lookup failed %s (%d)\n", u.mod->path, err); ++ break; ++ } ++ u.mod->h_root = dget(nd.dentry); ++ path_release(&nd); ++ opt->type = token; ++ break; ++#if 0 ++ case Opt_imod: ++ u.mod = &opt->mod; ++ u.mod->path = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ Err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ aufs_read_lock(root, !AUFS_I_RLOCK); ++ if (bindex < 0 || sbend(sb) < bindex) { ++ Err("out of bounds, %d\n", bindex); ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ break; ++ } ++ u.mod->perm = br_perm_val(args[1].from); ++ LKTRTrace("mod path %s, perm 0x%x, %s\n", ++ u.mod->path, u.mod->perm, args[1].from); ++ err = 0; ++ u.mod->h_root = dget(au_h_dptr_i(root, bindex)); ++ opt->type = token; ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ break; ++#endif ++ case Opt_xino: ++ u.xino = &opt->xino; ++ file = xino_create(sb, args[0].from, /*silent*/0, ++ /*parent*/NULL); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ break; ++ err = -EINVAL; ++ if (unlikely(file->f_dentry->d_sb == sb)) { ++ fput(file); ++ Err("%s must be outside\n", args[0].from); ++ break; ++ } ++ err = 0; ++ u.xino->file = file; ++ u.xino->path = args[0].from; ++ opt->type = token; ++ break; ++ ++ case Opt_dirwh: ++ if (unlikely(match_int(&args[0], &opt->dirwh))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(match_int(&args[0], &opt->rdcache))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_noxino: ++ case Opt_plink: ++ case Opt_noplink: ++ case Opt_list_plink: ++ case Opt_clean_plink: ++ case Opt_diropq_a: ++ case Opt_diropq_w: ++ case Opt_warn_perm: ++ case Opt_nowarn_perm: ++ case Opt_dlgt: ++ case Opt_nodlgt: ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_udba: ++ opt->udba = udba_val(args[0].from); ++ if (opt->udba >= 0) { ++ err = 0; ++ opt->type = token; ++ } ++ break; ++ ++#if 0 ++ case Opt_coo: ++ opt->coo = coo_val(args[0].from); ++ if (opt->coo >= 0) { ++ err = 0; ++ opt->type = token; ++ } ++ break; ++#endif ++ ++ case Opt_ignore: ++#ifndef CONFIG_AUFS_COMPAT ++ Warn("ignored %s\n", opt_str); ++#endif ++ skipped = 1; ++ err = 0; ++ break; ++ case Opt_err: ++ Err("unknown option %s\n", opt_str); ++ break; ++ } ++ ++ if (!err && !skipped) { ++ if (unlikely(++opt > opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ opt->type = Opt_tail; ++ break; ++ } ++ opt->type = Opt_tail; ++ } ++ } ++ ++ dump_opts(opts); ++ if (unlikely(err)) ++ au_free_opts(opts); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_do_opt_simple(struct super_block *sb, struct opt *opt, ++ int remount, unsigned int *given) ++{ ++ int err; ++ struct aufs_sbinfo *sbinfo = stosi(sb); ++ ++ TraceEnter(); ++ ++ err = 1; /* handled */ ++ switch (opt->type) { ++ case Opt_udba: ++ udba_set(sb, opt->udba); ++ *given |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ au_flag_set(sb, AuFlag_PLINK); ++ *given |= AuFlag_PLINK; ++ break; ++ case Opt_noplink: ++ if (au_flag_test(sb, AuFlag_PLINK)) ++ au_put_plink(sb); ++ au_flag_clr(sb, AuFlag_PLINK); ++ *given |= AuFlag_PLINK; ++ break; ++ case Opt_list_plink: ++ if (au_flag_test(sb, AuFlag_PLINK)) ++ au_list_plink(sb); ++ break; ++ case Opt_clean_plink: ++ if (au_flag_test(sb, AuFlag_PLINK)) ++ au_put_plink(sb); ++ break; ++ ++ case Opt_diropq_a: ++ au_flag_set(sb, AuFlag_ALWAYS_DIROPQ); ++ *given |= AuFlag_ALWAYS_DIROPQ; ++ break; ++ case Opt_diropq_w: ++ au_flag_clr(sb, AuFlag_ALWAYS_DIROPQ); ++ *given |= AuFlag_ALWAYS_DIROPQ; ++ break; ++ ++ case Opt_dlgt: ++ au_flag_set(sb, AuFlag_DLGT); ++ *given |= AuFlag_DLGT; ++ break; ++ case Opt_nodlgt: ++ au_flag_clr(sb, AuFlag_DLGT); ++ *given |= AuFlag_DLGT; ++ break; ++ ++ case Opt_warn_perm: ++ au_flag_set(sb, AuFlag_WARN_PERM); ++ *given |= AuFlag_WARN_PERM; ++ break; ++ case Opt_nowarn_perm: ++ au_flag_clr(sb, AuFlag_WARN_PERM); ++ *given |= AuFlag_WARN_PERM; ++ break; ++ ++ case Opt_coo: ++ coo_set(sb, opt->coo); ++ *given |= opt->coo; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache = opt->rdcache * HZ; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_do_opt_br(struct super_block *sb, struct opt *opt, int remount, ++ int *do_refresh) ++{ ++ int err; ++ ++ TraceEnter(); ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = sbend(sb) + 1; ++ goto add; ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ add: ++ case Opt_add: ++ err = br_add(sb, &opt->add, remount); ++ if (!err) ++ *do_refresh = err = 1; ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = br_del(sb, &opt->del, remount); ++ if (!err) ++ *do_refresh = err = 1; ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = br_mod(sb, &opt->mod, remount, do_refresh); ++ if (!err) ++ err = 1; ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int au_do_opt_xino(struct super_block *sb, struct opt *opt, int remount, ++ struct opt_xino **opt_xino) ++{ ++ int err; ++ ++ TraceEnter(); ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = xino_set(sb, &opt->xino, remount); ++ if (!err) ++ *opt_xino = &opt->xino; ++ break; ++ case Opt_noxino: ++ err = xino_clr(sb); ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int verify_opts(struct super_block *sb, int remount) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct aufs_branch *br; ++ struct dentry *root; ++ struct inode *dir; ++ unsigned int do_plink; ++ ++ TraceEnter(); ++ ++ if (unlikely(!(sb->s_flags & MS_RDONLY) ++ && !br_writable(sbr_perm(sb, 0)))) ++ Warn("first branch should be rw\n"); ++ ++ err = 0; ++ root = sb->s_root; ++ dir = sb->s_root->d_inode; ++ do_plink = au_flag_test(sb, AuFlag_PLINK); ++ bend = sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ struct inode *h_dir; ++ int skip; ++ ++ skip = 0; ++ h_dir = au_h_iptr_i(dir, bindex); ++ br = stobr(sb, bindex); ++ br_wh_read_lock(br); ++ switch (br->br_perm) { ++ case AuBr_RR: ++ case AuBr_RO: ++ case AuBr_RRWH: ++ case AuBr_ROWH: ++ skip = (!br->br_wh && !br->br_plink); ++ break; ++ ++ case AuBr_RWNoLinkWH: ++ skip = !br->br_wh; ++ if (skip) { ++ if (do_plink) ++ skip = !!br->br_plink; ++ else ++ skip = !br->br_plink; ++ } ++ break; ++ ++ case AuBr_RW: ++ skip = !!br->br_wh; ++ if (skip) { ++ if (do_plink) ++ skip = !!br->br_plink; ++ else ++ skip = !br->br_plink; ++ } ++ break; ++ ++ default: ++ BUG(); ++ } ++ br_wh_read_unlock(br); ++ ++ if (skip) ++ continue; ++ ++ hdir_lock(h_dir, dir, bindex); ++ br_wh_write_lock(br); ++ err = init_wh(au_h_dptr_i(root, bindex), br, ++ au_nfsmnt(sb, bindex), sb); ++ br_wh_write_unlock(br); ++ hdir_unlock(h_dir, dir, bindex); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++int au_do_opts_mount(struct super_block *sb, struct opts *opts) ++{ ++ int err, do_refresh; ++ struct inode *dir; ++ struct opt *opt; ++ unsigned int flags, given; ++ struct opt_xino *opt_xino; ++ aufs_bindex_t bend, bindex; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ DiMustWriteLock(sb->s_root); ++ dir = sb->s_root->d_inode; ++ IiMustWriteLock(dir); ++ ++ err = 0; ++ given = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_do_opt_simple(sb, opt++, /*remount*/0, &given); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable them temporary */ ++ flags = au_flag_test(sb, AuFlag_XINO | AuMask_UDBA | AuFlag_DLGT); ++ au_flag_clr(sb, AuFlag_XINO | AuFlag_DLGT); ++ udba_set(sb, AuFlag_UDBA_REVAL); ++ ++ do_refresh = 0; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_do_opt_br(sb, opt++, /*remount*/0, &do_refresh); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bend = sbend(sb); ++ if (unlikely(bend < 0)) { ++ err = -EINVAL; ++ Err("no branches\n"); ++ goto out; ++ } ++ ++ if (flags & AuFlag_XINO) ++ au_flag_set(sb, AuFlag_XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_do_opt_xino(sb, opt++, /*remount*/0, &opt_xino); ++ if (unlikely(err)) ++ goto out; ++ ++ //todo: test this error case. ++ err = verify_opts(sb, /*remount*/0); ++ DEBUG_ON(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* enable xino */ ++ if (au_flag_test(sb, AuFlag_XINO) && !opt_xino) { ++ struct file *xino_file = xino_def(sb); ++ err = PTR_ERR(xino_file); ++ if (IS_ERR(xino_file)) ++ goto out; ++ ++ err = 0; ++ for (bindex = 0; !err && bindex <= bend; bindex++) ++ err = xino_init(sb, bindex, xino_file, ++ /*do_test*/bindex); ++ fput(xino_file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore hinotify */ ++ udba_set(sb, flags & AuMask_UDBA); ++ if (flags & AuFlag_UDBA_INOTIFY) ++ au_reset_hinotify(dir, au_hi_flags(dir, 1) & ~AUFS_HI_XINO); ++ ++ /* restore dlgt */ ++ if (flags & AuFlag_DLGT) ++ au_flag_set(sb, AuFlag_DLGT); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++int au_do_opts_remount(struct super_block *sb, struct opts *opts, ++ int *do_refresh, unsigned int *given) ++{ ++ int err, rerr; ++ struct inode *dir; ++ struct opt_xino *opt_xino; ++ struct opt *opt; ++ unsigned int dlgt; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ DiMustWriteLock(sb->s_root); ++ dir = sb->s_root->d_inode; ++ IiMustWriteLock(dir); ++ //DEBUG_ON(au_flag_test(sb, AuFlag_UDBA_INOTIFY)); ++ ++ err = 0; ++ *do_refresh = 0; ++ *given = 0; ++ dlgt = au_flag_test(sb, AuFlag_DLGT); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_do_opt_simple(sb, opt, /*remount*/1, given); ++ ++ /* disable it temporary */ ++ dlgt = au_flag_test(sb, AuFlag_DLGT); ++ au_flag_clr(sb, AuFlag_DLGT); ++ ++ if (!err) ++ err = au_do_opt_br(sb, opt, /*remount*/1, do_refresh); ++ if (!err) ++ err = au_do_opt_xino(sb, opt, /*remount*/1, &opt_xino); ++ ++ /* restore it */ ++ au_flag_set(sb, dlgt); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ TraceErr(err); ++ ++ /* go on if err */ ++ ++ //todo: test this error case. ++ au_flag_clr(sb, AuFlag_DLGT); ++ rerr = verify_opts(sb, /*remount*/1); ++ au_flag_set(sb, dlgt); ++ ++ /* they are handled by the caller */ ++ if (!*do_refresh) ++ *do_refresh = !!((*given & AuMask_UDBA) ++ || au_flag_test(sb, AuFlag_XINO)); ++ ++ TraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h +new file mode 100755 +index 0000000..16c1a6a +--- /dev/null ++++ b/fs/aufs/opts.h +@@ -0,0 +1,96 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: opts.h,v 1.13 2007/05/14 06:27:18 sfjro Exp $ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++typedef const char* au_parser_pattern_t; ++#else ++typedef char* au_parser_pattern_t; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct opt_add { ++ aufs_bindex_t bindex; ++ char *path; ++ int perm; ++ struct nameidata nd; ++}; ++ ++struct opt_del { ++ char *path; ++ struct dentry *h_root; ++}; ++ ++struct opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct opt { ++ int type; ++ union { ++ struct opt_xino xino; ++ struct opt_add add; ++ struct opt_del del; ++ struct opt_mod mod; ++ int dirwh; ++ int rdcache; ++ int deblk; ++ int nhash; ++ int udba; ++ int coo; ++ }; ++}; ++ ++struct opts { ++ struct opt *opt; ++ int max_opt; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int br_perm_str(char *p, unsigned int len, int brperm); ++au_parser_pattern_t udba_str(int udba); ++void udba_set(struct super_block *sb, unsigned int flg); ++//au_parser_pattern_t coo_str(int coo); ++void au_free_opts(struct opts *opts); ++int au_parse_opts(struct super_block *sb, char *str, struct opts *opts); ++int au_do_opts_mount(struct super_block *sb, struct opts *opts); ++int au_do_opts_remount(struct super_block *sb, struct opts *opts, ++ int *do_refresh, unsigned int *given); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c +new file mode 100755 +index 0000000..0e520af +--- /dev/null ++++ b/fs/aufs/plink.c +@@ -0,0 +1,331 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: plink.c,v 1.4 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++struct pseudo_link { ++ struct list_head list; ++ struct inode *inode; ++}; ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_list_plink(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ ++ TraceEnter(); ++ SiMustAnyLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry(plink, plink_list, list) ++ Dbg("%lu\n", plink->inode->i_ino); ++ spin_unlock(&sbinfo->si_plink_lock); ++} ++#endif ++ ++int au_is_plinked(struct super_block *sb, struct inode *inode) ++{ ++ int found; ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ SiMustAnyLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ found = 0; ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry(plink, plink_list, list) ++ if (plink->inode == inode) { ++ found = 1; ++ break; ++ } ++ spin_unlock(&sbinfo->si_plink_lock); ++ return found; ++} ++ ++// 20 is max digits length of ulong 64 ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ LKTRTrace("i%lu, b%d\n", inode->i_ino, bindex); ++ DEBUG_ON(len != PLINK_NAME_LEN); ++ h_inode = au_h_iptr_i(inode, bindex); ++ DEBUG_ON(!h_inode); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ DEBUG_ON(rlen >= len); ++ return rlen; ++} ++ ++struct dentry *lkup_plink(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ struct dentry *h_dentry, *h_parent; ++ struct aufs_branch *br; ++ struct inode *h_dir; ++ char tgtname[PLINK_NAME_LEN]; ++ int len; ++ struct lkup_args lkup; ++ ++ LKTRTrace("b%d, i%lu\n", bindex, inode->i_ino); ++ br = stobr(sb, bindex); ++ h_parent = br->br_plink; ++ DEBUG_ON(!h_parent); ++ h_dir = h_parent->d_inode; ++ DEBUG_ON(!h_dir); ++ ++ len = plink_name(tgtname, sizeof(tgtname), inode, bindex); ++ ++ // always superio. ++ lkup.nfsmnt = au_do_nfsmnt(br->br_mnt); ++ lkup.dlgt = need_dlgt(sb); ++ hi_lock_whplink(h_dir); ++ h_dentry = sio_lkup_one(tgtname, h_parent, len, &lkup); ++ i_unlock(h_dir); ++ return h_dentry; ++} ++ ++static int do_whplink(char *tgt, int len, struct dentry *h_parent, ++ struct dentry *h_dentry, struct vfsmount *nfsmnt, ++ struct super_block *sb) ++{ ++ int err; ++ struct dentry *h_tgt; ++ struct inode *h_dir; ++ struct lkup_args lkup = { ++ .nfsmnt = nfsmnt, ++ .dlgt = need_dlgt(sb) ++ }; ++ ++ h_tgt = lkup_one(tgt, h_parent, len, &lkup); ++ err = PTR_ERR(h_tgt); ++ if (IS_ERR(h_tgt)) ++ goto out; ++ ++ err = 0; ++ h_dir = h_parent->d_inode; ++ if (unlikely(h_tgt->d_inode && h_tgt->d_inode != h_dentry->d_inode)) ++ err = vfsub_unlink(h_dir, h_tgt, lkup.dlgt); ++ if (!err && !h_tgt->d_inode) { ++ err = vfsub_link(h_dentry, h_dir, h_tgt, lkup.dlgt); ++ //inode->i_nlink++; ++ } ++ dput(h_tgt); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ char *tgt; ++ int len; ++ struct dentry *h_parent; ++ struct dentry *h_dentry; ++ struct vfsmount *nfsmnt; ++ struct super_block *sb; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->len, a->h_parent, a->h_dentry, ++ a->nfsmnt, a->sb); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex, struct super_block *sb) ++{ ++ int err, len; ++ struct aufs_branch *br; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ char tgtname[PLINK_NAME_LEN]; ++ ++ LKTRTrace("%.*s\n", DLNPair(h_dentry)); ++ br = stobr(inode->i_sb, bindex); ++ h_parent = br->br_plink; ++ DEBUG_ON(!h_parent); ++ h_dir = h_parent->d_inode; ++ DEBUG_ON(!h_dir); ++ ++ len = plink_name(tgtname, sizeof(tgtname), inode, bindex); ++ ++ // always superio. ++ hi_lock_whplink(h_dir); ++ if (!is_au_wkq(current)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = tgtname, ++ .len = len, ++ .h_parent = h_parent, ++ .h_dentry = h_dentry, ++ .nfsmnt = au_do_nfsmnt(br->br_mnt), ++ .sb = sb ++ }; ++ au_wkq_wait(call_do_whplink, &args, /*dlgt*/0); ++ } else ++ err = do_whplink(tgtname, len, h_parent, h_dentry, ++ au_do_nfsmnt(br->br_mnt), sb); ++ i_unlock(h_dir); ++ ++ TraceErr(err); ++ return err; ++} ++ ++void append_plink(struct super_block *sb, struct inode *inode, ++ struct dentry *h_dentry, aufs_bindex_t bindex) ++{ ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ int found, err, cnt; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ SiMustAnyLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ cnt = 0; ++ found = 0; ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry(plink, plink_list, list) { ++ cnt++; ++ if (plink->inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ ++ err = 0; ++ if (!found) { ++ struct pseudo_link *plink; ++ ++ plink = kmalloc(sizeof(*plink), GFP_ATOMIC); ++ if (plink) { ++ plink->inode = igrab(inode); ++ list_add(&plink->list, plink_list); ++ cnt++; ++ } else ++ err = -ENOMEM; ++ } ++ spin_unlock(&sbinfo->si_plink_lock); ++ ++ if (!err) ++ err = whplink(h_dentry, inode, bindex, sb); ++ ++ if (unlikely(cnt > 100)) ++ Warn1("unexpectedly many pseudo links, %d\n", cnt); ++ if (unlikely(err)) ++ Warn("err %d, damaged pseudo link. ignored.\n", err); ++} ++ ++static void do_put_plink(struct pseudo_link *plink, int do_del) ++{ ++ TraceEnter(); ++ ++ iput(plink->inode); ++ if (do_del) ++ list_del(&plink->list); ++ kfree(plink); ++} ++ ++void au_put_plink(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink, *tmp; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ //spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry_safe(plink, tmp, plink_list, list) ++ do_put_plink(plink, 0); ++ INIT_LIST_HEAD(plink_list); ++ //spin_unlock(&sbinfo->si_plink_lock); ++} ++ ++void half_refresh_plink(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink, *tmp; ++ struct inode *inode; ++ aufs_bindex_t bstart, bend, bindex; ++ int do_put; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ //spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry_safe(plink, tmp, plink_list, list) { ++ do_put = 0; ++ inode = igrab(plink->inode); ++ ii_write_lock_child(inode); ++ bstart = ibstart(inode); ++ bend = ibend(inode); ++ if (bstart >= 0) { ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ if (!au_h_iptr_i(inode, bindex) ++ || itoid_index(inode, bindex) != br_id) ++ continue; ++ set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ } else ++ do_put_plink(plink, 1); ++ ++ if (do_put) { ++ for (bindex = bstart; bindex <= bend; bindex++) ++ if (au_h_iptr_i(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ if (do_put) ++ do_put_plink(plink, 1); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ //spin_unlock(&sbinfo->si_plink_lock); ++} +diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c +new file mode 100755 +index 0000000..55cb64c +--- /dev/null ++++ b/fs/aufs/sbinfo.c +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: sbinfo.c,v 1.30 2007/05/14 03:39:31 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++struct aufs_sbinfo *stosi(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ sbinfo = sb->s_fs_info; ++ //DEBUG_ON(sbinfo->si_bend < 0); ++ return sbinfo; ++} ++ ++aufs_bindex_t sbend(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return stosi(sb)->si_bend; ++} ++ ++struct aufs_branch *stobr(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ DEBUG_ON(bindex < 0 || sbend(sb) < bindex ++ || !stosi(sb)->si_branch[0 + bindex]); ++ return stosi(sb)->si_branch[0 + bindex]; ++} ++ ++int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return stosi(sb)->si_generation; ++} ++ ++int au_sigen_inc(struct super_block *sb) ++{ ++ int gen; ++ ++ SiMustWriteLock(sb); ++ gen = ++stosi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ au_update_iigen(sb->s_root->d_inode); ++ sb->s_root->d_inode->i_version++; ++ return gen; ++} ++ ++int find_bindex(struct super_block *sb, struct aufs_branch *br) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ bend = sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (stobr(sb, bindex) == br) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry and super_block lock. call at entry point */ ++void aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ si_read_lock(dentry->d_sb); ++ if (flags & AUFS_D_WLOCK) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (flags & AUFS_D_WLOCK) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ //au_wkq_wait_nwtask(); ++ si_write_lock(dentry->d_sb); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++ //au_wkq_wait_nwtask(); ++} ++ ++void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ DEBUG_ON(d1 == d2 || d1->d_sb != d2->d_sb); ++ si_read_lock(d1->d_sb); ++ di_write_lock2_child(d1, d2, isdir); ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ DEBUG_ON(d1 == d2 || d1->d_sb != d2->d_sb); ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++aufs_bindex_t new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ ++ while (1) { ++ br_id = ++stosi(sb)->si_last_br_id; ++ if (br_id && find_brindex(sb, br_id) < 0) ++ return br_id; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SYSAUFS ++static int make_xino(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size) ++{ ++ int err; ++ struct super_block *sb = args->sb; ++ aufs_bindex_t bindex, bend; ++ struct file *xf; ++ struct inode *xi; ++ ++ TraceEnter(); ++ DEBUG_ON(args->index != SysaufsSb_XINO); ++ SiMustReadLock(sb); ++ ++ *do_size = 0; ++ err = seq_printf(seq, "%d %lu\n", sizeof(struct xino), ++ atomic_long_read(&stosi(sb)->si_xino)); ++ bend = sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ xf = stobr(sb, bindex)->br_xino; ++ xi = xf->f_dentry->d_inode; ++ err = seq_printf(seq, "%d: %d, %Lux%d %Ld\n", ++ bindex, file_count(xf), ++ (u64)xi->i_blocks, 1 << xi->i_blkbits, ++ i_size_read(xi)); ++ } ++ return err; ++} ++ ++sysaufs_op au_si_ops[] = { ++ [SysaufsSb_XINO] = make_xino ++}; ++#endif +diff --git a/fs/aufs/super.c b/fs/aufs/super.c +new file mode 100755 +index 0000000..c1123f8 +--- /dev/null ++++ b/fs/aufs/super.c +@@ -0,0 +1,716 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: super.c,v 1.50 2007/05/14 03:39:42 sfjro Exp $ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb) ++{ ++ struct aufs_icntnr *c; ++ ++ TraceEnter(); ++ ++ c = cache_alloc_icntnr(); ++ //if (LktrCond) {cache_free_icntnr(c); c = NULL;} ++ if (c) { ++ inode_init_once(&c->vfs_inode); ++ c->vfs_inode.i_version = 1; //sigen(sb); ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ au_iinfo_fin(inode); ++ cache_free_icntnr(container_of(inode, struct aufs_icntnr, vfs_inode)); ++} ++ ++//todo: how about merge with alloc_inode()? ++static void aufs_read_inode(struct inode *inode) ++{ ++ int err; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ ++ err = au_iinfo_init(inode); ++ //if (LktrCond) err = -1; ++ if (!err) { ++ inode->i_version++; ++ inode->i_op = &aufs_iop; ++ inode->i_fop = &aufs_file_fop; ++ inode->i_mapping->a_ops = &aufs_aop; ++ return; /* success */ ++ } ++ ++ LKTRTrace("intializing inode info failed(%d)\n", err); ++ make_bad_inode(inode); ++} ++ ++int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ char a[16]; ++ struct dentry *root; ++ ++ TraceEnter(); ++ SiMustAnyLock(sb); ++ root = sb->s_root; ++ DiMustAnyLock(root); ++ ++ err = 0; ++ bend = sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ err = br_perm_str(a, sizeof(a), sbr_perm(sb, bindex)); ++ if (!err) ++ err = seq_path(seq, sbr_mnt(sb, bindex), ++ au_h_dptr_i(root, bindex), au_esc_chars); ++ if (err > 0) ++ err = seq_printf(seq, "=%s", a); ++ if (!err && bindex != bend) ++ err = seq_putc(seq, ':'); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt) ++{ ++ int err, n; ++ struct super_block *sb; ++ struct aufs_sbinfo *sbinfo; ++ struct dentry *root; ++ struct file *xino; ++ ++ TraceEnter(); ++ ++ sb = mnt->mnt_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, !AUFS_I_RLOCK); ++ if (au_flag_test(sb, AuFlag_XINO)) { ++ err = seq_puts(m, ",xino="); ++ if (unlikely(err)) ++ goto out; ++ xino = stobr(sb, 0)->br_xino; ++ err = seq_path(m, xino->f_vfsmnt, xino->f_dentry, au_esc_chars); ++ if (unlikely(err <= 0)) ++ goto out; ++ err = 0; ++ ++#define Deleted "\\040(deleted)" ++ m->count -= sizeof(Deleted) - 1; ++ DEBUG_ON(memcmp(m->buf + m->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ } else ++ err = seq_puts(m, ",noxino"); ++ ++ n = au_flag_test(sb, AuFlag_PLINK); ++ if (unlikely(!err && (AuDefFlags & AuFlag_PLINK) != n)) ++ err = seq_printf(m, ",%splink", n ? "" : "no"); ++ n = au_flag_test_udba(sb); ++ if (unlikely(!err && (AuDefFlags & AuMask_UDBA) != n)) ++ err = seq_printf(m, ",udba=%s", udba_str(n)); ++ n = au_flag_test(sb, AuFlag_ALWAYS_DIROPQ); ++ if (unlikely(!err && (AuDefFlags & AuFlag_ALWAYS_DIROPQ) != n)) ++ err = seq_printf(m, ",diropq=%c", n ? 'a' : 'w'); ++ n = au_flag_test(sb, AuFlag_DLGT); ++ if (unlikely(!err && (AuDefFlags & AuFlag_DLGT) != n)) ++ err = seq_printf(m, ",%sdlgt", n ? "" : "no"); ++ n = au_flag_test(sb, AuFlag_WARN_PERM); ++ if (unlikely(!err && (AuDefFlags & AuFlag_WARN_PERM) != n)) ++ err = seq_printf(m, ",%swarn_perm", n ? "" : "no"); ++ ++ sbinfo = stosi(sb); ++ n = sbinfo->si_dirwh; ++ if (unlikely(!err && n != AUFS_DIRWH_DEF)) ++ err = seq_printf(m, ",dirwh=%d", n); ++ n = sbinfo->si_rdcache / HZ; ++ if (unlikely(!err && n != AUFS_RDCACHE_DEF)) ++ err = seq_printf(m, ",rdcache=%d", n); ++#if 0 ++ n = au_flag_test_coo(sb); ++ if (unlikely(!err && (AuDefFlags & AuMask_COO) != n)) ++ err = seq_printf(m, ",coo=%s", coo_str(n)); ++#endif ++ ++ if (!err && !sysaufs_brs) { ++#ifdef CONFIG_AUFS_COMPAT ++ err = seq_puts(m, ",dirs="); ++#else ++ err = seq_puts(m, ",br:"); ++#endif ++ if (!err) ++ err = au_show_brs(m, sb); ++ } ++ ++ out: ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ TraceErr(err); ++ if (err) ++ err = -E2BIG; ++ TraceErr(err); ++ return err; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++#define StatfsLock(d) aufs_read_lock((d)->d_sb->s_root, 0) ++#define StatfsUnlock(d) aufs_read_unlock((d)->d_sb->s_root, 0) ++#define StatfsArg(d) au_h_dptr((d)->d_sb->s_root) ++#define StatfsHInode(d) (StatfsArg(d)->d_inode) ++#define StatfsSb(d) ((d)->d_sb) ++static int aufs_statfs(struct dentry *arg, struct kstatfs *buf) ++#else ++#define StatfsLock(s) si_read_lock(s) ++#define StatfsUnlock(s) si_read_unlock(s) ++#define StatfsArg(s) sbr_sb(s, 0) ++#define StatfsHInode(s) (StatfsArg(s)->s_root->d_inode) ++#define StatfsSb(s) (s) ++static int aufs_statfs(struct super_block *arg, struct kstatfs *buf) ++#endif ++{ ++ int err; ++ ++ TraceEnter(); ++ ++ StatfsLock(arg); ++ err = vfsub_statfs(StatfsArg(arg), buf, need_dlgt(StatfsSb(arg))); ++ //if (LktrCond) err = -1; ++ StatfsUnlock(arg); ++ if (!err) { ++ //buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_type = 0; ++ buf->f_namelen -= AUFS_WH_PFX_LEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ //buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; ++ ++ TraceErr(err); ++ return err; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) || defined(UbuntuEdgy17Umount18) ++#define UmountBeginSb(mnt) (mnt)->mnt_sb ++static void aufs_umount_begin(struct vfsmount *arg, int flags) ++#else ++#define UmountBeginSb(sb) sb ++static void aufs_umount_begin(struct super_block *arg) ++#endif ++{ ++ struct super_block *sb = UmountBeginSb(arg); ++ ++ if (unlikely(!stosi(sb))) ++ return; ++ ++ //au_wkq_wait_nwtask(); ++ si_write_lock(sb); ++ if (au_flag_test(sb, AuFlag_PLINK)) { ++ au_put_plink(sb); ++ //kobj_umount(stosi(sb)); ++ } ++#if 0 ++ if (unlikely(au_flag_test(sb, AuFlag_UDBA_INOTIFY))) ++ shrink_dcache_sb(sb); ++#endif ++ si_write_unlock(sb); ++} ++ ++static void free_sbinfo(struct aufs_sbinfo *sbinfo) ++{ ++ TraceEnter(); ++ DEBUG_ON(!sbinfo ++ || !list_empty(&sbinfo->si_plink)); ++ ++ free_branches(sbinfo); ++ kfree(sbinfo->si_branch); ++ kfree(sbinfo); ++} ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ ++ sbinfo = stosi(sb); ++ if (unlikely(!sbinfo)) ++ return; ++ ++ sysaufs_del(sbinfo); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && !defined(UbuntuEdgy17Umount18) ++ // umount_begin() may not be called. ++ aufs_umount_begin(sb); ++#endif ++ free_sbinfo(sbinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh directories at remount time. ++ */ ++static int do_refresh_dir(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *inode; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode || !S_ISDIR(inode->i_mode)); ++ ++ di_write_lock_child(dentry); ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ err = au_refresh_hdentry(dentry, S_IFDIR); ++ if (err >= 0) { ++ err = au_refresh_hinode(inode, dentry); ++ if (!err) ++ au_reset_hinotify(inode, flags); ++ } ++ if (unlikely(err)) ++ Err("unrecoverable error %d\n", err); ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ dput(parent); ++ di_write_unlock(dentry); ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int test_dir(struct dentry *dentry, void *arg) ++{ ++ return S_ISDIR(dentry->d_inode->i_mode); ++} ++ ++static int refresh_dir(struct dentry *root, int sgen) ++{ ++ int err, i, j, ndentry; ++ const unsigned int flags = au_hi_flags(root->d_inode, /*isdir*/1); ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ LKTRTrace("sgen %d\n", sgen); ++ SiMustWriteLock(root->d_sb); ++ DEBUG_ON(au_digen(root) != sgen); ++ DiMustWriteLock(root); ++ ++ err = au_dpages_init(&dpages, GFP_KERNEL); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, test_dir, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ struct dentry *d; ++ d = dentries[j]; ++ DEBUG_ON(!S_ISDIR(d->d_inode->i_mode) ++ || IS_ROOT(d) ++ || au_digen(d->d_parent) != sgen); ++ if (au_digen(d) != sgen) ++ err = do_refresh_dir(d, flags); ++ } ++ } ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ TraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++/* protected by s_umount */ ++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int err, do_refresh; ++ struct dentry *root; ++ struct inode *inode; ++ struct opts opts; ++ unsigned int given, dlgt; ++ ++ //au_debug_on(); ++ LKTRTrace("flags 0x%x, data %s, len %d\n", ++ *flags, data ? data : "NULL", data ? strlen(data) : 0); ++ ++ err = 0; ++ if (unlikely(!data || !*data)) ++ goto out; /* success */ ++ ++ err = -ENOMEM; ++ memset(&opts, 0, sizeof(opts)); ++ opts.opt = (void*)__get_free_page(GFP_KERNEL); ++ //if (LktrCond) {free_page((unsigned long)opts.opt); opts.opt = NULL;} ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ ++ /* parse it before aufs lock */ ++ err = au_parse_opts(sb, data, &opts); ++ //if (LktrCond) {au_free_opts(&opts); err = -1;} ++ if (unlikely(err)) ++ goto out_opts; ++ ++ root = sb->s_root; ++ inode = root->d_inode; ++ i_lock(inode); ++ aufs_write_lock(root); ++ ++ //DbgSleep(3); ++ ++ /* au_do_opts() may return an error */ ++ do_refresh = 0; ++ given = 0; ++ err = au_do_opts_remount(sb, &opts, &do_refresh, &given); ++ //if (LktrCond) err = -1; ++ au_free_opts(&opts); ++ ++ if (do_refresh) { ++ int rerr; ++ struct aufs_sbinfo *sbinfo; ++ ++ dlgt = au_flag_test(sb, AuFlag_DLGT); ++ au_flag_clr(sb, AuFlag_DLGT); ++ au_sigen_inc(sb); ++ au_reset_hinotify(inode, au_hi_flags(inode, /*isdir*/1)); ++ sbinfo = stosi(sb); ++ sbinfo->si_failed_refresh_dirs = 0; ++ rerr = refresh_dir(root, au_sigen(sb)); ++ if (unlikely(rerr)) { ++ sbinfo->si_failed_refresh_dirs = 1; ++ Warn("Refreshing directories failed, ignores (%d)\n", ++ rerr); ++ } ++ au_cpup_attr_all(inode); ++ au_flag_set(sb, dlgt); ++ } ++ ++ aufs_write_unlock(root); ++ i_unlock(inode); ++ /* braces are added to stop a warning */ ++ if (do_refresh) { ++ sysaufs_notify_remount(); ++ } ++ ++ out_opts: ++ free_page((unsigned long)opts.opt); ++ out: ++ err = cvt_err(err); ++ TraceErr(err); ++ //au_debug_off(); ++ return err; ++} ++ ++static struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ .read_inode = aufs_read_inode, ++ //.dirty_inode = aufs_dirty_inode, ++ //.write_inode = aufs_write_inode, ++ //void (*put_inode) (struct inode *); ++ .drop_inode = generic_delete_inode, ++ //.delete_inode = aufs_delete_inode, ++ //.clear_inode = aufs_clear_inode, ++ ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ ++ .put_super = aufs_put_super, ++ //void (*write_super) (struct super_block *); ++ //int (*sync_fs)(struct super_block *sb, int wait); ++ //void (*write_super_lockfs) (struct super_block *); ++ //void (*unlockfs) (struct super_block *); ++ .remount_fs = aufs_remount_fs, ++ // depends upon umount flags. also use put_super() (< 2.6.18) ++ .umount_begin = aufs_umount_begin ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * at first mount time. ++ */ ++ ++static int alloc_sbinfo(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ ++ sbinfo = kmalloc(sizeof(*sbinfo), GFP_KERNEL); ++ //if (LktrCond) {kfree(sbinfo); sbinfo = NULL;} ++ if (unlikely(!sbinfo)) ++ goto out; ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_KERNEL); ++ //if (LktrCond) {kfree(sbinfo->si_branch); sbinfo->si_branch = NULL;} ++ if (unlikely(!sbinfo->si_branch)) { ++ kfree(sbinfo); ++ goto out; ++ } ++ rw_init_wlock(&sbinfo->si_rwsem); ++ sbinfo->si_bend = -1; ++ atomic_long_set(&sbinfo->si_xino, AUFS_FIRST_INO); ++ spin_lock_init(&sbinfo->si_plink_lock); ++ INIT_LIST_HEAD(&sbinfo->si_plink); ++ init_lvma(sbinfo); ++ sbinfo->si_generation = 0; ++ sbinfo->si_last_br_id = 0; ++ sbinfo->si_failed_refresh_dirs = 0; ++ sbinfo->si_flags = 0; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ sbinfo->si_rdcache = AUFS_RDCACHE_DEF * HZ; ++ //atomic_set(&sbinfo->si_hinotify, 0); ++ //init_waitqueue_head(&sbinfo->si_hinotify_wq); ++ ++ sb->s_fs_info = sbinfo; ++ au_flag_set(sb, AuDefFlags); ++#ifdef ForceInotify ++ udba_set(sb, AuFlag_UDBA_INOTIFY); ++#endif ++#ifdef ForceDlgt ++ au_flag_set(sb, AuFlag_DLGT); ++#endif ++#ifdef ForceNoPlink ++ au_flag_clr(sb, AuFlag_PLINK); ++#endif ++ return 0; /* success */ ++ ++ out: ++ TraceErr(-ENOMEM); ++ return -ENOMEM; ++} ++ ++static int alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ TraceEnter(); ++ ++ err = -ENOMEM; ++ inode = iget(sb, AUFS_ROOT_INO); ++ //if (LktrCond) {iput(inode); inode = NULL;} ++ if (unlikely(!inode)) ++ goto out; ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ err = -ENOMEM; ++ if (unlikely(is_bad_inode(inode))) ++ goto out_iput; ++ ++ root = d_alloc_root(inode); ++ //if (LktrCond) {igrab(inode); dput(root); root = NULL;} ++ if (unlikely(!root)) ++ goto out_iput; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out_iput; ++ ++ err = au_alloc_dinfo(root); ++ //if (LktrCond){rw_write_unlock(&dtodi(root)->di_rwsem);err=-1;} ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ goto out; /* do not iput */ ++ ++ out_iput: ++ iput(inode); ++ out: ++ TraceErr(err); ++ return err; ++ ++} ++ ++static int aufs_fill_super(struct super_block *sb, void *raw_data, int silent) ++{ ++ int err; ++ struct dentry *root; ++ struct inode *inode; ++ struct opts opts; ++ char *arg = raw_data; ++ ++ //au_debug_on(); ++ if (unlikely(!arg || !*arg)) { ++ err = -EINVAL; ++ Err("no arg\n"); ++ goto out; ++ } ++ LKTRTrace("%s, silent %d\n", arg, silent); ++ ++ err = -ENOMEM; ++ memset(&opts, 0, sizeof(opts)); ++ opts.opt = (void*)__get_free_page(GFP_KERNEL); ++ //if (LktrCond) {free_page((unsigned long)opts.opt); opts.opt = NULL;} ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ ++ err = alloc_sbinfo(sb); ++ //if (LktrCond) {si_write_unlock(sb);free_sbinfo(stosi(sb));err=-1;} ++ if (unlikely(err)) ++ goto out_opts; ++ SiMustWriteLock(sb); ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME; ++ sb->s_op = &aufs_sop; ++ au_init_export_op(sb); ++ //err = kobj_mount(stosi(sb)); ++ //if (err) ++ //goto out_info; ++ ++ err = alloc_root(sb); ++ //if (LktrCond) {rw_write_unlock(&dtodi(sb->s_root)->di_rwsem); ++ //dput(sb->s_root);sb->s_root=NULL;err=-1;} ++ if (unlikely(err)) { ++ DEBUG_ON(sb->s_root); ++ si_write_unlock(sb); ++ goto out_info; ++ } ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ inode = root->d_inode; ++ inode->i_nlink = 2; ++ ++ /* ++ * actually we can parse options regardless aufs lock here. ++ * but at remount time, parsing must be done before aufs lock. ++ * so we follow the same rule. ++ */ ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ err = au_parse_opts(sb, arg, &opts); ++ //if (LktrCond) {au_free_opts(&opts); err = -1;} ++ if (unlikely(err)) ++ goto out_root; ++ ++ /* lock vfs_inode first, then aufs. */ ++ i_lock(inode); ++ inode->i_op = &aufs_dir_iop; ++ inode->i_fop = &aufs_dir_fop; ++ aufs_write_lock(root); ++ ++ sb->s_maxbytes = 0; ++ err = au_do_opts_mount(sb, &opts); ++ //if (LktrCond) err = -1; ++ au_free_opts(&opts); ++ if (unlikely(err)) ++ goto out_unlock; ++ DEBUG_ON(!sb->s_maxbytes); ++ ++ //DbgDentry(root); ++ aufs_write_unlock(root); ++ i_unlock(inode); ++ //DbgSb(sb); ++ goto out_opts; /* success */ ++ ++ out_unlock: ++ aufs_write_unlock(root); ++ i_unlock(inode); ++ out_root: ++ dput(root); ++ sb->s_root = NULL; ++ out_info: ++ free_sbinfo(stosi(sb)); ++ sb->s_fs_info = NULL; ++ out_opts: ++ free_page((unsigned long)opts.opt); ++ out: ++ TraceErr(err); ++ err = cvt_err(err); ++ TraceErr(err); ++ //au_debug_off(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++static int aufs_get_sb(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *raw_data, ++ struct vfsmount *mnt) ++{ ++ int err; ++ ++ /* all timestamps always follow the ones on the branch */ ++ //mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; ++ err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt); ++ if (!err) { ++ struct aufs_sbinfo *sbinfo = stosi(mnt->mnt_sb); ++ sbinfo->si_mnt = mnt; ++ sysaufs_add(sbinfo); ++ } ++ return err; ++} ++#else ++static struct super_block *aufs_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, ++ void *raw_data) ++{ ++ return get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super); ++} ++#endif ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ .fs_flags = FS_REVAL_DOT, // for UDBA and NFS branch ++ .get_sb = aufs_get_sb, ++ .kill_sb = generic_shutdown_super, ++ //no need to __module_get() and module_put(). ++ .owner = THIS_MODULE, ++}; +diff --git a/fs/aufs/super.h b/fs/aufs/super.h +new file mode 100755 +index 0000000..56ddee1 +--- /dev/null ++++ b/fs/aufs/super.h +@@ -0,0 +1,339 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: super.h,v 1.44 2007/05/14 03:39:54 sfjro Exp $ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "misc.h" ++#include "sysaufs.h" ++ ++#ifdef CONFIG_AUFS_SYSAUFS ++/* entries under sysfs per mount-point */ ++enum {SysaufsSb_XINO, /* SysaufsSb_PLINK, */ SysaufsSb_Last}; ++struct sysaufs_sbinfo { ++ au_subsys_t subsys; ++ struct sysaufs_entry array[SysaufsSb_Last]; ++}; ++extern sysaufs_op au_si_ops[]; ++#else ++struct sysaufs_sbinfo {}; ++#endif ++ ++struct aufs_sbinfo { ++ struct aufs_rwsem si_rwsem; ++ ++ /* branch management */ ++ /* wrap around attack by superuser? No. */ ++ int si_generation; ++ ++ /* ++ * set true when refresh_dirs() at remount time failed. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecesary ++ */ ++ unsigned int si_failed_refresh_dirs:1; ++ ++ aufs_bindex_t si_bend; ++ aufs_bindex_t si_last_br_id; ++ struct aufs_branch **si_branch; ++ ++ /* mount flags */ ++ unsigned int si_flags; ++ ++ /* external inode number table */ ++ atomic_long_t si_xino; // time bomb ++ //struct file *si_xino_bmap; ++ ++ /* readdir cache time, max, in HZ */ ++ unsigned long si_rdcache; ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after rename_whtmp to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* pseudo_link list */ // dirty ++ spinlock_t si_plink_lock; ++ struct list_head si_plink; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++ /* super_blocks list is not exported */ ++ struct list_head si_list; ++ struct vfsmount *si_mnt; /* no get/put */ ++#endif ++ ++ /* sysfs */ ++ struct sysaufs_sbinfo si_sysaufs; ++ ++#ifdef CONFIG_AUFS_HINOTIFY ++ /* hinotify */ ++ //atomic_t si_hinotify; ++ //wait_queue_head_t si_hinotify_wq; ++#endif ++ ++#ifdef CONFIG_AUFS_ROBR ++ /* locked vma list for mmap() */ // very dirty ++ spinlock_t si_lvma_lock; ++ struct list_head si_lvma; ++#endif ++}; ++ ++/* an entry in a xino file */ ++struct xino { ++ ino_t ino; ++ //__u32 h_gen; ++} __attribute__ ((packed)); ++ ++//#define AuXino_INVALID_HGEN (-1) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Mount flags */ ++#define AuFlag_XINO 1 ++#define AuFlag_ZXINO (1 << 1) ++#define AuFlag_PLINK (1 << 2) ++#define AuFlag_UDBA_NONE (1 << 3) ++#define AuFlag_UDBA_REVAL (1 << 4) ++#define AuFlag_UDBA_INOTIFY (1 << 5) ++#define AuFlag_WARN_PERM (1 << 6) ++#define AuFlag_COO_NONE (1 << 7) ++#define AuFlag_COO_LEAF (1 << 8) ++#define AuFlag_COO_ALL (1 << 9) ++#define AuFlag_ALWAYS_DIROPQ (1 << 10) ++#define AuFlag_DLGT (1 << 11) ++ ++#define AuMask_UDBA (AuFlag_UDBA_NONE | AuFlag_UDBA_REVAL \ ++ | AuFlag_UDBA_INOTIFY) ++#define AuMask_COO (AuFlag_COO_NONE | AuFlag_COO_LEAF \ ++ | AuFlag_COO_ALL) ++ ++#ifdef CONFIG_AUFS_COMPAT ++#define AuDefFlag_DIROPQ AuFlag_ALWAYS_DIROPQ ++#else ++#define AuDefFlag_DIROPQ 0 ++#endif ++ ++#define AuDefFlags_COMM (AuFlag_XINO | AuFlag_UDBA_REVAL | AuFlag_WARN_PERM \ ++ | AuFlag_COO_NONE | AuDefFlag_DIROPQ) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++#define AuDefFlags (AuDefFlags_COMM | AuFlag_PLINK) ++#else ++#define AuDefFlags AuDefFlags_COMM ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for aufs_read_lock()/di_read_lock() */ ++#define AUFS_D_WLOCK 1 ++#define AUFS_I_RLOCK 2 ++#define AUFS_I_WLOCK 4 ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++int au_show_brs(struct seq_file *seq, struct super_block *sb); ++ ++/* xino.c */ ++struct file *xino_create(struct super_block *sb, char *fname, int silent, ++ struct dentry *parent); ++ino_t xino_new_ino(struct super_block *sb); ++int xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino); ++int xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ struct xino *xino); ++int xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ struct xino *xino); ++int xino_init(struct super_block *sb, aufs_bindex_t bindex, ++ struct file *base_file, int do_test); ++struct opt_xino; ++int xino_set(struct super_block *sb, struct opt_xino *xino, int remount); ++int xino_clr(struct super_block *sb); ++struct file *xino_def(struct super_block *sb); ++ ++/* sbinfo.c */ ++struct aufs_sbinfo *stosi(struct super_block *sb); ++aufs_bindex_t sbend(struct super_block *sb); ++struct aufs_branch *stobr(struct super_block *sb, aufs_bindex_t bindex); ++int au_sigen(struct super_block *sb); ++int au_sigen_inc(struct super_block *sb); ++int find_bindex(struct super_block *sb, struct aufs_branch *br); ++ ++void aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++aufs_bindex_t new_br_id(struct super_block *sb); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_is_aufs(struct super_block *sb) ++{ ++ return !strcmp(au_sbtype(sb), AUFS_FSTYPE); ++} ++ ++static inline int au_is_nfs(struct super_block *sb) ++{ ++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) ++ return !strcmp(au_sbtype(sb), "nfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_is_remote(struct super_block *sb) ++{ ++ return au_is_nfs(sb); ++} ++ ++#ifdef CONFIG_AUFS_EXPORT ++static inline void au_init_export_op(struct super_block *sb) ++{ ++ extern struct export_operations aufs_export_op; ++ sb->s_export_op = &aufs_export_op; ++} ++ ++static inline int au_is_nfsd(struct task_struct *tsk) ++{ ++ return (!tsk->mm && !strcmp(tsk->comm, "nfsd")); ++} ++ ++static inline void au_nfsd_lockdep_off(void) ++{ ++ /* braces are added to stop a warning */ ++ if (au_is_nfsd(current)) { ++ lockdep_off(); ++ } ++} ++ ++static inline void au_nfsd_lockdep_on(void) ++{ ++ /* braces are added to stop a warning */ ++ if (au_is_nfsd(current)) { ++ lockdep_on(); ++ } ++} ++#else ++static inline int au_is_nfsd(struct task_struct *tsk) ++{ ++ return 0; ++} ++static inline void au_init_export_op(struct super_block *sb) ++{ ++ /* nothing */ ++} ++#define au_nfsd_lockdep_off() /* */ ++#define au_nfsd_lockdep_on() /* */ ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++static inline void init_lvma(struct aufs_sbinfo *sbinfo) ++{ ++#ifdef CONFIG_AUFS_ROBR ++ spin_lock_init(&sbinfo->si_lvma_lock); ++ INIT_LIST_HEAD(&sbinfo->si_lvma); ++#else ++ /* nothing */ ++#endif ++} ++ ++/* limited support before 2.6.18 */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++static inline void au_mntget(struct super_block *sb) ++{ ++ mntget(stosi(sb)->si_mnt); ++} ++ ++static inline void au_mntput(struct super_block *sb) ++{ ++ mntput(stosi(sb)->si_mnt); ++} ++#else ++static inline void au_mntget(struct super_block *sb) ++{ ++ /* empty */ ++} ++ ++static inline void au_mntput(struct super_block *sb) ++{ ++ /* empty */ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void au_flag_set(struct super_block *sb, unsigned int flag) ++{ ++ //SiMustWriteLock(sb); ++ stosi(sb)->si_flags |= flag; ++} ++ ++static inline void au_flag_clr(struct super_block *sb, unsigned int flag) ++{ ++ //SiMustWriteLock(sb); ++ stosi(sb)->si_flags &= ~flag; ++} ++ ++static inline ++unsigned int au_flag_test(struct super_block *sb, unsigned int flag) ++{ ++ //SiMustAnyLock(sb); ++ return stosi(sb)->si_flags & flag; ++} ++ ++static inline unsigned int au_flag_test_udba(struct super_block *sb) ++{ ++ return au_flag_test(sb, AuMask_UDBA); ++} ++ ++static inline unsigned int au_flag_test_coo(struct super_block *sb) ++{ ++ return au_flag_test(sb, AuMask_COO); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++/* ++ * si_read_lock, si_write_lock, ++ * si_read_unlock, si_write_unlock, si_downgrade_lock ++ */ ++SimpleRwsemFuncs(si, struct super_block *sb, stosi(sb)->si_rwsem); ++ ++/* to debug easier, do not make them inlined functions */ ++#define SiMustReadLock(sb) RwMustReadLock(&stosi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) RwMustWriteLock(&stosi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) RwMustAnyLock(&stosi(sb)->si_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c +new file mode 100755 +index 0000000..d686862 +--- /dev/null ++++ b/fs/aufs/sysaufs.c +@@ -0,0 +1,620 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: sysaufs.c,v 1.6 2007/05/14 03:40:10 sfjro Exp $ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super_blocks list is not exported */ ++static DEFINE_MUTEX(aufs_sbilist_mtx); ++static LIST_HEAD(aufs_sbilist); ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef ssize_t (*rwfunc_t)(struct kobject *kobj, char *buf, loff_t offset, ++ size_t sz, struct sysaufs_args *args); ++static ssize_t sysaufs_read(struct kobject *kobj, char *buf, loff_t offset, ++ size_t sz, struct sysaufs_args *args); ++static ssize_t sysaufs_free_write(struct kobject *kobj, char *buf, loff_t ++ offset, size_t sz, struct sysaufs_args *args); ++ ++#define GFunc(name, _index, func) \ ++static ssize_t name(struct kobject *kobj, char *buf, loff_t offset, size_t sz) \ ++{ \ ++ struct sysaufs_args args = { \ ++ .index = (_index), \ ++ .mtx = &aufs_sbilist_mtx, \ ++ .sb = NULL \ ++ }; \ ++ return func(kobj, buf, offset, sz, &args); \ ++} ++ ++#define GFuncs(name, _index) \ ++ GFunc(read_##name, _index, sysaufs_read); \ ++ GFunc(write_##name, _index, sysaufs_free_write); ++ ++static struct super_block *find_sb_locked(struct kobject *kobj) ++{ ++ struct super_block *sb; ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ MtxMustLock(&aufs_sbilist_mtx); ++ ++ sb = NULL; ++ list_for_each_entry(sbinfo, &aufs_sbilist, si_list) { ++ if (&au_subsys_to_kset(sbinfo->si_sysaufs.subsys).kobj != kobj) ++ continue; ++ sb = sbinfo->si_mnt->mnt_sb; ++ si_read_lock(sb); ++ break; ++ } ++ return sb; ++} ++ ++static ssize_t sb_func(struct kobject *kobj, char *buf, loff_t offset, ++ size_t sz, struct sysaufs_args *args, rwfunc_t func) ++{ ++ ssize_t err; ++ ++ err = -ENOENT; ++ mutex_lock(&aufs_sbilist_mtx); ++ args->sb = find_sb_locked(kobj); ++ if (args->sb) { ++ err = func(kobj, buf, offset, sz, args); ++ si_read_unlock(args->sb); ++ } ++ mutex_unlock(&aufs_sbilist_mtx); ++ return err; ++} ++ ++#define SbFunc(name, _index, func) \ ++static ssize_t name(struct kobject *kobj, char *buf, loff_t offset, size_t sz) \ ++{ \ ++ struct sysaufs_args args = { \ ++ .index = (_index), \ ++ .mtx = NULL \ ++ }; \ ++ return sb_func(kobj, buf, offset, sz, &args, func); \ ++} ++ ++#define SbFuncs(name, index) \ ++ SbFunc(read_##name, index, sysaufs_read); \ ++ SbFunc(write_##name, index, sysaufs_free_write) ++ ++static decl_subsys(aufs, NULL, NULL); ++enum {Brs, Stat, Config, _Last}; ++static struct sysaufs_entry g_array[_Last]; ++GFuncs(brs, Brs); ++GFuncs(stat, Stat); ++GFuncs(config, Config); ++ ++SbFuncs(xino, SysaufsSb_XINO); ++ ++#define SetEntry(e, _name, init_size, _ops) \ ++ do { \ ++ (e)->attr.attr.name = #_name; \ ++ (e)->attr.attr.owner = THIS_MODULE; \ ++ (e)->attr.attr.mode = S_IRUGO | S_IWUSR; \ ++ (e)->attr.read = read_##_name; \ ++ (e)->attr.write = write_##_name; \ ++ (e)->allocated = init_size; \ ++ (e)->err = -1; \ ++ (e)->ops = _ops; \ ++ } while (0) ++ ++#define Priv(e) (e)->attr.private ++#define Allocated(e) (e)->allocated ++#define Len(e) (e)->attr.size ++#define Name(e) attr_name((e)->attr) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void free_entry(struct sysaufs_entry *e) ++{ ++ MtxMustLock(&aufs_sbilist_mtx); ++ DEBUG_ON(!Priv(e)); ++ ++ if (Allocated(e) > 0) ++ kfree(Priv(e)); ++ else ++ free_pages((unsigned long)Priv(e), -Allocated(e)); ++ Priv(e) = NULL; ++ Len(e) = 0; ++} ++ ++static void free_entries(void) ++{ ++ static int a[] = {Brs, -1}; ++ int *p = a; ++ ++ MtxMustLock(&aufs_sbilist_mtx); ++ ++ while (*p >= 0) { ++ if (Priv(g_array + *p)) ++ free_entry(g_array + *p); ++ p++; ++ } ++} ++ ++static int alloc_entry(struct sysaufs_entry *e) ++{ ++ MtxMustLock(&aufs_sbilist_mtx); ++ DEBUG_ON(Priv(e)); ++ //Dbg("%d\n", Allocated(e)); ++ ++ if (Allocated(e) > 0) ++ Priv(e) = kmalloc(Allocated(e), GFP_KERNEL); ++ else ++ Priv(e) = (void*)__get_free_pages(GFP_KERNEL, -Allocated(e)); ++ if (Priv(e)) ++ return 0; ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void unreg(au_subsys_t *subsys, struct sysaufs_entry *a, int n, ++ au_subsys_t *parent) ++{ ++ int i; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < n; i++, a++) ++ if (!a->err) { ++ sysfs_remove_bin_file ++ (&au_subsys_to_kset(*subsys).kobj, &a->attr); ++ if (Priv(a)) ++ free_entry(a); ++ } ++ ++ subsystem_unregister(subsys); ++ subsys_put(parent); ++} ++ ++static int reg(au_subsys_t *subsys, struct sysaufs_entry *a, int n, ++ au_subsys_t *parent) ++{ ++ int err, i; ++ ++ TraceEnter(); ++ ++ subsys_get(parent); ++ kobj_set_kset_s(&au_subsys_to_kset(*subsys), *parent); ++ err = subsystem_register(subsys); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < n; i++) ++ err = a[i].err = sysfs_create_bin_file ++ (&au_subsys_to_kset(*subsys).kobj, &a[i].attr); ++ if (unlikely(err)) ++ unreg(subsys, a, n, parent); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define SbSetEntry(index, name, init_size) \ ++ SetEntry(sa->array + index, name, init_size, au_si_ops); ++ ++void sysaufs_add(struct aufs_sbinfo *sbinfo) ++{ ++ int err; ++ struct sysaufs_sbinfo *sa = &sbinfo->si_sysaufs; ++ ++ TraceEnter(); ++ ++ mutex_lock(&aufs_sbilist_mtx); ++ list_add_tail(&sbinfo->si_list, &aufs_sbilist); ++ free_entries(); ++ ++ memset(sa, 0, sizeof(*sa)); ++ SbSetEntry(SysaufsSb_XINO, xino, 128); ++ err = kobject_set_name(&au_subsys_to_kset(sa->subsys).kobj, "%p", ++ sbinfo->si_mnt->mnt_sb); ++ if (!err) ++ err = reg(&sa->subsys, sa->array, ARRAY_SIZE(sa->array), ++ &aufs_subsys); ++ if (unlikely(err)) ++ Warn("failed adding sysfs (%d)\n", err); ++ ++ mutex_unlock(&aufs_sbilist_mtx); ++} ++ ++void sysaufs_del(struct aufs_sbinfo *sbinfo) ++{ ++ struct sysaufs_sbinfo *sa = &sbinfo->si_sysaufs; ++ ++ TraceEnter(); ++ ++ mutex_lock(&aufs_sbilist_mtx); ++ unreg(&sa->subsys, sa->array, ARRAY_SIZE(sa->array), &aufs_subsys); ++ list_del(&sbinfo->si_list); ++ free_entries(); ++ mutex_unlock(&aufs_sbilist_mtx); ++} ++ ++void sysaufs_notify_remount(void) ++{ ++ mutex_lock(&aufs_sbilist_mtx); ++ free_entries(); ++ mutex_unlock(&aufs_sbilist_mtx); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int make_brs(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size) ++{ ++ int err; ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ MtxMustLock(&aufs_sbilist_mtx); ++ DEBUG_ON(args->index != Brs); ++ ++ err = 0; ++ list_for_each_entry(sbinfo, &aufs_sbilist, si_list) { ++ struct super_block *sb; ++ struct dentry *root; ++ struct vfsmount *mnt; ++ ++ sb = sbinfo->si_mnt->mnt_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, !AUFS_I_RLOCK); ++ mnt = sbinfo->si_mnt; ++ err = seq_escape ++ (seq, mnt->mnt_devname ? mnt->mnt_devname : "none", ++ au_esc_chars); ++ if (!err) ++ err = seq_putc(seq, ' '); ++ if (!err) ++ err = seq_path(seq, mnt, root, au_esc_chars); ++ if (err > 0) ++ err = seq_printf(seq, " %p br:", sb); ++ if (!err) ++ err = au_show_brs(seq, sb); ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ if (!err) ++ err = seq_putc(seq, '\n'); ++ else ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int make_config(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size) ++{ ++ int err; ++ ++ TraceEnter(); ++ DEBUG_ON(args->index != Config); ++ ++#ifdef CONFIG_AUFS ++ err = seq_puts(seq, "CONFIG_AUFS=y\n"); ++#else ++ err = seq_puts(seq, "CONFIG_AUFS=m\n"); ++#endif ++ ++#define puts(m, v) \ ++ if (!err) err = seq_puts(seq, "CONFIG_AUFS_" #m "=" #v "\n") ++#define puts_bool(m) puts(m, y) ++#define puts_mod(m) puts(m, m) ++ ++#ifdef CONFIG_AUFS_FAKE_DM ++ puts_bool(FAKE_DM); ++#endif ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++ puts_bool(BRANCH_MAX_127); ++#elif defined(CONFIG_AUFS_BRANCH_MAX_511) ++ puts_bool(BRANCH_MAX_511); ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++ puts_bool(BRANCH_MAX_1023); ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++ puts_bool(BRANCH_MAX_32767); ++#endif ++ puts_bool(SYSAUFS); ++#ifdef CONFIG_AUFS_HINOTIFY ++ puts_bool(HINOTIFY); ++#endif ++#ifdef CONFIG_AUFS_EXPORT ++ puts_bool(EXPORT); ++#endif ++#ifdef CONFIG_AUFS_ROBR ++ puts_bool(ROBR); ++#endif ++#ifdef CONFIG_AUFS_DLGT ++ puts_bool(DLGT); ++#endif ++#ifdef CONFIG_AUFS_LHASH_PATCH ++ puts_bool(LHASH_PATCH); ++#endif ++#ifdef CONFIG_AUFS_KSIZE_PATCH ++ puts_bool(KSIZE_PATCH); ++#endif ++#ifdef CONFIG_AUFS_DEBUG ++ puts_bool(DEBUG); ++#endif ++#ifdef CONFIG_AUFS_COMPAT ++ puts_bool(COMPAT); ++#endif ++ ++#undef puts_bool ++#undef puts ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int make_stat(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size) ++{ ++ int err, i; ++ ++ TraceEnter(); ++ DEBUG_ON(args->index != Stat); ++ ++ *do_size = 0; ++ err = seq_puts(seq, "wkq max_busy:"); ++ for (i = 0; !err && i < aufs_nwkq; i++) ++ err = seq_printf(seq, " %u", au_wkq[i].max_busy); ++ if (!err) ++ err = seq_printf(seq, ", %u(generic)\n", ++ au_wkq[aufs_nwkq].max_busy); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int make(struct sysaufs_entry *e, struct sysaufs_args *args, ++ int *do_size) ++ ++{ ++ int err; ++ struct seq_file *seq; ++ ++ TraceEnter(); ++ DEBUG_ON(Priv(e)); ++ MtxMustLock(&aufs_sbilist_mtx); ++ ++ err = -ENOMEM; ++ seq = kzalloc(sizeof(*seq), GFP_KERNEL); ++ if (unlikely(!seq)) ++ goto out; ++ ++ Len(e) = 0; ++ while (1) { ++ err = alloc_entry(e); ++ if (unlikely(err)) ++ break; ++ ++ //mutex_init(&seq.lock); ++ seq->buf = Priv(e); ++ seq->count = 0; ++ seq->size = Allocated(e); ++ if (unlikely(Allocated(e) <= 0)) ++ seq->size = PAGE_SIZE << -Allocated(e); ++ ++ err = e->ops[args->index](seq, args, do_size); ++ if (!err) { ++ Len(e) = seq->count; ++ break; /* success */ ++ } ++ ++ free_entry(e); ++ if (Allocated(e) > 0) { ++ Allocated(e) <<= 1; ++ if (unlikely(Allocated(e) >= (int)PAGE_SIZE)) ++ Allocated(e) = 0; ++ } else ++ Allocated(e)--; ++ //Dbg("%d\n", Allocated(e)); ++ } ++ kfree(seq); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* why does sysfs pass my parent kobject? */ ++static struct dentry *find_me(struct dentry *parent, struct sysaufs_entry *e) ++{ ++#if 1 ++ struct dentry *dentry; ++ const char *name = Name(e); ++ const unsigned int len = strlen(name); ++ ++ //Dbg("%.*s\n", DLNPair(parent)); ++ spin_lock(&dcache_lock); ++ list_for_each_entry(dentry, &parent->d_subdirs, D_CHILD) { ++ //Dbg("%.*s\n", DLNPair(dentry)); ++ if (len == dentry->d_name.len ++ && !strcmp(dentry->d_name.name, name)) { ++ spin_unlock(&dcache_lock); ++ return dentry; ++ } ++ } ++ spin_unlock(&dcache_lock); ++#endif ++ return NULL; ++} ++ ++static ssize_t sysaufs_read(struct kobject *kobj, char *buf, loff_t offset, ++ size_t sz, struct sysaufs_args *args) ++{ ++ ssize_t err; ++ loff_t len; ++ struct dentry *d; ++ struct sysaufs_entry *e; ++ int do_size; ++ ++ LKTRTrace("{%d, %p}, offset %Ld, sz %lu\n", ++ args->index, args->sb, offset, (unsigned long)sz); ++ ++ if (unlikely(!sz)) ++ return 0; ++ ++ err = 0; ++ d = NULL; ++ e = g_array + args->index; ++ if (args->sb) ++ e = stosi(args->sb)->si_sysaufs.array + args->index; ++ ++ do_size = 1; ++ if (args->mtx) ++ mutex_lock(args->mtx); ++ if (unlikely(!Priv(e))) { ++ err = make(e, args, &do_size); ++ DEBUG_ON(Len(e) > INT_MAX); ++ if (do_size) { ++ d = find_me(kobj->dentry, e); ++ if (d) ++ i_size_write(d->d_inode, Len(e)); ++ } ++ } ++ ++ if (!err) { ++ err = len = Len(e) - offset; ++ LKTRTrace("%Ld\n", len); ++ if (len > 0) { ++ if (len > sz) ++ err = sz; ++ memcpy(buf, Priv(e) + offset, err); ++ } ++ ++ if (!do_size) ++ free_entry(e); ++ } ++ if (args->mtx) ++ mutex_unlock(args->mtx); ++ ++ TraceErr(err); ++ return err; ++} ++ ++static ssize_t sysaufs_free_write(struct kobject *kobj, char *buf, ++ loff_t offset, size_t sz, ++ struct sysaufs_args *args) ++{ ++ struct dentry *d; ++ int allocated, len; ++ struct sysaufs_entry *e; ++ ++ LKTRTrace("{%d, %p}\n", args->index, args->sb); ++ ++ e = g_array + args->index; ++ if (args->sb) ++ e = stosi(args->sb)->si_sysaufs.array + args->index; ++ ++ if (args->mtx) ++ mutex_lock(args->mtx); ++ if (Priv(e)) { ++ allocated = Allocated(e); ++ if (unlikely(allocated <= 0)) ++ allocated = PAGE_SIZE << -allocated; ++ allocated >>= 1; ++ len = Len(e); ++ ++ free_entry(e); ++ if (unlikely(len <= allocated)) { ++ if (Allocated(e) >= 0) ++ Allocated(e) = allocated; ++ else ++ Allocated(e)++; ++ } ++ ++ d = find_me(kobj->dentry, e); ++ if (d && i_size_read(d->d_inode)) ++ i_size_write(d->d_inode, 0); ++ } ++ if (args->mtx) ++ mutex_unlock(args->mtx); ++ ++ return sz; ++} ++ ++static sysaufs_op g_ops[] = { ++ [Brs] = make_brs, ++ [Stat] = make_stat, ++ [Config] = make_config ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define GSetEntry(index, name, init_size) \ ++ SetEntry(g_array + index, name, init_size, g_ops) ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ GSetEntry(Brs, brs, 128); ++ GSetEntry(Stat, stat, 32); ++ GSetEntry(Config, config, 256); ++ err = reg(&aufs_subsys, g_array, ARRAY_SIZE(g_array), &fs_subsys); ++ TraceErr(err); ++ return err; ++} ++ ++void __exit sysaufs_fin(void) ++{ ++ mutex_lock(&aufs_sbilist_mtx); ++ unreg(&aufs_subsys, g_array, ARRAY_SIZE(g_array), &fs_subsys); ++ mutex_unlock(&aufs_sbilist_mtx); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef DbgDlgt ++int is_branch(struct super_block *h_sb) ++{ ++ int found = 0; ++ struct aufs_sbinfo *sbinfo; ++ ++ //Dbg("here\n"); ++ mutex_lock(&aufs_sbilist_mtx); ++ list_for_each_entry(sbinfo, &aufs_sbilist, si_list) { ++ aufs_bindex_t bindex, bend; ++ struct super_block *sb; ++ ++ sb = sbinfo->si_mnt->mnt_sb; ++ si_read_lock(sb); ++ bend = sbend(sb); ++ for (bindex = 0; !found && bindex <= bend; bindex++) ++ found = (h_sb == sbr_sb(sb, bindex)); ++ si_read_unlock(sb); ++ } ++ mutex_unlock(&aufs_sbilist_mtx); ++ return found; ++} ++#endif +diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h +new file mode 100755 +index 0000000..cf0247f +--- /dev/null ++++ b/fs/aufs/sysaufs.h +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: sysaufs.h,v 1.3 2007/05/14 06:27:18 sfjro Exp $ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++typedef struct kset au_subsys_t; ++#define au_subsys_to_kset(subsys) (subsys) ++#else ++typedef struct subsystem au_subsys_t; ++#define au_subsys_to_kset(subsys) ((subsys).kset) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* arguments for an entry under sysfs */ ++struct sysaufs_args { ++ int index; ++ struct mutex *mtx; ++ struct super_block *sb; ++}; ++ ++typedef int (*sysaufs_op)(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size); ++ ++/* an entry under sysfs */ ++struct sysaufs_entry { ++ struct bin_attribute attr; ++ int allocated; /* zero minus means pages */ ++ int err; ++ sysaufs_op *ops; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_sbinfo; ++#ifdef CONFIG_AUFS_SYSAUFS ++void sysaufs_add(struct aufs_sbinfo *sbinfo); ++void sysaufs_del(struct aufs_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++void sysaufs_notify_remount(void); ++#else ++static inline void sysaufs_add(struct aufs_sbinfo *sbinfo) ++{ ++ /* nothing */ ++} ++ ++static inline void sysaufs_del(struct aufs_sbinfo *sbinfo) ++{ ++ /* nothing */ ++} ++#define sysaufs_init() 0 ++#define sysaufs_fin() /* */ ++#define sysaufs_notify_remount() /* */ ++#endif /* CONFIG_AUFS_SYSAUFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c +new file mode 100755 +index 0000000..8e99b7d +--- /dev/null ++++ b/fs/aufs/vdir.c +@@ -0,0 +1,802 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: vdir.c,v 1.22 2007/05/14 03:38:52 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++static int calc_size(int namelen) ++{ ++ int sz; ++ ++ sz = sizeof(struct aufs_de) + namelen; ++ if (sizeof(ino_t) == sizeof(long)) { ++ const int mask = sizeof(ino_t) - 1; ++ if (sz & mask) { ++ sz += sizeof(ino_t); ++ sz &= ~mask; ++ } ++ } else { ++#if 0 // remove ++ BUG(); ++ // this block will be discarded by optimizer. ++ int m; ++ m = sz % sizeof(ino_t); ++ if (m) ++ sz += sizeof(ino_t) - m; ++#endif ++ } ++ ++ DEBUG_ON(sz % sizeof(ino_t)); ++ return sz; ++} ++ ++static int set_deblk_end(union aufs_deblk_p *p, union aufs_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->p - p->p) { ++ p->de->de_str.len = 0; ++ //smp_mb(); ++ return 0; ++ } ++ return -1; // error ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union aufs_deblk_p *p, union aufs_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->p - p->p) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static aufs_deblk_t *last_deblk(struct aufs_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++void nhash_init(struct aufs_nhash *nhash) ++{ ++ int i; ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) ++ INIT_HLIST_HEAD(nhash->heads + i); ++} ++ ++struct aufs_nhash *nhash_new(gfp_t gfp) ++{ ++ struct aufs_nhash *nhash; ++ ++ nhash = kmalloc(sizeof(*nhash), gfp); ++ if (nhash) { ++ nhash_init(nhash); ++ return nhash; ++ } ++ return ERR_PTR(-ENOMEM); ++} ++ ++void nhash_del(struct aufs_nhash *nhash) ++{ ++ nhash_fin(nhash); ++ kfree(nhash); ++} ++ ++void nhash_move(struct aufs_nhash *dst, struct aufs_nhash *src) ++{ ++ int i; ++ ++ TraceEnter(); ++ ++ //DbgWhlist(src); ++ *dst = *src; ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ struct hlist_head *h; ++ h = dst->heads + i; ++ if (h->first) ++ h->first->pprev = &h->first; ++ INIT_HLIST_HEAD(src->heads + i); ++ } ++ //DbgWhlist(src); ++ //DbgWhlist(dst); ++ //smp_mb(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void nhash_fin(struct aufs_nhash *whlist) ++{ ++ int i; ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos, *n; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ head = whlist->heads + i; ++ hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) { ++ //hlist_del(pos); ++ kfree(tpos); ++ } ++ } ++} ++ ++int is_longer_wh(struct aufs_nhash *whlist, aufs_bindex_t btgt, int limit) ++{ ++ int n, i; ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos; ++ ++ LKTRTrace("limit %d\n", limit); ++ //return 1; ++ ++ n = 0; ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ head = whlist->heads + i; ++ hlist_for_each_entry(tpos, pos, head, wh_hash) ++ if (tpos->wh_bindex == btgt && ++n > limit) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++int test_known_wh(struct aufs_nhash *whlist, char *name, int namelen) ++{ ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos; ++ struct aufs_destr *str; ++ ++ LKTRTrace("%.*s\n", namelen, name); ++ ++ head = whlist->heads + au_name_hash(name, namelen); ++ hlist_for_each_entry(tpos, pos, head, wh_hash) { ++ str = &tpos->wh_str; ++ LKTRTrace("%.*s\n", str->len, str->name); ++ if (str->len == namelen && !memcmp(str->name, name, namelen)) ++ return 1; ++ } ++ return 0; ++} ++ ++int append_wh(struct aufs_nhash *whlist, char *name, int namelen, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct aufs_destr *str; ++ struct aufs_wh *wh; ++ ++ LKTRTrace("%.*s\n", namelen, name); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + namelen, GFP_KERNEL); ++ if (unlikely(!wh)) ++ goto out; ++ err = 0; ++ wh->wh_bindex = bindex; ++ str = &wh->wh_str; ++ str->len = namelen; ++ memcpy(str->name, name, namelen); ++ hlist_add_head(&wh->wh_hash, ++ whlist->heads + au_name_hash(name, namelen)); ++ //smp_mb(); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void free_vdir(struct aufs_vdir *vdir) ++{ ++ aufs_deblk_t **deblk; ++ ++ TraceEnter(); ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) { ++ kfree(*deblk); ++ deblk++; ++ } ++ kfree(vdir->vd_deblk); ++ cache_free_vdir(vdir); ++} ++ ++static int append_deblk(struct aufs_vdir *vdir) ++{ ++ int err, sz, i; ++ aufs_deblk_t **o; ++ union aufs_deblk_p p, deblk_end; ++ ++ TraceEnter(); ++ ++ err = -ENOMEM; ++ sz = sizeof(*o) * vdir->vd_nblk; ++ o = au_kzrealloc(vdir->vd_deblk, sz, sz + sizeof(*o), GFP_KERNEL); ++ if (unlikely(!o)) ++ goto out; ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(sizeof(*p.deblk), GFP_KERNEL); ++ if (p.deblk) { ++ i = vdir->vd_nblk++; ++ vdir->vd_deblk[i] = p.deblk; ++ vdir->vd_last.i = i; ++ vdir->vd_last.p.p = p.p; ++ deblk_end.deblk = p.deblk + 1; ++ err = set_deblk_end(&p, &deblk_end); ++ DEBUG_ON(err); ++ } ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static struct aufs_vdir *alloc_vdir(void) ++{ ++ struct aufs_vdir *vdir; ++ int err; ++ ++ TraceEnter(); ++ ++ err = -ENOMEM; ++ vdir = cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_KERNEL); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ kfree(vdir->vd_deblk); ++ ++ out_free: ++ cache_free_vdir(vdir); ++ out: ++ vdir = ERR_PTR(err); ++ TraceErrPtr(vdir); ++ return vdir; ++} ++ ++static int reinit_vdir(struct aufs_vdir *vdir) ++{ ++ int err; ++ union aufs_deblk_p p, deblk_end; ++ ++ TraceEnter(); ++ ++ while (vdir->vd_nblk > 1) { ++ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + 1; ++ err = set_deblk_end(&p, &deblk_end); ++ DEBUG_ON(err); ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ vdir->vd_last.i = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ //smp_mb(); ++ //DbgVdir(vdir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void free_dehlist(struct aufs_nhash *dehlist) ++{ ++ int i; ++ struct hlist_head *head; ++ struct aufs_dehstr *tpos; ++ struct hlist_node *pos, *n; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ head = dehlist->heads + i; ++ hlist_for_each_entry_safe(tpos, pos, n, head, hash) { ++ //hlist_del(pos); ++ cache_free_dehstr(tpos); ++ } ++ } ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct aufs_nhash *delist, char *name, int namelen) ++{ ++ struct hlist_head *head; ++ struct aufs_dehstr *tpos; ++ struct hlist_node *pos; ++ struct aufs_destr *str; ++ ++ LKTRTrace("%.*s\n", namelen, name); ++ ++ head = delist->heads + au_name_hash(name, namelen); ++ hlist_for_each_entry(tpos, pos, head, hash) { ++ str = tpos->str; ++ LKTRTrace("%.*s\n", str->len, str->name); ++ if (str->len == namelen && !memcmp(str->name, name, namelen)) ++ return 1; ++ } ++ return 0; ++ ++} ++ ++static int append_de(struct aufs_vdir *vdir, char *name, int namelen, ino_t ino, ++ unsigned int d_type, struct aufs_nhash *delist) ++{ ++ int err, sz; ++ union aufs_deblk_p p, *room, deblk_end; ++ struct aufs_dehstr *dehstr; ++ ++ LKTRTrace("%.*s %d, i%lu, dt%u\n", namelen, name, namelen, ino, d_type); ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + 1; ++ room = &vdir->vd_last.p; ++ DEBUG_ON(room->p < p.p || deblk_end.p <= room->p ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(namelen); ++ if (unlikely(sz > deblk_end.p - room->p)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + 1; ++ //smp_mb(); ++ DEBUG_ON(room->p != p.p); ++ } ++ ++ err = -ENOMEM; ++ dehstr = cache_alloc_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, ++ delist->heads + au_name_hash(name, namelen)); ++ ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = namelen; ++ memcpy(room->de->de_str.name, name, namelen); ++ ++ err = 0; ++ room->p += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ //smp_mb(); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct fillvdir_arg { ++ struct file *file; ++ struct aufs_vdir *vdir; ++ struct aufs_nhash *delist; ++ struct aufs_nhash *whlist; ++ aufs_bindex_t bindex; ++ int err; ++ int called; ++}; ++ ++static int fillvdir(void *__arg, const char *__name, int namelen, loff_t offset, ++ filldir_ino_t h_ino, unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = __arg; ++ char *name = (void*)__name; ++ aufs_bindex_t bindex, bend; ++ struct xino xino; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, namelen %d, i%Lu, dt%u\n", ++ namelen, name, namelen, (u64)h_ino, d_type); ++ ++ sb = arg->file->f_dentry->d_sb; ++ bend = arg->bindex; ++ arg->err = 0; ++ arg->called++; ++ //smp_mb(); ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ for (bindex = 0; bindex < bend; bindex++) ++ if (test_known(arg->delist + bindex, name, namelen) ++ || test_known_wh(arg->whlist + bindex, name, ++ namelen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = xino_read(sb, bend, h_ino, &xino); ++ if (!arg->err && !xino.ino) { ++ //struct inode *h_inode; ++ xino.ino = xino_new_ino(sb); ++ if (unlikely(!xino.ino)) ++ arg->err = -EIO; ++#if 0 ++ //xino.h_gen = AuXino_INVALID_HGEN; ++ h_inode = ilookup(sbr_sb(sb, bend), h_ino); ++ if (h_inode) { ++ if (!is_bad_inode(h_inode)) { ++ xino.h_gen = h_inode->i_generation; ++ WARN_ON(xino.h_gen == AuXino_INVALID_HGEN); ++ } ++ iput(h_inode); ++ } ++#endif ++ arg->err = xino_write(sb, bend, h_ino, &xino); ++ } ++ if (!arg->err) ++ arg->err = append_de(arg->vdir, name, namelen, xino.ino, ++ d_type, arg->delist + bend); ++ } else { ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ for (bindex = 0; bindex < bend; bindex++) ++ if (test_known_wh(arg->whlist + bend, name, namelen)) ++ goto out; /* already whiteouted */ ++ arg->err = append_wh(arg->whlist + bend, name, namelen, bend); ++ } ++ ++ out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ //smp_mb(); ++ TraceErr(arg->err); ++ return arg->err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err, do_read, dlgt; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct aufs_vdir *vdir, *allocated; ++ unsigned long expire; ++ struct fillvdir_arg arg; ++ aufs_bindex_t bindex, bend, bstart; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, may %d\n", DLNPair(dentry), may_read); ++ FiMustWriteLock(file); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ IiMustWriteLock(inode); ++ DEBUG_ON(!S_ISDIR(inode->i_mode)); ++ ++ err = 0; ++ allocated = NULL; ++ do_read = 0; ++ sb = inode->i_sb; ++ expire = stosi(sb)->si_rdcache; ++ vdir = ivdir(inode); ++ if (!vdir) { ++ DEBUG_ON(fvdir_cache(file)); ++ do_read = 1; ++ vdir = alloc_vdir(); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (inode->i_version != vdir->vd_version ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ LKTRTrace("iver %lu, vdver %lu, exp %lu\n", ++ inode->i_version, vdir->vd_version, ++ vdir->vd_jiffy + expire); ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ //DbgVdir(vdir); goto out; ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ err = -ENOMEM; ++ bend = fbend(file); ++ arg.delist = kmalloc(sizeof(*arg.delist) * (bend + 1), GFP_KERNEL); ++ if (unlikely(!arg.delist)) ++ goto out_vdir; ++ arg.whlist = kmalloc(sizeof(*arg.whlist) * (bend + 1), GFP_KERNEL); ++ if (unlikely(!arg.whlist)) ++ goto out_delist; ++ err = 0; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ nhash_init(arg.delist + bindex); ++ nhash_init(arg.whlist + bindex); ++ } ++ ++ dlgt = need_dlgt(sb); ++ arg.file = file; ++ arg.vdir = vdir; ++ bstart = fbstart(file); ++ for (bindex = bstart; !err && bindex <= bend; bindex++) { ++ struct file *hf; ++ struct inode *h_inode; ++ ++ hf = au_h_fptr_i(file, bindex); ++ if (!hf) ++ continue; ++ ++ h_inode = hf->f_dentry->d_inode; ++ //hf->f_pos = 0; ++ arg.bindex = bindex; ++ do { ++ arg.err = 0; ++ arg.called = 0; ++ //smp_mb(); ++ err = vfsub_readdir(hf, fillvdir, &arg, dlgt); ++ if (err >= 0) ++ err = arg.err; ++ } while (!err && arg.called); ++ } ++ ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ free_dehlist(arg.delist + bindex); ++ nhash_fin(arg.whlist + bindex); ++ } ++ kfree(arg.whlist); ++ ++ out_delist: ++ kfree(arg.delist); ++ out_vdir: ++ if (!err) { ++ //file->f_pos = 0; ++ vdir->vd_version = inode->i_version; ++ vdir->vd_last.i = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ set_ivdir(inode, allocated); ++ } else if (allocated) ++ free_vdir(allocated); ++ //DbgVdir(vdir); goto out; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static int copy_vdir(struct aufs_vdir *tgt, struct aufs_vdir *src) ++{ ++ int err, i, rerr, n; ++ ++ TraceEnter(); ++ DEBUG_ON(tgt->vd_nblk != 1); ++ //DbgVdir(tgt); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ aufs_deblk_t **p; ++ p = au_kzrealloc(tgt->vd_deblk, sizeof(*p) * tgt->vd_nblk, ++ sizeof(*p) * src->vd_nblk, GFP_KERNEL); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ n = tgt->vd_nblk = src->vd_nblk; ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], AUFS_DEBLK_SIZE); ++ //tgt->vd_last.i = 0; ++ //tgt->vd_last.p.deblk = tgt->vd_deblk[0]; ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ for (i = 1; i < n; i++) { ++ tgt->vd_deblk[i] = kmalloc(AUFS_DEBLK_SIZE, GFP_KERNEL); ++ if (tgt->vd_deblk[i]) ++ memcpy(tgt->vd_deblk[i], src->vd_deblk[i], ++ AUFS_DEBLK_SIZE); ++ else ++ goto out; ++ } ++ //smp_mb(); ++ //DbgVdir(tgt); ++ return 0; /* success */ ++ ++ out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ TraceErr(err); ++ return err; ++} ++ ++int au_init_vdir(struct file *file) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct aufs_vdir *vdir_cache, *allocated; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld\n", DLNPair(dentry), file->f_pos); ++ FiMustWriteLock(file); ++ inode = dentry->d_inode; ++ IiMustWriteLock(inode); ++ DEBUG_ON(!S_ISDIR(inode->i_mode)); ++ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ //DbgVdir(ivdir(inode)); goto out; ++ ++ allocated = NULL; ++ vdir_cache = fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ //err = 0; DbgVdir(vdir_cache); goto out; ++ ++ err = copy_vdir(vdir_cache, ivdir(inode)); ++ if (!err) { ++ file->f_version = inode->i_version; ++ if (allocated) ++ set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ free_vdir(allocated); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static loff_t calc_offset(struct aufs_vdir *vdir) ++{ ++ loff_t offset; ++ union aufs_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.i]; ++ offset = vdir->vd_last.p.p - p.p; ++ offset += sizeof(*p.deblk) * vdir->vd_last.i; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file) ++{ ++ int valid, i, n; ++ struct dentry *dentry; ++ struct aufs_vdir *vdir_cache; ++ loff_t offset; ++ union aufs_deblk_p p, deblk_end; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld\n", DLNPair(dentry), file->f_pos); ++ vdir_cache = fvdir_cache(file); ++ DEBUG_ON(!vdir_cache); ++ //DbgVdir(vdir_cache); ++ ++ valid = 1; ++ offset = calc_offset(vdir_cache); ++ LKTRTrace("offset %Ld\n", offset); ++ if (file->f_pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.i = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!file->f_pos) ++ goto out; ++ ++ valid = 0; ++ i = file->f_pos / AUFS_DEBLK_SIZE; ++ LKTRTrace("i %d\n", i); ++ if (i >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ //DbgVdir(vdir_cache); ++ for (; i < n; i++) { ++ p.deblk = vdir_cache->vd_deblk[i]; ++ deblk_end.deblk = p.deblk + 1; ++ offset = i * AUFS_DEBLK_SIZE; ++ while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) { ++ int l; ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.p += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.i = i; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++ out: ++ //smp_mb(); ++ //DbgVdir(vdir_cache); ++ TraceErr(!valid); ++ return valid; ++} ++ ++int au_fill_de(struct file *file, void *dirent, filldir_t filldir) ++{ ++ int err, l; ++ struct dentry *dentry; ++ struct aufs_vdir *vdir_cache; ++ struct aufs_de *de; ++ union aufs_deblk_p deblk_end; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld\n", DLNPair(dentry), file->f_pos); ++ vdir_cache = fvdir_cache(file); ++ DEBUG_ON(!vdir_cache); ++ //DbgVdir(vdir_cache); ++ ++ if (!seek_vdir(file)) ++ return 0; ++ ++ while (1) { ++ deblk_end.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.i] + 1; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ LKTRTrace("%.*s, off%Ld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ++ file->f_pos, de->de_ino, de->de_type); ++ err = filldir(dirent, de->de_str.name, de->de_str.len, ++ file->f_pos, de->de_ino, de->de_type); ++ if (unlikely(err)) { ++ TraceErr(err); ++ //return err; ++ //todo: ignore the error caused by udba. ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.p += l; ++ file->f_pos += l; ++ } ++ if (vdir_cache->vd_last.i < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.i++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.i]; ++ file->f_pos = sizeof(*vdir_cache->vd_last.p.deblk) ++ * vdir_cache->vd_last.i; ++ continue; ++ } ++ break; ++ } ++ ++ //smp_mb(); ++ return 0; ++} +diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c +new file mode 100755 +index 0000000..8571d21 +--- /dev/null ++++ b/fs/aufs/vfsub.c +@@ -0,0 +1,665 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: vfsub.c,v 1.5 2007/04/23 00:55:06 sfjro Exp $ */ ++// I'm going to slightly mad ++ ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DLGT ++struct permission_args { ++ int *errp; ++ struct inode *inode; ++ int mask; ++ struct nameidata *nd; ++}; ++ ++static void call_permission(void *args) ++{ ++ struct permission_args *a = args; ++ *a->errp = do_vfsub_permission(a->inode, a->mask, a->nd); ++} ++ ++int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, ++ int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_permission(inode, mask, nd); ++ else { ++ int err; ++ struct permission_args args = { ++ .errp = &err, ++ .inode = inode, ++ .mask = mask, ++ .nd = nd ++ }; ++ au_wkq_wait(call_permission, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct create_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++ int mode; ++ struct nameidata *nd; ++}; ++ ++static void call_create(void *args) ++{ ++ struct create_args *a = args; ++ *a->errp = do_vfsub_create(a->dir, a->dentry, a->mode, a->nd); ++} ++ ++int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_create(dir, dentry, mode, nd); ++ else { ++ int err; ++ struct create_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry, ++ .mode = mode, ++ .nd = nd ++ }; ++ au_wkq_wait(call_create, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct symlink_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++ const char *symname; ++ int mode; ++}; ++ ++static void call_symlink(void *args) ++{ ++ struct symlink_args *a = args; ++ *a->errp = do_vfsub_symlink(a->dir, a->dentry, a->symname, a->mode); ++} ++ ++int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, ++ int mode, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_symlink(dir, dentry, symname, mode); ++ else { ++ int err; ++ struct symlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry, ++ .symname = symname, ++ .mode = mode ++ }; ++ au_wkq_wait(call_symlink, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct mknod_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++ int mode; ++ dev_t dev; ++}; ++ ++static void call_mknod(void *args) ++{ ++ struct mknod_args *a = args; ++ *a->errp = do_vfsub_mknod(a->dir, a->dentry, a->mode, a->dev); ++} ++ ++int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, ++ int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_mknod(dir, dentry, mode, dev); ++ else { ++ int err; ++ struct mknod_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry, ++ .mode = mode, ++ .dev = dev ++ }; ++ au_wkq_wait(call_mknod, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++ int mode; ++}; ++ ++static void call_mkdir(void *args) ++{ ++ struct mkdir_args *a = args; ++ *a->errp = do_vfsub_mkdir(a->dir, a->dentry, a->mode); ++} ++ ++int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_mkdir(dir, dentry, mode); ++ else { ++ int err; ++ struct mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry, ++ .mode = mode ++ }; ++ au_wkq_wait(call_mkdir, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct link_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *src_dentry, *dentry; ++}; ++ ++static void call_link(void *args) ++{ ++ struct link_args *a = args; ++ *a->errp = do_vfsub_link(a->src_dentry, a->dir, a->dentry); ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_link(src_dentry, dir, dentry); ++ else { ++ int err; ++ struct link_args args = { ++ .errp = &err, ++ .src_dentry = src_dentry, ++ .dir = dir, ++ .dentry = dentry ++ }; ++ au_wkq_wait(call_link, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct rename_args { ++ int *errp; ++ struct inode *src_dir, *dir; ++ struct dentry *src_dentry, *dentry; ++}; ++ ++static void call_rename(void *args) ++{ ++ struct rename_args *a = args; ++ *a->errp = do_vfsub_rename(a->src_dir, a->src_dentry, a->dir, ++ a->dentry); ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_rename(src_dir, src_dentry, dir, dentry); ++ else { ++ int err; ++ struct rename_args args = { ++ .errp = &err, ++ .src_dir = src_dir, ++ .src_dentry = src_dentry, ++ .dir = dir, ++ .dentry = dentry ++ }; ++ au_wkq_wait(call_rename, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++}; ++ ++static void call_rmdir(void *args) ++{ ++ struct rmdir_args *a = args; ++ *a->errp = do_vfsub_rmdir(a->dir, a->dentry); ++} ++ ++int vfsub_rmdir(struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_rmdir(dir, dentry); ++ else { ++ int err; ++ struct rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry ++ }; ++ au_wkq_wait(call_rmdir, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct read_args { ++ ssize_t *errp; ++ struct file *file; ++ union { ++ void *kbuf; ++ char __user *ubuf; ++ }; ++ size_t count; ++ loff_t *ppos; ++}; ++ ++static void call_read_k(void *args) ++{ ++ struct read_args *a = args; ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(a->file->f_dentry), (unsigned long)a->count, ++ *a->ppos); ++ *a->errp = do_vfsub_read_k(a->file, a->kbuf, a->count, a->ppos); ++} ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_read_u(file, ubuf, count, ppos); ++ else { ++ ssize_t err, read; ++ struct read_args args = { ++ .errp = &err, ++ .file = file, ++ .count = count, ++ .ppos = ppos ++ }; ++ ++ if (unlikely(!count)) ++ return 0; ++ ++ /* ++ * workaround an application bug. ++ * generally, read(2) or write(2) may return the value shorter ++ * than requested. But many applications don't support it, ++ * for example bash. ++ */ ++ err = -ENOMEM; ++ if (args.count > PAGE_SIZE) ++ args.count = PAGE_SIZE; ++ args.kbuf = kmalloc(args.count, GFP_KERNEL); ++ if (unlikely(!args.kbuf)) ++ goto out; ++ ++ read = 0; ++ do { ++ au_wkq_wait(call_read_k, &args, /*dlgt*/1); ++ if (unlikely(err > 0 ++ && copy_to_user(ubuf, args.kbuf, err))) { ++ err = -EFAULT; ++ goto out_free; ++ } else if (!err) ++ break; ++ else if (unlikely(err < 0)) ++ goto out_free; ++ count -= err; ++ /* do not read too much because of file i/o pointer */ ++ if (unlikely(count < args.count)) ++ args.count = count; ++ ubuf += err; ++ read += err; ++ } while (count); ++ smp_mb(); ++ err = read; ++ ++ out_free: ++ kfree(args.kbuf); ++ out: ++ return err; ++ } ++} ++ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_read_k(file, kbuf, count, ppos); ++ else { ++ ssize_t err; ++ struct read_args args = { ++ .errp = &err, ++ .file = file, ++ .count = count, ++ .ppos = ppos ++ }; ++ args.kbuf = kbuf; ++ au_wkq_wait(call_read_k, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct write_args { ++ ssize_t *errp; ++ struct file *file; ++ union { ++ void *kbuf; ++ const char __user *ubuf; ++ }; ++ void *buf; ++ size_t count; ++ loff_t *ppos; ++}; ++ ++static void call_write_k(void *args) ++{ ++ struct write_args *a = args; ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(a->file->f_dentry), (unsigned long)a->count, ++ *a->ppos); ++ *a->errp = do_vfsub_write_k(a->file, a->kbuf, a->count, a->ppos); ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_write_u(file, ubuf, count, ppos); ++ else { ++ ssize_t err, written; ++ struct write_args args = { ++ .errp = &err, ++ .file = file, ++ .count = count, ++ .ppos = ppos ++ }; ++ ++ if (unlikely(!count)) ++ return 0; ++ ++ /* ++ * workaround an application bug. ++ * generally, read(2) or write(2) may return the value shorter ++ * than requested. But many applications don't support it, ++ * for example bash. ++ */ ++ err = -ENOMEM; ++ if (args.count > PAGE_SIZE) ++ args.count = PAGE_SIZE; ++ args.kbuf = kmalloc(args.count, GFP_KERNEL); ++ if (unlikely(!args.kbuf)) ++ goto out; ++ ++ written = 0; ++ do { ++ if (unlikely(copy_from_user(args.kbuf, ubuf, args.count))) { ++ err = -EFAULT; ++ goto out_free; ++ } ++ ++ au_wkq_wait(call_write_k, &args, /*dlgt*/1); ++ if (err > 0) { ++ count -= err; ++ if (count < args.count) ++ args.count = count; ++ ubuf += err; ++ written += err; ++ } else if (!err) ++ break; ++ else if (unlikely(err < 0)) ++ goto out_free; ++ } while (count); ++ err = written; ++ ++ out_free: ++ kfree(args.kbuf); ++ out: ++ return err; ++ } ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_write_k(file, kbuf, count, ppos); ++ else { ++ ssize_t err; ++ struct write_args args = { ++ .errp = &err, ++ .file = file, ++ .count = count, ++ .ppos = ppos ++ }; ++ args.kbuf = kbuf; ++ au_wkq_wait(call_write_k, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct readdir_args { ++ int *errp; ++ struct file *file; ++ filldir_t filldir; ++ void *arg; ++}; ++ ++static void call_readdir(void *args) ++{ ++ struct readdir_args *a = args; ++ *a->errp = do_vfsub_readdir(a->file, a->filldir, a->arg); ++} ++ ++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_readdir(file, filldir, arg); ++ else { ++ int err; ++ struct readdir_args args = { ++ .errp = &err, ++ .file = file, ++ .filldir = filldir, ++ .arg = arg ++ }; ++ au_wkq_wait(call_readdir, &args, /*dlgt*/1); ++ return err; ++ } ++} ++#endif /* CONFIG_AUFS_DLGT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct dentry *h_dentry; ++ struct iattr *ia; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ ++ LKTRTrace("%.*s, ia_valid 0x%x\n", ++ DLNPair(a->h_dentry), a->ia->ia_valid); ++ h_inode = a->h_dentry->d_inode; ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ lockdep_off(); ++ *a->errp = notify_change(a->h_dentry, a->ia); ++ lockdep_on(); ++ } ++ TraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct dentry *dentry, struct iattr *ia, int dlgt) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .h_dentry = dentry, ++ .ia = ia ++ }; ++ ++#ifndef CONFIG_AUFS_DLGT ++ call_notify_change(&args); ++#else ++ if (!dlgt) ++ call_notify_change(&args); ++ else ++ au_wkq_wait(call_notify_change, &args, /*dlgt*/1); ++#endif ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct inode *h_inode; ++ const int stop_sillyrename = (au_is_nfs(a->dentry->d_sb) ++ && atomic_read(&a->dentry->d_count) == 1); ++ ++ LKTRTrace("%.*s, stop_silly %d, cnt %d\n", ++ DLNPair(a->dentry), stop_sillyrename, ++ atomic_read(&a->dentry->d_count)); ++ IMustLock(a->dir); ++ ++ if (!stop_sillyrename) ++ dget(a->dentry); ++ h_inode = a->dentry->d_inode; ++ if (h_inode) ++ atomic_inc(&h_inode->i_count); ++#if 0 // partial testing ++ { ++ struct qstr *name = &a->dentry->d_name; ++ if (name->len == sizeof(AUFS_XINO_FNAME) - 1 ++ && !strncmp(name->name, AUFS_XINO_FNAME, name->len)) { ++ lockdep_off(); ++ *a->errp = vfs_unlink(a->dir, a->dentry); ++ lockdep_on(); ++ } else ++ err = -1; ++ } ++#else ++ // vfs_unlink() locks inode ++ lockdep_off(); ++ *a->errp = vfs_unlink(a->dir, a->dentry); ++ lockdep_on(); ++#endif ++ ++ if (!stop_sillyrename) ++ dput(a->dentry); ++ if (h_inode) ++ iput(h_inode); ++ ++ TraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry ++ }; ++ ++#ifndef CONFIG_AUFS_DLGT ++ call_unlink(&args); ++#else ++ if (!dlgt) ++ call_unlink(&args); ++ else ++ au_wkq_wait(call_unlink, &args, /*dlgt*/1); ++#endif ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct statfs_args { ++ int *errp; ++ void *arg; ++ struct kstatfs *buf; ++}; ++ ++static void call_statfs(void *args) ++{ ++ struct statfs_args *a = args; ++ *a->errp = vfs_statfs(a->arg, a->buf); ++} ++ ++int vfsub_statfs(void *arg, struct kstatfs *buf, int dlgt) ++{ ++ int err; ++ struct statfs_args args = { ++ .errp = &err, ++ .arg = arg, ++ .buf = buf ++ }; ++ ++#ifndef CONFIG_AUFS_DLGT ++ call_statfs(&args); ++#else ++ if (!dlgt) ++ call_statfs(&args); ++ else ++ au_wkq_wait(call_statfs, &args, /*dlgt*/1); ++#endif ++ return err; ++} +diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h +new file mode 100755 +index 0000000..52f15cc +--- /dev/null ++++ b/fs/aufs/vfsub.h +@@ -0,0 +1,427 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: vfsub.h,v 1.8 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "wkq.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* simple abstractions, for future use */ ++static inline ++int do_vfsub_permission(struct inode *inode, int mask, struct nameidata *nd) ++{ ++ LKTRTrace("i%lu, mask 0x%x, nd %p\n", inode->i_ino, mask, nd); ++#if 0 ++#else ++ return permission(inode, mask, nd); ++#endif ++} ++ ++static inline ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *err; ++ ++ LKTRTrace("%s\n", path); ++ ++ lockdep_off(); ++ err = filp_open(path, oflags, mode); ++ lockdep_on(); ++ return err; ++} ++ ++static inline ++int vfsub_path_lookup(const char *name, unsigned int flags, ++ struct nameidata *nd) ++{ ++ int err; ++ ++ LKTRTrace("%s\n", name); ++ ++ //lockdep_off(); ++ err = path_lookup(name, flags, nd); ++ //lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++int do_vfsub_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd) ++{ ++ LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, DLNPair(dentry), mode); ++#if 0 ++#else ++ return vfs_create(dir, dentry, mode, nd); ++#endif ++} ++ ++static inline ++int do_vfsub_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname, int mode) ++{ ++ LKTRTrace("i%lu, %.*s, %s, 0x%x\n", ++ dir->i_ino, DLNPair(dentry), symname, mode); ++#if 0 ++#else ++ return vfs_symlink(dir, dentry, symname, mode); ++#endif ++} ++ ++static inline ++int do_vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ dev_t dev) ++{ ++ LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, DLNPair(dentry), mode); ++#if 0 ++#else ++ return vfs_mknod(dir, dentry, mode, dev); ++#endif ++} ++ ++static inline ++int do_vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ LKTRTrace("%.*s, i%lu, %.*s\n", ++ DLNPair(src_dentry), dir->i_ino, DLNPair(dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_link(src_dentry, dir, dentry); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++static inline ++int do_vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ ++ LKTRTrace("i%lu, %.*s, i%lu, %.*s\n", ++ src_dir->i_ino, DLNPair(src_dentry), ++ dir->i_ino, DLNPair(dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_rename(src_dir, src_dentry, dir, dentry); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++static inline ++int do_vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, DLNPair(dentry), mode); ++#if 0 ++#else ++ return vfs_mkdir(dir, dentry, mode); ++#endif ++} ++ ++static inline int do_vfsub_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ ++ LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_rmdir(dir, dentry); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++ssize_t do_vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(file->f_dentry), (unsigned long)count, *ppos); ++ ++ /* nfs uses some locks */ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_read(file, ubuf, count, ppos); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++// kernel_read() ?? ++static inline ++ssize_t do_vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = do_vfsub_read_u(file, (char __user*)kbuf, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++static inline ++ssize_t do_vfsub_write_u(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(file->f_dentry), (unsigned long)count, *ppos); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_write(file, ubuf, count, ppos); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++static inline ++ssize_t do_vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = do_vfsub_write_u(file, (const char __user*)kbuf, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++static inline ++int do_vfsub_readdir(struct file *file, filldir_t filldir, void *arg) ++{ ++ int err; ++ ++ LKTRTrace("%.*s\n", DLNPair(file->f_dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_readdir(file, filldir, arg); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ LKTRTrace("%.*s\n", DLNPair(file->f_dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_llseek(file, offset, origin); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DLGT ++static inline int need_dlgt(struct super_block *sb) ++{ ++ return (au_flag_test(sb, AuFlag_DLGT) && !is_au_wkq(current)); ++} ++ ++int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, ++ int dlgt); ++ ++int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd, int dlgt); ++int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, ++ int mode, int dlgt); ++int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, ++ int dlgt); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry, int dlgt); ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, int dlgt); ++int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, int dlgt); ++int vfsub_rmdir(struct inode *dir, struct dentry *dentry, int dlgt); ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt); ++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt); ++ ++#else ++ ++static inline int need_dlgt(struct super_block *sb) ++{ ++ return 0; ++} ++ ++static inline ++int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, ++ int dlgt) ++{ ++ return do_vfsub_permission(inode, mask, nd); ++} ++ ++static inline ++int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd, int dlgt) ++{ ++ return do_vfsub_create(dir, dentry, mode, nd); ++} ++ ++static inline ++int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, ++ int mode, int dlgt) ++{ ++ return do_vfsub_symlink(dir, dentry, symname, mode); ++} ++ ++static inline ++int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, ++ int dlgt) ++{ ++ return do_vfsub_mknod(dir, dentry, mode, dev); ++} ++ ++static inline ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry, int dlgt) ++{ ++ return do_vfsub_link(src_dentry, dir, dentry); ++} ++ ++static inline ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ return do_vfsub_rename(src_dir, src_dentry, dir, dentry); ++} ++ ++static inline ++int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, ++ int dlgt) ++{ ++ return do_vfsub_mkdir(dir, dentry, mode); ++} ++ ++static inline ++int vfsub_rmdir(struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ return do_vfsub_rmdir(dir, dentry); ++} ++ ++static inline ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt) ++{ ++ return do_vfsub_read_u(file, ubuf, count, ppos); ++} ++ ++static inline ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt) ++{ ++ return do_vfsub_read_k(file, kbuf, count, ppos); ++} ++ ++static inline ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt) ++{ ++ return do_vfsub_write_u(file, ubuf, count, ppos); ++} ++ ++static inline ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt) ++{ ++ return do_vfsub_write_k(file, kbuf, count, ppos); ++} ++ ++static inline ++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt) ++{ ++ return do_vfsub_readdir(file, filldir, arg); ++} ++#endif /* CONFIG_AUFS_DLGT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct dentry *d2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ return d; ++} ++ ++static inline void vfsub_unlock_rename(struct dentry *d1, struct dentry *d2) ++{ ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_notify_change(struct dentry *dentry, struct iattr *ia, int dlgt); ++int vfsub_unlink(struct inode *dir, struct dentry *dentry, int dlgt); ++int vfsub_statfs(void *arg, struct kstatfs *buf, int dlgt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c +new file mode 100755 +index 0000000..b7f874c +--- /dev/null ++++ b/fs/aufs/whout.c +@@ -0,0 +1,933 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: whout.c,v 1.14 2007/05/14 03:40:40 sfjro Exp $ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++#define WH_MASK S_IRUGO ++ ++/* If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = { ++ .name = AUFS_WH_DIROPQ, ++ .len = sizeof(AUFS_WH_DIROPQ) - 1 ++}; ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by au_free_whname(). ++ */ ++int au_alloc_whname(const char *name, int len, struct qstr *wh) ++{ ++ char *p; ++ ++ DEBUG_ON(!name || !len || !wh); ++ ++ if (unlikely(len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = len + AUFS_WH_PFX_LEN; ++ wh->name = p = kmalloc(wh->len, GFP_KERNEL); ++ //if (LktrCond) {kfree(p); wh->name = p = NULL;} ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name, len); ++ //smp_mb(); ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++void au_free_whname(struct qstr *wh) ++{ ++ DEBUG_ON(!wh || !wh->name); ++ kfree(wh->name); ++#ifdef CONFIG_AUFS_DEBUG ++ wh->name = NULL; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @hidden_parent. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int is_wh(struct dentry *hidden_parent, struct qstr *wh_name, int try_sio, ++ struct lkup_args *lkup) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ struct inode *hidden_dir; ++ ++ LKTRTrace("%.*s/%.*s, lkup{%p, %d}\n", DLNPair(hidden_parent), ++ wh_name->len, wh_name->name, lkup->nfsmnt, lkup->dlgt); ++ hidden_dir = hidden_parent->d_inode; ++ DEBUG_ON(!S_ISDIR(hidden_dir->i_mode)); ++ IMustLock(hidden_dir); ++ ++ if (!try_sio) ++ wh_dentry = lkup_one(wh_name->name, hidden_parent, ++ wh_name->len, lkup); ++ else ++ wh_dentry = sio_lkup_one(wh_name->name, hidden_parent, ++ wh_name->len, lkup); ++ //if (LktrCond) {dput(wh_dentry); wh_dentry = ERR_PTR(-1);} ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ err = 0; ++ if (!wh_dentry->d_inode) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (S_ISREG(wh_dentry->d_inode->i_mode)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ IOErr("%.*s Invalid whiteout entry type 0%o.\n", ++ DLNPair(wh_dentry), wh_dentry->d_inode->i_mode); ++ ++ out_wh: ++ dput(wh_dentry); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * test if the @hidden_dentry sets opaque or not. ++ */ ++int is_diropq(struct dentry *hidden_dentry, struct lkup_args *lkup) ++{ ++ int err; ++ struct inode *hidden_dir; ++ ++ LKTRTrace("dentry %.*s\n", DLNPair(hidden_dentry)); ++ hidden_dir = hidden_dentry->d_inode; ++ DEBUG_ON(!S_ISDIR(hidden_dir->i_mode)); ++ IMustLock(hidden_dir); ++ ++ err = is_wh(hidden_dentry, &diropq_name, /*try_sio*/1, lkup); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *lkup_whtmp(struct dentry *hidden_parent, struct qstr *prefix, ++ struct lkup_args *lkup) ++{ ++#define HEX_LEN 4 ++ struct dentry *dentry; ++ int len, i; ++ char defname[AUFS_WH_PFX_LEN * 2 + DNAME_INLINE_LEN_MIN + 1 ++ + HEX_LEN + 1], *name, *p; ++ static unsigned char cnt; ++ ++ LKTRTrace("hp %.*s, prefix %.*s\n", ++ DLNPair(hidden_parent), prefix->len, prefix->name); ++ DEBUG_ON(!hidden_parent->d_inode); ++ IMustLock(hidden_parent->d_inode); ++ ++ name = defname; ++ len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(len >= PATH_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(len + 1, GFP_KERNEL); ++ //if (LktrCond) {kfree(name); name = NULL;} ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ // doubly whiteout-ed ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ DEBUG_ON(name + len + 1 - p <= HEX_LEN); ++ ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*d", HEX_LEN, cnt++); ++ dentry = sio_lkup_one(name, hidden_parent, len, lkup); ++ //if (LktrCond) {dput(dentry); dentry = ERR_PTR(-1);} ++ if (unlikely(IS_ERR(dentry) || !dentry->d_inode)) ++ goto out_name; ++ dput(dentry); ++ } ++ //Warn("could not get random name\n"); ++ dentry = ERR_PTR(-EEXIST); ++ Dbg("%.*s\n", len, name); ++ BUG(); ++ ++ out_name: ++ if (unlikely(name != defname)) ++ kfree(name); ++ out: ++ TraceErrPtr(dentry); ++ return dentry; ++#undef HEX_LEN ++} ++ ++/* ++ * rename the @dentry of @bindex to the whiteouted temporary name. ++ */ ++int rename_whtmp(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err; ++ struct inode *hidden_dir; ++ struct dentry *hidden_dentry, *hidden_parent, *tmp_dentry; ++ struct super_block *sb; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, b%d\n", DLNPair(dentry), bindex); ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ DEBUG_ON(!hidden_dentry || !hidden_dentry->d_inode); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ sb = dentry->d_sb; ++ lkup.nfsmnt = au_nfsmnt(sb, bindex); ++ lkup.dlgt = need_dlgt(sb); ++ tmp_dentry = lkup_whtmp(hidden_parent, &hidden_dentry->d_name, &lkup); ++ //if (LktrCond) {dput(tmp_dentry); tmp_dentry = ERR_PTR(-1);} ++ err = PTR_ERR(tmp_dentry); ++ if (!IS_ERR(tmp_dentry)) { ++ /* under the same dir, no need to lock_rename() */ ++ err = vfsub_rename(hidden_dir, hidden_dentry, ++ hidden_dir, tmp_dentry, lkup.dlgt); ++ //if (LktrCond) err = -1; //unavailable ++ TraceErr(err); ++ dput(tmp_dentry); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_unlink_wh_dentry(struct inode *hidden_dir, struct dentry *wh_dentry, ++ struct dentry *dentry, int dlgt) ++{ ++ int err; ++ ++ LKTRTrace("hi%lu, wh %.*s, d %p\n", hidden_dir->i_ino, ++ DLNPair(wh_dentry), dentry); ++ DEBUG_ON((dentry && dbwh(dentry) == -1) ++ || !wh_dentry->d_inode ++ || !S_ISREG(wh_dentry->d_inode->i_mode)); ++ IMustLock(hidden_dir); ++ ++ err = vfsub_unlink(hidden_dir, wh_dentry, dlgt); ++ //if (LktrCond) err = -1; // unavailable ++ if (!err && dentry) ++ set_dbwh(dentry, -1); ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int unlink_wh_name(struct dentry *hidden_parent, struct qstr *wh, ++ struct lkup_args *lkup) ++{ ++ int err; ++ struct inode *hidden_dir; ++ struct dentry *hidden_dentry; ++ ++ LKTRTrace("%.*s/%.*s\n", DLNPair(hidden_parent), LNPair(wh)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ // au_test_perm() is already done ++ hidden_dentry = lkup_one(wh->name, hidden_parent, wh->len, lkup); ++ //if (LktrCond) {dput(hidden_dentry); hidden_dentry = ERR_PTR(-1);} ++ if (!IS_ERR(hidden_dentry)) { ++ err = 0; ++ if (hidden_dentry->d_inode) ++ err = vfsub_unlink(hidden_dir, hidden_dentry, ++ lkup->dlgt); ++ dput(hidden_dentry); ++ } else ++ err = PTR_ERR(hidden_dentry); ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void clean_wh(struct inode *h_dir, struct dentry *wh) ++{ ++ TraceEnter(); ++ if (wh->d_inode) { ++ int err = vfsub_unlink(h_dir, wh, /*dlgt*/0); ++ if (unlikely(err)) ++ Warn("failed unlink %.*s (%d), ignored.\n", ++ DLNPair(wh), err); ++ } ++} ++ ++static void clean_plink(struct inode *h_dir, struct dentry *plink) ++{ ++ TraceEnter(); ++ if (plink->d_inode) { ++ int err = vfsub_rmdir(h_dir, plink, /*dlgt*/0); ++ if (unlikely(err)) ++ Warn("failed rmdir %.*s (%d), ignored.\n", ++ DLNPair(plink), err); ++ } ++} ++ ++static int test_linkable(struct inode *h_dir) ++{ ++ if (h_dir->i_op && h_dir->i_op->link) ++ return 0; ++ return -ENOSYS; ++} ++ ++static int plink_dir(struct inode *h_dir, struct dentry *plink) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (!plink->d_inode) { ++ int mode = S_IRWXU; ++ if (unlikely(au_is_nfs(plink->d_sb))) ++ mode |= S_IXUGO; ++ err = vfsub_mkdir(h_dir, plink, mode, /*dlgt*/0); ++ } else if (S_ISDIR(plink->d_inode->i_mode)) ++ err = 0; ++ else ++ Err("unknown %.*s exists\n", DLNPair(plink)); ++ ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int init_wh(struct dentry *h_root, struct aufs_branch *br, ++ struct vfsmount *nfsmnt, struct super_block *sb) ++{ ++ int err; ++ struct dentry *wh, *plink; ++ struct inode *h_dir; ++ static struct qstr base_name[] = { ++ {.name = AUFS_WH_BASENAME, .len = sizeof(AUFS_WH_BASENAME) - 1}, ++ {.name = AUFS_WH_PLINKDIR, .len = sizeof(AUFS_WH_PLINKDIR) - 1} ++ }; ++ struct lkup_args lkup = { ++ .nfsmnt = nfsmnt, ++ .dlgt = 0 // always no dlgt ++ }; ++ const int do_plink = au_flag_test(sb, AuFlag_PLINK); ++ ++ LKTRTrace("nfsmnt %p\n", nfsmnt); ++ BrWhMustWriteLock(br); ++ SiMustWriteLock(sb); ++ h_dir = h_root->d_inode; ++ IMustLock(h_dir); ++ ++ // doubly whiteouted ++ wh = lkup_wh(h_root, base_name + 0, &lkup); ++ //if (LktrCond) {dput(wh); wh = ERR_PTR(-1);} ++ err = PTR_ERR(wh); ++ if (IS_ERR(wh)) ++ goto out; ++ DEBUG_ON(br->br_wh && br->br_wh != wh); ++ ++ plink = lkup_wh(h_root, base_name + 1, &lkup); ++ err = PTR_ERR(plink); ++ if (IS_ERR(plink)) ++ goto out_dput_wh; ++ DEBUG_ON(br->br_plink && br->br_plink != plink); ++ ++ dput(br->br_wh); ++ dput(br->br_plink); ++ br->br_wh = br->br_plink = NULL; ++ ++ err = 0; ++ switch (br->br_perm) { ++ case AuBr_RR: ++ case AuBr_RO: ++ case AuBr_RRWH: ++ case AuBr_ROWH: ++ clean_wh(h_dir, wh); ++ clean_plink(h_dir, plink); ++ break; ++ ++ case AuBr_RWNoLinkWH: ++ clean_wh(h_dir, wh); ++ if (do_plink) { ++ err = test_linkable(h_dir); ++ if (unlikely(err)) ++ goto out_nolink; ++ ++ err = plink_dir(h_dir, plink); ++ if (unlikely(err)) ++ goto out_err; ++ br->br_plink = dget(plink); ++ } else ++ clean_plink(h_dir, plink); ++ break; ++ ++ case AuBr_RW: ++ /* ++ * for the moment, aufs supports the branch filesystem ++ * which does not support link(2). ++ * testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. ++ * finally, such filesystem will not be used as the writable branch. ++ */ ++ err = test_linkable(h_dir); ++ if (unlikely(err)) ++ goto out_nolink; ++ ++ err = -EEXIST; ++ if (!wh->d_inode) ++ err = vfsub_create(h_dir, wh, WH_MASK, NULL, /*dlgt*/0); ++ else if (S_ISREG(wh->d_inode->i_mode)) ++ err = 0; ++ else ++ Err("unknown %.*s/%.*s exists\n", ++ DLNPair(h_root), DLNPair(wh)); ++ if (unlikely(err)) ++ goto out_err; ++ ++ if (do_plink) { ++ err = plink_dir(h_dir, plink); ++ if (unlikely(err)) ++ goto out_err; ++ br->br_plink = dget(plink); ++ } else ++ clean_plink(h_dir, plink); ++ br->br_wh = dget(wh); ++ break; ++ ++ default: ++ BUG(); ++ } ++ ++ out_dput: ++ dput(plink); ++ out_dput_wh: ++ dput(wh); ++ out: ++ TraceErr(err); ++ return err; ++ out_nolink: ++ Err("%.*s doesn't support link(2), use noplink and rw+nolwh\n", ++ DLNPair(h_root)); ++ goto out_dput; ++ out_err: ++ Err("an error(%d) on the writable branch %.*s(%s)\n", ++ err, DLNPair(h_root), au_sbtype(h_root->d_sb)); ++ goto out_dput; ++} ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct aufs_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ struct reinit_br_wh *a = arg; ++ struct inode *hidden_dir, *dir; ++ struct dentry *hidden_root; ++ aufs_bindex_t bindex; ++ ++ TraceEnter(); ++ DEBUG_ON(!a->br->br_wh || !a->br->br_wh->d_inode || current->fsuid); ++ ++ err = 0; ++ /* big lock */ ++ si_write_lock(a->sb); ++ if (unlikely(!br_writable(a->br->br_perm))) ++ goto out; ++ bindex = find_brindex(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ dir = a->sb->s_root->d_inode; ++ hidden_root = a->br->br_wh->d_parent; ++ hidden_dir = hidden_root->d_inode; ++ DEBUG_ON(!hidden_dir->i_op || !hidden_dir->i_op->link); ++ hdir_lock(hidden_dir, dir, bindex); ++ br_wh_write_lock(a->br); ++ err = vfsub_unlink(hidden_dir, a->br->br_wh, /*dlgt*/0); ++ //if (LktrCond) err = -1; ++ dput(a->br->br_wh); ++ a->br->br_wh = NULL; ++ if (!err) ++ err = init_wh(hidden_root, a->br, au_do_nfsmnt(a->br->br_mnt), ++ a->sb); ++ br_wh_write_unlock(a->br); ++ hdir_unlock(hidden_dir, dir, bindex); ++ ++ out: ++ atomic_dec(&a->br->br_wh_running); ++ br_put(a->br); ++ si_write_unlock(a->sb); ++ au_mntput(a->sb); ++ kfree(arg); ++ if (unlikely(err)) ++ IOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct aufs_branch *br) ++{ ++ int do_dec; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wh_running) != 1) ++ goto out; ++ ++ // ignore ENOMEM ++ arg = kmalloc(sizeof(*arg), GFP_KERNEL); ++ if (arg) { ++ // dec(wh_running), kfree(arg) and br_put() in reinit function ++ arg->sb = sb; ++ arg->br = br; ++ br_get(br); ++ /* prohibit umount */ ++ au_mntget(sb); ++ au_wkq_nowait(reinit_br_wh, arg, /*dlgt*/0); ++ do_dec = 0; ++ } ++ ++ out: ++ if (do_dec) ++ atomic_dec(&br->br_wh_running); ++} ++ ++/* ++ * create the whiteoute @wh. ++ */ ++static int link_or_create_wh(struct dentry *wh, struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ int err, dlgt; ++ struct aufs_branch *br; ++ struct dentry *hidden_parent; ++ struct inode *hidden_dir; ++ ++ LKTRTrace("%.*s\n", DLNPair(wh)); ++ SiMustReadLock(sb); ++ hidden_parent = wh->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ dlgt = need_dlgt(sb); ++ br = stobr(sb, bindex); ++ br_wh_read_lock(br); ++ if (br->br_wh) { ++ err = vfsub_link(br->br_wh, hidden_dir, wh, dlgt); ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ // link count full. re-initialize br_wh. ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ // return this error in this context ++ err = vfsub_create(hidden_dir, wh, WH_MASK, NULL, dlgt); ++ ++ out: ++ br_wh_read_unlock(br); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ int do_create, int dlgt) ++{ ++ struct dentry *opq_dentry, *hidden_dentry; ++ struct inode *hidden_dir; ++ int err; ++ struct super_block *sb; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, bindex %d, do_create %d\n", DLNPair(dentry), ++ bindex, do_create); ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ DEBUG_ON(!hidden_dentry); ++ hidden_dir = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_dir || !S_ISDIR(hidden_dir->i_mode)); ++ IMustLock(hidden_dir); ++ ++ // already checked by au_test_perm(). ++ sb = dentry->d_sb; ++ lkup.nfsmnt = au_nfsmnt(sb, bindex); ++ lkup.dlgt = dlgt; ++ opq_dentry = lkup_one(diropq_name.name, hidden_dentry, diropq_name.len, ++ &lkup); ++ //if (LktrCond) {dput(opq_dentry); opq_dentry = ERR_PTR(-1);} ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (do_create) { ++ DEBUG_ON(opq_dentry->d_inode); ++ err = link_or_create_wh(opq_dentry, sb, bindex); ++ //if (LktrCond) {vfs_unlink(hidden_dir, opq_dentry); err = -1;} ++ if (!err) { ++ set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ DEBUG_ON(/* !S_ISDIR(dentry->d_inode->i_mode) ++ * || */!opq_dentry->d_inode); ++ err = vfsub_unlink(hidden_dir, opq_dentry, lkup.dlgt); ++ //if (LktrCond) err = -1; ++ if (!err) ++ set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++ out: ++ TraceErrPtr(opq_dentry); ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ int do_create, dlgt; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->do_create, a->dlgt); ++} ++ ++struct dentry *sio_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ int do_create, int dlgt) ++{ ++ struct dentry *diropq, *hidden_dentry; ++ ++ LKTRTrace("%.*s, bindex %d, do_create %d\n", ++ DLNPair(dentry), bindex, do_create); ++ ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!au_test_perm(hidden_dentry->d_inode, MAY_EXEC | MAY_WRITE, dlgt)) ++ diropq = do_diropq(dentry, bindex, do_create, dlgt); ++ else { ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .do_create = do_create, ++ .dlgt = dlgt ++ }; ++ au_wkq_wait(call_do_diropq, &args, /*dlgt*/0); ++ } ++ ++ TraceErrPtr(diropq); ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @hidden_parent: hidden parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *lkup_wh(struct dentry *hidden_parent, struct qstr *base_name, ++ struct lkup_args *lkup) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ ++ LKTRTrace("%.*s/%.*s\n", DLNPair(hidden_parent), LNPair(base_name)); ++ IMustLock(hidden_parent->d_inode); ++ ++ err = au_alloc_whname(base_name->name, base_name->len, &wh_name); ++ //if (LktrCond) {au_free_whname(&wh_name); err = -1;} ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ // do not superio. ++ wh_dentry = lkup_one(wh_name.name, hidden_parent, wh_name.len, ++ lkup); ++ au_free_whname(&wh_name); ++ } ++ TraceErrPtr(wh_dentry); ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *simple_create_wh(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *hidden_parent, ++ struct lkup_args *lkup) ++{ ++ struct dentry *wh_dentry; ++ int err; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s/%.*s on b%d\n", DLNPair(hidden_parent), ++ DLNPair(dentry), bindex); ++ ++ sb = dentry->d_sb; ++ wh_dentry = lkup_wh(hidden_parent, &dentry->d_name, lkup); ++ //au_nfsmnt(sb, bindex), need_dlgt(sb)); ++ //if (LktrCond) {dput(wh_dentry); wh_dentry = ERR_PTR(-1);} ++ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { ++ IMustLock(hidden_parent->d_inode); ++ err = link_or_create_wh(wh_dentry, sb, bindex); ++ if (!err) ++ set_dbwh(dentry, bindex); ++ else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ TraceErrPtr(wh_dentry); ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory in branch bindex. */ ++static int del_wh_children(struct aufs_nhash *whlist, ++ struct dentry *hidden_parent, aufs_bindex_t bindex, ++ struct lkup_args *lkup) ++{ ++ int err, i; ++ struct qstr wh_name; ++ char *p; ++ struct inode *hidden_dir; ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos; ++ struct aufs_destr *str; ++ ++ LKTRTrace("%.*s\n", DLNPair(hidden_parent)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ DEBUG_ON(IS_RDONLY(hidden_dir)); ++ //SiMustReadLock(??); ++ ++ err = -ENOMEM; ++ wh_name.name = p = __getname(); ++ //if (LktrCond) {__putname(p); wh_name.name = p = NULL;} ++ if (unlikely(!wh_name.name)) ++ goto out; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ ++ // already checked by au_test_perm(). ++ err = 0; ++ for (i = 0; !err && i < AUFS_NHASH_SIZE; i++) { ++ head = whlist->heads + i; ++ hlist_for_each_entry(tpos, pos, head, wh_hash) { ++ if (tpos->wh_bindex != bindex) ++ continue; ++ str = &tpos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(hidden_parent, &wh_name, ++ lkup); ++ //if (LktrCond) err = -1; ++ if (!err) ++ continue; ++ break; ++ } ++ IOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ __putname(wh_name.name); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct aufs_nhash *whlist; ++ struct dentry *hidden_parent; ++ aufs_bindex_t bindex; ++ struct lkup_args *lkup; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->whlist, a->hidden_parent, a->bindex, ++ a->lkup); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * rmdir the whiteouted temporary named dir @hidden_dentry. ++ * @whlist: whiteouted children. ++ */ ++int rmdir_whtmp(struct dentry *hidden_dentry, struct aufs_nhash *whlist, ++ aufs_bindex_t bindex, struct inode *dir, struct inode *inode) ++{ ++ int err; ++ struct inode *hidden_inode, *hidden_dir; ++ struct lkup_args lkup; ++ struct super_block *sb; ++ ++ LKTRTrace("hd %.*s, b%d, i%lu\n", ++ DLNPair(hidden_dentry), bindex, dir->i_ino); ++ IMustLock(dir); ++ IiMustAnyLock(dir); ++ hidden_dir = hidden_dentry->d_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ sb = inode->i_sb; ++ lkup.nfsmnt = au_nfsmnt(sb, bindex); ++ lkup.dlgt = need_dlgt(sb); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(hidden_inode != au_h_iptr_i(inode, bindex)); ++ hdir2_lock(hidden_inode, inode, bindex); ++ if (!au_test_perm(hidden_inode, MAY_EXEC | MAY_WRITE, lkup.dlgt)) ++ err = del_wh_children(whlist, hidden_dentry, bindex, &lkup); ++ else { ++ // ugly ++ int dlgt = lkup.dlgt; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .whlist = whlist, ++ .hidden_parent = hidden_dentry, ++ .bindex = bindex, ++ .lkup = &lkup ++ }; ++ ++ lkup.dlgt = 0; ++ au_wkq_wait(call_del_wh_children, &args, /*dlgt*/0); ++ lkup.dlgt = dlgt; ++ } ++ hdir_unlock(hidden_inode, inode, bindex); ++ ++ if (!err) { ++ err = vfsub_rmdir(hidden_dir, hidden_dentry, lkup.dlgt); ++ //d_drop(hidden_dentry); ++ //if (LktrCond) err = -1; ++ } ++ ++ if (!err) { ++ if (ibstart(dir) == bindex) { ++ au_cpup_attr_timesizes(dir); ++ //au_cpup_attr_nlink(dir); ++ dir->i_nlink--; ++ } ++ return 0; /* success */ ++ } ++ ++ Warn("failed removing %.*s(%d), ignored\n", ++ DLNPair(hidden_dentry), err); ++ return err; ++} ++ ++static void do_rmdir_whtmp(void *arg) ++{ ++ int err; ++ struct rmdir_whtmp_arg *a = arg; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, b%d, dir i%lu\n", ++ DLNPair(a->h_dentry), a->bindex, a->dir->i_ino); ++ ++ i_lock(a->dir); ++ sb = a->dir->i_sb; ++ si_read_lock(sb); ++ err = test_ro(sb, a->bindex, NULL); ++ if (!err) { ++ struct inode *hidden_dir = a->h_dentry->d_parent->d_inode; ++ ++ ii_write_lock_child(a->inode); ++ ii_write_lock_parent(a->dir); ++ hdir_lock(hidden_dir, a->dir, a->bindex); ++ err = rmdir_whtmp(a->h_dentry, &a->whlist, a->bindex, ++ a->dir, a->inode); ++ hdir_unlock(hidden_dir, a->dir, a->bindex); ++ ii_write_unlock(a->dir); ++ ii_write_unlock(a->inode); ++ } ++ dput(a->h_dentry); ++ nhash_fin(&a->whlist); ++ iput(a->inode); ++ si_read_unlock(sb); ++ au_mntput(sb); ++ i_unlock(a->dir); ++ iput(a->dir); ++ kfree(arg); ++ if (unlikely(err)) ++ IOErr("err %d\n", err); ++} ++ ++void kick_rmdir_whtmp(struct dentry *hidden_dentry, struct aufs_nhash *whlist, ++ aufs_bindex_t bindex, struct inode *dir, ++ struct inode *inode, struct rmdir_whtmp_arg *arg) ++{ ++ LKTRTrace("%.*s\n", DLNPair(hidden_dentry)); ++ IMustLock(dir); ++ ++ // all post-process will be done in do_rmdir_whtmp(). ++ arg->h_dentry = dget(hidden_dentry); ++ nhash_init(&arg->whlist); ++ nhash_move(&arg->whlist, whlist); ++ arg->bindex = bindex; ++ arg->dir = igrab(dir); ++ arg->inode = igrab(inode); ++ /* prohibit umount */ ++ au_mntget(dir->i_sb); ++ ++ au_wkq_nowait(do_rmdir_whtmp, arg, /*dlgt*/0); ++} +diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h +new file mode 100755 +index 0000000..d44c3cd +--- /dev/null ++++ b/fs/aufs/whout.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: whout.h,v 1.8 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++int au_alloc_whname(const char *name, int len, struct qstr *wh); ++void au_free_whname(struct qstr *wh); ++ ++struct lkup_args; ++int is_wh(struct dentry *h_parent, struct qstr *wh_name, int try_sio, ++ struct lkup_args *lkup); ++int is_diropq(struct dentry *h_dentry, struct lkup_args *lkup); ++ ++struct dentry *lkup_whtmp(struct dentry *h_parent, struct qstr *prefix, ++ struct lkup_args *lkup); ++int rename_whtmp(struct dentry *dentry, aufs_bindex_t bindex); ++int au_unlink_wh_dentry(struct inode *h_dir, struct dentry *wh_dentry, ++ struct dentry *dentry, int dlgt); ++ ++struct aufs_branch; ++int init_wh(struct dentry *h_parent, struct aufs_branch *br, ++ struct vfsmount *nfsmnt, struct super_block *sb); ++ ++struct dentry *sio_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ int do_create, int dlgt); ++ ++struct dentry *lkup_wh(struct dentry *h_parent, struct qstr *base_name, ++ struct lkup_args *lkup); ++struct dentry *simple_create_wh(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, ++ struct lkup_args *lkup); ++ ++/* real rmdir the whiteout-ed dir */ ++struct rmdir_whtmp_arg { ++ struct dentry *h_dentry; ++ struct aufs_nhash whlist; ++ aufs_bindex_t bindex; ++ struct inode *dir, *inode; ++}; ++ ++struct aufs_nhash; ++int rmdir_whtmp(struct dentry *h_dentry, struct aufs_nhash *whlist, ++ aufs_bindex_t bindex, struct inode *dir, struct inode *inode); ++void kick_rmdir_whtmp(struct dentry *h_dentry, struct aufs_nhash *whlist, ++ aufs_bindex_t bindex, struct inode *dir, ++ struct inode *inode, struct rmdir_whtmp_arg *arg); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++struct dentry *create_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ int dlgt) ++{ ++ return sio_diropq(dentry, bindex, 1, dlgt); ++} ++ ++static inline ++int remove_diropq(struct dentry *dentry, aufs_bindex_t bindex, int dlgt) ++{ ++ return PTR_ERR(sio_diropq(dentry, bindex, 0, dlgt)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c +new file mode 100755 +index 0000000..b5ab023 +--- /dev/null ++++ b/fs/aufs/wkq.c +@@ -0,0 +1,283 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: wkq.c,v 1.14 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++#include ++#include "aufs.h" ++ ++struct au_wkq *au_wkq; ++ ++struct au_cred { ++#ifdef CONFIG_AUFS_DLGT ++ uid_t fsuid; ++ gid_t fsgid; ++ kernel_cap_t cap_effective, cap_inheritable, cap_permitted; ++ //unsigned keep_capabilities:1; ++ //struct user_struct *user; ++ //struct fs_struct *fs; ++ //struct nsproxy *nsproxy; ++#endif ++}; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ ++ unsigned int wait:1; ++ unsigned int dlgt:1; ++ struct au_cred cred; ++ ++ au_wkq_func_t func; ++ void *args; ++ ++ atomic_t *busyp; ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DLGT ++static void cred_store(struct au_cred *cred) ++{ ++ cred->fsuid = current->fsuid; ++ cred->fsgid = current->fsgid; ++ cred->cap_effective = current->cap_effective; ++ cred->cap_inheritable = current->cap_inheritable; ++ cred->cap_permitted = current->cap_permitted; ++} ++ ++static void cred_revert(struct au_cred *cred) ++{ ++ DEBUG_ON(!is_au_wkq(current)); ++ current->fsuid = cred->fsuid; ++ current->fsgid = cred->fsgid; ++ current->cap_effective = cred->cap_effective; ++ current->cap_inheritable = cred->cap_inheritable; ++ current->cap_permitted = cred->cap_permitted; ++} ++ ++static void cred_switch(struct au_cred *old, struct au_cred *new) ++{ ++ cred_store(old); ++ cred_revert(new); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void update_busy(struct au_wkq *wkq, struct au_wkinfo *wkinfo) ++{ ++#ifdef CONFIG_AUFS_SYSAUFS ++ unsigned int new, old; ++ ++ do { ++ new = atomic_read(wkinfo->busyp); ++ old = wkq->max_busy; ++ if (new <= old) ++ break; ++ } while (cmpxchg(&wkq->max_busy, old, new) == old); ++#endif ++} ++ ++static int enqueue(struct au_wkq *wkq, struct au_wkinfo *wkinfo) ++{ ++ wkinfo->busyp = &wkq->busy; ++ update_busy(wkq, wkinfo); ++ if (wkinfo->wait) ++ return !queue_work(wkq->q, &wkinfo->wk); ++ else ++ return !schedule_work(&wkinfo->wk); ++} ++ ++static void do_wkq(struct au_wkinfo *wkinfo) ++{ ++ unsigned int idle, n; ++ int i, idle_idx; ++ ++ TraceEnter(); ++ ++ while (1) { ++ if (wkinfo->wait) { ++ idle_idx = 0; ++ idle = UINT_MAX; ++ for (i = 0; i < aufs_nwkq; i++) { ++ n = atomic_inc_return(&au_wkq[i].busy); ++ if (n == 1 && !enqueue(au_wkq + i, wkinfo)) ++ return; /* success */ ++ ++ if (n < idle) { ++ idle_idx = i; ++ idle = n; ++ } ++ atomic_dec(&au_wkq[i].busy); ++ } ++ } else ++ idle_idx = aufs_nwkq; ++ ++ atomic_inc(&au_wkq[idle_idx].busy); ++ if (!enqueue(au_wkq + idle_idx, wkinfo)) ++ return; /* success */ ++ ++ /* impossible? */ ++ Warn1("failed to queue_work()\n"); ++ yield(); ++ } ++} ++ ++static AuWkqFunc(wkq_func, wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ LKTRTrace("wkinfo{%u, %u, %p, %p, %p}\n", ++ wkinfo->wait, wkinfo->dlgt, wkinfo->func, wkinfo->busyp, ++ wkinfo->comp); ++#ifdef CONFIG_AUFS_DLGT ++ if (!wkinfo->dlgt) ++ wkinfo->func(wkinfo->args); ++ else { ++ struct au_cred cred; ++ cred_switch(&cred, &wkinfo->cred); ++ wkinfo->func(wkinfo->args); ++ cred_revert(&cred); ++ } ++#else ++ wkinfo->func(wkinfo->args); ++#endif ++ atomic_dec(wkinfo->busyp); ++ if (wkinfo->wait) ++ complete(wkinfo->comp); ++ else { ++ kfree(wkinfo); ++ module_put(THIS_MODULE); ++ } ++} ++ ++void au_wkq_run(au_wkq_func_t func, void *args, int dlgt, int do_wait) ++{ ++ DECLARE_COMPLETION_ONSTACK(comp); ++ struct au_wkinfo _wkinfo = { ++ .wait = 1, ++ .dlgt = !!dlgt, ++ .func = func, ++ .args = args, ++ .comp = &comp ++ }, *wkinfo = &_wkinfo; ++ ++ LKTRTrace("dlgt %d, do_wait %d\n", dlgt, do_wait); ++ DEBUG_ON(is_au_wkq(current)); ++ ++ if (unlikely(!do_wait)) { ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ /* ++ * never fail. ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ wait_event(wq, (wkinfo = kmalloc(sizeof(*wkinfo), GFP_KERNEL))); ++ wkinfo->wait = 0; ++ wkinfo->dlgt = !!dlgt; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ __module_get(THIS_MODULE); ++ } ++ ++ AuInitWkq(&wkinfo->wk, wkq_func); ++#ifdef CONFIG_AUFS_DLGT ++ if (dlgt) ++ cred_store(&wkinfo->cred); ++#endif ++ do_wkq(wkinfo); ++ if (do_wait) ++ wait_for_completion(wkinfo->comp); ++} ++ ++#if 0 ++void au_wkq_wait_nwtask(void) ++{ ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ wait_event(wq, !atomic_read(&au_wkq[aufs_nwkq].busy)); ++} ++#endif ++ ++void au_wkq_fin(void) ++{ ++ int i; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < aufs_nwkq; i++) ++ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) ++ destroy_workqueue(au_wkq[i].q); ++ kfree(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ int err, i; ++ struct au_wkq *nowaitq; ++ ++ LKTRTrace("%d\n", aufs_nwkq); ++ ++ /* '+1' is for accounting of nowait queue */ ++ err = -ENOMEM; ++ au_wkq = kcalloc(aufs_nwkq + 1, sizeof(*au_wkq), GFP_KERNEL); ++ if (unlikely(!au_wkq)) ++ goto out; ++ ++ err = 0; ++ for (i = 0; i < aufs_nwkq; i++) { ++ au_wkq[i].q = create_singlethread_workqueue(AUFS_WKQ_NAME); ++ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) { ++ atomic_set(&au_wkq[i].busy, 0); ++ au_wkq[i].max_busy = 0; ++ continue; ++ } ++ ++ err = PTR_ERR(au_wkq[i].q); ++ au_wkq_fin(); ++ break; ++ } ++ ++ /* nowait accounting */ ++ nowaitq = au_wkq + aufs_nwkq; ++ atomic_set(&nowaitq->busy, 0); ++ nowaitq->max_busy = 0; ++ nowaitq->q = NULL; ++ ++#if 0 // test accouting ++ if (!err) { ++ static void f(void *args) { ++ DbgSleep(1); ++ } ++ int i; ++ //au_debug_on(); ++ LKTRTrace("f %p\n", f); ++ for (i = 0; i < 10; i++) ++ au_wkq_nowait(f, NULL, 0); ++ for (i = 0; i < aufs_nwkq; i++) ++ au_wkq_wait(f, NULL, 0); ++ DbgSleep(11); ++ //au_debug_off(); ++ } ++#endif ++ ++ out: ++ TraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h +new file mode 100755 +index 0000000..cc1bb25 +--- /dev/null ++++ b/fs/aufs/wkq.h +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: wkq.h,v 1.9 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#define DECLARE_COMPLETION_ONSTACK(work) DECLARE_COMPLETION(work) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++struct au_wkq { ++ struct workqueue_struct *q; ++ ++ /* accounting */ ++ atomic_t busy; ++ unsigned int max_busy; ++} ;//__attribute__ ((aligned)); ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++#define AuInitWkq(wk, func) INIT_WORK(wk, func) ++#define AuWkqFunc(name, arg) void name(struct work_struct *arg) ++#else ++typedef void (*work_func_t)(void *arg); ++#define AuInitWkq(wk, func) INIT_WORK(wk, func, wk) ++#define AuWkqFunc(name, arg) void name(void *arg) ++#endif ++ ++extern struct au_wkq *au_wkq; ++ ++void au_wkq_run(au_wkq_func_t func, void *args, int dlgt, int do_wait); ++//void au_wkq_wait_nwtask(void); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int is_au_wkq(struct task_struct *tsk) ++{ ++ return (!tsk->mm && !strcmp(current->comm, AUFS_WKQ_NAME)); ++} ++ ++static inline void au_wkq_wait(au_wkq_func_t func, void *args, int dlgt) ++{ ++ au_wkq_run(func, args, dlgt, /*do_wait*/1); ++} ++ ++static inline void au_wkq_nowait(au_wkq_func_t func, void *args, int dlgt) ++{ ++ au_wkq_run(func, args, dlgt, /*do_wait*/0); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c +new file mode 100755 +index 0000000..145491e +--- /dev/null ++++ b/fs/aufs/xino.c +@@ -0,0 +1,644 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: xino.c,v 1.27 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++//#include ++#include ++#include ++#include "aufs.h" ++ ++static readf_t find_readf(struct file *h_file) ++{ ++ const struct file_operations *fop = h_file->f_op; ++ ++ if (fop) { ++ if (fop->read) ++ return fop->read; ++ if (fop->aio_read) ++ return do_sync_read; ++ } ++ return ERR_PTR(-ENOSYS); ++} ++ ++static writef_t find_writef(struct file *h_file) ++{ ++ const struct file_operations *fop = h_file->f_op; ++ ++ if (fop) { ++ if (fop->write) ++ return fop->write; ++ if (fop->aio_write) ++ return do_sync_write; ++ } ++ return ERR_PTR(-ENOSYS); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t xino_fread(readf_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ LKTRTrace("%.*s, sz %lu, *pos %Ld\n", ++ DLNPair(file->f_dentry), (unsigned long)size, *pos); ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, (char __user*)buf, size, pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ set_fs(oldfs); ++ ++#if 0 ++ if (err > 0) ++ fsnotify_access(file->f_dentry); ++#endif ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t do_xino_fwrite(writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ lockdep_off(); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, (const char __user*)buf, size, pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ set_fs(oldfs); ++ lockdep_on(); ++ ++#if 0 ++ if (err > 0) ++ fsnotify_modify(file->f_dentry); ++#endif ++ ++ TraceErr(err); ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ writef_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite(writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ ++ LKTRTrace("%.*s, sz %lu, *pos %Ld\n", ++ DLNPair(file->f_dentry), (unsigned long)size, *pos); ++ ++ // signal block and no wkq? ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ if (!is_au_wkq(current)) { ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ au_wkq_wait(call_do_xino_fwrite, &args, /*dlgt*/0); ++ } else ++ err = do_xino_fwrite(func, file, buf, size, pos); ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @_ino. ++ * when @ino is zero, it is written to the xinofile and means no entry. ++ */ ++int xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ struct xino *xino) ++{ ++ struct aufs_branch *br; ++ loff_t pos; ++ ssize_t sz; ++ ++ LKTRTrace("b%d, hi%lu, i%lu\n", bindex, h_ino, xino->ino); ++ //DEBUG_ON(!xino->ino /* || !xino->h_gen */); ++ //WARN_ON(bindex == 0 && h_ino == 31); ++ ++ if (unlikely(!au_flag_test(sb, AuFlag_XINO))) ++ return 0; ++ ++ br = stobr(sb, bindex); ++ DEBUG_ON(!br || !br->br_xino); ++ pos = h_ino * sizeof(*xino); ++ sz = xino_fwrite(br->br_xino_write, br->br_xino, xino, sizeof(*xino), ++ &pos); ++ //if (LktrCond) sz = 1; ++ if (sz == sizeof(*xino)) ++ return 0; /* success */ ++ ++ IOErr("write failed (%ld)\n", (long)sz); ++ return -EIO; ++} ++ ++int xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct xino xino = { ++ .ino = 0 ++ }; ++ return xino_write(sb, bindex, h_ino, &xino); ++} ++ ++// why is not atomic_long_inc_return defined? ++static DEFINE_SPINLOCK(alir_lock); ++static long atomic_long_inc_return(atomic_long_t *a) ++{ ++ long l; ++ ++ spin_lock(&alir_lock); ++ atomic_long_inc(a); ++ l = atomic_long_read(a); ++ spin_unlock(&alir_lock); ++ return l; ++} ++ ++ino_t xino_new_ino(struct super_block *sb) ++{ ++ ino_t ino; ++ ++ TraceEnter(); ++ ino = atomic_long_inc_return(&stosi(sb)->si_xino); ++ BUILD_BUG_ON(AUFS_FIRST_INO < AUFS_ROOT_INO); ++ if (ino >= AUFS_ROOT_INO) ++ return ino; ++ else { ++ atomic_long_dec(&stosi(sb)->si_xino); ++ IOErr1("inode number overflow\n"); ++ return 0; ++ } ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * if @ino does not exist and @do_new is true, get new one. ++ */ ++int xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ struct xino *xino) ++{ ++ int err; ++ struct aufs_branch *br; ++ struct file *file; ++ loff_t pos; ++ ssize_t sz; ++ ++ LKTRTrace("b%d, hi%lu\n", bindex, h_ino); ++ ++ err = 0; ++ xino->ino = 0; ++ if (unlikely(!au_flag_test(sb, AuFlag_XINO))) ++ return 0; /* no ino */ ++ ++ br = stobr(sb, bindex); ++ file = br->br_xino; ++ DEBUG_ON(!file); ++ pos = h_ino * sizeof(*xino); ++ if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*xino)) ++ return 0; /* no ino */ ++ ++ sz = xino_fread(br->br_xino_read, file, xino, sizeof(*xino), &pos); ++ if (sz == sizeof(*xino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ IOErr("xino read error (%ld)\n", (long)sz); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file *xino_create(struct super_block *sb, char *fname, int silent, ++ struct dentry *parent) ++{ ++ struct file *file; ++ int err; ++ struct dentry *hidden_parent; ++ struct inode *hidden_dir; ++ //const int udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY); ++ ++ LKTRTrace("%s\n", fname); ++ //DEBUG_ON(!au_flag_test(sb, AuFlag_XINO)); ++ ++ // LSM may detect it ++ // use sio? ++ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, ++ S_IRUGO | S_IWUGO); ++ //file = ERR_PTR(-1); ++ if (IS_ERR(file)) { ++ if (!silent) ++ Err("open %s(%ld)\n", fname, PTR_ERR(file)); ++ return file; ++ } ++#if 0 ++ if (unlikely(udba && parent)) ++ au_direval_dec(parent); ++#endif ++ ++ /* keep file count */ ++ hidden_parent = dget_parent(file->f_dentry); ++ hidden_dir = hidden_parent->d_inode; ++ hi_lock_parent(hidden_dir); ++ err = vfsub_unlink(hidden_dir, file->f_dentry, /*dlgt*/0); ++#if 0 ++ if (unlikely(!err && udba && parent)) ++ au_direval_dec(parent); ++#endif ++ i_unlock(hidden_dir); ++ dput(hidden_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ Err("unlink %s(%d)\n", fname, err); ++ goto out; ++ } ++ if (sb != file->f_dentry->d_sb) ++ return file; /* success */ ++ ++ if (!silent) ++ Err("%s must be outside\n", fname); ++ err = -EINVAL; ++ ++ out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bend. ++ */ ++static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bend) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb = sbr_sb(sb, btgt); ++ ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (unlikely(btgt != bindex && tgt_sb == sbr_sb(sb, bindex))) ++ return bindex; ++ return -1; ++} ++ ++/* ++ * create a new xinofile at the same place/path as @base_file. ++ */ ++static struct file *xino_create2(struct file *base_file) ++{ ++ struct file *file; ++ int err; ++ struct dentry *base, *dentry, *parent; ++ struct inode *dir; ++ struct qstr *name; ++ struct lkup_args lkup = { ++ .nfsmnt = NULL, ++ .dlgt = 0 ++ }; ++ ++ base = base_file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(base)); ++ parent = dget_parent(base); ++ dir = parent->d_inode; ++ IMustLock(dir); ++ ++ file = ERR_PTR(-EINVAL); ++ if (unlikely(au_is_nfs(parent->d_sb))) ++ goto out; ++ ++ // do not superio, nor NFS. ++ name = &base->d_name; ++ dentry = lkup_one(name->name, parent, name->len, &lkup); ++ //if (LktrCond) {dput(dentry); dentry = ERR_PTR(-1);} ++ if (IS_ERR(dentry)) { ++ file = (void*)dentry; ++ Err("%.*s lookup err %ld\n", LNPair(name), PTR_ERR(dentry)); ++ goto out; ++ } ++ err = vfsub_create(dir, dentry, S_IRUGO | S_IWUGO, NULL, /*dlgt*/0); ++ //if (LktrCond) {vfs_unlink(dir, dentry); err = -1;} ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ Err("%.*s create err %d\n", LNPair(name), err); ++ goto out_dput; ++ } ++ file = dentry_open(dget(dentry), mntget(base_file->f_vfsmnt), ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ if (IS_ERR(file)) { ++ Err("%.*s open err %ld\n", LNPair(name), PTR_ERR(file)); ++ goto out_dput; ++ } ++ err = vfsub_unlink(dir, dentry, /*dlgt*/0); ++ //if (LktrCond) err = -1; ++ if (!err) ++ goto out_dput; /* success */ ++ ++ Err("%.*s unlink err %d\n", LNPair(name), err); ++ fput(file); ++ file = ERR_PTR(err); ++ ++ out_dput: ++ dput(dentry); ++ out: ++ dput(parent); ++ TraceErrPtr(file); ++ return file; ++} ++ ++/* ++ * initialize the xinofile for the specified branch{@sb, @bindex} ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if @do_test is true. ++ */ ++int xino_init(struct super_block *sb, aufs_bindex_t bindex, ++ struct file *base_file, int do_test) ++{ ++ int err; ++ struct aufs_branch *br; ++ aufs_bindex_t bshared, bend; ++ struct file *file; ++ struct inode *inode, *hidden_inode; ++ struct xino xino; ++ ++ LKTRTrace("b%d, base_file %p, do_test %d\n", ++ bindex, base_file, do_test); ++ SiMustWriteLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_XINO)); ++ br = stobr(sb, bindex); ++ DEBUG_ON(br->br_xino); ++ ++ file = NULL; ++ bshared = -1; ++ bend = sbend(sb); ++ if (do_test) ++ bshared = is_sb_shared(sb, bindex, bend); ++ if (unlikely(bshared >= 0)) { ++ struct aufs_branch *shared_br = stobr(sb, bshared); ++ if (shared_br->br_xino) { ++ file = shared_br->br_xino; ++ get_file(file); ++ } ++ } ++ ++ if (!file) { ++ struct dentry *parent = dget_parent(base_file->f_dentry); ++ struct inode *dir = parent->d_inode; ++ ++ hi_lock_parent(dir); ++ file = xino_create2(base_file); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ i_unlock(dir); ++ dput(parent); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ } ++ br->br_xino_read = find_readf(file); ++ err = PTR_ERR(br->br_xino_read); ++ if (IS_ERR(br->br_xino_read)) ++ goto out_put; ++ br->br_xino_write = find_writef(file); ++ err = PTR_ERR(br->br_xino_write); ++ if (IS_ERR(br->br_xino_write)) ++ goto out_put; ++ br->br_xino = file; ++ ++ inode = sb->s_root->d_inode; ++ hidden_inode = au_h_iptr_i(inode, bindex); ++ xino.ino = inode->i_ino; ++ //xino.h_gen = hidden_inode->i_generation; ++ //WARN_ON(xino.h_gen == AuXino_INVALID_HGEN); ++ err = xino_write(sb, bindex, hidden_inode->i_ino, &xino); ++ //if (LktrCond) err = -1; ++ if (!err) ++ return 0; /* success */ ++ ++ br->br_xino = NULL; ++ ++ out_put: ++ fput(file); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * set xino mount option. ++ */ ++int xino_set(struct super_block *sb, struct opt_xino *xino, int remount) ++{ ++ int err, sparse; ++ aufs_bindex_t bindex, bend; ++ struct aufs_branch *br; ++ struct dentry *parent; ++ struct qstr *name; ++ struct file *cur_xino; ++ struct inode *dir; ++ ++ LKTRTrace("%s\n", xino->path); ++ ++ err = 0; ++ name = &xino->file->f_dentry->d_name; ++ parent = dget_parent(xino->file->f_dentry); ++ dir = parent->d_inode; ++ cur_xino = stobr(sb, 0)->br_xino; ++ if (remount ++ && cur_xino ++ && cur_xino->f_dentry->d_parent == parent ++ && name->len == cur_xino->f_dentry->d_name.len ++ && !memcmp(name->name, cur_xino->f_dentry->d_name.name, name->len)) ++ goto out; ++ ++ au_flag_set(sb, AuFlag_XINO); ++ bend = sbend(sb); ++ for (bindex = bend; bindex >= 0; bindex--) { ++ br = stobr(sb, bindex); ++ if (unlikely(br->br_xino && file_count(br->br_xino) > 1)) { ++ fput(br->br_xino); ++ br->br_xino = NULL; ++ } ++ } ++ ++ for (bindex = 0; bindex <= bend; bindex++) { ++ struct file *file; ++ struct inode *inode; ++ ++ br = stobr(sb, bindex); ++ if (unlikely(!br->br_xino)) ++ continue; ++ ++ DEBUG_ON(file_count(br->br_xino) != 1); ++ hi_lock_parent(dir); ++ file = xino_create2(xino->file); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) { ++ i_unlock(dir); ++ break; ++ } ++ inode = br->br_xino->f_dentry->d_inode; ++ err = au_copy_file(file, br->br_xino, i_size_read(inode), sb, ++ &sparse); ++ //if (LktrCond) err = -1; ++ i_unlock(dir); ++ if (unlikely(err)) { ++ fput(file); ++ break; ++ } ++ fput(br->br_xino); ++ br->br_xino = file; ++ br->br_xino_read = find_readf(file); ++ DEBUG_ON(IS_ERR(br->br_xino_read)); ++ br->br_xino_write = find_writef(file); ++ DEBUG_ON(IS_ERR(br->br_xino_write)); ++ } ++ ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (unlikely(!stobr(sb, bindex)->br_xino)) { ++ err = xino_init(sb, bindex, xino->file, /*do_test*/1); ++ //if (LktrCond) {fput(stobr(sb, bindex)->br_xino); ++ //stobr(sb, bindex)->br_xino = NULL; err = -1;} ++ if (!err) ++ continue; ++ IOErr("creating xino for branch %d(%d), " ++ "forcing noxino\n", bindex, err); ++ err = -EIO; ++ break; ++ } ++ out: ++ dput(parent); ++ if (!err) ++ au_flag_set(sb, AuFlag_XINO); ++ else ++ au_flag_clr(sb, AuFlag_XINO); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * clear xino mount option ++ */ ++int xino_clr(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ ++ bend = sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ struct aufs_branch *br; ++ br = stobr(sb, bindex); ++ if (br->br_xino) { ++ fput(br->br_xino); ++ br->br_xino = NULL; ++ } ++ } ++ ++ //todo: need to make iunique() to return the larger inode number ++ ++ au_flag_clr(sb, AuFlag_XINO); ++ return 0; ++} ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ aufs_bindex_t bend, bindex, bwr; ++ char *page, *p; ++ ++ bend = sbend(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (br_writable(sbr_perm(sb, bindex)) ++ && !au_is_nfs(au_h_dptr_i(sb->s_root, bindex)->d_sb)) { ++ bwr = bindex; ++ break; ++ } ++ ++ if (bwr != -1) { ++ // todo: rewrite with lkup_one() ++ file = ERR_PTR(-ENOMEM); ++ page = __getname(); ++ //if (LktrCond) {__putname(page); page = NULL;} ++ if (unlikely(!page)) ++ goto out; ++ p = d_path(au_h_dptr_i(sb->s_root, bwr), sbr_mnt(sb, bwr), page, ++ PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ //if (LktrCond) p = ERR_PTR(-1); ++ file = (void*)p; ++ if (p && !IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ LKTRTrace("%s\n", p); ++ file = xino_create(sb, p, /*silent*/0, sb->s_root); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ } ++ __putname(page); ++ } else { ++ file = xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, ++ /*parent*/NULL); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ } ++ ++ out: ++ TraceErrPtr(file); ++ return file; ++} +diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile +new file mode 100644 +index 0000000..1bc7b06 +--- /dev/null ++++ b/fs/squashfs/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for the linux squashfs routines. ++# ++ ++obj-$(CONFIG_SQUASHFS) += squashfs.o ++squashfs-y += inode.o ++squashfs-y += squashfs2_0.o +diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c +new file mode 100644 +index 0000000..895b699 +--- /dev/null ++++ b/fs/squashfs/inode.c +@@ -0,0 +1,2329 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * inode.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "squashfs.h" ++ ++static void vfs_read_inode(struct inode *i); ++static struct dentry *squashfs_get_parent(struct dentry *child); ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); ++static int squashfs_statfs(struct dentry *, struct kstatfs *); ++static int squashfs_symlink_readpage(struct file *file, struct page *page); ++static long long read_blocklist(struct inode *inode, int index, ++ int readahead_blks, char *block_list, ++ unsigned short **block_p, unsigned int *bsize); ++static int squashfs_readpage(struct file *file, struct page *page); ++static int squashfs_readpage4K(struct file *file, struct page *page); ++static int squashfs_readdir(struct file *, void *, filldir_t); ++static struct dentry *squashfs_lookup(struct inode *, struct dentry *, ++ struct nameidata *); ++static int squashfs_remount(struct super_block *s, int *flags, char *data); ++static void squashfs_put_super(struct super_block *); ++static int squashfs_get_sb(struct file_system_type *,int, const char *, void *, ++ struct vfsmount *); ++static struct inode *squashfs_alloc_inode(struct super_block *sb); ++static void squashfs_destroy_inode(struct inode *inode); ++static int init_inodecache(void); ++static void destroy_inodecache(void); ++ ++static struct file_system_type squashfs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "squashfs", ++ .get_sb = squashfs_get_sb, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV ++}; ++ ++static const unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static struct super_operations squashfs_super_ops = { ++ .alloc_inode = squashfs_alloc_inode, ++ .destroy_inode = squashfs_destroy_inode, ++ .statfs = squashfs_statfs, ++ .put_super = squashfs_put_super, ++ .remount_fs = squashfs_remount ++}; ++ ++static struct super_operations squashfs_export_super_ops = { ++ .alloc_inode = squashfs_alloc_inode, ++ .destroy_inode = squashfs_destroy_inode, ++ .statfs = squashfs_statfs, ++ .put_super = squashfs_put_super, ++ .read_inode = vfs_read_inode ++}; ++ ++static struct export_operations squashfs_export_ops = { ++ .get_parent = squashfs_get_parent ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = { ++ .readpage = squashfs_symlink_readpage ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_aops = { ++ .readpage = squashfs_readpage ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_aops_4K = { ++ .readpage = squashfs_readpage4K ++}; ++ ++static const struct file_operations squashfs_dir_ops = { ++ .read = generic_read_dir, ++ .readdir = squashfs_readdir ++}; ++ ++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = { ++ .lookup = squashfs_lookup ++}; ++ ++ ++static struct buffer_head *get_block_length(struct super_block *s, ++ int *cur_index, int *offset, int *c_byte) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ unsigned short temp; ++ struct buffer_head *bh; ++ ++ if (!(bh = sb_bread(s, *cur_index))) ++ goto out; ++ ++ if (msblk->devblksize - *offset == 1) { ++ if (msblk->swap) ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ else ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ brelse(bh); ++ if (!(bh = sb_bread(s, ++(*cur_index)))) ++ goto out; ++ if (msblk->swap) ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ bh->b_data); ++ else ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ bh->b_data); ++ *c_byte = temp; ++ *offset = 1; ++ } else { ++ if (msblk->swap) { ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset + 1)); ++ } else { ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset + 1)); ++ } ++ *c_byte = temp; ++ *offset += 2; ++ } ++ ++ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) { ++ if (*offset == msblk->devblksize) { ++ brelse(bh); ++ if (!(bh = sb_bread(s, ++(*cur_index)))) ++ goto out; ++ *offset = 0; ++ } ++ if (*((unsigned char *) (bh->b_data + *offset)) != ++ SQUASHFS_MARKER_BYTE) { ++ ERROR("Metadata block marker corrupt @ %x\n", ++ *cur_index); ++ brelse(bh); ++ goto out; ++ } ++ (*offset)++; ++ } ++ return bh; ++ ++out: ++ return NULL; ++} ++ ++ ++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, ++ long long index, unsigned int length, ++ long long *next_index, int srclength) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> ++ msblk->devblksize_log2) + 2]; ++ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); ++ unsigned int cur_index = index >> msblk->devblksize_log2; ++ int bytes, avail_bytes, b = 0, k = 0; ++ unsigned int compressed; ++ unsigned int c_byte = length; ++ ++ if (c_byte) { ++ bytes = msblk->devblksize - offset; ++ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); ++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); ++ ++ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed ++ ? "" : "un", (unsigned int) c_byte, srclength); ++ ++ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used) ++ goto read_failure; ++ ++ if (!(bh[0] = sb_getblk(s, cur_index))) ++ goto block_release; ++ ++ for (b = 1; bytes < c_byte; b++) { ++ if (!(bh[b] = sb_getblk(s, ++cur_index))) ++ goto block_release; ++ bytes += msblk->devblksize; ++ } ++ ll_rw_block(READ, b, bh); ++ } else { ++ if (index < 0 || (index + 2) > sblk->bytes_used) ++ goto read_failure; ++ ++ if (!(bh[0] = get_block_length(s, &cur_index, &offset, ++ &c_byte))) ++ goto read_failure; ++ ++ bytes = msblk->devblksize - offset; ++ compressed = SQUASHFS_COMPRESSED(c_byte); ++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); ++ ++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed ++ ? "" : "un", (unsigned int) c_byte); ++ ++ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used) ++ goto read_failure; ++ ++ for (b = 1; bytes < c_byte; b++) { ++ if (!(bh[b] = sb_getblk(s, ++cur_index))) ++ goto block_release; ++ bytes += msblk->devblksize; ++ } ++ ll_rw_block(READ, b - 1, bh + 1); ++ } ++ ++ if (compressed) { ++ int zlib_err = 0; ++ ++ /* ++ * uncompress block ++ */ ++ ++ mutex_lock(&msblk->read_data_mutex); ++ ++ msblk->stream.next_out = buffer; ++ msblk->stream.avail_out = srclength; ++ ++ for (bytes = 0; k < b; k++) { ++ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? ++ msblk->devblksize - offset : ++ c_byte - bytes; ++ wait_on_buffer(bh[k]); ++ if (!buffer_uptodate(bh[k])) ++ goto release_mutex; ++ ++ msblk->stream.next_in = bh[k]->b_data + offset; ++ msblk->stream.avail_in = avail_bytes; ++ ++ if (k == 0) { ++ zlib_err = zlib_inflateInit(&msblk->stream); ++ if (zlib_err != Z_OK) { ++ ERROR("zlib_inflateInit returned unexpected result 0x%x, srclength %d\n", ++ zlib_err, srclength); ++ goto release_mutex; ++ } ++ ++ if (avail_bytes == 0) { ++ offset = 0; ++ brelse(bh[k]); ++ continue; ++ } ++ } ++ ++ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); ++ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) { ++ ERROR("zlib_inflate returned unexpected result 0x%x, srclength %d, avail_in %d, avail_out %d\n", ++ zlib_err, srclength, msblk->stream.avail_in, msblk->stream.avail_out); ++ goto release_mutex; ++ } ++ ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ ++ if (zlib_err != Z_STREAM_END) ++ goto release_mutex; ++ ++ zlib_err = zlib_inflateEnd(&msblk->stream); ++ if (zlib_err != Z_OK) { ++ ERROR("zlib_inflateEnd returned unexpected result 0x%x, srclength %d\n", ++ zlib_err, srclength); ++ goto release_mutex; ++ } ++ bytes = msblk->stream.total_out; ++ mutex_unlock(&msblk->read_data_mutex); ++ } else { ++ int i; ++ ++ for(i = 0; i < b; i++) { ++ wait_on_buffer(bh[i]); ++ if(!buffer_uptodate(bh[i])) ++ goto block_release; ++ } ++ ++ for (bytes = 0; k < b; k++) { ++ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? ++ msblk->devblksize - offset : ++ c_byte - bytes; ++ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes); ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ } ++ ++ if (next_index) ++ *next_index = index + c_byte + (length ? 0 : ++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ++ ? 3 : 2)); ++ return bytes; ++ ++release_mutex: ++ mutex_unlock(&msblk->read_data_mutex); ++ ++block_release: ++ for (; k < b; k++) ++ brelse(bh[k]); ++ ++read_failure: ++ ERROR("sb_bread failed reading block 0x%x\n", cur_index); ++ return 0; ++} ++ ++ ++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, ++ long long block, unsigned int offset, ++ int length, long long *next_block, ++ unsigned int *next_offset) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ int n, i, bytes, return_length = length; ++ long long next_index; ++ ++ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); ++ ++ while ( 1 ) { ++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ if (msblk->block_cache[i].block == block) ++ break; ++ ++ mutex_lock(&msblk->block_cache_mutex); ++ ++ if (i == SQUASHFS_CACHED_BLKS) { ++ /* read inode header block */ ++ for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS; ++ n ; n --, i = (i + 1) % ++ SQUASHFS_CACHED_BLKS) ++ if (msblk->block_cache[i].block != ++ SQUASHFS_USED_BLK) ++ break; ++ ++ if (n == 0) { ++ wait_queue_t wait; ++ ++ init_waitqueue_entry(&wait, current); ++ add_wait_queue(&msblk->waitq, &wait); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ mutex_unlock(&msblk->block_cache_mutex); ++ schedule(); ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&msblk->waitq, &wait); ++ continue; ++ } ++ msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS; ++ ++ if (msblk->block_cache[i].block == ++ SQUASHFS_INVALID_BLK) { ++ if (!(msblk->block_cache[i].data = ++ kmalloc(SQUASHFS_METADATA_SIZE, ++ GFP_KERNEL))) { ++ ERROR("Failed to allocate cache" ++ "block\n"); ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } ++ } ++ ++ msblk->block_cache[i].block = SQUASHFS_USED_BLK; ++ mutex_unlock(&msblk->block_cache_mutex); ++ ++ msblk->block_cache[i].length = squashfs_read_data(s, ++ msblk->block_cache[i].data, block, 0, &next_index, SQUASHFS_METADATA_SIZE); ++ if (msblk->block_cache[i].length == 0) { ++ ERROR("Unable to read cache block [%llx:%x]\n", ++ block, offset); ++ mutex_lock(&msblk->block_cache_mutex); ++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; ++ kfree(msblk->block_cache[i].data); ++ wake_up(&msblk->waitq); ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } ++ ++ mutex_lock(&msblk->block_cache_mutex); ++ wake_up(&msblk->waitq); ++ msblk->block_cache[i].block = block; ++ msblk->block_cache[i].next_index = next_index; ++ TRACE("Read cache block [%llx:%x]\n", block, offset); ++ } ++ ++ if (msblk->block_cache[i].block != block) { ++ mutex_unlock(&msblk->block_cache_mutex); ++ continue; ++ } ++ ++ bytes = msblk->block_cache[i].length - offset; ++ ++ if (bytes < 1) { ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } else if (bytes >= length) { ++ if (buffer) ++ memcpy(buffer, msblk->block_cache[i].data + ++ offset, length); ++ if (msblk->block_cache[i].length - offset == length) { ++ *next_block = msblk->block_cache[i].next_index; ++ *next_offset = 0; ++ } else { ++ *next_block = block; ++ *next_offset = offset + length; ++ } ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto finish; ++ } else { ++ if (buffer) { ++ memcpy(buffer, msblk->block_cache[i].data + ++ offset, bytes); ++ buffer += bytes; ++ } ++ block = msblk->block_cache[i].next_index; ++ mutex_unlock(&msblk->block_cache_mutex); ++ length -= bytes; ++ offset = 0; ++ } ++ } ++ ++finish: ++ return return_length; ++out: ++ return 0; ++} ++ ++ ++static int get_fragment_location(struct super_block *s, unsigned int fragment, ++ long long *fragment_start_block, ++ unsigned int *fragment_size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start_block = ++ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); ++ struct squashfs_fragment_entry fragment_entry; ++ ++ if (msblk->swap) { ++ struct squashfs_fragment_entry sfragment_entry; ++ ++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, ++ start_block, offset, ++ sizeof(sfragment_entry), &start_block, ++ &offset)) ++ goto out; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, ++ start_block, offset, ++ sizeof(fragment_entry), &start_block, ++ &offset)) ++ goto out; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++ ++out: ++ return 0; ++} ++ ++ ++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct ++ squashfs_fragment_cache *fragment) ++{ ++ mutex_lock(&msblk->fragment_mutex); ++ fragment->locked --; ++ wake_up(&msblk->fragment_wait_queue); ++ mutex_unlock(&msblk->fragment_mutex); ++} ++ ++ ++SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block ++ *s, long long start_block, ++ int length) ++{ ++ int i, n; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ while ( 1 ) { ++ mutex_lock(&msblk->fragment_mutex); ++ ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS && ++ msblk->fragment[i].block != start_block; i++); ++ ++ if (i == SQUASHFS_CACHED_FRAGMENTS) { ++ for (i = msblk->next_fragment, n = ++ SQUASHFS_CACHED_FRAGMENTS; n && ++ msblk->fragment[i].locked; n--, i = (i + 1) % ++ SQUASHFS_CACHED_FRAGMENTS); ++ ++ if (n == 0) { ++ wait_queue_t wait; ++ ++ init_waitqueue_entry(&wait, current); ++ add_wait_queue(&msblk->fragment_wait_queue, ++ &wait); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ mutex_unlock(&msblk->fragment_mutex); ++ schedule(); ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&msblk->fragment_wait_queue, ++ &wait); ++ continue; ++ } ++ msblk->next_fragment = (msblk->next_fragment + 1) % ++ SQUASHFS_CACHED_FRAGMENTS; ++ ++ if (msblk->fragment[i].data == NULL) ++ if (!(msblk->fragment[i].data = SQUASHFS_ALLOC ++ (SQUASHFS_FILE_MAX_SIZE))) { ++ ERROR("Failed to allocate fragment " ++ "cache block\n"); ++ mutex_unlock(&msblk->fragment_mutex); ++ goto out; ++ } ++ ++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ msblk->fragment[i].locked = 1; ++ mutex_unlock(&msblk->fragment_mutex); ++ ++ if (!(msblk->fragment[i].length = squashfs_read_data(s, ++ msblk->fragment[i].data, ++ start_block, length, NULL, sblk->block_size))) { ++ ERROR("Unable to read fragment cache block " ++ "[%llx]\n", start_block); ++ msblk->fragment[i].locked = 0; ++ smp_mb(); ++ goto out; ++ } ++ ++ mutex_lock(&msblk->fragment_mutex); ++ msblk->fragment[i].block = start_block; ++ TRACE("New fragment %d, start block %lld, locked %d\n", ++ i, msblk->fragment[i].block, ++ msblk->fragment[i].locked); ++ mutex_unlock(&msblk->fragment_mutex); ++ break; ++ } ++ ++ msblk->fragment[i].locked++; ++ mutex_unlock(&msblk->fragment_mutex); ++ TRACE("Got fragment %d, start block %lld, locked %d\n", i, ++ msblk->fragment[i].block, ++ msblk->fragment[i].locked); ++ break; ++ } ++ ++ return &msblk->fragment[i]; ++ ++out: ++ return NULL; ++} ++ ++ ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, ++ struct squashfs_base_inode_header *inodeb) ++{ ++ i->i_ino = inodeb->inode_number; ++ i->i_mtime.tv_sec = inodeb->mtime; ++ i->i_atime.tv_sec = inodeb->mtime; ++ i->i_ctime.tv_sec = inodeb->mtime; ++ i->i_uid = msblk->uid[inodeb->uid]; ++ i->i_mode = inodeb->mode; ++ i->i_size = 0; ++ if (inodeb->guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msblk->guid[inodeb->guid]; ++} ++ ++ ++static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)]; ++ int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1); ++ squashfs_inode_t inode; ++ ++ TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino); ++ ++ if (msblk->swap) { ++ squashfs_inode_t sinode; ++ ++ if (!squashfs_get_cached_block(s, (char *) &sinode, start, offset, ++ sizeof(sinode), &start, &offset)) ++ goto out; ++ SQUASHFS_SWAP_INODE_T((&inode), &sinode); ++ } else if (!squashfs_get_cached_block(s, (char *) &inode, start, offset, ++ sizeof(inode), &start, &offset)) ++ goto out; ++ ++ TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode); ++ ++ return inode; ++ ++out: ++ return SQUASHFS_INVALID_BLK; ++} ++ ++ ++static void vfs_read_inode(struct inode *i) ++{ ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, i->i_ino); ++ ++ TRACE("Entered vfs_read_inode\n"); ++ ++ if(inode != SQUASHFS_INVALID_BLK) ++ (msblk->read_inode)(i, inode); ++} ++ ++ ++static struct dentry *squashfs_get_parent(struct dentry *child) ++{ ++ struct inode *i = child->d_inode; ++ struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode); ++ struct dentry *rv; ++ ++ TRACE("Entered squashfs_get_parent\n"); ++ ++ if(parent == NULL) { ++ rv = ERR_PTR(-EACCES); ++ goto out; ++ } ++ ++ rv = d_alloc_anon(parent); ++ if(rv == NULL) ++ rv = ERR_PTR(-ENOMEM); ++ ++out: ++ return rv; ++} ++ ++ ++SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct inode *i = iget_locked(s, inode_number); ++ ++ TRACE("Entered squashfs_iget\n"); ++ ++ if(i && (i->i_state & I_NEW)) { ++ (msblk->read_inode)(i, inode); ++ unlock_new_inode(i); ++ } ++ ++ return i; ++} ++ ++ ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode) ++{ ++ struct super_block *s = i->i_sb; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long block = SQUASHFS_INODE_BLK(inode) + ++ sblk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ long long next_block; ++ unsigned int next_offset; ++ union squashfs_inode_header id, sid; ++ struct squashfs_base_inode_header *inodeb = &id.base, ++ *sinodeb = &sid.base; ++ ++ TRACE("Entered squashfs_read_inode\n"); ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, ++ offset, sizeof(*sinodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, ++ sizeof(*sinodeb)); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) inodeb, block, ++ offset, sizeof(*inodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ squashfs_new_inode(msblk, i, inodeb); ++ ++ switch(inodeb->inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ unsigned int frag_size; ++ long long frag_blk; ++ struct squashfs_reg_inode_header *inodep = &id.reg; ++ struct squashfs_reg_inode_header *sinodep = &sid.reg; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG && ++ !get_fragment_location(s, ++ inodep->fragment, &frag_blk, &frag_size)) ++ goto failed_read; ++ ++ i->i_nlink = 1; ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ if (sblk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else ++ i->i_data.a_ops = &squashfs_aops_4K; ++ ++ TRACE("File inode %x:%x, start_block %llx, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_LREG_TYPE: { ++ unsigned int frag_size; ++ long long frag_blk; ++ struct squashfs_lreg_inode_header *inodep = &id.lreg; ++ struct squashfs_lreg_inode_header *sinodep = &sid.lreg; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG && ++ !get_fragment_location(s, ++ inodep->fragment, &frag_blk, &frag_size)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ if (sblk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else ++ i->i_data.a_ops = &squashfs_aops_4K; ++ ++ TRACE("File inode %x:%x, start_block %llx, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ struct squashfs_dir_inode_header *inodep = &id.dir; ++ struct squashfs_dir_inode_header *sinodep = &sid.dir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0; ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; ++ ++ TRACE("Directory inode %x:%x, start_block %x, offset " ++ "%x\n", SQUASHFS_INODE_BLK(inode), ++ offset, inodep->start_block, ++ inodep->offset); ++ break; ++ } ++ case SQUASHFS_LDIR_TYPE: { ++ struct squashfs_ldir_inode_header *inodep = &id.ldir; ++ struct squashfs_ldir_inode_header *sinodep = &sid.ldir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = ++ next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = ++ inodep->i_count; ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; ++ ++ TRACE("Long directory inode %x:%x, start_block %x, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, inodep->offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ struct squashfs_symlink_inode_header *inodep = ++ &id.symlink; ++ struct squashfs_symlink_inode_header *sinodep = ++ &sid.symlink; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ SQUASHFS_I(i)->start_block = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ ++ TRACE("Symbolic link inode %x:%x, start_block %llx, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ struct squashfs_dev_inode_header *inodep = &id.dev; ++ struct squashfs_dev_inode_header *sinodep = &sid.dev; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_mode |= (inodeb->inode_type == ++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : ++ S_IFBLK; ++ init_special_inode(i, i->i_mode, ++ old_decode_dev(inodep->rdev)); ++ ++ TRACE("Device inode %x:%x, rdev %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ struct squashfs_ipc_inode_header *inodep = &id.ipc; ++ struct squashfs_ipc_inode_header *sinodep = &sid.ipc; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ++ ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", ++ inodeb->inode_type); ++ goto failed_read1; ++ } ++ ++ return 1; ++ ++failed_read: ++ ERROR("Unable to read inode [%llx:%x]\n", block, offset); ++ ++failed_read1: ++ make_bad_inode(i); ++ return 0; ++} ++ ++ ++static int read_inode_lookup_table(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes); ++ ++ TRACE("In read_inode_lookup_table, length %d\n", length); ++ ++ /* Allocate inode lookup table */ ++ if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) { ++ ERROR("Failed to allocate inode lookup table\n"); ++ return 0; ++ } ++ ++ if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table, ++ sblk->lookup_table_start, length | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ++ ERROR("unable to read inode lookup table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ long long block; ++ ++ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { ++ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), ++ &msblk->inode_lookup_table[i], 1); ++ msblk->inode_lookup_table[i] = block; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int read_fragment_index_table(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); ++ ++ if(length == 0) ++ return 1; ++ ++ /* Allocate fragment index table */ ++ if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) { ++ ERROR("Failed to allocate fragment index table\n"); ++ return 0; ++ } ++ ++ if (!squashfs_read_data(s, (char *) msblk->fragment_index, ++ sblk->fragment_table_start, length | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ++ ERROR("unable to read fragment index table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ long long fragment; ++ ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { ++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), ++ &msblk->fragment_index[i], 1); ++ msblk->fragment_index[i] = fragment; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ msblk->read_inode = squashfs_read_inode; ++ msblk->read_blocklist = read_blocklist; ++ msblk->read_fragment_index_table = read_fragment_index_table; ++ ++ if (sblk->s_major == 1) { ++ if (!squashfs_1_0_supported(msblk)) { ++ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " ++ "are unsupported\n"); ++ SERROR("Please recompile with " ++ "Squashfs 1.0 support enabled\n"); ++ return 0; ++ } ++ } else if (sblk->s_major == 2) { ++ if (!squashfs_2_0_supported(msblk)) { ++ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " ++ "are unsupported\n"); ++ SERROR("Please recompile with " ++ "Squashfs 2.0 support enabled\n"); ++ return 0; ++ } ++ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > ++ SQUASHFS_MINOR) { ++ SERROR("Major/Minor mismatch, trying to mount newer %d.%d " ++ "filesystem\n", sblk->s_major, sblk->s_minor); ++ SERROR("Please update your kernel\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static int squashfs_fill_super(struct super_block *s, void *data, int silent) ++{ ++ struct squashfs_sb_info *msblk; ++ struct squashfs_super_block *sblk; ++ int i; ++ char b[BDEVNAME_SIZE]; ++ struct inode *root; ++ ++ TRACE("Entered squashfs_read_superblock\n"); ++ ++ if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info), ++ GFP_KERNEL))) { ++ ERROR("Failed to allocate superblock\n"); ++ goto failure; ++ } ++ memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info)); ++ msblk = s->s_fs_info; ++ if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) { ++ ERROR("Failed to allocate zlib workspace\n"); ++ goto failure; ++ } ++ sblk = &msblk->sblk; ++ ++ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); ++ msblk->devblksize_log2 = ffz(~msblk->devblksize); ++ ++ mutex_init(&msblk->read_data_mutex); ++ mutex_init(&msblk->read_page_mutex); ++ mutex_init(&msblk->block_cache_mutex); ++ mutex_init(&msblk->fragment_mutex); ++ mutex_init(&msblk->meta_index_mutex); ++ ++ init_waitqueue_head(&msblk->waitq); ++ init_waitqueue_head(&msblk->fragment_wait_queue); ++ ++ sblk->bytes_used = sizeof(struct squashfs_super_block); ++ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, ++ sizeof(struct squashfs_super_block) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) { ++ SERROR("unable to read superblock\n"); ++ goto failed_mount; ++ } ++ ++ /* Check it is a SQUASHFS superblock */ ++ msblk->swap = 0; ++ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) { ++ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) { ++ struct squashfs_super_block ssblk; ++ ++ WARNING("Mounting a different endian SQUASHFS " ++ "filesystem on %s\n", bdevname(s->s_bdev, b)); ++ ++ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); ++ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); ++ msblk->swap = 1; ++ } else { ++ SERROR("Can't find a SQUASHFS superblock on %s\n", ++ bdevname(s->s_bdev, b)); ++ goto failed_mount; ++ } ++ } ++ ++ /* Check the MAJOR & MINOR versions */ ++ if(!supported_squashfs_filesystem(msblk, silent)) ++ goto failed_mount; ++ ++ /* Check the filesystem does not extend beyond the end of the ++ block device */ ++ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode)) ++ goto failed_mount; ++ ++ /* Check the root inode for sanity */ ++ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE) ++ goto failed_mount; ++ ++ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); ++ TRACE("Inodes are %scompressed\n", ++ SQUASHFS_UNCOMPRESSED_INODES ++ (sblk->flags) ? "un" : ""); ++ TRACE("Data is %scompressed\n", ++ SQUASHFS_UNCOMPRESSED_DATA(sblk->flags) ++ ? "un" : ""); ++ TRACE("Check data is %s present in the filesystem\n", ++ SQUASHFS_CHECK_DATA(sblk->flags) ? ++ "" : "not"); ++ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); ++ TRACE("Block size %d\n", sblk->block_size); ++ TRACE("Number of inodes %d\n", sblk->inodes); ++ if (sblk->s_major > 1) ++ TRACE("Number of fragments %d\n", sblk->fragments); ++ TRACE("Number of uids %d\n", sblk->no_uids); ++ TRACE("Number of gids %d\n", sblk->no_guids); ++ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); ++ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); ++ if (sblk->s_major > 1) ++ TRACE("sblk->fragment_table_start %llx\n", ++ sblk->fragment_table_start); ++ TRACE("sblk->uid_start %llx\n", sblk->uid_start); ++ ++ s->s_flags |= MS_RDONLY; ++ s->s_op = &squashfs_super_ops; ++ ++ /* Init inode_table block pointer array */ ++ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * ++ SQUASHFS_CACHED_BLKS, GFP_KERNEL))) { ++ ERROR("Failed to allocate block cache\n"); ++ goto failed_mount; ++ } ++ ++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; ++ ++ msblk->next_cache = 0; ++ ++ /* Allocate read_page block */ ++ if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) { ++ ERROR("Failed to allocate read_page block\n"); ++ goto failed_mount; ++ } ++ ++ /* Allocate uid and gid tables */ ++ if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ goto failed_mount; ++ } ++ msblk->guid = msblk->uid + sblk->no_uids; ++ ++ if (msblk->swap) { ++ unsigned int suid[sblk->no_uids + sblk->no_guids]; ++ ++ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, ++ ((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int)) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ++ ERROR("unable to read uid/gid table\n"); ++ goto failed_mount; ++ } ++ ++ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids + ++ sblk->no_guids), (sizeof(unsigned int) * 8)); ++ } else ++ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, ++ ((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int)) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ++ ERROR("unable to read uid/gid table\n"); ++ goto failed_mount; ++ } ++ ++ ++ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) ++ goto allocate_root; ++ ++ if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) * ++ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { ++ ERROR("Failed to allocate fragment block cache\n"); ++ goto failed_mount; ++ } ++ ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { ++ msblk->fragment[i].locked = 0; ++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ msblk->fragment[i].data = NULL; ++ } ++ ++ msblk->next_fragment = 0; ++ ++ /* Allocate and read fragment index table */ ++ if (msblk->read_fragment_index_table(s) == 0) ++ goto failed_mount; ++ ++ if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK) ++ goto allocate_root; ++ ++ /* Allocate and read inode lookup table */ ++ if (read_inode_lookup_table(s) == 0) ++ goto failed_mount; ++ ++ s->s_op = &squashfs_export_super_ops; ++ s->s_export_op = &squashfs_export_ops; ++ ++allocate_root: ++ root = new_inode(s); ++ if ((msblk->read_inode)(root, sblk->root_inode) == 0) ++ goto failed_mount; ++ insert_inode_hash(root); ++ ++ if ((s->s_root = d_alloc_root(root)) == NULL) { ++ ERROR("Root inode create failed\n"); ++ iput(root); ++ goto failed_mount; ++ } ++ ++ TRACE("Leaving squashfs_read_super\n"); ++ return 0; ++ ++failed_mount: ++ kfree(msblk->inode_lookup_table); ++ kfree(msblk->fragment_index); ++ kfree(msblk->fragment); ++ kfree(msblk->uid); ++ kfree(msblk->read_page); ++ kfree(msblk->block_cache); ++ kfree(msblk->fragment_index_2); ++ vfree(msblk->stream.workspace); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ return -EINVAL; ++ ++failure: ++ return -ENOMEM; ++} ++ ++ ++static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ TRACE("Entered squashfs_statfs\n"); ++ ++ buf->f_type = SQUASHFS_MAGIC; ++ buf->f_bsize = sblk->block_size; ++ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1; ++ buf->f_bfree = buf->f_bavail = 0; ++ buf->f_files = sblk->inodes; ++ buf->f_ffree = 0; ++ buf->f_namelen = SQUASHFS_NAME_LEN; ++ ++ return 0; ++} ++ ++ ++static int squashfs_symlink_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes; ++ long long block = SQUASHFS_I(inode)->start_block; ++ int offset = SQUASHFS_I(inode)->offset; ++ void *pageaddr = kmap(page); ++ ++ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " ++ "%llx, offset %x\n", page->index, ++ SQUASHFS_I(inode)->start_block, ++ SQUASHFS_I(inode)->offset); ++ ++ for (length = 0; length < index; length += bytes) { ++ if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, ++ block, offset, PAGE_CACHE_SIZE, &block, ++ &offset))) { ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, ++ offset); ++ goto skip_read; ++ } ++ } ++ ++ if (length != index) { ++ ERROR("(squashfs_symlink_readpage) length != index\n"); ++ bytes = 0; ++ goto skip_read; ++ } ++ ++ bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : ++ i_size_read(inode) - length; ++ ++ if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, ++ offset, bytes, &block, &offset))) ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ return 0; ++} ++ ++ ++struct meta_index *locate_meta_index(struct inode *inode, int index, int offset) ++{ ++ struct meta_index *meta = NULL; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ int i; ++ ++ mutex_lock(&msblk->meta_index_mutex); ++ ++ TRACE("locate_meta_index: index %d, offset %d\n", index, offset); ++ ++ if(msblk->meta_index == NULL) ++ goto not_allocated; ++ ++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) ++ if (msblk->meta_index[i].inode_number == inode->i_ino && ++ msblk->meta_index[i].offset >= offset && ++ msblk->meta_index[i].offset <= index && ++ msblk->meta_index[i].locked == 0) { ++ TRACE("locate_meta_index: entry %d, offset %d\n", i, ++ msblk->meta_index[i].offset); ++ meta = &msblk->meta_index[i]; ++ offset = meta->offset; ++ } ++ ++ if (meta) ++ meta->locked = 1; ++ ++not_allocated: ++ mutex_unlock(&msblk->meta_index_mutex); ++ ++ return meta; ++} ++ ++ ++struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip) ++{ ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct meta_index *meta = NULL; ++ int i; ++ ++ mutex_lock(&msblk->meta_index_mutex); ++ ++ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); ++ ++ if(msblk->meta_index == NULL) { ++ if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) * ++ SQUASHFS_META_NUMBER, GFP_KERNEL))) { ++ ERROR("Failed to allocate meta_index\n"); ++ goto failed; ++ } ++ for(i = 0; i < SQUASHFS_META_NUMBER; i++) { ++ msblk->meta_index[i].inode_number = 0; ++ msblk->meta_index[i].locked = 0; ++ } ++ msblk->next_meta_index = 0; ++ } ++ ++ for(i = SQUASHFS_META_NUMBER; i && ++ msblk->meta_index[msblk->next_meta_index].locked; i --) ++ msblk->next_meta_index = (msblk->next_meta_index + 1) % ++ SQUASHFS_META_NUMBER; ++ ++ if(i == 0) { ++ TRACE("empty_meta_index: failed!\n"); ++ goto failed; ++ } ++ ++ TRACE("empty_meta_index: returned meta entry %d, %p\n", ++ msblk->next_meta_index, ++ &msblk->meta_index[msblk->next_meta_index]); ++ ++ meta = &msblk->meta_index[msblk->next_meta_index]; ++ msblk->next_meta_index = (msblk->next_meta_index + 1) % ++ SQUASHFS_META_NUMBER; ++ ++ meta->inode_number = inode->i_ino; ++ meta->offset = offset; ++ meta->skip = skip; ++ meta->entries = 0; ++ meta->locked = 1; ++ ++failed: ++ mutex_unlock(&msblk->meta_index_mutex); ++ return meta; ++} ++ ++ ++void release_meta_index(struct inode *inode, struct meta_index *meta) ++{ ++ meta->locked = 0; ++ smp_mb(); ++} ++ ++ ++static int read_block_index(struct super_block *s, int blocks, char *block_list, ++ long long *start_block, int *offset) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ unsigned int *block_listp; ++ int block = 0; ++ ++ if (msblk->swap) { ++ char sblock_list[blocks << 2]; ++ ++ if (!squashfs_get_cached_block(s, sblock_list, *start_block, ++ *offset, blocks << 2, start_block, offset)) { ++ ERROR("Unable to read block list [%llx:%x]\n", ++ *start_block, *offset); ++ goto failure; ++ } ++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ++ ((unsigned int *)sblock_list), blocks); ++ } else ++ if (!squashfs_get_cached_block(s, block_list, *start_block, ++ *offset, blocks << 2, start_block, offset)) { ++ ERROR("Unable to read block list [%llx:%x]\n", ++ *start_block, *offset); ++ goto failure; ++ } ++ ++ for (block_listp = (unsigned int *) block_list; blocks; ++ block_listp++, blocks --) ++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); ++ ++ return block; ++ ++failure: ++ return -1; ++} ++ ++ ++#define SIZE 256 ++ ++static inline int calculate_skip(int blocks) { ++ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES); ++ return skip >= 7 ? 7 : skip + 1; ++} ++ ++ ++static int get_meta_index(struct inode *inode, int index, ++ long long *index_block, int *index_offset, ++ long long *data_block, char *block_list) ++{ ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log); ++ int offset = 0; ++ struct meta_index *meta; ++ struct meta_entry *meta_entry; ++ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start; ++ int cur_offset = SQUASHFS_I(inode)->offset; ++ long long cur_data_block = SQUASHFS_I(inode)->start_block; ++ int i; ++ ++ index /= SQUASHFS_META_INDEXES * skip; ++ ++ while ( offset < index ) { ++ meta = locate_meta_index(inode, index, offset + 1); ++ ++ if (meta == NULL) { ++ if ((meta = empty_meta_index(inode, offset + 1, ++ skip)) == NULL) ++ goto all_done; ++ } else { ++ if(meta->entries == 0) ++ goto failed; ++ offset = index < meta->offset + meta->entries ? index : ++ meta->offset + meta->entries - 1; ++ meta_entry = &meta->meta_entry[offset - meta->offset]; ++ cur_index_block = meta_entry->index_block + sblk->inode_table_start; ++ cur_offset = meta_entry->offset; ++ cur_data_block = meta_entry->data_block; ++ TRACE("get_meta_index: offset %d, meta->offset %d, " ++ "meta->entries %d\n", offset, meta->offset, ++ meta->entries); ++ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" ++ " data_block 0x%llx\n", cur_index_block, ++ cur_offset, cur_data_block); ++ } ++ ++ for (i = meta->offset + meta->entries; i <= index && ++ i < meta->offset + SQUASHFS_META_ENTRIES; i++) { ++ int blocks = skip * SQUASHFS_META_INDEXES; ++ ++ while (blocks) { ++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : ++ blocks; ++ int res = read_block_index(inode->i_sb, block, ++ block_list, &cur_index_block, ++ &cur_offset); ++ ++ if (res == -1) ++ goto failed; ++ ++ cur_data_block += res; ++ blocks -= block; ++ } ++ ++ meta_entry = &meta->meta_entry[i - meta->offset]; ++ meta_entry->index_block = cur_index_block - sblk->inode_table_start; ++ meta_entry->offset = cur_offset; ++ meta_entry->data_block = cur_data_block; ++ meta->entries ++; ++ offset ++; ++ } ++ ++ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", ++ meta->offset, meta->entries); ++ ++ release_meta_index(inode, meta); ++ } ++ ++all_done: ++ *index_block = cur_index_block; ++ *index_offset = cur_offset; ++ *data_block = cur_data_block; ++ ++ return offset * SQUASHFS_META_INDEXES * skip; ++ ++failed: ++ release_meta_index(inode, meta); ++ return -1; ++} ++ ++ ++static long long read_blocklist(struct inode *inode, int index, ++ int readahead_blks, char *block_list, ++ unsigned short **block_p, unsigned int *bsize) ++{ ++ long long block_ptr; ++ int offset; ++ long long block; ++ int res = get_meta_index(inode, index, &block_ptr, &offset, &block, ++ block_list); ++ ++ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" ++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, ++ block); ++ ++ if(res == -1) ++ goto failure; ++ ++ index -= res; ++ ++ while ( index ) { ++ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; ++ int res = read_block_index(inode->i_sb, blocks, block_list, ++ &block_ptr, &offset); ++ if (res == -1) ++ goto failure; ++ block += res; ++ index -= blocks; ++ } ++ ++ if (read_block_index(inode->i_sb, 1, block_list, ++ &block_ptr, &offset) == -1) ++ goto failure; ++ *bsize = *((unsigned int *) block_list); ++ ++ return block; ++ ++failure: ++ return 0; ++} ++ ++ ++static int squashfs_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned char *block_list; ++ long long block; ++ unsigned int bsize, i = 0, bytes = 0, byte_offset = 0; ++ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); ++ void *pageaddr; ++ struct squashfs_fragment_cache *fragment = NULL; ++ char *data_ptr = msblk->read_page; ++ ++ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; ++ int start_index = page->index & ~mask; ++ int end_index = start_index | mask; ++ ++ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", ++ page->index, ++ SQUASHFS_I(inode)->start_block); ++ ++ if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) { ++ ERROR("Failed to allocate block_list\n"); ++ goto skip_read; ++ } ++ ++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> ++ PAGE_CACHE_SHIFT)) ++ goto skip_read; ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || index < (i_size_read(inode) >> ++ sblk->block_log)) { ++ if ((block = (msblk->read_blocklist)(inode, index, 1, ++ block_list, NULL, &bsize)) == 0) ++ goto skip_read; ++ ++ mutex_lock(&msblk->read_page_mutex); ++ ++ if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page, ++ block, bsize, NULL, sblk->block_size))) { ++ ERROR("Unable to read page, block %llx, size %x\n", block, ++ bsize); ++ mutex_unlock(&msblk->read_page_mutex); ++ goto skip_read; ++ } ++ } else { ++ if ((fragment = get_cached_fragment(inode->i_sb, ++ SQUASHFS_I(inode)-> ++ u.s1.fragment_start_block, ++ SQUASHFS_I(inode)->u.s1.fragment_size)) ++ == NULL) { ++ ERROR("Unable to read page, block %llx, size %x\n", ++ SQUASHFS_I(inode)-> ++ u.s1.fragment_start_block, ++ (int) SQUASHFS_I(inode)-> ++ u.s1.fragment_size); ++ goto skip_read; ++ } ++ bytes = SQUASHFS_I(inode)->u.s1.fragment_offset + ++ (i_size_read(inode) & (sblk->block_size ++ - 1)); ++ byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset; ++ data_ptr = fragment->data; ++ } ++ ++ for (i = start_index; i <= end_index && byte_offset < bytes; ++ i++, byte_offset += PAGE_CACHE_SIZE) { ++ struct page *push_page; ++ int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ? ++ PAGE_CACHE_SIZE : bytes - byte_offset; ++ ++ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", ++ bytes, i, byte_offset, avail); ++ ++ push_page = (i == page->index) ? page : ++ grab_cache_page_nowait(page->mapping, i); ++ ++ if (!push_page) ++ continue; ++ ++ if (PageUptodate(push_page)) ++ goto skip_page; ++ ++ pageaddr = kmap_atomic(push_page, KM_USER0); ++ memcpy(pageaddr, data_ptr + byte_offset, avail); ++ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(push_page); ++ SetPageUptodate(push_page); ++skip_page: ++ unlock_page(push_page); ++ if(i != page->index) ++ page_cache_release(push_page); ++ } ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || index < (i_size_read(inode) >> ++ sblk->block_log)) ++ mutex_unlock(&msblk->read_page_mutex); ++ else ++ release_cached_fragment(msblk, fragment); ++ ++ kfree(block_list); ++ return 0; ++ ++skip_read: ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ kfree(block_list); ++ return 0; ++} ++ ++ ++static int squashfs_readpage4K(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned char *block_list; ++ long long block; ++ unsigned int bsize, bytes = 0; ++ void *pageaddr; ++ ++ TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n", ++ page->index, ++ SQUASHFS_I(inode)->start_block); ++ ++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> ++ PAGE_CACHE_SHIFT)) { ++ block_list = NULL; ++ goto skip_read; ++ } ++ ++ if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) { ++ ERROR("Failed to allocate block_list\n"); ++ goto skip_read; ++ } ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || page->index < (i_size_read(inode) >> ++ sblk->block_log)) { ++ block = (msblk->read_blocklist)(inode, page->index, 1, ++ block_list, NULL, &bsize); ++ if(block == 0) ++ goto skip_read; ++ ++ mutex_lock(&msblk->read_page_mutex); ++ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, ++ bsize, NULL, sblk->block_size); ++ if (bytes) { ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memcpy(pageaddr, msblk->read_page, bytes); ++ kunmap_atomic(pageaddr, KM_USER0); ++ } else ++ ERROR("Unable to read page, block %llx, size %x\n", ++ block, bsize); ++ mutex_unlock(&msblk->read_page_mutex); ++ } else { ++ struct squashfs_fragment_cache *fragment = ++ get_cached_fragment(inode->i_sb, ++ SQUASHFS_I(inode)-> ++ u.s1.fragment_start_block, ++ SQUASHFS_I(inode)-> u.s1.fragment_size); ++ if (fragment) { ++ bytes = i_size_read(inode) & (sblk->block_size - 1); ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)-> ++ u.s1.fragment_offset, bytes); ++ kunmap_atomic(pageaddr, KM_USER0); ++ release_cached_fragment(msblk, fragment); ++ } else ++ ERROR("Unable to read page, block %llx, size %x\n", ++ SQUASHFS_I(inode)-> ++ u.s1.fragment_start_block, (int) ++ SQUASHFS_I(inode)-> u.s1.fragment_size); ++ } ++ ++skip_read: ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ kfree(block_list); ++ return 0; ++} ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ long long f_pos) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index index; ++ ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", ++ i_count, (unsigned int) f_pos); ++ ++ f_pos =- 3; ++ if (f_pos == 0) ++ goto finish; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) &index, ++ index_start, index_offset, ++ sizeof(index), &index_start, ++ &index_offset); ++ ++ if (index.index > f_pos) ++ break; ++ ++ squashfs_get_cached_block(s, NULL, index_start, index_offset, ++ index.size + 1, &index_start, ++ &index_offset); ++ ++ length = index.index; ++ *next_block = index.start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ ++finish: ++ return length + 3; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ const char *name, int size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index *index; ++ char *str; ++ ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); ++ ++ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_index\n"); ++ goto failure; ++ } ++ ++ index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1); ++ strncpy(str, name, size); ++ str[size] = '\0'; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX(index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) index, ++ index_start, index_offset, ++ sizeof(struct squashfs_dir_index), ++ &index_start, &index_offset); ++ ++ squashfs_get_cached_block(s, index->name, index_start, ++ index_offset, index->size + 1, ++ &index_start, &index_offset); ++ ++ index->name[index->size + 1] = '\0'; ++ ++ if (strcmp(index->name, str) > 0) ++ break; ++ ++ length = index->index; ++ *next_block = index->start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ kfree(str); ++failure: ++ return length + 3; ++} ++ ++ ++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header dirh; ++ struct squashfs_dir_entry *dire; ++ ++ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto finish; ++ } ++ ++ while(file->f_pos < 3) { ++ char *name; ++ int size, i_ino; ++ ++ if(file->f_pos == 0) { ++ name = "."; ++ size = 1; ++ i_ino = i->i_ino; ++ } else { ++ name = ".."; ++ size = 2; ++ i_ino = SQUASHFS_I(i)->u.s2.parent_inode; ++ } ++ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", ++ (unsigned int) dirent, name, size, (int) ++ file->f_pos, i_ino, ++ squashfs_filetype_table[1]); ++ ++ if (filldir(dirent, name, size, ++ file->f_pos, i_ino, ++ squashfs_filetype_table[1]) < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos += size; ++ } ++ ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, ++ file->f_pos); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header sdirh; ++ ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block, next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block, next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, ++ dire->size + 1, &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", ++ (unsigned int) dirent, dire->name, ++ dire->size + 1, (int) file->f_pos, ++ dirh.start_block, dire->offset, ++ dirh.inode_number + dire->inode_number, ++ squashfs_filetype_table[dire->type]); ++ ++ if (filldir(dirent, dire->name, dire->size + 1, ++ file->f_pos, ++ dirh.inode_number + dire->inode_number, ++ squashfs_filetype_table[dire->type]) ++ < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos = length; ++ } ++ } ++ ++finish: ++ kfree(dire); ++ return 0; ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ kfree(dire); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ const unsigned char *name = dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header dirh; ++ struct squashfs_dir_entry *dire; ++ ++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto exit_lookup; ++ } ++ ++ if (len > SQUASHFS_NAME_LEN) ++ goto exit_lookup; ++ ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, ++ len); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header sdirh; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block,next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block,next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, dire->size + 1, ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (name[0] < dire->name[0]) ++ goto exit_lookup; ++ ++ if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) { ++ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, ++ dire->offset); ++ ++ TRACE("calling squashfs_iget for directory " ++ "entry %s, inode %x:%x, %d\n", name, ++ dirh.start_block, dire->offset, ++ dirh.inode_number + dire->inode_number); ++ ++ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); ++ ++ goto exit_lookup; ++ } ++ } ++ } ++ ++exit_lookup: ++ kfree(dire); ++ if (inode) ++ return d_splice_alias(inode, dentry); ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ goto exit_lookup; ++} ++ ++ ++static int squashfs_remount(struct super_block *s, int *flags, char *data) ++{ ++ *flags |= MS_RDONLY; ++ return 0; ++} ++ ++ ++static void squashfs_put_super(struct super_block *s) ++{ ++ int i; ++ ++ if (s->s_fs_info) { ++ struct squashfs_sb_info *sbi = s->s_fs_info; ++ if (sbi->block_cache) ++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ if (sbi->block_cache[i].block != ++ SQUASHFS_INVALID_BLK) ++ kfree(sbi->block_cache[i].data); ++ if (sbi->fragment) ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) ++ SQUASHFS_FREE(sbi->fragment[i].data); ++ kfree(sbi->fragment); ++ kfree(sbi->block_cache); ++ kfree(sbi->read_page); ++ kfree(sbi->uid); ++ kfree(sbi->fragment_index); ++ kfree(sbi->fragment_index_2); ++ kfree(sbi->meta_index); ++ vfree(sbi->stream.workspace); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ } ++} ++ ++ ++static int squashfs_get_sb(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data, ++ struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, ++ mnt); ++} ++ ++ ++static int __init init_squashfs_fs(void) ++{ ++ int err = init_inodecache(); ++ if (err) ++ goto out; ++ ++ printk(KERN_INFO "squashfs: version 3.2-r2 (2007/01/15) " ++ "Phillip Lougher\n"); ++ ++ if ((err = register_filesystem(&squashfs_fs_type))) ++ destroy_inodecache(); ++ ++out: ++ return err; ++} ++ ++ ++static void __exit exit_squashfs_fs(void) ++{ ++ unregister_filesystem(&squashfs_fs_type); ++ destroy_inodecache(); ++} ++ ++ ++static struct kmem_cache * squashfs_inode_cachep; ++ ++ ++static struct inode *squashfs_alloc_inode(struct super_block *sb) ++{ ++ struct squashfs_inode_info *ei; ++ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); ++ if (!ei) ++ return NULL; ++ return &ei->vfs_inode; ++} ++ ++ ++static void squashfs_destroy_inode(struct inode *inode) ++{ ++ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); ++} ++ ++ ++static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) ++{ ++ struct squashfs_inode_info *ei = foo; ++ ++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == ++ SLAB_CTOR_CONSTRUCTOR) ++ inode_init_once(&ei->vfs_inode); ++} ++ ++ ++static int __init init_inodecache(void) ++{ ++ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", ++ sizeof(struct squashfs_inode_info), ++ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, ++ init_once, NULL); ++ if (squashfs_inode_cachep == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++ ++static void destroy_inodecache(void) ++{ ++ kmem_cache_destroy(squashfs_inode_cachep); ++} ++ ++ ++module_init(init_squashfs_fs); ++module_exit(exit_squashfs_fs); ++MODULE_DESCRIPTION("squashfs 3.2-r2, a compressed read-only filesystem"); ++MODULE_AUTHOR("Phillip Lougher "); ++MODULE_LICENSE("GPL"); +diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h +new file mode 100644 +index 0000000..6f863f0 +--- /dev/null ++++ b/fs/squashfs/squashfs.h +@@ -0,0 +1,87 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs.h ++ */ ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++#endif ++ ++#ifdef SQUASHFS_TRACE ++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) ++#else ++#define TRACE(s, args...) {} ++#endif ++ ++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) ++ ++#define SERROR(s, args...) do { \ ++ if (!silent) \ ++ printk(KERN_ERR "SQUASHFS error: "s, ## args);\ ++ } while(0) ++ ++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) ++ ++static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) ++{ ++ return list_entry(inode, struct squashfs_inode_info, vfs_inode); ++} ++ ++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY) ++#define SQSH_EXTERN ++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, ++ long long index, unsigned int length, ++ long long *next_index, int srclength); ++extern int squashfs_get_cached_block(struct super_block *s, char *buffer, ++ long long block, unsigned int offset, ++ int length, long long *next_block, ++ unsigned int *next_offset); ++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct ++ squashfs_fragment_cache *fragment); ++extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block ++ *s, long long start_block, ++ int length); ++extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); ++extern const struct address_space_operations squashfs_symlink_aops; ++extern const struct address_space_operations squashfs_aops; ++extern const struct address_space_operations squashfs_aops_4K; ++extern struct inode_operations squashfs_dir_inode_ops; ++#else ++#define SQSH_EXTERN static ++#endif ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk); ++#else ++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk) ++{ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk); ++#else ++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk) ++{ ++ return 0; ++} ++#endif +diff --git a/fs/squashfs/squashfs2_0.c b/fs/squashfs/squashfs2_0.c +new file mode 100644 +index 0000000..d8d9d55 +--- /dev/null ++++ b/fs/squashfs/squashfs2_0.c +@@ -0,0 +1,742 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs2_0.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "squashfs.h" ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir); ++static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *, ++ struct nameidata *); ++ ++static struct file_operations squashfs_dir_ops_2 = { ++ .read = generic_read_dir, ++ .readdir = squashfs_readdir_2 ++}; ++ ++static struct inode_operations squashfs_dir_inode_ops_2 = { ++ .lookup = squashfs_lookup_2 ++}; ++ ++static unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static int read_fragment_index_table_2(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2 ++ (sblk->fragments), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ return 0; ++ } ++ ++ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && ++ !squashfs_read_data(s, (char *) ++ msblk->fragment_index_2, ++ sblk->fragment_table_start, ++ SQUASHFS_FRAGMENT_INDEX_BYTES_2 ++ (sblk->fragments) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { ++ ERROR("unable to read fragment index table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ unsigned int fragment; ++ ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments); ++ i++) { ++ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment), ++ &msblk->fragment_index_2[i], 1); ++ msblk->fragment_index_2[i] = fragment; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int get_fragment_location_2(struct super_block *s, unsigned int fragment, ++ long long *fragment_start_block, ++ unsigned int *fragment_size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start_block = ++ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment); ++ struct squashfs_fragment_entry_2 fragment_entry; ++ ++ if (msblk->swap) { ++ struct squashfs_fragment_entry_2 sfragment_entry; ++ ++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, ++ start_block, offset, ++ sizeof(sfragment_entry), &start_block, ++ &offset)) ++ goto out; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, ++ start_block, offset, ++ sizeof(fragment_entry), &start_block, ++ &offset)) ++ goto out; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++ ++out: ++ return 0; ++} ++ ++ ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, ++ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ i->i_ino = ino; ++ i->i_mtime.tv_sec = sblk->mkfs_time; ++ i->i_atime.tv_sec = sblk->mkfs_time; ++ i->i_ctime.tv_sec = sblk->mkfs_time; ++ i->i_uid = msblk->uid[inodeb->uid]; ++ i->i_mode = inodeb->mode; ++ i->i_nlink = 1; ++ i->i_size = 0; ++ if (inodeb->guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msblk->guid[inodeb->guid]; ++} ++ ++ ++static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) ++{ ++ struct super_block *s = i->i_sb; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int block = SQUASHFS_INODE_BLK(inode) + ++ sblk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ unsigned int ino = i->i_ino; ++ long long next_block; ++ unsigned int next_offset; ++ union squashfs_inode_header_2 id, sid; ++ struct squashfs_base_inode_header_2 *inodeb = &id.base, ++ *sinodeb = &sid.base; ++ ++ TRACE("Entered squashfs_iget\n"); ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, ++ offset, sizeof(*sinodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, ++ sizeof(*sinodeb)); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) inodeb, block, ++ offset, sizeof(*inodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ squashfs_new_inode(msblk, i, inodeb, ino); ++ ++ switch(inodeb->inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ struct squashfs_reg_inode_header_2 *inodep = &id.reg; ++ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; ++ long long frag_blk; ++ unsigned int frag_size = 0; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG && ++ !get_fragment_location_2(s, ++ inodep->fragment, &frag_blk, &frag_size)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ if (sblk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else ++ i->i_data.a_ops = &squashfs_aops_4K; ++ ++ TRACE("File inode %x:%x, start_block %x, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ struct squashfs_dir_inode_header_2 *inodep = &id.dir; ++ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops_2; ++ i->i_fop = &squashfs_dir_ops_2; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0; ++ SQUASHFS_I(i)->u.s2.parent_inode = 0; ++ ++ TRACE("Directory inode %x:%x, start_block %x, offset " ++ "%x\n", SQUASHFS_INODE_BLK(inode), ++ offset, inodep->start_block, ++ inodep->offset); ++ break; ++ } ++ case SQUASHFS_LDIR_TYPE: { ++ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; ++ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops_2; ++ i->i_fop = &squashfs_dir_ops_2; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = ++ next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = ++ inodep->i_count; ++ SQUASHFS_I(i)->u.s2.parent_inode = 0; ++ ++ TRACE("Long directory inode %x:%x, start_block %x, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, inodep->offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ struct squashfs_symlink_inode_header_2 *inodep = ++ &id.symlink; ++ struct squashfs_symlink_inode_header_2 *sinodep = ++ &sid.symlink; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ SQUASHFS_I(i)->start_block = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ ++ TRACE("Symbolic link inode %x:%x, start_block %llx, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ struct squashfs_dev_inode_header_2 *inodep = &id.dev; ++ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_mode |= (inodeb->inode_type == ++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : ++ S_IFBLK; ++ init_special_inode(i, i->i_mode, ++ old_decode_dev(inodep->rdev)); ++ ++ TRACE("Device inode %x:%x, rdev %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ++ ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", ++ inodeb->inode_type); ++ goto failed_read1; ++ } ++ ++ return 1; ++ ++failed_read: ++ ERROR("Unable to read inode [%x:%x]\n", block, offset); ++ ++failed_read1: ++ return 0; ++} ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ long long f_pos) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index_2 index; ++ ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", ++ i_count, (unsigned int) f_pos); ++ ++ if (f_pos == 0) ++ goto finish; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index_2 sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) &index, ++ index_start, index_offset, ++ sizeof(index), &index_start, ++ &index_offset); ++ ++ if (index.index > f_pos) ++ break; ++ ++ squashfs_get_cached_block(s, NULL, index_start, index_offset, ++ index.size + 1, &index_start, ++ &index_offset); ++ ++ length = index.index; ++ *next_block = index.start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ ++finish: ++ return length; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ const char *name, int size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index_2 *index; ++ char *str; ++ ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); ++ ++ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_index\n"); ++ goto failure; ++ } ++ ++ index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1); ++ strncpy(str, name, size); ++ str[size] = '\0'; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index_2 sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) index, ++ index_start, index_offset, ++ sizeof(struct squashfs_dir_index_2), ++ &index_start, &index_offset); ++ ++ squashfs_get_cached_block(s, index->name, index_start, ++ index_offset, index->size + 1, ++ &index_start, &index_offset); ++ ++ index->name[index->size + 1] = '\0'; ++ ++ if (strcmp(index->name, str) > 0) ++ break; ++ ++ length = index->index; ++ *next_block = index->start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ kfree(str); ++failure: ++ return length; ++} ++ ++ ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header_2 dirh; ++ struct squashfs_dir_entry_2 *dire; ++ ++ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto finish; ++ } ++ ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, ++ file->f_pos); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header_2 sdirh; ++ ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry_2 sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block, next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block, next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, ++ dire->size + 1, &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", ++ (unsigned int) dirent, dire->name, ++ dire->size + 1, (int) file->f_pos, ++ dirh.start_block, dire->offset, ++ squashfs_filetype_table[dire->type]); ++ ++ if (filldir(dirent, dire->name, dire->size + 1, ++ file->f_pos, SQUASHFS_MK_VFS_INODE( ++ dirh.start_block, dire->offset), ++ squashfs_filetype_table[dire->type]) ++ < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos = length; ++ } ++ } ++ ++finish: ++ kfree(dire); ++ return 0; ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ kfree(dire); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ const unsigned char *name = dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header_2 dirh; ++ struct squashfs_dir_entry_2 *dire; ++ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; ++ ++ TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto exit_loop; ++ } ++ ++ if (len > SQUASHFS_NAME_LEN) ++ goto exit_loop; ++ ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, ++ len); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header_2 sdirh; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry_2 sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block,next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block,next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, dire->size + 1, ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (sorted && name[0] < dire->name[0]) ++ goto exit_loop; ++ ++ if ((len == dire->size + 1) && !strncmp(name, ++ dire->name, len)) { ++ squashfs_inode_t ino = ++ SQUASHFS_MKINODE(dirh.start_block, ++ dire->offset); ++ unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, ++ dire->offset); ++ ++ TRACE("calling squashfs_iget for directory " ++ "entry %s, inode %x:%x, %lld\n", name, ++ dirh.start_block, dire->offset, ino); ++ ++ inode = squashfs_iget(i->i_sb, ino, inode_number); ++ ++ goto exit_loop; ++ } ++ } ++ } ++ ++exit_loop: ++ kfree(dire); ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ goto exit_loop; ++} ++ ++ ++int squashfs_2_0_supported(struct squashfs_sb_info *msblk) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ msblk->read_inode = squashfs_read_inode_2; ++ msblk->read_fragment_index_table = read_fragment_index_table_2; ++ ++ sblk->bytes_used = sblk->bytes_used_2; ++ sblk->uid_start = sblk->uid_start_2; ++ sblk->guid_start = sblk->guid_start_2; ++ sblk->inode_table_start = sblk->inode_table_start_2; ++ sblk->directory_table_start = sblk->directory_table_start_2; ++ sblk->fragment_table_start = sblk->fragment_table_start_2; ++ ++ return 1; ++} +diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h +new file mode 100755 +index 0000000..8b4629e +--- /dev/null ++++ b/include/linux/aufs_type.h +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: aufs_type.h,v 1.55 2007/05/14 03:40:57 sfjro Exp $ */ ++ ++#include ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#define AUFS_VERSION "20070514" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef char aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef short aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#else ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif ++ ++#define AUFS_NAME "aufs" ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_NWKQ_DEF 4 ++ ++#ifdef CONFIG_AUFS_COMPAT ++#define AUFS_DIROPQ_NAME "__dir_opaque" ++#else ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#endif ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++/* will be whiteouted doubly */ ++#define AUFS_WH_BASENAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX "plink" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum {AuCtlErr, AuCtlErr_Last}; ++enum { ++ AuCtl_REFRESH, //AuCtl_REFRESHV, ++ //AuCtl_FLUSH_PLINK, ++ //AuCtl_CPUP, ++ AuCtl_CPDOWN, AuCtl_MVDOWN ++}; ++ ++struct aufs_ctl_cp { ++ int bsrc, bdst; ++ int err; ++}; ++ ++#define Type 'A' ++#define AUFS_CTL_REFRESH _IO(Type, AuCtl_REFRESH) ++//#define AUFS_CTL_REFRESHV _IO(Type, AuCtl_REFRESHV) ++//#define AUFS_CTL_FLUSH_PLINK _IOR(Type, AuCtl_FLUSH_PLINK) ++//#define AUFS_CTL_CPUP _IOWR(Type, AuCtl_CPUP, struct aufs_ctl_cp) ++#define AUFS_CTL_CPDOWN _IOWR(Type, AuCtl_CPDOWN, struct aufs_ctl_cp) ++#define AUFS_CTL_MVDOWN _IOWR(Type, AuCtl_MVDOWN, struct aufs_ctl_cp) ++#undef Type ++ ++#endif /* __AUFS_TYPE_H__ */ +diff --git a/include/linux/squashfs_fs.h b/include/linux/squashfs_fs.h +new file mode 100644 +index 0000000..a9380ad +--- /dev/null ++++ b/include/linux/squashfs_fs.h +@@ -0,0 +1,934 @@ ++#ifndef SQUASHFS_FS ++#define SQUASHFS_FS ++ ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs.h ++ */ ++ ++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY ++#endif ++ ++#ifdef CONFIG_SQUASHFS_VMALLOC ++#define SQUASHFS_ALLOC(a) vmalloc(a) ++#define SQUASHFS_FREE(a) vfree(a) ++#else ++#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL) ++#define SQUASHFS_FREE(a) kfree(a) ++#endif ++#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE ++#define SQUASHFS_MAJOR 3 ++#define SQUASHFS_MINOR 0 ++#define SQUASHFS_MAGIC 0x73717368 ++#define SQUASHFS_MAGIC_SWAP 0x68737173 ++#define SQUASHFS_START 0 ++ ++/* size of metadata (inode and directory) blocks */ ++#define SQUASHFS_METADATA_SIZE 8192 ++#define SQUASHFS_METADATA_LOG 13 ++ ++/* default size of data blocks */ ++#define SQUASHFS_FILE_SIZE 65536 ++#define SQUASHFS_FILE_LOG 16 ++ ++#define SQUASHFS_FILE_MAX_SIZE 65536 ++ ++/* Max number of uids and gids */ ++#define SQUASHFS_UIDS 256 ++#define SQUASHFS_GUIDS 255 ++ ++/* Max length of filename (not 255) */ ++#define SQUASHFS_NAME_LEN 256 ++ ++#define SQUASHFS_INVALID ((long long) 0xffffffffffff) ++#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) ++#define SQUASHFS_INVALID_BLK ((long long) -1) ++#define SQUASHFS_USED_BLK ((long long) -2) ++ ++/* Filesystem flags */ ++#define SQUASHFS_NOI 0 ++#define SQUASHFS_NOD 1 ++#define SQUASHFS_CHECK 2 ++#define SQUASHFS_NOF 3 ++#define SQUASHFS_NO_FRAG 4 ++#define SQUASHFS_ALWAYS_FRAG 5 ++#define SQUASHFS_DUPLICATE 6 ++#define SQUASHFS_EXPORT 7 ++ ++#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) ++ ++#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOI) ++ ++#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOD) ++ ++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOF) ++ ++#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NO_FRAG) ++ ++#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_ALWAYS_FRAG) ++ ++#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_DUPLICATE) ++ ++#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_EXPORT) ++ ++#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_CHECK) ++ ++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ ++ duplicate_checking, exortable) (noi | (nod << 1) | (check_data << 2) \ ++ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ ++ (duplicate_checking << 6) | (exportable << 7)) ++ ++/* Max number of types and file types */ ++#define SQUASHFS_DIR_TYPE 1 ++#define SQUASHFS_FILE_TYPE 2 ++#define SQUASHFS_SYMLINK_TYPE 3 ++#define SQUASHFS_BLKDEV_TYPE 4 ++#define SQUASHFS_CHRDEV_TYPE 5 ++#define SQUASHFS_FIFO_TYPE 6 ++#define SQUASHFS_SOCKET_TYPE 7 ++#define SQUASHFS_LDIR_TYPE 8 ++#define SQUASHFS_LREG_TYPE 9 ++ ++/* 1.0 filesystem type definitions */ ++#define SQUASHFS_TYPES 5 ++#define SQUASHFS_IPC_TYPE 0 ++ ++/* Flag whether block is compressed or uncompressed, bit is set if block is ++ * uncompressed */ ++#define SQUASHFS_COMPRESSED_BIT (1 << 15) ++ ++#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ ++ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) ++ ++#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) ++ ++#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) ++ ++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \ ++ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \ ++ ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) ++ ++#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) ++ ++/* ++ * Inode number ops. Inodes consist of a compressed block number, and an ++ * uncompressed offset within that block ++ */ ++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) ++ ++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) ++ ++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\ ++ << 16) + (B))) ++ ++/* Compute 32 bit VFS inode number from squashfs inode number */ ++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ ++ ((b) >> 2) + 1)) ++/* XXX */ ++ ++/* Translate between VFS mode and squashfs mode */ ++#define SQUASHFS_MODE(a) ((a) & 0xfff) ++ ++/* fragment and fragment table defines */ ++#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry)) ++ ++#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ ++ sizeof(long long)) ++ ++/* inode lookup table defines */ ++#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t)) ++ ++#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ ++ sizeof(long long)) ++ ++/* cached data constants for filesystem */ ++#define SQUASHFS_CACHED_BLKS 8 ++ ++#define SQUASHFS_MAX_FILE_SIZE_LOG 64 ++ ++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ ++ (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) ++ ++#define SQUASHFS_MARKER_BYTE 0xff ++ ++/* meta index cache */ ++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) ++#define SQUASHFS_META_ENTRIES 31 ++#define SQUASHFS_META_NUMBER 8 ++#define SQUASHFS_SLOTS 4 ++ ++struct meta_entry { ++ long long data_block; ++ unsigned int index_block; ++ unsigned short offset; ++ unsigned short pad; ++}; ++ ++struct meta_index { ++ unsigned int inode_number; ++ unsigned int offset; ++ unsigned short entries; ++ unsigned short skip; ++ unsigned short locked; ++ unsigned short pad; ++ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; ++}; ++ ++ ++/* ++ * definitions for structures on disk ++ */ ++ ++typedef long long squashfs_block_t; ++typedef long long squashfs_inode_t; ++ ++struct squashfs_super_block { ++ unsigned int s_magic; ++ unsigned int inodes; ++ unsigned int bytes_used_2; ++ unsigned int uid_start_2; ++ unsigned int guid_start_2; ++ unsigned int inode_table_start_2; ++ unsigned int directory_table_start_2; ++ unsigned int s_major:16; ++ unsigned int s_minor:16; ++ unsigned int block_size_1:16; ++ unsigned int block_log:16; ++ unsigned int flags:8; ++ unsigned int no_uids:8; ++ unsigned int no_guids:8; ++ unsigned int mkfs_time /* time of filesystem creation */; ++ squashfs_inode_t root_inode; ++ unsigned int block_size; ++ unsigned int fragments; ++ unsigned int fragment_table_start_2; ++ long long bytes_used; ++ long long uid_start; ++ long long guid_start; ++ long long inode_table_start; ++ long long directory_table_start; ++ long long fragment_table_start; ++ long long lookup_table_start; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_index { ++ unsigned int index; ++ unsigned int start_block; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_BASE_INODE_HEADER \ ++ unsigned int inode_type:4; \ ++ unsigned int mode:12; \ ++ unsigned int uid:8; \ ++ unsigned int guid:8; \ ++ unsigned int mtime; \ ++ unsigned int inode_number; ++ ++struct squashfs_base_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ squashfs_block_t start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_lreg_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ squashfs_block_t start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ long long file_size; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int start_block; ++ unsigned int parent_inode; ++} __attribute__ ((packed)); ++ ++struct squashfs_ldir_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned int file_size:27; ++ unsigned int offset:13; ++ unsigned int start_block; ++ unsigned int i_count:16; ++ unsigned int parent_inode; ++ struct squashfs_dir_index index[0]; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header { ++ struct squashfs_base_inode_header base; ++ struct squashfs_dev_inode_header dev; ++ struct squashfs_symlink_inode_header symlink; ++ struct squashfs_reg_inode_header reg; ++ struct squashfs_lreg_inode_header lreg; ++ struct squashfs_dir_inode_header dir; ++ struct squashfs_ldir_inode_header ldir; ++ struct squashfs_ipc_inode_header ipc; ++}; ++ ++struct squashfs_dir_entry { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ int inode_number:16; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_header { ++ unsigned int count:8; ++ unsigned int start_block; ++ unsigned int inode_number; ++} __attribute__ ((packed)); ++ ++struct squashfs_fragment_entry { ++ long long start_block; ++ unsigned int size; ++ unsigned int pending; ++} __attribute__ ((packed)); ++ ++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); ++extern int squashfs_uncompress_init(void); ++extern int squashfs_uncompress_exit(void); ++ ++/* ++ * macros to convert each packed bitfield structure from little endian to big ++ * endian and vice versa. These are needed when creating or using a filesystem ++ * on a machine with different byte ordering to the target architecture. ++ * ++ */ ++ ++#define SQUASHFS_SWAP_START \ ++ int bits;\ ++ int b_pos;\ ++ unsigned long long val;\ ++ unsigned char *s;\ ++ unsigned char *d; ++ ++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\ ++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ ++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ ++ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ ++ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ ++ SQUASHFS_SWAP((s)->flags, d, 288, 8);\ ++ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ ++ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ ++ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ ++ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ ++ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ ++ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ ++ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ ++ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ ++ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ ++ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ ++ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ ++ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ ++ SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\ ++} ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 64, 32); ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_ipc_inode_header))\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_dev_inode_header)); \ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_reg_inode_header));\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ ++ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_lreg_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ ++ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 224, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_dir_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 147, 13);\ ++ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_ldir_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ ++ SQUASHFS_SWAP((s)->offset, d, 155, 13);\ ++ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ ++ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ ++ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\ ++ SQUASHFS_SWAP((s)->index, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 64, 8);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ ++ SQUASHFS_SWAP((s)->size, d, 64, 32);\ ++} ++ ++#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) ++ ++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 2);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 16)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ ++} ++ ++#define SQUASHFS_SWAP_INTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 4);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 32)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 64)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ ++} ++ ++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * bits / 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ bits)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) ++#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++ ++struct squashfs_base_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int type:4; ++ unsigned int offset:4; ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int mtime; ++ unsigned int start_block; ++ unsigned int file_size:32; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ ++ SQUASHFS_SWAP((s)->guid, d, 20, 4); ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_ipc_inode_header_1));\ ++ SQUASHFS_SWAP((s)->type, d, 24, 4);\ ++ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_dev_inode_header_1));\ ++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header_1));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_reg_inode_header_1));\ ++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_dir_inode_header_1));\ ++ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ ++} ++ ++#endif ++ ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++ ++struct squashfs_dir_index_2 { ++ unsigned int index:27; ++ unsigned int start_block:29; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_base_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int mtime; ++ unsigned int start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size:32; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++struct squashfs_ldir_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:27; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++ unsigned int i_count:16; ++ struct squashfs_dir_index_2 index[0]; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header_2 { ++ struct squashfs_base_inode_header_2 base; ++ struct squashfs_dev_inode_header_2 dev; ++ struct squashfs_symlink_inode_header_2 symlink; ++ struct squashfs_reg_inode_header_2 reg; ++ struct squashfs_dir_inode_header_2 dir; ++ struct squashfs_ldir_inode_header_2 ldir; ++ struct squashfs_ipc_inode_header_2 ipc; ++}; ++ ++struct squashfs_dir_header_2 { ++ unsigned int count:8; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_entry_2 { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_fragment_entry_2 { ++ unsigned int start_block; ++ unsigned int size; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_dev_inode_header_2)); \ ++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header_2));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_reg_inode_header_2));\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_dir_inode_header_2));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 51, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ ++} ++ ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_ldir_inode_header_2));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ ++ SQUASHFS_SWAP((s)->offset, d, 59, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ ++ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ ++ SQUASHFS_SWAP((s)->index, d, 0, 27);\ ++ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ ++ SQUASHFS_SWAP((s)->size, d, 56, 8);\ ++} ++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 32, 32);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) ++ ++/* fragment and fragment table defines */ ++#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2)) ++ ++#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ ++ sizeof(int)) ++ ++#endif ++ ++#ifdef __KERNEL__ ++ ++/* ++ * macros used to swap each structure entry, taking into account ++ * bitfields and different bitfield placing conventions on differing ++ * architectures ++ */ ++ ++#include ++ ++#ifdef __BIG_ENDIAN ++ /* convert from little endian to big endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ ++ tbits, b_pos) ++#else ++ /* convert from big endian to little endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ ++ tbits, 64 - tbits - b_pos) ++#endif ++ ++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ ++ b_pos = pos % 8;\ ++ val = 0;\ ++ s = (unsigned char *)p + (pos / 8);\ ++ d = ((unsigned char *) &val) + 7;\ ++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ ++ *d-- = *s++;\ ++ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ ++} ++ ++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); ++ ++#endif ++#endif +diff --git a/include/linux/squashfs_fs_i.h b/include/linux/squashfs_fs_i.h +new file mode 100644 +index 0000000..798891a +--- /dev/null ++++ b/include/linux/squashfs_fs_i.h +@@ -0,0 +1,45 @@ ++#ifndef SQUASHFS_FS_I ++#define SQUASHFS_FS_I ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_i.h ++ */ ++ ++struct squashfs_inode_info { ++ long long start_block; ++ unsigned int offset; ++ union { ++ struct { ++ long long fragment_start_block; ++ unsigned int fragment_size; ++ unsigned int fragment_offset; ++ long long block_list_start; ++ } s1; ++ struct { ++ long long directory_index_start; ++ unsigned int directory_index_offset; ++ unsigned int directory_index_count; ++ unsigned int parent_inode; ++ } s2; ++ } u; ++ struct inode vfs_inode; ++}; ++#endif +diff --git a/include/linux/squashfs_fs_sb.h b/include/linux/squashfs_fs_sb.h +new file mode 100644 +index 0000000..8f3bf99 +--- /dev/null ++++ b/include/linux/squashfs_fs_sb.h +@@ -0,0 +1,74 @@ ++#ifndef SQUASHFS_FS_SB ++#define SQUASHFS_FS_SB ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_sb.h ++ */ ++ ++#include ++ ++struct squashfs_cache { ++ long long block; ++ int length; ++ long long next_index; ++ char *data; ++}; ++ ++struct squashfs_fragment_cache { ++ long long block; ++ int length; ++ unsigned int locked; ++ char *data; ++}; ++ ++struct squashfs_sb_info { ++ struct squashfs_super_block sblk; ++ int devblksize; ++ int devblksize_log2; ++ int swap; ++ struct squashfs_cache *block_cache; ++ struct squashfs_fragment_cache *fragment; ++ int next_cache; ++ int next_fragment; ++ int next_meta_index; ++ unsigned int *uid; ++ unsigned int *guid; ++ long long *fragment_index; ++ unsigned int *fragment_index_2; ++ char *read_page; ++ struct mutex read_data_mutex; ++ struct mutex read_page_mutex; ++ struct mutex block_cache_mutex; ++ struct mutex fragment_mutex; ++ struct mutex meta_index_mutex; ++ wait_queue_head_t waitq; ++ wait_queue_head_t fragment_wait_queue; ++ struct meta_index *meta_index; ++ z_stream stream; ++ long long *inode_lookup_table; ++ int (*read_inode)(struct inode *i, squashfs_inode_t \ ++ inode); ++ long long (*read_blocklist)(struct inode *inode, int \ ++ index, int readahead_blks, char *block_list, \ ++ unsigned short **block_p, unsigned int *bsize); ++ int (*read_fragment_index_table)(struct super_block *s); ++}; ++#endif +diff --git a/init/Kconfig b/init/Kconfig +index b170aa1..bcfc3b4 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -244,23 +244,21 @@ config AUDITSYSCALL + ensure that INOTIFY is configured. + + config IKCONFIG +- tristate "Kernel .config support" ++ tristate "Kernel .miniconfig support" + ---help--- +- This option enables the complete Linux kernel ".config" file ++ This option enables the mini Linux kernel ".miniconfig" file + contents to be saved in the kernel. It provides documentation + of which kernel options are used in a running kernel or in an +- on-disk kernel. This information can be extracted from the kernel +- image file with the script scripts/extract-ikconfig and used as +- input to rebuild the current kernel or to build another kernel. +- It can also be extracted from a running kernel by reading +- /proc/config.gz if enabled (below). ++ on-disk kernel. ++ It can be extracted from a running kernel by reading ++ /proc/miniconfig.gz if enabled (below). + + config IKCONFIG_PROC +- bool "Enable access to .config through /proc/config.gz" ++ bool "Enable access to .miniconfig through /proc/miniconfig.gz" + depends on IKCONFIG && PROC_FS + ---help--- + This option enables access to the kernel configuration file +- through /proc/config.gz. ++ through /proc/miniconfig.gz. + + config CPUSETS + bool "Cpuset support" +diff --git a/init/LzmaDecode.c b/init/LzmaDecode.c +new file mode 100644 +index 0000000..21bf40b +--- /dev/null ++++ b/init/LzmaDecode.c +@@ -0,0 +1,588 @@ ++/* ++ LzmaDecode.c ++ LZMA Decoder (optimized for Speed version) ++ ++ LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this Code, expressly permits you to ++ statically or dynamically link your Code (or bind by name) to the ++ interfaces of this file without subjecting your linked Code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#include "LzmaDecode.h" ++ ++#ifndef Byte ++#define Byte unsigned char ++#endif ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_READ_BYTE (*Buffer++) ++ ++#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ ++ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} ++ ++#ifdef _LZMA_IN_CB ++ ++#define RC_TEST { if (Buffer == BufferLim) \ ++ { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \ ++ BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }} ++ ++#define RC_INIT Buffer = BufferLim = 0; RC_INIT2 ++ ++#else ++ ++#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } ++ ++#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 ++ ++#endif ++ ++#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } ++ ++#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) ++#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; ++#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; ++ ++#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ ++ { UpdateBit0(p); mi <<= 1; A0; } else \ ++ { UpdateBit1(p); mi = (mi + mi) + 1; A1; } ++ ++#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) ++ ++#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ ++ { int i = numLevels; res = 1; \ ++ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \ ++ res -= (1 << numLevels); } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) ++{ ++ unsigned char prop0; ++ if (size < LZMA_PROPERTIES_SIZE) ++ return LZMA_RESULT_DATA_ERROR; ++ prop0 = propsData[0]; ++ if (prop0 >= (9 * 5 * 5)) ++ return LZMA_RESULT_DATA_ERROR; ++ { ++ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); ++ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); ++ propsRes->lc = prop0; ++ /* ++ unsigned char remainder = (unsigned char)(prop0 / 9); ++ propsRes->lc = prop0 % 9; ++ propsRes->pb = remainder / 5; ++ propsRes->lp = remainder % 5; ++ */ ++ } ++ ++ #ifdef _LZMA_OUT_READ ++ { ++ int i; ++ propsRes->DictionarySize = 0; ++ for (i = 0; i < 4; i++) ++ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); ++ if (propsRes->DictionarySize == 0) ++ propsRes->DictionarySize = 1; ++ } ++ #endif ++ return LZMA_RESULT_OK; ++} ++ ++#define kLzmaStreamWasFinishedId (-1) ++ ++int LzmaDecode(CLzmaDecoderState *vs, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *InCallback, ++ #else ++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, ++ #endif ++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) ++{ ++ CProb *p = vs->Probs; ++ SizeT nowPos = 0; ++ Byte previousByte = 0; ++ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; ++ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; ++ int lc = vs->Properties.lc; ++ ++ #ifdef _LZMA_OUT_READ ++ ++ UInt32 Range = vs->Range; ++ UInt32 Code = vs->Code; ++ #ifdef _LZMA_IN_CB ++ const Byte *Buffer = vs->Buffer; ++ const Byte *BufferLim = vs->BufferLim; ++ #else ++ const Byte *Buffer = inStream; ++ const Byte *BufferLim = inStream + inSize; ++ #endif ++ int state = vs->State; ++ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; ++ int len = vs->RemainLen; ++ UInt32 globalPos = vs->GlobalPos; ++ UInt32 distanceLimit = vs->DistanceLimit; ++ ++ Byte *dictionary = vs->Dictionary; ++ UInt32 dictionarySize = vs->Properties.DictionarySize; ++ UInt32 dictionaryPos = vs->DictionaryPos; ++ ++ Byte tempDictionary[4]; ++ ++ #ifndef _LZMA_IN_CB ++ *inSizeProcessed = 0; ++ #endif ++ *outSizeProcessed = 0; ++ if (len == kLzmaStreamWasFinishedId) ++ return LZMA_RESULT_OK; ++ ++ if (dictionarySize == 0) ++ { ++ dictionary = tempDictionary; ++ dictionarySize = 1; ++ tempDictionary[0] = vs->TempDictionary[0]; ++ } ++ ++ if (len == kLzmaNeedInitId) ++ { ++ { ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); ++ UInt32 i; ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ rep0 = rep1 = rep2 = rep3 = 1; ++ state = 0; ++ globalPos = 0; ++ distanceLimit = 0; ++ dictionaryPos = 0; ++ dictionary[dictionarySize - 1] = 0; ++ #ifdef _LZMA_IN_CB ++ RC_INIT; ++ #else ++ RC_INIT(inStream, inSize); ++ #endif ++ } ++ len = 0; ++ } ++ while(len != 0 && nowPos < outSize) ++ { ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ len--; ++ } ++ if (dictionaryPos == 0) ++ previousByte = dictionary[dictionarySize - 1]; ++ else ++ previousByte = dictionary[dictionaryPos - 1]; ++ ++ #else /* if !_LZMA_OUT_READ */ ++ ++ int state = 0; ++ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; ++ int len = 0; ++ const Byte *Buffer; ++ const Byte *BufferLim; ++ UInt32 Range; ++ UInt32 Code; ++ ++ #ifndef _LZMA_IN_CB ++ *inSizeProcessed = 0; ++ #endif ++ *outSizeProcessed = 0; ++ ++ { ++ UInt32 i; ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ } ++ ++ #ifdef _LZMA_IN_CB ++ RC_INIT; ++ #else ++ RC_INIT(inStream, inSize); ++ #endif ++ ++ #endif /* _LZMA_OUT_READ */ ++ ++ while(nowPos < outSize) ++ { ++ CProb *prob; ++ UInt32 bound; ++ int posState = (int)( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & posStateMask); ++ ++ prob = p + IsMatch + (state << kNumPosBitsMax) + posState; ++ IfBit0(prob) ++ { ++ int symbol = 1; ++ UpdateBit0(prob) ++ prob = p + Literal + (LZMA_LIT_SIZE * ++ ((( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & literalPosMask) << lc) + (previousByte >> (8 - lc)))); ++ ++ if (state >= kNumLitStates) ++ { ++ int matchByte; ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ matchByte = dictionary[pos]; ++ #else ++ matchByte = outStream[nowPos - rep0]; ++ #endif ++ do ++ { ++ int bit; ++ CProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & 0x100); ++ probLit = prob + 0x100 + bit + symbol; ++ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) ++ } ++ while (symbol < 0x100); ++ } ++ while (symbol < 0x100) ++ { ++ CProb *probLit = prob + symbol; ++ RC_GET_BIT(probLit, symbol) ++ } ++ previousByte = (Byte)symbol; ++ ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit < dictionarySize) ++ distanceLimit++; ++ ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #endif ++ if (state < 4) state = 0; ++ else if (state < 10) state -= 3; ++ else state -= 6; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRep + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ state = state < kNumLitStates ? 0 : 3; ++ prob = p + LenCoder; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRepG0 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IfBit0(prob) ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos; ++ #endif ++ UpdateBit0(prob); ++ ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit == 0) ++ #else ++ if (nowPos == 0) ++ #endif ++ return LZMA_RESULT_DATA_ERROR; ++ ++ state = state < kNumLitStates ? 9 : 11; ++ #ifdef _LZMA_OUT_READ ++ pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit < dictionarySize) ++ distanceLimit++; ++ #endif ++ ++ continue; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ } ++ } ++ else ++ { ++ UInt32 distance; ++ UpdateBit1(prob); ++ prob = p + IsRepG1 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRepG2 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = p + RepLenCoder; ++ } ++ { ++ int numBits, offset; ++ CProb *probLen = prob + LenChoice; ++ IfBit0(probLen) ++ { ++ UpdateBit0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ numBits = kLenNumLowBits; ++ } ++ else ++ { ++ UpdateBit1(probLen); ++ probLen = prob + LenChoice2; ++ IfBit0(probLen) ++ { ++ UpdateBit0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ numBits = kLenNumMidBits; ++ } ++ else ++ { ++ UpdateBit1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ numBits = kLenNumHighBits; ++ } ++ } ++ RangeDecoderBitTreeDecode(probLen, numBits, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ int posSlot; ++ state += kNumLitStates; ++ prob = p + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ rep0 = (2 | ((UInt32)posSlot & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ rep0 <<= numDirectBits; ++ prob = p + SpecPos + rep0 - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ RC_NORMALIZE ++ Range >>= 1; ++ rep0 <<= 1; ++ if (Code >= Range) ++ { ++ Code -= Range; ++ rep0 |= 1; ++ } ++ } ++ while (--numDirectBits != 0); ++ prob = p + Align; ++ rep0 <<= kNumAlignBits; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ int i = 1; ++ int mi = 1; ++ do ++ { ++ CProb *prob3 = prob + mi; ++ RC_GET_BIT2(prob3, mi, ; , rep0 |= i); ++ i <<= 1; ++ } ++ while(--numDirectBits != 0); ++ } ++ } ++ else ++ rep0 = posSlot; ++ if (++rep0 == (UInt32)(0)) ++ { ++ /* it's for stream version */ ++ len = kLzmaStreamWasFinishedId; ++ break; ++ } ++ } ++ ++ len += kMatchMinLen; ++ #ifdef _LZMA_OUT_READ ++ if (rep0 > distanceLimit) ++ #else ++ if (rep0 > nowPos) ++ #endif ++ return LZMA_RESULT_DATA_ERROR; ++ ++ #ifdef _LZMA_OUT_READ ++ if (dictionarySize - distanceLimit > (UInt32)len) ++ distanceLimit += len; ++ else ++ distanceLimit = dictionarySize; ++ #endif ++ ++ do ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ len--; ++ outStream[nowPos++] = previousByte; ++ } ++ while(len != 0 && nowPos < outSize); ++ } ++ } ++ RC_NORMALIZE; ++ ++ #ifdef _LZMA_OUT_READ ++ vs->Range = Range; ++ vs->Code = Code; ++ vs->DictionaryPos = dictionaryPos; ++ vs->GlobalPos = globalPos + (UInt32)nowPos; ++ vs->DistanceLimit = distanceLimit; ++ vs->Reps[0] = rep0; ++ vs->Reps[1] = rep1; ++ vs->Reps[2] = rep2; ++ vs->Reps[3] = rep3; ++ vs->State = state; ++ vs->RemainLen = len; ++ vs->TempDictionary[0] = tempDictionary[0]; ++ #endif ++ ++ #ifdef _LZMA_IN_CB ++ vs->Buffer = Buffer; ++ vs->BufferLim = BufferLim; ++ #else ++ *inSizeProcessed = (SizeT)(Buffer - inStream); ++ #endif ++ *outSizeProcessed = nowPos; ++ return LZMA_RESULT_OK; ++} +diff --git a/init/LzmaDecode.h b/init/LzmaDecode.h +new file mode 100644 +index 0000000..213062a +--- /dev/null ++++ b/init/LzmaDecode.h +@@ -0,0 +1,131 @@ ++/* ++ LzmaDecode.h ++ LZMA Decoder interface ++ ++ LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this code, expressly permits you to ++ statically or dynamically link your code (or bind by name) to the ++ interfaces of this file without subjecting your linked code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#ifndef __LZMADECODE_H ++#define __LZMADECODE_H ++ ++/* #define _LZMA_IN_CB */ ++/* Use callback for input data */ ++ ++/* #define _LZMA_OUT_READ */ ++/* Use read function for output data */ ++ ++/* #define _LZMA_PROB32 */ ++/* It can increase speed on some 32-bit CPUs, ++ but memory usage will be doubled in that case */ ++ ++/* #define _LZMA_LOC_OPT */ ++/* Enable local speed optimizations inside code */ ++ ++/* #define _LZMA_SYSTEM_SIZE_T */ ++/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/ ++ ++#ifndef UInt32 ++#ifdef _LZMA_UINT32_IS_ULONG ++#define UInt32 unsigned long ++#else ++#define UInt32 unsigned int ++#endif ++#endif ++ ++#ifndef SizeT ++#ifdef _LZMA_SYSTEM_SIZE_T ++#include ++#define SizeT size_t ++#else ++#define SizeT UInt32 ++#endif ++#endif ++ ++#ifdef _LZMA_PROB32 ++#define CProb UInt32 ++#else ++#define CProb unsigned short ++#endif ++ ++#define LZMA_RESULT_OK 0 ++#define LZMA_RESULT_DATA_ERROR 1 ++ ++#ifdef _LZMA_IN_CB ++typedef struct _ILzmaInCallback ++{ ++ int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize); ++} ILzmaInCallback; ++#endif ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LZMA_PROPERTIES_SIZE 5 ++ ++typedef struct _CLzmaProperties ++{ ++ int lc; ++ int lp; ++ int pb; ++ #ifdef _LZMA_OUT_READ ++ UInt32 DictionarySize; ++ #endif ++}CLzmaProperties; ++ ++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); ++ ++#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) ++ ++#define kLzmaNeedInitId (-2) ++ ++typedef struct _CLzmaDecoderState ++{ ++ CLzmaProperties Properties; ++ CProb *Probs; ++ ++ #ifdef _LZMA_IN_CB ++ const unsigned char *Buffer; ++ const unsigned char *BufferLim; ++ #endif ++ ++ #ifdef _LZMA_OUT_READ ++ unsigned char *Dictionary; ++ UInt32 Range; ++ UInt32 Code; ++ UInt32 DictionaryPos; ++ UInt32 GlobalPos; ++ UInt32 DistanceLimit; ++ UInt32 Reps[4]; ++ int State; ++ int RemainLen; ++ unsigned char TempDictionary[4]; ++ #endif ++} CLzmaDecoderState; ++ ++#ifdef _LZMA_OUT_READ ++#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; } ++#endif ++ ++int LzmaDecode(CLzmaDecoderState *vs, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback, ++ #else ++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, ++ #endif ++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); ++ ++#endif +diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c +index ed652f4..5fd1ec5 100644 +--- a/init/do_mounts_rd.c ++++ b/init/do_mounts_rd.c +@@ -5,7 +5,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + + #include "do_mounts.h" +@@ -31,6 +33,9 @@ static int __init ramdisk_start_setup(char *str) + __setup("ramdisk_start=", ramdisk_start_setup); + + static int __init crd_load(int in_fd, int out_fd); ++#ifdef CONFIG_LZMA_INITRD ++static int __init lzma_rd_load(int in_fd, int out_fd); ++#endif + + /* + * This routine tries to find a RAM disk image to load, and returns the +@@ -39,6 +44,7 @@ static int __init crd_load(int in_fd, int out_fd); + * numbers could not be found. + * + * We currently check for the following magic numbers: ++ * squashfs + * minix + * ext2 + * romfs +@@ -53,6 +59,7 @@ identify_ramdisk_image(int fd, int start_block) + struct ext2_super_block *ext2sb; + struct romfs_super_block *romfsb; + struct cramfs_super *cramfsb; ++ struct squashfs_super_block *squashfsb; + int nblocks = -1; + unsigned char *buf; + +@@ -64,6 +71,7 @@ identify_ramdisk_image(int fd, int start_block) + ext2sb = (struct ext2_super_block *) buf; + romfsb = (struct romfs_super_block *) buf; + cramfsb = (struct cramfs_super *) buf; ++ squashfsb = (struct squashfs_super_block *) buf; + memset(buf, 0xe5, size); + + /* +@@ -82,6 +90,17 @@ identify_ramdisk_image(int fd, int start_block) + nblocks = 0; + goto done; + } ++ /* ++ * handle lzma compressed initrd, returns nblocks=1 as indication ++ */ ++ if( buf[0] < 9 * 5 * 5 && buf[9] == 0 && buf[10] == 0 && buf[11] == 0 ++ && buf[12] == 0 ) ++ { ++ printk( KERN_NOTICE "RAMDISK: LZMA image found at block %d\n", ++ start_block); ++ nblocks = 1; // just a convenient return flag ++ goto done; ++ } + + /* romfs is at block zero too */ + if (romfsb->word0 == ROMSB_WORD0 && +@@ -101,6 +120,18 @@ identify_ramdisk_image(int fd, int start_block) + goto done; + } + ++ /* squashfs is at block zero too */ ++ if (squashfsb->s_magic == SQUASHFS_MAGIC) { ++ printk(KERN_NOTICE ++ "RAMDISK: squashfs filesystem found at block %d\n", ++ start_block); ++ if (squashfsb->s_major < 3) ++ nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ else ++ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ goto done; ++ } ++ + /* + * Read block 1 to test for minix and ext2 superblock + */ +@@ -172,7 +203,22 @@ int __init rd_load_image(char *from) + #endif + goto done; + } +- ++#ifdef CONFIG_LZMA_INITRD ++ /* ++ * handle lzma compressed image ++ */ ++ if ( nblocks == 1 ) ++ { ++ nblocks = 0; ++ if ( lzma_rd_load(in_fd, out_fd) == 0 ) ++ { ++ printk("\nLZMA initrd loaded successfully\n"); ++ goto successful_load; ++ } ++ printk(KERN_NOTICE "LZMA initrd is not in the correct format\n"); ++ goto done; ++ } ++#endif + /* + * NOTE NOTE: nblocks is not actually blocks but + * the number of kibibytes of data to load into a ramdisk. +@@ -393,6 +439,134 @@ static void __init error(char *x) + unzip_error = 1; + } + ++#ifdef CONFIG_LZMA_INITRD ++#define _LZMA_IN_CB ++#define _LZMA_OUT_READ ++#include "LzmaDecode.h" ++#include "LzmaDecode.c" ++ ++static int read_byte(void *object, const unsigned char **buffer, SizeT *bufferSize); ++ ++/* ++ * Do the lzma decompression ++ */ ++static int __init lzma_rd_load(int in_fd, int out_fd) ++{ ++ unsigned int i; ++ CLzmaDecoderState state; ++ unsigned char* outputbuffer; ++ unsigned int uncompressedSize = 0; ++ unsigned char* p; ++ unsigned int kBlockSize = 0x10000; ++ unsigned int nowPos = 0; ++ unsigned int outsizeProcessed = 0; ++ int res; ++ ILzmaInCallback callback; ++ ++ insize = 0; /* valid bytes in inbuf */ ++ inptr = 0; /* index of next byte to be processed in inbuf */ ++ exit_code = 0; ++ crd_infd = in_fd; ++ inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); ++ if (inbuf == 0) ++ { ++ printk(KERN_ERR "RAMDISK: Couldn't allocate lzma input buffer\n"); ++ return -1; ++ } ++ ++ callback.Read = read_byte; ++ ++ /* lzma args */ ++ i = get_byte(); ++ state.Properties.lc = i % 9, i = i / 9; ++ state.Properties.lp = i % 5, state.Properties.pb = i / 5; ++ ++ /* read dictionary size */ ++ p = (char*)&state.Properties.DictionarySize; ++ for (i = 0; i < 4; i++) ++ *p++ = get_byte(); ++ ++ /* get uncompressedSize */ ++ p= (char*)&uncompressedSize; ++ for (i = 0; i < 4; i++) ++ *p++ = get_byte(); ++ ++ /* skip big file */ ++ for (i = 0; i < 4; i++) ++ get_byte(); ++ ++ printk( KERN_NOTICE "RAMDISK: LZMA lc=%d,lp=%d,pb=%d,dictSize=%d,origSize=%d\n", ++ state.Properties.lc, state.Properties.lp, state.Properties.pb, state.Properties.DictionarySize, uncompressedSize); ++ outputbuffer = kmalloc(kBlockSize, GFP_KERNEL); ++ if (outputbuffer == 0) { ++ printk(KERN_ERR "RAMDISK: Couldn't allocate lzma output buffer\n"); ++ return -1; ++ } ++ ++ state.Probs = (CProb*)kmalloc( LzmaGetNumProbs(&state.Properties)*sizeof(CProb), GFP_KERNEL); ++ if ( state.Probs == 0) { ++ printk(KERN_ERR "RAMDISK: Couldn't allocate lzma workspace\n"); ++ return -1; ++ } ++ ++#ifdef CONFIG_LZMA_INITRD_KMALLOC_ONLY ++ state.Dictionary = kmalloc( state.Properties.DictionarySize, GFP_KERNEL); ++#else ++ state.Dictionary = vmalloc( state.Properties.DictionarySize); ++#endif ++ if ( state.Dictionary == 0) { ++ printk(KERN_ERR "RAMDISK: Couldn't allocate lzma dictionary\n"); ++ return -1; ++ } ++ ++ printk( KERN_NOTICE "LZMA initrd by Ming-Ching Tiew " ); ++ ++ LzmaDecoderInit( &state ); ++ ++ for( nowPos =0; nowPos < uncompressedSize ; ) ++ { ++ UInt32 blockSize = uncompressedSize - nowPos; ++ if( blockSize > kBlockSize) ++ blockSize = kBlockSize; ++ res = LzmaDecode( &state, &callback, outputbuffer, blockSize, &outsizeProcessed); ++ if( res != 0 ) { ++ printk( KERN_ERR "RAMDISK: Lzma decode failure\n"); ++ return -1; ++ } ++ if( outsizeProcessed == 0 ) ++ { ++ uncompressedSize = nowPos; ++ printk( KERN_NOTICE "RAMDISK nowPos=%d, uncompressedSize=%d\n", ++ nowPos, uncompressedSize ); ++ break; ++ } ++ sys_write(out_fd, outputbuffer, outsizeProcessed ); ++ nowPos += outsizeProcessed; ++ printk( "."); ++ } ++ ++#ifdef CONFIG_LZMA_INITRD_KMALLOC_ONLY ++ kfree(state.Dictionary); ++#else ++ vfree(state.Dictionary); ++#endif ++ kfree(inbuf); ++ kfree(outputbuffer); ++ kfree(state.Probs); ++ return 0; ++} ++ ++static int read_byte(void *object, const unsigned char **buffer, SizeT *bufferSize) ++{ ++ static unsigned char val; ++ *bufferSize = 1; ++ val = get_byte(); ++ *buffer = &val; ++ return LZMA_RESULT_OK; ++} ++ ++#endif /*CONFIG_LZMA_INITRD*/ ++ + static int __init crd_load(int in_fd, int out_fd) + { + int result; +diff --git a/init/initramfs.c b/init/initramfs.c +index 00eff7a..30d32a2 100644 +--- a/init/initramfs.c ++++ b/init/initramfs.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + static __initdata char *message; + static void __init error(char *x) +@@ -441,6 +442,118 @@ static void __init flush_window(void) + outcnt = 0; + } + ++#ifdef CONFIG_LZMA_INITRAM_FS ++#define _LZMA_IN_CB ++#define _LZMA_OUT_READ ++#include "LzmaDecode.h" ++#ifndef CONFIG_LZMA_INITRD ++ #include "LzmaDecode.c" ++#endif ++static int read_byte(void *object, const unsigned char **buffer, SizeT *bufferSize) ++{ ++ static unsigned char val; ++ *bufferSize = 1; ++ val = get_byte(); ++ *buffer = &val; ++ return LZMA_RESULT_OK; ++} ++ ++static int __init lzma_unzip(void) ++{ ++ unsigned int i; ++ CLzmaDecoderState state; ++ unsigned char* outputbuffer; ++ unsigned int uncompressedSize = 0; ++ unsigned char* p; ++ unsigned int kBlockSize = 0x10000; ++ unsigned int nowPos = 0; ++ unsigned int outsizeProcessed = 0; ++ int res; ++ ILzmaInCallback callback; ++ ++ callback.Read = read_byte; ++ ++ // lzma args ++ i = get_byte(); ++ state.Properties.lc = i % 9, i = i / 9; ++ state.Properties.lp = i % 5, state.Properties.pb = i / 5; ++ ++ // read dictionary size ++ p = (char*)&state.Properties.DictionarySize; ++ for (i = 0; i < 4; i++) ++ *p++ = get_byte(); ++ ++ // get uncompressedSize ++ p= (char*)&uncompressedSize; ++ for (i = 0; i < 4; i++) ++ *p++ = get_byte(); ++ ++ // skip big file ++ for (i = 0; i < 4; i++) ++ get_byte(); ++ ++ printk( KERN_NOTICE "initramfs: LZMA lc=%d,lp=%d,pb=%d,dictSize=%d,origSize=%d\n", ++ state.Properties.lc,state.Properties.lp,state.Properties.pb,state.Properties.DictionarySize, uncompressedSize); ++ outputbuffer = kmalloc(kBlockSize, GFP_KERNEL); ++ if (outputbuffer == 0) { ++ printk(KERN_ERR "initramfs: Couldn't allocate lzma output buffer\n"); ++ return -1; ++ } ++ ++ state.Probs = (CProb*) kmalloc( LzmaGetNumProbs(&state.Properties)*sizeof(CProb), GFP_KERNEL); ++ if ( state.Probs == 0) { ++ printk(KERN_ERR "initramfs: Couldn't allocate lzma workspace\n"); ++ return -1; ++ } ++ ++#ifdef CONFIG_LZMA_INITRAM_FS_KMALLOC_ONLY ++ state.Dictionary = kmalloc( state.Properties.DictionarySize, GFP_KERNEL); ++#else ++ state.Dictionary = vmalloc( state.Properties.DictionarySize); ++#endif ++ if ( state.Dictionary == 0) { ++ printk(KERN_ERR "initramfs: Couldn't allocate lzma dictionary\n"); ++ return -1; ++ } ++ ++ printk( KERN_NOTICE "LZMA initramfs by Ming-Ching Tiew " ); ++ ++ LzmaDecoderInit( &state ); ++ ++ for( nowPos =0; nowPos < uncompressedSize ; ) ++ { ++ UInt32 blockSize = uncompressedSize - nowPos; ++ if( blockSize > kBlockSize) ++ blockSize = kBlockSize; ++ res = LzmaDecode( &state, &callback, outputbuffer, blockSize, &outsizeProcessed); ++ if( res != 0 ) { ++ panic( KERN_ERR "initramfs: Lzma decode failure\n"); ++ return -1; ++ } ++ if( outsizeProcessed == 0 ) ++ { ++ uncompressedSize = nowPos; ++ printk( KERN_NOTICE "initramfs: nowPos=%d, uncompressedSize=%d\n", ++ nowPos, uncompressedSize ); ++ break; ++ } ++ flush_buffer(outputbuffer, outsizeProcessed); ++ nowPos += outsizeProcessed; ++ printk( "."); ++ } ++ ++#ifdef CONFIG_LZMA_INITRAM_FS_KMALLOC_ONLY ++ kfree(state.Dictionary); ++#else ++ vfree(state.Dictionary); ++#endif ++ kfree(outputbuffer); ++ kfree(state.Probs); ++ return 0; ++} ++ ++#endif /*CONFIG LZMA_INITRAM_FS*/ ++ + static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) + { + int written; +@@ -475,12 +588,31 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) + inptr = 0; + outcnt = 0; /* bytes in output buffer */ + bytes_out = 0; +- crc = (ulg)0xffffffffL; /* shift register contents */ +- makecrc(); +- gunzip(); +- if (state != Reset) ++ if( inbuf[0] == 037 && ((inbuf[1] == 0213) || (inbuf[1] == 0236))) ++ { ++ printk( KERN_NOTICE "detected gzip initramfs\n"); ++ crc = (ulg)0xffffffffL; /* shift register contents */ ++ makecrc(); ++ gunzip(); ++ if (state != Reset) + error("junk in gzipped archive"); +- this_header = saved_offset + inptr; ++ } ++#ifdef CONFIG_LZMA_INITRAM_FS ++ else if( inbuf[0] < 9 * 5 * 5 && buf[9] == 0 && buf[10] == 0 ++ && buf[11] == 0 && buf[12] == 0 ) ++ { ++ printk( KERN_NOTICE "detected lzma initramfs\n"); ++ lzma_unzip(); ++ } ++#endif ++ else ++ { ++ // skip forward ? ++ crc = (ulg)0xffffffffL; /* shift register contents */ ++ makecrc(); ++ gunzip(); ++ } ++ this_header = saved_offset + inptr; + buf += inptr; + len -= inptr; + } +diff --git a/kernel/Makefile b/kernel/Makefile +index ac6b27a..bd498a2 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -66,7 +66,7 @@ $(obj)/configs.o: $(obj)/config_data.h + # config_data.h contains the same information as ikconfig.h but gzipped. + # Info from config_data can be extracted from /proc/config* + targets += config_data.gz +-$(obj)/config_data.gz: .config FORCE ++$(obj)/config_data.gz: .miniconfig FORCE + $(call if_changed,gzip) + + quiet_cmd_ikconfiggz = IKCFG $@ +diff --git a/kernel/configs.c b/kernel/configs.c +index 8fa1fb2..c8407eb 100644 +--- a/kernel/configs.c ++++ b/kernel/configs.c +@@ -88,7 +88,7 @@ static int __init ikconfig_init(void) + struct proc_dir_entry *entry; + + /* create the current config file */ +- entry = create_proc_entry("config.gz", S_IFREG | S_IRUGO, ++ entry = create_proc_entry("miniconfig.gz", S_IFREG | S_IRUGO, + &proc_root); + if (!entry) + return -ENOMEM; +@@ -104,7 +104,7 @@ static int __init ikconfig_init(void) + + static void __exit ikconfig_cleanup(void) + { +- remove_proc_entry("config.gz", &proc_root); ++ remove_proc_entry("miniconfig.gz", &proc_root); + } + + module_init(ikconfig_init); +diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c +index fe5c7db..a5150e6 100644 +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -85,8 +85,8 @@ static void clocksource_ratewd(struct clocksource *cs, int64_t delta) + if (delta > -WATCHDOG_TRESHOLD && delta < WATCHDOG_TRESHOLD) + return; + +- printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", +- cs->name, delta); ++/* printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", ++ cs->name, delta); */ + cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); + clocksource_change_rating(cs, 0); + cs->flags &= ~CLOCK_SOURCE_WATCHDOG; +diff --git a/kernel/timer.c b/kernel/timer.c +index dd6c2c1..3a8f485 100644 +--- a/kernel/timer.c ++++ b/kernel/timer.c +@@ -916,8 +916,8 @@ static void change_clocksource(void) + + tick_clock_notify(); + +- printk(KERN_INFO "Time: %s clocksource has been installed.\n", +- clock->name); ++/* printk(KERN_INFO "Time: %s clocksource has been installed.\n", ++ clock->name); */ + } + #else + static inline void change_clocksource(void) { } +diff --git a/miniconfig.sh b/miniconfig.sh +new file mode 100755 +index 0000000..28e7433 +--- /dev/null ++++ b/miniconfig.sh +@@ -0,0 +1,2 @@ ++#!/bin/sh -f ++make allnoconfig KCONFIG_ALLCONFIG=.miniconfig +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index fc498fe..e98172c 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -162,4 +162,9 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ + quiet_cmd_gzip = GZIP $@ + cmd_gzip = gzip -f -9 < $< > $@ + ++# LZMA ++# ++quiet_cmd_lzma = LZMA $@ ++cmd_lzma = lzma e $< $@ -lc7 -lp0 -pb0 2>/dev/null ++ + +diff --git a/scripts/gen_lzma_initramfs_list.sh b/scripts/gen_lzma_initramfs_list.sh +new file mode 100644 +index 0000000..be3ed6a +--- /dev/null ++++ b/scripts/gen_lzma_initramfs_list.sh +@@ -0,0 +1,292 @@ ++#!/bin/bash ++# Copyright (C) Martin Schlemmer ++# Copyright (c) 2006 Sam Ravnborg ++# ++# Released under the terms of the GNU GPL ++# ++# Generate a cpio packed initramfs. It uses gen_init_cpio to generate ++# the cpio archive, and gzip to pack it. ++# The script may also be used to generate the inputfile used for gen_init_cpio ++# This script assumes that gen_init_cpio is located in usr/ directory ++ ++# error out on errors ++set -e ++ ++usage() { ++cat << EOF ++Usage: ++$0 [-o ] [-u ] [-g ] { -s | -d | } ... ++ -o Create lzma initramfs file named using ++ gen_init_cpio and lzma ++ -u User ID to map to user ID 0 (root). ++ is only meaningful if ++ is a directory. ++ -g Group ID to map to group ID 0 (root). ++ is only meaningful if ++ is a directory. ++ File list or directory for cpio archive. ++ If is a .cpio file it will be used ++ as direct input to initramfs. ++ -s Create lzma file with small dictionary size ++ -d Output the default cpio list. ++ ++All options except -o and -l may be repeated and are interpreted ++sequentially and immediately. -u and -g states are preserved across ++ options so an explicit "-u 0 -g 0" is required ++to reset the root/group mapping. ++EOF ++} ++ ++list_default_initramfs() { ++ # echo usr/kinit/kinit ++ : ++} ++ ++default_initramfs() { ++ cat <<-EOF >> ${output} ++ # This is a very simple, default initramfs ++ ++ dir /dev 0755 0 0 ++ nod /dev/console 0600 0 0 c 5 1 ++ dir /root 0700 0 0 ++ # file /kinit usr/kinit/kinit 0755 0 0 ++ # slink /init kinit 0755 0 0 ++ EOF ++} ++ ++filetype() { ++ local argv1="$1" ++ ++ # symlink test must come before file test ++ if [ -L "${argv1}" ]; then ++ echo "slink" ++ elif [ -f "${argv1}" ]; then ++ echo "file" ++ elif [ -d "${argv1}" ]; then ++ echo "dir" ++ elif [ -b "${argv1}" -o -c "${argv1}" ]; then ++ echo "nod" ++ elif [ -p "${argv1}" ]; then ++ echo "pipe" ++ elif [ -S "${argv1}" ]; then ++ echo "sock" ++ else ++ echo "invalid" ++ fi ++ return 0 ++} ++ ++list_print_mtime() { ++ : ++} ++ ++print_mtime() { ++ local my_mtime="0" ++ ++ if [ -e "$1" ]; then ++ my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1) ++ fi ++ ++ echo "# Last modified: ${my_mtime}" >> ${output} ++ echo "" >> ${output} ++} ++ ++list_parse() { ++ echo "$1 \\" ++} ++ ++# for each file print a line in following format ++# ++# for links, devices etc the format differs. See gen_init_cpio for details ++parse() { ++ local location="$1" ++ local name="${location/${srcdir}//}" ++ # change '//' into '/' ++ name="${name//\/\///}" ++ local mode="$2" ++ local uid="$3" ++ local gid="$4" ++ local ftype=$(filetype "${location}") ++ # remap uid/gid to 0 if necessary ++ [ "$uid" -eq "$root_uid" ] && uid=0 ++ [ "$gid" -eq "$root_gid" ] && gid=0 ++ local str="${mode} ${uid} ${gid}" ++ ++ [ "${ftype}" == "invalid" ] && return 0 ++ [ "${location}" == "${srcdir}" ] && return 0 ++ ++ case "${ftype}" in ++ "file") ++ str="${ftype} ${name} ${location} ${str}" ++ ;; ++ "nod") ++ local dev_type= ++ local maj=$(LC_ALL=C ls -l "${location}" | \ ++ gawk '{sub(/,/, "", $5); print $5}') ++ local min=$(LC_ALL=C ls -l "${location}" | \ ++ gawk '{print $6}') ++ ++ if [ -b "${location}" ]; then ++ dev_type="b" ++ else ++ dev_type="c" ++ fi ++ str="${ftype} ${name} ${str} ${dev_type} ${maj} ${min}" ++ ;; ++ "slink") ++ local target=$(LC_ALL=C ls -l "${location}" | \ ++ gawk '{print $11}') ++ str="${ftype} ${name} ${target} ${str}" ++ ;; ++ *) ++ str="${ftype} ${name} ${str}" ++ ;; ++ esac ++ ++ echo "${str}" >> ${output} ++ ++ return 0 ++} ++ ++unknown_option() { ++ printf "ERROR: unknown option \"$arg\"\n" >&2 ++ printf "If the filename validly begins with '-', " >&2 ++ printf "then it must be prefixed\n" >&2 ++ printf "by './' so that it won't be interpreted as an option." >&2 ++ printf "\n" >&2 ++ usage >&2 ++ exit 1 ++} ++ ++list_header() { ++ : ++} ++ ++header() { ++ printf "\n#####################\n# $1\n" >> ${output} ++} ++ ++# process one directory (incl sub-directories) ++dir_filelist() { ++ ${dep_list}header "$1" ++ ++ srcdir=$(echo "$1" | sed -e 's://*:/:g') ++ dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" 2>/dev/null) ++ ++ # If $dirlist is only one line, then the directory is empty ++ if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then ++ ${dep_list}print_mtime "$1" ++ ++ echo "${dirlist}" | \ ++ while read x; do ++ ${dep_list}parse ${x} ++ done ++ fi ++} ++ ++# if only one file is specified and it is .cpio file then use it direct as fs ++# if a directory is specified then add all files in given direcotry to fs ++# if a regular file is specified assume it is in gen_initramfs format ++input_file() { ++ source="$1" ++ if [ -f "$1" ]; then ++ ${dep_list}header "$1" ++ is_cpio="$(echo "$1" | sed 's/^.*\.cpio/cpio/')" ++ if [ $2 -eq 0 -a ${is_cpio} == "cpio" ]; then ++ cpio_file=$1 ++ [ ! -z ${dep_list} ] && echo "$1" ++ return 0 ++ fi ++ if [ -z ${dep_list} ]; then ++ print_mtime "$1" >> ${output} ++ cat "$1" >> ${output} ++ else ++ cat "$1" | while read type dir file perm ; do ++ if [ "$type" == "file" ]; then ++ echo "$file \\"; ++ fi ++ done ++ fi ++ elif [ -d "$1" ]; then ++ dir_filelist "$1" ++ else ++ echo " ${prog}: Cannot open '$1'" >&2 ++ exit 1 ++ fi ++} ++ ++prog=$0 ++root_uid=0 ++root_gid=0 ++dep_list= ++cpio_file= ++cpio_list= ++output="/dev/stdout" ++output_file="" ++opt="" ++ ++arg="$1" ++case "$arg" in ++ "-l") # files included in initramfs - used by kbuild ++ dep_list="list_" ++ echo "deps_initramfs := \\" ++ shift ++ ;; ++ "-o") # generate lzma-ed cpio image named $1 ++ shift ++ output_file="$1" ++ cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)" ++ output=${cpio_list} ++ shift ++ ;; ++esac ++while [ $# -gt 0 ]; do ++ arg="$1" ++ shift ++ case "$arg" in ++ "-u") # map $1 to uid=0 (root) ++ root_uid="$1" ++ shift ++ ;; ++ "-g") # map $1 to gid=0 (root) ++ root_gid="$1" ++ shift ++ ;; ++ "-s") ++ opt="-d16" ++ ;; ++ "-d") # display default initramfs list ++ default_list="$arg" ++ ${dep_list}default_initramfs ++ ;; ++ "-h") ++ usage ++ exit 0 ++ ;; ++ *) ++ case "$arg" in ++ "-"*) ++ unknown_option ++ ;; ++ *) # input file/dir - process it ++ input_file "$arg" "$#" ++ ;; ++ esac ++ ;; ++ esac ++done ++ ++# If output_file is set we will generate cpio archive and lzma it ++# we are carefull to delete tmp files ++if [ ! -z ${output_file} ]; then ++ if [ -z ${cpio_file} ]; then ++ cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)" ++ usr/gen_init_cpio ${cpio_list} > ${cpio_tfile} ++ else ++ cpio_tfile=${cpio_file} ++ fi ++ rm ${cpio_list} ++ lzma e ${cpio_tfile} ${output_file} ${opt} ++ [ -z ${cpio_file} ] && rm ${cpio_tfile} ++fi ++exit 0 +diff --git a/shrinkconfig.sh b/shrinkconfig.sh +new file mode 100755 +index 0000000..e7a3df7 +--- /dev/null ++++ b/shrinkconfig.sh +@@ -0,0 +1,79 @@ ++#! /bin/bash ++ ++# shrinkconfig copyright 2006 by Rob Landley ++# Licensed under the GNU General Public License version 2. ++ ++if [ $# -ne 1 ] ++then ++ echo "Turns current .config into a miniconfig file." ++ echo "Usage: shrinkconfig mini.config" ++ exit 1 ++fi ++ ++if [ ! -f .config ] ++then ++ echo "Need a .config file to shrink." ++ exit 1 ++fi ++LENGTH=$(wc -l < .config) ++ ++OUTPUT="$1" ++cp .config "$OUTPUT" ++if [ $? -ne 0 ] ++then ++ echo "Couldn't create $OUTPUT" ++ exit 1 ++fi ++ ++# If we get interrupted, clean up the mess ++ ++KERNELOUTPUT="" ++ ++function cleanup ++{ ++ echo ++ echo "Interrupted." ++ [ ! -z "$KERNELOUTPUT" ] && rm -rf "$KERNELOUTPUT" ++ rm "$OUTPUT" ++ exit 1 ++} ++ ++trap cleanup HUP INT QUIT TERM ++ ++# Since the "O=" argument to make doesn't work recursively, we need to jump ++# through a few hoops to avoid overwriting the .config that we're shrinking. ++ ++# If we're building out of tree, we'll have absolute paths to source and build ++# directories in the Makefile. ++ ++KERNELSRC=$(sed -n -e 's/KERNELSRC[^/]*:=[^/]*//p' Makefile) ++[ -z "$KERNELSRC" ] && KERNELSRC=$(pwd) ++KERNELOUTPUT=`pwd`/.config.minitemp ++ ++mkdir -p "$KERNELOUTPUT" || exit 1 ++ ++echo "Shrinking .config to $OUTPUT..." ++ ++for I in $(seq 1 $LENGTH) ++do ++ echo -n -e "\r"$I/$LENGTH lines $(wc -c < "$OUTPUT") bytes ++ ++ sed -n "${I}!p" "$OUTPUT" > "$KERNELOUTPUT"/.config.test ++ # Do a config with this file ++ make -C "$KERNELSRC" O="$KERNELOUTPUT" allnoconfig KCONFIG_ALLCONFIG="$KERNELOUTPUT"/.config.test > /dev/null ++ ++ # Compare. The date changes, so expect a small difference each time. ++ D=$(diff "$KERNELOUTPUT"/.config .config | wc -l) ++ if [ $D -eq 4 ] ++ then ++ mv "$KERNELOUTPUT"/.config.test "$OUTPUT" ++ LENGTH=$[$LENGTH-1] ++ else ++ I=$[$I + 1] ++ fi ++done ++ ++rm -rf "$KERNELOUTPUT" ++ ++# One extra echo to preserve status line. ++echo +diff --git a/usr/Makefile b/usr/Makefile +index 201f27f..8e1f6ea 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -19,6 +19,7 @@ $(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz FORCE + + hostprogs-y := gen_init_cpio + initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh ++lzma_initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_lzma_initramfs_list.sh + ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \ + $(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d) + ramfs-args := \ +@@ -36,6 +37,14 @@ endif + quiet_cmd_initfs = GEN $@ + cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) + ++ifdef CONFIG_LZMA_INITRAM_FS_SMALLMEM ++quiet_cmd_lzma_initfs = LZRAMFS $@ ++ cmd_lzma_initfs = $(lzma_initramfs) -o $@ $(ramfs-args) -s $(ramfs-input) ++else ++quiet_cmd_lzma_initfs = LZRAMFS $@ ++ cmd_lzma_initfs = $(lzma_initramfs) -o $@ $(ramfs-args) $(ramfs-input) ++endif ++ + targets := initramfs_data.cpio.gz + # do not try to update files included in initramfs + $(deps_initramfs): ; +@@ -48,5 +57,9 @@ $(deps_initramfs): klibcdirs + # 4) arguments to gen_initramfs.sh changes + $(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs + $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.gz.d ++ifdef CONFIG_LZMA_INITRAM_FS ++ $(call if_changed,lzma_initfs) ++else + $(call if_changed,initfs) ++endif + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.21.5-002-lzma-vmlinuz.01.patch b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.21.5-002-lzma-vmlinuz.01.patch new file mode 100644 index 0000000000..05361ff9d4 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.21.5-002-lzma-vmlinuz.01.patch @@ -0,0 +1,54 @@ +diff -rdup linux-2.6.21.5.oorig/arch/i386/boot/compressed/Makefile linux-2.6.21.5/arch/i386/boot/compressed/Makefile +--- linux-2.6.21.5.oorig/arch/i386/boot/compressed/Makefile 2007-07-24 13:08:51.000000000 +0200 ++++ linux-2.6.21.5/arch/i386/boot/compressed/Makefile 2007-07-24 14:54:38.000000000 +0200 +@@ -4,7 +4,7 @@ + # create a compressed vmlinux image from the original vmlinux + # + +-tragets := head.o lzma_misc.o piggy.o \ ++targets := head.o lzma_misc.o piggy.o \ + vmlinux.bin.all vmlinux.relocs \ + vmlinux vmlinux.bin vmlinux.bin.gz + EXTRA_AFLAGS := -traditional +diff -rdup linux-2.6.21.5.oorig/scripts/gen_lzma_initramfs_list.sh linux-2.6.21.5/scripts/gen_lzma_initramfs_list.sh +--- linux-2.6.21.5.oorig/scripts/gen_lzma_initramfs_list.sh 2007-07-24 13:08:51.000000000 +0200 ++++ linux-2.6.21.5/scripts/gen_lzma_initramfs_list.sh 2007-07-24 15:12:10.000000000 +0200 +@@ -253,7 +253,7 @@ while [ $# -gt 0 ]; do + shift + ;; + "-s") +- opt="-d16" ++ #opt="-d16" ? what was that supposed to do? + ;; + "-d") # display default initramfs list + default_list="$arg" +@@ -286,7 +286,7 @@ if [ ! -z ${output_file} ]; then + cpio_tfile=${cpio_file} + fi + rm ${cpio_list} +- lzma e ${cpio_tfile} ${output_file} ${opt} ++ lzma -z ${cpio_tfile} ${opt} -c > ${output_file} + [ -z ${cpio_file} ] && rm ${cpio_tfile} + fi + exit 0 +--- linux-2.6.21.5.oorig/arch/i386/boot/compressed/lzma_misc.c 2007-07-24 15:24:44.000000000 +0200 ++++ linux-2.6.21.5/arch/i386/boot/compressed/lzma_misc.c 2007-07-24 17:09:40.000000000 +0200 +@@ -241,7 +241,6 @@ static int lzma_unzip(uch* output) + + static int read_byte(void *object, const unsigned char **buffer, SizeT *bufferSize) + { +- static unsigned int i = 0; + static unsigned char val; + *bufferSize = 1; + val = get_byte(); +--- linux-2.6.21.5.oorig/scripts/Makefile.lib 2007-07-24 15:24:44.000000000 +0200 ++++ linux-2.6.21.5/scripts/Makefile.lib 2007-07-24 18:03:57.000000000 +0200 +@@ -165,6 +165,7 @@ cmd_gzip = gzip -f -9 < $< > $@ + # LZMA + # + quiet_cmd_lzma = LZMA $@ +-cmd_lzma = lzma e $< $@ -lc7 -lp0 -pb0 2>/dev/null ++#cmd_lzma = lzma e $< $@ -lc7 -lp0 -pb0 2>/dev/null ++cmd_lzma = lzma -z $< -c > $@ + + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-001-lzma-vmlinuz.00.patch b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-001-lzma-vmlinuz.00.patch new file mode 100644 index 0000000000..16f9ef7417 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-001-lzma-vmlinuz.00.patch @@ -0,0 +1,26856 @@ +diff -rduNp linux-2.6.22.1.oorig/.miniconfig linux-2.6.22.1/.miniconfig +--- linux-2.6.22.1.oorig/.miniconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/.miniconfig 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,89 @@ ++#make allnoconfig KCONFIG_ALLCONFIG=miniconfig ++CONFIG_X86_32=y ++CONFIG_CLOCKSOURCE_WATCHDOG=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_SEMAPHORE_SLEEPERS=y ++CONFIG_MMU=y ++CONFIG_GENERIC_ISA_DMA=y ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_DMI=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_SYSFS_DEPRECATED=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_SYSCTL=y ++CONFIG_EMBEDDED=y ++CONFIG_PRINTK=y ++CONFIG_BASE_SMALL=1 ++CONFIG_BLOCK=y ++CONFIG_IOSCHED_NOOP=y ++CONFIG_DEFAULT_IOSCHED="noop" ++CONFIG_X86_GENERIC=y ++CONFIG_X86_L1_CACHE_SHIFT=7 ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_X86_WP_WORKS_OK=y ++CONFIG_X86_BSWAP=y ++CONFIG_X86_CMPXCHG64=y ++CONFIG_X86_INTEL_USERCOPY=y ++CONFIG_X86_TSC=y ++CONFIG_PREEMPT_NONE=y ++CONFIG_VM86=y ++CONFIG_HIGHMEM=y ++CONFIG_FLATMEM=y ++CONFIG_MTRR=y ++CONFIG_HZ_250=y ++CONFIG_PHYSICAL_ALIGN=0x100000 ++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y ++CONFIG_PM=y ++CONFIG_ACPI=y ++CONFIG_ACPI_SLEEP=y ++CONFIG_ACPI_BLACKLIST_YEAR=0 ++CONFIG_ACPI_EC=y ++CONFIG_ACPI_SYSTEM=y ++CONFIG_PCI=y ++CONFIG_PCI_GOANY=y ++CONFIG_PCI_DIRECT=y ++CONFIG_BINFMT_ELF=y ++CONFIG_STANDALONE=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_IDE=y ++CONFIG_IDE_MAX_HWIFS=2 ++CONFIG_BLK_DEV_IDE=y ++CONFIG_BLK_DEV_IDEDISK=y ++CONFIG_IDEDISK_MULTI_MODE=y ++CONFIG_BLK_DEV_IDECD=y ++CONFIG_IDE_GENERIC=y ++CONFIG_INPUT_MOUSEDEV=y ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 ++CONFIG_INPUT_KEYBOARD=y ++CONFIG_KEYBOARD_ATKBD=y ++CONFIG_SERIO=y ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_UNIX98_PTYS=y ++CONFIG_VGA_CONSOLE=y ++CONFIG_USB_ARCH_HAS_HCD=y ++CONFIG_USB_ARCH_HAS_EHCI=y ++CONFIG_EXT2_FS=y ++CONFIG_DNOTIFY=y ++CONFIG_ISO9660_FS=y ++CONFIG_FAT_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++CONFIG_PROC_FS=y ++CONFIG_PROC_SYSCTL=y ++CONFIG_SYSFS=y ++CONFIG_RAMFS=y ++CONFIG_SQUASHFS=y ++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 ++CONFIG_MSDOS_PARTITION=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_AUFS=y ++CONFIG_AUFS_FAKE_DM=y ++CONFIG_EARLY_PRINTK=y ++CONFIG_DOUBLEFAULT=y ++CONFIG_ZLIB_INFLATE=y ++CONFIG_HAS_IOPORT=y ++CONFIG_GENERIC_IRQ_PROBE=y ++CONFIG_KTIME_SCALAR=y +diff -rduNp linux-2.6.22.1.oorig/Makefile linux-2.6.22.1/Makefile +--- linux-2.6.22.1.oorig/Makefile 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/Makefile 2007-07-24 14:17:46.000000000 +0200 +@@ -188,7 +188,7 @@ CROSS_COMPILE ?= + # Architecture as present in compile.h + UTS_MACHINE := $(ARCH) + +-KCONFIG_CONFIG ?= .config ++KCONFIG_CONFIG ?= .miniconfig + + # SHELL used by kbuild + CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ +diff -rduNp linux-2.6.22.1.oorig/arch/i386/boot/compressed/LzmaDecode.c linux-2.6.22.1/arch/i386/boot/compressed/LzmaDecode.c +--- linux-2.6.22.1.oorig/arch/i386/boot/compressed/LzmaDecode.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/arch/i386/boot/compressed/LzmaDecode.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,588 @@ ++/* ++ LzmaDecode.c ++ LZMA Decoder (optimized for Speed version) ++ ++ LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this Code, expressly permits you to ++ statically or dynamically link your Code (or bind by name) to the ++ interfaces of this file without subjecting your linked Code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#include "LzmaDecode.h" ++ ++#ifndef Byte ++#define Byte unsigned char ++#endif ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_READ_BYTE (*Buffer++) ++ ++#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ ++ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} ++ ++#ifdef _LZMA_IN_CB ++ ++#define RC_TEST { if (Buffer == BufferLim) \ ++ { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \ ++ BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }} ++ ++#define RC_INIT Buffer = BufferLim = 0; RC_INIT2 ++ ++#else ++ ++#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } ++ ++#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 ++ ++#endif ++ ++#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } ++ ++#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) ++#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; ++#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; ++ ++#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ ++ { UpdateBit0(p); mi <<= 1; A0; } else \ ++ { UpdateBit1(p); mi = (mi + mi) + 1; A1; } ++ ++#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) ++ ++#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ ++ { int i = numLevels; res = 1; \ ++ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \ ++ res -= (1 << numLevels); } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) ++{ ++ unsigned char prop0; ++ if (size < LZMA_PROPERTIES_SIZE) ++ return LZMA_RESULT_DATA_ERROR; ++ prop0 = propsData[0]; ++ if (prop0 >= (9 * 5 * 5)) ++ return LZMA_RESULT_DATA_ERROR; ++ { ++ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); ++ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); ++ propsRes->lc = prop0; ++ /* ++ unsigned char remainder = (unsigned char)(prop0 / 9); ++ propsRes->lc = prop0 % 9; ++ propsRes->pb = remainder / 5; ++ propsRes->lp = remainder % 5; ++ */ ++ } ++ ++ #ifdef _LZMA_OUT_READ ++ { ++ int i; ++ propsRes->DictionarySize = 0; ++ for (i = 0; i < 4; i++) ++ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); ++ if (propsRes->DictionarySize == 0) ++ propsRes->DictionarySize = 1; ++ } ++ #endif ++ return LZMA_RESULT_OK; ++} ++ ++#define kLzmaStreamWasFinishedId (-1) ++ ++int LzmaDecode(CLzmaDecoderState *vs, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *InCallback, ++ #else ++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, ++ #endif ++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) ++{ ++ CProb *p = vs->Probs; ++ SizeT nowPos = 0; ++ Byte previousByte = 0; ++ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; ++ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; ++ int lc = vs->Properties.lc; ++ ++ #ifdef _LZMA_OUT_READ ++ ++ UInt32 Range = vs->Range; ++ UInt32 Code = vs->Code; ++ #ifdef _LZMA_IN_CB ++ const Byte *Buffer = vs->Buffer; ++ const Byte *BufferLim = vs->BufferLim; ++ #else ++ const Byte *Buffer = inStream; ++ const Byte *BufferLim = inStream + inSize; ++ #endif ++ int state = vs->State; ++ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; ++ int len = vs->RemainLen; ++ UInt32 globalPos = vs->GlobalPos; ++ UInt32 distanceLimit = vs->DistanceLimit; ++ ++ Byte *dictionary = vs->Dictionary; ++ UInt32 dictionarySize = vs->Properties.DictionarySize; ++ UInt32 dictionaryPos = vs->DictionaryPos; ++ ++ Byte tempDictionary[4]; ++ ++ #ifndef _LZMA_IN_CB ++ *inSizeProcessed = 0; ++ #endif ++ *outSizeProcessed = 0; ++ if (len == kLzmaStreamWasFinishedId) ++ return LZMA_RESULT_OK; ++ ++ if (dictionarySize == 0) ++ { ++ dictionary = tempDictionary; ++ dictionarySize = 1; ++ tempDictionary[0] = vs->TempDictionary[0]; ++ } ++ ++ if (len == kLzmaNeedInitId) ++ { ++ { ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); ++ UInt32 i; ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ rep0 = rep1 = rep2 = rep3 = 1; ++ state = 0; ++ globalPos = 0; ++ distanceLimit = 0; ++ dictionaryPos = 0; ++ dictionary[dictionarySize - 1] = 0; ++ #ifdef _LZMA_IN_CB ++ RC_INIT; ++ #else ++ RC_INIT(inStream, inSize); ++ #endif ++ } ++ len = 0; ++ } ++ while(len != 0 && nowPos < outSize) ++ { ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ len--; ++ } ++ if (dictionaryPos == 0) ++ previousByte = dictionary[dictionarySize - 1]; ++ else ++ previousByte = dictionary[dictionaryPos - 1]; ++ ++ #else /* if !_LZMA_OUT_READ */ ++ ++ int state = 0; ++ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; ++ int len = 0; ++ const Byte *Buffer; ++ const Byte *BufferLim; ++ UInt32 Range; ++ UInt32 Code; ++ ++ #ifndef _LZMA_IN_CB ++ *inSizeProcessed = 0; ++ #endif ++ *outSizeProcessed = 0; ++ ++ { ++ UInt32 i; ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ } ++ ++ #ifdef _LZMA_IN_CB ++ RC_INIT; ++ #else ++ RC_INIT(inStream, inSize); ++ #endif ++ ++ #endif /* _LZMA_OUT_READ */ ++ ++ while(nowPos < outSize) ++ { ++ CProb *prob; ++ UInt32 bound; ++ int posState = (int)( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & posStateMask); ++ ++ prob = p + IsMatch + (state << kNumPosBitsMax) + posState; ++ IfBit0(prob) ++ { ++ int symbol = 1; ++ UpdateBit0(prob) ++ prob = p + Literal + (LZMA_LIT_SIZE * ++ ((( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & literalPosMask) << lc) + (previousByte >> (8 - lc)))); ++ ++ if (state >= kNumLitStates) ++ { ++ int matchByte; ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ matchByte = dictionary[pos]; ++ #else ++ matchByte = outStream[nowPos - rep0]; ++ #endif ++ do ++ { ++ int bit; ++ CProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & 0x100); ++ probLit = prob + 0x100 + bit + symbol; ++ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) ++ } ++ while (symbol < 0x100); ++ } ++ while (symbol < 0x100) ++ { ++ CProb *probLit = prob + symbol; ++ RC_GET_BIT(probLit, symbol) ++ } ++ previousByte = (Byte)symbol; ++ ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit < dictionarySize) ++ distanceLimit++; ++ ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #endif ++ if (state < 4) state = 0; ++ else if (state < 10) state -= 3; ++ else state -= 6; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRep + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ state = state < kNumLitStates ? 0 : 3; ++ prob = p + LenCoder; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRepG0 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IfBit0(prob) ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos; ++ #endif ++ UpdateBit0(prob); ++ ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit == 0) ++ #else ++ if (nowPos == 0) ++ #endif ++ return LZMA_RESULT_DATA_ERROR; ++ ++ state = state < kNumLitStates ? 9 : 11; ++ #ifdef _LZMA_OUT_READ ++ pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit < dictionarySize) ++ distanceLimit++; ++ #endif ++ ++ continue; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ } ++ } ++ else ++ { ++ UInt32 distance; ++ UpdateBit1(prob); ++ prob = p + IsRepG1 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRepG2 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = p + RepLenCoder; ++ } ++ { ++ int numBits, offset; ++ CProb *probLen = prob + LenChoice; ++ IfBit0(probLen) ++ { ++ UpdateBit0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ numBits = kLenNumLowBits; ++ } ++ else ++ { ++ UpdateBit1(probLen); ++ probLen = prob + LenChoice2; ++ IfBit0(probLen) ++ { ++ UpdateBit0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ numBits = kLenNumMidBits; ++ } ++ else ++ { ++ UpdateBit1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ numBits = kLenNumHighBits; ++ } ++ } ++ RangeDecoderBitTreeDecode(probLen, numBits, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ int posSlot; ++ state += kNumLitStates; ++ prob = p + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ rep0 = (2 | ((UInt32)posSlot & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ rep0 <<= numDirectBits; ++ prob = p + SpecPos + rep0 - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ RC_NORMALIZE ++ Range >>= 1; ++ rep0 <<= 1; ++ if (Code >= Range) ++ { ++ Code -= Range; ++ rep0 |= 1; ++ } ++ } ++ while (--numDirectBits != 0); ++ prob = p + Align; ++ rep0 <<= kNumAlignBits; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ int i = 1; ++ int mi = 1; ++ do ++ { ++ CProb *prob3 = prob + mi; ++ RC_GET_BIT2(prob3, mi, ; , rep0 |= i); ++ i <<= 1; ++ } ++ while(--numDirectBits != 0); ++ } ++ } ++ else ++ rep0 = posSlot; ++ if (++rep0 == (UInt32)(0)) ++ { ++ /* it's for stream version */ ++ len = kLzmaStreamWasFinishedId; ++ break; ++ } ++ } ++ ++ len += kMatchMinLen; ++ #ifdef _LZMA_OUT_READ ++ if (rep0 > distanceLimit) ++ #else ++ if (rep0 > nowPos) ++ #endif ++ return LZMA_RESULT_DATA_ERROR; ++ ++ #ifdef _LZMA_OUT_READ ++ if (dictionarySize - distanceLimit > (UInt32)len) ++ distanceLimit += len; ++ else ++ distanceLimit = dictionarySize; ++ #endif ++ ++ do ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ len--; ++ outStream[nowPos++] = previousByte; ++ } ++ while(len != 0 && nowPos < outSize); ++ } ++ } ++ RC_NORMALIZE; ++ ++ #ifdef _LZMA_OUT_READ ++ vs->Range = Range; ++ vs->Code = Code; ++ vs->DictionaryPos = dictionaryPos; ++ vs->GlobalPos = globalPos + (UInt32)nowPos; ++ vs->DistanceLimit = distanceLimit; ++ vs->Reps[0] = rep0; ++ vs->Reps[1] = rep1; ++ vs->Reps[2] = rep2; ++ vs->Reps[3] = rep3; ++ vs->State = state; ++ vs->RemainLen = len; ++ vs->TempDictionary[0] = tempDictionary[0]; ++ #endif ++ ++ #ifdef _LZMA_IN_CB ++ vs->Buffer = Buffer; ++ vs->BufferLim = BufferLim; ++ #else ++ *inSizeProcessed = (SizeT)(Buffer - inStream); ++ #endif ++ *outSizeProcessed = nowPos; ++ return LZMA_RESULT_OK; ++} +diff -rduNp linux-2.6.22.1.oorig/arch/i386/boot/compressed/LzmaDecode.h linux-2.6.22.1/arch/i386/boot/compressed/LzmaDecode.h +--- linux-2.6.22.1.oorig/arch/i386/boot/compressed/LzmaDecode.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/arch/i386/boot/compressed/LzmaDecode.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,131 @@ ++/* ++ LzmaDecode.h ++ LZMA Decoder interface ++ ++ LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this code, expressly permits you to ++ statically or dynamically link your code (or bind by name) to the ++ interfaces of this file without subjecting your linked code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#ifndef __LZMADECODE_H ++#define __LZMADECODE_H ++ ++/* #define _LZMA_IN_CB */ ++/* Use callback for input data */ ++ ++/* #define _LZMA_OUT_READ */ ++/* Use read function for output data */ ++ ++/* #define _LZMA_PROB32 */ ++/* It can increase speed on some 32-bit CPUs, ++ but memory usage will be doubled in that case */ ++ ++/* #define _LZMA_LOC_OPT */ ++/* Enable local speed optimizations inside code */ ++ ++/* #define _LZMA_SYSTEM_SIZE_T */ ++/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/ ++ ++#ifndef UInt32 ++#ifdef _LZMA_UINT32_IS_ULONG ++#define UInt32 unsigned long ++#else ++#define UInt32 unsigned int ++#endif ++#endif ++ ++#ifndef SizeT ++#ifdef _LZMA_SYSTEM_SIZE_T ++#include ++#define SizeT size_t ++#else ++#define SizeT UInt32 ++#endif ++#endif ++ ++#ifdef _LZMA_PROB32 ++#define CProb UInt32 ++#else ++#define CProb unsigned short ++#endif ++ ++#define LZMA_RESULT_OK 0 ++#define LZMA_RESULT_DATA_ERROR 1 ++ ++#ifdef _LZMA_IN_CB ++typedef struct _ILzmaInCallback ++{ ++ int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize); ++} ILzmaInCallback; ++#endif ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LZMA_PROPERTIES_SIZE 5 ++ ++typedef struct _CLzmaProperties ++{ ++ int lc; ++ int lp; ++ int pb; ++ #ifdef _LZMA_OUT_READ ++ UInt32 DictionarySize; ++ #endif ++}CLzmaProperties; ++ ++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); ++ ++#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) ++ ++#define kLzmaNeedInitId (-2) ++ ++typedef struct _CLzmaDecoderState ++{ ++ CLzmaProperties Properties; ++ CProb *Probs; ++ ++ #ifdef _LZMA_IN_CB ++ const unsigned char *Buffer; ++ const unsigned char *BufferLim; ++ #endif ++ ++ #ifdef _LZMA_OUT_READ ++ unsigned char *Dictionary; ++ UInt32 Range; ++ UInt32 Code; ++ UInt32 DictionaryPos; ++ UInt32 GlobalPos; ++ UInt32 DistanceLimit; ++ UInt32 Reps[4]; ++ int State; ++ int RemainLen; ++ unsigned char TempDictionary[4]; ++ #endif ++} CLzmaDecoderState; ++ ++#ifdef _LZMA_OUT_READ ++#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; } ++#endif ++ ++int LzmaDecode(CLzmaDecoderState *vs, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback, ++ #else ++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, ++ #endif ++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); ++ ++#endif +diff -rduNp linux-2.6.22.1.oorig/arch/i386/boot/compressed/Makefile linux-2.6.22.1/arch/i386/boot/compressed/Makefile +--- linux-2.6.22.1.oorig/arch/i386/boot/compressed/Makefile 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/arch/i386/boot/compressed/Makefile 2007-07-24 14:17:46.000000000 +0200 +@@ -4,15 +4,16 @@ + # create a compressed vmlinux image from the original vmlinux + # + +-targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o \ +- vmlinux.bin.all vmlinux.relocs ++tragets := head.o lzma_misc.o piggy.o \ ++ vmlinux.bin.all vmlinux.relocs \ ++ vmlinux vmlinux.bin vmlinux.bin.gz + EXTRA_AFLAGS := -traditional + + LDFLAGS_vmlinux := -T +-CFLAGS_misc.o += -fPIC ++CFLAGS_lzma_misc.o += -fPIC + hostprogs-y := relocs + +-$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE ++$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/lzma_misc.o $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +@@ -33,10 +34,10 @@ $(obj)/vmlinux.bin.all: $(vmlinux.bin.al + + ifdef CONFIG_RELOCATABLE + $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE +- $(call if_changed,gzip) ++ $(call if_changed,lzma) + else + $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE +- $(call if_changed,gzip) ++ $(call if_changed,lzma) + endif + + LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T +diff -rduNp linux-2.6.22.1.oorig/arch/i386/boot/compressed/lzma_misc.c linux-2.6.22.1/arch/i386/boot/compressed/lzma_misc.c +--- linux-2.6.22.1.oorig/arch/i386/boot/compressed/lzma_misc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/arch/i386/boot/compressed/lzma_misc.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,290 @@ ++/* ++ * lzma_misc.c ++ * ++ * Decompress LZMA compressed vmlinuz ++ * Version 0.9 Copyright (c) Ming-Ching Tiew mctiew@yahoo.com ++ * Program adapted from misc.c for 2.6.20.1 kernel ++ * Please refer to misc.c for authorship and copyright. ++ * Date: 25 March 2007 ++ * Source released under GPL ++ */ ++ ++#undef CONFIG_PARAVIRT ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* WARNING!! ++ * This code is compiled with -fPIC and it is relocated dynamically ++ * at run time, but no relocation processing is performed. ++ * This means that it is not safe to place pointers in static structures. ++ */ ++ ++#define OF(args) args ++#define STATIC static ++ ++#undef memset ++#undef memcpy ++ ++typedef unsigned char uch; ++typedef unsigned short ush; ++typedef unsigned long ulg; ++ ++#define WSIZE 0x80000000 /* Window size must be at least 32k, ++ * and a power of two ++ * We don't actually have a window just ++ * a huge output buffer so I report ++ * a 2G windows size, as that should ++ * always be larger than our output buffer. ++ */ ++ ++static uch *inbuf; /* input buffer */ ++static uch *window; /* Sliding window buffer, (and final output buffer) */ ++ ++static unsigned insize; /* valid bytes in inbuf */ ++static unsigned inptr; /* index of next byte to be processed in inbuf */ ++ ++/* gzip flag byte */ ++#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ ++#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ ++#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ ++#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ ++#define COMMENT 0x10 /* bit 4 set: file comment present */ ++#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ ++#define RESERVED 0xC0 /* bit 6,7: reserved */ ++ ++#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) ++ ++/* Diagnostic functions */ ++#ifdef DEBUG ++# define Assert(cond,msg) {if(!(cond)) error(msg);} ++# define Trace(x) fprintf x ++# define Tracev(x) {if (verbose) fprintf x ;} ++# define Tracevv(x) {if (verbose>1) fprintf x ;} ++# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} ++# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} ++#else ++# define Assert(cond,msg) ++# define Trace(x) ++# define Tracev(x) ++# define Tracevv(x) ++# define Tracec(c,x) ++# define Tracecv(c,x) ++#endif ++ ++static int fill_inbuf(void); ++static void error(char *m); ++ ++/* ++ * This is set up by the setup-routine at boot-time ++ */ ++static unsigned char *real_mode; /* Pointer to real-mode data */ ++ ++#define RM_EXT_MEM_K (*(unsigned short *)(real_mode + 0x2)) ++#ifndef STANDARD_MEMORY_BIOS_CALL ++#define RM_ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0)) ++#endif ++#define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0)) ++ ++extern unsigned char input_data[]; ++extern int input_len; ++ ++static long bytes_out = 0; ++ ++static void *memcpy(void *dest, const void *src, unsigned n); ++ ++static void putstr(const char *); ++ ++static unsigned long free_mem_ptr; ++static unsigned long free_mem_end_ptr; ++ ++#define HEAP_SIZE 0x3000 ++ ++static char *vidmem = (char *)0xb8000; ++static int vidport; ++static int lines, cols; ++ ++#ifdef CONFIG_X86_NUMAQ ++void *xquad_portio; ++#endif ++ ++static void scroll(void) ++{ ++ int i; ++ ++ memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); ++ for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) ++ vidmem[i] = ' '; ++} ++ ++static void putstr(const char *s) ++{ ++ int x,y,pos; ++ char c; ++ ++ x = RM_SCREEN_INFO.orig_x; ++ y = RM_SCREEN_INFO.orig_y; ++ ++ while ( ( c = *s++ ) != '\0' ) { ++ if ( c == '\n' ) { ++ x = 0; ++ if ( ++y >= lines ) { ++ scroll(); ++ y--; ++ } ++ } else { ++ vidmem [ ( x + cols * y ) * 2 ] = c; ++ if ( ++x >= cols ) { ++ x = 0; ++ if ( ++y >= lines ) { ++ scroll(); ++ y--; ++ } ++ } ++ } ++ } ++ ++ RM_SCREEN_INFO.orig_x = x; ++ RM_SCREEN_INFO.orig_y = y; ++ ++ pos = (x + cols * y) * 2; /* Update cursor position */ ++ outb_p(14, vidport); ++ outb_p(0xff & (pos >> 9), vidport+1); ++ outb_p(15, vidport); ++ outb_p(0xff & (pos >> 1), vidport+1); ++} ++ ++static void* memcpy(void* dest, const void* src, unsigned n) ++{ ++ int i; ++ char *d = (char *)dest, *s = (char *)src; ++ ++ for (i=0;i ((-__PAGE_OFFSET-(512 <<20)-1) & 0x7fffffff)) ++ error("Destination address too large"); ++#ifndef CONFIG_RELOCATABLE ++ if ((u32)output != LOAD_PHYSICAL_ADDR) ++ error("Wrong destination address"); ++#endif ++ if( lzma_unzip(output) != 0 ) ++ { ++ error("inflate error\n"); ++ } ++ putstr("Ok, booting the kernel.\n"); ++ ++ return; ++} +diff -rduNp linux-2.6.22.1.oorig/arch/i386/boot/compressed/vmlinux.scr linux-2.6.22.1/arch/i386/boot/compressed/vmlinux.scr +--- linux-2.6.22.1.oorig/arch/i386/boot/compressed/vmlinux.scr 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/arch/i386/boot/compressed/vmlinux.scr 2007-07-24 14:17:46.000000000 +0200 +@@ -3,8 +3,8 @@ SECTIONS + .data.compressed : { + input_len = .; + LONG(input_data_end - input_data) input_data = .; ++ output_len = . + 5; + *(.data) +- output_len = . - 4; + input_data_end = .; + } + } +diff -rduNp linux-2.6.22.1.oorig/drivers/block/Kconfig linux-2.6.22.1/drivers/block/Kconfig +--- linux-2.6.22.1.oorig/drivers/block/Kconfig 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/drivers/block/Kconfig 2007-07-24 14:17:46.000000000 +0200 +@@ -406,6 +406,47 @@ config BLK_DEV_RAM_BLOCKSIZE + setups function - apparently needed by the rd_load_image routine + that supposes the filesystem in the image uses a 1024 blocksize. + ++config LZMA_INITRD ++ boolean "Allow LZMA compression on initrd" ++ depends on BLK_DEV_INITRD=y ++ default "y" ++ help ++ Use lzma compression on initrd, example 'lzma e initrd initrd.7z -d16'. ++ If you have sufficient memory, you could compress using bigger dictionary size, ++ 'lzma e initrd initrd.7z'. ++ ++config LZMA_INITRD_KMALLOC_ONLY ++ boolean "Use only kmalloc, do not use vmalloc on lzma initrd" ++ depends on LZMA_INITRD=y ++ default "n" ++ help ++ Set to y if you do not want to use vmalloc, ie use only kmalloc. ++ ++config LZMA_INITRAM_FS ++ boolean "Allow LZMA compression on initramfs" ++ depends on BLK_DEV_RAM=y ++ default "y" ++ help ++ Use lzma compression on initramfs, example 'lzma e initramfs.cpio initramfs.cpio.lzma'. ++ ++config LZMA_INITRAM_FS_SMALLMEM ++ boolean "Use lzma compression with small dictonary size." ++ depends on LZMA_INITRAM_FS=y ++ default "y" ++ help ++ Use lzma compression on initramfs with small dictionary size, example ++ 'lzma e initramfs.cpio initramfs.cpio.lzma -d16'. ++ Affects only the initramfs.cpio in the ~usr directory, which is compiled into ++ the kernel. If you prepared initramfs.cpio for use with bootloader, you would ++ need to specify the commandline options (-d16) yourself. ++ ++config LZMA_INITRAM_FS_KMALLOC_ONLY ++ boolean "Use only kmalloc, do not use vmalloc on lzma initramfs" ++ depends on LZMA_INITRAM_FS=y ++ default "n" ++ help ++ Set to y if you do not want to use vmalloc, ie use only kmalloc. ++ + config CDROM_PKTCDVD + tristate "Packet writing on CD/DVD media" + depends on !UML +diff -rduNp linux-2.6.22.1.oorig/fs/Kconfig linux-2.6.22.1/fs/Kconfig +--- linux-2.6.22.1.oorig/fs/Kconfig 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/fs/Kconfig 2007-07-24 14:17:46.000000000 +0200 +@@ -1367,6 +1367,71 @@ config CRAMFS + + If unsure, say N. + ++config SQUASHFS ++ tristate "SquashFS 3.2 - Squashed file system support" ++ select ZLIB_INFLATE ++ help ++ Saying Y here includes support for SquashFS 3.2 (a Compressed Read-Only File ++ System). Squashfs is a highly compressed read-only filesystem for Linux. ++ It uses zlib compression to compress both files, inodes and directories. ++ Inodes in the system are very small and all blocks are packed to minimise ++ data overhead. Block sizes greater than 4K are supported up to a maximum of 64K. ++ SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full ++ uid/gid information, hard links and timestamps. ++ ++ Squashfs is intended for general read-only filesystem use, for archival ++ use (i.e. in cases where a .tar.gz file may be used), and in embedded ++ systems where low overhead is needed. Further information and filesystem tools ++ are available from http://squashfs.sourceforge.net. ++ ++ If you want to compile this as a module ( = code which can be ++ inserted in and removed from the running kernel whenever you want), ++ say M here and read . The module ++ will be called squashfs. Note that the root file system (the one ++ containing the directory /) cannot be compiled as a module. ++ ++ If unsure, say N. ++ ++config SQUASHFS_EMBEDDED ++ ++ bool "Additional options for memory-constrained systems" ++ depends on SQUASHFS ++ default n ++ help ++ Saying Y here allows you to specify cache sizes and how Squashfs ++ allocates memory. This is only intended for memory constrained ++ systems. ++ ++ If unsure, say N. ++ ++config SQUASHFS_FRAGMENT_CACHE_SIZE ++ int "Number of fragments cached" if SQUASHFS_EMBEDDED ++ depends on SQUASHFS ++ default "3" ++ help ++ By default SquashFS caches the last 3 fragments read from ++ the filesystem. Increasing this amount may mean SquashFS ++ has to re-read fragments less often from disk, at the expense ++ of extra system memory. Decreasing this amount will mean ++ SquashFS uses less memory at the expense of extra reads from disk. ++ ++ Note there must be at least one cached fragment. Anything ++ much more than three will probably not make much difference. ++ ++config SQUASHFS_VMALLOC ++ bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED ++ depends on SQUASHFS ++ default n ++ help ++ By default SquashFS uses kmalloc to obtain fragment cache memory. ++ Kmalloc memory is the standard kernel allocator, but it can fail ++ on memory constrained systems. Because of the way Vmalloc works, ++ Vmalloc can succeed when kmalloc fails. Specifying this option ++ will make SquashFS always use Vmalloc to allocate the ++ fragment cache memory. ++ ++ If unsure, say N. ++ + config VXFS_FS + tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" + depends on BLOCK +@@ -2072,3 +2137,4 @@ source "fs/dlm/Kconfig" + + endmenu + ++source "fs/aufs/Kconfig" +diff -rduNp linux-2.6.22.1.oorig/fs/Makefile linux-2.6.22.1/fs/Makefile +--- linux-2.6.22.1.oorig/fs/Makefile 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/fs/Makefile 2007-07-24 14:17:46.000000000 +0200 +@@ -72,6 +72,7 @@ obj-$(CONFIG_JBD) += jbd/ + obj-$(CONFIG_JBD2) += jbd2/ + obj-$(CONFIG_EXT2_FS) += ext2/ + obj-$(CONFIG_CRAMFS) += cramfs/ ++obj-$(CONFIG_SQUASHFS) += squashfs/ + obj-$(CONFIG_RAMFS) += ramfs/ + obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ + obj-$(CONFIG_CODA_FS) += coda/ +@@ -118,3 +119,4 @@ obj-$(CONFIG_HPPFS) += hppfs/ + obj-$(CONFIG_DEBUG_FS) += debugfs/ + obj-$(CONFIG_OCFS2_FS) += ocfs2/ + obj-$(CONFIG_GFS2_FS) += gfs2/ ++obj-$(CONFIG_AUFS) += aufs/ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/Kconfig linux-2.6.22.1/fs/aufs/Kconfig +--- linux-2.6.22.1.oorig/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/Kconfig 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,73 @@ ++config AUFS ++ tristate "Another unionfs" ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. After many original ++ ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ See Unionfs for the basic features. ++ ++if AUFS ++comment "These options are generated automatically for "#UTS_RELEASE ++ ++config AUFS_FAKE_DM ++ bool "Use simplified (fake) nameidata" ++ depends on AUFS ++ default y ++ help ++ Faking nameidata (VFS internal data), you can get better performance ++ in some cases. ++ ++choice ++ prompt "Maximum number of branches" ++ depends on AUFS ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++ ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. ++endchoice ++config AUFS_DEBUG ++ bool "Debug aufs" ++ depends on AUFS ++ default y ++ help ++ Enable this to compile aufs internal debug code. ++ The performance will be damaged. ++ ++config AUFS_COMPAT ++ bool "Compatibility with Unionfs (obsolete)" ++ depends on AUFS ++ default n ++ help ++ This makes aufs compatible with unionfs-style mount options and some ++ behaviours. ++ The dirs= mount option and =nfsro branch permission flag are always ++ interpreted as br: mount option and =ro flag respectively. The ++ 'debug', 'delete' and 'imap' mount options are ignored. ++ If you disable this option, you will get, ++ - aufs issues a warning about the ignored mount options ++ - the default branch permission flag is set. RW for the first branch, ++ and RO for the rests. ++ - the name of a internal file which represents the directory is ++ 'opaque', becomes '.wh..wh..opq' ++ - the 'diropq=w' mount option is set by default ++endif +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/Makefile linux-2.6.22.1/fs/aufs/Makefile +--- linux-2.6.22.1.oorig/fs/aufs/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/Makefile 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,18 @@ ++# AUFS Makefile for the Linux 2.6.16 and later ++# $Id: Makefile,v 1.29 2007/04/23 00:59:50 sfjro Exp $ ++ ++obj-$(CONFIG_AUFS) += aufs.o ++aufs-y := module.o super.o sbinfo.o xino.o \ ++ branch.o cpup.o whout.o plink.o wkq.o dcsub.o vfsub.o \ ++ opts.o \ ++ dentry.o dinfo.o \ ++ file.o f_op.o finfo.o \ ++ dir.o vdir.o \ ++ inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o iinfo.o \ ++ misc.o ++#xattr.o ++aufs-$(CONFIG_AUFS_SYSAUFS) += sysaufs.o ++aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++#aufs-$(CONFIG_DEBUGFS) += dbgfs.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/aufs.h linux-2.6.22.1/fs/aufs/aufs.h +--- linux-2.6.22.1.oorig/fs/aufs/aufs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/aufs.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: aufs.h,v 1.24 2007/05/14 03:41:51 sfjro Exp $ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* limited support before 2.6.16, curretly 2.6.15 only. */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++#define atomic_long_t atomic_t ++#define atomic_long_set atomic_set ++#define timespec_to_ns(ts) ({(long long)(ts)->tv_sec;}) ++#define D_CHILD d_child ++#else ++#define D_CHILD d_u.d_child ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "inode.h" ++#include "misc.h" ++#include "module.h" ++#include "opts.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++//#include "xattr.h" ++ ++#if defined(CONFIG_AUFS_MODULE) && !defined(CONFIG_AUFS_KSIZE_PATCH) ++#define ksize(p) (-1U) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/branch.c linux-2.6.22.1/fs/aufs/branch.c +--- linux-2.6.22.1.oorig/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/branch.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,818 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: branch.c,v 1.49 2007/05/14 03:38:23 sfjro Exp $ */ ++ ++//#include ++//#include ++#include "aufs.h" ++ ++static void free_branch(struct aufs_branch *br) ++{ ++ TraceEnter(); ++ ++ if (br->br_xino) ++ fput(br->br_xino); ++ dput(br->br_wh); ++ dput(br->br_plink); ++ mntput(br->br_mnt); ++ DEBUG_ON(br_count(br) || atomic_read(&br->br_wh_running)); ++ kfree(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void free_branches(struct aufs_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct aufs_branch **br; ++ ++ TraceEnter(); ++ bmax = sbinfo->si_bend + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ free_branch(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int find_brindex(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ TraceEnter(); ++ ++ bend = sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ++ * test if the @br is readonly or not. ++ */ ++int br_rdonly(struct aufs_branch *br) ++{ ++ return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY) ++ || !br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++/* ++ * returns writable branch index, otherwise an error. ++ * todo: customizable writable-branch-policy ++ */ ++static int find_rw_parent(struct dentry *dentry, aufs_bindex_t bend) ++{ ++ int err; ++ aufs_bindex_t bindex, candidate; ++ struct super_block *sb; ++ struct dentry *parent, *hidden_parent; ++ ++ err = bend; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++#if 1 // branch policy ++ hidden_parent = au_h_dptr_i(parent, bend); ++ if (hidden_parent && !br_rdonly(stobr(sb, bend))) ++ goto out; /* success */ ++#endif ++ ++ candidate = -1; ++ for (bindex = dbstart(parent); bindex <= bend; bindex++) { ++ hidden_parent = au_h_dptr_i(parent, bindex); ++ if (hidden_parent && !br_rdonly(stobr(sb, bindex))) { ++#if 0 // branch policy ++ if (candidate == -1) ++ candidate = bindex; ++ if (!au_test_perm(hidden_parent->d_inode, MAY_WRITE)) ++ return bindex; ++#endif ++ err = bindex; ++ goto out; /* success */ ++ } ++ } ++#if 0 // branch policy ++ err = candidate; ++ if (candidate != -1) ++ goto out; /* success */ ++#endif ++ err = -EROFS; ++ ++ out: ++ dput(parent); ++ return err; ++} ++ ++int find_rw_br(struct super_block *sb, aufs_bindex_t bend) ++{ ++ aufs_bindex_t bindex; ++ ++ for (bindex = bend; bindex >= 0; bindex--) ++ if (!br_rdonly(stobr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++int find_rw_parent_br(struct dentry *dentry, aufs_bindex_t bend) ++{ ++ int err; ++ ++ err = find_rw_parent(dentry, bend); ++ if (err >= 0) ++ return err; ++ return find_rw_br(dentry->d_sb, bend); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if two hidden_dentries have overlapping branches. ++ */ ++//todo: try is_subdir() ++static int do_is_overlap(struct super_block *sb, struct dentry *hidden_d1, ++ struct dentry *hidden_d2) ++{ ++ struct dentry *d; ++ ++ d = hidden_d1; ++ do { ++ if (unlikely(d == hidden_d2)) ++ return 1; ++ d = d->d_parent; // dget_parent() ++ } while (!IS_ROOT(d)); ++ ++ return (d == hidden_d2); ++} ++ ++#if defined(CONFIG_BLK_DEV_LOOP) || defined(CONFIG_BLK_DEV_LOOP_MODULE) ++#include ++static int is_overlap_loopback(struct super_block *sb, struct dentry *hidden_d1, ++ struct dentry *hidden_d2) ++{ ++ struct inode *hidden_inode; ++ struct loop_device *l; ++ ++ hidden_inode = hidden_d1->d_inode; ++ if (MAJOR(hidden_inode->i_sb->s_dev) != LOOP_MAJOR) ++ return 0; ++ ++ l = hidden_inode->i_sb->s_bdev->bd_disk->private_data; ++ hidden_d1 = l->lo_backing_file->f_dentry; ++ if (unlikely(hidden_d1->d_sb == sb)) ++ return 1; ++ return do_is_overlap(sb, hidden_d1, hidden_d2); ++} ++#else ++#define is_overlap_loopback(sb, hidden_d1, hidden_d2) 0 ++#endif ++ ++static int is_overlap(struct super_block *sb, struct dentry *hidden_d1, ++ struct dentry *hidden_d2) ++{ ++ LKTRTrace("d1 %.*s, d2 %.*s\n", DLNPair(hidden_d1), DLNPair(hidden_d2)); ++ if (unlikely(hidden_d1 == hidden_d2)) ++ return 1; ++ return do_is_overlap(sb, hidden_d1, hidden_d2) ++ || do_is_overlap(sb, hidden_d2, hidden_d1) ++ || is_overlap_loopback(sb, hidden_d1, hidden_d2) ++ || is_overlap_loopback(sb, hidden_d2, hidden_d1); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int init_br_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_branch *br, int new_perm, ++ struct dentry *h_root, struct vfsmount *h_mnt) ++{ ++ int err, old_perm; ++ struct inode *dir = sb->s_root->d_inode, ++ *h_dir = h_root->d_inode; ++ const int new = (bindex < 0); ++ ++ LKTRTrace("b%d, new_perm %d\n", bindex, new_perm); ++ ++ if (new) ++ hi_lock_parent(h_dir); ++ else ++ hdir_lock(h_dir, dir, bindex); ++ ++ br_wh_write_lock(br); ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ err = init_wh(h_root, br, au_do_nfsmnt(h_mnt), sb); ++ br->br_perm = old_perm; ++ br_wh_write_unlock(br); ++ ++ if (new) ++ i_unlock(h_dir); ++ else ++ hdir_unlock(h_dir, dir, bindex); ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct aufs_branch *alloc_addbr(struct super_block *sb, int new_nbranch) ++{ ++ struct aufs_branch **branchp, *add_branch; ++ int sz; ++ void *p; ++ struct dentry *root; ++ struct inode *inode; ++ struct aufs_hinode *hinodep; ++ struct aufs_hdentry *hdentryp; ++ ++ LKTRTrace("new_nbranch %d\n", new_nbranch); ++ SiMustWriteLock(sb); ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ inode = root->d_inode; ++ IiMustWriteLock(inode); ++ ++ add_branch = kmalloc(sizeof(*add_branch), GFP_KERNEL); ++ //if (LktrCond) {kfree(add_branch); add_branch = NULL;} ++ if (unlikely(!add_branch)) ++ goto out; ++ ++ sz = sizeof(*branchp) * (new_nbranch - 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*branchp); ++ p = stosi(sb)->si_branch; ++ branchp = au_kzrealloc(p, sz, sizeof(*branchp) * new_nbranch, ++ GFP_KERNEL); ++ //if (LktrCond) branchp = NULL; ++ if (unlikely(!branchp)) ++ goto out; ++ stosi(sb)->si_branch = branchp; ++ ++ sz = sizeof(*hdentryp) * (new_nbranch - 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*hdentryp); ++ p = dtodi(root)->di_hdentry; ++ hdentryp = au_kzrealloc(p, sz, sizeof(*hdentryp) * new_nbranch, ++ GFP_KERNEL); ++ //if (LktrCond) hdentryp = NULL; ++ if (unlikely(!hdentryp)) ++ goto out; ++ dtodi(root)->di_hdentry = hdentryp; ++ ++ sz = sizeof(*hinodep) * (new_nbranch - 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*hinodep); ++ p = itoii(inode)->ii_hinode; ++ hinodep = au_kzrealloc(p, sz, sizeof(*hinodep) * new_nbranch, ++ GFP_KERNEL); ++ //if (LktrCond) hinodep = NULL; // unavailable test ++ if (unlikely(!hinodep)) ++ goto out; ++ itoii(inode)->ii_hinode = hinodep; ++ return add_branch; /* success */ ++ ++ out: ++ kfree(add_branch); ++ TraceErr(-ENOMEM); ++ return ERR_PTR(-ENOMEM); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct super_block *sb, struct inode *inode, int brperm, ++ char *path) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(br_writable(brperm) && IS_RDONLY(inode))) { ++ Err("write permission for readonly fs or inode, %s\n", path); ++ err = -EINVAL; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * retunrs,,, ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct opt_add *add, int remount) ++{ ++ int err; ++ struct dentry *root; ++ struct inode *inode, *hidden_inode; ++ aufs_bindex_t bend, bindex; ++ ++ LKTRTrace("%s, remo%d\n", add->path, remount); ++ ++ root = sb->s_root; ++ if (unlikely(au_find_dbindex(root, add->nd.dentry) != -1)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ Err("%s duplicated\n", add->path); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; //-E2BIG; ++ bend = sbend(sb); ++ //if (LktrCond) bend = AUFS_BRANCH_MAX; ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bend)) { ++ Err("number of branches exceeded %s\n", add->path); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { ++ Err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = add->nd.dentry->d_inode; ++ DEBUG_ON(!inode || !S_ISDIR(inode->i_mode)); ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ Err("no existence %s\n", add->path); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ Err("%s must be outside\n", add->path); ++ goto out; ++ } ++ ++#if 1 //ndef CONFIG_AUFS_ROBR ++ if (unlikely(au_is_aufs(inode->i_sb) ++ || !strcmp(au_sbtype(inode->i_sb), "unionfs"))) { ++ Err("nested " AUFS_NAME " %s\n", add->path); ++ goto out; ++ } ++#endif ++ ++#ifdef AuNoNfsBranch ++ if (unlikely(au_is_nfs(inode->i_sb))) { ++ Err(AuNoNfsBranchMsg ". %s\n", add->path); ++ goto out; ++ } ++#endif ++ ++ err = test_br(sb, add->nd.dentry->d_inode, add->perm, add->path); ++ if (unlikely(err)) ++ goto out; ++ ++ if (unlikely(bend == -1)) ++ return 0; /* success */ ++ ++ hidden_inode = au_h_dptr(root)->d_inode; ++ if (unlikely(au_flag_test(sb, AuFlag_WARN_PERM) ++ && ((hidden_inode->i_mode & S_IALLUGO) ++ != (inode->i_mode & S_IALLUGO) ++ || hidden_inode->i_uid != inode->i_uid ++ || hidden_inode->i_gid != inode->i_gid))) ++ Warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->path, ++ inode->i_uid, inode->i_gid, (inode->i_mode & S_IALLUGO), ++ hidden_inode->i_uid, hidden_inode->i_gid, ++ (hidden_inode->i_mode & S_IALLUGO)); ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (unlikely(is_overlap(sb, add->nd.dentry, ++ au_h_dptr_i(root, bindex)))) { ++ Err("%s is overlapped\n", add->path); ++ goto out; ++ } ++ err = 0; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++int br_add(struct super_block *sb, struct opt_add *add, int remount) ++{ ++ int err, sz; ++ aufs_bindex_t bend, add_bindex; ++ struct dentry *root; ++ struct aufs_iinfo *iinfo; ++ struct aufs_sbinfo *sbinfo; ++ struct aufs_dinfo *dinfo; ++ struct inode *root_inode; ++ unsigned long long maxb; ++ struct aufs_branch **branchp, *add_branch; ++ struct aufs_hdentry *hdentryp; ++ struct aufs_hinode *hinodep; ++ ++ LKTRTrace("b%d, %s, 0x%x, %.*s\n", add->bindex, add->path, ++ add->perm, DLNPair(add->nd.dentry)); ++ SiMustWriteLock(sb); ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ root_inode = root->d_inode; ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (unlikely(err)) ++ return 0; /* success */ ++ ++ bend = sbend(sb); ++ add_branch = alloc_addbr(sb, bend + 2); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = 0; ++ rw_init_nolock(&add_branch->br_wh_rwsem); ++ add_branch->br_wh = add_branch->br_plink = NULL; ++ if (unlikely(br_writable(add->perm))) { ++ err = init_br_wh(sb, /*bindex*/-1, add_branch, add->perm, ++ add->nd.dentry, add->nd.mnt); ++ if (unlikely(err)) { ++ kfree(add_branch); ++ goto out; ++ } ++ } ++ add_branch->br_xino = NULL; ++ add_branch->br_mnt = mntget(add->nd.mnt); ++ atomic_set(&add_branch->br_wh_running, 0); ++ add_branch->br_id = new_br_id(sb); ++ add_branch->br_perm = add->perm; ++ atomic_set(&add_branch->br_count, 0); ++ ++ sbinfo = stosi(sb); ++ dinfo = dtodi(root); ++ iinfo = itoii(root_inode); ++ ++ add_bindex = add->bindex; ++ sz = sizeof(*(sbinfo->si_branch)) * (bend + 1 - add_bindex); ++ branchp = sbinfo->si_branch + add_bindex; ++ memmove(branchp + 1, branchp, sz); ++ *branchp = add_branch; ++ sz = sizeof(*hdentryp) * (bend + 1 - add_bindex); ++ hdentryp = dinfo->di_hdentry + add_bindex; ++ memmove(hdentryp + 1, hdentryp, sz); ++ hdentryp->hd_dentry = NULL; ++ sz = sizeof(*hinodep) * (bend + 1 - add_bindex); ++ hinodep = iinfo->ii_hinode + add_bindex; ++ memmove(hinodep + 1, hinodep, sz); ++ hinodep->hi_inode = NULL; ++ hinodep->hi_notify = NULL; ++ ++ sbinfo->si_bend++; ++ dinfo->di_bend++; ++ iinfo->ii_bend++; ++ if (unlikely(bend == -1)) { ++ dinfo->di_bstart = 0; ++ iinfo->ii_bstart = 0; ++ } ++ set_h_dptr(root, add_bindex, dget(add->nd.dentry)); ++ set_h_iptr(root_inode, add_bindex, igrab(add->nd.dentry->d_inode), 0); ++ if (!add_bindex) ++ au_cpup_attr_all(root_inode); ++ else ++ au_add_nlink(root_inode, add->nd.dentry->d_inode); ++ maxb = add->nd.dentry->d_sb->s_maxbytes; ++ if (sb->s_maxbytes < maxb) ++ sb->s_maxbytes = maxb; ++ ++ if (au_flag_test(sb, AuFlag_XINO)) { ++ struct file *base_file = stobr(sb, 0)->br_xino; ++ if (!add_bindex) ++ base_file = stobr(sb, 1)->br_xino; ++ err = xino_init(sb, add_bindex, base_file, /*do_test*/1); ++ if (unlikely(err)) { ++ DEBUG_ON(add_branch->br_xino); ++ Err("ignored xino err %d, force noxino\n", err); ++ err = 0; ++ au_flag_clr(sb, AuFlag_XINO); ++ } ++ } ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) ++{ ++ int err, i, j, sigen; ++ struct au_dcsub_pages dpages; ++ ++ LKTRTrace("b%d\n", bindex); ++ SiMustWriteLock(root->d_sb); ++ DiMustWriteLock(root); ++ ++ err = au_dpages_init(&dpages, GFP_KERNEL); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ struct au_dpage *dpage; ++ dpage = dpages.dpages + i; ++ for (j = 0; !err && j < dpage->ndentry; j++) { ++ struct dentry *d; ++ ++ d = dpage->dentries[j]; ++ if (au_digen(d) == sigen) ++ di_read_lock_child(d, AUFS_I_RLOCK); ++ else { ++ di_write_lock_child(d); ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AUFS_I_RLOCK); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ if (au_h_dptr_i(d, bindex) ++ && (!S_ISDIR(d->d_inode->i_mode) ++ || dbstart(d) == dbend(d))) ++ err = -EBUSY; ++ di_read_unlock(d, AUFS_I_RLOCK); ++ if (err) ++ LKTRTrace("%.*s\n", DLNPair(d)); ++ } ++ } ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++int br_del(struct super_block *sb, struct opt_del *del, int remount) ++{ ++ int err, do_wh, rerr; ++ struct dentry *root; ++ struct inode *inode, *hidden_dir; ++ aufs_bindex_t bindex, bend, br_id; ++ struct aufs_sbinfo *sbinfo; ++ struct aufs_dinfo *dinfo; ++ struct aufs_iinfo *iinfo; ++ struct aufs_branch *br; ++ ++ LKTRTrace("%s, %.*s\n", del->path, DLNPair(del->h_root)); ++ SiMustWriteLock(sb); ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ inode = root->d_inode; ++ IiMustWriteLock(inode); ++ ++ bindex = au_find_dbindex(root, del->h_root); ++ if (unlikely(bindex < 0)) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ Err("%s no such branch\n", del->path); ++ goto out; ++ } ++ LKTRTrace("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ bend = sbend(sb); ++ br = stobr(sb, bindex); ++ if (unlikely(!bend || br_count(br))) { ++ LKTRTrace("bend %d, br_count %d\n", bend, br_count(br)); ++ goto out; ++ } ++ ++ do_wh = 0; ++ hidden_dir = del->h_root->d_inode; ++ if (unlikely(br->br_wh || br->br_plink)) { ++#if 0 ++ /* remove whiteout base */ ++ err = init_br_wh(sb, bindex, br, AuBr_RO, del->h_root, ++ br->br_mnt); ++ if (unlikely(err)) ++ goto out; ++#else ++ dput(br->br_wh); ++ dput(br->br_plink); ++ br->br_wh = br->br_plink = NULL; ++#endif ++ do_wh = 1; ++ } ++ ++ err = test_children_busy(root, bindex); ++ if (unlikely(err)) { ++ if (unlikely(do_wh)) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ sbinfo = stosi(sb); ++ dinfo = dtodi(root); ++ iinfo = itoii(inode); ++ ++ dput(au_h_dptr_i(root, bindex)); ++ aufs_hiput(iinfo->ii_hinode + bindex); ++ br_id = br->br_id; ++ free_branch(br); ++ ++ //todo: realloc and shrink memeory ++ if (bindex < bend) { ++ const aufs_bindex_t n = bend - bindex; ++ struct aufs_branch **brp; ++ struct aufs_hdentry *hdp; ++ struct aufs_hinode *hip; ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp, brp + 1, sizeof(*brp) * n); ++ hdp = dinfo->di_hdentry + bindex; ++ memmove(hdp, hdp + 1, sizeof(*hdp) * n); ++ hip = iinfo->ii_hinode + bindex; ++ memmove(hip, hip + 1, sizeof(*hip) * n); ++ } ++ sbinfo->si_branch[0 + bend] = NULL; ++ dinfo->di_hdentry[0 + bend].hd_dentry = NULL; ++ iinfo->ii_hinode[0 + bend].hi_inode = NULL; ++ iinfo->ii_hinode[0 + bend].hi_notify = NULL; ++ ++ sbinfo->si_bend--; ++ dinfo->di_bend--; ++ iinfo->ii_bend--; ++ if (!bindex) ++ au_cpup_attr_all(inode); ++ else ++ au_sub_nlink(inode, del->h_root->d_inode); ++ if (au_flag_test(sb, AuFlag_PLINK)) ++ half_refresh_plink(sb, br_id); ++ ++ if (sb->s_maxbytes == del->h_root->d_sb->s_maxbytes) { ++ bend--; ++ sb->s_maxbytes = 0; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ unsigned long long maxb; ++ maxb = sbr_sb(sb, bindex)->s_maxbytes; ++ if (sb->s_maxbytes < maxb) ++ sb->s_maxbytes = maxb; ++ } ++ } ++ goto out; /* success */ ++ ++ out_wh: ++ /* revert */ ++ rerr = init_br_wh(sb, bindex, br, br->br_perm, del->h_root, br->br_mnt); ++ if (rerr) ++ Warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->path, rerr); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return (br_whable(a) && !br_whable(b)); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return (do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old)); ++} ++ ++int br_mod(struct super_block *sb, struct opt_mod *mod, int remount, ++ int *do_update) ++{ ++ int err; ++ struct dentry *root; ++ aufs_bindex_t bindex; ++ struct aufs_branch *br; ++ struct inode *hidden_dir; ++ ++ LKTRTrace("%s, %.*s, 0x%x\n", ++ mod->path, DLNPair(mod->h_root), mod->perm); ++ SiMustWriteLock(sb); ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ IiMustWriteLock(root->d_inode); ++ ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (unlikely(bindex < 0)) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ Err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ LKTRTrace("bindex b%d\n", bindex); ++ ++ hidden_dir = mod->h_root->d_inode; ++ err = test_br(sb, hidden_dir, mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = stobr(sb, bindex); ++ if (unlikely(br->br_perm == mod->perm)) ++ return 0; /* success */ ++ ++ if (br_writable(br->br_perm)) { ++#if 1 ++ /* remove whiteout base */ ++ //todo: mod->perm? ++ err = init_br_wh(sb, bindex, br, AuBr_RO, mod->h_root, ++ br->br_mnt); ++ if (unlikely(err)) ++ goto out; ++#else ++ dput(br->br_wh); ++ dput(br->br_plink); ++ br->br_wh = br->br_plink = NULL; ++#endif ++ ++ if (!br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ struct file *file, *hf; ++ ++#if 1 // test here ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ ++ // no need file_list_lock() since sbinfo is locked ++ //file_list_lock(); ++ list_for_each_entry(file, &sb->s_files, f_u.fu_list) { ++ LKTRTrace("%.*s\n", DLNPair(file->f_dentry)); ++ fi_read_lock(file); ++ if (!S_ISREG(file->f_dentry->d_inode->i_mode) ++ || !(file->f_mode & FMODE_WRITE) ++ || fbstart(file) != bindex) { ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ continue; ++ } ++ ++ // todo: already flushed? ++ hf = au_h_fptr(file); ++ hf->f_flags = au_file_roflags(hf->f_flags); ++ hf->f_mode &= ~FMODE_WRITE; ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ } ++ //file_list_unlock(); ++ ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++#endif ++ } ++ } ++ ++ *do_update |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ return err; /* success */ ++ ++ out: ++ TraceErr(err); ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/branch.h linux-2.6.22.1/fs/aufs/branch.h +--- linux-2.6.22.1.oorig/fs/aufs/branch.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/branch.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,235 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: branch.h,v 1.30 2007/05/14 03:41:51 sfjro Exp $ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "misc.h" ++#include "super.h" ++ ++/* protected by superblock rwsem */ ++struct aufs_branch { ++ struct file *br_xino; ++ readf_t br_xino_read; ++ writef_t br_xino_write; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct vfsmount *br_mnt; ++ atomic_t br_count; ++ ++ /* whiteout base */ ++ struct aufs_rwsem br_wh_rwsem; ++ struct dentry *br_wh; ++ atomic_t br_wh_running; ++ ++ /* pseudo-link dir */ ++ struct dentry *br_plink; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch permission and attribute */ ++enum { ++ AuBr_RW, /* writable, linkable wh */ ++ AuBr_RO, /* readonly, no wh */ ++ AuBr_RR, /* natively readonly, no wh */ ++ ++ AuBr_RWNoLinkWH, /* un-linkable whiteouts */ ++ ++ AuBr_ROWH, ++ AuBr_RRWH, /* whiteout-able */ ++ ++ AuBr_Last ++}; ++ ++static inline int br_writable(int brperm) ++{ ++ return (brperm == AuBr_RW ++ || brperm == AuBr_RWNoLinkWH); ++} ++ ++static inline int br_whable(int brperm) ++{ ++ return (brperm == AuBr_RW ++ || brperm == AuBr_ROWH ++ || brperm == AuBr_RRWH); ++} ++ ++static inline int br_linkable_wh(int brperm) ++{ ++ return (brperm == AuBr_RW); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define _AuNoNfsBranchMsg "NFS branch is not supported" ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,15) ++#define AuNoNfsBranch ++#define AuNoNfsBranchMsg _AuNoNfsBranchMsg ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) \ ++ && !defined(CONFIG_AUFS_LHASH_PATCH) ++#define AuNoNfsBranch ++#define AuNoNfsBranchMsg _AuNoNfsBranchMsg \ ++ ", try lhash.patch and CONFIG_AUFS_LHASH_PATCH" ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_sbinfo; ++void free_branches(struct aufs_sbinfo *sinfo); ++int br_rdonly(struct aufs_branch *br); ++int find_brindex(struct super_block *sb, aufs_bindex_t br_id); ++int find_rw_br(struct super_block *sb, aufs_bindex_t bend); ++int find_rw_parent_br(struct dentry *dentry, aufs_bindex_t bend); ++struct opt_add; ++int br_add(struct super_block *sb, struct opt_add *add, int remount); ++struct opt_del; ++int br_del(struct super_block *sb, struct opt_del *del, int remount); ++struct opt_mod; ++int br_mod(struct super_block *sb, struct opt_mod *mod, int remount, ++ int *do_update); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int br_count(struct aufs_branch *br) ++{ ++ return atomic_read(&br->br_count); ++} ++ ++static inline void br_get(struct aufs_branch *br) ++{ ++ atomic_inc(&br->br_count); ++} ++ ++static inline void br_put(struct aufs_branch *br) ++{ ++ atomic_dec(&br->br_count); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Superblock to branch */ ++static inline aufs_bindex_t sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return stobr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return stobr(sb, bindex)->br_mnt; ++} ++ ++static inline ++struct super_block *sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return sbr_mnt(sb, bindex)->mnt_sb; ++} ++ ++#if 0 ++static inline int sbr_count(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return br_count(stobr(sb, bindex)); ++} ++ ++static inline void sbr_get(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ br_get(stobr(sb, bindex)); ++} ++#endif ++ ++static inline void sbr_put(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ br_put(stobr(sb, bindex)); ++} ++ ++static inline int sbr_perm(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return stobr(sb, bindex)->br_perm; ++} ++ ++static inline int sbr_is_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return br_whable(sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_LHASH_PATCH ++static inline struct vfsmount *au_do_nfsmnt(struct vfsmount *h_mnt) ++{ ++ if (!au_is_nfs(h_mnt->mnt_sb)) ++ return NULL; ++ return h_mnt; ++} ++ ++/* it doesn't mntget() */ ++static inline ++struct vfsmount *au_nfsmnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_do_nfsmnt(sbr_mnt(sb, bindex)); ++} ++#else ++static inline struct vfsmount *au_do_nfsmnt(struct vfsmount *h_mnt) ++{ ++ return NULL; ++} ++ ++static inline ++struct vfsmount *au_nfsmnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return NULL; ++} ++#endif /* CONFIG_AUFS_LHASH_PATCH */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * br_wh_read_lock, br_wh_write_lock ++ * br_wh_read_unlock, br_wh_write_unlock, br_wh_downgrade_lock ++ */ ++SimpleRwsemFuncs(br_wh, struct aufs_branch *br, br->br_wh_rwsem); ++ ++/* to debug easier, do not make them inlined functions */ ++#define BrWhMustReadLock(br) do { \ ++ /* SiMustAnyLock(sb); */ \ ++ RwMustReadLock(&(br)->br_wh_rwsem); \ ++} while (0) ++ ++#define BrWhMustWriteLock(br) do { \ ++ /* SiMustAnyLock(sb); */ \ ++ RwMustWriteLock(&(br)->br_wh_rwsem); \ ++} while (0) ++ ++#define BrWhMustAnyLock(br) do { \ ++ /* SiMustAnyLock(sb); */ \ ++ RwMustAnyLock(&(br)->br_wh_rwsem); \ ++} while (0) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/cpup.c linux-2.6.22.1/fs/aufs/cpup.c +--- linux-2.6.22.1.oorig/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/cpup.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,773 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: cpup.c,v 1.37 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#include ++#include "aufs.h" ++ ++/* violent cpup_attr_*() functions don't care inode lock */ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *hidden_inode; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ //IMustLock(inode); ++ hidden_inode = au_h_iptr(inode); ++ DEBUG_ON(!hidden_inode); ++ //IMustLock(!hidden_inode); ++ ++ inode->i_atime = hidden_inode->i_atime; ++ inode->i_mtime = hidden_inode->i_mtime; ++ inode->i_ctime = hidden_inode->i_ctime; ++ spin_lock(&inode->i_lock); ++ i_size_write(inode, i_size_read(hidden_inode)); ++ inode->i_blocks = hidden_inode->i_blocks; ++ spin_unlock(&inode->i_lock); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ //IMustLock(inode); ++ DEBUG_ON(!inode->i_mode); ++ ++ h_inode = au_h_iptr(inode); ++ inode->i_nlink = h_inode->i_nlink; ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (unlikely(S_ISDIR(h_inode->i_mode))) { ++ aufs_bindex_t bindex, bend; ++ bend = ibend(inode); ++ for (bindex = ibstart(inode) + 1; bindex <= bend; bindex++) { ++ h_inode = au_h_iptr_i(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changable(struct inode *inode) ++{ ++ struct inode *hidden_inode; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ //IMustLock(inode); ++ hidden_inode = au_h_iptr(inode); ++ DEBUG_ON(!hidden_inode); ++ ++ inode->i_mode = hidden_inode->i_mode; ++ inode->i_uid = hidden_inode->i_uid; ++ inode->i_gid = hidden_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ ++ //?? ++ inode->i_flags = hidden_inode->i_flags; ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ inode->i_generation = h_inode->i_generation; ++ itoii(inode)->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode) ++{ ++ struct inode *hidden_inode; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ //IMustLock(inode); ++ hidden_inode = au_h_iptr(inode); ++ DEBUG_ON(!hidden_inode); ++ ++ au_cpup_attr_changable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode); ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFBLK: ++ case S_IFCHR: ++ inode->i_rdev = hidden_inode->i_rdev; ++ } ++ inode->i_blkbits = hidden_inode->i_blkbits; ++ au_cpup_attr_blksize(inode, hidden_inode); ++ au_cpup_igen(inode, hidden_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_hidden_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void dtime_store(struct dtime *dt, struct dentry *dentry, ++ struct dentry *hidden_dentry) ++{ ++ struct inode *inode; ++ ++ TraceEnter(); ++ DEBUG_ON(!dentry || !hidden_dentry || !hidden_dentry->d_inode); ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_dentry = hidden_dentry; ++ inode = hidden_dentry->d_inode; ++ dt->dt_atime = inode->i_atime; ++ dt->dt_mtime = inode->i_mtime; ++ //smp_mb(); ++} ++ ++// todo: remove extra parameter ++void dtime_revert(struct dtime *dt, int h_parent_is_locked) ++{ ++ struct iattr attr; ++ int err; ++ struct dentry *dentry; ++ ++ LKTRTrace("h_parent locked %d\n", h_parent_is_locked); ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ //smp_mb(); ++ dentry = NULL; ++ if (!h_parent_is_locked /* && !IS_ROOT(dt->dt_dentry) */) ++ dentry = dt->dt_dentry; ++ err = vfsub_notify_change(dt->dt_h_dentry, &attr, ++ need_dlgt(dt->dt_dentry->d_sb)); ++ if (unlikely(err)) ++ Warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int cpup_iattr(struct dentry *hidden_dst, struct dentry *hidden_src, ++ int dlgt) ++{ ++ int err; ++ struct iattr ia; ++ struct inode *hidden_isrc, *hidden_idst; ++ ++ LKTRTrace("%.*s\n", DLNPair(hidden_dst)); ++ hidden_idst = hidden_dst->d_inode; ++ //IMustLock(hidden_idst); ++ hidden_isrc = hidden_src->d_inode; ++ //IMustLock(hidden_isrc); ++ ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ ia.ia_mode = hidden_isrc->i_mode; ++ ia.ia_uid = hidden_isrc->i_uid; ++ ia.ia_gid = hidden_isrc->i_gid; ++ ia.ia_atime = hidden_isrc->i_atime; ++ ia.ia_mtime = hidden_isrc->i_mtime; ++ err = vfsub_notify_change(hidden_dst, &ia, dlgt); ++ //if (LktrCond) err = -1; ++ if (!err) ++ hidden_idst->i_flags = hidden_isrc->i_flags; //?? ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int cpup_regular(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len) ++{ ++ int err, i, sparse; ++ struct super_block *sb; ++ struct inode *hidden_inode; ++ enum {SRC, DST}; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ struct file *file; ++ void *label, *label_file; ++ } *h, hidden[] = { ++ { ++ .bindex = bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ .file = NULL, ++ .label = &&out, ++ .label_file = &&out_src_file ++ }, ++ { ++ .bindex = bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .file = NULL, ++ .label = &&out_src_file, ++ .label_file = &&out_dst_file ++ } ++ }; ++ ++ LKTRTrace("dentry %.*s, bdst %d, bsrc %d, len %lld\n", ++ DLNPair(dentry), bdst, bsrc, len); ++ DEBUG_ON(bsrc <= bdst); ++ DEBUG_ON(!len); ++ sb = dentry->d_sb; ++ DEBUG_ON(test_ro(sb, bdst, dentry->d_inode)); ++ // bsrc branch can be ro/rw. ++ ++ h = hidden; ++ for (i = 0; i < 2; i++, h++) { ++ h->dentry = au_h_dptr_i(dentry, h->bindex); ++ DEBUG_ON(!h->dentry); ++ hidden_inode = h->dentry->d_inode; ++ DEBUG_ON(!hidden_inode || !S_ISREG(hidden_inode->i_mode)); ++ h->file = hidden_open(dentry, h->bindex, h->flags); ++ //if (LktrCond) ++ //{fput(h->file); sbr_put(sb, h->bindex); h->file = ERR_PTR(-1);} ++ err = PTR_ERR(h->file); ++ if (IS_ERR(h->file)) ++ goto *h->label; ++ err = -EINVAL; ++ if (unlikely(!h->file->f_op)) ++ goto *h->label_file; ++ } ++ ++ /* stop updating while we copyup */ ++ IMustLock(hidden[SRC].dentry->d_inode); ++ sparse = 0; ++ err = au_copy_file(hidden[DST].file, hidden[SRC].file, len, sb, ++ &sparse); ++ ++ /* sparse file: update i_blocks next time */ ++ if (unlikely(!err && sparse)) ++ d_drop(dentry); ++ ++ out_dst_file: ++ fput(hidden[DST].file); ++ sbr_put(sb, hidden[DST].bindex); ++ out_src_file: ++ fput(hidden[SRC].file); ++ sbr_put(sb, hidden[SRC].bindex); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++// unnecessary? ++unsigned int au_flags_cpup(unsigned int init, struct dentry *parent) ++{ ++ if (unlikely(parent && IS_ROOT(parent))) ++ init |= CPUP_LOCKED_GHDIR; ++ return init; ++} ++ ++/* return with hidden dst inode is locked */ ++static int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags, ++ int dlgt) ++{ ++ int err, isdir, symlen; ++ struct dentry *hidden_src, *hidden_dst, *hidden_parent, *parent; ++ struct inode *hidden_inode, *hidden_dir, *dir; ++ struct dtime dt; ++ umode_t mode; ++ char *sym; ++ mm_segment_t old_fs; ++ const int do_dt = flags & CPUP_DTIME; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, ++ flags); ++ sb = dentry->d_sb; ++ DEBUG_ON(bdst >= bsrc || test_ro(sb, bdst, NULL)); ++ // bsrc branch can be ro/rw. ++ ++ hidden_src = au_h_dptr_i(dentry, bsrc); ++ DEBUG_ON(!hidden_src); ++ hidden_inode = hidden_src->d_inode; ++ DEBUG_ON(!hidden_inode); ++ ++ /* stop refrencing while we are creating */ ++ //parent = dget_parent(dentry); ++ parent = dentry->d_parent; ++ dir = parent->d_inode; ++ hidden_dst = au_h_dptr_i(dentry, bdst); ++ DEBUG_ON(hidden_dst && hidden_dst->d_inode); ++ //hidden_parent = dget_parent(hidden_dst); ++ hidden_parent = hidden_dst->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ if (do_dt) ++ dtime_store(&dt, parent, hidden_parent); ++ ++ isdir = 0; ++ mode = hidden_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* stop updating while we are referencing */ ++ IMustLock(hidden_inode); ++ err = vfsub_create(hidden_dir, hidden_dst, mode | S_IWUSR, NULL, ++ dlgt); ++ //if (LktrCond) {vfs_unlink(hidden_dir, hidden_dst); err = -1;} ++ if (!err) { ++ loff_t l = i_size_read(hidden_inode); ++ if (len == -1 || l < len) ++ len = l; ++ if (len) { ++ err = cpup_regular(dentry, bdst, bsrc, len); ++ //if (LktrCond) err = -1; ++ } ++ if (unlikely(err)) { ++ int rerr; ++ rerr = vfsub_unlink(hidden_dir, hidden_dst, ++ dlgt); ++ if (rerr) { ++ IOErr("failed unlinking cpup-ed %.*s" ++ "(%d, %d)\n", ++ DLNPair(hidden_dst), err, rerr); ++ err = -EIO; ++ } ++ } ++ } ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(hidden_dir, hidden_dst, mode, dlgt); ++ //if (LktrCond) {vfs_rmdir(hidden_dir, hidden_dst); err = -1;} ++ if (!err) { ++ /* setattr case: dir is not locked */ ++ if (0 && ibstart(dir) == bdst) ++ au_cpup_attr_nlink(dir); ++ au_cpup_attr_nlink(dentry->d_inode); ++ } ++ break; ++ case S_IFLNK: ++ err = -ENOMEM; ++ sym = __getname(); ++ //if (LktrCond) {__putname(sym); sym = NULL;} ++ if (unlikely(!sym)) ++ break; ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = symlen = hidden_inode->i_op->readlink ++ (hidden_src, (char __user*)sym, PATH_MAX); ++ //if (LktrCond) err = symlen = -1; ++ set_fs(old_fs); ++ if (symlen > 0) { ++ sym[symlen] = 0; ++ err = vfsub_symlink(hidden_dir, hidden_dst, sym, mode, ++ dlgt); ++ //if (LktrCond) ++ //{vfs_unlink(hidden_dir, hidden_dst); err = -1;} ++ } ++ __putname(sym); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ DEBUG_ON(!capable(CAP_MKNOD)); ++ /*FALLTHROUGH*/ ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(hidden_dir, hidden_dst, mode, ++ hidden_inode->i_rdev, dlgt); ++ //if (LktrCond) {vfs_unlink(hidden_dir, hidden_dst); err = -1;} ++ break; ++ default: ++ IOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ ++ if (do_dt) ++ dtime_revert(&dt, flags & CPUP_LOCKED_GHDIR); ++ //dput(parent); ++ //dput(hidden_parent); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of hidden dentries. ++ * @len is for trucating when it is -1 copyup the entire file. ++ */ ++int cpup_single(struct dentry *dentry, aufs_bindex_t bdst, aufs_bindex_t bsrc, ++ loff_t len, unsigned int flags) ++{ ++ int err, rerr, isdir, dlgt; ++ struct dentry *hidden_src, *hidden_dst, *parent;//, *h_parent; ++ struct inode *dst_inode, *hidden_dir, *inode, *src_inode; ++ struct super_block *sb; ++ aufs_bindex_t old_ibstart; ++ struct dtime dt; ++ ++ LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, ++ flags); ++ sb = dentry->d_sb; ++ DEBUG_ON(bsrc <= bdst); ++ hidden_dst = au_h_dptr_i(dentry, bdst); ++ DEBUG_ON(!hidden_dst || hidden_dst->d_inode); ++ //h_parent = dget_parent(hidden_dst); ++ //hidden_dir = h_parent->d_inode; ++ hidden_dir = hidden_dst->d_parent->d_inode; ++ IMustLock(hidden_dir); ++ hidden_src = au_h_dptr_i(dentry, bsrc); ++ DEBUG_ON(!hidden_src || !hidden_src->d_inode); ++ inode = dentry->d_inode; ++ IiMustWriteLock(inode); ++ ++ dlgt = need_dlgt(sb); ++ dst_inode = au_h_iptr_i(inode, bdst); ++ if (unlikely(dst_inode)) { ++ if (unlikely(!au_flag_test(sb, AuFlag_PLINK))) { ++ err = -EIO; ++ IOErr("i%lu exists on a upper branch " ++ "but plink is disabled\n", inode->i_ino); ++ goto out; ++ } ++ ++ if (dst_inode->i_nlink) { ++ hidden_src = lkup_plink(sb, bdst, inode); ++ err = PTR_ERR(hidden_src); ++ if (IS_ERR(hidden_src)) ++ goto out; ++ DEBUG_ON(!hidden_src->d_inode); ++ // vfs_link() does lock the inode ++ err = vfsub_link(hidden_src, hidden_dir, hidden_dst, dlgt); ++ dput(hidden_src); ++ goto out; ++ } else ++ /* udba work */ ++ au_update_brange(inode, 1); ++ } ++ ++ old_ibstart = ibstart(inode); ++ err = cpup_entry(dentry, bdst, bsrc, len, flags, dlgt); ++ if (unlikely(err)) ++ goto out; ++ dst_inode = hidden_dst->d_inode; ++ hi_lock_child2(dst_inode); ++ ++ //todo: test dlgt ++ err = cpup_iattr(hidden_dst, hidden_src, dlgt); ++ //if (LktrCond) err = -1; ++#if 0 // xattr ++ if (0 && !err) ++ err = cpup_xattrs(hidden_src, hidden_dst); ++#endif ++ isdir = S_ISDIR(dst_inode->i_mode); ++ if (!err) { ++ if (bdst < old_ibstart) ++ set_ibstart(inode, bdst); ++ set_h_iptr(inode, bdst, igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ i_unlock(dst_inode); ++ src_inode = hidden_src->d_inode; ++ if (!isdir) { ++ if (src_inode->i_nlink > 1 ++ && au_flag_test(sb, AuFlag_PLINK)) ++ append_plink(sb, inode, hidden_dst, bdst); ++ else { ++ /* braces are added to stop a warning */ ++ ;//xino_write0(sb, bsrc, src_inode->i_ino); ++ /* ignore this error */ ++ } ++ } ++ //goto out; /* success */ ++ return 0; /* success */ ++ } ++ ++ /* revert */ ++ i_unlock(dst_inode); ++ parent = dget_parent(dentry); ++ //dtime_store(&dt, parent, h_parent); ++ dtime_store(&dt, parent, hidden_dst->d_parent); ++ dput(parent); ++ if (!isdir) ++ rerr = vfsub_unlink(hidden_dir, hidden_dst, dlgt); ++ else ++ rerr = vfsub_rmdir(hidden_dir, hidden_dst, dlgt); ++ //rerr = -1; ++ dtime_revert(&dt, flags & CPUP_LOCKED_GHDIR); ++ if (rerr) { ++ IOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++ ++ out: ++ //dput(h_parent); ++ TraceErr(err); ++ return err; ++} ++ ++struct cpup_single_args { ++ int *errp; ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ unsigned int flags; ++}; ++ ++static void call_cpup_single(void *args) ++{ ++ struct cpup_single_args *a = args; ++ *a->errp = cpup_single(a->dentry, a->bdst, a->bsrc, a->len, a->flags); ++} ++ ++int sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags) ++{ ++ int err; ++ struct dentry *hidden_dentry; ++ umode_t mode; ++ ++ LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, ++ flags); ++ ++ hidden_dentry = au_h_dptr_i(dentry, bsrc); ++ mode = hidden_dentry->d_inode->i_mode & S_IFMT; ++ if ((mode != S_IFCHR && mode != S_IFBLK) ++ || capable(CAP_MKNOD)) ++ err = cpup_single(dentry, bdst, bsrc, len, flags); ++ else { ++ struct cpup_single_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = bsrc, ++ .len = len, ++ .flags = flags ++ }; ++ au_wkq_wait(call_cpup_single, &args, /*dlgt*/0); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * copyup the @dentry from the first active hidden branch to @bdst, ++ * using cpup_single(). ++ */ ++int cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags) ++{ ++ int err; ++ struct inode *inode; ++ aufs_bindex_t bsrc, bend; ++ ++ LKTRTrace("%.*s, bdst %d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), bdst, len, flags); ++ inode = dentry->d_inode; ++ DEBUG_ON(!S_ISDIR(inode->i_mode) && dbstart(dentry) < bdst); ++ ++ bend = dbend(dentry); ++ for (bsrc = bdst + 1; bsrc <= bend; bsrc++) ++ if (au_h_dptr_i(dentry, bsrc)) ++ break; ++ DEBUG_ON(!au_h_dptr_i(dentry, bsrc)); ++ ++ err = lkup_neg(dentry, bdst); ++ //err = -1; ++ if (!err) { ++ err = cpup_single(dentry, bdst, bsrc, len, flags); ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ set_h_dptr(dentry, bdst, NULL); ++ set_dbstart(dentry, bsrc); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++struct cpup_simple_args { ++ int *errp; ++ struct dentry *dentry; ++ aufs_bindex_t bdst; ++ loff_t len; ++ unsigned int flags; ++}; ++ ++static void call_cpup_simple(void *args) ++{ ++ struct cpup_simple_args *a = args; ++ *a->errp = cpup_simple(a->dentry, a->bdst, a->len, a->flags); ++} ++ ++int sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags) ++{ ++ int err, do_sio, dlgt; ++ //struct dentry *parent; ++ struct inode *hidden_dir, *dir; ++ ++ LKTRTrace("%.*s, b%d, len %Ld, flags 0x%x\n", ++ DLNPair(dentry), bdst, len, flags); ++ ++ //parent = dget_parent(dentry); ++ //dir = parent->d_inode; ++ dir = dentry->d_parent->d_inode; ++ hidden_dir = au_h_iptr_i(dir, bdst); ++ dlgt = need_dlgt(dir->i_sb); ++ do_sio = au_test_perm(hidden_dir, MAY_EXEC | MAY_WRITE, dlgt); ++ if (!do_sio) { ++ umode_t mode = dentry->d_inode->i_mode & S_IFMT; ++ do_sio = ((mode == S_IFCHR || mode == S_IFBLK) ++ && !capable(CAP_MKNOD)); ++ } ++ if (!do_sio) ++ err = cpup_simple(dentry, bdst, len, flags); ++ else { ++ struct cpup_simple_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bdst, ++ .len = len, ++ .flags = flags ++ }; ++ au_wkq_wait(call_cpup_simple, &args, /*dlgt*/0); ++ } ++ ++ //dput(parent); ++ TraceErr(err); ++ return err; ++} ++ ++//todo: dcsub ++/* cf. revalidate function in file.c */ ++int cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst, struct dentry *locked) ++{ ++ int err; ++ struct super_block *sb; ++ struct dentry *d, *parent, *hidden_parent; ++ unsigned int udba; ++ ++ LKTRTrace("%.*s, b%d, parent i%lu, locked %p\n", ++ DLNPair(dentry), bdst, parent_ino(dentry), locked); ++ sb = dentry->d_sb; ++ DEBUG_ON(test_ro(sb, bdst, NULL)); ++ parent = dentry->d_parent; ++ IiMustWriteLock(parent->d_inode); ++ if (unlikely(IS_ROOT(parent))) ++ return 0; ++ if (locked) { ++ DiMustAnyLock(locked); ++ IiMustAnyLock(locked->d_inode); ++ } ++ ++ /* slow loop, keep it simple and stupid */ ++ err = 0; ++ udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY); ++ while (1) { ++ parent = dentry->d_parent; // dget_parent() ++ hidden_parent = au_h_dptr_i(parent, bdst); ++ if (hidden_parent) ++ return 0; /* success */ ++ ++ /* find top dir which is needed to cpup */ ++ do { ++ d = parent; ++ parent = d->d_parent; // dget_parent() ++ if (parent != locked) ++ di_read_lock_parent3(parent, !AUFS_I_RLOCK); ++ hidden_parent = au_h_dptr_i(parent, bdst); ++ if (parent != locked) ++ di_read_unlock(parent, !AUFS_I_RLOCK); ++ } while (!hidden_parent); ++ ++ if (d != dentry->d_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ if (!au_h_dptr_i(d, bdst) || !au_h_dptr_i(d, bdst)->d_inode) { ++ struct inode *h_dir = hidden_parent->d_inode, ++ *dir = parent->d_inode, ++ *h_gdir, *gdir; ++ ++ if (au_h_dptr_i(d, bdst)) ++ au_update_dbstart(d); ++ //DEBUG_ON(dbstart(d) <= bdst); ++ if (parent != locked) ++ di_read_lock_parent3(parent, AUFS_I_RLOCK); ++ h_gdir = gdir = NULL; ++ if (unlikely(udba && !IS_ROOT(parent))) { ++ gdir = parent->d_parent->d_inode; ++ h_gdir = hidden_parent->d_parent->d_inode; ++ hgdir_lock(h_gdir, gdir, bdst); ++ } ++ hdir_lock(h_dir, dir, bdst); ++ err = sio_cpup_simple(d, bdst, -1, ++ au_flags_cpup(CPUP_DTIME, ++ parent)); ++ //if (LktrCond) err = -1; ++ hdir_unlock(h_dir, dir, bdst); ++ if (unlikely(gdir)) ++ hdir_unlock(h_gdir, gdir, bdst); ++ if (parent != locked) ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ } ++ ++ if (d != dentry->d_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++// out: ++ TraceErr(err); ++ return err; ++} ++ ++int test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *locked) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dentry->d_parent; ++ dir = parent->d_inode; ++ LKTRTrace("%.*s, b%d, parent i%lu, locked %p\n", ++ DLNPair(dentry), bdst, dir->i_ino, locked); ++ DiMustReadLock(parent); ++ IiMustReadLock(dir); ++ ++ if (au_h_iptr_i(dir, bdst)) ++ return 0; ++ ++ err = 0; ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ di_write_lock_parent(parent); ++ if (au_h_iptr_i(dir, bdst)) ++ goto out; ++ ++ err = cpup_dirs(dentry, bdst, locked); ++ ++ out: ++ di_downgrade_lock(parent, AUFS_I_RLOCK); ++ TraceErr(err); ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/cpup.h linux-2.6.22.1/fs/aufs/cpup.h +--- linux-2.6.22.1.oorig/fs/aufs/cpup.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/cpup.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: cpup.h,v 1.15 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++static inline ++void au_cpup_attr_blksize(struct inode *inode, struct inode *h_inode) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ++ inode->i_blksize = h_inode->i_blksize; ++#endif ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode); ++void au_cpup_attr_changable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode); ++ ++#define CPUP_DTIME 1 // do dtime_store/revert ++// todo: remove this ++#define CPUP_LOCKED_GHDIR 2 // grand parent hidden dir is locked ++unsigned int au_flags_cpup(unsigned int init, struct dentry *parent); ++ ++int cpup_single(struct dentry *dentry, aufs_bindex_t bdst, aufs_bindex_t bsrc, ++ loff_t len, unsigned int flags); ++int sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags); ++int cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags); ++int sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags); ++ ++int cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst, struct dentry *locked); ++int test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *locked); ++ ++/* keep timestamps when copyup */ ++struct dtime { ++ struct dentry *dt_dentry, *dt_h_dentry; ++ struct timespec dt_atime, dt_mtime; ++}; ++void dtime_store(struct dtime *dt, struct dentry *dentry, ++ struct dentry *h_dentry); ++void dtime_revert(struct dtime *dt, int h_parent_is_locked); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/dcsub.c linux-2.6.22.1/fs/aufs/dcsub.c +--- linux-2.6.22.1.oorig/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/dcsub.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,175 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dcsub.c,v 1.3 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ ++ TraceEnter(); ++ DEBUG_ON(!dpage); ++ ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(dpage->dentries[i]); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ TraceEnter(); ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ p = (void*)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++ out_dpages: ++ kfree(dpages->dpages); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(dpages->dpages + i); ++ kfree(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ //TraceEnter(); ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ DEBUG_ON(!dpage); ++ sz = PAGE_SIZE/sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ LKTRLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp); ++ if (unlikely(!p)) ++ goto out; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void*)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ dpage->dentries[dpage->ndentry++] = dget(dentry); ++ return 0; /* success */ ++ ++ out: ++ //TraceErr(err); ++ return err; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ int err; ++ struct dentry *this_parent = root; ++ struct list_head *next; ++ struct super_block *sb = root->d_sb; ++ ++ TraceEnter(); ++ ++ err = 0; ++ spin_lock(&dcache_lock); ++ repeat: ++ next = this_parent->d_subdirs.next; ++ resume: ++ if (this_parent->d_sb == sb ++ && !IS_ROOT(this_parent) ++ && atomic_read(&this_parent->d_count) ++ && this_parent->d_inode ++ && (!test || test(this_parent, arg))) { ++ err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ while (next != &this_parent->d_subdirs) { ++ struct list_head *tmp = next; ++ struct dentry *dentry = list_entry(tmp, struct dentry, D_CHILD); ++ next = tmp->next; ++ if (unlikely(/*d_unhashed(dentry) || */!dentry->d_inode)) ++ continue; ++ if (!list_empty(&dentry->d_subdirs)) { ++ this_parent = dentry; ++ goto repeat; ++ } ++ if (dentry->d_sb == sb ++ && atomic_read(&dentry->d_count) ++ && (!test || test(dentry, arg))) { ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ if (unlikely(err)) ++ goto out; ++ } ++ } ++ ++ if (this_parent != root) { ++ next = this_parent->D_CHILD.next; ++ this_parent = this_parent->d_parent; ++ goto resume; ++ } ++ out: ++ spin_unlock(&dcache_lock); ++#if 0 ++ if (!err) { ++ int i, j; ++ j = 0; ++ for (i = 0; i < dpages->ndpage; i++) { ++ if ((dpages->dpages + i)->ndentry) ++ Dbg("%d: %d\n", i, (dpages->dpages + i)->ndentry); ++ j += (dpages->dpages + i)->ndentry; ++ } ++ if (j) ++ Dbg("ndpage %d, %d\n", dpages->ndpage, j); ++ } ++#endif ++ TraceErr(err); ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/dcsub.h linux-2.6.22.1/fs/aufs/dcsub.h +--- linux-2.6.22.1.oorig/fs/aufs/dcsub.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/dcsub.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dcsub.h,v 1.2 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/debug.c linux-2.6.22.1/fs/aufs/debug.c +--- linux-2.6.22.1.oorig/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/debug.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,262 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: debug.c,v 1.27 2007/04/30 05:48:23 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++atomic_t aufs_cond = ATOMIC_INIT(0); ++ ++#if defined(CONFIG_LKTR) || defined(CONFIG_LKTR_MODULE) ++#define dpri(fmt, arg...) \ ++ do {if (LktrCond) printk(KERN_DEBUG fmt, ##arg);} while (0) ++#else ++#define dpri(fmt, arg...) printk(KERN_DEBUG fmt, ##arg) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct aufs_nhash *whlist) ++{ ++ int i; ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos; ++ ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ head = whlist->heads + i; ++ hlist_for_each_entry(tpos, pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ tpos->wh_bindex, ++ tpos->wh_str.len, tpos->wh_str.name, ++ tpos->wh_str.len); ++ } ++} ++ ++void au_dpri_vdir(struct aufs_vdir *vdir) ++{ ++ int i; ++ union aufs_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("nblk %d, deblk %p %d, last{%d, %p}, ver %lu\n", ++ vdir->vd_nblk, vdir->vd_deblk, ksize(vdir->vd_deblk), ++ vdir->vd_last.i, vdir->vd_last.p.p, vdir->vd_version); ++ for (i = 0; i < vdir->vd_nblk; i++) { ++ p.deblk = vdir->vd_deblk[i]; ++ o = p.p; ++ dpri("[%d]: %p %d\n", i, o, ksize(o)); ++#if 0 // verbose ++ int j; ++ for (j = 0; j < 8; j++) { ++ dpri("%p(+%d) {%02x %02x %02x %02x %02x %02x %02x %02x " ++ "%02x %02x %02x %02x %02x %02x %02x %02x}\n", ++ p.p, p.p - o, ++ p.p[0], p.p[1], p.p[2], p.p[3], ++ p.p[4], p.p[5], p.p[6], p.p[7], ++ p.p[8], p.p[9], p.p[10], p.p[11], ++ p.p[12], p.p[13], p.p[14], p.p[15]); ++ p.p += 16; ++ } ++#endif ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode) ++{ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LSF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, sz %Lu, blk %Lu," ++ " ct %Ld, np %lu, st 0x%lx, g %x\n", ++ bindex, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (u64)inode->i_blocks, ++ timespec_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_generation); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct aufs_iinfo *iinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_inode(-1, inode); ++ if (err || !au_is_aufs(inode->i_sb)) ++ return; ++ ++ iinfo = itoii(inode); ++ if (!iinfo) ++ return; ++ dpri("i-1: bstart %d, bend %d, gen %d\n", ++ iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode)); ++ if (iinfo->ii_bstart < 0) ++ return; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) ++ do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ dpri("d%d: %.*s/%.*s, %s, cnt %d, flags 0x%x\n", ++ bindex, ++ DLNPair(dentry->d_parent), DLNPair(dentry), ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ atomic_read(&dentry->d_count), dentry->d_flags); ++ do_pri_inode(bindex, dentry->d_inode); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct aufs_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_is_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = dtodi(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n", ++ dinfo->di_bstart, dinfo->di_bend, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry)); ++ if (dinfo->di_bstart < 0) ++ return; ++ for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) ++ do_pri_dentry(bindex, dinfo->di_hdentry[0 + bindex].hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex == -1 && ftofi(file)) ++ snprintf(a, sizeof(a), ", mmapped %d", au_is_mmapped(file)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %d, pos %Lu%s\n", ++ bindex, file->f_mode, file->f_flags, file_count(file), ++ file->f_pos, a); ++ do_pri_dentry(bindex, file->f_dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct aufs_finfo *finfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err || !file->f_dentry || !au_is_aufs(file->f_dentry->d_sb)) ++ return; ++ ++ finfo = ftofi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_bstart < 0) ++ return; ++ for (bindex = finfo->fi_bstart; bindex <= finfo->fi_bend; bindex++) { ++ struct aufs_hfile *hf; ++ //dpri("bindex %d\n", bindex); ++ hf = finfo->fi_hfile + bindex; ++ do_pri_file(bindex, hf ? hf->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct aufs_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br) ++ || !(mnt = br->br_mnt) || IS_ERR(mnt) ++ || !(sb = mnt->mnt_sb) || IS_ERR(sb)) { ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++ } ++ ++ dpri("s%d: {perm 0x%x, cnt %d}, " ++ "%s, flags 0x%lx, cnt(BIAS) %d, active %d, xino %p %p\n", ++ bindex, br->br_perm, br_count(br), ++ au_sbtype(sb), sb->s_flags, sb->s_count - S_BIAS, ++ atomic_read(&sb->s_active), br->br_xino, ++ br->br_xino ? br->br_xino->f_dentry : NULL); ++ return 0; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ struct vfsmount mnt = {.mnt_sb = sb}; ++ struct aufs_branch fake = { ++ .br_perm = 0, ++ .br_mnt = &mnt, ++ .br_count = ATOMIC_INIT(0), ++ .br_xino = NULL ++ }; ++ ++ atomic_set(&fake.br_count, 0); ++ err = do_pri_br(-1, &fake); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_is_aufs(sb)) ++ return; ++ ++ sbinfo = stosi(sb); ++ if (!sbinfo) ++ return; ++ for (bindex = 0; bindex <= sbinfo->si_bend; bindex++) { ++ //dpri("bindex %d\n", bindex); ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void DbgSleep(int sec) ++{ ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ Dbg("sleep %d sec\n", sec); ++ wait_event_timeout(wq, 0, sec * HZ); ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/debug.h linux-2.6.22.1/fs/aufs/debug.h +--- linux-2.6.22.1.oorig/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/debug.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: debug.h,v 1.31 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DEBUG_ON(a) BUG_ON(a) ++extern atomic_t aufs_cond; ++#define au_debug_on() atomic_inc(&aufs_cond) ++#define au_debug_off() atomic_dec(&aufs_cond) ++#define au_is_debug() atomic_read(&aufs_cond) ++#else ++#define DEBUG_ON(a) /* */ ++#define au_debug_on() /* */ ++#define au_debug_off() /* */ ++#define au_is_debug() 0 ++#endif ++ ++#define MtxMustLock(mtx) DEBUG_ON(!mutex_is_locked(mtx)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++#if defined(CONFIG_LKTR) || defined(CONFIG_LKTR_MODULE) ++#include ++#ifdef CONFIG_AUFS_DEBUG ++#undef LktrCond ++#define LktrCond unlikely((lktr_cond && lktr_cond()) || au_is_debug()) ++#endif ++#else ++#define LktrCond au_is_debug() ++#define LKTRDumpVma(pre, vma, suf) /* */ ++#define LKTRDumpStack() /* */ ++#define LKTRTrace(fmt, args...) do { \ ++ if (LktrCond) \ ++ Dbg(fmt, ##args); \ ++} while (0) ++#define LKTRLabel(label) LKTRTrace("%s\n", #label) ++#endif /* CONFIG_LKTR */ ++ ++#define TraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ LKTRTrace("err %d\n", (int)(e)); \ ++} while (0) ++#define TraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ LKTRTrace("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++#define TraceEnter() LKTRLabel(enter) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define LNPair(qstr) (qstr)->len,(qstr)->name ++#define DLNPair(d) LNPair(&(d)->d_name) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define Dpri(lvl, fmt, arg...) \ ++ printk(lvl AUFS_NAME " %s:%d:%s[%d]: " fmt, \ ++ __func__, __LINE__, current->comm, current->pid, ##arg) ++#define Dbg(fmt, arg...) Dpri(KERN_DEBUG, fmt, ##arg) ++#define Warn(fmt, arg...) Dpri(KERN_WARNING, fmt, ##arg) ++#define Warn1(fmt, arg...) do { \ ++ static unsigned char c; \ ++ if (!c++) Warn(fmt, ##arg); \ ++ } while (0) ++#define Err(fmt, arg...) Dpri(KERN_ERR, fmt, ##arg) ++#define Err1(fmt, arg...) do { \ ++ static unsigned char c; \ ++ if (!c++) Err(fmt, ##arg); \ ++ } while (0) ++#define IOErr(fmt, arg...) Err("I/O Error, " fmt, ##arg) ++#define IOErr1(fmt, arg...) do { \ ++ static unsigned char c; \ ++ if (!c++) IOErr(fmt, ##arg); \ ++ } while (0) ++#define IOErrWhck(fmt, arg...) Err("I/O Error, try whck. " fmt, ##arg) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++struct aufs_nhash; ++void au_dpri_whlist(struct aufs_nhash *whlist); ++struct aufs_vdir; ++void au_dpri_vdir(struct aufs_vdir *vdir); ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++void au_dpri_file(struct file *filp); ++void au_dpri_sb(struct super_block *sb); ++#define DbgWhlist(w) do{LKTRTrace(#w "\n"); au_dpri_whlist(w);}while(0) ++#define DbgVdir(v) do{LKTRTrace(#v "\n"); au_dpri_vdir(v);}while(0) ++#define DbgInode(i) do{LKTRTrace(#i "\n"); au_dpri_inode(i);}while(0) ++#define DbgDentry(d) do{LKTRTrace(#d "\n"); au_dpri_dentry(d);}while(0) ++#define DbgFile(f) do{LKTRTrace(#f "\n"); au_dpri_file(f);}while(0) ++#define DbgSb(sb) do{LKTRTrace(#sb "\n"); au_dpri_sb(sb);}while(0) ++void DbgSleep(int sec); ++#else ++#define DbgWhlist(w) /* */ ++#define DbgVdir(v) /* */ ++#define DbgInode(i) /* */ ++#define DbgDentry(d) /* */ ++#define DbgFile(f) /* */ ++#define DbgSb(sb) /* */ ++#define DbgSleep(sec) /* */ ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/dentry.c linux-2.6.22.1/fs/aufs/dentry.c +--- linux-2.6.22.1.oorig/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/dentry.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,946 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dentry.c,v 1.41 2007/05/14 03:38:38 sfjro Exp $ */ ++ ++//#include ++//#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_LHASH_PATCH ++ ++#ifdef CONFIG_AUFS_DLGT ++struct lookup_hash_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct dentry *base; ++ struct nameidata *nd; ++}; ++ ++static void call_lookup_hash(void *args) ++{ ++ struct lookup_hash_args *a = args; ++ *a->errp = __lookup_hash(a->name, a->base, a->nd); ++} ++#endif /* CONFIG_AUFS_DLGT */ ++ ++static struct dentry *lkup_hash(const char *name, struct dentry *parent, ++ int len, struct lkup_args *lkup) ++{ ++ struct dentry *dentry; ++ char *p; ++ unsigned long hash; ++ struct qstr this; ++ unsigned int c; ++ struct nameidata tmp_nd; ++ ++ dentry = ERR_PTR(-EACCES); ++ this.name = name; ++ this.len = len; ++ if (unlikely(!len)) ++ goto out; ++ ++ p = (void*)name; ++ hash = init_name_hash(); ++ while (len--) { ++ c = *p++; ++ if (unlikely(c == '/' || c == '\0')) ++ goto out; ++ hash = partial_name_hash(c, hash); ++ } ++ this.hash = end_name_hash(hash); ++ ++ memset(&tmp_nd, 0, sizeof(tmp_nd)); ++ tmp_nd.dentry = dget(parent); ++ tmp_nd.mnt = mntget(lkup->nfsmnt); ++#ifndef CONFIG_AUFS_DLGT ++ dentry = __lookup_hash(&this, parent, &tmp_nd); ++#else ++ if (!lkup->dlgt) ++ dentry = __lookup_hash(&this, parent, &tmp_nd); ++ else { ++ struct lookup_hash_args args = { ++ .errp = &dentry, ++ .name = &this, ++ .base = parent, ++ .nd = &tmp_nd ++ }; ++ au_wkq_wait(call_lookup_hash, &args, /*dlgt*/1); ++ } ++#endif ++ path_release(&tmp_nd); ++ ++ out: ++ TraceErrPtr(dentry); ++ return dentry; ++} ++#elif defined(CONFIG_AUFS_DLGT) ++static struct dentry *lkup_hash(const char *name, struct dentry *parent, ++ int len, struct lkup_args *lkup) ++{ ++ return ERR_PTR(-ENOSYS); ++} ++#endif ++ ++#ifdef CONFIG_AUFS_DLGT ++struct lookup_one_len_args { ++ struct dentry **errp; ++ const char *name; ++ struct dentry *parent; ++ int len; ++}; ++ ++static void call_lookup_one_len(void *args) ++{ ++ struct lookup_one_len_args *a = args; ++ *a->errp = lookup_one_len(a->name, a->parent, a->len); ++} ++#endif /* CONFIG_AUFS_DLGT */ ++ ++#if defined(CONFIG_AUFS_LHASH_PATCH) || defined(CONFIG_AUFS_DLGT) ++/* cf. lookup_one_len() in linux/fs/namei.c */ ++struct dentry *lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup) ++{ ++ struct dentry *dentry; ++ ++ LKTRTrace("%.*s/%.*s, lkup{%p, %d}\n", ++ DLNPair(parent), len, name, lkup->nfsmnt, lkup->dlgt); ++ ++ if (!lkup->nfsmnt) { ++#ifndef CONFIG_AUFS_DLGT ++ dentry = lookup_one_len(name, parent, len); ++#else ++ if (!lkup->dlgt) ++ dentry = lookup_one_len(name, parent, len); ++ else { ++ struct lookup_one_len_args args = { ++ .errp = &dentry, ++ .name = name, ++ .parent = parent, ++ .len = len ++ }; ++ au_wkq_wait(call_lookup_one_len, &args, /*dlgt*/1); ++ } ++#endif ++ } else ++ dentry = lkup_hash(name, parent, len, lkup); ++ ++ TraceErrPtr(dentry); ++ return dentry; ++} ++#endif ++ ++struct lkup_one_args { ++ struct dentry **errp; ++ const char *name; ++ struct dentry *parent; ++ int len; ++ struct lkup_args *lkup; ++}; ++ ++static void call_lkup_one(void *args) ++{ ++ struct lkup_one_args *a = args; ++ *a->errp = lkup_one(a->name, a->parent, a->len, a->lkup); ++} ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry *do_lookup(struct dentry *hidden_parent, ++ struct dentry *dentry, aufs_bindex_t bindex, ++ struct qstr *wh_name, int allow_neg, ++ mode_t type, int dlgt) ++{ ++ struct dentry *hidden_dentry; ++ int wh_found, wh_able, opq; ++ struct inode *hidden_dir, *hidden_inode; ++ struct qstr *name; ++ struct super_block *sb; ++ struct lkup_args lkup = {.dlgt = dlgt}; ++ ++ LKTRTrace("%.*s/%.*s, b%d, allow_neg %d, type 0%o, dlgt %d\n", ++ DLNPair(hidden_parent), DLNPair(dentry), bindex, allow_neg, ++ type, dlgt); ++ DEBUG_ON(IS_ROOT(dentry)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ wh_found = 0; ++ sb = dentry->d_sb; ++ wh_able = sbr_is_whable(sb, bindex); ++ lkup.nfsmnt = au_nfsmnt(sb, bindex); ++ name = &dentry->d_name; ++ if (unlikely(wh_able)) { ++#if 0 //def CONFIG_AUFS_ROBR ++ if (strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ wh_found = is_wh(hidden_parent, wh_name, /*try_sio*/0, ++ &lkup); ++ else ++ wh_found = -EPERM; ++#else ++ wh_found = is_wh(hidden_parent, wh_name, /*try_sio*/0, &lkup); ++#endif ++ } ++ //if (LktrCond) wh_found = -1; ++ hidden_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ //set_dbend(dentry, bindex); ++ set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++ real_lookup: ++ // do not superio. ++ hidden_dentry = lkup_one(name->name, hidden_parent, name->len, &lkup); ++ //if (LktrCond) {dput(hidden_dentry); hidden_dentry = ERR_PTR(-1);} ++ if (IS_ERR(hidden_dentry)) ++ goto out; ++ DEBUG_ON(d_unhashed(hidden_dentry)); ++ hidden_inode = hidden_dentry->d_inode; ++ if (!hidden_inode) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (type && type != (hidden_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ ++ if (dbend(dentry) <= bindex) ++ set_dbend(dentry, bindex); ++ if (dbstart(dentry) == -1 || bindex < dbstart(dentry)) ++ set_dbstart(dentry, bindex); ++ set_h_dptr(dentry, bindex, hidden_dentry); ++ ++ if (!hidden_inode || !S_ISDIR(hidden_inode->i_mode) || !wh_able) ++ return hidden_dentry; /* success */ ++ ++ hi_lock_child(hidden_inode); ++ opq = is_diropq(hidden_dentry, &lkup); ++ //if (LktrCond) opq = -1; ++ i_unlock(hidden_inode); ++ if (opq > 0) ++ set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ set_h_dptr(dentry, bindex, NULL); ++ hidden_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++ out_neg: ++ dput(hidden_dentry); ++ hidden_dentry = NULL; ++ out: ++ TraceErrPtr(hidden_dentry); ++ return hidden_dentry; ++} ++ ++/* ++ * returns the number of hidden positive dentries, ++ * otherwise an error. ++ */ ++int lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type) ++{ ++ int npositive, err, allow_neg, dlgt; ++ struct dentry *parent; ++ aufs_bindex_t bindex, btail; ++ const struct qstr *name = &dentry->d_name; ++ struct qstr whname; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, b%d, type 0%o\n", LNPair(name), bstart, type); ++ DEBUG_ON(bstart < 0 || IS_ROOT(dentry)); ++ parent = dget_parent(dentry); ++ ++#if 1 //ndef CONFIG_AUFS_ROBR ++ err = -EPERM; ++ if (unlikely(!strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ goto out; ++#endif ++ ++ err = au_alloc_whname(name->name, name->len, &whname); ++ //if (LktrCond) {au_free_whname(&whname); err = -1;} ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ dlgt = need_dlgt(sb); ++ allow_neg = !type; ++ npositive = 0; ++ btail = dbtaildir(parent); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ struct dentry *hidden_parent, *hidden_dentry; ++ struct inode *hidden_inode; ++ struct inode *hidden_dir; ++ ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (hidden_dentry) { ++ if (hidden_dentry->d_inode) ++ npositive++; ++ if (type != S_IFDIR) ++ break; ++ continue; ++ } ++ hidden_parent = au_h_dptr_i(parent, bindex); ++ if (!hidden_parent) ++ continue; ++ hidden_dir = hidden_parent->d_inode; ++ if (!hidden_dir || !S_ISDIR(hidden_dir->i_mode)) ++ continue; ++ ++ hi_lock_parent(hidden_dir); ++ hidden_dentry = do_lookup(hidden_parent, dentry, bindex, ++ &whname, allow_neg, type, dlgt); ++ // do not dput for testing ++ //if (LktrCond) {hidden_dentry = ERR_PTR(-1);} ++ i_unlock(hidden_dir); ++ err = PTR_ERR(hidden_dentry); ++ if (IS_ERR(hidden_dentry)) ++ goto out_wh; ++ allow_neg = 0; ++ ++ if (dbwh(dentry) != -1) ++ break; ++ if (!hidden_dentry) ++ continue; ++ hidden_inode = hidden_dentry->d_inode; ++ if (!hidden_inode) ++ continue; ++ npositive++; ++ if (!type) ++ type = hidden_inode->i_mode & S_IFMT; ++ if (type != S_IFDIR) ++ break; ++ else if (dbdiropq(dentry) != -1) ++ break; ++ } ++ ++ if (npositive) { ++ LKTRLabel(positive); ++ au_update_dbstart(dentry); ++ } ++ err = npositive; ++ ++ out_wh: ++ au_free_whname(&whname); ++ out: ++ dput(parent); ++ TraceErr(err); ++ return err; ++} ++ ++struct dentry *sio_lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup) ++{ ++ struct dentry *dentry; ++ ++ LKTRTrace("%.*s/%.*s\n", DLNPair(parent), len, name); ++ IMustLock(parent->d_inode); ++ ++ if (!au_test_perm(parent->d_inode, MAY_EXEC, lkup->dlgt)) ++ dentry = lkup_one(name, parent, len, lkup); ++ else { ++ // ugly ++ int dlgt = lkup->dlgt; ++ struct lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .parent = parent, ++ .len = len, ++ .lkup = lkup ++ }; ++ ++ lkup->dlgt = 0; ++ au_wkq_wait(call_lkup_one, &args, /*dlgt*/0); ++ lkup->dlgt = dlgt; ++ } ++ ++ TraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int lkup_neg(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err; ++ struct dentry *parent, *hidden_parent, *hidden_dentry; ++ struct inode *hidden_dir; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, b%d\n", DLNPair(dentry), bindex); ++ parent = dget_parent(dentry); ++ DEBUG_ON(!parent || !parent->d_inode ++ || !S_ISDIR(parent->d_inode->i_mode)); ++ hidden_parent = au_h_dptr_i(parent, bindex); ++ DEBUG_ON(!hidden_parent); ++ hidden_dir = hidden_parent->d_inode; ++ DEBUG_ON(!hidden_dir || !S_ISDIR(hidden_dir->i_mode)); ++ IMustLock(hidden_dir); ++ ++ lkup.nfsmnt = au_nfsmnt(dentry->d_sb, bindex); ++ lkup.dlgt = need_dlgt(dentry->d_sb); ++ hidden_dentry = sio_lkup_one(dentry->d_name.name, hidden_parent, ++ dentry->d_name.len, &lkup); ++ //if (LktrCond) {dput(hidden_dentry); hidden_dentry = ERR_PTR(-1);} ++ err = PTR_ERR(hidden_dentry); ++ if (IS_ERR(hidden_dentry)) ++ goto out; ++ if (unlikely(hidden_dentry->d_inode)) { ++ err = -EIO; ++ IOErr("b%d %.*s should be negative.%s\n", ++ bindex, DLNPair(hidden_dentry), ++ au_flag_test(dentry->d_sb, AuFlag_UDBA_INOTIFY) ? "" : ++ " Try udba=inotify."); ++ dput(hidden_dentry); ++ goto out; ++ } ++ ++ if (bindex < dbstart(dentry)) ++ set_dbstart(dentry, bindex); ++ if (dbend(dentry) < bindex) ++ set_dbend(dentry, bindex); ++ set_h_dptr(dentry, bindex, hidden_dentry); ++ err = 0; ++ ++ out: ++ dput(parent); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * returns the number of found hidden positive dentries, ++ * otherwise an error. ++ */ ++int au_refresh_hdentry(struct dentry *dentry, mode_t type) ++{ ++ int npositive, pgen, new_sz, sgen, dgen; ++ struct aufs_dinfo *dinfo; ++ struct super_block *sb; ++ struct dentry *parent; ++ aufs_bindex_t bindex, parent_bend, parent_bstart, bwh, bdiropq, bend; ++ struct aufs_hdentry *p; ++ //struct nameidata nd; ++ ++ LKTRTrace("%.*s, type 0%o\n", DLNPair(dentry), type); ++ DiMustWriteLock(dentry); ++ sb = dentry->d_sb; ++ DEBUG_ON(IS_ROOT(dentry)); ++ parent = dget_parent(dentry); ++ pgen = au_digen(parent); ++ sgen = au_sigen(sb); ++ dgen = au_digen(dentry); ++ DEBUG_ON(pgen != sgen); ++ ++ npositive = -ENOMEM; ++ new_sz = sizeof(*dinfo->di_hdentry) * (sbend(sb) + 1); ++ dinfo = dtodi(dentry); ++ p = au_kzrealloc(dinfo->di_hdentry, sizeof(*p) * (dinfo->di_bend + 1), ++ new_sz, GFP_KERNEL); ++ //p = NULL; ++ if (unlikely(!p)) ++ goto out; ++ dinfo->di_hdentry = p; ++ ++ bend = dinfo->di_bend; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ p += dinfo->di_bstart; ++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { ++ struct dentry *hd, *hdp; ++ struct aufs_hdentry tmp, *q; ++ aufs_bindex_t new_bindex; ++ ++ hd = p->hd_dentry; ++ if (!hd) ++ continue; ++ hdp = dget_parent(hd); ++ if (hdp == au_h_dptr_i(parent, bindex)) { ++ dput(hdp); ++ continue; ++ } ++ ++ new_bindex = au_find_dbindex(parent, hdp); ++ dput(hdp); ++ DEBUG_ON(new_bindex == bindex); ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { // test here ++ hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ /* swap two hidden dentries, and loop again */ ++ q = dinfo->di_hdentry + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ // test here ++ dinfo->di_bwh = -1; ++ if (unlikely(bwh != -1 && bwh <= sbend(sb) && sbr_is_whable(sb, bwh))) ++ dinfo->di_bwh = bwh; ++ dinfo->di_bdiropq = -1; ++ if (unlikely(bdiropq != -1 && bdiropq <= sbend(sb) ++ && sbr_is_whable(sb, bdiropq))) ++ dinfo->di_bdiropq = bdiropq; ++ parent_bend = dbend(parent); ++ p = dinfo->di_hdentry; ++ for (bindex = 0; bindex <= parent_bend; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_bstart = bindex; ++ break; ++ } ++ p = dinfo->di_hdentry + parent_bend; ++ //for (bindex = parent_bend; bindex > dinfo->di_bstart; bindex--, p--) ++ for (bindex = parent_bend; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bend = bindex; ++ break; ++ } ++ ++ npositive = 0; ++ parent_bstart = dbstart(parent); ++ if (type != S_IFDIR && dinfo->di_bstart == parent_bstart) ++ goto out_dgen; /* success */ ++ ++#if 0 ++ nd.last_type = LAST_ROOT; ++ nd.flags = LOOKUP_FOLLOW; ++ nd.depth = 0; ++ nd.mnt = mntget(??); ++ nd.dentry = dget(parent); ++#endif ++ npositive = lkup_dentry(dentry, parent_bstart, type); ++ //if (LktrCond) npositive = -1; ++ if (npositive < 0) ++ goto out; ++ ++ out_dgen: ++ au_update_digen(dentry); ++ out: ++ dput(parent); ++ TraceErr(npositive); ++ return npositive; ++} ++ ++static int h_d_revalidate(struct dentry *dentry, struct nameidata *nd, ++ int do_udba) ++{ ++ int err, plus, locked, unhashed, is_root, h_plus, is_nfs; ++ struct nameidata fake_nd, *p; ++ aufs_bindex_t bindex, btail, bstart, ibs, ibe; ++ struct super_block *sb; ++ struct inode *inode, *first, *h_inode, *h_cached_inode; ++ umode_t mode, h_mode; ++ struct dentry *h_dentry; ++ int (*reval)(struct dentry *, struct nameidata *); ++ struct qstr *name; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(inode && au_digen(dentry) != au_iigen(inode)); ++ //DbgDentry(dentry); ++ //DbgInode(inode); ++ ++ err = 0; ++ sb = dentry->d_sb; ++ plus = 0; ++ mode = 0; ++ first = NULL; ++ ibs = ibe = -1; ++ unhashed = d_unhashed(dentry); ++ is_root = IS_ROOT(dentry); ++ name = &dentry->d_name; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of INOTIFY. ++ * But inotify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * IN_DELETE for NFS dentry ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ first = au_h_iptr(inode); ++ ibs = ibstart(inode); ++ ibe = ibend(inode); ++ } ++ ++ btail = bstart = dbstart(dentry); ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = dbtaildir(dentry); ++ locked = 0; ++ if (nd) { ++ fake_nd = *nd; ++#ifndef CONFIG_AUFS_FAKE_DM ++ if (dentry != nd->dentry) { ++ di_read_lock_parent(nd->dentry, 0); ++ locked = 1; ++ } ++#endif ++ } ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr_i(dentry, bindex); ++ if (unlikely(!h_dentry)) ++ continue; ++ if (unlikely(do_udba ++ && !is_root ++ && (unhashed != d_unhashed(h_dentry) ++#if 1 ++ || name->len != h_dentry->d_name.len ++ || memcmp(name->name, h_dentry->d_name.name, ++ name->len) ++#endif ++ ))) { ++ LKTRTrace("unhash 0x%x 0x%x, %.*s %.*s\n", ++ unhashed, d_unhashed(h_dentry), ++ DLNPair(dentry), DLNPair(h_dentry)); ++ goto err; ++ } ++ ++ reval = NULL; ++ if (h_dentry->d_op) ++ reval = h_dentry->d_op->d_revalidate; ++ if (unlikely(reval)) { ++ //LKTRLabel(hidden reval); ++ p = fake_dm(&fake_nd, nd, sb, bindex); ++ DEBUG_ON(IS_ERR(p)); ++ err = !reval(h_dentry, p); ++ fake_dm_release(p); ++ if (unlikely(err)) { ++ //Dbg("here\n"); ++ goto err; ++ } ++ } ++ ++ if (unlikely(!do_udba)) ++ continue; ++ ++ /* UDBA tests */ ++ h_inode = h_dentry->d_inode; ++ if (unlikely(!!inode != !!h_inode)) { ++ //Dbg("here\n"); ++ goto err; ++ } ++ ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ is_nfs = 0; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) { ++ h_cached_inode = au_h_iptr_i(inode, bindex); ++ //is_nfs = au_is_nfs(h_cached_inode->i_sb); ++ } ++ ++ LKTRTrace("{%d, 0%o, %p}, h{%d, 0%o, %p}\n", ++ plus, mode, h_cached_inode, ++ h_plus, h_mode, h_inode); ++ if (unlikely(plus != h_plus || mode != h_mode ++ || (h_cached_inode != h_inode /* && !is_nfs */))) { ++ //Dbg("here\n"); ++ goto err; ++ } ++ continue; ++ ++ err: ++ err = -EINVAL; ++ break; ++ } ++#ifndef CONFIG_AUFS_FAKE_DM ++ if (unlikely(locked)) ++ di_read_unlock(nd->dentry, 0); ++#endif ++ ++#if 0 ++ // some filesystem uses CURRENT_TIME_SEC instead of CURRENT_TIME. ++ // NFS may stop IN_DELETE because of DCACHE_NFSFS_RENAMED. ++#if 0 ++ && (!timespec_equal(&inode->i_ctime, &first->i_ctime) ++ || !timespec_equal(&inode->i_atime, &first->i_atime)) ++#endif ++ if (unlikely(!err && udba && first)) ++ au_cpup_attr_all(inode); ++#endif ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int simple_reval_dpath(struct dentry *dentry, int sgen) ++{ ++ int err; ++ mode_t type; ++ struct dentry *parent; ++ struct inode *inode; ++ ++ LKTRTrace("%.*s, sgen %d\n", DLNPair(dentry), sgen); ++ SiMustAnyLock(dentry->d_sb); ++ DiMustWriteLock(dentry); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode); ++ ++ if (au_digen(dentry) == sgen) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ DEBUG_ON(au_digen(parent) != sgen); ++#ifdef CONFIG_AUFS_DEBUG ++ { ++ struct dentry *d = parent; ++ while (!IS_ROOT(d)) { ++ DEBUG_ON(au_digen(d) != sgen); ++ d = d->d_parent; ++ } ++ } ++#endif ++ type = (inode->i_mode & S_IFMT); ++ /* returns a number of positive dentries */ ++ err = au_refresh_hdentry(dentry, type); ++ if (err >= 0) ++ err = au_refresh_hinode(inode, dentry); ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ dput(parent); ++ TraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, int sgen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ struct inode *inode; ++ ++ LKTRTrace("%.*s, sgen %d\n", DLNPair(dentry), sgen); ++ DEBUG_ON(!dentry->d_inode); ++ DiMustWriteLock(dentry); ++ ++ if (!stosi(dentry->d_sb)->si_failed_refresh_dirs) ++ return simple_reval_dpath(dentry, sgen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: cpup_dirs() */ ++ err = 0; ++ while (au_digen(dentry) != sgen) { ++ d = dentry; ++ while (1) { ++ parent = d->d_parent; // dget_parent() ++ if (au_digen(parent) == sgen) ++ break; ++ d = parent; ++ } ++ ++ inode = d->d_inode; ++ if (d != dentry) { ++ //i_lock(inode); ++ di_write_lock_child(d); ++ } ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen(d) != sgen) { ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ /* returns a number of positive dentries */ ++ err = au_refresh_hdentry(d, inode->i_mode & S_IFMT); ++ //err = -1; ++ if (err >= 0) ++ err = au_refresh_hinode(inode, d); ++ //err = -1; ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ } ++ ++ if (d != dentry) { ++ di_write_unlock(d); ++ //i_unlock(inode); ++ } ++ if (unlikely(err)) ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * THIS IS A BOOLEAN FUNCTION: returns 1 if valid, 0 otherwise. ++ * nfsd passes NULL as nameidata. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd) ++{ ++ int valid, sgen, err, do_udba; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ LKTRTrace("dentry %.*s\n", DLNPair(dentry)); ++ if (nd && nd->dentry) ++ LKTRTrace("nd %.*s\n", DLNPair(nd->dentry)); ++ //dir case: DEBUG_ON(dentry->d_parent != nd->dentry); ++ //remove failure case: DEBUG_ON(!IS_ROOT(dentry) && d_unhashed(dentry)); ++ DEBUG_ON(!dentry->d_fsdata); ++ //DbgDentry(dentry); ++ ++ err = -EINVAL; ++ inode = dentry->d_inode; ++ //DbgInode(inode); ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ sgen = au_sigen(sb); ++ if (au_digen(dentry) == sgen) ++ di_read_lock_child(dentry, !AUFS_I_RLOCK); ++ else { ++ DEBUG_ON(IS_ROOT(dentry)); ++#ifdef ForceInotify ++ Dbg("UDBA or digen, %.*s\n", DLNPair(dentry)); ++#endif ++ //i_lock(inode); ++ di_write_lock_child(dentry); ++ if (inode) ++ err = au_reval_dpath(dentry, sgen); ++ //err = -1; ++ di_downgrade_lock(dentry, AUFS_I_RLOCK); ++ //i_unlock(inode); ++ if (unlikely(err)) ++ goto out; ++ ii_read_unlock(inode); ++ DEBUG_ON(au_iigen(inode) != sgen); ++ } ++ ++ if (inode) { ++ if (au_iigen(inode) == sgen) ++ ii_read_lock_child(inode); ++ else { ++ DEBUG_ON(IS_ROOT(dentry)); ++#ifdef ForceInotify ++ Dbg("UDBA or survived, %.*s\n", DLNPair(dentry)); ++#endif ++ ii_write_lock_child(inode); ++ err = au_refresh_hinode(inode, dentry); ++ ii_downgrade_lock(inode); ++ if (unlikely(err)) ++ goto out; ++ DEBUG_ON(au_iigen(inode) != sgen); ++ } ++ } ++ ++#if 0 // fix it ++ /* parent dir i_nlink is not updated in the case of setattr */ ++ if (S_ISDIR(inode->i_mode)) { ++ i_lock(inode); ++ ii_write_lock(inode); ++ au_cpup_attr_nlink(inode); ++ ii_write_unlock(inode); ++ i_unlock(inode); ++ } ++#endif ++ ++ err = -EINVAL; ++ do_udba = !au_flag_test(sb, AuFlag_UDBA_NONE); ++ if (do_udba && inode && ibstart(inode) >= 0 ++ && au_test_higen(inode, au_h_iptr(inode))) ++ goto out; ++ err = h_d_revalidate(dentry, nd, do_udba); ++ //err = -1; ++ ++ out: ++ aufs_read_unlock(dentry, AUFS_I_RLOCK); ++ TraceErr(err); ++ valid = !err; ++ //au_debug_on(); ++ if (!valid) ++ LKTRTrace("%.*s invalid\n", DLNPair(dentry)); ++ //au_debug_off(); ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ struct aufs_dinfo *dinfo; ++ aufs_bindex_t bend, bindex; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(!d_unhashed(dentry)); ++ ++ dinfo = dentry->d_fsdata; ++ if (unlikely(!dinfo)) ++ return; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_bstart; ++ if (bindex >= 0) { ++ struct aufs_hdentry *p; ++ bend = dinfo->di_bend; ++ DEBUG_ON(bend < bindex); ++ p = dinfo->di_hdentry + bindex; ++ while (bindex++ <= bend) { ++ if (p->hd_dentry) ++ hdput(p); ++ p++; ++ } ++ } ++ kfree(dinfo->di_hdentry); ++ cache_free_dinfo(dinfo); ++} ++ ++#if 0 ++/* it may be called at remount time, too */ ++static void aufs_d_iput(struct dentry *dentry, struct inode *inode) ++{ ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, i%lu\n", DLNPair(dentry), inode->i_ino); ++ ++ sb = dentry->d_sb; ++#if 0 ++ si_read_lock(sb); ++ if (unlikely(au_flag_test(sb, AuFlag_PLINK) ++ && au_is_plinked(sb, inode))) { ++ ii_write_lock(inode); ++ au_update_brange(inode, 1); ++ ii_write_unlock(inode); ++ } ++ si_read_unlock(sb); ++#endif ++ iput(inode); ++} ++#endif ++ ++struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++ //.d_iput = aufs_d_iput ++}; +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/dentry.h linux-2.6.22.1/fs/aufs/dentry.h +--- linux-2.6.22.1.oorig/fs/aufs/dentry.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/dentry.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,183 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dentry.h,v 1.25 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "misc.h" ++ ++struct aufs_hdentry { ++ struct dentry *hd_dentry; ++}; ++ ++struct aufs_dinfo { ++ atomic_t di_generation; ++ ++ struct aufs_rwsem di_rwsem; ++ aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq; ++ struct aufs_hdentry *di_hdentry; ++}; ++ ++struct lkup_args { ++ struct vfsmount *nfsmnt; ++ int dlgt; ++ //struct super_block *sb; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++#if defined(CONFIG_AUFS_LHASH_PATCH) || defined(CONFIG_AUFS_DLGT) ++struct dentry *lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup); ++#else ++static inline ++struct dentry *lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup) ++{ ++ return lookup_one_len(name, parent, len); ++} ++#endif ++ ++extern struct dentry_operations aufs_dop; ++struct dentry *sio_lkup_one(const char *name, struct dentry *parent, int len, ++ struct lkup_args *lkup); ++int lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type); ++int lkup_neg(struct dentry *dentry, aufs_bindex_t bindex); ++int au_refresh_hdentry(struct dentry *dentry, mode_t type); ++int au_reval_dpath(struct dentry *dentry, int sgen); ++ ++/* dinfo.c */ ++int au_alloc_dinfo(struct dentry *dentry); ++struct aufs_dinfo *dtodi(struct dentry *dentry); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++aufs_bindex_t dbstart(struct dentry *dentry); ++aufs_bindex_t dbend(struct dentry *dentry); ++aufs_bindex_t dbwh(struct dentry *dentry); ++aufs_bindex_t dbdiropq(struct dentry *dentry); ++struct dentry *au_h_dptr_i(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_dptr(struct dentry *dentry); ++ ++aufs_bindex_t dbtail(struct dentry *dentry); ++aufs_bindex_t dbtaildir(struct dentry *dentry); ++aufs_bindex_t dbtail_generic(struct dentry *dentry); ++ ++void set_dbstart(struct dentry *dentry, aufs_bindex_t bindex); ++void set_dbend(struct dentry *dentry, aufs_bindex_t bindex); ++void set_dbwh(struct dentry *dentry, aufs_bindex_t bindex); ++void set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex); ++void hdput(struct aufs_hdentry *hdentry); ++void set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++ ++void au_update_digen(struct dentry *dentry); ++void au_update_dbstart(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_digen(struct dentry *d) ++{ ++ return atomic_read(&dtodi(d)->di_generation); ++} ++ ++#ifdef CONFIG_AUFS_HINOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&dtodi(d)->di_generation); ++} ++#endif /* CONFIG_AUFS_HINOTIFY */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hinotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3 ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define ReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{di_read_lock(d, flags, AuLsc_DI_##lsc);} ++ ++#define WriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{di_write_lock(d, AuLsc_DI_##lsc);} ++ ++#define RWLockFuncs(name, lsc) \ ++ ReadLockFunc(name, lsc); \ ++ WriteLockFunc(name, lsc) ++ ++RWLockFuncs(child, CHILD); ++RWLockFuncs(child2, CHILD2); ++RWLockFuncs(child3, CHILD3); ++RWLockFuncs(parent, PARENT); ++RWLockFuncs(parent2, PARENT2); ++RWLockFuncs(parent3, PARENT3); ++ ++#undef ReadLockFunc ++#undef WriteLockFunc ++#undef RWLockFunc ++ ++/* to debug easier, do not make them inlined functions */ ++#define DiMustReadLock(d) do { \ ++ SiMustAnyLock((d)->d_sb); \ ++ RwMustReadLock(&dtodi(d)->di_rwsem); \ ++} while (0) ++ ++#define DiMustWriteLock(d) do { \ ++ SiMustAnyLock((d)->d_sb); \ ++ RwMustWriteLock(&dtodi(d)->di_rwsem); \ ++} while (0) ++ ++#define DiMustAnyLock(d) do { \ ++ SiMustAnyLock((d)->d_sb); \ ++ RwMustAnyLock(&dtodi(d)->di_rwsem); \ ++} while (0) ++ ++#define DiMustNoWaiters(d) RwMustNoWaiters(&dtodi(d)->di_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/dinfo.c linux-2.6.22.1/fs/aufs/dinfo.c +--- linux-2.6.22.1.oorig/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/dinfo.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,419 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dinfo.c,v 1.23 2007/05/07 03:43:36 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++int au_alloc_dinfo(struct dentry *dentry) ++{ ++ struct aufs_dinfo *dinfo; ++ struct super_block *sb; ++ int nbr; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(dentry->d_fsdata); ++ ++ dinfo = cache_alloc_dinfo(); ++ //if (LktrCond) {cache_free_dinfo(dinfo); dinfo = NULL;} ++ if (dinfo) { ++ sb = dentry->d_sb; ++ nbr = sbend(sb) + 1; ++ if (unlikely(!nbr)) ++ nbr++; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), ++ GFP_KERNEL); ++ //if (LktrCond) ++ //{kfree(dinfo->di_hdentry); dinfo->di_hdentry = NULL;} ++ if (dinfo->di_hdentry) { ++ rw_init_wlock_nested(&dinfo->di_rwsem, AuLsc_DI_PARENT); ++ dinfo->di_bstart = dinfo->di_bend = -1; ++ dinfo->di_bwh = dinfo->di_bdiropq = -1; ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ ++ dentry->d_fsdata = dinfo; ++ dentry->d_op = &aufs_dop; ++ return 0; /* success */ ++ } ++ cache_free_dinfo(dinfo); ++ } ++ TraceErr(-ENOMEM); ++ return -ENOMEM; ++} ++ ++struct aufs_dinfo *dtodi(struct dentry *dentry) ++{ ++ struct aufs_dinfo *dinfo = dentry->d_fsdata; ++ DEBUG_ON(!dinfo ++ || !dinfo->di_hdentry ++ /* || stosi(dentry->d_sb)->si_bend < dinfo->di_bend */ ++ || dinfo->di_bend < dinfo->di_bstart ++ /* dbwh can be outside of this range */ ++ || (0 <= dinfo->di_bdiropq ++ && (dinfo->di_bdiropq < dinfo->di_bstart ++ /* || dinfo->di_bend < dinfo->di_bdiropq */)) ++ ); ++ return dinfo; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ SiMustAnyLock(d->d_sb); ++ // todo: always nested? ++ rw_read_lock_nested(&dtodi(d)->di_rwsem, lsc); ++ if (d->d_inode) { ++ if (flags & AUFS_I_WLOCK) ++ do_ii_write_lock(d->d_inode, lsc); ++ else if (flags & AUFS_I_RLOCK) ++ do_ii_read_lock(d->d_inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ SiMustAnyLock(d->d_sb); ++ if (d->d_inode) { ++ if (flags & AUFS_I_WLOCK) ++ ii_write_unlock(d->d_inode); ++ else if (flags & AUFS_I_RLOCK) ++ ii_read_unlock(d->d_inode); ++ } ++ rw_read_unlock(&dtodi(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ SiMustAnyLock(d->d_sb); ++ rw_dgrade_lock(&dtodi(d)->di_rwsem); ++ if (d->d_inode && (flags & AUFS_I_RLOCK)) ++ ii_downgrade_lock(d->d_inode); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ SiMustAnyLock(d->d_sb); ++ // todo: always nested? ++ rw_write_lock_nested(&dtodi(d)->di_rwsem, lsc); ++ if (d->d_inode) ++ do_ii_write_lock(d->d_inode, lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ SiMustAnyLock(d->d_sb); ++ if (d->d_inode) ++ ii_write_unlock(d->d_inode); ++ rw_write_unlock(&dtodi(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ struct dentry *d; ++ ++ TraceEnter(); ++ DEBUG_ON(d1 == d2 ++ || d1->d_inode == d2->d_inode ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir) ++ for (d = d1; d->d_parent != d; d = d->d_parent) // dget_parent() ++ if (d->d_parent == d2) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ return; ++ } ++ ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ struct dentry *d; ++ ++ TraceEnter(); ++ DEBUG_ON(d1 == d2 ++ || d1->d_inode == d2->d_inode ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir) ++ for (d = d1; d->d_parent != d; d = d->d_parent) // dget_parent() ++ if (d->d_parent == d2) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ return; ++ } ++ ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d1->d_inode == d2->d_inode) ++ rw_write_unlock(&dtodi(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++aufs_bindex_t dbstart(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return dtodi(dentry)->di_bstart; ++} ++ ++aufs_bindex_t dbend(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return dtodi(dentry)->di_bend; ++} ++ ++aufs_bindex_t dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return dtodi(dentry)->di_bwh; ++} ++ ++aufs_bindex_t dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ DEBUG_ON(dentry->d_inode ++ && dentry->d_inode->i_mode ++ && !S_ISDIR(dentry->d_inode->i_mode)); ++ return dtodi(dentry)->di_bdiropq; ++} ++ ++struct dentry *au_h_dptr_i(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ if (dbstart(dentry) < 0 || bindex < dbstart(dentry)) ++ return NULL; ++ DEBUG_ON(bindex < 0 ++ /* || bindex > sbend(dentry->d_sb) */); ++ d = dtodi(dentry)->di_hdentry[0 + bindex].hd_dentry; ++ DEBUG_ON(d && (atomic_read(&d->d_count) <= 0)); ++ return d; ++} ++ ++struct dentry *au_h_dptr(struct dentry *dentry) ++{ ++ return au_h_dptr_i(dentry, dbstart(dentry)); ++} ++ ++aufs_bindex_t dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bend, bwh; ++ ++ bend = dbend(dentry); ++ if (0 <= bend) { ++ bwh = dbwh(dentry); ++ //DEBUG_ON(bend < bwh); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bend) ++ return bwh - 1; ++ } ++ return bend; ++} ++ ++aufs_bindex_t dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bend, bopq; ++ ++ DEBUG_ON(dentry->d_inode ++ && dentry->d_inode->i_mode ++ && !S_ISDIR(dentry->d_inode->i_mode)); ++ ++ bend = dbtail(dentry); ++ if (0 <= bend) { ++ bopq = dbdiropq(dentry); ++ DEBUG_ON(bend < bopq); ++ if (0 <= bopq && bopq < bend) ++ bend = bopq; ++ } ++ return bend; ++} ++ ++aufs_bindex_t dbtail_generic(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ if (inode && S_ISDIR(inode->i_mode)) ++ return dbtaildir(dentry); ++ else ++ return dbtail(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++// hard/soft set ++void set_dbstart(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ DEBUG_ON(sbend(dentry->d_sb) < bindex); ++ /* */ ++ dtodi(dentry)->di_bstart = bindex; ++} ++ ++void set_dbend(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ DEBUG_ON(sbend(dentry->d_sb) < bindex ++ || bindex < dbstart(dentry)); ++ dtodi(dentry)->di_bend = bindex; ++} ++ ++void set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ DEBUG_ON(sbend(dentry->d_sb) < bindex); ++ /* dbwh can be outside of bstart - bend range */ ++ dtodi(dentry)->di_bwh = bindex; ++} ++ ++void set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ DEBUG_ON(sbend(dentry->d_sb) < bindex); ++ DEBUG_ON((bindex != -1 ++ && (bindex < dbstart(dentry) || dbend(dentry) < bindex)) ++ || (dentry->d_inode ++ && dentry->d_inode->i_mode ++ && !S_ISDIR(dentry->d_inode->i_mode))); ++ dtodi(dentry)->di_bdiropq = bindex; ++} ++ ++void hdput(struct aufs_hdentry *hd) ++{ ++ dput(hd->hd_dentry); ++} ++ ++void set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct aufs_hdentry *hd = dtodi(dentry)->di_hdentry + bindex; ++ DiMustWriteLock(dentry); ++ DEBUG_ON(bindex < dtodi(dentry)->di_bstart ++ || bindex > dtodi(dentry)->di_bend ++ || (h_dentry && atomic_read(&h_dentry->d_count) <= 0) ++ || (h_dentry && hd->hd_dentry) ++ ); ++ if (hd->hd_dentry) ++ hdput(hd); ++ hd->hd_dentry = h_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ //DiMustWriteLock(dentry); ++ DEBUG_ON(!dentry->d_sb); ++ atomic_set(&dtodi(dentry)->di_generation, au_sigen(dentry->d_sb)); ++} ++ ++void au_update_dbstart(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bstart = dbstart(dentry), bend = dbend(dentry); ++ struct dentry *hidden_dentry; ++ ++ DiMustWriteLock(dentry); ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!hidden_dentry) ++ continue; ++ if (hidden_dentry->d_inode) { ++ set_dbstart(dentry, bindex); ++ return; ++ } ++ set_h_dptr(dentry, bindex, NULL); ++ } ++ //set_dbstart(dentry, -1); ++ //set_dbend(dentry, -1); ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *hidden_dentry) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); bindex <= bend; bindex++) ++ if (au_h_dptr_i(dentry, bindex) == hidden_dentry) ++ return bindex; ++ return -1; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/dir.c linux-2.6.22.1/fs/aufs/dir.c +--- linux-2.6.22.1.oorig/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/dir.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,564 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dir.c,v 1.36 2007/05/14 03:38:52 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ struct dentry *dentry, *hidden_dentry; ++ aufs_bindex_t bindex, btail, bstart; ++ struct file *hidden_file; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(!S_ISDIR(dentry->d_inode->i_mode)); ++ ++ /* open all hidden dirs */ ++ bstart = dbstart(dentry); ++#if 1 ++ for (bindex = fbstart(file); bindex < bstart; bindex++) ++ set_h_fptr(file, bindex, NULL); ++#endif ++ set_fbstart(file, bstart); ++ btail = dbtaildir(dentry); ++#if 1 ++ for (bindex = fbend(file); btail < bindex; bindex--) ++ set_h_fptr(file, bindex, NULL); ++#endif ++ set_fbend(file, btail); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!hidden_dentry) ++ continue; ++ hidden_file = au_h_fptr_i(file, bindex); ++ if (hidden_file) { ++ DEBUG_ON(hidden_file->f_dentry != hidden_dentry); ++ continue; ++ } ++ ++ hidden_file = hidden_open(dentry, bindex, file->f_flags); ++ // unavailable ++ //if (LktrCond) {fput(hidden_file); ++ //br_put(stobr(dentry->d_sb, bindex));hidden_file=ERR_PTR(-1);} ++ err = PTR_ERR(hidden_file); ++ if (IS_ERR(hidden_file)) ++ goto out; // close all? ++ //cpup_file_flags(hidden_file, file); ++ set_h_fptr(file, bindex, hidden_file); ++ } ++ err = 0; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *hidden_dentry; ++ struct file *hidden_file; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, 0x%x\n", DLNPair(dentry), flags); ++ DEBUG_ON(!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)); ++ ++ err = 0; ++ set_fvdir_cache(file, NULL); ++ file->f_version = dentry->d_inode->i_version; ++ bindex = dbstart(dentry); ++ set_fbstart(file, bindex); ++ btail = dbtaildir(dentry); ++ set_fbend(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!hidden_dentry) ++ continue; ++ ++ hidden_file = hidden_open(dentry, bindex, flags); ++ //if (LktrCond) {fput(hidden_file); ++ //br_put(stobr(dentry->d_sb, bindex));hidden_file=ERR_PTR(-1);} ++ if (!IS_ERR(hidden_file)) { ++ set_h_fptr(file, bindex, hidden_file); ++ continue; ++ } ++ err = PTR_ERR(hidden_file); ++ } ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = fbstart(file); !err && bindex <= btail; bindex++) ++ set_h_fptr(file, bindex, NULL); ++ set_fbstart(file, -1); ++ set_fbend(file, -1); ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode, struct file *file) ++{ ++ return au_do_open(inode, file, do_open_dir); ++} ++ ++static int aufs_release_dir(struct inode *inode, struct file *file) ++{ ++ struct aufs_vdir *vdir_cache; ++ struct super_block *sb; ++ ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(file->f_dentry)); ++ ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb); ++ fi_write_lock(file); ++ vdir_cache = fvdir_cache(file); ++ if (vdir_cache) ++ free_vdir(vdir_cache); ++ fi_write_unlock(file); ++ au_fin_finfo(file); ++ si_read_unlock(sb); ++ return 0; ++} ++ ++static int fsync_dir(struct dentry *dentry, int datasync) ++{ ++ int err; ++ struct inode *inode; ++ struct super_block *sb; ++ aufs_bindex_t bend, bindex; ++ ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), datasync); ++ DiMustAnyLock(dentry); ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ IiMustAnyLock(inode); ++ ++ err = 0; ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); !err && bindex <= bend; bindex++) { ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct file_operations *fop; ++ ++ if (test_ro(sb, bindex, inode)) ++ continue; ++ h_dentry = au_h_dptr_i(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = h_dentry->d_inode; ++ if (!h_inode) ++ continue; ++ ++ /* cf. fs/nsfd/vfs.c and fs/nfsd/nfs4recover.c */ ++ //hdir_lock(h_inode, inode, bindex); ++ i_lock(h_inode); ++ fop = (void*)h_inode->i_fop; ++ err = filemap_fdatawrite(h_inode->i_mapping); ++ if (!err && fop && fop->fsync) ++ err = fop->fsync(NULL, h_dentry, datasync); ++ if (!err) ++ err = filemap_fdatawrite(h_inode->i_mapping); ++ //hdir_unlock(h_inode, inode, bindex); ++ i_unlock(h_inode); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, struct dentry *dentry, ++ int datasync) ++{ ++ int err; ++ struct inode *inode; ++ struct file *hidden_file; ++ struct super_block *sb; ++ aufs_bindex_t bend, bindex; ++ ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), datasync); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ err = 0; ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ if (file) { ++ err = au_reval_and_lock_finfo(file, reopen_dir, /*wlock*/1, ++ /*locked*/1); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ } else ++ di_read_lock_child(dentry, !AUFS_I_WLOCK); ++ ++ ii_write_lock_child(inode); ++ if (file) { ++ bend = fbend(file); ++ for (bindex = fbstart(file); !err && bindex <= bend; bindex++) { ++ hidden_file = au_h_fptr_i(file, bindex); ++ if (!hidden_file || test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = -EINVAL; ++ if (hidden_file->f_op && hidden_file->f_op->fsync) { ++ // todo: try do_fsync() in fs/sync.c ++#if 0 ++ DEBUG_ON(hidden_file->f_dentry->d_inode ++ != au_h_iptr_i(inode, bindex)); ++ hdir_lock(hidden_file->f_dentry->d_inode, inode, ++ bindex); ++#else ++ i_lock(hidden_file->f_dentry->d_inode); ++#endif ++ err = hidden_file->f_op->fsync ++ (hidden_file, hidden_file->f_dentry, ++ datasync); ++ //err = -1; ++#if 0 ++ hdir_unlock(hidden_file->f_dentry->d_inode, ++ inode, bindex); ++#else ++ i_unlock(hidden_file->f_dentry->d_inode); ++#endif ++ } ++ } ++ } else ++ err = fsync_dir(dentry, datasync); ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ if (file) ++ fi_write_unlock(file); ++ else ++ di_read_unlock(dentry, !AUFS_I_WLOCK); ++ ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld\n", DLNPair(dentry), file->f_pos); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ au_nfsd_lockdep_off(); ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, reopen_dir, /*wlock*/1, ++ /*locked*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ ii_write_lock_child(inode); ++ err = au_init_vdir(file); ++ if (unlikely(err)) { ++ ii_write_unlock(inode); ++ goto out_unlock; ++ } ++ //DbgVdir(fvdir_cache(file));// goto out_unlock; ++ ++ /* nfsd filldir calls lookup_one_len(). */ ++ ii_downgrade_lock(inode); ++ err = au_fill_de(file, dirent, filldir); ++ //DbgVdir(fvdir_cache(file));// goto out_unlock; ++ ++ inode->i_atime = au_h_iptr(inode)->i_atime; ++ ii_read_unlock(inode); ++ ++ out_unlock: ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ au_nfsd_lockdep_on(); ++#if 0 // debug ++ if (LktrCond) ++ igrab(inode); ++#endif ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct test_empty_arg { ++ struct aufs_nhash *whlist; ++ int whonly; ++ aufs_bindex_t bindex; ++ int err, called; ++}; ++ ++static int test_empty_cb(void *__arg, const char *__name, int namelen, ++ loff_t offset, filldir_ino_t ino, unsigned int d_type) ++{ ++ struct test_empty_arg *arg = __arg; ++ char *name = (void*)__name; ++ ++ LKTRTrace("%.*s\n", namelen, name); ++ ++ arg->err = 0; ++ arg->called++; ++ //smp_mb(); ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ return 0; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (arg->whonly && !test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!test_known_wh(arg->whlist, name, namelen)) ++ arg->err = append_wh(arg->whlist, name, namelen, arg->bindex); ++ ++ out: ++ //smp_mb(); ++ TraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, dlgt; ++ struct file *hidden_file; ++ ++ LKTRTrace("%.*s, {%p, %d, %d}\n", ++ DLNPair(dentry), arg->whlist, arg->whonly, arg->bindex); ++ ++ hidden_file = hidden_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY ++ | O_LARGEFILE); ++ err = PTR_ERR(hidden_file); ++ if (IS_ERR(hidden_file)) ++ goto out; ++ ++ dlgt = need_dlgt(dentry->d_sb); ++ //hidden_file->f_pos = 0; ++ do { ++ arg->err = 0; ++ arg->called = 0; ++ //smp_mb(); ++ err = vfsub_readdir(hidden_file, test_empty_cb, arg, dlgt); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && arg->called); ++ fput(hidden_file); ++ sbr_put(dentry->d_sb, arg->bindex); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct dentry *hidden_dentry; ++ struct inode *hidden_inode; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ hidden_dentry = au_h_dptr_i(dentry, arg->bindex); ++ DEBUG_ON(!hidden_dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode || !S_ISDIR(hidden_inode->i_mode)); ++ ++ hi_lock_child(hidden_inode); ++ err = au_test_perm(hidden_inode, MAY_EXEC | MAY_READ, ++ need_dlgt(dentry->d_sb)); ++ i_unlock(hidden_inode); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ au_wkq_wait(call_do_test_empty, &args, /*dlgt*/0); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ struct inode *inode; ++ struct test_empty_arg arg; ++ struct aufs_nhash *whlist; ++ aufs_bindex_t bindex, bstart, btail; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode || !S_ISDIR(inode->i_mode)); ++ ++ whlist = nhash_new(GFP_KERNEL); ++ err = PTR_ERR(whlist); ++ if (IS_ERR(whlist)) ++ goto out; ++ ++ bstart = dbstart(dentry); ++ arg.whlist = whlist; ++ arg.whonly = 0; ++ arg.bindex = bstart; ++ err = do_test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ arg.whonly = 1; ++ btail = dbtaildir(dentry); ++ for (bindex = bstart + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *hidden_dentry; ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (hidden_dentry && hidden_dentry->d_inode) { ++ DEBUG_ON(!S_ISDIR(hidden_dentry->d_inode->i_mode)); ++ arg.bindex = bindex; ++ err = do_test_empty(dentry, &arg); ++ } ++ } ++ ++ out_whlist: ++ nhash_del(whlist); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++int test_empty(struct dentry *dentry, struct aufs_nhash *whlist) ++{ ++ int err; ++ struct inode *inode; ++ struct test_empty_arg arg; ++ aufs_bindex_t bindex, btail; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode || !S_ISDIR(inode->i_mode)); ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.whonly = 1; ++ btail = dbtaildir(dentry); ++ for (bindex = dbstart(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *hidden_dentry; ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (hidden_dentry && hidden_dentry->d_inode) { ++ DEBUG_ON(!S_ISDIR(hidden_dentry->d_inode->i_mode)); ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ DEBUG_ON(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ dir->i_nlink += h_dir->i_nlink - 2; ++ if (unlikely(h_dir->i_nlink < 2)) ++ dir->i_nlink += 2; ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ DEBUG_ON(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ dir->i_nlink -= h_dir->i_nlink - 2; ++ if (unlikely(h_dir->i_nlink < 2)) ++ dir->i_nlink -= 2; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 // comment ++struct file_operations { ++ struct module *owner; ++ loff_t (*llseek) (struct file *, loff_t, int); ++ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ++ ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); ++ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ++ ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); ++ int (*readdir) (struct file *, void *, filldir_t); ++ unsigned int (*poll) (struct file *, struct poll_table_struct *); ++ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); ++ long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); ++ long (*compat_ioctl) (struct file *, unsigned int, unsigned long); ++ int (*mmap) (struct file *, struct vm_area_struct *); ++ int (*open) (struct inode *, struct file *); ++ int (*flush) (struct file *); ++ int (*release) (struct inode *, struct file *); ++ int (*fsync) (struct file *, struct dentry *, int datasync); ++ int (*aio_fsync) (struct kiocb *, int datasync); ++ int (*fasync) (int, struct file *, int); ++ int (*lock) (struct file *, int, struct file_lock *); ++ ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ++ ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ++ ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); ++ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); ++ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); ++ int (*check_flags)(int); ++ int (*dir_notify)(struct file *file, unsigned long arg); ++ int (*flock) (struct file *, int, struct file_lock *); ++}; ++#endif ++ ++struct file_operations aufs_dir_fop = { ++ .read = generic_read_dir, ++ .readdir = aufs_readdir, ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush, ++ .fsync = aufs_fsync_dir, ++}; +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/dir.h linux-2.6.22.1/fs/aufs/dir.h +--- linux-2.6.22.1.oorig/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/dir.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,125 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: dir.h,v 1.18 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++#define filldir_ino_t u64 ++#else ++#define filldir_ino_t ino_t ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++#define AUFS_DEBLK_SIZE 512 // todo: changable ++#define AUFS_NHASH_SIZE 32 // todo: changable ++#if AUFS_DEBLK_SIZE < NAME_MAX || PAGE_SIZE < AUFS_DEBLK_SIZE ++#error invalid size AUFS_DEBLK_SIZE ++#endif ++ ++typedef char aufs_deblk_t[AUFS_DEBLK_SIZE]; ++ ++struct aufs_nhash { ++ struct hlist_head heads[AUFS_NHASH_SIZE]; ++}; ++ ++struct aufs_destr { ++ unsigned char len; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct aufs_dehstr { ++ struct hlist_node hash; ++ struct aufs_destr *str; ++}; ++ ++struct aufs_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ //caution: packed ++ struct aufs_destr de_str; ++} __attribute__ ((packed)); ++ ++struct aufs_wh { ++ struct hlist_node wh_hash; ++ aufs_bindex_t wh_bindex; ++ struct aufs_destr wh_str; ++} __attribute__ ((packed)); ++ ++union aufs_deblk_p { ++ unsigned char *p; ++ aufs_deblk_t *deblk; ++ struct aufs_de *de; ++}; ++ ++struct aufs_vdir { ++ aufs_deblk_t **vd_deblk; ++ int vd_nblk; ++ struct { ++ int i; ++ union aufs_deblk_p p; ++ } vd_last; ++ ++ unsigned long vd_version; ++ unsigned long vd_jiffy; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern struct file_operations aufs_dir_fop; ++int au_test_empty_lower(struct dentry *dentry); ++int test_empty(struct dentry *dentry, struct aufs_nhash *whlist); ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++ ++/* vdir.c */ ++struct aufs_nhash *nhash_new(gfp_t gfp); ++void nhash_del(struct aufs_nhash *nhash); ++void nhash_init(struct aufs_nhash *nhash); ++void nhash_move(struct aufs_nhash *dst, struct aufs_nhash *src); ++void nhash_fin(struct aufs_nhash *nhash); ++int is_longer_wh(struct aufs_nhash *whlist, aufs_bindex_t btgt, int limit); ++int test_known_wh(struct aufs_nhash *whlist, char *name, int namelen); ++int append_wh(struct aufs_nhash *whlist, char *name, int namelen, ++ aufs_bindex_t bindex); ++void free_vdir(struct aufs_vdir *vdir); ++int au_init_vdir(struct file *file); ++int au_fill_de(struct file *file, void *dirent, filldir_t filldir); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++unsigned int au_name_hash(const unsigned char *name, unsigned int len) ++{ ++ return (full_name_hash(name, len) % AUFS_NHASH_SIZE); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/export.c linux-2.6.22.1/fs/aufs/export.c +--- linux-2.6.22.1.oorig/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/export.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,585 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: export.c,v 1.7 2007/05/14 03:38:24 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++extern struct export_operations export_op_default; ++#define CALL(ops, func) (((ops)->func) ? ((ops)->func) : export_op_default.func) ++#define is_anon(d) ((d)->d_flags & DCACHE_DISCONNECTED) ++ ++union conv { ++#if BITS_PER_LONG == 32 ++ __u32 a[1]; ++#else ++ __u32 a[2]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ u.a[0] = a[0]; ++#if BITS_PER_LONG == 64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ u.ino = ino; ++ a[0] = u.a[0]; ++#if BITS_PER_LONG == 64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++static void decode_br_id_sigen(__u32 a, aufs_bindex_t *br_id, ++ aufs_bindex_t *sigen) ++{ ++ BUILD_BUG_ON((sizeof(*br_id) + sizeof(*sigen)) > sizeof(a)); ++ *br_id = a >> 16; ++ DEBUG_ON(*br_id < 0); ++ *sigen = a; ++ DEBUG_ON(*sigen < 0); ++} ++ ++static __u32 encode_br_id_sigen(aufs_bindex_t br_id, aufs_bindex_t sigen) ++{ ++ DEBUG_ON(br_id < 0 || sigen < 0); ++ return (br_id << 16) | sigen; ++} ++ ++/* NFS file handle */ ++enum { ++ /* support 64bit inode number */ ++ /* but untested */ ++ Fh_br_id_sigen, ++ Fh_ino1, ++#if BITS_PER_LONG == 64 ++ Fh_ino2, ++#endif ++ Fh_dir_ino1, ++#if BITS_PER_LONG == 64 ++ Fh_dir_ino2, ++#endif ++ Fh_h_ino1, ++#if BITS_PER_LONG == 64 ++ Fh_h_ino2, ++#endif ++ Fh_h_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1, ++ Fh_h_ino = Fh_h_ino1, ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ LKTRTrace("i%lu, diri%lu\n", ino, dir_ino); ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (unlikely(!inode)) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ if (unlikely(is_bad_inode(inode))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!S_ISDIR(inode->i_mode)) { ++ struct dentry *d; ++ spin_lock(&dcache_lock); ++ list_for_each_entry(d, &inode->i_dentry, d_alias) ++ if (!is_anon(d) ++ && d->d_parent->d_inode->i_ino == dir_ino) { ++ dentry = dget_locked(d); ++ break; ++ } ++ spin_unlock(&dcache_lock); ++ } else { ++ dentry = d_find_alias(inode); ++ if (dentry ++ && !is_anon(dentry) ++ && dentry->d_parent->d_inode->i_ino == dir_ino) ++ goto out_iput; /* success */ ++ ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++ out_iput: ++ iput(inode); ++ out: ++ TraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct find_name_by_ino { ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset, ++ filldir_ino_t ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = arg; ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *parent; ++ struct inode *dir; ++ struct find_name_by_ino arg; ++ struct file *file; ++ int err; ++ ++ LKTRTrace("i%lu, diri%lu\n", ino, dir_ino); ++ ++ dentry = NULL; ++ dir = ilookup(sb, dir_ino); ++ if (unlikely(!dir)) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ if (unlikely(is_bad_inode(dir))) ++ goto out_iput; ++ ++ dentry = NULL; ++ parent = d_find_alias(dir); ++ if (parent) { ++ if (unlikely(is_anon(parent))) { ++ dput(parent); ++ goto out_iput; ++ } ++ } else ++ goto out_iput; ++ ++ file = dentry_open(parent, NULL, au_dir_roflags); ++ dentry = (void*)file; ++ if (IS_ERR(file)) ++ goto out_iput; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = __getname(); ++ if (unlikely(!arg.name)) ++ goto out_fput; ++ arg.ino = ino; ++ arg.found = 0; ++ ++ do { ++ arg.called = 0; ++ //smp_mb(); ++ err = vfsub_readdir(file, find_name_by_ino, &arg, /*dlgt*/0); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (arg.found) { ++ /* do not call lkup_one(), nor dlgt */ ++ i_lock(dir); ++ dentry = lookup_one_len(arg.name, parent, arg.namelen); ++ i_unlock(dir); ++ TraceErrPtr(dentry); ++ } ++ ++ //out_putname: ++ __putname(arg.name); ++ out_fput: ++ fput(file); ++ out_iput: ++ iput(dir); ++ out: ++ TraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct append_name { ++ int found, called, len; ++ char *h_path; ++ ino_t h_ino; ++}; ++ ++static int append_name(void *arg, const char *name, int len, loff_t pos, ++ filldir_ino_t ino, unsigned int d_type) ++{ ++ struct append_name *a = arg; ++ char *p; ++ ++ a->called++; ++ if (ino != a->h_ino) ++ return 0; ++ ++ DEBUG_ON(len == 1 && *name == '.'); ++ DEBUG_ON(len == 2 && name[0] == '.' && name[1] == '.'); ++ a->len = strlen(a->h_path); ++ memmove(a->h_path - a->len - 1, a->h_path, a->len); ++ a->h_path -= a->len + 1; ++ p = a->h_path + a->len; ++ *p++ = '/'; ++ memcpy(p, name, a->len); ++ a->len += 1 + len; ++ a->found++; ++ return 1; ++} ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static struct dentry* ++decode_by_path(struct super_block *sb, aufs_bindex_t bindex, __u32 *fh, ++ int fh_len, void *context) ++{ ++ struct dentry *dentry, *h_parent, *root, *h_root; ++ struct super_block *h_sb; ++ char *path, *p; ++ struct vfsmount *h_mnt; ++ struct append_name arg; ++ int len, err; ++ struct file *h_file; ++ struct nameidata nd; ++ struct aufs_branch *br; ++ ++ LKTRTrace("b%d\n", bindex); ++ SiMustAnyLock(sb); ++ ++ br = stobr(sb, bindex); ++ //br_get(br); ++ h_mnt = br->br_mnt; ++ h_sb = h_mnt->mnt_sb; ++ LKTRTrace("%s, h_decode_fh\n", au_sbtype(h_sb)); ++ h_parent = CALL(h_sb->s_export_op, decode_fh) ++ (h_sb, fh + Fh_tail, fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ Warn1("%s decode_fh failed\n", au_sbtype(h_sb)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(is_anon(h_parent))) { ++ Warn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ dput(h_parent); ++ goto out; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ path = __getname(); ++ if (unlikely(!path)) { ++ dput(h_parent); ++ goto out; ++ } ++ ++ root = sb->s_root; ++ di_read_lock_parent(root, !AUFS_I_RLOCK); ++ h_root = au_h_dptr_i(root, bindex); ++ di_read_unlock(root, !AUFS_I_RLOCK); ++ arg.h_path = d_path(h_root, h_mnt, path, PATH_MAX); ++ dentry = (void*)arg.h_path; ++ if (unlikely(!arg.h_path || IS_ERR(arg.h_path))) ++ goto out_putname; ++ len = strlen(arg.h_path); ++ arg.h_path = d_path(h_parent, h_mnt, path, PATH_MAX); ++ dentry = (void*)arg.h_path; ++ if (unlikely(!arg.h_path || IS_ERR(arg.h_path))) ++ goto out_putname; ++ LKTRTrace("%s\n", arg.h_path); ++ if (len != 1) ++ arg.h_path += len; ++ LKTRTrace("%s\n", arg.h_path); ++ ++ /* cf. fs/exportfs/expfs.c */ ++ h_file = dentry_open(h_parent, NULL, au_dir_roflags); ++ dentry = (void*)h_file; ++ if (IS_ERR(h_file)) ++ goto out_putname; ++ ++ arg.found = 0; ++ arg.h_ino = decode_ino(fh + Fh_h_ino); ++ do { ++ arg.called = 0; ++ err = vfsub_readdir(h_file, append_name, &arg, /*dlgt*/0); ++ } while (!err && !arg.found && arg.called); ++ LKTRTrace("%s, %d\n", arg.h_path, arg.len); ++ ++ p = d_path(root, stosi(sb)->si_mnt, path, PATH_MAX - arg.len - 2); ++ dentry = (void*)p; ++ if (unlikely(!p || IS_ERR(p))) ++ goto out_fput; ++ p[strlen(p)] = '/'; ++ LKTRTrace("%s\n", p); ++ ++ err = path_lookup(p, LOOKUP_FOLLOW, &nd); ++ dentry = ERR_PTR(err); ++ if (!err) { ++ dentry = dget(nd.dentry); ++ if (unlikely(is_anon(dentry))) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ path_release(&nd); ++ } ++ ++ out_fput: ++ fput(h_file); ++ out_putname: ++ __putname(path); ++ out: ++ //br_put(br); ++ TraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry* ++aufs_decode_fh(struct super_block *sb, __u32 *fh, int fh_len, int fh_type, ++ int (*acceptable)(void *context, struct dentry *de), ++ void *context) ++{ ++ struct dentry *dentry; ++ ino_t ino, dir_ino; ++ aufs_bindex_t bindex, br_id, sigen_v; ++ struct inode *inode, *h_inode; ++ ++ //au_debug_on(); ++ LKTRTrace("%d, fh{i%u, br_id_sigen 0x%x, hi%u}\n", ++ fh_type, fh[Fh_ino], fh[Fh_br_id_sigen], fh[Fh_h_ino]); ++ DEBUG_ON(fh_len < Fh_tail); ++ ++ si_read_lock(sb); ++ lockdep_off(); ++ ++ /* branch id may be wrapped around */ ++ dentry = ERR_PTR(-ESTALE); ++ decode_br_id_sigen(fh[Fh_br_id_sigen], &br_id, &sigen_v); ++ bindex = find_brindex(sb, br_id); ++ if (unlikely(bindex < 0 || au_sigen(sb) < sigen_v)) ++ goto out; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ dentry = decode_by_dir_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, bindex, fh, fh_len, context); ++ if (IS_ERR(dentry)) ++ goto out; ++ if (unlikely(!dentry)) ++ goto out_stale; ++ if (unlikely(dentry->d_inode->i_ino != ino)) ++ goto out_dput; ++ ++ accept: ++ inode = dentry->d_inode; ++ h_inode = NULL; ++ ii_read_lock_child(inode); ++ if (ibstart(inode) <= bindex && bindex <= ibend(inode)) ++ h_inode = au_h_iptr_i(inode, bindex); ++ ii_read_unlock(inode); ++ if (h_inode ++ && h_inode->i_generation == fh[Fh_h_igen] ++ && acceptable(context, dentry)) ++ goto out; /* success */ ++ out_dput: ++ dput(dentry); ++ out_stale: ++ dentry = ERR_PTR(-ESTALE); ++ out: ++ lockdep_on(); ++ si_read_unlock(sb); ++ TraceErrPtr(dentry); ++ //au_debug_off(); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, ++ int connectable) ++{ ++ int err; ++ struct super_block *sb, *h_sb; ++ struct inode *inode, *h_inode, *dir; ++ aufs_bindex_t bindex; ++ union conv u; ++ struct dentry *parent, *h_parent; ++ ++ //au_debug_on(); ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ LKTRTrace("%.*s, max %d, conn %d\n", ++ DLNPair(dentry), *max_len, connectable); ++ DEBUG_ON(is_anon(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode); ++ parent = dentry->d_parent; ++ DEBUG_ON(is_anon(parent)); ++ ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ Warn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ di_read_lock_child(dentry, AUFS_I_RLOCK); ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_flag_test(sb, AuFlag_XINO))) ++ Warn1("NFS-exporting requires xino\n"); ++#if 0 ++ if (unlikely(au_flag_test(sb, AuFlag_UDBA_INOTIFY))) ++ Warn1("udba=inotify is not recommended when exporting\n"); ++#endif ++#endif ++ ++ err = -EPERM; ++ bindex = ibstart(inode); ++ h_sb = sbr_sb(sb, bindex); ++ if (unlikely(!h_sb->s_export_op)) { ++ Err1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_unlock; ++ } ++ ++#if 0 //def CONFIG_AUFS_ROBR ++ if (unlikely(SB_AUFS(h_sb))) { ++ Err1("aufs branch is not supported\n"); ++ goto out_unlock; ++ } ++#endif ++ ++ /* doesn't support pseudo-link */ ++ if (unlikely(bindex < dbstart(dentry) ++ || dbend(dentry) < bindex ++ || !au_h_dptr_i(dentry, bindex))) { ++ Err("%.*s/%.*s, b%d, pseudo-link?\n", ++ DLNPair(dentry->d_parent), DLNPair(dentry), bindex); ++ goto out_unlock; ++ } ++ ++ fh[Fh_br_id_sigen] = encode_br_id_sigen(sbr_id(sb, bindex), ++ au_sigen(sb)); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ dir = parent->d_inode; ++ encode_ino(fh + Fh_dir_ino, dir->i_ino); ++ h_inode = au_h_iptr(inode); ++ encode_ino(fh + Fh_h_ino, h_inode->i_ino); ++ fh[Fh_h_igen] = h_inode->i_generation; ++ ++ /* it should be set at exporting time */ ++ if (unlikely(!h_sb->s_export_op->find_exported_dentry)) { ++ Warn("set default find_exported_dentry for %s\n", ++ au_sbtype(h_sb)); ++ h_sb->s_export_op->find_exported_dentry = find_exported_dentry; ++ } ++ ++ *max_len -= Fh_tail; ++ //LKTRTrace("Fh_tail %d, max_len %d\n", Fh_tail, *max_len); ++ h_parent = au_h_dptr_i(parent, bindex); ++ DEBUG_ON(is_anon(h_parent)); ++ err = fh[Fh_h_type] = CALL(h_sb->s_export_op, encode_fh) ++ (h_parent, fh + Fh_tail, max_len, connectable); ++ *max_len += Fh_tail; ++ if (err != 255) ++ err = 2; //?? ++ else ++ Warn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++ out_unlock: ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ aufs_read_unlock(dentry, AUFS_I_RLOCK); ++ out: ++ TraceErr(err); ++ //au_debug_off(); ++ if (unlikely(err < 0)) ++ err = 255; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 ++struct export_operations { ++ struct dentry *(*decode_fh)(struct super_block *sb, __u32 *fh, int fh_len, int fh_type, ++ int (*acceptable)(void *context, struct dentry *de), ++ void *context); ++ int (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len, ++ int connectable); ++ ++ /* the following are only called from the filesystem itself */ ++ int (*get_name)(struct dentry *parent, char *name, ++ struct dentry *child); ++ struct dentry * (*get_parent)(struct dentry *child); ++ struct dentry * (*get_dentry)(struct super_block *sb, void *inump); ++ ++ /* This is set by the exporting module to a standard helper */ ++ struct dentry * (*find_exported_dentry)( ++ struct super_block *sb, void *obj, void *parent, ++ int (*acceptable)(void *context, struct dentry *de), ++ void *context); ++}; ++#endif ++ ++struct export_operations aufs_export_op = { ++ .decode_fh = aufs_decode_fh, ++ .encode_fh = aufs_encode_fh ++}; +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/f_op.c linux-2.6.22.1/fs/aufs/f_op.c +--- linux-2.6.22.1.oorig/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/f_op.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,684 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: f_op.c,v 1.27 2007/05/14 03:38:24 sfjro Exp $ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* common function to regular file and dir */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++#define FlushArgs hidden_file, id ++int aufs_flush(struct file *file, fl_owner_t id) ++#else ++#define FlushArgs hidden_file ++int aufs_flush(struct file *file) ++#endif ++{ ++ int err; ++ struct dentry *dentry; ++ aufs_bindex_t bindex, bend; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ ++ // aufs_read_lock_file() ++ si_read_lock(dentry->d_sb); ++ fi_read_lock(file); ++ di_read_lock_child(dentry, !AUFS_I_RLOCK); ++ ++ err = 0; ++ bend = fbend(file); ++ for (bindex = fbstart(file); !err && bindex <= bend; bindex++) { ++ struct file *hidden_file; ++ hidden_file = au_h_fptr_i(file, bindex); ++ if (hidden_file && hidden_file->f_op ++ && hidden_file->f_op->flush) ++ err = hidden_file->f_op->flush(FlushArgs); ++ } ++ ++ di_read_unlock(dentry, !AUFS_I_RLOCK); ++ fi_read_unlock(file); ++ si_read_unlock(dentry->d_sb); ++ TraceErr(err); ++ return err; ++} ++#undef FlushArgs ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int do_open_nondir(struct file *file, int flags) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct file *hidden_file; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct aufs_finfo *finfo; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, flags 0%o\n", DLNPair(dentry), flags); ++ FiMustWriteLock(file); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode || S_ISDIR(inode->i_mode)); ++ ++ err = 0; ++ finfo = ftofi(file); ++ finfo->fi_h_vm_ops = NULL; ++ sb = dentry->d_sb; ++ bindex = dbstart(dentry); ++ DEBUG_ON(!au_h_dptr(dentry)->d_inode); ++ /* O_TRUNC is processed already */ ++ BUG_ON(test_ro(sb, bindex, inode) && (flags & O_TRUNC)); ++ ++ hidden_file = hidden_open(dentry, bindex, flags); ++ //if (LktrCond) {fput(hidden_file); br_put(stobr(dentry->d_sb, bindex)); ++ //hidden_file = ERR_PTR(-1);} ++ if (!IS_ERR(hidden_file)) { ++ set_fbstart(file, bindex); ++ set_fbend(file, bindex); ++ set_h_fptr(file, bindex, hidden_file); ++ return 0; /* success */ ++ } ++ err = PTR_ERR(hidden_file); ++ TraceErr(err); ++ return err; ++} ++ ++static int aufs_open_nondir(struct inode *inode, struct file *file) ++{ ++ return au_do_open(inode, file, do_open_nondir); ++} ++ ++static int aufs_release_nondir(struct inode *inode, struct file *file) ++{ ++ struct super_block *sb = file->f_dentry->d_sb; ++ ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(file->f_dentry)); ++ ++ si_read_lock(sb); ++ au_fin_finfo(file); ++ si_read_unlock(sb); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ struct dentry *dentry; ++ struct file *hidden_file; ++ struct super_block *sb; ++ struct inode *h_inode; ++ int dlgt; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(dentry), (unsigned long)count, *ppos); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/0, ++ /*locked*/0); ++ //if (LktrCond) {fi_read_unlock(file); err = -1;} ++ if (unlikely(err)) ++ goto out; ++ ++ /* support LSM and notify */ ++ dlgt = need_dlgt(sb); ++ hidden_file = au_h_fptr(file); ++ h_inode = hidden_file->f_dentry->d_inode; ++ if (!au_flag_test(sb, AuFlag_UDBA_INOTIFY)) ++ err = vfsub_read_u(hidden_file, buf, count, ppos, dlgt); ++ else { ++ struct inode *dir = dentry->d_parent->d_inode, ++ *h_dir = hidden_file->f_dentry->d_parent->d_inode; ++ aufs_bindex_t bstart = fbstart(file); ++ hdir_lock(h_dir, dir, bstart); ++ err = vfsub_read_u(hidden_file, buf, count, ppos, dlgt); ++ hdir_unlock(h_dir, dir, bstart); ++ } ++ memcpy(&file->f_ra, &hidden_file->f_ra, sizeof(file->f_ra)); //?? ++ dentry->d_inode->i_atime = hidden_file->f_dentry->d_inode->i_atime; ++ ++ fi_read_unlock(file); ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++static ssize_t aufs_write(struct file *file, const char __user *__buf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *hidden_file; ++ char __user *buf = (char __user*)__buf; ++ struct inode *h_inode; ++ int dlgt; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(dentry), (unsigned long)count, *ppos); ++ ++ inode = dentry->d_inode; ++ i_lock(inode); ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/1, ++ /*locked*/1); ++ //if (LktrCond) {fi_write_unlock(file); err = -1;} ++ if (unlikely(err)) ++ goto out; ++ err = au_ready_to_write(file, -1); ++ //if (LktrCond) err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* support LSM and notify */ ++ dlgt = need_dlgt(sb); ++ hidden_file = au_h_fptr(file); ++ h_inode = hidden_file->f_dentry->d_inode; ++ if (!au_flag_test(sb, AuFlag_UDBA_INOTIFY)) ++ err = vfsub_write_u(hidden_file, buf, count, ppos, dlgt); ++ else { ++ struct inode *dir = dentry->d_parent->d_inode, ++ *h_dir = hidden_file->f_dentry->d_parent->d_inode; ++ aufs_bindex_t bstart = fbstart(file); ++ hdir_lock(h_dir, dir, bstart); ++ err = vfsub_write_u(hidden_file, buf, count, ppos, dlgt); ++ hdir_unlock(h_dir, dir, bstart); ++ } ++ ii_write_lock_child(inode); ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ ++ out_unlock: ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ i_unlock(inode); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 //def CONFIG_AUFS_ROBR ++struct lvma { ++ struct list_head list; ++ struct vm_area_struct *vma; ++}; ++ ++static struct file *safe_file(struct vm_area_struct *vma) ++{ ++ struct file *file = vma->vm_file; ++ struct super_block *sb = file->f_dentry->d_sb; ++ struct lvma *lvma, *entry; ++ struct aufs_sbinfo *sbinfo; ++ int found, warn; ++ ++ TraceEnter(); ++ DEBUG_ON(!SB_AUFS(sb)); ++ ++ warn = 0; ++ found = 0; ++ sbinfo = stosi(sb); ++ spin_lock(&sbinfo->si_lvma_lock); ++ list_for_each_entry(entry, &sbinfo->si_lvma, list) { ++ found = (entry->vma == vma); ++ if (unlikely(found)) ++ break; ++ } ++ if (!found) { ++ lvma = kmalloc(sizeof(*lvma), GFP_ATOMIC); ++ if (lvma) { ++ lvma->vma = vma; ++ list_add(&lvma->list, &sbinfo->si_lvma); ++ } else { ++ warn = 1; ++ file = NULL; ++ } ++ } else ++ file = NULL; ++ spin_unlock(&sbinfo->si_lvma_lock); ++ ++ if (unlikely(warn)) ++ Warn1("no memory for lvma\n"); ++ return file; ++} ++ ++static void reset_file(struct vm_area_struct *vma, struct file *file) ++{ ++ struct super_block *sb = file->f_dentry->d_sb; ++ struct lvma *entry, *found; ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ DEBUG_ON(!SB_AUFS(sb)); ++ ++ vma->vm_file = file; ++ ++ found = NULL; ++ sbinfo = stosi(sb); ++ spin_lock(&sbinfo->si_lvma_lock); ++ list_for_each_entry(entry, &sbinfo->si_lvma, list) ++ if (entry->vma == vma){ ++ found = entry; ++ break; ++ } ++ DEBUG_ON(!found); ++ list_del(&found->list); ++ spin_unlock(&sbinfo->si_lvma_lock); ++ kfree(found); ++} ++ ++#else ++ ++static struct file *safe_file(struct vm_area_struct *vma) ++{ ++ struct file *file; ++ ++ file = vma->vm_file; ++ if (file->private_data && au_is_aufs(file->f_dentry->d_sb)) ++ return file; ++ return NULL; ++} ++ ++static void reset_file(struct vm_area_struct *vma, struct file *file) ++{ ++ vma->vm_file = file; ++ smp_mb(); ++} ++#endif /* CONFIG_AUFS_ROBR */ ++ ++static struct page *aufs_nopage(struct vm_area_struct *vma, unsigned long addr, ++ int *type) ++{ ++ struct page *page; ++ struct dentry *dentry; ++ struct file *file, *hidden_file; ++ struct inode *inode; ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ struct aufs_finfo *finfo; ++ ++ TraceEnter(); ++ DEBUG_ON(!vma || !vma->vm_file); ++ wait_event(wq, (file = safe_file(vma))); ++ DEBUG_ON(!au_is_aufs(file->f_dentry->d_sb)); ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, addr %lx\n", DLNPair(dentry), addr); ++ inode = dentry->d_inode; ++ DEBUG_ON(!S_ISREG(inode->i_mode)); ++ ++ // do not revalidate, nor lock ++ finfo = ftofi(file); ++ hidden_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; ++ DEBUG_ON(!hidden_file || !au_is_mmapped(file)); ++ vma->vm_file = hidden_file; ++ //smp_mb(); ++ page = finfo->fi_h_vm_ops->nopage(vma, addr, type); ++ reset_file(vma, file); ++#if 0 //def CONFIG_SMP ++ //wake_up_nr(&wq, online_cpu - 1); ++ wake_up_all(&wq); ++#else ++ wake_up(&wq); ++#endif ++ if (!IS_ERR(page)) { ++ //page->mapping = file->f_mapping; ++ //get_page(page); ++ //file->f_mapping = hidden_file->f_mapping; ++ //touch_atime(NULL, dentry); ++ //inode->i_atime = hidden_file->f_dentry->d_inode->i_atime; ++ } ++ TraceErrPtr(page); ++ return page; ++} ++ ++static int aufs_populate(struct vm_area_struct *vma, unsigned long addr, ++ unsigned long len, pgprot_t prot, unsigned long pgoff, ++ int nonblock) ++{ ++ Err("please report me this application\n"); ++ BUG(); ++ return ftofi(vma->vm_file)->fi_h_vm_ops->populate ++ (vma, addr, len, prot, pgoff, nonblock); ++} ++ ++static struct vm_operations_struct aufs_vm_ops = { ++ //.open = aufs_vmaopen, ++ //.close = aufs_vmaclose, ++ .nopage = aufs_nopage, ++ .populate = aufs_populate, ++ //page_mkwrite(struct vm_area_struct *vma, struct page *page) ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err, wlock, mmapped; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct file *h_file; ++ struct vm_operations_struct *vm_ops; ++ unsigned long flags; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, %lx, len %lu\n", ++ DLNPair(dentry), vma->vm_start, vma->vm_end - vma->vm_start); ++ DEBUG_ON(!S_ISREG(dentry->d_inode->i_mode)); ++ DEBUG_ON(down_write_trylock(&vma->vm_mm->mmap_sem)); ++ ++ mmapped = au_is_mmapped(file); ++ wlock = 0; ++ if (file->f_mode & FMODE_WRITE) { ++ flags = VM_SHARED | VM_WRITE; ++ wlock = ((flags & vma->vm_flags) == flags); ++ } ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, ++ wlock | !mmapped, /*locked*/0); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ ++ if (wlock) { ++ err = au_ready_to_write(file, -1); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ h_file = au_h_fptr(file); ++ vm_ops = ftofi(file)->fi_h_vm_ops; ++ if (unlikely(!mmapped)) { ++ // nfs uses some locks ++ lockdep_off(); ++ err = h_file->f_op->mmap(h_file, vma); ++ lockdep_on(); ++ if (unlikely(err)) ++ goto out_unlock; ++ vm_ops = vma->vm_ops; ++ DEBUG_ON(!vm_ops); ++ err = do_munmap(current->mm, vma->vm_start, ++ vma->vm_end - vma->vm_start); ++ if (unlikely(err)) { ++ IOErr("failed internal unmapping %.*s, %d\n", ++ DLNPair(h_file->f_dentry), err); ++ err = -EIO; ++ goto out_unlock; ++ } ++ } ++ DEBUG_ON(!vm_ops); ++ ++ err = generic_file_mmap(file, vma); ++ if (!err) { ++ file_accessed(h_file); ++ dentry->d_inode->i_atime = h_file->f_dentry->d_inode->i_atime; ++ vma->vm_ops = &aufs_vm_ops; ++ if (unlikely(!mmapped)) ++ ftofi(file)->fi_h_vm_ops = vm_ops; ++ } ++ ++ out_unlock: ++ if (!wlock && mmapped) ++ fi_read_unlock(file); ++ else ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++// todo: try do_sendfile() in fs/read_write.c ++static ssize_t aufs_sendfile(struct file *file, loff_t *ppos, ++ size_t count, read_actor_t actor, void *target) ++{ ++ ssize_t err; ++ struct file *h_file; ++ const char c = current->comm[4]; ++ /* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++ const int loopback = (current->mm == NULL ++ && '0' <= c && c <= '9' ++ && strncmp(current->comm, "loop", 4) == 0); ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld, cnt %lu, loopback %d\n", ++ DLNPair(dentry), *ppos, (unsigned long)count, loopback); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/0, ++ /*locked*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -EINVAL; ++ h_file = au_h_fptr(file); ++ if (h_file->f_op && h_file->f_op->sendfile) { ++ if (/* unlikely */(loopback)) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); //?? ++ } ++ // nfs uses some locks ++ lockdep_off(); ++ err = h_file->f_op->sendfile ++ (h_file, ppos, count, actor, target); ++ lockdep_on(); ++ dentry->d_inode->i_atime = h_file->f_dentry->d_inode->i_atime; ++ } ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* copied from linux/fs/select.h, must match */ ++#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) ++ ++static unsigned int aufs_poll(struct file *file, poll_table *wait) ++{ ++ unsigned int mask; ++ struct file *hidden_file; ++ int err; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, wait %p\n", DLNPair(dentry), wait); ++ DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode)); ++ ++ /* We should pretend an error happend. */ ++ mask = POLLERR /* | POLLIN | POLLOUT */; ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/0, ++ /*locked*/0); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ ++ /* it is not an error of hidden_file has no operation */ ++ mask = DEFAULT_POLLMASK; ++ hidden_file = au_h_fptr(file); ++ if (hidden_file->f_op && hidden_file->f_op->poll) ++ mask = hidden_file->f_op->poll(hidden_file, wait); ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ TraceErr((int)mask); ++ return mask; ++} ++ ++static int aufs_fsync_nondir(struct file *file, struct dentry *dentry, ++ int datasync) ++{ ++ int err, my_lock; ++ struct inode *inode; ++ struct file *hidden_file; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), datasync); ++ inode = dentry->d_inode; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) ++ IMustLock(inode); ++ my_lock = 0; ++#else ++ /* before 2.6.17, ++ * msync(2) calls me without locking i_sem/i_mutex, but fsync(2). ++ */ ++ my_lock = !i_trylock(inode); ++#endif ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = 0; //-EBADF; // posix? ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/1, ++ /*locked*/1); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ err = au_ready_to_write(file, -1); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -EINVAL; ++ hidden_file = au_h_fptr(file); ++ if (hidden_file->f_op && hidden_file->f_op->fsync) { ++ // todo: apparmor thread? ++ //file->f_mapping->host->i_mutex ++ ii_write_lock_child(inode); ++ hi_lock_child(hidden_file->f_dentry->d_inode); ++ err = hidden_file->f_op->fsync ++ (hidden_file, hidden_file->f_dentry, datasync); ++ //err = -1; ++ au_cpup_attr_timesizes(inode); ++ i_unlock(hidden_file->f_dentry->d_inode); ++ ii_write_unlock(inode); ++ } ++ ++ out_unlock: ++ fi_write_unlock(file); ++ out: ++ if (unlikely(my_lock)) ++ i_unlock(inode); ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *hidden_file; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), flag); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ err = au_reval_and_lock_finfo(file, au_reopen_nondir, /*wlock*/0, ++ /*locked*/0); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ ++ hidden_file = au_h_fptr(file); ++ if (hidden_file->f_op && hidden_file->f_op->fasync) ++ err = hidden_file->f_op->fasync(fd, hidden_file, flag); ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 // comment ++struct file_operations { ++ struct module *owner; ++ loff_t (*llseek) (struct file *, loff_t, int); ++ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ++ ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); ++ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ++ ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); ++ int (*readdir) (struct file *, void *, filldir_t); ++ unsigned int (*poll) (struct file *, struct poll_table_struct *); ++ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); ++ long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); ++ long (*compat_ioctl) (struct file *, unsigned int, unsigned long); ++ int (*mmap) (struct file *, struct vm_area_struct *); ++ int (*open) (struct inode *, struct file *); ++ int (*flush) (struct file *); ++ int (*release) (struct inode *, struct file *); ++ int (*fsync) (struct file *, struct dentry *, int datasync); ++ int (*aio_fsync) (struct kiocb *, int datasync); ++ int (*fasync) (int, struct file *, int); ++ int (*lock) (struct file *, int, struct file_lock *); ++ ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ++ ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ++ ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); ++ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); ++ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); ++ int (*check_flags)(int); ++ int (*dir_notify)(struct file *file, unsigned long arg); ++ int (*flock) (struct file *, int, struct file_lock *); ++}; ++#endif ++ ++struct file_operations aufs_file_fop = { ++ .read = aufs_read, ++ .write = aufs_write, ++ .poll = aufs_poll, ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ .fasync = aufs_fasync, ++ .sendfile = aufs_sendfile, ++}; +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/file.c linux-2.6.22.1/fs/aufs/file.c +--- linux-2.6.22.1.oorig/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/file.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,832 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: file.c,v 1.42 2007/05/14 03:39:09 sfjro Exp $ */ ++ ++//#include ++#include ++//#include ++//#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *hidden_open(struct dentry *dentry, aufs_bindex_t bindex, int flags) ++{ ++ struct dentry *hidden_dentry; ++ struct inode *hidden_inode; ++ struct super_block *sb; ++ struct vfsmount *hidden_mnt; ++ struct file *hidden_file; ++ struct aufs_branch *br; ++ loff_t old_size; ++ int udba; ++ ++ LKTRTrace("%.*s, b%d, flags 0%o\n", DLNPair(dentry), bindex, flags); ++ DEBUG_ON(!dentry); ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ DEBUG_ON(!hidden_dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode); ++ ++ sb = dentry->d_sb; ++ udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY); ++ if (unlikely(udba)) { ++ // test here? ++ } ++ ++ br = stobr(sb, bindex); ++ br_get(br); ++ /* drop flags for writing */ ++ if (test_ro(sb, bindex, dentry->d_inode)) ++ flags = au_file_roflags(flags); ++ flags &= ~O_CREAT; ++ spin_lock(&hidden_inode->i_lock); ++ old_size = i_size_read(hidden_inode); ++ spin_unlock(&hidden_inode->i_lock); ++ ++ //DbgSleep(3); ++ ++ dget(hidden_dentry); ++ hidden_mnt = mntget(br->br_mnt); ++ hidden_file = dentry_open(hidden_dentry, hidden_mnt, flags); ++ //if (LktrCond) {fput(hidden_file); hidden_file = ERR_PTR(-1);} ++ ++ if (!IS_ERR(hidden_file)) { ++#if 0 // remove this ++ if (/* old_size && */ (flags & O_TRUNC)) { ++ au_direval_dec(dentry); ++ if (!IS_ROOT(dentry)) ++ au_direval_dec(dentry->d_parent); ++ } ++#endif ++ return hidden_file; ++ } ++ ++ br_put(br); ++ TraceErrPtr(hidden_file); ++ return hidden_file; ++} ++ ++static int do_coo(struct dentry *dentry, aufs_bindex_t bstart) ++{ ++ int err; ++ struct dentry *parent, *h_parent, *h_dentry; ++ aufs_bindex_t bcpup; ++ struct inode *h_dir, *h_inode, *dir; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(IS_ROOT(dentry)); ++ DiMustWriteLock(dentry); ++ ++ parent = dentry->d_parent; // dget_parent() ++ di_write_lock_parent(parent); ++ bcpup = err = find_rw_parent_br(dentry, bstart); ++ //bcpup = err = find_rw_br(sb, bstart); ++ if (unlikely(err < 0)) { ++ err = 0; // stop copyup, it is not an error ++ goto out; ++ } ++ err = 0; ++ ++ h_parent = au_h_dptr_i(parent, bcpup); ++ if (!h_parent) { ++ err = cpup_dirs(dentry, bcpup, NULL); ++ if (unlikely(err)) ++ goto out; ++ h_parent = au_h_dptr_i(parent, bcpup); ++ } ++ ++ h_dir = h_parent->d_inode; ++ h_dentry = au_h_dptr_i(dentry, bstart); ++ h_inode = h_dentry->d_inode; ++ dir = parent->d_inode; ++ hdir_lock(h_dir, dir, bcpup); ++ hi_lock_child(h_inode); ++ DEBUG_ON(au_h_dptr_i(dentry, bcpup)); ++ err = sio_cpup_simple(dentry, bcpup, -1, ++ au_flags_cpup(CPUP_DTIME, parent)); ++ TraceErr(err); ++ i_unlock(h_inode); ++ hdir_unlock(h_dir, dir, bcpup); ++ ++ out: ++ di_write_unlock(parent); ++ TraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct inode *inode, struct file *file, ++ int (*open)(struct file *file, int flags)) ++{ ++ int err, coo; ++ struct dentry *dentry; ++ struct super_block *sb; ++ aufs_bindex_t bstart; ++ struct inode *h_dir, *dir; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(dentry)); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb); ++ coo = 0; ++#if 0 ++ switch (au_flag_test_coo(sb)) { ++ case AuFlag_COO_LEAF: ++ coo = !S_ISDIR(inode->i_mode); ++ break; ++ case AuFlag_COO_ALL: ++ coo = 1; ++ break; ++ } ++#endif ++ err = au_init_finfo(file); ++ //if (LktrCond) {fi_write_unlock(file); fin_finfo(file); err = -1;} ++ if (unlikely(err)) ++ goto out; ++ ++ if (!coo) { ++ di_read_lock_child(dentry, AUFS_I_RLOCK); ++ bstart = dbstart(dentry); ++ } else { ++ di_write_lock_child(dentry); ++ bstart = dbstart(dentry); ++ if (test_ro(sb, bstart, dentry->d_inode)) { ++ err = do_coo(dentry, bstart); ++ if (err) { ++ di_write_unlock(dentry); ++ goto out_finfo; ++ } ++ bstart = dbstart(dentry); ++ } ++ di_downgrade_lock(dentry, AUFS_I_RLOCK); ++ } ++ ++ // todo: remove this extra locks ++ dir = dentry->d_parent->d_inode; ++ if (!IS_ROOT(dentry)) ++ ii_read_lock_parent(dir); ++ h_dir = au_h_iptr_i(dir, bstart); ++ hdir_lock(h_dir, dir, bstart); ++ err = open(file, file->f_flags); ++ //if (LktrCond) err = -1; ++ hdir_unlock(h_dir, dir, bstart); ++ if (!IS_ROOT(dentry)) ++ ii_read_unlock(dir); ++ di_read_unlock(dentry, AUFS_I_RLOCK); ++ ++ out_finfo: ++ fi_write_unlock(file); ++ if (unlikely(err)) ++ au_fin_finfo(file); ++ //DbgFile(file); ++ out: ++ si_read_unlock(sb); ++ TraceErr(err); ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ struct dentry *dentry; ++ aufs_bindex_t bstart, bindex, bend; ++ struct file *hidden_file, *h_file_tmp; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode) ++ || !au_h_dptr(dentry)->d_inode); ++ bstart = dbstart(dentry); ++ ++ h_file_tmp = NULL; ++ if (fbstart(file) == bstart) { ++ hidden_file = au_h_fptr(file); ++ if (file->f_mode == hidden_file->f_mode) ++ return 0; /* success */ ++ h_file_tmp = hidden_file; ++ get_file(h_file_tmp); ++ set_h_fptr(file, bstart, NULL); ++ } ++ DEBUG_ON(fbstart(file) < bstart ++ || ftofi(file)->fi_hfile[0 + bstart].hf_file); ++ ++ hidden_file = hidden_open(dentry, bstart, file->f_flags & ~O_TRUNC); ++ //if (LktrCond) {fput(hidden_file); br_put(stobr(dentry->d_sb, bstart)); ++ //hidden_file = ERR_PTR(-1);} ++ err = PTR_ERR(hidden_file); ++ if (IS_ERR(hidden_file)) ++ goto out; // close all? ++ err = 0; ++ //cpup_file_flags(hidden_file, file); ++ set_fbstart(file, bstart); ++ set_h_fptr(file, bstart, hidden_file); ++ memcpy(&hidden_file->f_ra, &file->f_ra, sizeof(file->f_ra)); //?? ++ ++ /* close lower files */ ++ bend = fbend(file); ++ for (bindex = bstart + 1; bindex <= bend; bindex++) ++ set_h_fptr(file, bindex, NULL); ++ set_fbend(file, bstart); ++ ++ out: ++ if (h_file_tmp) ++ fput(h_file_tmp); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int cpup_wh_file(struct file *file, aufs_bindex_t bdst, loff_t len) ++{ ++ int err; ++ struct dentry *dentry, *parent, *hidden_parent, *tmp_dentry; ++ struct dentry *hidden_dentry_bstart, *hidden_dentry_bdst; ++ struct inode *hidden_dir; ++ aufs_bindex_t bstart; ++ struct aufs_dinfo *dinfo; ++ struct dtime dt; ++ struct lkup_args lkup; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, bdst %d, len %Lu\n", DLNPair(dentry), bdst, len); ++ DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode) ++ || !(file->f_mode & FMODE_WRITE)); ++ DiMustWriteLock(dentry); ++ parent = dentry->d_parent; ++ IiMustAnyLock(parent->d_inode); ++ hidden_parent = au_h_dptr_i(parent, bdst); ++ DEBUG_ON(!hidden_parent); ++ hidden_dir = hidden_parent->d_inode; ++ DEBUG_ON(!hidden_dir); ++ IMustLock(hidden_dir); ++ ++ sb = parent->d_sb; ++ lkup.nfsmnt = au_nfsmnt(sb, bdst); ++ lkup.dlgt = need_dlgt(sb); ++ tmp_dentry = lkup_whtmp(hidden_parent, &dentry->d_name, &lkup); ++ //if (LktrCond) {dput(tmp_dentry); tmp_dentry = ERR_PTR(-1);} ++ err = PTR_ERR(tmp_dentry); ++ if (IS_ERR(tmp_dentry)) ++ goto out; ++ ++ dtime_store(&dt, parent, hidden_parent); ++ dinfo = dtodi(dentry); ++ bstart = dinfo->di_bstart; ++ hidden_dentry_bdst = dinfo->di_hdentry[0 + bdst].hd_dentry; ++ hidden_dentry_bstart = dinfo->di_hdentry[0 + bstart].hd_dentry; ++ dinfo->di_bstart = bdst; ++ dinfo->di_hdentry[0 + bdst].hd_dentry = tmp_dentry; ++ dinfo->di_hdentry[0 + bstart].hd_dentry = au_h_fptr(file)->f_dentry; ++ err = cpup_single(dentry, bdst, bstart, len, ++ au_flags_cpup(!CPUP_DTIME, parent)); ++ //if (LktrCond) err = -1; ++ if (!err) ++ err = au_reopen_nondir(file); ++ //err = -1; ++ dinfo->di_hdentry[0 + bstart].hd_dentry = hidden_dentry_bstart; ++ dinfo->di_hdentry[0 + bdst].hd_dentry = hidden_dentry_bdst; ++ dinfo->di_bstart = bstart; ++ if (unlikely(err)) ++ goto out_tmp; ++ ++ DEBUG_ON(!d_unhashed(dentry)); ++ err = vfsub_unlink(hidden_dir, tmp_dentry, lkup.dlgt); ++ //if (LktrCond) err = -1; ++ if (unlikely(err)) { ++ IOErr("failed remove copied-up tmp file %.*s(%d)\n", ++ DLNPair(tmp_dentry), err); ++ err = -EIO; ++ } ++ dtime_revert(&dt, !CPUP_LOCKED_GHDIR); ++ ++ out_tmp: ++ dput(tmp_dentry); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct cpup_wh_file_args { ++ int *errp; ++ struct file *file; ++ aufs_bindex_t bdst; ++ loff_t len; ++}; ++ ++static void call_cpup_wh_file(void *args) ++{ ++ struct cpup_wh_file_args *a = args; ++ *a->errp = cpup_wh_file(a->file, a->bdst, a->len); ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len) ++{ ++ int err; ++ struct dentry *dentry, *parent, *hidden_dentry, *hidden_parent; ++ struct inode *hidden_inode, *hidden_dir, *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bstart, bcpup; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, len %Ld\n", DLNPair(dentry), len); ++ FiMustWriteLock(file); ++ ++ sb = dentry->d_sb; ++ bstart = fbstart(file); ++ DEBUG_ON(ftobr(file, bstart) != stobr(sb, bstart)); ++ ++ inode = dentry->d_inode; ++ ii_read_lock_child(inode); ++ LKTRTrace("rdonly %d, bstart %d\n", test_ro(sb, bstart, inode), bstart); ++ err = test_ro(sb, bstart, inode); ++ ii_read_unlock(inode); ++ if (!err && (au_h_fptr(file)->f_mode & FMODE_WRITE)) ++ return 0; ++ ++ /* need to cpup */ ++ parent = dentry->d_parent; // dget_parent() ++ di_write_lock_child(dentry); ++ di_write_lock_parent(parent); ++ bcpup = err = find_rw_parent_br(dentry, bstart); ++ //bcpup = err = find_rw_br(sb, bstart); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ err = 0; ++ ++ hidden_parent = au_h_dptr_i(parent, bcpup); ++ if (!hidden_parent) { ++ err = cpup_dirs(dentry, bcpup, NULL); ++ //if (LktrCond) err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ hidden_parent = au_h_dptr_i(parent, bcpup); ++ } ++ ++ hidden_dir = hidden_parent->d_inode; ++ hidden_dentry = au_h_fptr(file)->f_dentry; ++ hidden_inode = hidden_dentry->d_inode; ++ dir = parent->d_inode; ++ hdir_lock(hidden_dir, dir, bcpup); ++ hi_lock_child(hidden_inode); ++ if (d_unhashed(dentry) || d_unhashed(hidden_dentry) ++ /* || !hidden_inode->i_nlink */) { ++ if (!au_test_perm(hidden_dir, MAY_EXEC | MAY_WRITE, ++ need_dlgt(sb))) ++ err = cpup_wh_file(file, bcpup, len); ++ else { ++ struct cpup_wh_file_args args = { ++ .errp = &err, ++ .file = file, ++ .bdst = bcpup, ++ .len = len ++ }; ++ au_wkq_wait(call_cpup_wh_file, &args, /*dlgt*/0); ++ } ++ //if (LktrCond) err = -1; ++ TraceErr(err); ++ } else { ++ if (!au_h_dptr_i(dentry, bcpup)) ++ err = sio_cpup_simple(dentry, bcpup, len, ++ au_flags_cpup(CPUP_DTIME, ++ parent)); ++ //if (LktrCond) err = -1; ++ TraceErr(err); ++ if (!err) ++ err = au_reopen_nondir(file); ++ //if (LktrCond) err = -1; ++ TraceErr(err); ++ } ++ i_unlock(hidden_inode); ++ hdir_unlock(hidden_dir, dir, bcpup); ++ ++ out_unlock: ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++// out: ++ TraceErr(err); ++ return err; ++ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, new_sz; ++ struct dentry *dentry; ++ aufs_bindex_t bend, bindex, bstart, brid; ++ struct aufs_hfile *p; ++ struct aufs_finfo *finfo; ++ struct super_block *sb; ++ struct inode *inode; ++ struct file *hidden_file; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ FiMustWriteLock(file); ++ DiMustReadLock(dentry); ++ inode = dentry->d_inode; ++ IiMustReadLock(inode); ++ //au_debug_on(); ++ //DbgDentry(dentry); ++ //DbgFile(file); ++ //au_debug_off(); ++ ++ err = -ENOMEM; ++ sb = dentry->d_sb; ++ finfo = ftofi(file); ++ bstart = finfo->fi_bstart; ++ bend = finfo->fi_bstart; ++ new_sz = sizeof(*finfo->fi_hfile) * (sbend(sb) + 1); ++ p = au_kzrealloc(finfo->fi_hfile, sizeof(*p) * (finfo->fi_bend + 1), ++ new_sz, GFP_KERNEL); ++ //p = NULL; ++ if (unlikely(!p)) ++ goto out; ++ finfo->fi_hfile = p; ++ hidden_file = p[0 + bstart].hf_file; ++ ++ p = finfo->fi_hfile + finfo->fi_bstart; ++ brid = p->hf_br->br_id; ++ bend = finfo->fi_bend; ++ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++, p++) { ++ struct aufs_hfile tmp, *q; ++ aufs_bindex_t new_bindex; ++ ++ if (!p->hf_file) ++ continue; ++ new_bindex = find_bindex(sb, p->hf_br); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { // test here ++ set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two hidden inode, and loop again */ ++ q = finfo->fi_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ { ++ aufs_bindex_t s = finfo->fi_bstart, e = finfo->fi_bend; ++ finfo->fi_bstart = 0; ++ finfo->fi_bend = sbend(sb); ++ //au_debug_on(); ++ //DbgFile(file); ++ //au_debug_off(); ++ finfo->fi_bstart = s; ++ finfo->fi_bend = e; ++ } ++ ++ p = finfo->fi_hfile; ++ if (!au_is_mmapped(file) && !d_unhashed(dentry)) { ++ bend = sbend(sb); ++ for (finfo->fi_bstart = 0; finfo->fi_bstart <= bend; ++ finfo->fi_bstart++, p++) ++ if (p->hf_file) { ++ if (p->hf_file->f_dentry ++ && p->hf_file->f_dentry->d_inode) ++ break; ++ else ++ au_hfput(p); ++ } ++ } else { ++ bend = find_brindex(sb, brid); ++ //LKTRTrace("%d\n", bend); ++ for (finfo->fi_bstart = 0; finfo->fi_bstart < bend; ++ finfo->fi_bstart++, p++) ++ if (p->hf_file) ++ au_hfput(p); ++ //LKTRTrace("%d\n", finfo->fi_bstart); ++ bend = sbend(sb); ++ } ++ ++ p = finfo->fi_hfile + bend; ++ for (finfo->fi_bend = bend; finfo->fi_bend >= finfo->fi_bstart; ++ finfo->fi_bend--, p--) ++ if (p->hf_file) { ++ if (p->hf_file->f_dentry ++ && p->hf_file->f_dentry->d_inode) ++ break; ++ else ++ au_hfput(p); ++ } ++ //Dbg("%d, %d\n", finfo->fi_bstart, finfo->fi_bend); ++ DEBUG_ON(finfo->fi_bend < finfo->fi_bstart); ++ //DbgFile(file); ++ //DbgDentry(file->f_dentry); ++ ++ err = 0; ++#if 0 // todo: ++ if (!au_h_dptr(dentry)->d_inode) { ++ au_update_figen(file); ++ goto out; /* success */ ++ } ++#endif ++ ++ if (unlikely(au_is_mmapped(file) || d_unhashed(dentry))) ++ goto out_update; /* success */ ++ ++ again: ++ bstart = ibstart(inode); ++ if (bstart < finfo->fi_bstart ++ && au_flag_test(sb, AuFlag_PLINK) ++ && au_is_plinked(sb, inode)) { ++ struct dentry *parent = dentry->d_parent; // dget_parent() ++ struct inode *dir = parent->d_inode, *h_dir; ++ ++ if (test_ro(sb, bstart, inode)) { ++ di_read_lock_parent(parent, !AUFS_I_RLOCK); ++ bstart = err = find_rw_parent_br(dentry, bstart); ++ //bstart = err = find_rw_br(sb, bstart); ++ di_read_unlock(parent, !AUFS_I_RLOCK); ++ //todo: err = -1; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ di_read_unlock(dentry, AUFS_I_RLOCK); ++ di_write_lock_child(dentry); ++ if (bstart != ibstart(inode)) { // todo ++ /* someone changed our inode while we were sleeping */ ++ di_downgrade_lock(dentry, AUFS_I_RLOCK); ++ goto again; ++ } ++ ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ err = test_and_cpup_dirs(dentry, bstart, NULL); ++ ++ // always superio. ++#if 1 ++ h_dir = au_h_dptr_i(parent, bstart)->d_inode; ++ hdir_lock(h_dir, dir, bstart); ++ err = sio_cpup_simple(dentry, bstart, -1, ++ au_flags_cpup(CPUP_DTIME, parent)); ++ hdir_unlock(h_dir, dir, bstart); ++ di_read_unlock(parent, AUFS_I_RLOCK); ++#else ++ if (!is_au_wkq(current)) { ++ struct cpup_pseudo_link_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bstart, ++ .do_lock = 1 ++ }; ++ au_wkq_wait(call_cpup_pseudo_link, &args); ++ } else ++ err = cpup_pseudo_link(dentry, bstart, /*do_lock*/1); ++#endif ++ di_downgrade_lock(dentry, AUFS_I_RLOCK); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = reopen(file); ++ //err = -1; ++ out_update: ++ if (!err) { ++ au_update_figen(file); ++ //DbgFile(file); ++ return 0; /* success */ ++ } ++ ++ /* error, close all hidden files */ ++ bend = fbend(file); ++ for (bindex = fbstart(file); bindex <= bend; bindex++) ++ set_h_fptr(file, bindex, NULL); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_finfo(struct file *file, int (*reopen)(struct file *file), ++ int wlock, int locked) ++{ ++ int err, sgen, fgen, pseudo_link; ++ struct dentry *dentry; ++ struct super_block *sb; ++ aufs_bindex_t bstart; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, w %d, l %d\n", DLNPair(dentry), wlock, locked); ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ sgen = au_sigen(sb); ++ fi_write_lock(file); ++ fgen = au_figen(file); ++ di_read_lock_child(dentry, AUFS_I_RLOCK); ++ bstart = dbstart(dentry); ++ pseudo_link = (bstart != ibstart(dentry->d_inode)); ++ di_read_unlock(dentry, AUFS_I_RLOCK); ++ if (sgen == fgen && !pseudo_link && fbstart(file) == bstart) { ++ if (!wlock) ++ fi_downgrade_lock(file); ++ return 0; /* success */ ++ } ++ ++ LKTRTrace("sgen %d, fgen %d\n", sgen, fgen); ++ if (sgen != au_digen(dentry)) { ++ /* ++ * d_path() and path_lookup() is a simple and good approach ++ * to revalidate. but si_rwsem in DEBUG_RWSEM will cause a ++ * deadlock. removed the code. ++ */ ++ di_write_lock_child(dentry); ++ err = au_reval_dpath(dentry, sgen); ++ //if (LktrCond) err = -1; ++ di_write_unlock(dentry); ++ if (unlikely(err < 0)) ++ goto out; ++ DEBUG_ON(au_digen(dentry) != sgen); ++ } ++ ++ di_read_lock_child(dentry, AUFS_I_RLOCK); ++ err = refresh_file(file, reopen); ++ //if (LktrCond) err = -1; ++ di_read_unlock(dentry, AUFS_I_RLOCK); ++ if (!err) { ++ if (!wlock) ++ fi_downgrade_lock(file); ++ } else ++ fi_write_unlock(file); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++// cf. aufs_nopage() ++// for madvise(2) ++static int aufs_readpage(struct file *file, struct page *page) ++{ ++ TraceEnter(); ++ unlock_page(page); ++ return 0; ++} ++ ++// they will never be called. ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_prepare_write(struct file *file, struct page *page, ++ unsigned from, unsigned to) ++{BUG();return 0;} ++static int aufs_commit_write(struct file *file, struct page *page, ++ unsigned from, unsigned to) ++{BUG();return 0;} ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{BUG();return 0;} ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) ++static void aufs_sync_page(struct page *page) ++{BUG();} ++#else ++static int aufs_sync_page(struct page *page) ++{BUG(); return 0;} ++#endif ++ ++#if 0 // comment ++static int aufs_writepages(struct address_space *mapping, ++ struct writeback_control *wbc) ++{BUG();return 0;} ++static int aufs_readpages(struct file *filp, struct address_space *mapping, ++ struct list_head *pages, unsigned nr_pages) ++{BUG();return 0;} ++static sector_t aufs_bmap(struct address_space *mapping, sector_t block) ++{BUG();return 0;} ++#endif ++ ++static int aufs_set_page_dirty(struct page *page) ++{BUG();return 0;} ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) ++static void aufs_invalidatepage (struct page *page, unsigned long offset) ++{BUG();} ++#else ++static int aufs_invalidatepage (struct page *page, unsigned long offset) ++{BUG(); return 0;} ++#endif ++static int aufs_releasepage (struct page *page, gfp_t gfp) ++{BUG();return 0;} ++static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, ++ const struct iovec *iov, loff_t offset, ++ unsigned long nr_segs) ++{BUG();return 0;} ++static struct page* aufs_get_xip_page(struct address_space *mapping, ++ sector_t offset, int create) ++{BUG();return NULL;} ++//static int aufs_migratepage (struct page *newpage, struct page *page) ++//{BUG();return 0;} ++#endif ++ ++#if 0 // comment ++struct address_space { ++ struct inode *host; /* owner: inode, block_device */ ++ struct radix_tree_root page_tree; /* radix tree of all pages */ ++ rwlock_t tree_lock; /* and rwlock protecting it */ ++ unsigned int i_mmap_writable;/* count VM_SHARED mappings */ ++ struct prio_tree_root i_mmap; /* tree of private and shared mappings */ ++ struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */ ++ spinlock_t i_mmap_lock; /* protect tree, count, list */ ++ unsigned int truncate_count; /* Cover race condition with truncate */ ++ unsigned long nrpages; /* number of total pages */ ++ pgoff_t writeback_index;/* writeback starts here */ ++ struct address_space_operations *a_ops; /* methods */ ++ unsigned long flags; /* error bits/gfp mask */ ++ struct backing_dev_info *backing_dev_info; /* device readahead, etc */ ++ spinlock_t private_lock; /* for use by the address_space */ ++ struct list_head private_list; /* ditto */ ++ struct address_space *assoc_mapping; /* ditto */ ++} __attribute__((aligned(sizeof(long)))); ++ ++struct address_space_operations { ++ int (*writepage)(struct page *page, struct writeback_control *wbc); ++ int (*readpage)(struct file *, struct page *); ++ void (*sync_page)(struct page *); ++ ++ /* Write back some dirty pages from this mapping. */ ++ int (*writepages)(struct address_space *, struct writeback_control *); ++ ++ /* Set a page dirty. Return true if this dirtied it */ ++ int (*set_page_dirty)(struct page *page); ++ ++ int (*readpages)(struct file *filp, struct address_space *mapping, ++ struct list_head *pages, unsigned nr_pages); ++ ++ /* ++ * ext3 requires that a successful prepare_write() call be followed ++ * by a commit_write() call - they must be balanced ++ */ ++ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); ++ int (*commit_write)(struct file *, struct page *, unsigned, unsigned); ++ /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ ++ sector_t (*bmap)(struct address_space *, sector_t); ++ void (*invalidatepage) (struct page *, unsigned long); ++ int (*releasepage) (struct page *, gfp_t); ++ ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, ++ loff_t offset, unsigned long nr_segs); ++ struct page* (*get_xip_page)(struct address_space *, sector_t, ++ int); ++ /* migrate the contents of a page to the specified target */ ++ int (*migratepage) (struct page *, struct page *); ++}; ++#endif ++ ++struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ .sync_page = aufs_sync_page, ++ //.writepages = aufs_writepages, ++ .set_page_dirty = aufs_set_page_dirty, ++ //.readpages = aufs_readpages, ++ .prepare_write = aufs_prepare_write, ++ .commit_write = aufs_commit_write, ++ //.bmap = aufs_bmap, ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ .direct_IO = aufs_direct_IO, ++ .get_xip_page = aufs_get_xip_page, ++ //.migratepage = aufs_migratepage ++#endif ++}; +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/file.h linux-2.6.22.1/fs/aufs/file.h +--- linux-2.6.22.1.oorig/fs/aufs/file.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/file.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,140 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: file.h,v 1.25 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "misc.h" ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++// SEEK_xxx are defined in linux/fs.h ++#else ++enum {SEEK_SET, SEEK_CUR, SEEK_END}; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_branch; ++struct aufs_hfile { ++ struct file *hf_file; ++ struct aufs_branch *hf_br; ++}; ++ ++struct aufs_vdir; ++struct aufs_finfo { ++ atomic_t fi_generation; ++ ++ struct aufs_rwsem fi_rwsem; ++ struct aufs_hfile *fi_hfile; ++ aufs_bindex_t fi_bstart, fi_bend; ++ ++ union { ++ struct vm_operations_struct *fi_h_vm_ops; ++ struct aufs_vdir *fi_vdir_cache; ++ }; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *hidden_open(struct dentry *dentry, aufs_bindex_t bindex, ++ int flags); ++int au_do_open(struct inode *inode, struct file *file, ++ int (*open)(struct file *file, int flags)); ++int au_reopen_nondir(struct file *file); ++int au_ready_to_write(struct file *file, loff_t len); ++int au_reval_and_lock_finfo(struct file *file, int (*reopen)(struct file *file), ++ int wlock, int locked); ++ ++/* f_op.c */ ++extern struct file_operations aufs_file_fop; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++int aufs_flush(struct file *file, fl_owner_t id); ++#else ++int aufs_flush(struct file *file); ++#endif ++ ++/* finfo.c */ ++struct aufs_finfo *ftofi(struct file *file); ++aufs_bindex_t fbstart(struct file *file); ++aufs_bindex_t fbend(struct file *file); ++struct aufs_vdir *fvdir_cache(struct file *file); ++struct aufs_branch *ftobr(struct file *file, aufs_bindex_t bindex); ++struct file *au_h_fptr_i(struct file *file, aufs_bindex_t bindex); ++struct file *au_h_fptr(struct file *file); ++ ++void set_fbstart(struct file *file, aufs_bindex_t bindex); ++void set_fbend(struct file *file, aufs_bindex_t bindex); ++void set_fvdir_cache(struct file *file, struct aufs_vdir *vdir_cache); ++void au_hfput(struct aufs_hfile *hf); ++void set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *h_file); ++void au_update_figen(struct file *file); ++ ++void au_fin_finfo(struct file *file); ++int au_init_finfo(struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_figen(struct file *f) ++{ ++ return atomic_read(&ftofi(f)->fi_generation); ++} ++ ++static inline int au_is_mmapped(struct file *f) ++{ ++ return !!(ftofi(f)->fi_h_vm_ops); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * fi_read_lock, fi_write_lock, ++ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock ++ */ ++SimpleRwsemFuncs(fi, struct file *f, ftofi(f)->fi_rwsem); ++ ++/* to debug easier, do not make them inlined functions */ ++#define FiMustReadLock(f) do {\ ++ SiMustAnyLock((f)->f_dentry->d_sb); \ ++ RwMustReadLock(&ftofi(f)->fi_rwsem); \ ++} while (0) ++ ++#define FiMustWriteLock(f) do { \ ++ SiMustAnyLock((f)->f_dentry->d_sb); \ ++ RwMustWriteLock(&ftofi(f)->fi_rwsem); \ ++} while (0) ++ ++#define FiMustAnyLock(f) do { \ ++ SiMustAnyLock((f)->f_dentry->d_sb); \ ++ RwMustAnyLock(&ftofi(f)->fi_rwsem); \ ++} while (0) ++ ++#define FiMustNoWaiters(f) RwMustNoWaiters(&ftofi(f)->fi_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/finfo.c linux-2.6.22.1/fs/aufs/finfo.c +--- linux-2.6.22.1.oorig/fs/aufs/finfo.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/finfo.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,211 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: finfo.c,v 1.23 2007/04/30 05:45:21 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++struct aufs_finfo *ftofi(struct file *file) ++{ ++ struct aufs_finfo *finfo = file->private_data; ++ DEBUG_ON(!finfo ++ || !finfo->fi_hfile ++ || (0 < finfo->fi_bend ++ && (/* stosi(file->f_dentry->d_sb)->si_bend ++ < finfo->fi_bend ++ || */ finfo->fi_bend < finfo->fi_bstart))); ++ return finfo; ++} ++ ++// hard/soft set ++aufs_bindex_t fbstart(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return ftofi(file)->fi_bstart; ++} ++ ++aufs_bindex_t fbend(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return ftofi(file)->fi_bend; ++} ++ ++struct aufs_vdir *fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return ftofi(file)->fi_vdir_cache; ++} ++ ++struct aufs_branch *ftobr(struct file *file, aufs_bindex_t bindex) ++{ ++ struct aufs_finfo *finfo = ftofi(file); ++ struct aufs_hfile *hf; ++ ++ FiMustAnyLock(file); ++ DEBUG_ON(!finfo ++ || finfo->fi_bstart < 0 ++ || bindex < finfo->fi_bstart ++ || finfo->fi_bend < bindex); ++ hf = finfo->fi_hfile + bindex; ++ DEBUG_ON(hf->hf_br && br_count(hf->hf_br) <= 0); ++ return hf->hf_br; ++} ++ ++struct file *au_h_fptr_i(struct file *file, aufs_bindex_t bindex) ++{ ++ struct aufs_finfo *finfo = ftofi(file); ++ struct aufs_hfile *hf; ++ ++ FiMustAnyLock(file); ++ DEBUG_ON(!finfo ++ || finfo->fi_bstart < 0 ++ || bindex < finfo->fi_bstart ++ || finfo->fi_bend < bindex); ++ hf = finfo->fi_hfile + bindex; ++ DEBUG_ON(hf->hf_file ++ && file_count(hf->hf_file) <= 0 ++ && br_count(hf->hf_br) <= 0); ++ return hf->hf_file; ++} ++ ++struct file *au_h_fptr(struct file *file) ++{ ++ return au_h_fptr_i(file, fbstart(file)); ++} ++ ++void set_fbstart(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ DEBUG_ON(sbend(file->f_dentry->d_sb) < bindex); ++ ftofi(file)->fi_bstart = bindex; ++} ++ ++void set_fbend(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ DEBUG_ON(sbend(file->f_dentry->d_sb) < bindex ++ || bindex < fbstart(file)); ++ ftofi(file)->fi_bend = bindex; ++} ++ ++void set_fvdir_cache(struct file *file, struct aufs_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ DEBUG_ON(!S_ISDIR(file->f_dentry->d_inode->i_mode) ++ || (ftofi(file)->fi_vdir_cache && vdir_cache)); ++ ftofi(file)->fi_vdir_cache = vdir_cache; ++} ++ ++void au_hfput(struct aufs_hfile *hf) ++{ ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ DEBUG_ON(!hf->hf_br); ++ br_put(hf->hf_br); ++ hf->hf_br = NULL; ++} ++ ++void set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct aufs_finfo *finfo = ftofi(file); ++ struct aufs_hfile *hf; ++ ++ FiMustWriteLock(file); ++ DEBUG_ON(!finfo ++ || finfo->fi_bstart < 0 ++ || bindex < finfo->fi_bstart ++ || finfo->fi_bend < bindex); ++ DEBUG_ON(val && file_count(val) <= 0); ++ hf = finfo->fi_hfile + bindex; ++ DEBUG_ON(val && hf->hf_file); ++ if (hf->hf_file) ++ au_hfput(hf); ++ if (val) { ++ hf->hf_file = val; ++ hf->hf_br = stobr(file->f_dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&ftofi(file)->fi_generation, au_digen(file->f_dentry)); ++} ++ ++void au_fin_finfo(struct file *file) ++{ ++ struct aufs_finfo *finfo; ++ struct dentry *dentry; ++ aufs_bindex_t bindex, bend; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ SiMustAnyLock(dentry->d_sb); ++ ++ fi_write_lock(file); ++ bend = fbend(file); ++ bindex = fbstart(file); ++ if (bindex >= 0) ++ for (; bindex <= bend; bindex++) ++ set_h_fptr(file, bindex, NULL); ++ ++ finfo = ftofi(file); ++#ifdef CONFIG_AUFS_DEBUG ++ if (finfo->fi_bstart >= 0) { ++ bend = fbend(file); ++ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++) { ++ struct aufs_hfile *hf; ++ hf = finfo->fi_hfile + bindex; ++ DEBUG_ON(hf->hf_file || hf->hf_br); ++ } ++ } ++#endif ++ ++ kfree(finfo->fi_hfile); ++ fi_write_unlock(file); ++ cache_free_finfo(finfo); ++ //file->private_data = NULL; ++} ++ ++int au_init_finfo(struct file *file) ++{ ++ struct aufs_finfo *finfo; ++ struct dentry *dentry; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ DEBUG_ON(!dentry->d_inode); ++ ++ finfo = cache_alloc_finfo(); ++ if (finfo) { ++ finfo->fi_hfile = kcalloc(sbend(dentry->d_sb) + 1, ++ sizeof(*finfo->fi_hfile), GFP_KERNEL); ++ if (finfo->fi_hfile) { ++ rw_init_wlock(&finfo->fi_rwsem); ++ finfo->fi_bstart = -1; ++ finfo->fi_bend = -1; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ ++ file->private_data = finfo; ++ return 0; /* success */ ++ } ++ cache_free_finfo(finfo); ++ } ++ ++ TraceErr(-ENOMEM); ++ return -ENOMEM; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/hinotify.c linux-2.6.22.1/fs/aufs/hinotify.c +--- linux-2.6.22.1.oorig/fs/aufs/hinotify.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/hinotify.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,536 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: hinotify.c,v 1.19 2007/05/14 03:39:21 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++static struct inotify_handle *in_handle; ++static const __u32 in_mask = (IN_MOVE | IN_DELETE | IN_CREATE /* | IN_ACCESS */ ++ | IN_MODIFY | IN_ATTRIB ++ | IN_DELETE_SELF | IN_MOVE_SELF); ++ ++int alloc_hinotify(struct aufs_hinode *hinode, struct inode *inode, ++ struct inode *hidden_inode) ++{ ++ int err; ++ struct aufs_hinotify *hin; ++ s32 wd; ++ ++ LKTRTrace("i%lu, hi%lu\n", inode->i_ino, hidden_inode->i_ino); ++ ++ err = -ENOMEM; ++ hin = cache_alloc_hinotify(); ++ if (hin) { ++ DEBUG_ON(hinode->hi_notify); ++ hinode->hi_notify = hin; ++ hin->hin_aufs_inode = inode; ++ inotify_init_watch(&hin->hin_watch); ++ wd = inotify_add_watch(in_handle, &hin->hin_watch, hidden_inode, ++ in_mask); ++ if (wd >= 0) ++ return 0; /* success */ ++ ++ err = wd; ++ put_inotify_watch(&hin->hin_watch); ++ cache_free_hinotify(hin); ++ hinode->hi_notify = NULL; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++void do_free_hinotify(struct aufs_hinode *hinode) ++{ ++ int err; ++ struct aufs_hinotify *hin; ++ ++ TraceEnter(); ++ ++ hin = hinode->hi_notify; ++ if (hin) { ++ err = 0; ++ if (atomic_read(&hin->hin_watch.count)) ++ err = inotify_rm_watch(in_handle, &hin->hin_watch); ++ ++ if (!err) { ++ cache_free_hinotify(hin); ++ hinode->hi_notify = NULL; ++ } else ++ IOErr1("failed inotify_rm_watch() %d\n", err); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void ctl_hinotify(struct aufs_hinode *hinode, const __u32 mask) ++{ ++ struct inode *hi; ++ struct inotify_watch *watch; ++ ++ hi = hinode->hi_inode; ++ LKTRTrace("hi%lu, sb %p, 0x%x\n", hi->i_ino, hi->i_sb, mask); ++ if (0 && !strcmp(current->comm, "link")) ++ dump_stack(); ++ IMustLock(hi); ++ if (!hinode->hi_notify) ++ return; ++ ++ watch = &hinode->hi_notify->hin_watch; ++#if 0 ++ { ++ u32 wd; ++ wd = inotify_find_update_watch(in_handle, hi, mask); ++ TraceErr(wd); ++ // ignore an err; ++ } ++#else ++ watch->mask = mask; ++ smp_mb(); ++#endif ++ LKTRTrace("watch %p, mask %u\n", watch, watch->mask); ++} ++ ++#define suspend_hinotify(hi) ctl_hinotify(hi, 0) ++#define resume_hinotify(hi) ctl_hinotify(hi, in_mask) ++ ++void do_hdir_lock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex, ++ unsigned int lsc) ++{ ++ struct aufs_hinode *hinode; ++ ++ LKTRTrace("i%lu, b%d, lsc %d\n", dir->i_ino, bindex, lsc); ++ DEBUG_ON(!S_ISDIR(dir->i_mode)); ++ hinode = itoii(dir)->ii_hinode + bindex; ++ DEBUG_ON(h_dir != hinode->hi_inode); ++ ++ hi_lock(h_dir, lsc); ++ if (1 /* unlikely(au_flag_test(dir->i_sb, AuFlag_UDBA_HINOTIFY) */) ++ suspend_hinotify(hinode); ++} ++ ++void hdir_unlock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex) ++{ ++ struct aufs_hinode *hinode; ++ ++ LKTRTrace("i%lu, b%d\n", dir->i_ino, bindex); ++ DEBUG_ON(!S_ISDIR(dir->i_mode)); ++ hinode = itoii(dir)->ii_hinode + bindex; ++ DEBUG_ON(h_dir != hinode->hi_inode); ++ ++ if (1 /* unlikely(au_flag_test(dir->i_sb, AuFlag_UDBA_HINOTIFY) */) ++ resume_hinotify(hinode); ++ i_unlock(h_dir); ++} ++ ++void hdir_lock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir) ++{ ++ struct aufs_hinode *hinode; ++ ++ LKTRTrace("%.*s, %.*s\n", DLNPair(h_parents[0]), DLNPair(h_parents[1])); ++ ++ vfsub_lock_rename(h_parents[0], h_parents[1]); ++ hinode = itoii(dirs[0])->ii_hinode + bindex; ++ DEBUG_ON(h_parents[0]->d_inode != hinode->hi_inode); ++ suspend_hinotify(hinode); ++ if (issamedir) ++ return; ++ hinode = itoii(dirs[1])->ii_hinode + bindex; ++ DEBUG_ON(h_parents[1]->d_inode != hinode->hi_inode); ++ suspend_hinotify(hinode); ++} ++ ++void hdir_unlock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir) ++{ ++ struct aufs_hinode *hinode; ++ ++ LKTRTrace("%.*s, %.*s\n", DLNPair(h_parents[0]), DLNPair(h_parents[1])); ++ ++ hinode = itoii(dirs[0])->ii_hinode + bindex; ++ DEBUG_ON(h_parents[0]->d_inode != hinode->hi_inode); ++ resume_hinotify(hinode); ++ if (!issamedir) { ++ hinode = itoii(dirs[1])->ii_hinode + bindex; ++ DEBUG_ON(h_parents[1]->d_inode != hinode->hi_inode); ++ resume_hinotify(hinode); ++ } ++ vfsub_unlock_rename(h_parents[0], h_parents[1]); ++} ++ ++void au_reset_hinotify(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bend; ++ struct inode *hi; ++ ++ LKTRTrace("i%lu, 0x%x\n", inode->i_ino, flags); ++ ++ bend = ibend(inode); ++ for (bindex = ibstart(inode); bindex <= bend; bindex++) { ++ hi = au_h_iptr_i(inode, bindex); ++ if (hi) { ++ //hi_lock(hi, AUFS_LSC_H_CHILD); ++ igrab(hi); ++ set_h_iptr(inode, bindex, NULL, 0); ++ set_h_iptr(inode, bindex, igrab(hi), flags); ++ iput(hi); ++ //i_unlock(hi); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++static char *in_name(u32 mask) ++{ ++#define test_ret(flag) if (mask & flag) return #flag; ++ test_ret(IN_ACCESS); ++ test_ret(IN_MODIFY); ++ test_ret(IN_ATTRIB); ++ test_ret(IN_CLOSE_WRITE); ++ test_ret(IN_CLOSE_NOWRITE); ++ test_ret(IN_OPEN); ++ test_ret(IN_MOVED_FROM); ++ test_ret(IN_MOVED_TO); ++ test_ret(IN_CREATE); ++ test_ret(IN_DELETE); ++ test_ret(IN_DELETE_SELF); ++ test_ret(IN_MOVE_SELF); ++ test_ret(IN_UNMOUNT); ++ test_ret(IN_Q_OVERFLOW); ++ test_ret(IN_IGNORED); ++ return ""; ++#undef test_ret ++} ++#else ++#define in_name(m) "??" ++#endif ++ ++static int dec_gen_by_name(struct inode *dir, const char *_name, u32 mask) ++{ ++ int err; ++ struct dentry *parent, *child; ++ struct inode *inode; ++ struct qstr *dname; ++ char *name = (void*)_name; ++ unsigned int len; ++ ++ LKTRTrace("i%lu, %s, 0x%x %s\n", ++ dir->i_ino, name, mask, in_name(mask)); ++ ++ err = -1; ++ parent = d_find_alias(dir); ++ if (unlikely(!parent)) ++ goto out; ++ ++#if 0 ++ if (unlikely(!memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ name += AUFS_WH_PFX_LEN; ++#endif ++ len = strlen(name); ++ spin_lock(&dcache_lock); ++ list_for_each_entry(child, &parent->d_subdirs, d_u.d_child) { ++ dname = &child->d_name; ++ if (len == dname->len && !memcmp(dname->name, name, len)) { ++ au_digen_dec(child); ++#if 1 ++ //todo: why both are needed ++ if (mask & IN_MOVE) { ++ spin_lock(&child->d_lock); ++ __d_drop(child); ++ spin_unlock(&child->d_lock); ++ } ++#endif ++ ++ inode = child->d_inode; ++ if (inode) ++ au_iigen_dec(inode); ++ err = !!inode; ++ ++ // todo: the i_nlink of newly created name by link(2) ++ // should be updated ++ // todo: some nfs dentry doesn't notified at deleteing ++ break; ++ } ++ } ++ spin_unlock(&dcache_lock); ++ dput(parent); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct postproc_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ char *h_child_name; ++ u32 mask; ++}; ++ ++static void dec_gen_by_ino(struct postproc_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend, bfound; ++ struct xino xino; ++ struct inode *cinode; ++ ++ TraceEnter(); ++ ++ sb = a->dir->i_sb; ++ DEBUG_ON(!au_flag_test(sb, AuFlag_XINO)); ++ ++ bfound = -1; ++ bend = ibend(a->dir); ++ for (bindex = ibstart(a->dir); bfound == -1 && bindex <= bend; bindex++) ++ if (au_h_iptr_i(a->dir, bindex) == a->h_dir) ++ bfound = bindex; ++ if (bfound < 0) ++ return; ++ ++ bindex = find_brindex(sb, itoii(a->dir)->ii_hinode[bfound + 0].hi_id); ++ if (bindex < 0) ++ return; ++ if (unlikely(xino_read(sb, bindex, a->h_child_inode->i_ino, &xino))) ++ return; ++ cinode = NULL; ++ if (xino.ino) ++ cinode = ilookup(sb, xino.ino); ++ if (cinode) { ++#if 1 ++ if (1 || a->mask & IN_MOVE) { ++ struct dentry *child; ++ spin_lock(&dcache_lock); ++ list_for_each_entry(child, &cinode->i_dentry, d_alias) ++ au_digen_dec(child); ++ spin_unlock(&dcache_lock); ++ } ++#endif ++ au_iigen_dec(cinode); ++ iput(cinode); ++ } ++} ++ ++static void reset_ino(struct postproc_args *a) ++{ ++ aufs_bindex_t bindex, bend; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ sb = a->dir->i_sb; ++ bend = ibend(a->dir); ++ for (bindex = ibstart(a->dir); bindex <= bend; bindex++) { ++ h_dir = au_h_iptr_i(a->dir, bindex); ++ if (h_dir && h_dir != a->h_dir) ++ xino_write0(sb, bindex, h_dir->i_ino); ++ /* ignore this error */ ++ } ++} ++ ++static void postproc(void *args) ++{ ++ struct postproc_args *a = args; ++ struct super_block *sb; ++ struct aufs_vdir *vdir; ++ ++ //au_debug_on(); ++ LKTRTrace("mask 0x%x %s, i%lu, hi%lu, hci%lu\n", ++ a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ DEBUG_ON(!a->dir); ++#if 0//def ForceInotify ++ Dbg("mask 0x%x %s, i%lu, hi%lu, hci%lu\n", ++ a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++#endif ++ ++ i_lock(a->dir); ++ sb = a->dir->i_sb; ++ si_read_lock(sb); // consider write_lock ++ ii_write_lock_parent(a->dir); ++ ++ /* make dir entries obsolete */ ++ vdir = ivdir(a->dir); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ a->dir->i_version++; ++ ++ /* ++ * special handling root directory, ++ * sine d_revalidate may not be called later. ++ * main purpose is maintaining i_nlink. ++ */ ++ if (unlikely(a->dir->i_ino == AUFS_ROOT_INO)) ++ au_cpup_attr_all(a->dir); ++ ++ if (a->h_child_inode && au_flag_test(sb, AuFlag_XINO)) ++ dec_gen_by_ino(a); ++ else if (a->mask & (IN_MOVE_SELF | IN_DELETE_SELF)) ++ reset_ino(a); ++ ++ ii_write_unlock(a->dir); ++ si_read_unlock(sb); ++ i_unlock(a->dir); ++ ++ au_mntput(a->dir->i_sb); ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++#if 0 ++ if (atomic_dec_and_test(&stosi(sb)->si_hinotify)) ++ wake_up_all(&stosi(sb)->si_hinotify_wq); ++#endif ++ kfree(a); ++ //au_debug_off(); ++} ++ ++static void aufs_inotify(struct inotify_watch *watch, u32 wd, u32 mask, ++ u32 cookie, const char *h_child_name, ++ struct inode *h_child_inode) ++{ ++ struct aufs_hinotify *hinotify; ++ struct postproc_args *args; ++ int len; ++ char *p; ++ struct inode *dir; ++ //static DECLARE_WAIT_QUEUE_HEAD(wq); ++ ++ //au_debug_on(); ++ LKTRTrace("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s, hi%lu\n", ++ watch->inode->i_ino, wd, mask, in_name(mask), cookie, ++ h_child_name ? h_child_name : "", ++ h_child_inode ? h_child_inode->i_ino : 0); ++ //au_debug_off(); ++ //IMustLock(h_dir); ++#if 0 //defined(ForceInotify) || defined(DbgInotify) ++ Dbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s, hi%lu\n", ++ watch->inode->i_ino, wd, mask, in_name(mask), cookie, ++ h_child_name ? h_child_name : "", ++ h_child_inode ? h_child_inode->i_ino : 0); ++#endif ++ /* if IN_UNMOUNT happens, there must be another bug */ ++ if (mask & (IN_IGNORED | IN_UNMOUNT)) { ++ put_inotify_watch(watch); ++ return; ++ } ++ ++ switch (mask & IN_ALL_EVENTS) { ++ case IN_MODIFY: ++ case IN_ATTRIB: ++ if (h_child_name) ++ return; ++ break; ++ ++ case IN_MOVED_FROM: ++ case IN_MOVED_TO: ++ case IN_CREATE: ++ DEBUG_ON(!h_child_name || !h_child_inode); ++ break; ++ case IN_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalide() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ DEBUG_ON(!h_child_name); ++ break; ++ ++ case IN_DELETE_SELF: ++ case IN_MOVE_SELF: ++ DEBUG_ON(h_child_name || h_child_inode); ++ break; ++ ++ case IN_ACCESS: ++ default: ++ DEBUG_ON(1); ++ } ++ ++#ifdef DbgInotify ++ WARN_ON(1); ++#endif ++ ++ /* iput() will be called in postproc() */ ++ hinotify = container_of(watch, struct aufs_hinotify, hin_watch); ++ DEBUG_ON(!hinotify || !hinotify->hin_aufs_inode); ++ dir = hinotify->hin_aufs_inode; ++ ++ /* force re-lookup in next d_revalidate() */ ++ if (dir->i_ino != AUFS_ROOT_INO) ++ au_iigen_dec(dir); ++ len = 0; ++ if (h_child_name && dec_gen_by_name(dir, h_child_name, mask)) ++ len = strlen(h_child_name); ++ ++ //wait_event(wq, (args = kmalloc(sizeof(*args), GFP_KERNEL))); ++ args = kmalloc(sizeof(*args) + len + 1, GFP_KERNEL); ++ if (unlikely(!args)) { ++ Err("no memory\n"); ++ return; ++ } ++ args->mask = mask; ++ args->dir = igrab(dir); ++ args->h_dir = igrab(watch->inode); ++ args->h_child_inode = NULL; ++ if (len) { ++ if (h_child_inode) ++ args->h_child_inode = igrab(h_child_inode); ++ p = (void*)args; ++ args->h_child_name = p + sizeof(*args); ++ memcpy(args->h_child_name, h_child_name, len + 1); ++ } ++ //atomic_inc(&stosi(args->dir->i_sb)->si_hinotify); ++ /* prohibit umount */ ++ au_mntget(args->dir->i_sb); ++ au_wkq_nowait(postproc, args, /*dlgt*/0); ++} ++ ++#if 0 ++void hinotify_flush(struct super_block *sb) ++{ ++ atomic_t *p = &stosi(sb)->si_hinotify; ++ wait_event(stosi(sb)->si_hinotify_wq, !atomic_read(p)); ++} ++#endif ++ ++static void aufs_inotify_destroy(struct inotify_watch *watch) ++{ ++ return; ++} ++ ++static struct inotify_operations aufs_inotify_ops = { ++ .handle_event = aufs_inotify, ++ .destroy_watch = aufs_inotify_destroy ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_inotify_init(void) ++{ ++ in_handle = inotify_init(&aufs_inotify_ops); ++ if (!IS_ERR(in_handle)) ++ return 0; ++ TraceErrPtr(in_handle); ++ return PTR_ERR(in_handle); ++} ++ ++void au_inotify_fin(void) ++{ ++ inotify_destroy(in_handle); ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/i_op.c linux-2.6.22.1/fs/aufs/i_op.c +--- linux-2.6.22.1.oorig/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/i_op.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,641 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: i_op.c,v 1.30 2007/04/23 00:55:05 sfjro Exp $ */ ++ ++//#include ++//#include ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_DLGT ++struct security_inode_permission_args { ++ int *errp; ++ struct inode *h_inode; ++ int mask; ++ struct nameidata *fake_nd; ++}; ++ ++static void call_security_inode_permission(void *args) ++{ ++ struct security_inode_permission_args *a = args; ++ LKTRTrace("fsuid %d\n", current->fsuid); ++ *a->errp = security_inode_permission(a->h_inode, a->mask, a->fake_nd); ++} ++#endif ++ ++static int hidden_permission(struct inode *hidden_inode, int mask, ++ struct nameidata *fake_nd, int brperm, int dlgt) ++{ ++ int err, submask; ++ const int write_mask = (mask & (MAY_WRITE | MAY_APPEND)); ++ ++ LKTRTrace("ino %lu, mask 0x%x, brperm 0x%x\n", ++ hidden_inode->i_ino, mask, brperm); ++ ++ err = -EACCES; ++ if (unlikely(write_mask && IS_IMMUTABLE(hidden_inode))) ++ goto out; ++ ++ /* skip hidden fs test in the case of write to ro branch */ ++ submask = mask & ~MAY_APPEND; ++ if (unlikely((write_mask && !br_writable(brperm)) ++ || !hidden_inode->i_op ++ || !hidden_inode->i_op->permission)) { ++ //LKTRLabel(generic_permission); ++ err = generic_permission(hidden_inode, submask, NULL); ++ } else { ++ //LKTRLabel(h_inode->permission); ++ err = hidden_inode->i_op->permission(hidden_inode, submask, ++ fake_nd); ++ TraceErr(err); ++ } ++ ++#if 1 ++ if (!err) { ++#ifndef CONFIG_AUFS_DLGT ++ err = security_inode_permission(hidden_inode, mask, fake_nd); ++#else ++ if (!dlgt) ++ err = security_inode_permission(hidden_inode, mask, ++ fake_nd); ++ else { ++ struct security_inode_permission_args args = { ++ .errp = &err, ++ .h_inode = hidden_inode, ++ .mask = mask, ++ .fake_nd = fake_nd ++ }; ++ au_wkq_wait(call_security_inode_permission, &args, ++ /*dlgt*/1); ++ } ++#endif ++ } ++#endif ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static int silly_lock(struct inode *inode, struct nameidata *nd) ++{ ++ int locked = 0; ++ struct super_block *sb = inode->i_sb; ++ ++ LKTRTrace("i%lu, nd %p\n", inode->i_ino, nd); ++ ++#ifdef CONFIG_AUFS_FAKE_DM ++ si_read_lock(sb); ++ ii_read_lock_child(inode); ++#else ++ if (!nd || !nd->dentry) { ++ si_read_lock(sb); ++ ii_read_lock_child(inode); ++ } else if (nd->dentry->d_inode != inode) { ++ locked = 1; ++ /* lock child first, then parent */ ++ si_read_lock(sb); ++ ii_read_lock_child(inode); ++ di_read_lock_parent(nd->dentry, 0); ++ } else { ++ locked = 2; ++ aufs_read_lock(nd->dentry, AUFS_I_RLOCK); ++ } ++#endif ++ return locked; ++} ++ ++static void silly_unlock(int locked, struct inode *inode, struct nameidata *nd) ++{ ++ struct super_block *sb = inode->i_sb; ++ ++ LKTRTrace("locked %d, i%lu, nd %p\n", locked, inode->i_ino, nd); ++ ++#ifdef CONFIG_AUFS_FAKE_DM ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++#else ++ switch (locked) { ++ case 0: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ break; ++ case 1: ++ di_read_unlock(nd->dentry, 0); ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ break; ++ case 2: ++ aufs_read_unlock(nd->dentry, AUFS_I_RLOCK); ++ break; ++ default: ++ BUG(); ++ } ++#endif ++} ++ ++static int aufs_permission(struct inode *inode, int mask, struct nameidata *nd) ++{ ++ int err, locked, dlgt; ++ aufs_bindex_t bindex, bend; ++ struct inode *hidden_inode; ++ struct super_block *sb; ++ struct nameidata fake_nd, *p; ++ const int write_mask = (mask & (MAY_WRITE | MAY_APPEND)); ++ const int nondir = !S_ISDIR(inode->i_mode); ++ ++ LKTRTrace("ino %lu, mask 0x%x, nondir %d, write_mask %d, " ++ "nd %p{%p, %p}\n", ++ inode->i_ino, mask, nondir, write_mask, ++ nd, nd ? nd->dentry : NULL, nd ? nd->mnt : NULL); ++ ++ sb = inode->i_sb; ++ locked = silly_lock(inode, nd); ++ dlgt = need_dlgt(sb); ++ ++ if (nd) ++ fake_nd = *nd; ++ if (/* unlikely */(nondir || write_mask)) { ++ hidden_inode = au_h_iptr(inode); ++ DEBUG_ON(!hidden_inode ++ || ((hidden_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))); ++ err = 0; ++ bindex = ibstart(inode); ++ p = fake_dm(&fake_nd, nd, sb, bindex); ++ /* actual test will be delegated to LSM */ ++ if (IS_ERR(p)) ++ DEBUG_ON(PTR_ERR(p) != -ENOENT); ++ else { ++ err = hidden_permission(hidden_inode, mask, p, ++ sbr_perm(sb, bindex), dlgt); ++ fake_dm_release(p); ++ } ++ if (write_mask && !err) { ++ err = find_rw_br(sb, bindex); ++ if (err >= 0) ++ err = 0; ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bend = ibend(inode); ++ for (bindex = ibstart(inode); !err && bindex <= bend; bindex++) { ++ hidden_inode = au_h_iptr_i(inode, bindex); ++ if (!hidden_inode) ++ continue; ++ DEBUG_ON(!S_ISDIR(hidden_inode->i_mode)); ++ ++ p = fake_dm(&fake_nd, nd, sb, bindex); ++ /* actual test will be delegated to LSM */ ++ if (IS_ERR(p)) ++ DEBUG_ON(PTR_ERR(p) != -ENOENT); ++ else { ++ err = hidden_permission(hidden_inode, mask, p, ++ sbr_perm(sb, bindex), dlgt); ++ fake_dm_release(p); ++ } ++ } ++ ++ out: ++ silly_unlock(locked, inode, nd); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ struct dentry *ret, *parent; ++ int err, npositive; ++ struct inode *inode; ++ ++ LKTRTrace("dir %lu, %.*s\n", dir->i_ino, DLNPair(dentry)); ++ DEBUG_ON(IS_ROOT(dentry)); ++ IMustLock(dir); ++ ++ parent = dentry->d_parent; // dget_parent() ++ aufs_read_lock(parent, !AUFS_I_RLOCK); ++ err = au_alloc_dinfo(dentry); ++ //if (LktrCond) err = -1; ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = npositive = lkup_dentry(dentry, dbstart(parent), /*type*/0); ++ //err = -1; ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ inode = NULL; ++ if (npositive) { ++ inode = au_new_inode(dentry); ++ ret = (void*)inode; ++ } ++ if (!IS_ERR(inode)) { ++#if 1 ++ /* d_splice_alias() also supports d_add() */ ++ ret = d_splice_alias(inode, dentry); ++ if (unlikely(IS_ERR(ret) && inode)) ++ ii_write_unlock(inode); ++#else ++ d_add(dentry, inode); ++#endif ++ } ++ ++ out_unlock: ++ di_write_unlock(dentry); ++ out: ++ aufs_read_unlock(parent, !AUFS_I_RLOCK); ++ TraceErrPtr(ret); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int wr_dir(struct dentry *dentry, int add_entry, struct dentry *src_dentry, ++ aufs_bindex_t force_btgt, int do_lock_srcdir) ++{ ++ int err; ++ aufs_bindex_t bcpup, bstart, src_bstart; ++ struct dentry *hidden_parent; ++ struct super_block *sb; ++ struct dentry *parent, *src_parent = NULL; ++ struct inode *dir, *src_dir = NULL; ++ ++ LKTRTrace("%.*s, add %d, src %p, force %d, lock_srcdir %d\n", ++ DLNPair(dentry), add_entry, src_dentry, force_btgt, ++ do_lock_srcdir); ++ ++ sb = dentry->d_sb; ++ parent = dentry->d_parent; // dget_parent() ++ bcpup = bstart = dbstart(dentry); ++ if (force_btgt < 0) { ++ if (src_dentry) { ++ src_bstart = dbstart(src_dentry); ++ if (src_bstart < bstart) ++ bcpup = src_bstart; ++ } ++ if (test_ro(sb, bcpup, dentry->d_inode)) { ++ if (!add_entry) ++ di_read_lock_parent(parent, !AUFS_I_RLOCK); ++ bcpup = err = find_rw_parent_br(dentry, bcpup); ++ //bcpup = err = find_rw_br(sb, bcpup); ++ if (!add_entry) ++ di_read_unlock(parent, !AUFS_I_RLOCK); ++ //err = -1; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ DEBUG_ON(bstart <= force_btgt ++ || test_ro(sb, force_btgt, dentry->d_inode)); ++ bcpup = force_btgt; ++ } ++ LKTRTrace("bstart %d, bcpup %d\n", bstart, bcpup); ++ ++ err = bcpup; ++ if (bcpup == bstart) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ hidden_parent = au_h_dptr(dentry)->d_parent; // dget_parent() ++ if (src_dentry) { ++ src_parent = src_dentry->d_parent; // dget_parent() ++ src_dir = src_parent->d_inode; ++ if (do_lock_srcdir) ++ di_write_lock_parent2(src_parent); ++ } ++ ++ dir = parent->d_inode; ++ if (add_entry) { ++ au_update_dbstart(dentry); ++ IMustLock(dir); ++ DiMustWriteLock(parent); ++ IiMustWriteLock(dir); ++ } else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr_i(parent, bcpup)) ++ err = cpup_dirs(dentry, bcpup, src_parent); ++ //err = -1; ++ if (!err && add_entry) { ++ hidden_parent = au_h_dptr_i(parent, bcpup); ++ DEBUG_ON(!hidden_parent || !hidden_parent->d_inode); ++ hi_lock_parent(hidden_parent->d_inode); ++ err = lkup_neg(dentry, bcpup); ++ //err = -1; ++ i_unlock(hidden_parent->d_inode); ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (do_lock_srcdir) ++ di_write_unlock(src_parent); ++ if (!err) ++ err = bcpup; /* success */ ++ //err = -EPERM; ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_setattr(struct dentry *dentry, struct iattr *ia) ++{ ++ int err, isdir; ++ aufs_bindex_t bstart, bcpup; ++ struct inode *hidden_inode, *inode, *dir, *h_dir, *gh_dir, *gdir; ++ struct dentry *hidden_dentry, *parent; ++ unsigned int udba; ++ ++ LKTRTrace("%.*s, ia_valid 0x%x\n", DLNPair(dentry), ia->ia_valid); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ bstart = dbstart(dentry); ++ bcpup = err = wr_dir(dentry, /*add*/0, /*src_dentry*/NULL, ++ /*force_btgt*/-1, /*do_lock_srcdir*/0); ++ //err = -1; ++ if (unlikely(err < 0)) ++ goto out; ++ ++ /* crazy udba locks */ ++ udba = au_flag_test(dentry->d_sb, AuFlag_UDBA_INOTIFY); ++ parent = NULL; ++ gdir = gh_dir = dir = h_dir = NULL; ++ if ((udba || bstart != bcpup) && !IS_ROOT(dentry)) { ++ parent = dentry->d_parent; // dget_parent() ++ dir = parent->d_inode; ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ h_dir = au_h_iptr_i(dir, bcpup); ++ } ++ if (parent) { ++ if (unlikely(udba && !IS_ROOT(parent))) { ++ gdir = parent->d_parent->d_inode; // dget_parent() ++ ii_read_lock_parent2(gdir); ++ gh_dir = au_h_iptr_i(gdir, bcpup); ++ hgdir_lock(gh_dir, gdir, bcpup); ++ } ++ hdir_lock(h_dir, dir, bcpup); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ hidden_dentry = au_h_dptr(dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode); ++ ++#define HiLock(bindex) do {\ ++ if (!isdir) \ ++ hi_lock_child(hidden_inode); \ ++ else \ ++ hdir2_lock(hidden_inode, inode, bindex); \ ++ } while (0) ++#define HiUnlock(bindex) do {\ ++ if (!isdir) \ ++ i_unlock(hidden_inode); \ ++ else \ ++ hdir_unlock(hidden_inode, inode, bindex); \ ++ } while (0) ++ ++ if (bstart != bcpup) { ++ loff_t size = -1; ++ ++ if ((ia->ia_valid & ATTR_SIZE) ++ && ia->ia_size < i_size_read(inode)) { ++ size = ia->ia_size; ++ ia->ia_valid &= ~ATTR_SIZE; ++ } ++ HiLock(bstart); ++ err = sio_cpup_simple(dentry, bcpup, size, ++ au_flags_cpup(CPUP_DTIME, parent)); ++ //err = -1; ++ HiUnlock(bstart); ++ if (unlikely(err || !ia->ia_valid)) ++ goto out_unlock; ++ ++ hidden_dentry = au_h_dptr(dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode); ++ } ++ ++ HiLock(bcpup); ++ err = vfsub_notify_change(hidden_dentry, ia, need_dlgt(dentry->d_sb)); ++ //err = -1; ++ if (!err) ++ au_cpup_attr_changable(inode); ++ HiUnlock(bcpup); ++#undef HiLock ++#undef HiUnlock ++ ++ out_unlock: ++ if (parent) { ++ hdir_unlock(h_dir, dir, bcpup); ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ } ++ if (unlikely(gdir)) { ++ hdir_unlock(gh_dir, gdir, bcpup); ++ ii_read_unlock(gdir); ++ } ++ out: ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hidden_readlink(struct dentry *dentry, int bindex, ++ char __user * buf, int bufsiz) ++{ ++ struct super_block *sb; ++ struct dentry *hidden_dentry; ++ ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (unlikely(!hidden_dentry->d_inode->i_op ++ || !hidden_dentry->d_inode->i_op->readlink)) ++ return -EINVAL; ++ ++ sb = dentry->d_sb; ++ if (!test_ro(sb, bindex, dentry->d_inode)) { ++ touch_atime(sbr_mnt(sb, bindex), hidden_dentry); ++ dentry->d_inode->i_atime = hidden_dentry->d_inode->i_atime; ++ } ++ return hidden_dentry->d_inode->i_op->readlink ++ (hidden_dentry, buf, bufsiz); ++} ++ ++static int aufs_readlink(struct dentry *dentry, char __user * buf, int bufsiz) ++{ ++ int err; ++ ++ LKTRTrace("%.*s, %d\n", DLNPair(dentry), bufsiz); ++ ++ aufs_read_lock(dentry, AUFS_I_RLOCK); ++ err = hidden_readlink(dentry, dbstart(dentry), buf, bufsiz); ++ //err = -1; ++ aufs_read_unlock(dentry, AUFS_I_RLOCK); ++ TraceErr(err); ++ return err; ++} ++ ++static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ int err; ++ char *buf; ++ mm_segment_t old_fs; ++ ++ LKTRTrace("%.*s, nd %.*s\n", DLNPair(dentry), DLNPair(nd->dentry)); ++ ++ err = -ENOMEM; ++ buf = __getname(); ++ //buf = NULL; ++ if (unlikely(!buf)) ++ goto out; ++ ++ aufs_read_lock(dentry, AUFS_I_RLOCK); ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = hidden_readlink(dentry, dbstart(dentry), (char __user *)buf, ++ PATH_MAX); ++ //err = -1; ++ set_fs(old_fs); ++ aufs_read_unlock(dentry, AUFS_I_RLOCK); ++ ++ if (err >= 0) { ++ buf[err] = 0; ++ /* will be freed by put_link */ ++ nd_set_link(nd, buf); ++ return NULL; /* success */ ++ } ++ __putname(buf); ++ ++ out: ++ path_release(nd); ++ TraceErr(err); ++ return ERR_PTR(err); ++} ++ ++static void aufs_put_link(struct dentry *dentry, struct nameidata *nd, ++ void *cookie) ++{ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ __putname(nd_get_link(nd)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++#if 0 // comment ++struct inode_operations { ++ int (*create) (struct inode *,struct dentry *,int, struct nameidata *); ++ struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); ++ int (*link) (struct dentry *,struct inode *,struct dentry *); ++ int (*unlink) (struct inode *,struct dentry *); ++ int (*symlink) (struct inode *,struct dentry *,const char *); ++ int (*mkdir) (struct inode *,struct dentry *,int); ++ int (*rmdir) (struct inode *,struct dentry *); ++ int (*mknod) (struct inode *,struct dentry *,int,dev_t); ++ int (*rename) (struct inode *, struct dentry *, ++ struct inode *, struct dentry *); ++ int (*readlink) (struct dentry *, char __user *,int); ++ void * (*follow_link) (struct dentry *, struct nameidata *); ++ void (*put_link) (struct dentry *, struct nameidata *, void *); ++ void (*truncate) (struct inode *); ++ int (*permission) (struct inode *, int, struct nameidata *); ++ int (*setattr) (struct dentry *, struct iattr *); ++ int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); ++ int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); ++ ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); ++ ssize_t (*listxattr) (struct dentry *, char *, size_t); ++ int (*removexattr) (struct dentry *, const char *); ++ void (*truncate_range)(struct inode *, loff_t, loff_t); ++}; ++#endif ++ ++struct inode_operations aufs_symlink_iop = { ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ ++ .readlink = aufs_readlink, ++ .follow_link = aufs_follow_link, ++ .put_link = aufs_put_link ++}; ++ ++//i_op_add.c ++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev); ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); ++int aufs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode); ++ ++//i_op_del.c ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++// i_op_ren.c ++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry); ++ ++struct inode_operations aufs_dir_iop = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ ++#if 0 // xattr ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr ++#endif ++}; ++ ++struct inode_operations aufs_iop = { ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ ++#if 0 // xattr ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr ++#endif ++}; +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/i_op_add.c linux-2.6.22.1/fs/aufs/i_op_add.c +--- linux-2.6.22.1.oorig/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/i_op_add.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,621 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: i_op_add.c,v 1.37 2007/05/07 03:46:08 sfjro Exp $ */ ++ ++//#include ++//#include ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct inode *inode, *dir; ++ struct dentry *wh; ++ struct lkup_args lkup; ++ ++ LKTRTrace("wh %p, %.*s\n", wh_dentry, DLNPair(dentry)); ++ ++ lkup.dlgt = need_dlgt(dentry->d_sb); ++ bwh = -1; ++ if (wh_dentry) { ++ bwh = dbwh(dentry); ++ err = au_unlink_wh_dentry(wh_dentry->d_parent->d_inode, ++ wh_dentry, dentry, lkup.dlgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry); ++ //inode = ERR_PTR(-1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = dentry->d_parent->d_inode; ++ /* or always cpup dir mtime? */ ++ if (ibstart(dir) == dbstart(dentry)) ++ au_cpup_attr_timesizes(dir); ++ dir->i_version++; ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ lkup.nfsmnt = au_nfsmnt(dentry->d_sb, bwh); ++ wh = simple_create_wh(dentry, bwh, wh_dentry->d_parent, &lkup); ++ //wh = ERR_PTR(-1); ++ rerr = PTR_ERR(wh); ++ if (!IS_ERR(wh)) { ++ dput(wh); ++ goto out; ++ } ++ IOErr("%.*s reverting whiteout failed(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ err = -EIO; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * lookup whiteout for the new entry. ++ */ ++static struct dentry * ++lock_hdir_lkup_wh(struct dentry *dentry, struct dtime *dt, ++ struct dentry *src_dentry, int do_lock_srcdir) ++{ ++ struct dentry *wh_dentry, *parent, *hidden_parent; ++ int err; ++ aufs_bindex_t bstart, bcpup; ++ struct inode *dir, *h_dir; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, src %p\n", DLNPair(dentry), src_dentry); ++ ++ parent = dentry->d_parent; ++ bstart = dbstart(dentry); ++ bcpup = err = wr_dir(dentry, 1, src_dentry, -1, do_lock_srcdir); ++ //err = -1; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ dir = parent->d_inode; ++ hidden_parent = au_h_dptr_i(parent, bcpup); ++ h_dir = hidden_parent->d_inode; ++ hdir_lock(h_dir, dir, bcpup); ++ if (dt) ++ dtime_store(dt, parent, hidden_parent); ++ if (/* bcpup != bstart || */ bcpup != dbwh(dentry)) ++ return NULL; /* success */ ++ ++ lkup.nfsmnt = au_nfsmnt(parent->d_sb, bcpup); ++ lkup.dlgt = need_dlgt(parent->d_sb); ++ wh_dentry = lkup_wh(hidden_parent, &dentry->d_name, &lkup); ++ //wh_dentry = ERR_PTR(-1); ++ if (IS_ERR(wh_dentry)) ++ hdir_unlock(h_dir, dir, bcpup); ++ ++ out: ++ TraceErrPtr(wh_dentry); ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum {Mknod, Symlink, Creat}; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ int mode; ++ struct nameidata *nd; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ int mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, dlgt; ++ struct dentry *hidden_dentry, *hidden_parent, *wh_dentry, *parent; ++ struct inode *hidden_dir; ++ struct dtime dt; ++ ++ LKTRTrace("type %d, %.*s\n", arg->type, DLNPair(dentry)); ++ IMustLock(dir); ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ parent = dentry->d_parent; ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, ++ /*do_lock_srcdir*/0); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ hidden_dentry = au_h_dptr(dentry); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ dlgt = need_dlgt(dir->i_sb); ++ ++#if 1 // partial testing ++ switch (arg->type) { ++ case Creat: ++#if 0 ++ if (arg->u.c.nd) { ++ struct nameidata fake_nd; ++ fake_nd = *arg->u.c.nd; ++ fake_nd.dentry = dget(hidden_parent); ++ fake_nd.mnt = sbr_mnt(dentry->d_sb, dbstart(dentry)); ++ mntget(fake_nd.mnt); ++ err = vfsub_create(hidden_dir, hidden_dentry, ++ arg->u.c.mode, &fake_nd, dlgt); ++ path_release(&fake_nd); ++ } else ++#endif ++ err = vfsub_create(hidden_dir, hidden_dentry, ++ arg->u.c.mode, NULL, dlgt); ++ break; ++ case Symlink: ++ err = vfsub_symlink(hidden_dir, hidden_dentry, ++ arg->u.s.symname, S_IALLUGO, dlgt); ++ break; ++ case Mknod: ++ err = vfsub_mknod(hidden_dir, hidden_dentry, ++ arg->u.m.mode, arg->u.m.dev, dlgt); ++ break; ++ default: ++ BUG(); ++ } ++#else ++ err = -1; ++#endif ++ if (!err) ++ err = epilog(wh_dentry, dentry); ++ //err = -1; ++ ++ /* revert */ ++ if (unlikely(err && hidden_dentry->d_inode)) { ++ int rerr; ++ rerr = vfsub_unlink(hidden_dir, hidden_dentry, dlgt); ++ //rerr = -1; ++ if (rerr) { ++ IOErr("%.*s revert failure(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ dtime_revert(&dt, !CPUP_LOCKED_GHDIR); ++ d_drop(dentry); ++ } ++ ++ hdir_unlock(hidden_dir, dir, dbstart(dentry)); ++ dput(wh_dentry); ++ ++ out: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = {.mode = mode, .dev = dev} ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = {.mode = mode, .nd = nd} ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct link_arg { ++ aufs_bindex_t bdst, bsrc; ++ int issamedir, dlgt; ++ struct dentry *src_parent, *parent, *hidden_dentry; ++ struct inode *hidden_dir, *inode; ++}; ++ ++static int cpup_before_link(struct dentry *src_dentry, struct inode *dir, ++ struct link_arg *a) ++{ ++ int err; ++ unsigned int flags; ++ struct inode *hi, *hdir = NULL, *src_dir; ++ ++ TraceEnter(); ++ ++ err = 0; ++ flags = au_flags_cpup(CPUP_DTIME, a->parent); ++ src_dir = a->src_parent->d_inode; ++ if (!a->issamedir) { ++ // todo: dead lock? ++ di_read_lock_parent2(a->src_parent, AUFS_I_RLOCK); ++ // this temporary unlock/lock is safe ++ hdir_unlock(a->hidden_dir, dir, a->bdst); ++ err = test_and_cpup_dirs(src_dentry, a->bdst, a->parent); ++ //err = -1; ++ if (!err) { ++ hdir = au_h_iptr_i(src_dir, a->bdst); ++ hdir_lock(hdir, src_dir, a->bdst); ++ flags = au_flags_cpup(CPUP_DTIME, a->src_parent); ++ } ++ } ++ ++ if (!err) { ++ hi = au_h_dptr(src_dentry)->d_inode; ++ hi_lock_child(hi); ++ err = sio_cpup_simple(src_dentry, a->bdst, -1, flags); ++ //err = -1; ++ i_unlock(hi); ++ } ++ ++ if (!a->issamedir) { ++ if (hdir) ++ hdir_unlock(hdir, src_dir, a->bdst); ++ hdir_lock(a->hidden_dir, dir, a->bdst); ++ di_read_unlock(a->src_parent, AUFS_I_RLOCK); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int cpup_or_link(struct dentry *src_dentry, struct link_arg *a) ++{ ++ int err; ++ struct inode *inode, *h_inode, *h_dst_inode; ++ struct dentry *h_dentry; ++ aufs_bindex_t bstart; ++ struct super_block *sb; ++ ++ TraceEnter(); ++ ++ sb = src_dentry->d_sb; ++ inode = src_dentry->d_inode; ++ h_dentry = au_h_dptr(src_dentry); ++ h_inode = h_dentry->d_inode; ++ bstart = ibstart(inode); ++ h_dst_inode = NULL; ++ if (bstart <= a->bdst) ++ h_dst_inode = au_h_iptr_i(inode, a->bdst); ++ ++ if (!h_dst_inode) { ++ /* copyup src_dentry as the name of dentry. */ ++ set_dbstart(src_dentry, a->bdst); ++ set_h_dptr(src_dentry, a->bdst, dget(a->hidden_dentry)); ++ hi_lock_child(h_inode); ++ err = sio_cpup_single(src_dentry, a->bdst, a->bsrc, -1, ++ au_flags_cpup(!CPUP_DTIME, a->parent)); ++ //err = -1; ++ i_unlock(h_inode); ++ set_h_dptr(src_dentry, a->bdst, NULL); ++ set_dbstart(src_dentry, a->bsrc); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_dentry = d_find_alias(h_dst_inode); ++ if (h_dentry) { ++ err = vfsub_link(h_dentry, a->hidden_dir, ++ a->hidden_dentry, a->dlgt); ++ dput(h_dentry); ++ } else { ++ IOErr("no dentry found for i%lu on b%d\n", ++ h_dst_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err) ++ append_plink(sb, a->inode, a->hidden_dentry, a->bdst); ++ ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct dentry *hidden_parent, *wh_dentry, *hidden_src_dentry; ++ struct dtime dt; ++ struct link_arg a; ++ struct super_block *sb; ++ ++ LKTRTrace("src %.*s, i%lu, dst %.*s\n", ++ DLNPair(src_dentry), dir->i_ino, DLNPair(dentry)); ++ IMustLock(dir); ++ IMustLock(src_dentry->d_inode); ++ ++ aufs_read_and_write_lock2(dentry, src_dentry, /*isdir*/0); ++ a.src_parent = src_dentry->d_parent; ++ a.parent = dentry->d_parent; ++ a.issamedir = (a.src_parent == a.parent); ++ di_write_lock_parent(a.parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, !a.issamedir); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ a.inode = src_dentry->d_inode; ++ a.hidden_dentry = au_h_dptr(dentry); ++ hidden_parent = a.hidden_dentry->d_parent; ++ a.hidden_dir = hidden_parent->d_inode; ++ IMustLock(a.hidden_dir); ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a.dlgt = need_dlgt(sb); ++ ++ //todo: minor optimize, their sb may be same while their bindex differs. ++ a.bsrc = dbstart(src_dentry); ++ a.bdst = dbstart(dentry); ++ hidden_src_dentry = au_h_dptr(src_dentry); ++ if (unlikely(!au_flag_test(sb, AuFlag_PLINK))) { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ * gave up 'pseudo link by cpup' approach, ++ * since nlink may be one and some applications will not work. ++ */ ++ if (a.bdst < a.bsrc ++ /* && hidden_src_dentry->d_sb != a.hidden_dentry->d_sb */) ++ err = cpup_before_link(src_dentry, dir, &a); ++ if (!err) { ++ hidden_src_dentry = au_h_dptr(src_dentry); ++ err = vfsub_link(hidden_src_dentry, a.hidden_dir, ++ a.hidden_dentry, a.dlgt); ++ //err = -1; ++ } ++ } else { ++ if (a.bdst < a.bsrc ++ /* && hidden_src_dentry->d_sb != a.hidden_dentry->d_sb */) ++ err = cpup_or_link(src_dentry, &a); ++ else { ++ hidden_src_dentry = au_h_dptr(src_dentry); ++ err = vfsub_link(hidden_src_dentry, a.hidden_dir, ++ a.hidden_dentry, a.dlgt); ++ //err = -1; ++ } ++ } ++ if (unlikely(err)) ++ goto out_unlock; ++ if (wh_dentry) { ++ err = au_unlink_wh_dentry(a.hidden_dir, wh_dentry, dentry, ++ a.dlgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ dir->i_version++; ++ if (ibstart(dir) == dbstart(dentry)) ++ au_cpup_attr_timesizes(dir); ++ if (!d_unhashed(a.hidden_dentry) ++ /* || hidden_old_inode->i_nlink <= nlink */ ++ /* || SB_NFS(hidden_src_dentry->d_sb) */) { ++ dentry->d_inode = igrab(a.inode); ++ d_instantiate(dentry, a.inode); ++ a.inode->i_nlink++; ++ a.inode->i_ctime = dir->i_ctime; ++ } else ++ /* nfs case (< 2.6.15) */ ++ d_drop(dentry); ++#if 0 ++ au_debug_on(); ++ DbgInode(a.inode); ++ au_debug_off(); ++ { ++ aufs_bindex_t i; ++ for (i = ibstart(a.inode); i <= ibend(a.inode); i++) { ++ struct xino xino; ++ struct inode *hi; ++ hi = au_h_iptr_i(a.inode, i); ++ if (hi) { ++ xino_read(sb, i, hi->i_ino, &xino); ++ Dbg("hi%lu, i%lu\n", hi->i_ino, xino.ino); ++ } ++ } ++ } ++#endif ++ goto out_unlock; /* success */ ++ ++ out_revert: ++#if 0 // remove ++ if (d_unhashed(a.hidden_dentry)) { ++ /* hardlink on nfs (< 2.6.15) */ ++ struct dentry *d; ++ const struct qstr *name = &a.hidden_dentry->d_name; ++ DEBUG_ON(a.hidden_dentry->d_parent->d_inode != a.hidden_dir); ++ // do not superio. ++ d = lkup_one(name->name, a.hidden_dentry->d_parent, name->len, ++ au_nfsmnt(sb, a.bdst)??, need_dlgt(sb)); ++ rerr = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out_rerr; ++ dput(a.hidden_dentry); ++ a.hidden_dentry = d; ++ DEBUG_ON(!d->d_inode); ++ } ++#endif ++ rerr = vfsub_unlink(a.hidden_dir, a.hidden_dentry, a.dlgt); ++ //rerr = -1; ++ if (!rerr) ++ goto out_dt; ++// out_rerr: ++ IOErr("%.*s reverting failed(%d, %d)\n", DLNPair(dentry), err, rerr); ++ err = -EIO; ++ out_dt: ++ d_drop(dentry); ++ dtime_revert(&dt, !CPUP_LOCKED_GHDIR); ++ out_unlock: ++ hdir_unlock(a.hidden_dir, dir, a.bdst); ++ dput(wh_dentry); ++ out: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(a.parent); ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ int err, rerr, diropq, dlgt; ++ struct dentry *hidden_dentry, *hidden_parent, *wh_dentry, *parent, ++ *opq_dentry; ++ struct inode *hidden_dir, *hidden_inode; ++ struct dtime dt; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ ++ LKTRTrace("i%lu, %.*s, mode 0%o\n", dir->i_ino, DLNPair(dentry), mode); ++ IMustLock(dir); ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ parent = dentry->d_parent; ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, ++ /*do_lock_srcdir*/0); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ bindex = dbstart(dentry); ++ hidden_dentry = au_h_dptr(dentry); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ dlgt = need_dlgt(sb); ++ ++ err = vfsub_mkdir(hidden_dir, hidden_dentry, mode, dlgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_unlock; ++ hidden_inode = hidden_dentry->d_inode; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ if (unlikely(wh_dentry || au_flag_test(sb, AuFlag_ALWAYS_DIROPQ))) { ++ hi_lock_child(hidden_inode); ++ opq_dentry = create_diropq(dentry, bindex, dlgt); ++ //opq_dentry = ERR_PTR(-1); ++ i_unlock(hidden_inode); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(wh_dentry, dentry); ++ //err = -1; ++ if (!err) { ++ dir->i_nlink++; ++ goto out_unlock; /* success */ ++ } ++ ++ /* revert */ ++ if (unlikely(diropq)) { ++ LKTRLabel(revert opq); ++ hi_lock_child(hidden_inode); ++ rerr = remove_diropq(dentry, bindex, dlgt); ++ //rerr = -1; ++ i_unlock(hidden_inode); ++ if (rerr) { ++ IOErr("%.*s reverting diropq failed(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ } ++ ++ out_dir: ++ LKTRLabel(revert dir); ++ rerr = vfsub_rmdir(hidden_dir, hidden_dentry, dlgt); ++ //rerr = -1; ++ if (rerr) { ++ IOErr("%.*s reverting dir failed(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ d_drop(dentry); ++ dtime_revert(&dt, /*fake flag*/CPUP_LOCKED_GHDIR); ++ out_unlock: ++ hdir_unlock(hidden_dir, dir, bindex); ++ dput(wh_dentry); ++ out: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ TraceErr(err); ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/i_op_del.c linux-2.6.22.1/fs/aufs/i_op_del.c +--- linux-2.6.22.1.oorig/fs/aufs/i_op_del.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/i_op_del.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,414 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: i_op_del.c,v 1.35 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++/* returns, ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup, ++ struct dentry *locked) ++{ ++ int need_wh, err; ++ aufs_bindex_t bstart; ++ struct dentry *hidden_dentry; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, isdir %d, *bcpup %d, locked %p\n", ++ DLNPair(dentry), isdir, *bcpup, locked); ++ sb = dentry->d_sb; ++ ++ bstart = dbstart(dentry); ++ LKTRTrace("bcpup %d, bstart %d\n", *bcpup, bstart); ++ hidden_dentry = au_h_dptr(dentry); ++ if (*bcpup < 0) { ++ *bcpup = bstart; ++ if (test_ro(sb, bstart, dentry->d_inode)) { ++ *bcpup = err = find_rw_parent_br(dentry, bstart); ++ //*bcpup = err = find_rw_br(sb, bstart); ++ //err = -1; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ /* braces are added to stop a warning */ ++ DEBUG_ON(bstart < *bcpup ++ || test_ro(sb, *bcpup, dentry->d_inode)); ++ } ++ LKTRTrace("bcpup %d, bstart %d\n", *bcpup, bstart); ++ ++ if (*bcpup != bstart) { ++ err = cpup_dirs(dentry, *bcpup, locked); ++ //err = -1; ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ //struct nameidata nd; ++ aufs_bindex_t old_bend, new_bend, bdiropq = -1; ++ old_bend = dbend(dentry); ++ if (isdir) { ++ bdiropq = dbdiropq(dentry); ++ set_dbdiropq(dentry, -1); ++ } ++ err = need_wh = lkup_dentry(dentry, bstart + 1, /*type*/0); ++ //err = -1; ++ if (isdir) ++ set_dbdiropq(dentry, bdiropq); ++ if (unlikely(err < 0)) ++ goto out; ++ new_bend = dbend(dentry); ++ if (!need_wh && old_bend != new_bend) { ++ set_h_dptr(dentry, new_bend, NULL); ++ set_dbend(dentry, old_bend); ++#if 0 ++ } else if (!au_h_dptr_i(dentry, new_bend)->d_inode) { ++ LKTRTrace("negative\n"); ++ set_h_dptr(dentry, new_bend, NULL); ++ set_dbend(dentry, old_bend); ++ need_wh = 0; ++#endif ++ } ++ } ++ LKTRTrace("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static struct dentry * ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup, ++ struct dtime *dt) ++{ ++ struct dentry *wh_dentry; ++ int err, need_wh; ++ struct dentry *hidden_parent, *parent; ++ struct inode *dir, *h_dir; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, isdir %d\n", DLNPair(dentry), isdir); ++ ++ err = need_wh = wr_dir_need_wh(dentry, isdir, bcpup, NULL); ++ //err = -1; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ parent = dentry->d_parent; ++ dir = parent->d_inode; ++ hidden_parent = au_h_dptr_i(parent, *bcpup); ++ h_dir = hidden_parent->d_inode; ++ hdir_lock(h_dir, dir, *bcpup); ++ dtime_store(dt, parent, hidden_parent); ++ if (!need_wh) ++ return NULL; /* success, no need to create whiteout */ ++ ++ lkup.nfsmnt = au_nfsmnt(dentry->d_sb, *bcpup); ++ lkup.dlgt = need_dlgt(dentry->d_sb); ++ wh_dentry = simple_create_wh(dentry, *bcpup, hidden_parent, &lkup); ++ //wh_dentry = ERR_PTR(-1); ++ if (!IS_ERR(wh_dentry)) ++ goto out; /* success */ ++ /* returns with the parent is locked and wh_dentry is DGETed */ ++ ++ hdir_unlock(h_dir, dir, *bcpup); ++ ++ out: ++ TraceErrPtr(wh_dentry); ++ return wh_dentry; ++} ++ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct aufs_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err; ++ struct dentry *hidden_dentry; ++ ++ LKTRTrace("%.*s, b%d\n", DLNPair(dentry), bindex); ++ ++ err = rename_whtmp(dentry, bindex); ++ //err = -1; ++#if 0 ++ //todo: bug ++ if (unlikely(err)) { ++ au_direval_inc(dentry->d_parent); ++ return err; ++ } ++#endif ++ ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!au_is_nfs(hidden_dentry->d_sb)) { ++ const int dirwh = stosi(dentry->d_sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = is_longer_wh(whlist, bindex, dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = rmdir_whtmp(hidden_dentry, whlist, bindex, dir, dentry->d_inode); ++ //err = -1; ++ if (unlikely(err)) { ++ IOErr("rmdir %.*s, b%d failed, %d. ignored\n", ++ DLNPair(hidden_dentry), bindex, err); ++ err = 0; ++ } ++ TraceErr(err); ++ return err; ++} ++ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ d_drop(dentry); ++ dentry->d_inode->i_ctime = dir->i_ctime; ++ if (atomic_read(&dentry->d_count) == 1) { ++ set_h_dptr(dentry, dbstart(dentry), NULL); ++ au_update_dbstart(dentry); ++ } ++ if (ibstart(dir) == bindex) ++ au_cpup_attr_timesizes(dir); ++ dir->i_version++; ++} ++ ++static int do_revert(int err, struct dentry *wh_dentry, struct dentry *dentry, ++ aufs_bindex_t bwh, struct dtime *dt, int dlgt) ++{ ++ int rerr; ++ ++ rerr = au_unlink_wh_dentry(wh_dentry->d_parent->d_inode, wh_dentry, ++ dentry, dlgt); ++ //rerr = -1; ++ if (!rerr) { ++ set_dbwh(dentry, bwh); ++ dtime_revert(dt, !CPUP_LOCKED_GHDIR); ++ return 0; ++ } ++ ++ IOErr("%.*s reverting whiteout failed(%d, %d)\n", ++ DLNPair(dentry), err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err, dlgt; ++ struct inode *inode, *hidden_dir; ++ struct dentry *parent, *wh_dentry, *hidden_dentry, *hidden_parent; ++ struct dtime dt; ++ aufs_bindex_t bwh, bindex, bstart; ++ struct super_block *sb; ++ ++ LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry)); ++ IMustLock(dir); ++ inode = dentry->d_inode; ++ if (unlikely(!inode)) ++ return -ENOENT; // possible? ++ IMustLock(inode); ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ parent = dentry->d_parent; ++ di_write_lock_parent(parent); ++ ++ bstart = dbstart(dentry); ++ bwh = dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ sb = dir->i_sb; ++ dlgt = need_dlgt(sb); ++ hidden_dentry = au_h_dptr(dentry); ++ dget(hidden_dentry); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ ++ if (bindex == bstart) { ++ err = vfsub_unlink(hidden_dir, hidden_dentry, dlgt); ++ //err = -1; ++ } else { ++ DEBUG_ON(!wh_dentry); ++ hidden_parent = wh_dentry->d_parent; ++ DEBUG_ON(hidden_parent != au_h_dptr_i(parent, bindex)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ inode->i_nlink--; ++ epilog(dir, dentry, bindex); ++#if 0 ++ xino_write0(sb, bstart, hidden_dentry->d_inode->i_ino); ++ /* ignore this error */ ++#endif ++ goto out_unlock; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ rerr = do_revert(err, wh_dentry, dentry, bwh, &dt, dlgt); ++ if (rerr) ++ err = rerr; ++ } ++ ++ out_unlock: ++ hdir_unlock(hidden_dir, dir, bindex); ++ dput(wh_dentry); ++ dput(hidden_dentry); ++ out: ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ struct inode *inode, *hidden_dir; ++ struct dentry *parent, *wh_dentry, *hidden_dentry, *hidden_parent; ++ struct dtime dt; ++ aufs_bindex_t bwh, bindex, bstart; ++ struct rmdir_whtmp_arg *arg; ++ struct aufs_nhash *whlist; ++ struct super_block *sb; ++ ++ LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry)); ++ IMustLock(dir); ++ inode = dentry->d_inode; ++ if (unlikely(!inode)) ++ return -ENOENT; // possible? ++ IMustLock(inode); ++ ++ whlist = nhash_new(GFP_KERNEL); ++ err = PTR_ERR(whlist); ++ if (IS_ERR(whlist)) ++ goto out; ++ ++ err = -ENOMEM; ++ arg = kmalloc(sizeof(*arg), GFP_KERNEL); ++ //arg = NULL; ++ if (unlikely(!arg)) ++ goto out_whlist; ++ ++ aufs_read_lock(dentry, AUFS_D_WLOCK); ++ parent = dentry->d_parent; ++ di_write_lock_parent(parent); ++ err = test_empty(dentry, whlist); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_arg; ++ ++ bstart = dbstart(dentry); ++ bwh = dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/ 1, &bindex, &dt); ++ //wh_dentry = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_arg; ++ ++ hidden_dentry = au_h_dptr(dentry); ++ dget(hidden_dentry); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ ++ rmdir_later = 0; ++ if (bindex == bstart) { ++ IMustLock(hidden_dir); ++ err = renwh_and_rmdir(dentry, bstart, whlist, dir); ++ //err = -1; ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ DEBUG_ON(!wh_dentry); ++ hidden_parent = wh_dentry->d_parent; ++ DEBUG_ON(hidden_parent != au_h_dptr_i(parent, bindex)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ err = 0; ++ } ++ ++ sb = dentry->d_sb; ++ if (!err) { ++ //aufs_bindex_t bi, bend; ++ ++ au_reset_hinotify(inode, /*flags*/0); ++ inode->i_nlink = 0; ++ set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ kick_rmdir_whtmp(hidden_dentry, whlist, bstart, dir, ++ inode, arg); ++ arg = NULL; ++ } ++ ++#if 0 ++ bend = dbend(dentry); ++ for (bi = bstart; bi <= bend; bi++) { ++ struct dentry *hd; ++ hd = au_h_dptr_i(dentry, bi); ++ if (hd && hd->d_inode) ++ xino_write0(sb, bi, hd->d_inode->i_ino); ++ /* ignore this error */ ++ } ++#endif ++ ++ goto out_unlock; /* success */ ++ } ++ ++ /* revert */ ++ LKTRLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ rerr = do_revert(err, wh_dentry, dentry, bwh, &dt, ++ need_dlgt(sb)); ++ if (rerr) ++ err = rerr; ++ } ++ ++ out_unlock: ++ hdir_unlock(hidden_dir, dir, bindex); ++ dput(wh_dentry); ++ dput(hidden_dentry); ++ out_arg: ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AUFS_D_WLOCK); ++ kfree(arg); ++ out_whlist: ++ nhash_del(whlist); ++ out: ++ TraceErr(err); ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/i_op_ren.c linux-2.6.22.1/fs/aufs/i_op_ren.c +--- linux-2.6.22.1.oorig/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/i_op_ren.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,637 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: i_op_ren.c,v 1.39 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++//#include ++//#include ++#include "aufs.h" ++ ++enum {SRC, DST}; ++struct rename_args { ++ struct dentry *hidden_dentry[2], *parent[2], *hidden_parent[2]; ++ struct aufs_nhash whlist; ++ aufs_bindex_t btgt, bstart[2]; ++ struct super_block *sb; ++ ++ unsigned int isdir:1; ++ unsigned int issamedir:1; ++ unsigned int whsrc:1; ++ unsigned int whdst:1; ++ unsigned int dlgt:1; ++} __attribute__((aligned(sizeof(long)))); ++ ++static int do_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, ++ struct rename_args *a) ++{ ++ int err, need_diropq, bycpup, rerr; ++ struct rmdir_whtmp_arg *tharg; ++ struct dentry *wh_dentry[2], *hidden_dst, *hg_parent; ++ struct inode *hidden_dir[2]; ++ aufs_bindex_t bindex, bend; ++ unsigned int flags; ++ struct lkup_args lkup = {.dlgt = a->dlgt}; ++ ++ LKTRTrace("%.*s/%.*s, %.*s/%.*s, " ++ "hd{%p, %p}, hp{%p, %p}, wh %p, btgt %d, bstart{%d, %d}, " ++ "flags{%d, %d, %d, %d}\n", ++ DLNPair(a->parent[SRC]), DLNPair(src_dentry), ++ DLNPair(a->parent[DST]), DLNPair(dentry), ++ a->hidden_dentry[SRC], a->hidden_dentry[DST], ++ a->hidden_parent[SRC], a->hidden_parent[DST], ++ &a->whlist, a->btgt, ++ a->bstart[SRC], a->bstart[DST], ++ a->isdir, a->issamedir, a->whsrc, a->whdst); ++ hidden_dir[SRC] = a->hidden_parent[SRC]->d_inode; ++ hidden_dir[DST] = a->hidden_parent[DST]->d_inode; ++ IMustLock(hidden_dir[SRC]); ++ IMustLock(hidden_dir[DST]); ++ ++ /* prepare workqueue arg */ ++ hidden_dst = NULL; ++ tharg = NULL; ++ if (a->isdir && a->hidden_dentry[DST]->d_inode) { ++ err = -ENOMEM; ++ tharg = kmalloc(sizeof(*tharg), GFP_KERNEL); ++ //tharg = NULL; ++ if (unlikely(!tharg)) ++ goto out; ++ hidden_dst = dget(a->hidden_dentry[DST]); ++ } ++ ++ wh_dentry[SRC] = wh_dentry[DST] = NULL; ++ lkup.nfsmnt = au_nfsmnt(a->sb, a->btgt); ++ /* create whiteout for src_dentry */ ++ if (a->whsrc) { ++ wh_dentry[SRC] = simple_create_wh(src_dentry, a->btgt, ++ a->hidden_parent[SRC], &lkup); ++ //wh_dentry[SRC] = ERR_PTR(-1); ++ err = PTR_ERR(wh_dentry[SRC]); ++ if (IS_ERR(wh_dentry[SRC])) ++ goto out_tharg; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (a->whdst) { ++ struct dentry *d; ++ d = lkup_wh(a->hidden_parent[DST], &dentry->d_name, &lkup); ++ //d = ERR_PTR(-1); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out_whsrc; ++ if (!d->d_inode) ++ dput(d); ++ else ++ wh_dentry[DST] = d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (tharg) { ++ err = rename_whtmp(dentry, a->btgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_whdst; ++ set_h_dptr(dentry, a->btgt, NULL); ++ err = lkup_neg(dentry, a->btgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->hidden_dentry[DST] = au_h_dptr_i(dentry, a->btgt); ++ } ++ ++ /* cpup src */ ++ if (a->hidden_dentry[DST]->d_inode && a->bstart[SRC] != a->btgt) { ++ flags = au_flags_cpup(!CPUP_DTIME, a->parent[SRC]); ++ hg_parent = a->hidden_parent[SRC]->d_parent; ++ if (!(flags & CPUP_LOCKED_GHDIR) ++ && hg_parent == a->hidden_parent[DST]) ++ flags |= CPUP_LOCKED_GHDIR; ++ ++ hi_lock_child(a->hidden_dentry[SRC]->d_inode); ++ err = sio_cpup_simple(src_dentry, a->btgt, -1, flags); ++ //err = -1; // untested dir ++ i_unlock(a->hidden_dentry[SRC]->d_inode); ++ if (unlikely(err)) ++ goto out_whtmp; ++ } ++ ++#if 0 ++ /* clear the target ino in xino */ ++ LKTRTrace("dir %d, dst inode %p\n", a->isdir, a->hidden_dentry[DST]->d_inode); ++ if (a->isdir && a->hidden_dentry[DST]->d_inode) { ++ Dbg("here\n"); ++ err = xino_write(a->sb, a->btgt, ++ a->hidden_dentry[DST]->d_inode->i_ino, 0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ } ++#endif ++ ++ /* rename by vfs_rename or cpup */ ++ need_diropq = a->isdir ++ && (wh_dentry[DST] ++ || dbdiropq(dentry) == a->btgt ++ || au_flag_test(a->sb, AuFlag_ALWAYS_DIROPQ)); ++ bycpup = 0; ++ if (dbstart(src_dentry) == a->btgt) { ++ if (need_diropq && dbdiropq(src_dentry) == a->btgt) ++ need_diropq = 0; ++ err = vfsub_rename(hidden_dir[SRC], au_h_dptr(src_dentry), ++ hidden_dir[DST], a->hidden_dentry[DST], ++ a->dlgt); ++ //err = -1; ++ } else { ++ bycpup = 1; ++ flags = au_flags_cpup(!CPUP_DTIME, a->parent[DST]); ++ hg_parent = a->hidden_parent[DST]->d_parent; ++ if (!(flags & CPUP_LOCKED_GHDIR) ++ && hg_parent == a->hidden_parent[SRC]) ++ flags |= CPUP_LOCKED_GHDIR; ++ ++ hi_lock_child(a->hidden_dentry[SRC]->d_inode); ++ set_dbstart(src_dentry, a->btgt); ++ set_h_dptr(src_dentry, a->btgt, dget(a->hidden_dentry[DST])); ++ //DbgDentry(src_dentry); ++ //DbgInode(src_dentry->d_inode); ++ err = sio_cpup_single(src_dentry, a->btgt, a->bstart[SRC], -1, ++ flags); ++ //err = -1; // untested dir ++ if (unlikely(err)) { ++ set_h_dptr(src_dentry, a->btgt, NULL); ++ set_dbstart(src_dentry, a->bstart[SRC]); ++ } ++ i_unlock(a->hidden_dentry[SRC]->d_inode); ++ } ++ if (unlikely(err)) ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ if (need_diropq) { ++ struct dentry *diropq; ++ struct inode *h_inode; ++ ++ h_inode = au_h_dptr_i(src_dentry, a->btgt)->d_inode; ++ hdir_lock(h_inode, src_dentry->d_inode, a->btgt); ++ diropq = create_diropq(src_dentry, a->btgt, a->dlgt); ++ //diropq = ERR_PTR(-1); ++ hdir_unlock(h_inode, src_dentry->d_inode, a->btgt); ++ err = PTR_ERR(diropq); ++ if (IS_ERR(diropq)) ++ goto out_rename; ++ dput(diropq); ++ } ++ ++ /* remove whiteout for dentry */ ++ if (wh_dentry[DST]) { ++ err = au_unlink_wh_dentry(hidden_dir[DST], wh_dentry[DST], ++ dentry, a->dlgt); ++ //err = -1; ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (tharg) { ++ if (au_is_nfs(hidden_dst->d_sb) ++ || !is_longer_wh(&a->whlist, a->btgt, ++ stosi(a->sb)->si_dirwh)) { ++ err = rmdir_whtmp(hidden_dst, &a->whlist, a->btgt, dir, ++ dentry->d_inode); ++ if (unlikely(err)) ++ Warn("failed removing whtmp dir %.*s (%d), " ++ "ignored.\n", DLNPair(hidden_dst), err); ++ } else { ++ kick_rmdir_whtmp(hidden_dst, &a->whlist, a->btgt, dir, ++ dentry->d_inode, tharg); ++ dput(hidden_dst); ++ tharg = NULL; ++ } ++ } ++ err = 0; ++ goto out_success; ++ ++#define RevertFailure(fmt, args...) do { \ ++ IOErrWhck("revert failure: " fmt " (%d, %d)\n", \ ++ ##args, err, rerr); \ ++ err = -EIO; \ ++ } while(0) ++ ++ out_diropq: ++ if (need_diropq) { ++ struct inode *h_inode; ++ ++ h_inode = au_h_dptr_i(src_dentry, a->btgt)->d_inode; ++ // i_lock simplly since inotify is not set to h_inode. ++ hi_lock_parent(h_inode); ++ //hdir_lock(h_inode, src_dentry->d_inode, a->btgt); ++ rerr = remove_diropq(src_dentry, a->btgt, a->dlgt); ++ //rerr = -1; ++ //hdir_unlock(h_inode, src_dentry->d_inode, a->btgt); ++ i_unlock(h_inode); ++ if (rerr) ++ RevertFailure("remove diropq %.*s", ++ DLNPair(src_dentry)); ++ } ++ out_rename: ++ if (!bycpup) { ++ struct dentry *d; ++ struct qstr *name = &src_dentry->d_name; ++ d = lkup_one(name->name, a->hidden_parent[SRC], name->len, ++ &lkup); ++ //d = ERR_PTR(-1); ++ rerr = PTR_ERR(d); ++ if (IS_ERR(d)) { ++ RevertFailure("lkup_one %.*s", DLNPair(src_dentry)); ++ goto out_whtmp; ++ } ++ DEBUG_ON(d->d_inode); ++ rerr = vfsub_rename ++ (hidden_dir[DST], au_h_dptr_i(src_dentry, a->btgt), ++ hidden_dir[SRC], d, a->dlgt); ++ //rerr = -1; ++ d_drop(d); ++ dput(d); ++ //set_h_dptr(src_dentry, a->btgt, NULL); ++ if (rerr) ++ RevertFailure("rename %.*s", DLNPair(src_dentry)); ++ } else { ++ rerr = vfsub_unlink(hidden_dir[DST], a->hidden_dentry[DST], ++ a->dlgt); ++ //rerr = -1; ++ set_h_dptr(src_dentry, a->btgt, NULL); ++ set_dbstart(src_dentry, a->bstart[SRC]); ++ if (rerr) ++ RevertFailure("unlink %.*s", ++ DLNPair(a->hidden_dentry[DST])); ++ } ++ out_whtmp: ++ if (tharg) { ++ struct dentry *d; ++ struct qstr *name = &dentry->d_name; ++ LKTRLabel(here); ++ d = lkup_one(name->name, a->hidden_parent[DST], name->len, ++ &lkup); ++ //d = ERR_PTR(-1); ++ rerr = PTR_ERR(d); ++ if (IS_ERR(d)) { ++ RevertFailure("lookup %.*s", LNPair(name)); ++ goto out_whdst; ++ } ++ if (d->d_inode) { ++ d_drop(d); ++ dput(d); ++ goto out_whdst; ++ } ++ DEBUG_ON(d->d_inode); ++ rerr = vfsub_rename(hidden_dir[DST], hidden_dst, ++ hidden_dir[DST], d, a->dlgt); ++ //rerr = -1; ++ d_drop(d); ++ dput(d); ++ if (rerr) { ++ RevertFailure("rename %.*s", DLNPair(hidden_dst)); ++ goto out_whdst; ++ } ++ set_h_dptr(dentry, a->btgt, NULL); ++ set_h_dptr(dentry, a->btgt, dget(hidden_dst)); ++ } ++ out_whdst: ++ dput(wh_dentry[DST]); ++ wh_dentry[DST] = NULL; ++ out_whsrc: ++ if (wh_dentry[SRC]) { ++ LKTRLabel(here); ++ rerr = au_unlink_wh_dentry(hidden_dir[SRC], wh_dentry[SRC], ++ src_dentry, a->dlgt); ++ //rerr = -1; ++ if (rerr) ++ RevertFailure("unlink %.*s", DLNPair(wh_dentry[SRC])); ++ } ++#undef RevertFailure ++ d_drop(src_dentry); ++ bend = dbend(src_dentry); ++ for (bindex = dbstart(src_dentry); bindex <= bend; bindex++) { ++ struct dentry *hd; ++ hd = au_h_dptr_i(src_dentry, bindex); ++ if (hd) ++ d_drop(hd); ++ } ++ d_drop(dentry); ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); bindex <= bend; bindex++) { ++ struct dentry *hd; ++ hd = au_h_dptr_i(dentry, bindex); ++ if (hd) ++ d_drop(hd); ++ } ++ au_update_dbstart(dentry); ++ if (tharg) ++ d_drop(hidden_dst); ++ out_success: ++ dput(wh_dentry[SRC]); ++ dput(wh_dentry[DST]); ++ out_tharg: ++ if (tharg) { ++ dput(hidden_dst); ++ kfree(tharg); ++ } ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, aufs_bindex_t btgt, ++ struct aufs_nhash *whlist) ++{ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ ++ return test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @dentry dir can be rename source or not. ++ * if it can, return 0 and @children is filled. ++ * success means, ++ * - or, it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch. ++ */ ++static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ ++ bstart = dbstart(dentry); ++ if (bstart != btgt) { ++ struct aufs_nhash *whlist; ++ ++ whlist = nhash_new(GFP_KERNEL); ++ err = PTR_ERR(whlist); ++ if (IS_ERR(whlist)) ++ goto out; ++ err = test_empty(dentry, whlist); ++ nhash_del(whlist); ++ goto out; ++ } ++ ++ if (bstart == dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++ out: ++ if (/* unlikely */(err == -ENOTEMPTY)) ++ err = -EXDEV; ++ TraceErr(err); ++ return err; ++} ++ ++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry) ++{ ++ int err, do_dt_dstdir; ++ aufs_bindex_t bend, bindex; ++ struct inode *inode, *dirs[2]; ++ enum {PARENT, CHILD}; ++ /* reduce stack space */ ++ struct { ++ struct rename_args a; ++ struct dtime dt[2][2]; ++ } *p; ++ ++ LKTRTrace("i%lu, %.*s, i%lu, %.*s\n", ++ src_dir->i_ino, DLNPair(src_dentry), ++ dir->i_ino, DLNPair(dentry)); ++ IMustLock(src_dir); ++ IMustLock(dir); ++ /* braces are added to stop a warning */ ++ if (dentry->d_inode) { ++ IMustLock(dentry->d_inode); ++ } ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*p) > PAGE_SIZE); ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -ENOTDIR; ++ p->a.sb = src_dentry->d_sb; ++ inode = src_dentry->d_inode; ++ p->a.isdir = !!S_ISDIR(inode->i_mode); ++ if (unlikely(p->a.isdir && dentry->d_inode ++ && !S_ISDIR(dentry->d_inode->i_mode))) ++ goto out_free; ++ ++ aufs_read_and_write_lock2(dentry, src_dentry, p->a.isdir); ++ p->a.dlgt = !!need_dlgt(p->a.sb); ++ p->a.parent[SRC] = p->a.parent[DST] = dentry->d_parent; ++ p->a.issamedir = (src_dir == dir); ++ if (p->a.issamedir) ++ di_write_lock_parent(p->a.parent[DST]); ++ else { ++ p->a.parent[SRC] = src_dentry->d_parent; ++ di_write_lock2_parent(p->a.parent[SRC], p->a.parent[DST], ++ /*isdir*/1); ++ } ++ ++ /* which branch we process */ ++ p->a.bstart[DST] = dbstart(dentry); ++ p->a.btgt = err = wr_dir(dentry, 1, src_dentry, /*force_btgt*/-1, ++ /*do_lock_srcdir*/0); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ /* are they available to be renamed */ ++ err = 0; ++ nhash_init(&p->a.whlist); ++ if (p->a.isdir && dentry->d_inode) { ++ set_dbstart(dentry, p->a.bstart[DST]); ++ err = may_rename_dstdir(dentry, p->a.btgt, &p->a.whlist); ++ set_dbstart(dentry, p->a.btgt); ++ } ++ p->a.hidden_dentry[DST] = au_h_dptr(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ //todo: minor optimize, their sb may be same while their bindex differs. ++ p->a.bstart[SRC] = dbstart(src_dentry); ++ p->a.hidden_dentry[SRC] = au_h_dptr(src_dentry); ++ if (p->a.isdir) { ++ err = may_rename_srcdir(src_dentry, p->a.btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ /* prepare the writable parent dir on the same branch */ ++ err = wr_dir_need_wh(src_dentry, p->a.isdir, &p->a.btgt, ++ p->a.issamedir ? NULL : p->a.parent[DST]); ++ if (unlikely(err < 0)) ++ goto out_children; ++ p->a.whsrc = !!err; ++ p->a.whdst = (p->a.bstart[DST] == p->a.btgt); ++ if (!p->a.whdst) { ++ err = cpup_dirs(dentry, p->a.btgt, ++ p->a.issamedir ? NULL : p->a.parent[SRC]); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ p->a.hidden_parent[SRC] = au_h_dptr_i(p->a.parent[SRC], p->a.btgt); ++ p->a.hidden_parent[DST] = au_h_dptr_i(p->a.parent[DST], p->a.btgt); ++ dirs[0] = src_dir; ++ dirs[1] = dir; ++ hdir_lock_rename(p->a.hidden_parent, dirs, p->a.btgt, p->a.issamedir); ++ ++ /* store timestamps to be revertible */ ++ dtime_store(p->dt[PARENT] + SRC, p->a.parent[SRC], ++ p->a.hidden_parent[SRC]); ++ if (!p->a.issamedir) ++ dtime_store(p->dt[PARENT] + DST, p->a.parent[DST], ++ p->a.hidden_parent[DST]); ++ do_dt_dstdir = 0; ++ if (p->a.isdir) { ++ dtime_store(p->dt[CHILD] + SRC, src_dentry, ++ p->a.hidden_dentry[SRC]); ++ if (p->a.hidden_dentry[DST]->d_inode) { ++ do_dt_dstdir = 1; ++ dtime_store(p->dt[CHILD] + DST, dentry, ++ p->a.hidden_dentry[DST]); ++ } ++ } ++ ++ err = do_rename(src_dir, src_dentry, dir, dentry, &p->a); ++ if (unlikely(err)) ++ goto out_dt; ++ hdir_unlock_rename(p->a.hidden_parent, dirs, p->a.btgt, p->a.issamedir); ++ ++ /* update dir attributes */ ++ dir->i_version++; ++ if (p->a.isdir) ++ au_cpup_attr_nlink(dir); ++ if (ibstart(dir) == p->a.btgt) ++ au_cpup_attr_timesizes(dir); ++ ++ if (!p->a.issamedir) { ++ src_dir->i_version++; ++ if (p->a.isdir) ++ au_cpup_attr_nlink(src_dir); ++ if (ibstart(src_dir) == p->a.btgt) ++ au_cpup_attr_timesizes(src_dir); ++ } ++ ++ // is this updating defined in POSIX? ++ if (unlikely(p->a.isdir)) { ++ //i_lock(inode); ++ au_cpup_attr_timesizes(inode); ++ //i_unlock(inode); ++ } ++ ++#if 0 ++ d_drop(src_dentry); ++#else ++ /* dput/iput all lower dentries */ ++ set_dbwh(src_dentry, -1); ++ bend = dbend(src_dentry); ++ for (bindex = p->a.btgt + 1; bindex <= bend; bindex++) { ++ struct dentry *hd; ++ hd = au_h_dptr_i(src_dentry, bindex); ++ if (hd) ++ set_h_dptr(src_dentry, bindex, NULL); ++ } ++ set_dbend(src_dentry, p->a.btgt); ++ ++ bend = ibend(inode); ++ for (bindex = p->a.btgt + 1; bindex <= bend; bindex++) { ++ struct inode *hi; ++ hi = au_h_iptr_i(inode, bindex); ++ if (hi) ++ set_h_iptr(inode, bindex, NULL, 0); ++ } ++ set_ibend(inode, p->a.btgt); ++#endif ++ ++#if 0 ++ //au_debug_on(); ++ //DbgDentry(dentry); ++ //DbgInode(dentry->d_inode); ++ //au_debug_off(); ++ inode = dentry->d_inode; ++ if (inode) { ++ aufs_bindex_t bindex, bend; ++ struct dentry *hd; ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); bindex <= bend; bindex++) { ++ hd = au_h_dptr_i(dentry, bindex); ++ if (hd && hd->d_inode) ++ xino_write0(p->a.sb, bindex, hd->d_inode->i_ino); ++ /* ignore this error */ ++ } ++ } ++#endif ++ ++ goto out_children; /* success */ ++ ++ out_dt: ++ dtime_revert(p->dt[PARENT] + SRC, ++ p->a.hidden_parent[SRC]->d_parent ++ == p->a.hidden_parent[DST]); ++ if (!p->a.issamedir) ++ dtime_revert(p->dt[PARENT] + DST, ++ p->a.hidden_parent[DST]->d_parent ++ == p->a.hidden_parent[SRC]); ++ if (p->a.isdir && err != -EIO) { ++ struct dentry *hd; ++ ++ hd = p->dt[CHILD][SRC].dt_h_dentry; ++ hi_lock_child(hd->d_inode); ++ dtime_revert(p->dt[CHILD] + SRC, 1); ++ i_unlock(hd->d_inode); ++ if (do_dt_dstdir) { ++ hd = p->dt[CHILD][DST].dt_h_dentry; ++ hi_lock_child(hd->d_inode); ++ dtime_revert(p->dt[CHILD] + DST, 1); ++ i_unlock(hd->d_inode); ++ } ++ } ++ hdir_unlock_rename(p->a.hidden_parent, dirs, p->a.btgt, p->a.issamedir); ++ out_children: ++ nhash_fin(&p->a.whlist); ++ out_unlock: ++ //if (unlikely(err /* && p->a.isdir */)) { ++ if (unlikely(err && p->a.isdir)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ if (p->a.issamedir) ++ di_write_unlock(p->a.parent[DST]); ++ else ++ di_write_unlock2(p->a.parent[SRC], p->a.parent[DST]); ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++ out_free: ++ kfree(p); ++ out: ++ TraceErr(err); ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/iinfo.c linux-2.6.22.1/fs/aufs/iinfo.c +--- linux-2.6.22.1.oorig/fs/aufs/iinfo.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/iinfo.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,286 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: iinfo.c,v 1.31 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++//#include ++#include "aufs.h" ++ ++struct aufs_iinfo *itoii(struct inode *inode) ++{ ++ struct aufs_iinfo *iinfo; ++ ++ iinfo = &(container_of(inode, struct aufs_icntnr, vfs_inode)->iinfo); ++ /* bad_inode case */ ++ if (unlikely(!iinfo->ii_hinode)) ++ return NULL; ++ DEBUG_ON(!iinfo->ii_hinode ++ /* || stosi(inode->i_sb)->si_bend < iinfo->ii_bend */ ++ || iinfo->ii_bend < iinfo->ii_bstart); ++ return iinfo; ++} ++ ++aufs_bindex_t ibstart(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return itoii(inode)->ii_bstart; ++} ++ ++aufs_bindex_t ibend(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return itoii(inode)->ii_bend; ++} ++ ++struct aufs_vdir *ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ DEBUG_ON(!S_ISDIR(inode->i_mode)); ++ return itoii(inode)->ii_vdir; ++} ++ ++struct inode *au_h_iptr_i(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *hidden_inode; ++ ++ IiMustAnyLock(inode); ++ DEBUG_ON(bindex < 0 || ibend(inode) < bindex); ++ hidden_inode = itoii(inode)->ii_hinode[0 + bindex].hi_inode; ++ DEBUG_ON(hidden_inode && atomic_read(&hidden_inode->i_count) <= 0); ++ return hidden_inode; ++} ++ ++struct inode *au_h_iptr(struct inode *inode) ++{ ++ return au_h_iptr_i(inode, ibstart(inode)); ++} ++ ++aufs_bindex_t itoid_index(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ DEBUG_ON(bindex < 0 ++ || ibend(inode) < bindex ++ || !itoii(inode)->ii_hinode[0 + bindex].hi_inode); ++ return itoii(inode)->ii_hinode[0 + bindex].hi_id; ++} ++ ++// hard/soft set ++void set_ibstart(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct aufs_iinfo *iinfo = itoii(inode); ++ struct inode *h_inode; ++ ++ IiMustWriteLock(inode); ++ DEBUG_ON(sbend(inode->i_sb) < bindex); ++ iinfo->ii_bstart = bindex; ++ h_inode = iinfo->ii_hinode[bindex + 0].hi_inode; ++ if (h_inode) ++ au_cpup_igen(inode, h_inode); ++} ++ ++void set_ibend(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ DEBUG_ON(sbend(inode->i_sb) < bindex ++ || bindex < ibstart(inode)); ++ itoii(inode)->ii_bend = bindex; ++} ++ ++void set_ivdir(struct inode *inode, struct aufs_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ DEBUG_ON(!S_ISDIR(inode->i_mode) ++ || (itoii(inode)->ii_vdir && vdir)); ++ itoii(inode)->ii_vdir = vdir; ++} ++ ++void aufs_hiput(struct aufs_hinode *hinode) ++{ ++ if (unlikely(hinode->hi_notify)) ++ do_free_hinotify(hinode); ++ if (hinode->hi_inode) ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ struct super_block *sb = inode->i_sb; ++ ++ flags = 0; ++ if (au_flag_test(sb, AuFlag_XINO)) ++ flags = AUFS_HI_XINO; ++ if (unlikely(isdir && au_flag_test(sb, AuFlag_UDBA_INOTIFY))) ++ flags |= AUFS_HI_NOTIFY; ++ return flags; ++} ++ ++void set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct aufs_hinode *hinode; ++ struct inode *hi; ++ struct aufs_iinfo *iinfo = itoii(inode); ++ ++ LKTRTrace("i%lu, b%d, hi%lu, flags 0x%x\n", ++ inode->i_ino, bindex, h_inode ? h_inode->i_ino : 0, flags); ++ IiMustWriteLock(inode); ++ hinode = iinfo->ii_hinode + bindex; ++ hi = hinode->hi_inode; ++ DEBUG_ON(bindex < ibstart(inode) || ibend(inode) < bindex ++ || (h_inode && atomic_read(&h_inode->i_count) <= 0) ++ || (h_inode && hi)); ++ ++ if (hi) ++ aufs_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ ++ if (bindex == iinfo->ii_bstart) ++ au_cpup_igen(inode, h_inode); ++ hinode->hi_id = sbr_id(sb, bindex); ++ if (flags & AUFS_HI_XINO) { ++ struct xino xino = { ++ .ino = inode->i_ino, ++ //.h_gen = h_inode->i_generation ++ }; ++ //WARN_ON(xino.h_gen == AuXino_INVALID_HGEN); ++ err = xino_write(sb, bindex, h_inode->i_ino, &xino); ++ if (unlikely(err)) { ++ IOErr1("failed xino_write() %d, force noxino\n", ++ err); ++ au_flag_clr(sb, AuFlag_XINO); ++ } ++ } ++ if (flags & AUFS_HI_NOTIFY) { ++ err = alloc_hinotify(hinode, inode, h_inode); ++ if (unlikely(err)) ++ IOErr1("alloc_hinotify() %d\n", err); ++ else { ++ /* braces are added to stop a warning */ ++ DEBUG_ON(!hinode->hi_notify); ++ } ++ } ++ } ++} ++ ++void au_update_iigen(struct inode *inode) ++{ ++ //IiMustWriteLock(inode); ++ DEBUG_ON(!inode->i_sb); ++ atomic_set(&itoii(inode)->ii_generation, au_sigen(inode->i_sb)); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_brange(struct inode *inode, int do_put_zero) ++{ ++ struct aufs_iinfo *iinfo; ++ ++ LKTRTrace("i%lu, %d\n", inode->i_ino, do_put_zero); ++ IiMustWriteLock(inode); ++ ++ iinfo = itoii(inode); ++ if (unlikely(!iinfo) || iinfo->ii_bstart < 0) ++ return; ++ ++ if (do_put_zero) { ++ aufs_bindex_t bindex; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++) { ++ struct inode *h_i; ++ h_i = iinfo->ii_hinode[0 + bindex].hi_inode; ++ if (h_i && !h_i->i_nlink) ++ set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_bstart = -1; ++ while (++iinfo->ii_bstart <= iinfo->ii_bend) ++ if (iinfo->ii_hinode[0 + iinfo->ii_bstart].hi_inode) ++ break; ++ if (iinfo->ii_bstart > iinfo->ii_bend) { ++ iinfo->ii_bend = iinfo->ii_bstart = -1; ++ return; ++ } ++ ++ iinfo->ii_bend++; ++ while (0 <= --iinfo->ii_bend) ++ if (iinfo->ii_hinode[0 + iinfo->ii_bend].hi_inode) ++ break; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct aufs_iinfo *iinfo; ++ struct super_block *sb; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ DEBUG_ON(!sb); ++ iinfo = &(container_of(inode, struct aufs_icntnr, vfs_inode)->iinfo); ++ DEBUG_ON(iinfo->ii_hinode); ++ nbr = sbend(sb) + 1; ++ if (unlikely(!nbr)) ++ nbr++; ++ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_KERNEL); ++ //iinfo->ii_hinode = NULL; ++ if (iinfo->ii_hinode) { ++ for (i = 0; i < nbr; i++) ++ iinfo->ii_hinode[i].hi_id = -1; ++ atomic_set(&iinfo->ii_generation, au_sigen(sb)); ++ rw_init_nolock(&iinfo->ii_rwsem); ++ iinfo->ii_bstart = -1; ++ iinfo->ii_bend = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct aufs_iinfo *iinfo; ++ ++ iinfo = itoii(inode); ++ /* bad_inode case */ ++ if (unlikely(!iinfo)) ++ return; ++ ++ if (unlikely(iinfo->ii_vdir)) ++ free_vdir(iinfo->ii_vdir); ++ ++ if (iinfo->ii_bstart >= 0) { ++ aufs_bindex_t bend; ++ struct aufs_hinode *hi; ++ hi = iinfo->ii_hinode + iinfo->ii_bstart; ++ bend = iinfo->ii_bend; ++ while (iinfo->ii_bstart++ <= bend) { ++ if (hi->hi_inode) ++ aufs_hiput(hi); ++ hi++; ++ } ++ //iinfo->ii_bstart = iinfo->ii_bend = -1; ++ } ++ ++ kfree(iinfo->ii_hinode); ++ //iinfo->ii_hinode = NULL; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/inode.c linux-2.6.22.1/fs/aufs/inode.c +--- linux-2.6.22.1.oorig/fs/aufs/inode.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/inode.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,339 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: inode.c,v 1.22 2007/05/07 03:44:35 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, new_sz, update, isdir; ++ struct inode *first; ++ struct aufs_hinode *p, *q, tmp; ++ struct super_block *sb; ++ struct aufs_iinfo *iinfo; ++ aufs_bindex_t bindex, bend, new_bindex; ++ unsigned int flags; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ IiMustWriteLock(inode); ++ ++ err = -ENOMEM; ++ sb = dentry->d_sb; ++ bend = sbend(sb); ++ new_sz = sizeof(*iinfo->ii_hinode) * (bend + 1); ++ iinfo = itoii(inode); ++ p = au_kzrealloc(iinfo->ii_hinode, sizeof(*p) * (iinfo->ii_bend + 1), ++ new_sz, GFP_KERNEL); ++ //p = NULL; ++ if (unlikely(!p)) ++ goto out; ++ ++ iinfo->ii_hinode = p; ++ err = 0; ++ update = 0; ++ p = iinfo->ii_hinode + iinfo->ii_bstart; ++ first = p->hi_inode; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++, p++) { ++ if (unlikely(!p->hi_inode)) ++ continue; ++ ++ new_bindex = find_brindex(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ update++; ++ aufs_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = new_bindex; ++ if (iinfo->ii_bend < new_bindex) ++ iinfo->ii_bend = new_bindex; ++ /* swap two hidden inode, and loop again */ ++ q = iinfo->ii_hinode + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ flags = au_hi_flags(inode, isdir); ++ bend = dbend(dentry); ++ for (bindex = dbstart(dentry); bindex <= bend; bindex++) { ++ struct inode *hi; ++ struct dentry *hd; ++ ++ hd = au_h_dptr_i(dentry, bindex); ++ if (!hd || !hd->d_inode) ++ continue; ++ ++ if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { ++ hi = au_h_iptr_i(inode, bindex); ++ if (hi) { ++ if (hi == hd->d_inode) ++ continue; ++ //Dbg("here\n"); ++ err = -ESTALE; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = bindex; ++ if (iinfo->ii_bend < bindex) ++ iinfo->ii_bend = bindex; ++ set_h_iptr(inode, bindex, igrab(hd->d_inode), flags); ++ update++; ++ } ++ ++ bend = iinfo->ii_bend; ++ p = iinfo->ii_hinode; ++ for (bindex = 0; bindex <= bend; bindex++, p++) ++ if (p->hi_inode) { ++ iinfo->ii_bstart = bindex; ++ break; ++ } ++ p = iinfo->ii_hinode + bend; ++ for (bindex = bend; bindex > iinfo->ii_bstart; bindex--, p--) ++ if (p->hi_inode) { ++ iinfo->ii_bend = bindex; ++ break; ++ } ++ DEBUG_ON(iinfo->ii_bstart > bend || iinfo->ii_bend < 0); ++ ++ if (unlikely(err)) ++ goto out; ++ ++ if (1 || first != au_h_iptr(inode)) ++ au_cpup_attr_all(inode); ++ if (update && isdir) ++ inode->i_version++; ++ au_update_iigen(inode); ++ ++ out: ++ //au_debug_on(); ++ TraceErr(err); ++ //au_debug_off(); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, isdir; ++ struct dentry *hidden_dentry; ++ struct inode *hidden_inode; ++ umode_t mode; ++ aufs_bindex_t bindex, bstart, btail; ++ struct aufs_iinfo *iinfo; ++ unsigned int flags; ++ ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(dentry)); ++ DEBUG_ON(!(inode->i_state & I_NEW)); ++ IiMustWriteLock(inode); ++ hidden_dentry = au_h_dptr(dentry); ++ DEBUG_ON(!hidden_dentry); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_inode); ++ ++ err = 0; ++ isdir = 0; ++ bstart = dbstart(dentry); ++ mode = hidden_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = dbtail(dentry); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = dbtaildir(dentry); ++ inode->i_op = &aufs_dir_iop; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = dbtail(dentry); ++ inode->i_op = &aufs_symlink_iop; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = dbtail(dentry); ++ init_special_inode(inode, mode, hidden_inode->i_rdev); ++ break; ++ default: ++ IOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ flags = au_hi_flags(inode, isdir); ++ iinfo = itoii(inode); ++ iinfo->ii_bstart = bstart; ++ iinfo->ii_bend = btail; ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!hidden_dentry) ++ continue; ++ DEBUG_ON(!hidden_dentry->d_inode); ++ set_h_iptr(inode, bindex, igrab(hidden_dentry->d_inode), flags); ++ } ++ au_cpup_attr_all(inode); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++//todo: return with unlocked? ++static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched) ++{ ++ int err; ++ struct inode *h_inode, *h_dinode; ++ aufs_bindex_t bindex, bend; ++ //const int udba = !au_flag_test(inode->i_sb, AuFlag_UDBA_NONE); ++ ++ LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(dentry)); ++ ++ *matched = 0; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ h_dinode = au_h_dptr(dentry)->d_inode; ++ hi_lock_child(inode); // bad name, this is not a hidden inode. ++ ii_write_lock_new(inode); ++ bend = ibend(inode); ++ for (bindex = ibstart(inode); bindex <= bend; bindex++) { ++ h_inode = au_h_iptr_i(inode, bindex); ++ if (h_inode && h_inode == h_dinode) { ++ //&& (ibs != bstart || !au_test_higen(inode, h_inode))); ++ *matched = 1; ++ err = 0; ++ if (unlikely(au_iigen(inode) != au_digen(dentry))) ++ err = au_refresh_hinode(inode, dentry); ++ break; ++ } ++ } ++ i_unlock(inode); ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++//todo: return with unlocked? ++struct inode *au_new_inode(struct dentry *dentry) ++{ ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ino_t h_ino; ++ struct super_block *sb; ++ int err, match; ++ aufs_bindex_t bstart; ++ struct xino xino; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ sb = dentry->d_sb; ++ h_dentry = au_h_dptr(dentry); ++ DEBUG_ON(!h_dentry); ++ h_inode = h_dentry->d_inode; ++ DEBUG_ON(!h_inode); ++ ++ bstart = dbstart(dentry); ++ h_ino = h_inode->i_ino; ++ err = xino_read(sb, bstart, h_ino, &xino); ++ //err = -1; ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ new_ino: ++ if (!xino.ino) { ++ xino.ino = xino_new_ino(sb); ++ if (!xino.ino) { ++ inode = ERR_PTR(-EIO); ++ goto out; ++ } ++ } ++ ++ LKTRTrace("i%lu\n", xino.ino); ++ err = -ENOMEM; ++ inode = iget_locked(sb, xino.ino); ++ if (unlikely(!inode)) ++ goto out; ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ err = -ENOMEM; ++ if (unlikely(is_bad_inode(inode))) ++ goto out_iput; ++ ++ LKTRTrace("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ sb->s_op->read_inode(inode); ++ if (!is_bad_inode(inode)) { ++ ii_write_lock_new(inode); ++ err = set_inode(inode, dentry); ++ //err = -1; ++ } ++ unlock_new_inode(inode); ++ if (!err) ++ goto out; /* success */ ++ ii_write_unlock(inode); ++ goto out_iput; ++ } else { ++ err = reval_inode(inode, dentry, &match); ++ if (!err) ++ goto out; /* success */ ++ else if (match) ++ goto out_iput; ++ } ++ ++ Warn1("broken ino, b%d, %.*s/%.*s, hi%lu, i%lu. Try udba=inotify.\n", ++ bstart, DLNPair(dentry->d_parent), DLNPair(dentry), h_ino, ++ xino.ino); ++ xino.ino = 0; ++ err = xino_write0(sb, bstart, h_ino); ++ if (!err) { ++ iput(inode); ++ goto new_ino; ++ } ++ ++ out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++ out: ++ TraceErrPtr(inode); ++ return inode; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/inode.h linux-2.6.22.1/fs/aufs/inode.h +--- linux-2.6.22.1.oorig/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/inode.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,377 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: inode.h,v 1.32 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "misc.h" ++#include "vfsub.h" ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++#else ++struct inotify_watch {}; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_hinotify { ++ struct inotify_watch hin_watch; ++ struct inode *hin_aufs_inode; /* no get/put */ ++}; ++ ++struct aufs_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++ struct aufs_hinotify *hi_notify; ++}; ++ ++struct aufs_vdir; ++struct aufs_iinfo { ++ atomic_t ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct aufs_rwsem ii_rwsem; ++ aufs_bindex_t ii_bstart, ii_bend; ++ struct aufs_hinode *ii_hinode; ++ struct aufs_vdir *ii_vdir; ++}; ++ ++struct aufs_icntnr { ++ struct aufs_iinfo iinfo; ++ struct inode vfs_inode; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++struct inode *au_new_inode(struct dentry *dentry); ++ ++/* i_op.c */ ++extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop; ++int wr_dir(struct dentry *dentry, int negative, struct dentry *src_dentry, ++ aufs_bindex_t force_btgt, int do_lock_srcdir); ++ ++/* i_op_del.c */ ++int wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup, ++ struct dentry *locked); ++ ++/* iinfo.c */ ++struct aufs_iinfo *itoii(struct inode *inode); ++aufs_bindex_t ibstart(struct inode *inode); ++aufs_bindex_t ibend(struct inode *inode); ++struct aufs_vdir *ivdir(struct inode *inode); ++struct inode *au_h_iptr_i(struct inode *inode, aufs_bindex_t bindex); ++struct inode *au_h_iptr(struct inode *inode); ++aufs_bindex_t itoid_index(struct inode *inode, aufs_bindex_t bindex); ++ ++void set_ibstart(struct inode *inode, aufs_bindex_t bindex); ++void set_ibend(struct inode *inode, aufs_bindex_t bindex); ++void set_ivdir(struct inode *inode, struct aufs_vdir *vdir); ++void aufs_hiput(struct aufs_hinode *hinode); ++#define AUFS_HI_XINO 1 ++#define AUFS_HI_NOTIFY 2 ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++void set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++void au_update_iigen(struct inode *inode); ++void au_update_brange(struct inode *inode, int do_put_zero); ++ ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++ ++/* plink.c */ ++#ifdef CONFIG_AUFS_DEBUG ++void au_list_plink(struct super_block *sb); ++#else ++static inline void au_list_plink(struct super_block *sb) ++{ ++ /* nothing */ ++} ++#endif ++int au_is_plinked(struct super_block *sb, struct inode *inode); ++struct dentry *lkup_plink(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++void append_plink(struct super_block *sb, struct inode *inode, ++ struct dentry *h_dentry, aufs_bindex_t bindex); ++void au_put_plink(struct super_block *sb); ++void half_refresh_plink(struct super_block *sb, aufs_bindex_t br_id); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for hidden inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++// todo: reduce it by dcsub. ++enum { ++ AuLsc_Begin = I_MUTEX_QUOTA, ++ AuLsc_HI_GPARENT, /* setattr with inotify */ ++ AuLsc_HI_PARENT, /* hidden inode, parent first */ ++ AuLsc_HI_CHILD, ++ AuLsc_HI_PARENT2, /* copyup dirs */ ++ AuLsc_HI_CHILD2, ++ AuLsc_End ++}; ++ ++/* simple abstraction */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++static inline void i_lock(struct inode *i) ++{ ++ down(&i->i_sem); ++} ++ ++static inline void i_unlock(struct inode *i) ++{ ++ up(&i->i_sem); ++} ++ ++static inline int i_trylock(struct inode *i) ++{ ++ return down_trylock(&i->i_sem); ++} ++ ++static inline void hi_lock(struct inode *i, unsigned int lsc) ++{ ++ i_lock(i); ++} ++ ++#define IMustLock(i) DEBUG_ON(!down_trylock(&(i)->i_sem)) ++#else ++static inline void i_lock(struct inode *i) ++{ ++ mutex_lock(&i->i_mutex); ++} ++ ++static inline void i_unlock(struct inode *i) ++{ ++ mutex_unlock(&i->i_mutex); ++} ++ ++static inline int i_trylock(struct inode *i) ++{ ++ return mutex_trylock(&i->i_mutex); ++} ++ ++static inline void hi_lock(struct inode *i, unsigned int lsc) ++{ ++ mutex_lock_nested(&i->i_mutex, lsc); ++} ++ ++#define IMustLock(i) MtxMustLock(&(i)->i_mutex) ++#endif ++ ++/* ++ * hi_lock_gparent, hi_lock_parent, hi_lock_parent2, hi_lock_child, ++ * hi_lock_child2, hi_lock_whplink ++ */ ++#define LockFunc(name, lsc) \ ++static inline void hi_lock_##name(struct inode *h_i) \ ++{hi_lock(h_i, AuLsc_HI_##lsc);} ++ ++LockFunc(gparent, GPARENT); ++LockFunc(parent, PARENT); ++LockFunc(parent2, PARENT2); ++LockFunc(child, CHILD); ++LockFunc(child2, CHILD2); ++LockFunc(whplink, CHILD2); /* sharing lock-subclass */ ++ ++#undef LockFunc ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ //IiMustAnyLock(inode); ++ return !(itoii(inode)->ii_hsb1 == h_inode->i_sb ++ && inode->i_generation == h_inode->i_generation); ++} ++ ++static inline int au_iigen(struct inode *inode) ++{ ++ return atomic_read(&itoii(inode)->ii_generation); ++} ++ ++#ifdef CONFIG_AUFS_HINOTIFY ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ //Dbg("i%lu\n", inode->i_ino); ++ atomic_dec(&itoii(inode)->ii_generation); ++} ++ ++/* hinotify.c */ ++int alloc_hinotify(struct aufs_hinode *hinode, struct inode *inode, ++ struct inode *h_inode); ++void do_free_hinotify(struct aufs_hinode *hinode); ++void do_hdir_lock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex, ++ unsigned int lsc); ++void hdir_unlock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex); ++void hdir_lock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir); ++void hdir_unlock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir); ++void au_reset_hinotify(struct inode *inode, unsigned int flags); ++int __init au_inotify_init(void); ++void au_inotify_fin(void); ++#else ++static inline ++int alloc_hinotify(struct aufs_hinode *hinode, struct inode *inode, ++ struct inode *h_inode) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline void do_free_hinotify(struct aufs_hinode *hinode) ++{ ++ /* nothing */ ++} ++ ++static inline ++void do_hdir_lock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex, ++ unsigned int lsc) ++{ ++ hi_lock(h_dir, lsc); ++} ++ ++static inline ++void hdir_unlock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex) ++{ ++ i_unlock(h_dir); ++} ++ ++static inline ++void hdir_lock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir) ++{ ++ vfsub_lock_rename(h_parents[0], h_parents[1]); ++} ++ ++static inline ++void hdir_unlock_rename(struct dentry **h_parents, struct inode **dirs, ++ aufs_bindex_t bindex, int issamedir) ++{ ++ vfsub_unlock_rename(h_parents[0], h_parents[1]); ++} ++ ++static inline void au_reset_hinotify(struct inode *inode, unsigned int flags) ++{ ++ /* nothing */ ++} ++ ++#define au_inotify_init() 0 ++#define au_inotify_fin() /* */ ++#endif /* CONFIG_AUFS_HINOTIFY */ ++ ++static inline void free_hinotify(struct inode *inode, aufs_bindex_t bindex) ++{ ++ do_free_hinotify(itoii(inode)->ii_hinode + bindex); ++} ++ ++/* ++ * hgdir_lock, hdir_lock, hdir2_lock ++ */ ++#define LockFunc(name, lsc) \ ++static inline \ ++void name##_lock(struct inode *h_dir, struct inode *dir, aufs_bindex_t bindex) \ ++{do_hdir_lock(h_dir, dir, bindex, AuLsc_HI_##lsc);} ++ ++LockFunc(hgdir, GPARENT); ++LockFunc(hdir, PARENT); ++LockFunc(hdir2, PARENT2); ++ ++#undef LockFunc ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hinotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, ++ AuLsc_II_NEW /* new inode */ ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new, ii_write_lock_new ++ */ ++#define ReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{rw_read_lock_nested(&itoii(i)->ii_rwsem, AuLsc_II_##lsc);} ++ ++#define WriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{rw_write_lock_nested(&itoii(i)->ii_rwsem, AuLsc_II_##lsc);} ++ ++#define RWLockFuncs(name, lsc) \ ++ ReadLockFunc(name, lsc); \ ++ WriteLockFunc(name, lsc) ++ ++RWLockFuncs(child, CHILD); ++RWLockFuncs(child2, CHILD2); ++RWLockFuncs(child3, CHILD3); ++RWLockFuncs(parent, PARENT); ++RWLockFuncs(parent2, PARENT2); ++RWLockFuncs(parent3, PARENT3); ++RWLockFuncs(new, NEW); ++ ++#undef ReadLockFunc ++#undef WriteLockFunc ++#undef RWLockFunc ++ ++/* ++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock ++ */ ++SimpleUnlockRwsemFuncs(ii, struct inode *i, itoii(i)->ii_rwsem); ++ ++/* to debug easier, do not make them inlined functions */ ++#define IiMustReadLock(i) do { \ ++ SiMustAnyLock((i)->i_sb); \ ++ RwMustReadLock(&itoii(i)->ii_rwsem); \ ++} while (0) ++ ++#define IiMustWriteLock(i) do { \ ++ SiMustAnyLock((i)->i_sb); \ ++ RwMustWriteLock(&itoii(i)->ii_rwsem); \ ++} while (0) ++ ++#define IiMustAnyLock(i) do { \ ++ SiMustAnyLock((i)->i_sb); \ ++ RwMustAnyLock(&itoii(i)->ii_rwsem); \ ++} while (0) ++ ++#define IiMustNoWaiters(i) RwMustNoWaiters(&itoii(i)->ii_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/misc.c linux-2.6.22.1/fs/aufs/misc.c +--- linux-2.6.22.1.oorig/fs/aufs/misc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/misc.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: misc.c,v 1.31 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++//#include ++//#include ++//#include ++//#include ++#include "aufs.h" ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) ++{ ++ void *q; ++ ++ LKTRTrace("p %p, nused %d, sz %d, ksize %d\n", ++ p, nused, new_sz, ksize(p)); ++ DEBUG_ON(new_sz <= 0); ++ if (new_sz <= nused) ++ return p; ++ if (new_sz <= ksize(p)) { ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++ } ++ ++ q = kmalloc(new_sz, gfp); ++ //q = NULL; ++ if (unlikely(!q)) ++ return NULL; ++ memcpy(q, p, nused); ++ memset(q + nused, 0, new_sz - nused); ++ //smp_mb(); ++ kfree(p); ++ return q; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++// todo: make it inline ++struct nameidata *fake_dm(struct nameidata *fake_nd, struct nameidata *nd, ++ struct super_block *sb, aufs_bindex_t bindex) ++{ ++ LKTRTrace("nd %p, b%d\n", nd, bindex); ++ ++ if (!nd) ++ return NULL; ++ ++ fake_nd->dentry = NULL; ++ fake_nd->mnt = NULL; ++ ++#ifndef CONFIG_AUFS_FAKE_DM ++ DiMustAnyLock(nd->dentry); ++ ++ if (bindex <= dbend(nd->dentry)) ++ fake_nd->dentry = au_h_dptr_i(nd->dentry, bindex); ++ if (fake_nd->dentry) { ++ dget(fake_nd->dentry); ++ fake_nd->mnt = sbr_mnt(sb, bindex); ++ DEBUG_ON(!fake_nd->mnt); ++ mntget(fake_nd->mnt); ++ } else ++ fake_nd = ERR_PTR(-ENOENT); ++#endif ++ ++ TraceErrPtr(fake_nd); ++ return fake_nd; ++} ++ ++void fake_dm_release(struct nameidata *fake_nd) ++{ ++#ifndef CONFIG_AUFS_FAKE_DM ++ if (fake_nd) { ++ mntput(fake_nd->mnt); ++ dput(fake_nd->dentry); ++ } ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len, ++ struct super_block *sb, int *sparse) ++{ ++ int err, all_zero, dlgt; ++ unsigned long blksize; ++ char *buf; ++ /* reduce stack space */ ++ struct iattr *ia; ++ ++ LKTRTrace("%.*s, %.*s\n", ++ DLNPair(dst->f_dentry), DLNPair(src->f_dentry)); ++ DEBUG_ON(!(dst->f_mode & FMODE_WRITE)); ++ IMustLock(dst->f_dentry->d_parent->d_inode); ++ ++ err = -ENOMEM; ++ blksize = dst->f_dentry->d_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ LKTRTrace("blksize %lu\n", blksize); ++ buf = kmalloc(blksize, GFP_KERNEL); ++ //buf = NULL; ++ if (unlikely(!buf)) ++ goto out; ++ ia = kmalloc(sizeof(*ia), GFP_KERNEL); ++ if (unlikely(!ia)) ++ goto out_buf; ++ ++ dlgt = need_dlgt(sb); ++ err = all_zero = 0; ++ dst->f_pos = src->f_pos = 0; ++ while (len) { ++ size_t sz, rbytes, wbytes, i; ++ char *p; ++ ++ LKTRTrace("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ /* support LSM and notify */ ++ rbytes = 0; ++ while (!rbytes || err == -EAGAIN || err == -EINTR) ++ err = rbytes = vfsub_read_k(src, buf, sz, &src->f_pos, ++ dlgt); ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) { ++ all_zero = 1; ++ p = buf; ++ for (i = 0; all_zero && i < rbytes; i++) ++ all_zero = !*p++; ++ } ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ /* support LSM and notify */ ++ err = b = vfsub_write_k(dst, p, wbytes, ++ &dst->f_pos, dlgt); ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ } else { ++ loff_t res; ++ LKTRLabel(hole); ++ *sparse = 1; ++ err = res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (unlikely(!err && all_zero)) { ++ struct dentry *h_d = dst->f_dentry; ++ struct inode *h_i = h_d->d_inode; ++ ++ LKTRLabel(last hole); ++ do { ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos, dlgt); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) { ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ hi_lock_child2(h_i); ++ err = vfsub_notify_change(h_d, ia, dlgt); ++ i_unlock(h_i); ++ } ++ } ++ ++ kfree(ia); ++ out_buf: ++ kfree(buf); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int test_ro(struct super_block *sb, aufs_bindex_t bindex, struct inode *inode) ++{ ++ int err; ++ ++ err = br_rdonly(stobr(sb, bindex)); ++ if (!err && inode) { ++ struct inode *hi = au_h_iptr_i(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ return err; ++} ++ ++int au_test_perm(struct inode *hidden_inode, int mask, int dlgt) ++{ ++ if (!current->fsuid) ++ return 0; ++ if (unlikely(au_is_nfs(hidden_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(hidden_inode->i_mode))) ++ mask |= MAY_READ; /* force permission check */ ++ return vfsub_permission(hidden_inode, mask, NULL, dlgt); ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/misc.h linux-2.6.22.1/fs/aufs/misc.h +--- linux-2.6.22.1.oorig/fs/aufs/misc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/misc.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,187 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: misc.h,v 1.25 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_MISC_H__ ++#define __AUFS_MISC_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#define I_MUTEX_QUOTA 0 ++#define lockdep_off() /* */ ++#define lockdep_on() /* */ ++#define mutex_lock_nested(mtx, lsc) mutex_lock(mtx) ++#define down_write_nested(rw, lsc) down_write(rw) ++#define down_read_nested(rw, lsc) down_read(rw) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_rwsem { ++ struct rw_semaphore rwsem; ++#ifdef CONFIG_AUFS_DEBUG ++ atomic_t rcnt; ++#endif ++}; ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DbgRcntInit(rw) atomic_set(&(rw)->rcnt, 0) ++#define DbgRcntInc(rw) atomic_inc(&(rw)->rcnt) ++#define DbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0) ++#else ++#define DbgRcntInit(rw) /* */ ++#define DbgRcntInc(rw) /* */ ++#define DbgRcntDec(rw) /* */ ++#endif ++ ++static inline void rw_init_nolock(struct aufs_rwsem *rw) ++{ ++ DbgRcntInit(rw); ++ init_rwsem(&rw->rwsem); ++} ++ ++static inline void rw_init_wlock(struct aufs_rwsem *rw) ++{ ++ rw_init_nolock(rw); ++ down_write(&rw->rwsem); ++} ++ ++static inline void rw_init_wlock_nested(struct aufs_rwsem *rw, unsigned int lsc) ++{ ++ rw_init_nolock(rw); ++ down_write_nested(&rw->rwsem, lsc); ++} ++ ++static inline void rw_read_lock(struct aufs_rwsem *rw) ++{ ++ down_read(&rw->rwsem); ++ DbgRcntInc(rw); ++} ++ ++static inline void rw_read_lock_nested(struct aufs_rwsem *rw, unsigned int lsc) ++{ ++ down_read_nested(&rw->rwsem, lsc); ++ DbgRcntInc(rw); ++} ++ ++static inline void rw_read_unlock(struct aufs_rwsem *rw) ++{ ++ DbgRcntDec(rw); ++ up_read(&rw->rwsem); ++} ++ ++static inline void rw_dgrade_lock(struct aufs_rwsem *rw) ++{ ++ DbgRcntInc(rw); ++ downgrade_write(&rw->rwsem); ++} ++ ++static inline void rw_write_lock(struct aufs_rwsem *rw) ++{ ++ down_write(&rw->rwsem); ++} ++ ++static inline void rw_write_lock_nested(struct aufs_rwsem *rw, unsigned int lsc) ++{ ++ down_write_nested(&rw->rwsem, lsc); ++} ++ ++static inline void rw_write_unlock(struct aufs_rwsem *rw) ++{ ++ up_write(&rw->rwsem); ++} ++ ++#if 0 // why is not _nested version defined ++static inline int rw_read_trylock(struct aufs_rwsem *rw) ++{ ++ int ret = down_read_trylock(&rw->rwsem); ++ if (ret) ++ DbgRcntInc(rw); ++ return ret; ++} ++ ++static inline int rw_write_trylock(struct aufs_rwsem *rw) ++{ ++ return down_write_trylock(&rw->rwsem); ++} ++#endif ++ ++#undef DbgRcntInit ++#undef DbgRcntInc ++#undef DbgRcntDec ++ ++/* to debug easier, do not make them inlined functions */ ++#define RwMustNoWaiters(rw) DEBUG_ON(!list_empty(&(rw)->rwsem.wait_list)) ++#define RwMustAnyLock(rw) DEBUG_ON(down_write_trylock(&(rw)->rwsem)) ++#ifdef CONFIG_AUFS_DEBUG ++#define RwMustReadLock(rw) do { \ ++ RwMustAnyLock(rw); \ ++ DEBUG_ON(!atomic_read(&(rw)->rcnt)); \ ++} while (0) ++#define RwMustWriteLock(rw) do { \ ++ RwMustAnyLock(rw); \ ++ DEBUG_ON(atomic_read(&(rw)->rcnt)); \ ++} while (0) ++#else ++#define RwMustReadLock(rw) RwMustAnyLock(rw) ++#define RwMustWriteLock(rw) RwMustAnyLock(rw) ++#endif ++ ++#define SimpleLockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_lock(param) {rw_read_lock(&(rwsem));} \ ++static inline void prefix##_write_lock(param) {rw_write_lock(&(rwsem));} ++//static inline void prefix##_read_trylock(param) {rw_read_trylock(&(rwsem));} ++//static inline void prefix##_write_trylock(param) {rw_write_trylock(&(rwsem));} ++//static inline void prefix##_read_trylock_nested(param, lsc) ++//{rw_read_trylock_nested(&(rwsem, lsc));} ++//static inline void prefix##_write_trylock_nestd(param, lsc) ++//{rw_write_trylock_nested(&(rwsem), nested);} ++ ++#define SimpleUnlockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_unlock(param) {rw_read_unlock(&(rwsem));} \ ++static inline void prefix##_write_unlock(param) {rw_write_unlock(&(rwsem));} \ ++static inline void prefix##_downgrade_lock(param) {rw_dgrade_lock(&(rwsem));} ++ ++#define SimpleRwsemFuncs(prefix, param, rwsem) \ ++ SimpleLockRwsemFuncs(prefix, param, rwsem); \ ++ SimpleUnlockRwsemFuncs(prefix, param, rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef ssize_t (*readf_t)(struct file*, char __user*, size_t, loff_t*); ++typedef ssize_t (*writef_t)(struct file*, const char __user*, size_t, loff_t*); ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); ++struct nameidata *fake_dm(struct nameidata *fake_nd, struct nameidata *nd, ++ struct super_block *sb, aufs_bindex_t bindex); ++void fake_dm_release(struct nameidata *fake_nd); ++int au_copy_file(struct file *dst, struct file *src, loff_t len, ++ struct super_block *sb, int *sparse); ++int test_ro(struct super_block *sb, aufs_bindex_t bindex, struct inode *inode); ++int au_test_perm(struct inode *h_inode, int mask, int dlgt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MISC_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/module.c linux-2.6.22.1/fs/aufs/module.c +--- linux-2.6.22.1.oorig/fs/aufs/module.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/module.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,334 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: module.c,v 1.9 2007/04/30 05:46:32 sfjro Exp $ */ ++ ++//#include ++//#include ++#include ++//#include ++//#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *aufs_cachep[AuCache_Last]; ++static int __init create_cache(void) ++{ ++#define Cache(type) kmem_cache_create(#type, sizeof(struct type), 0, \ ++ SLAB_RECLAIM_ACCOUNT, NULL, NULL) ++ ++ if ((aufs_cachep[AuCache_DINFO] = Cache(aufs_dinfo)) ++ && (aufs_cachep[AuCache_ICNTNR] = Cache(aufs_icntnr)) ++ && (aufs_cachep[AuCache_FINFO] = Cache(aufs_finfo)) ++ //&& (aufs_cachep[AuCache_FINFO] = NULL) ++ && (aufs_cachep[AuCache_VDIR] = Cache(aufs_vdir)) ++ && (aufs_cachep[AuCache_DEHSTR] = Cache(aufs_dehstr)) ++ && (aufs_cachep[AuCache_HINOTIFY] = Cache(aufs_hinotify))) ++ return 0; ++ return -ENOMEM; ++ ++#undef Cache ++} ++ ++static void destroy_cache(void) ++{ ++ int i; ++ for (i = 0; i < AuCache_Last; i++) ++ if (aufs_cachep[i]) ++ kmem_cache_destroy(aufs_cachep[i]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++int au_dir_roflags; ++extern struct file_system_type aufs_fs_type; ++ ++#ifdef DbgDlgt ++#include ++#include "dbg_dlgt.c" ++#else ++#define dbg_dlgt_init() 0 ++#define dbg_dlgt_fin() /* */ ++#endif ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Junjiro Okajima"); ++MODULE_DESCRIPTION(AUFS_NAME " -- Another unionfs"); ++MODULE_VERSION(AUFS_VERSION); ++ ++/* it should be 'byte', but param_set_byte() prints by "%c" */ ++short aufs_nwkq = AUFS_NWKQ_DEF; ++MODULE_PARM_DESC(nwkq, "the number of workqueue thread, " AUFS_WKQ_NAME); ++module_param_named(nwkq, aufs_nwkq, short, 0444); ++ ++int sysaufs_brs = 0; ++MODULE_PARM_DESC(brs, "use /fs/aufs/brs"); ++module_param_named(brs, sysaufs_brs, int, 0444); ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ //sbinfo->si_xino is atomic_long_t ++ BUILD_BUG_ON(sizeof(ino_t) != sizeof(long)); ++ ++#ifdef CONFIG_AUFS_DEBUG ++ { ++ struct aufs_destr destr; ++ destr.len = -1; ++ DEBUG_ON(destr.len < NAME_MAX); ++ } ++ ++#ifdef CONFIG_4KSTACKS ++ printk("CONFIG_4KSTACKS is defined.\n"); ++#endif ++#if 0 // verbose debug ++ { ++ union { ++ struct aufs_branch *br; ++ struct aufs_dinfo *di; ++ struct aufs_finfo *fi; ++ struct aufs_iinfo *ii; ++ struct aufs_hinode *hi; ++ struct aufs_sbinfo *si; ++ struct aufs_destr *destr; ++ struct aufs_de *de; ++ struct aufs_wh *wh; ++ struct aufs_vdir *vd; ++ } u; ++ ++ printk("br{" ++ "xino %d, readf %d, writef %d, " ++ "id %d, perm %d, mnt %d, count %d, " ++ "wh_sem %d, wh %d, run %d} %d\n", ++ offsetof(typeof(*u.br), br_xino), ++ offsetof(typeof(*u.br), br_xino_read), ++ offsetof(typeof(*u.br), br_xino_write), ++ offsetof(typeof(*u.br), br_id), ++ offsetof(typeof(*u.br), br_perm), ++ offsetof(typeof(*u.br), br_mnt), ++ offsetof(typeof(*u.br), br_count), ++ offsetof(typeof(*u.br), br_wh_rwsem), ++ offsetof(typeof(*u.br), br_wh), ++ offsetof(typeof(*u.br), br_wh_running), ++ sizeof(*u.br)); ++ printk("di{gen %d, rwsem %d, bstart %d, bend %d, bwh %d, " ++ "bdiropq %d, hdentry %d, reval %d} %d\n", ++ offsetof(typeof(*u.di), di_generation), ++ offsetof(typeof(*u.di), di_rwsem), ++ offsetof(typeof(*u.di), di_bstart), ++ offsetof(typeof(*u.di), di_bend), ++ offsetof(typeof(*u.di), di_bwh), ++ offsetof(typeof(*u.di), di_bdiropq), ++ offsetof(typeof(*u.di), di_hdentry), ++ offsetof(typeof(*u.di), di_reval), ++ sizeof(*u.di)); ++ printk("fi{gen %d, rwsem %d, hfile %d, bstart %d, bend %d, " ++ "h_vm_ops %d, vdir_cach %d} %d\n", ++ offsetof(typeof(*u.fi), fi_generation), ++ offsetof(typeof(*u.fi), fi_rwsem), ++ offsetof(typeof(*u.fi), fi_hfile), ++ offsetof(typeof(*u.fi), fi_bstart), ++ offsetof(typeof(*u.fi), fi_bend), ++ offsetof(typeof(*u.fi), fi_h_vm_ops), ++ offsetof(typeof(*u.fi), fi_vdir_cache), ++ sizeof(*u.fi)); ++ printk("ii{rwsem %d, bstart %d, bend %d, hinode %d, vdir %d} " ++ "%d\n", ++ offsetof(typeof(*u.ii), ii_rwsem), ++ offsetof(typeof(*u.ii), ii_bstart), ++ offsetof(typeof(*u.ii), ii_bend), ++ offsetof(typeof(*u.ii), ii_hinode), ++ offsetof(typeof(*u.ii), ii_vdir), ++ sizeof(*u.ii)); ++ printk("hi{inode %d, id %d, notify %d} %d\n", ++ offsetof(typeof(*u.hi), hi_inode), ++ offsetof(typeof(*u.hi), hi_id), ++ offsetof(typeof(*u.hi), hi_notify), ++ sizeof(*u.hi)); ++ printk("si{rwsem %d, gen %d, " ++ "failed_refresh %d, " ++ "bend %d, last id %d, br %d, " ++ "flags %d, " ++ "xino %d, " ++ "rdcache %d, " ++ "dirwh %d, " ++ "pl_lock %d, pl %d, " ++ "kobj %d} %d\n", ++ offsetof(typeof(*u.si), si_rwsem), ++ offsetof(typeof(*u.si), si_generation), ++ -1,//offsetof(typeof(*u.si), si_failed_refresh_dirs), ++ offsetof(typeof(*u.si), si_bend), ++ offsetof(typeof(*u.si), si_last_br_id), ++ offsetof(typeof(*u.si), si_branch), ++ offsetof(typeof(*u.si), si_flags), ++ offsetof(typeof(*u.si), si_xino), ++ offsetof(typeof(*u.si), si_rdcache), ++ offsetof(typeof(*u.si), si_dirwh), ++ offsetof(typeof(*u.si), si_plink_lock), ++ offsetof(typeof(*u.si), si_plink), ++ offsetof(typeof(*u.si), si_kobj), ++ sizeof(*u.si)); ++ printk("destr{len %d, name %d} %d\n", ++ offsetof(typeof(*u.destr), len), ++ offsetof(typeof(*u.destr), name), ++ sizeof(*u.destr)); ++ printk("de{ino %d, type %d, str %d} %d\n", ++ offsetof(typeof(*u.de), de_ino), ++ offsetof(typeof(*u.de), de_type), ++ offsetof(typeof(*u.de), de_str), ++ sizeof(*u.de)); ++ printk("wh{hash %d, bindex %d, str %d} %d\n", ++ offsetof(typeof(*u.wh), wh_hash), ++ offsetof(typeof(*u.wh), wh_bindex), ++ offsetof(typeof(*u.wh), wh_str), ++ sizeof(*u.wh)); ++ printk("vd{deblk %d, nblk %d, last %d, ver %d, jiffy %d} %d\n", ++ offsetof(typeof(*u.vd), vd_deblk), ++ offsetof(typeof(*u.vd), vd_nblk), ++ offsetof(typeof(*u.vd), vd_last), ++ offsetof(typeof(*u.vd), vd_version), ++ offsetof(typeof(*u.vd), vd_jiffy), ++ sizeof(*u.vd)); ++ } ++#endif ++#endif ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++#ifndef CONFIG_AUFS_SYSAUFS ++ sysaufs_brs = 0; ++#endif ++ ++ err = -EINVAL; ++ if (unlikely(aufs_nwkq <= 0)) ++ goto out; ++ err = create_cache(); ++ if (unlikely(err)) ++ goto out; ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out_cache; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_kobj; ++ err = au_inotify_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = dbg_dlgt_init(); ++ if (unlikely(err)) ++ goto out_inotify; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_dlgt; ++ printk(AUFS_NAME " " AUFS_VERSION "\n"); ++ return 0; /* success */ ++ ++ out_dlgt: ++ dbg_dlgt_fin(); ++ out_inotify: ++ au_inotify_fin(); ++ out_wkq: ++ au_wkq_fin(); ++ out_kobj: ++ sysaufs_fin(); ++ out_cache: ++ destroy_cache(); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ dbg_dlgt_fin(); ++ au_inotify_fin(); ++ au_wkq_fin(); ++ sysaufs_fin(); ++ destroy_cache(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); ++ ++/* ---------------------------------------------------------------------- */ ++ ++// fake Kconfig ++#if 1 ++#ifdef CONFIG_AUFS_HINOTIFY ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#error CONFIG_AUFS_HINOTIFY is supported in linux-2.6.18 and later. ++#endif ++#ifndef CONFIG_INOTIFY ++#error enable CONFIG_INOTIFY to use CONFIG_AUFS_HINOTIFY. ++#endif ++#endif ++ ++#if AUFS_BRANCH_MAX > 511 && BITS_PER_LONG == 64 && PAGE_SIZE == 4096 ++#warning For 4k pagesize and 64bit environment, \ ++ CONFIG_AUFS_BRANCH_MAX_511 or smaller is recommended. ++#endif ++ ++#ifdef CONFIG_AUFS_SYSAUFS ++#ifndef CONFIG_SYSFS ++#error CONFIG_AUFS_SYSAUFS requires CONFIG_SYSFS. ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#error CONFIG_AUFS_SYSAUFS requires linux-2.6.18 and later. ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_EXPORT ++#if !defined(CONFIG_EXPORTFS) && !defined(CONFIG_EXPORTFS_MODULE) ++#error CONFIG_AUFS_EXPORT requires CONFIG_EXPORTFS ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#error CONFIG_AUFS_EXPORT requires linux-2.6.18 and later. ++#endif ++#if defined(CONFIG_EXPORTFS_MODULE) && defined(CONFIG_AUFS) ++#error need CONFIG_EXPORTFS=y to link aufs statically with CONFIG_AUFS_EXPORT ++#endif ++#endif ++ ++#ifdef CONFIG_DEBUG_PROVE_LOCKING ++#if MAX_LOCKDEP_SUBCLASSES < AuLsc_End ++#warning lockdep will not work since aufs uses deeper locks. ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_COMPAT ++#warning CONFIG_AUFS_COMPAT will be removed in the near future. ++#endif ++ ++#endif +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/module.h linux-2.6.22.1/fs/aufs/module.h +--- linux-2.6.22.1.oorig/fs/aufs/module.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/module.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: module.h,v 1.8 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameters */ ++extern short aufs_nwkq; ++extern int sysaufs_brs; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern char au_esc_chars[]; ++extern int au_dir_roflags; ++ ++/* kmem cache */ ++enum {AuCache_DINFO, AuCache_ICNTNR, AuCache_FINFO, AuCache_VDIR, ++ AuCache_DEHSTR, AuCache_HINOTIFY, AuCache_Last}; ++extern struct kmem_cache *aufs_cachep[]; ++ ++#define CacheFuncs(name, index) \ ++static inline void *cache_alloc_##name(void) \ ++{return kmem_cache_alloc(aufs_cachep[index], GFP_KERNEL);} \ ++static inline void cache_free_##name(void *p) \ ++{kmem_cache_free(aufs_cachep[index], p);} ++ ++CacheFuncs(dinfo, AuCache_DINFO); ++CacheFuncs(icntnr, AuCache_ICNTNR); ++CacheFuncs(finfo, AuCache_FINFO); ++CacheFuncs(vdir, AuCache_VDIR); ++CacheFuncs(dehstr, AuCache_DEHSTR); ++CacheFuncs(hinotify, AuCache_HINOTIFY); ++ ++#undef CacheFuncs ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/opts.c linux-2.6.22.1/fs/aufs/opts.c +--- linux-2.6.22.1.oorig/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/opts.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,1043 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: opts.c,v 1.34 2007/05/14 03:40:27 sfjro Exp $ */ ++ ++#include // a distribution requires ++#include ++#include "aufs.h" ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_deblk, Opt_nhash, ++ Opt_xino, Opt_zxino, Opt_noxino, ++ Opt_plink, Opt_noplink, Opt_list_plink, Opt_clean_plink, ++ Opt_udba, ++ Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, Opt_nowarn_perm, ++ Opt_findrw_dir, Opt_findrw_br, ++ Opt_coo, ++ Opt_dlgt, Opt_nodlgt, ++ Opt_tail, Opt_ignore, Opt_err ++}; ++ ++static match_table_t options = { ++ {Opt_br, "br=%s"}, ++ {Opt_br, "br:%s"}, ++ ++ {Opt_add, "add=%d:%s"}, ++ {Opt_add, "add:%d:%s"}, ++ {Opt_add, "ins=%d:%s"}, ++ {Opt_add, "ins:%d:%s"}, ++ {Opt_append, "append=%s"}, ++ {Opt_append, "append:%s"}, ++ {Opt_prepend, "prepend=%s"}, ++ {Opt_prepend, "prepend:%s"}, ++ ++ {Opt_del, "del=%s"}, ++ {Opt_del, "del:%s"}, ++ //{Opt_idel, "idel:%d"}, ++ {Opt_mod, "mod=%s"}, ++ {Opt_mod, "mod:%s"}, ++ //{Opt_imod, "imod:%d:%s"}, ++ ++ {Opt_dirwh, "dirwh=%d"}, ++ {Opt_dirwh, "dirwh:%d"}, ++ ++ {Opt_xino, "xino=%s"}, ++ {Opt_xino, "xino:%s"}, ++ {Opt_noxino, "noxino"}, ++ //{Opt_zxino, "zxino=%s"}, ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++ {Opt_plink, "plink"}, ++ {Opt_noplink, "noplink"}, ++#ifdef CONFIG_AUFS_DEBUG ++ {Opt_list_plink, "list_plink"}, ++#endif ++ {Opt_clean_plink, "clean_plink"}, ++#endif ++ ++ {Opt_udba, "udba=%s"}, ++ ++ {Opt_diropq_a, "diropq=always"}, ++ {Opt_diropq_a, "diropq=a"}, ++ {Opt_diropq_w, "diropq=whiteouted"}, ++ {Opt_diropq_w, "diropq=w"}, ++ ++ {Opt_warn_perm, "warn_perm"}, ++ {Opt_nowarn_perm, "nowarn_perm"}, ++ ++#ifdef CONFIG_AUFS_DLGT ++ {Opt_dlgt, "dlgt"}, ++ {Opt_nodlgt, "nodlgt"}, ++#endif ++ ++ {Opt_rdcache, "rdcache=%d"}, ++ {Opt_rdcache, "rdcache:%d"}, ++#if 0 ++ {Opt_findrw_dir, "findrw=dir"}, ++ {Opt_findrw_br, "findrw=br"}, ++ ++ {Opt_coo, "coo=%s"}, ++ ++ {Opt_deblk, "deblk=%d"}, ++ {Opt_deblk, "deblk:%d"}, ++ {Opt_nhash, "nhash=%d"}, ++ {Opt_nhash, "nhash:%d"}, ++#endif ++ ++ {Opt_br, "dirs=%s"}, ++ {Opt_ignore, "debug=%d"}, ++ {Opt_ignore, "delete=whiteout"}, ++ {Opt_ignore, "delete=all"}, ++ {Opt_ignore, "imap=%s"}, ++ ++ {Opt_err, NULL} ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define RW "rw" ++#define RO "ro" ++#define WH "wh" ++#define RR "rr" ++#define NoLinkWH "nolwh" ++ ++static match_table_t brperms = { ++ {AuBr_RR, RR}, ++ {AuBr_RO, RO}, ++ {AuBr_RW, RW}, ++ ++ {AuBr_RRWH, RR "+" WH}, ++ {AuBr_ROWH, RO "+" WH}, ++ {AuBr_RWNoLinkWH, RW "+" NoLinkWH}, ++ ++ {AuBr_ROWH, "nfsro"}, ++ {AuBr_RO, NULL} ++}; ++ ++static int br_perm_val(char *perm) ++{ ++ int val; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ DEBUG_ON(!perm || !*perm); ++ LKTRTrace("perm %s\n", perm); ++ val = match_token(perm, brperms, args); ++ TraceErr(val); ++ return val; ++} ++ ++int br_perm_str(char *p, unsigned int len, int brperm) ++{ ++ struct match_token *bp = brperms; ++ ++ LKTRTrace("len %d, 0x%x\n", len, brperm); ++ ++ while (bp->pattern) { ++ if (bp->token == brperm) { ++ if (strlen(bp->pattern) < len) { ++ strcpy(p, bp->pattern); ++ return 0; ++ } else ++ return -E2BIG; ++ } ++ bp++; ++ } ++ ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuFlag_UDBA_REVAL, "reval"}, ++#ifdef CONFIG_AUFS_HINOTIFY ++ {AuFlag_UDBA_INOTIFY, "inotify"}, ++#endif ++ {AuFlag_UDBA_NONE, "none"}, ++ {-1, NULL} ++}; ++ ++static int udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ return match_token(str, udbalevel, args); ++} ++ ++au_parser_pattern_t udba_str(int udba) ++{ ++ struct match_token *p = udbalevel; ++ while (p->pattern) { ++ if (p->token == udba) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++void udba_set(struct super_block *sb, unsigned int flg) ++{ ++ au_flag_clr(sb, AuMask_UDBA); ++ au_flag_set(sb, flg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t coolevel = { ++ {AuFlag_COO_LEAF, "leaf"}, ++ {AuFlag_COO_ALL, "all"}, ++ {AuFlag_COO_NONE, "none"}, ++ {-1, NULL} ++}; ++ ++#if 0 ++static int coo_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ return match_token(str, coolevel, args); ++} ++#endif ++ ++au_parser_pattern_t coo_str(int coo) ++{ ++ struct match_token *p = coolevel; ++ while (p->pattern) { ++ if (p->token == coo) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++static void coo_set(struct super_block *sb, unsigned int flg) ++{ ++ au_flag_clr(sb, AuMask_COO); ++ au_flag_set(sb, flg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; ++ ++#ifdef CONFIG_AUFS_DEBUG ++static void dump_opts(struct opts *opts) ++{ ++ /* reduce stack space */ ++ union { ++ struct opt_add *add; ++ struct opt_del *del; ++ struct opt_mod *mod; ++ struct opt_xino *xino; ++ } u; ++ struct opt *opt; ++ ++ TraceEnter(); ++ ++ opt = opts->opt; ++ while (/* opt < opts_tail && */ opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ LKTRTrace("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->path, u.add->perm, ++ u.add->nd.dentry); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ u.del = &opt->del; ++ LKTRTrace("del {%s, %p}\n", u.del->path, u.del->h_root); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ u.mod = &opt->mod; ++ LKTRTrace("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ LKTRTrace("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->path, u.add->perm, ++ u.add->nd.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ LKTRTrace("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->path, u.add->perm, ++ u.add->nd.dentry); ++ break; ++ case Opt_dirwh: ++ LKTRTrace("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ LKTRTrace("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_xino: ++ u.xino = &opt->xino; ++ LKTRTrace("xino {%s %.*s}\n", ++ u.xino->path, DLNPair(u.xino->file->f_dentry)); ++ break; ++ case Opt_noxino: ++ LKTRLabel(noxino); ++ break; ++ case Opt_plink: ++ LKTRLabel(plink); ++ break; ++ case Opt_noplink: ++ LKTRLabel(noplink); ++ break; ++ case Opt_list_plink: ++ LKTRLabel(list_plink); ++ break; ++ case Opt_clean_plink: ++ LKTRLabel(clean_plink); ++ break; ++ case Opt_udba: ++ LKTRTrace("udba %d, %s\n", ++ opt->udba, udba_str(opt->udba)); ++ break; ++ case Opt_diropq_a: ++ LKTRLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ LKTRLabel(diropq_w); ++ break; ++ case Opt_warn_perm: ++ LKTRLabel(warn_perm); ++ break; ++ case Opt_nowarn_perm: ++ LKTRLabel(nowarn_perm); ++ break; ++ case Opt_dlgt: ++ LKTRLabel(dlgt); ++ break; ++ case Opt_nodlgt: ++ LKTRLabel(nodlgt); ++ break; ++ case Opt_coo: ++ LKTRTrace("coo %d, %s\n", opt->coo, coo_str(opt->coo)); ++ break; ++ default: ++ BUG(); ++ } ++ opt++; ++ } ++} ++#else ++#define dump_opts(opts) /* */ ++#endif ++ ++void au_free_opts(struct opts *opts) ++{ ++ struct opt *opt; ++ ++ TraceEnter(); ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ case Opt_append: ++ case Opt_prepend: ++ path_release(&opt->add.nd); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ dput(opt->del.h_root); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static int opt_add(struct opt *opt, char *opt_str, struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct opt_add *add = &opt->add; ++ char *p; ++ ++ LKTRTrace("%s, b%d\n", opt_str, bindex); ++ ++ add->bindex = bindex; ++ add->perm = AuBr_RO; ++ if (!bindex && !(sb->s_flags & MS_RDONLY)) ++ add->perm = AuBr_RW; ++#ifdef CONFIG_AUFS_COMPAT ++ add->perm = AuBr_RW; ++#endif ++ add->path = opt_str; ++ p = strchr(opt_str, '='); ++ if (unlikely(p)) { ++ *p++ = 0; ++ if (*p) ++ add->perm = br_perm_val(p); ++ } ++ ++ // LSM may detect it ++ // do not superio. ++ err = path_lookup(add->path, lkup_dirflags, &add->nd); ++ //err = -1; ++ if (!err) { ++ opt->type = Opt_add; ++ goto out; ++ } ++ Err("lookup failed %s (%d)\n", add->path, err); ++ err = -EINVAL; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* called without aufs lock */ ++int au_parse_opts(struct super_block *sb, char *str, struct opts *opts) ++{ ++ int err, n; ++ struct dentry *root; ++ struct opt *opt, *opt_tail; ++ char *opt_str; ++ substring_t args[MAX_OPT_ARGS]; ++ aufs_bindex_t bindex; ++ struct nameidata nd; ++ /* reduce stack space */ ++ union { ++ struct opt_del *del; ++ struct opt_mod *mod; ++ struct opt_xino *xino; ++ } u; ++ struct file *file; ++ ++ LKTRTrace("%s, nopts %d\n", str, opts->max_opt); ++ ++ root = sb->s_root; ++ err = 0; ++ bindex = 0; ++ opt = opts->opt; ++ opt_tail = opt + opts->max_opt - 1; ++ opt->type = Opt_tail; ++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { ++ int token, skipped; ++ char *p; ++ err = -EINVAL; ++ token = match_token(opt_str, options, args); ++ LKTRTrace("%s, token %d, args[0]{%p, %p}\n", ++ opt_str, token, args[0].from, args[0].to); ++ ++ skipped = 0; ++ switch (token) { ++ case Opt_br: ++ err = 0; ++ while (!err && (opt_str = strsep(&args[0].from, ":")) ++ && *opt_str) { ++ err = opt_add(opt, opt_str, sb, bindex++); ++ //if (LktrCond) err = -1; ++ if (unlikely(!err && ++opt > opt_tail)) { ++ err = -E2BIG; ++ break; ++ } ++ opt->type = Opt_tail; ++ skipped = 1; ++ } ++ break; ++ case Opt_add: ++ if (unlikely(match_int(&args[0], &n))) { ++ Err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ err = opt_add(opt, args[1].from, sb, bindex); ++ break; ++ case Opt_append: ++ case Opt_prepend: ++ err = opt_add(opt, args[0].from, sb, /*dummy bindex*/1); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_del: ++ u.del = &opt->del; ++ u.del->path = args[0].from; ++ LKTRTrace("del path %s\n", u.del->path); ++ // LSM may detect it ++ // do not superio. ++ err = path_lookup(u.del->path, lkup_dirflags, &nd); ++ if (unlikely(err)) { ++ Err("lookup failed %s (%d)\n", u.del->path, err); ++ break; ++ } ++ u.del->h_root = dget(nd.dentry); ++ path_release(&nd); ++ opt->type = token; ++ break; ++#if 0 ++ case Opt_idel: ++ u.del = &opt->del; ++ u.del->path = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ Err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ aufs_read_lock(root, !AUFS_I_RLOCK); ++ if (bindex < 0 || sbend(sb) < bindex) { ++ Err("out of bounds, %d\n", bindex); ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ break; ++ } ++ err = 0; ++ u.del->h_root = dget(au_h_dptr_i(root, bindex)); ++ opt->type = token; ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ break; ++#endif ++ ++ case Opt_mod: ++ u.mod = &opt->mod; ++ u.mod->path = args[0].from; ++ p = strchr(u.mod->path, '='); ++ if (unlikely(!p)) { ++ Err("no permssion %s\n", opt_str); ++ break; ++ } ++ *p++ = 0; ++ u.mod->perm = br_perm_val(p); ++ LKTRTrace("mod path %s, perm 0x%x, %s\n", ++ u.mod->path, u.mod->perm, p); ++ // LSM may detect it ++ // do not superio. ++ err = path_lookup(u.mod->path, lkup_dirflags, &nd); ++ if (unlikely(err)) { ++ Err("lookup failed %s (%d)\n", u.mod->path, err); ++ break; ++ } ++ u.mod->h_root = dget(nd.dentry); ++ path_release(&nd); ++ opt->type = token; ++ break; ++#if 0 ++ case Opt_imod: ++ u.mod = &opt->mod; ++ u.mod->path = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ Err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ aufs_read_lock(root, !AUFS_I_RLOCK); ++ if (bindex < 0 || sbend(sb) < bindex) { ++ Err("out of bounds, %d\n", bindex); ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ break; ++ } ++ u.mod->perm = br_perm_val(args[1].from); ++ LKTRTrace("mod path %s, perm 0x%x, %s\n", ++ u.mod->path, u.mod->perm, args[1].from); ++ err = 0; ++ u.mod->h_root = dget(au_h_dptr_i(root, bindex)); ++ opt->type = token; ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ break; ++#endif ++ case Opt_xino: ++ u.xino = &opt->xino; ++ file = xino_create(sb, args[0].from, /*silent*/0, ++ /*parent*/NULL); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ break; ++ err = -EINVAL; ++ if (unlikely(file->f_dentry->d_sb == sb)) { ++ fput(file); ++ Err("%s must be outside\n", args[0].from); ++ break; ++ } ++ err = 0; ++ u.xino->file = file; ++ u.xino->path = args[0].from; ++ opt->type = token; ++ break; ++ ++ case Opt_dirwh: ++ if (unlikely(match_int(&args[0], &opt->dirwh))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(match_int(&args[0], &opt->rdcache))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_noxino: ++ case Opt_plink: ++ case Opt_noplink: ++ case Opt_list_plink: ++ case Opt_clean_plink: ++ case Opt_diropq_a: ++ case Opt_diropq_w: ++ case Opt_warn_perm: ++ case Opt_nowarn_perm: ++ case Opt_dlgt: ++ case Opt_nodlgt: ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_udba: ++ opt->udba = udba_val(args[0].from); ++ if (opt->udba >= 0) { ++ err = 0; ++ opt->type = token; ++ } ++ break; ++ ++#if 0 ++ case Opt_coo: ++ opt->coo = coo_val(args[0].from); ++ if (opt->coo >= 0) { ++ err = 0; ++ opt->type = token; ++ } ++ break; ++#endif ++ ++ case Opt_ignore: ++#ifndef CONFIG_AUFS_COMPAT ++ Warn("ignored %s\n", opt_str); ++#endif ++ skipped = 1; ++ err = 0; ++ break; ++ case Opt_err: ++ Err("unknown option %s\n", opt_str); ++ break; ++ } ++ ++ if (!err && !skipped) { ++ if (unlikely(++opt > opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ opt->type = Opt_tail; ++ break; ++ } ++ opt->type = Opt_tail; ++ } ++ } ++ ++ dump_opts(opts); ++ if (unlikely(err)) ++ au_free_opts(opts); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_do_opt_simple(struct super_block *sb, struct opt *opt, ++ int remount, unsigned int *given) ++{ ++ int err; ++ struct aufs_sbinfo *sbinfo = stosi(sb); ++ ++ TraceEnter(); ++ ++ err = 1; /* handled */ ++ switch (opt->type) { ++ case Opt_udba: ++ udba_set(sb, opt->udba); ++ *given |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ au_flag_set(sb, AuFlag_PLINK); ++ *given |= AuFlag_PLINK; ++ break; ++ case Opt_noplink: ++ if (au_flag_test(sb, AuFlag_PLINK)) ++ au_put_plink(sb); ++ au_flag_clr(sb, AuFlag_PLINK); ++ *given |= AuFlag_PLINK; ++ break; ++ case Opt_list_plink: ++ if (au_flag_test(sb, AuFlag_PLINK)) ++ au_list_plink(sb); ++ break; ++ case Opt_clean_plink: ++ if (au_flag_test(sb, AuFlag_PLINK)) ++ au_put_plink(sb); ++ break; ++ ++ case Opt_diropq_a: ++ au_flag_set(sb, AuFlag_ALWAYS_DIROPQ); ++ *given |= AuFlag_ALWAYS_DIROPQ; ++ break; ++ case Opt_diropq_w: ++ au_flag_clr(sb, AuFlag_ALWAYS_DIROPQ); ++ *given |= AuFlag_ALWAYS_DIROPQ; ++ break; ++ ++ case Opt_dlgt: ++ au_flag_set(sb, AuFlag_DLGT); ++ *given |= AuFlag_DLGT; ++ break; ++ case Opt_nodlgt: ++ au_flag_clr(sb, AuFlag_DLGT); ++ *given |= AuFlag_DLGT; ++ break; ++ ++ case Opt_warn_perm: ++ au_flag_set(sb, AuFlag_WARN_PERM); ++ *given |= AuFlag_WARN_PERM; ++ break; ++ case Opt_nowarn_perm: ++ au_flag_clr(sb, AuFlag_WARN_PERM); ++ *given |= AuFlag_WARN_PERM; ++ break; ++ ++ case Opt_coo: ++ coo_set(sb, opt->coo); ++ *given |= opt->coo; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache = opt->rdcache * HZ; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_do_opt_br(struct super_block *sb, struct opt *opt, int remount, ++ int *do_refresh) ++{ ++ int err; ++ ++ TraceEnter(); ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = sbend(sb) + 1; ++ goto add; ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ add: ++ case Opt_add: ++ err = br_add(sb, &opt->add, remount); ++ if (!err) ++ *do_refresh = err = 1; ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = br_del(sb, &opt->del, remount); ++ if (!err) ++ *do_refresh = err = 1; ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = br_mod(sb, &opt->mod, remount, do_refresh); ++ if (!err) ++ err = 1; ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int au_do_opt_xino(struct super_block *sb, struct opt *opt, int remount, ++ struct opt_xino **opt_xino) ++{ ++ int err; ++ ++ TraceEnter(); ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = xino_set(sb, &opt->xino, remount); ++ if (!err) ++ *opt_xino = &opt->xino; ++ break; ++ case Opt_noxino: ++ err = xino_clr(sb); ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int verify_opts(struct super_block *sb, int remount) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct aufs_branch *br; ++ struct dentry *root; ++ struct inode *dir; ++ unsigned int do_plink; ++ ++ TraceEnter(); ++ ++ if (unlikely(!(sb->s_flags & MS_RDONLY) ++ && !br_writable(sbr_perm(sb, 0)))) ++ Warn("first branch should be rw\n"); ++ ++ err = 0; ++ root = sb->s_root; ++ dir = sb->s_root->d_inode; ++ do_plink = au_flag_test(sb, AuFlag_PLINK); ++ bend = sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ struct inode *h_dir; ++ int skip; ++ ++ skip = 0; ++ h_dir = au_h_iptr_i(dir, bindex); ++ br = stobr(sb, bindex); ++ br_wh_read_lock(br); ++ switch (br->br_perm) { ++ case AuBr_RR: ++ case AuBr_RO: ++ case AuBr_RRWH: ++ case AuBr_ROWH: ++ skip = (!br->br_wh && !br->br_plink); ++ break; ++ ++ case AuBr_RWNoLinkWH: ++ skip = !br->br_wh; ++ if (skip) { ++ if (do_plink) ++ skip = !!br->br_plink; ++ else ++ skip = !br->br_plink; ++ } ++ break; ++ ++ case AuBr_RW: ++ skip = !!br->br_wh; ++ if (skip) { ++ if (do_plink) ++ skip = !!br->br_plink; ++ else ++ skip = !br->br_plink; ++ } ++ break; ++ ++ default: ++ BUG(); ++ } ++ br_wh_read_unlock(br); ++ ++ if (skip) ++ continue; ++ ++ hdir_lock(h_dir, dir, bindex); ++ br_wh_write_lock(br); ++ err = init_wh(au_h_dptr_i(root, bindex), br, ++ au_nfsmnt(sb, bindex), sb); ++ br_wh_write_unlock(br); ++ hdir_unlock(h_dir, dir, bindex); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++int au_do_opts_mount(struct super_block *sb, struct opts *opts) ++{ ++ int err, do_refresh; ++ struct inode *dir; ++ struct opt *opt; ++ unsigned int flags, given; ++ struct opt_xino *opt_xino; ++ aufs_bindex_t bend, bindex; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ DiMustWriteLock(sb->s_root); ++ dir = sb->s_root->d_inode; ++ IiMustWriteLock(dir); ++ ++ err = 0; ++ given = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_do_opt_simple(sb, opt++, /*remount*/0, &given); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable them temporary */ ++ flags = au_flag_test(sb, AuFlag_XINO | AuMask_UDBA | AuFlag_DLGT); ++ au_flag_clr(sb, AuFlag_XINO | AuFlag_DLGT); ++ udba_set(sb, AuFlag_UDBA_REVAL); ++ ++ do_refresh = 0; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_do_opt_br(sb, opt++, /*remount*/0, &do_refresh); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bend = sbend(sb); ++ if (unlikely(bend < 0)) { ++ err = -EINVAL; ++ Err("no branches\n"); ++ goto out; ++ } ++ ++ if (flags & AuFlag_XINO) ++ au_flag_set(sb, AuFlag_XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_do_opt_xino(sb, opt++, /*remount*/0, &opt_xino); ++ if (unlikely(err)) ++ goto out; ++ ++ //todo: test this error case. ++ err = verify_opts(sb, /*remount*/0); ++ DEBUG_ON(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* enable xino */ ++ if (au_flag_test(sb, AuFlag_XINO) && !opt_xino) { ++ struct file *xino_file = xino_def(sb); ++ err = PTR_ERR(xino_file); ++ if (IS_ERR(xino_file)) ++ goto out; ++ ++ err = 0; ++ for (bindex = 0; !err && bindex <= bend; bindex++) ++ err = xino_init(sb, bindex, xino_file, ++ /*do_test*/bindex); ++ fput(xino_file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore hinotify */ ++ udba_set(sb, flags & AuMask_UDBA); ++ if (flags & AuFlag_UDBA_INOTIFY) ++ au_reset_hinotify(dir, au_hi_flags(dir, 1) & ~AUFS_HI_XINO); ++ ++ /* restore dlgt */ ++ if (flags & AuFlag_DLGT) ++ au_flag_set(sb, AuFlag_DLGT); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++int au_do_opts_remount(struct super_block *sb, struct opts *opts, ++ int *do_refresh, unsigned int *given) ++{ ++ int err, rerr; ++ struct inode *dir; ++ struct opt_xino *opt_xino; ++ struct opt *opt; ++ unsigned int dlgt; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ DiMustWriteLock(sb->s_root); ++ dir = sb->s_root->d_inode; ++ IiMustWriteLock(dir); ++ //DEBUG_ON(au_flag_test(sb, AuFlag_UDBA_INOTIFY)); ++ ++ err = 0; ++ *do_refresh = 0; ++ *given = 0; ++ dlgt = au_flag_test(sb, AuFlag_DLGT); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_do_opt_simple(sb, opt, /*remount*/1, given); ++ ++ /* disable it temporary */ ++ dlgt = au_flag_test(sb, AuFlag_DLGT); ++ au_flag_clr(sb, AuFlag_DLGT); ++ ++ if (!err) ++ err = au_do_opt_br(sb, opt, /*remount*/1, do_refresh); ++ if (!err) ++ err = au_do_opt_xino(sb, opt, /*remount*/1, &opt_xino); ++ ++ /* restore it */ ++ au_flag_set(sb, dlgt); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ TraceErr(err); ++ ++ /* go on if err */ ++ ++ //todo: test this error case. ++ au_flag_clr(sb, AuFlag_DLGT); ++ rerr = verify_opts(sb, /*remount*/1); ++ au_flag_set(sb, dlgt); ++ ++ /* they are handled by the caller */ ++ if (!*do_refresh) ++ *do_refresh = !!((*given & AuMask_UDBA) ++ || au_flag_test(sb, AuFlag_XINO)); ++ ++ TraceErr(err); ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/opts.h linux-2.6.22.1/fs/aufs/opts.h +--- linux-2.6.22.1.oorig/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/opts.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,96 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: opts.h,v 1.13 2007/05/14 06:27:18 sfjro Exp $ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++typedef const char* au_parser_pattern_t; ++#else ++typedef char* au_parser_pattern_t; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct opt_add { ++ aufs_bindex_t bindex; ++ char *path; ++ int perm; ++ struct nameidata nd; ++}; ++ ++struct opt_del { ++ char *path; ++ struct dentry *h_root; ++}; ++ ++struct opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct opt { ++ int type; ++ union { ++ struct opt_xino xino; ++ struct opt_add add; ++ struct opt_del del; ++ struct opt_mod mod; ++ int dirwh; ++ int rdcache; ++ int deblk; ++ int nhash; ++ int udba; ++ int coo; ++ }; ++}; ++ ++struct opts { ++ struct opt *opt; ++ int max_opt; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int br_perm_str(char *p, unsigned int len, int brperm); ++au_parser_pattern_t udba_str(int udba); ++void udba_set(struct super_block *sb, unsigned int flg); ++//au_parser_pattern_t coo_str(int coo); ++void au_free_opts(struct opts *opts); ++int au_parse_opts(struct super_block *sb, char *str, struct opts *opts); ++int au_do_opts_mount(struct super_block *sb, struct opts *opts); ++int au_do_opts_remount(struct super_block *sb, struct opts *opts, ++ int *do_refresh, unsigned int *given); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/plink.c linux-2.6.22.1/fs/aufs/plink.c +--- linux-2.6.22.1.oorig/fs/aufs/plink.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/plink.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,331 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: plink.c,v 1.4 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++struct pseudo_link { ++ struct list_head list; ++ struct inode *inode; ++}; ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_list_plink(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ ++ TraceEnter(); ++ SiMustAnyLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry(plink, plink_list, list) ++ Dbg("%lu\n", plink->inode->i_ino); ++ spin_unlock(&sbinfo->si_plink_lock); ++} ++#endif ++ ++int au_is_plinked(struct super_block *sb, struct inode *inode) ++{ ++ int found; ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ SiMustAnyLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ found = 0; ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry(plink, plink_list, list) ++ if (plink->inode == inode) { ++ found = 1; ++ break; ++ } ++ spin_unlock(&sbinfo->si_plink_lock); ++ return found; ++} ++ ++// 20 is max digits length of ulong 64 ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ LKTRTrace("i%lu, b%d\n", inode->i_ino, bindex); ++ DEBUG_ON(len != PLINK_NAME_LEN); ++ h_inode = au_h_iptr_i(inode, bindex); ++ DEBUG_ON(!h_inode); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ DEBUG_ON(rlen >= len); ++ return rlen; ++} ++ ++struct dentry *lkup_plink(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ struct dentry *h_dentry, *h_parent; ++ struct aufs_branch *br; ++ struct inode *h_dir; ++ char tgtname[PLINK_NAME_LEN]; ++ int len; ++ struct lkup_args lkup; ++ ++ LKTRTrace("b%d, i%lu\n", bindex, inode->i_ino); ++ br = stobr(sb, bindex); ++ h_parent = br->br_plink; ++ DEBUG_ON(!h_parent); ++ h_dir = h_parent->d_inode; ++ DEBUG_ON(!h_dir); ++ ++ len = plink_name(tgtname, sizeof(tgtname), inode, bindex); ++ ++ // always superio. ++ lkup.nfsmnt = au_do_nfsmnt(br->br_mnt); ++ lkup.dlgt = need_dlgt(sb); ++ hi_lock_whplink(h_dir); ++ h_dentry = sio_lkup_one(tgtname, h_parent, len, &lkup); ++ i_unlock(h_dir); ++ return h_dentry; ++} ++ ++static int do_whplink(char *tgt, int len, struct dentry *h_parent, ++ struct dentry *h_dentry, struct vfsmount *nfsmnt, ++ struct super_block *sb) ++{ ++ int err; ++ struct dentry *h_tgt; ++ struct inode *h_dir; ++ struct lkup_args lkup = { ++ .nfsmnt = nfsmnt, ++ .dlgt = need_dlgt(sb) ++ }; ++ ++ h_tgt = lkup_one(tgt, h_parent, len, &lkup); ++ err = PTR_ERR(h_tgt); ++ if (IS_ERR(h_tgt)) ++ goto out; ++ ++ err = 0; ++ h_dir = h_parent->d_inode; ++ if (unlikely(h_tgt->d_inode && h_tgt->d_inode != h_dentry->d_inode)) ++ err = vfsub_unlink(h_dir, h_tgt, lkup.dlgt); ++ if (!err && !h_tgt->d_inode) { ++ err = vfsub_link(h_dentry, h_dir, h_tgt, lkup.dlgt); ++ //inode->i_nlink++; ++ } ++ dput(h_tgt); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ char *tgt; ++ int len; ++ struct dentry *h_parent; ++ struct dentry *h_dentry; ++ struct vfsmount *nfsmnt; ++ struct super_block *sb; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->len, a->h_parent, a->h_dentry, ++ a->nfsmnt, a->sb); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex, struct super_block *sb) ++{ ++ int err, len; ++ struct aufs_branch *br; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ char tgtname[PLINK_NAME_LEN]; ++ ++ LKTRTrace("%.*s\n", DLNPair(h_dentry)); ++ br = stobr(inode->i_sb, bindex); ++ h_parent = br->br_plink; ++ DEBUG_ON(!h_parent); ++ h_dir = h_parent->d_inode; ++ DEBUG_ON(!h_dir); ++ ++ len = plink_name(tgtname, sizeof(tgtname), inode, bindex); ++ ++ // always superio. ++ hi_lock_whplink(h_dir); ++ if (!is_au_wkq(current)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = tgtname, ++ .len = len, ++ .h_parent = h_parent, ++ .h_dentry = h_dentry, ++ .nfsmnt = au_do_nfsmnt(br->br_mnt), ++ .sb = sb ++ }; ++ au_wkq_wait(call_do_whplink, &args, /*dlgt*/0); ++ } else ++ err = do_whplink(tgtname, len, h_parent, h_dentry, ++ au_do_nfsmnt(br->br_mnt), sb); ++ i_unlock(h_dir); ++ ++ TraceErr(err); ++ return err; ++} ++ ++void append_plink(struct super_block *sb, struct inode *inode, ++ struct dentry *h_dentry, aufs_bindex_t bindex) ++{ ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ int found, err, cnt; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ SiMustAnyLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ cnt = 0; ++ found = 0; ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry(plink, plink_list, list) { ++ cnt++; ++ if (plink->inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ ++ err = 0; ++ if (!found) { ++ struct pseudo_link *plink; ++ ++ plink = kmalloc(sizeof(*plink), GFP_ATOMIC); ++ if (plink) { ++ plink->inode = igrab(inode); ++ list_add(&plink->list, plink_list); ++ cnt++; ++ } else ++ err = -ENOMEM; ++ } ++ spin_unlock(&sbinfo->si_plink_lock); ++ ++ if (!err) ++ err = whplink(h_dentry, inode, bindex, sb); ++ ++ if (unlikely(cnt > 100)) ++ Warn1("unexpectedly many pseudo links, %d\n", cnt); ++ if (unlikely(err)) ++ Warn("err %d, damaged pseudo link. ignored.\n", err); ++} ++ ++static void do_put_plink(struct pseudo_link *plink, int do_del) ++{ ++ TraceEnter(); ++ ++ iput(plink->inode); ++ if (do_del) ++ list_del(&plink->list); ++ kfree(plink); ++} ++ ++void au_put_plink(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink, *tmp; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ //spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry_safe(plink, tmp, plink_list, list) ++ do_put_plink(plink, 0); ++ INIT_LIST_HEAD(plink_list); ++ //spin_unlock(&sbinfo->si_plink_lock); ++} ++ ++void half_refresh_plink(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct aufs_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink, *tmp; ++ struct inode *inode; ++ aufs_bindex_t bstart, bend, bindex; ++ int do_put; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_PLINK)); ++ ++ sbinfo = stosi(sb); ++ plink_list = &sbinfo->si_plink; ++ //spin_lock(&sbinfo->si_plink_lock); ++ list_for_each_entry_safe(plink, tmp, plink_list, list) { ++ do_put = 0; ++ inode = igrab(plink->inode); ++ ii_write_lock_child(inode); ++ bstart = ibstart(inode); ++ bend = ibend(inode); ++ if (bstart >= 0) { ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ if (!au_h_iptr_i(inode, bindex) ++ || itoid_index(inode, bindex) != br_id) ++ continue; ++ set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ } else ++ do_put_plink(plink, 1); ++ ++ if (do_put) { ++ for (bindex = bstart; bindex <= bend; bindex++) ++ if (au_h_iptr_i(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ if (do_put) ++ do_put_plink(plink, 1); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ //spin_unlock(&sbinfo->si_plink_lock); ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/sbinfo.c linux-2.6.22.1/fs/aufs/sbinfo.c +--- linux-2.6.22.1.oorig/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/sbinfo.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: sbinfo.c,v 1.30 2007/05/14 03:39:31 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++struct aufs_sbinfo *stosi(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ sbinfo = sb->s_fs_info; ++ //DEBUG_ON(sbinfo->si_bend < 0); ++ return sbinfo; ++} ++ ++aufs_bindex_t sbend(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return stosi(sb)->si_bend; ++} ++ ++struct aufs_branch *stobr(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ DEBUG_ON(bindex < 0 || sbend(sb) < bindex ++ || !stosi(sb)->si_branch[0 + bindex]); ++ return stosi(sb)->si_branch[0 + bindex]; ++} ++ ++int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return stosi(sb)->si_generation; ++} ++ ++int au_sigen_inc(struct super_block *sb) ++{ ++ int gen; ++ ++ SiMustWriteLock(sb); ++ gen = ++stosi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ au_update_iigen(sb->s_root->d_inode); ++ sb->s_root->d_inode->i_version++; ++ return gen; ++} ++ ++int find_bindex(struct super_block *sb, struct aufs_branch *br) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ bend = sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (stobr(sb, bindex) == br) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry and super_block lock. call at entry point */ ++void aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ si_read_lock(dentry->d_sb); ++ if (flags & AUFS_D_WLOCK) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (flags & AUFS_D_WLOCK) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ //au_wkq_wait_nwtask(); ++ si_write_lock(dentry->d_sb); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++ //au_wkq_wait_nwtask(); ++} ++ ++void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ DEBUG_ON(d1 == d2 || d1->d_sb != d2->d_sb); ++ si_read_lock(d1->d_sb); ++ di_write_lock2_child(d1, d2, isdir); ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ DEBUG_ON(d1 == d2 || d1->d_sb != d2->d_sb); ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++aufs_bindex_t new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ ++ while (1) { ++ br_id = ++stosi(sb)->si_last_br_id; ++ if (br_id && find_brindex(sb, br_id) < 0) ++ return br_id; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SYSAUFS ++static int make_xino(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size) ++{ ++ int err; ++ struct super_block *sb = args->sb; ++ aufs_bindex_t bindex, bend; ++ struct file *xf; ++ struct inode *xi; ++ ++ TraceEnter(); ++ DEBUG_ON(args->index != SysaufsSb_XINO); ++ SiMustReadLock(sb); ++ ++ *do_size = 0; ++ err = seq_printf(seq, "%d %lu\n", sizeof(struct xino), ++ atomic_long_read(&stosi(sb)->si_xino)); ++ bend = sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ xf = stobr(sb, bindex)->br_xino; ++ xi = xf->f_dentry->d_inode; ++ err = seq_printf(seq, "%d: %d, %Lux%d %Ld\n", ++ bindex, file_count(xf), ++ (u64)xi->i_blocks, 1 << xi->i_blkbits, ++ i_size_read(xi)); ++ } ++ return err; ++} ++ ++sysaufs_op au_si_ops[] = { ++ [SysaufsSb_XINO] = make_xino ++}; ++#endif +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/super.c linux-2.6.22.1/fs/aufs/super.c +--- linux-2.6.22.1.oorig/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/super.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,716 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: super.c,v 1.50 2007/05/14 03:39:42 sfjro Exp $ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb) ++{ ++ struct aufs_icntnr *c; ++ ++ TraceEnter(); ++ ++ c = cache_alloc_icntnr(); ++ //if (LktrCond) {cache_free_icntnr(c); c = NULL;} ++ if (c) { ++ inode_init_once(&c->vfs_inode); ++ c->vfs_inode.i_version = 1; //sigen(sb); ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ au_iinfo_fin(inode); ++ cache_free_icntnr(container_of(inode, struct aufs_icntnr, vfs_inode)); ++} ++ ++//todo: how about merge with alloc_inode()? ++static void aufs_read_inode(struct inode *inode) ++{ ++ int err; ++ ++ LKTRTrace("i%lu\n", inode->i_ino); ++ ++ err = au_iinfo_init(inode); ++ //if (LktrCond) err = -1; ++ if (!err) { ++ inode->i_version++; ++ inode->i_op = &aufs_iop; ++ inode->i_fop = &aufs_file_fop; ++ inode->i_mapping->a_ops = &aufs_aop; ++ return; /* success */ ++ } ++ ++ LKTRTrace("intializing inode info failed(%d)\n", err); ++ make_bad_inode(inode); ++} ++ ++int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ char a[16]; ++ struct dentry *root; ++ ++ TraceEnter(); ++ SiMustAnyLock(sb); ++ root = sb->s_root; ++ DiMustAnyLock(root); ++ ++ err = 0; ++ bend = sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ err = br_perm_str(a, sizeof(a), sbr_perm(sb, bindex)); ++ if (!err) ++ err = seq_path(seq, sbr_mnt(sb, bindex), ++ au_h_dptr_i(root, bindex), au_esc_chars); ++ if (err > 0) ++ err = seq_printf(seq, "=%s", a); ++ if (!err && bindex != bend) ++ err = seq_putc(seq, ':'); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt) ++{ ++ int err, n; ++ struct super_block *sb; ++ struct aufs_sbinfo *sbinfo; ++ struct dentry *root; ++ struct file *xino; ++ ++ TraceEnter(); ++ ++ sb = mnt->mnt_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, !AUFS_I_RLOCK); ++ if (au_flag_test(sb, AuFlag_XINO)) { ++ err = seq_puts(m, ",xino="); ++ if (unlikely(err)) ++ goto out; ++ xino = stobr(sb, 0)->br_xino; ++ err = seq_path(m, xino->f_vfsmnt, xino->f_dentry, au_esc_chars); ++ if (unlikely(err <= 0)) ++ goto out; ++ err = 0; ++ ++#define Deleted "\\040(deleted)" ++ m->count -= sizeof(Deleted) - 1; ++ DEBUG_ON(memcmp(m->buf + m->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ } else ++ err = seq_puts(m, ",noxino"); ++ ++ n = au_flag_test(sb, AuFlag_PLINK); ++ if (unlikely(!err && (AuDefFlags & AuFlag_PLINK) != n)) ++ err = seq_printf(m, ",%splink", n ? "" : "no"); ++ n = au_flag_test_udba(sb); ++ if (unlikely(!err && (AuDefFlags & AuMask_UDBA) != n)) ++ err = seq_printf(m, ",udba=%s", udba_str(n)); ++ n = au_flag_test(sb, AuFlag_ALWAYS_DIROPQ); ++ if (unlikely(!err && (AuDefFlags & AuFlag_ALWAYS_DIROPQ) != n)) ++ err = seq_printf(m, ",diropq=%c", n ? 'a' : 'w'); ++ n = au_flag_test(sb, AuFlag_DLGT); ++ if (unlikely(!err && (AuDefFlags & AuFlag_DLGT) != n)) ++ err = seq_printf(m, ",%sdlgt", n ? "" : "no"); ++ n = au_flag_test(sb, AuFlag_WARN_PERM); ++ if (unlikely(!err && (AuDefFlags & AuFlag_WARN_PERM) != n)) ++ err = seq_printf(m, ",%swarn_perm", n ? "" : "no"); ++ ++ sbinfo = stosi(sb); ++ n = sbinfo->si_dirwh; ++ if (unlikely(!err && n != AUFS_DIRWH_DEF)) ++ err = seq_printf(m, ",dirwh=%d", n); ++ n = sbinfo->si_rdcache / HZ; ++ if (unlikely(!err && n != AUFS_RDCACHE_DEF)) ++ err = seq_printf(m, ",rdcache=%d", n); ++#if 0 ++ n = au_flag_test_coo(sb); ++ if (unlikely(!err && (AuDefFlags & AuMask_COO) != n)) ++ err = seq_printf(m, ",coo=%s", coo_str(n)); ++#endif ++ ++ if (!err && !sysaufs_brs) { ++#ifdef CONFIG_AUFS_COMPAT ++ err = seq_puts(m, ",dirs="); ++#else ++ err = seq_puts(m, ",br:"); ++#endif ++ if (!err) ++ err = au_show_brs(m, sb); ++ } ++ ++ out: ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ TraceErr(err); ++ if (err) ++ err = -E2BIG; ++ TraceErr(err); ++ return err; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++#define StatfsLock(d) aufs_read_lock((d)->d_sb->s_root, 0) ++#define StatfsUnlock(d) aufs_read_unlock((d)->d_sb->s_root, 0) ++#define StatfsArg(d) au_h_dptr((d)->d_sb->s_root) ++#define StatfsHInode(d) (StatfsArg(d)->d_inode) ++#define StatfsSb(d) ((d)->d_sb) ++static int aufs_statfs(struct dentry *arg, struct kstatfs *buf) ++#else ++#define StatfsLock(s) si_read_lock(s) ++#define StatfsUnlock(s) si_read_unlock(s) ++#define StatfsArg(s) sbr_sb(s, 0) ++#define StatfsHInode(s) (StatfsArg(s)->s_root->d_inode) ++#define StatfsSb(s) (s) ++static int aufs_statfs(struct super_block *arg, struct kstatfs *buf) ++#endif ++{ ++ int err; ++ ++ TraceEnter(); ++ ++ StatfsLock(arg); ++ err = vfsub_statfs(StatfsArg(arg), buf, need_dlgt(StatfsSb(arg))); ++ //if (LktrCond) err = -1; ++ StatfsUnlock(arg); ++ if (!err) { ++ //buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_type = 0; ++ buf->f_namelen -= AUFS_WH_PFX_LEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ //buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; ++ ++ TraceErr(err); ++ return err; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) || defined(UbuntuEdgy17Umount18) ++#define UmountBeginSb(mnt) (mnt)->mnt_sb ++static void aufs_umount_begin(struct vfsmount *arg, int flags) ++#else ++#define UmountBeginSb(sb) sb ++static void aufs_umount_begin(struct super_block *arg) ++#endif ++{ ++ struct super_block *sb = UmountBeginSb(arg); ++ ++ if (unlikely(!stosi(sb))) ++ return; ++ ++ //au_wkq_wait_nwtask(); ++ si_write_lock(sb); ++ if (au_flag_test(sb, AuFlag_PLINK)) { ++ au_put_plink(sb); ++ //kobj_umount(stosi(sb)); ++ } ++#if 0 ++ if (unlikely(au_flag_test(sb, AuFlag_UDBA_INOTIFY))) ++ shrink_dcache_sb(sb); ++#endif ++ si_write_unlock(sb); ++} ++ ++static void free_sbinfo(struct aufs_sbinfo *sbinfo) ++{ ++ TraceEnter(); ++ DEBUG_ON(!sbinfo ++ || !list_empty(&sbinfo->si_plink)); ++ ++ free_branches(sbinfo); ++ kfree(sbinfo->si_branch); ++ kfree(sbinfo); ++} ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ ++ sbinfo = stosi(sb); ++ if (unlikely(!sbinfo)) ++ return; ++ ++ sysaufs_del(sbinfo); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && !defined(UbuntuEdgy17Umount18) ++ // umount_begin() may not be called. ++ aufs_umount_begin(sb); ++#endif ++ free_sbinfo(sbinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh directories at remount time. ++ */ ++static int do_refresh_dir(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *inode; ++ ++ LKTRTrace("%.*s\n", DLNPair(dentry)); ++ inode = dentry->d_inode; ++ DEBUG_ON(!inode || !S_ISDIR(inode->i_mode)); ++ ++ di_write_lock_child(dentry); ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AUFS_I_RLOCK); ++ err = au_refresh_hdentry(dentry, S_IFDIR); ++ if (err >= 0) { ++ err = au_refresh_hinode(inode, dentry); ++ if (!err) ++ au_reset_hinotify(inode, flags); ++ } ++ if (unlikely(err)) ++ Err("unrecoverable error %d\n", err); ++ di_read_unlock(parent, AUFS_I_RLOCK); ++ dput(parent); ++ di_write_unlock(dentry); ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int test_dir(struct dentry *dentry, void *arg) ++{ ++ return S_ISDIR(dentry->d_inode->i_mode); ++} ++ ++static int refresh_dir(struct dentry *root, int sgen) ++{ ++ int err, i, j, ndentry; ++ const unsigned int flags = au_hi_flags(root->d_inode, /*isdir*/1); ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ LKTRTrace("sgen %d\n", sgen); ++ SiMustWriteLock(root->d_sb); ++ DEBUG_ON(au_digen(root) != sgen); ++ DiMustWriteLock(root); ++ ++ err = au_dpages_init(&dpages, GFP_KERNEL); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, test_dir, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ struct dentry *d; ++ d = dentries[j]; ++ DEBUG_ON(!S_ISDIR(d->d_inode->i_mode) ++ || IS_ROOT(d) ++ || au_digen(d->d_parent) != sgen); ++ if (au_digen(d) != sgen) ++ err = do_refresh_dir(d, flags); ++ } ++ } ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ TraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++/* protected by s_umount */ ++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int err, do_refresh; ++ struct dentry *root; ++ struct inode *inode; ++ struct opts opts; ++ unsigned int given, dlgt; ++ ++ //au_debug_on(); ++ LKTRTrace("flags 0x%x, data %s, len %d\n", ++ *flags, data ? data : "NULL", data ? strlen(data) : 0); ++ ++ err = 0; ++ if (unlikely(!data || !*data)) ++ goto out; /* success */ ++ ++ err = -ENOMEM; ++ memset(&opts, 0, sizeof(opts)); ++ opts.opt = (void*)__get_free_page(GFP_KERNEL); ++ //if (LktrCond) {free_page((unsigned long)opts.opt); opts.opt = NULL;} ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ ++ /* parse it before aufs lock */ ++ err = au_parse_opts(sb, data, &opts); ++ //if (LktrCond) {au_free_opts(&opts); err = -1;} ++ if (unlikely(err)) ++ goto out_opts; ++ ++ root = sb->s_root; ++ inode = root->d_inode; ++ i_lock(inode); ++ aufs_write_lock(root); ++ ++ //DbgSleep(3); ++ ++ /* au_do_opts() may return an error */ ++ do_refresh = 0; ++ given = 0; ++ err = au_do_opts_remount(sb, &opts, &do_refresh, &given); ++ //if (LktrCond) err = -1; ++ au_free_opts(&opts); ++ ++ if (do_refresh) { ++ int rerr; ++ struct aufs_sbinfo *sbinfo; ++ ++ dlgt = au_flag_test(sb, AuFlag_DLGT); ++ au_flag_clr(sb, AuFlag_DLGT); ++ au_sigen_inc(sb); ++ au_reset_hinotify(inode, au_hi_flags(inode, /*isdir*/1)); ++ sbinfo = stosi(sb); ++ sbinfo->si_failed_refresh_dirs = 0; ++ rerr = refresh_dir(root, au_sigen(sb)); ++ if (unlikely(rerr)) { ++ sbinfo->si_failed_refresh_dirs = 1; ++ Warn("Refreshing directories failed, ignores (%d)\n", ++ rerr); ++ } ++ au_cpup_attr_all(inode); ++ au_flag_set(sb, dlgt); ++ } ++ ++ aufs_write_unlock(root); ++ i_unlock(inode); ++ /* braces are added to stop a warning */ ++ if (do_refresh) { ++ sysaufs_notify_remount(); ++ } ++ ++ out_opts: ++ free_page((unsigned long)opts.opt); ++ out: ++ err = cvt_err(err); ++ TraceErr(err); ++ //au_debug_off(); ++ return err; ++} ++ ++static struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ .read_inode = aufs_read_inode, ++ //.dirty_inode = aufs_dirty_inode, ++ //.write_inode = aufs_write_inode, ++ //void (*put_inode) (struct inode *); ++ .drop_inode = generic_delete_inode, ++ //.delete_inode = aufs_delete_inode, ++ //.clear_inode = aufs_clear_inode, ++ ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ ++ .put_super = aufs_put_super, ++ //void (*write_super) (struct super_block *); ++ //int (*sync_fs)(struct super_block *sb, int wait); ++ //void (*write_super_lockfs) (struct super_block *); ++ //void (*unlockfs) (struct super_block *); ++ .remount_fs = aufs_remount_fs, ++ // depends upon umount flags. also use put_super() (< 2.6.18) ++ .umount_begin = aufs_umount_begin ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * at first mount time. ++ */ ++ ++static int alloc_sbinfo(struct super_block *sb) ++{ ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ ++ sbinfo = kmalloc(sizeof(*sbinfo), GFP_KERNEL); ++ //if (LktrCond) {kfree(sbinfo); sbinfo = NULL;} ++ if (unlikely(!sbinfo)) ++ goto out; ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_KERNEL); ++ //if (LktrCond) {kfree(sbinfo->si_branch); sbinfo->si_branch = NULL;} ++ if (unlikely(!sbinfo->si_branch)) { ++ kfree(sbinfo); ++ goto out; ++ } ++ rw_init_wlock(&sbinfo->si_rwsem); ++ sbinfo->si_bend = -1; ++ atomic_long_set(&sbinfo->si_xino, AUFS_FIRST_INO); ++ spin_lock_init(&sbinfo->si_plink_lock); ++ INIT_LIST_HEAD(&sbinfo->si_plink); ++ init_lvma(sbinfo); ++ sbinfo->si_generation = 0; ++ sbinfo->si_last_br_id = 0; ++ sbinfo->si_failed_refresh_dirs = 0; ++ sbinfo->si_flags = 0; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ sbinfo->si_rdcache = AUFS_RDCACHE_DEF * HZ; ++ //atomic_set(&sbinfo->si_hinotify, 0); ++ //init_waitqueue_head(&sbinfo->si_hinotify_wq); ++ ++ sb->s_fs_info = sbinfo; ++ au_flag_set(sb, AuDefFlags); ++#ifdef ForceInotify ++ udba_set(sb, AuFlag_UDBA_INOTIFY); ++#endif ++#ifdef ForceDlgt ++ au_flag_set(sb, AuFlag_DLGT); ++#endif ++#ifdef ForceNoPlink ++ au_flag_clr(sb, AuFlag_PLINK); ++#endif ++ return 0; /* success */ ++ ++ out: ++ TraceErr(-ENOMEM); ++ return -ENOMEM; ++} ++ ++static int alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ TraceEnter(); ++ ++ err = -ENOMEM; ++ inode = iget(sb, AUFS_ROOT_INO); ++ //if (LktrCond) {iput(inode); inode = NULL;} ++ if (unlikely(!inode)) ++ goto out; ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ err = -ENOMEM; ++ if (unlikely(is_bad_inode(inode))) ++ goto out_iput; ++ ++ root = d_alloc_root(inode); ++ //if (LktrCond) {igrab(inode); dput(root); root = NULL;} ++ if (unlikely(!root)) ++ goto out_iput; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out_iput; ++ ++ err = au_alloc_dinfo(root); ++ //if (LktrCond){rw_write_unlock(&dtodi(root)->di_rwsem);err=-1;} ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ goto out; /* do not iput */ ++ ++ out_iput: ++ iput(inode); ++ out: ++ TraceErr(err); ++ return err; ++ ++} ++ ++static int aufs_fill_super(struct super_block *sb, void *raw_data, int silent) ++{ ++ int err; ++ struct dentry *root; ++ struct inode *inode; ++ struct opts opts; ++ char *arg = raw_data; ++ ++ //au_debug_on(); ++ if (unlikely(!arg || !*arg)) { ++ err = -EINVAL; ++ Err("no arg\n"); ++ goto out; ++ } ++ LKTRTrace("%s, silent %d\n", arg, silent); ++ ++ err = -ENOMEM; ++ memset(&opts, 0, sizeof(opts)); ++ opts.opt = (void*)__get_free_page(GFP_KERNEL); ++ //if (LktrCond) {free_page((unsigned long)opts.opt); opts.opt = NULL;} ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ ++ err = alloc_sbinfo(sb); ++ //if (LktrCond) {si_write_unlock(sb);free_sbinfo(stosi(sb));err=-1;} ++ if (unlikely(err)) ++ goto out_opts; ++ SiMustWriteLock(sb); ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME; ++ sb->s_op = &aufs_sop; ++ au_init_export_op(sb); ++ //err = kobj_mount(stosi(sb)); ++ //if (err) ++ //goto out_info; ++ ++ err = alloc_root(sb); ++ //if (LktrCond) {rw_write_unlock(&dtodi(sb->s_root)->di_rwsem); ++ //dput(sb->s_root);sb->s_root=NULL;err=-1;} ++ if (unlikely(err)) { ++ DEBUG_ON(sb->s_root); ++ si_write_unlock(sb); ++ goto out_info; ++ } ++ root = sb->s_root; ++ DiMustWriteLock(root); ++ inode = root->d_inode; ++ inode->i_nlink = 2; ++ ++ /* ++ * actually we can parse options regardless aufs lock here. ++ * but at remount time, parsing must be done before aufs lock. ++ * so we follow the same rule. ++ */ ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ err = au_parse_opts(sb, arg, &opts); ++ //if (LktrCond) {au_free_opts(&opts); err = -1;} ++ if (unlikely(err)) ++ goto out_root; ++ ++ /* lock vfs_inode first, then aufs. */ ++ i_lock(inode); ++ inode->i_op = &aufs_dir_iop; ++ inode->i_fop = &aufs_dir_fop; ++ aufs_write_lock(root); ++ ++ sb->s_maxbytes = 0; ++ err = au_do_opts_mount(sb, &opts); ++ //if (LktrCond) err = -1; ++ au_free_opts(&opts); ++ if (unlikely(err)) ++ goto out_unlock; ++ DEBUG_ON(!sb->s_maxbytes); ++ ++ //DbgDentry(root); ++ aufs_write_unlock(root); ++ i_unlock(inode); ++ //DbgSb(sb); ++ goto out_opts; /* success */ ++ ++ out_unlock: ++ aufs_write_unlock(root); ++ i_unlock(inode); ++ out_root: ++ dput(root); ++ sb->s_root = NULL; ++ out_info: ++ free_sbinfo(stosi(sb)); ++ sb->s_fs_info = NULL; ++ out_opts: ++ free_page((unsigned long)opts.opt); ++ out: ++ TraceErr(err); ++ err = cvt_err(err); ++ TraceErr(err); ++ //au_debug_off(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++static int aufs_get_sb(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *raw_data, ++ struct vfsmount *mnt) ++{ ++ int err; ++ ++ /* all timestamps always follow the ones on the branch */ ++ //mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; ++ err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt); ++ if (!err) { ++ struct aufs_sbinfo *sbinfo = stosi(mnt->mnt_sb); ++ sbinfo->si_mnt = mnt; ++ sysaufs_add(sbinfo); ++ } ++ return err; ++} ++#else ++static struct super_block *aufs_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, ++ void *raw_data) ++{ ++ return get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super); ++} ++#endif ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ .fs_flags = FS_REVAL_DOT, // for UDBA and NFS branch ++ .get_sb = aufs_get_sb, ++ .kill_sb = generic_shutdown_super, ++ //no need to __module_get() and module_put(). ++ .owner = THIS_MODULE, ++}; +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/super.h linux-2.6.22.1/fs/aufs/super.h +--- linux-2.6.22.1.oorig/fs/aufs/super.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/super.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,339 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: super.h,v 1.44 2007/05/14 03:39:54 sfjro Exp $ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "misc.h" ++#include "sysaufs.h" ++ ++#ifdef CONFIG_AUFS_SYSAUFS ++/* entries under sysfs per mount-point */ ++enum {SysaufsSb_XINO, /* SysaufsSb_PLINK, */ SysaufsSb_Last}; ++struct sysaufs_sbinfo { ++ au_subsys_t subsys; ++ struct sysaufs_entry array[SysaufsSb_Last]; ++}; ++extern sysaufs_op au_si_ops[]; ++#else ++struct sysaufs_sbinfo {}; ++#endif ++ ++struct aufs_sbinfo { ++ struct aufs_rwsem si_rwsem; ++ ++ /* branch management */ ++ /* wrap around attack by superuser? No. */ ++ int si_generation; ++ ++ /* ++ * set true when refresh_dirs() at remount time failed. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecesary ++ */ ++ unsigned int si_failed_refresh_dirs:1; ++ ++ aufs_bindex_t si_bend; ++ aufs_bindex_t si_last_br_id; ++ struct aufs_branch **si_branch; ++ ++ /* mount flags */ ++ unsigned int si_flags; ++ ++ /* external inode number table */ ++ atomic_long_t si_xino; // time bomb ++ //struct file *si_xino_bmap; ++ ++ /* readdir cache time, max, in HZ */ ++ unsigned long si_rdcache; ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after rename_whtmp to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* pseudo_link list */ // dirty ++ spinlock_t si_plink_lock; ++ struct list_head si_plink; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++ /* super_blocks list is not exported */ ++ struct list_head si_list; ++ struct vfsmount *si_mnt; /* no get/put */ ++#endif ++ ++ /* sysfs */ ++ struct sysaufs_sbinfo si_sysaufs; ++ ++#ifdef CONFIG_AUFS_HINOTIFY ++ /* hinotify */ ++ //atomic_t si_hinotify; ++ //wait_queue_head_t si_hinotify_wq; ++#endif ++ ++#ifdef CONFIG_AUFS_ROBR ++ /* locked vma list for mmap() */ // very dirty ++ spinlock_t si_lvma_lock; ++ struct list_head si_lvma; ++#endif ++}; ++ ++/* an entry in a xino file */ ++struct xino { ++ ino_t ino; ++ //__u32 h_gen; ++} __attribute__ ((packed)); ++ ++//#define AuXino_INVALID_HGEN (-1) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Mount flags */ ++#define AuFlag_XINO 1 ++#define AuFlag_ZXINO (1 << 1) ++#define AuFlag_PLINK (1 << 2) ++#define AuFlag_UDBA_NONE (1 << 3) ++#define AuFlag_UDBA_REVAL (1 << 4) ++#define AuFlag_UDBA_INOTIFY (1 << 5) ++#define AuFlag_WARN_PERM (1 << 6) ++#define AuFlag_COO_NONE (1 << 7) ++#define AuFlag_COO_LEAF (1 << 8) ++#define AuFlag_COO_ALL (1 << 9) ++#define AuFlag_ALWAYS_DIROPQ (1 << 10) ++#define AuFlag_DLGT (1 << 11) ++ ++#define AuMask_UDBA (AuFlag_UDBA_NONE | AuFlag_UDBA_REVAL \ ++ | AuFlag_UDBA_INOTIFY) ++#define AuMask_COO (AuFlag_COO_NONE | AuFlag_COO_LEAF \ ++ | AuFlag_COO_ALL) ++ ++#ifdef CONFIG_AUFS_COMPAT ++#define AuDefFlag_DIROPQ AuFlag_ALWAYS_DIROPQ ++#else ++#define AuDefFlag_DIROPQ 0 ++#endif ++ ++#define AuDefFlags_COMM (AuFlag_XINO | AuFlag_UDBA_REVAL | AuFlag_WARN_PERM \ ++ | AuFlag_COO_NONE | AuDefFlag_DIROPQ) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++#define AuDefFlags (AuDefFlags_COMM | AuFlag_PLINK) ++#else ++#define AuDefFlags AuDefFlags_COMM ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for aufs_read_lock()/di_read_lock() */ ++#define AUFS_D_WLOCK 1 ++#define AUFS_I_RLOCK 2 ++#define AUFS_I_WLOCK 4 ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++int au_show_brs(struct seq_file *seq, struct super_block *sb); ++ ++/* xino.c */ ++struct file *xino_create(struct super_block *sb, char *fname, int silent, ++ struct dentry *parent); ++ino_t xino_new_ino(struct super_block *sb); ++int xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino); ++int xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ struct xino *xino); ++int xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ struct xino *xino); ++int xino_init(struct super_block *sb, aufs_bindex_t bindex, ++ struct file *base_file, int do_test); ++struct opt_xino; ++int xino_set(struct super_block *sb, struct opt_xino *xino, int remount); ++int xino_clr(struct super_block *sb); ++struct file *xino_def(struct super_block *sb); ++ ++/* sbinfo.c */ ++struct aufs_sbinfo *stosi(struct super_block *sb); ++aufs_bindex_t sbend(struct super_block *sb); ++struct aufs_branch *stobr(struct super_block *sb, aufs_bindex_t bindex); ++int au_sigen(struct super_block *sb); ++int au_sigen_inc(struct super_block *sb); ++int find_bindex(struct super_block *sb, struct aufs_branch *br); ++ ++void aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++aufs_bindex_t new_br_id(struct super_block *sb); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_is_aufs(struct super_block *sb) ++{ ++ return !strcmp(au_sbtype(sb), AUFS_FSTYPE); ++} ++ ++static inline int au_is_nfs(struct super_block *sb) ++{ ++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) ++ return !strcmp(au_sbtype(sb), "nfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_is_remote(struct super_block *sb) ++{ ++ return au_is_nfs(sb); ++} ++ ++#ifdef CONFIG_AUFS_EXPORT ++static inline void au_init_export_op(struct super_block *sb) ++{ ++ extern struct export_operations aufs_export_op; ++ sb->s_export_op = &aufs_export_op; ++} ++ ++static inline int au_is_nfsd(struct task_struct *tsk) ++{ ++ return (!tsk->mm && !strcmp(tsk->comm, "nfsd")); ++} ++ ++static inline void au_nfsd_lockdep_off(void) ++{ ++ /* braces are added to stop a warning */ ++ if (au_is_nfsd(current)) { ++ lockdep_off(); ++ } ++} ++ ++static inline void au_nfsd_lockdep_on(void) ++{ ++ /* braces are added to stop a warning */ ++ if (au_is_nfsd(current)) { ++ lockdep_on(); ++ } ++} ++#else ++static inline int au_is_nfsd(struct task_struct *tsk) ++{ ++ return 0; ++} ++static inline void au_init_export_op(struct super_block *sb) ++{ ++ /* nothing */ ++} ++#define au_nfsd_lockdep_off() /* */ ++#define au_nfsd_lockdep_on() /* */ ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++static inline void init_lvma(struct aufs_sbinfo *sbinfo) ++{ ++#ifdef CONFIG_AUFS_ROBR ++ spin_lock_init(&sbinfo->si_lvma_lock); ++ INIT_LIST_HEAD(&sbinfo->si_lvma); ++#else ++ /* nothing */ ++#endif ++} ++ ++/* limited support before 2.6.18 */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++static inline void au_mntget(struct super_block *sb) ++{ ++ mntget(stosi(sb)->si_mnt); ++} ++ ++static inline void au_mntput(struct super_block *sb) ++{ ++ mntput(stosi(sb)->si_mnt); ++} ++#else ++static inline void au_mntget(struct super_block *sb) ++{ ++ /* empty */ ++} ++ ++static inline void au_mntput(struct super_block *sb) ++{ ++ /* empty */ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void au_flag_set(struct super_block *sb, unsigned int flag) ++{ ++ //SiMustWriteLock(sb); ++ stosi(sb)->si_flags |= flag; ++} ++ ++static inline void au_flag_clr(struct super_block *sb, unsigned int flag) ++{ ++ //SiMustWriteLock(sb); ++ stosi(sb)->si_flags &= ~flag; ++} ++ ++static inline ++unsigned int au_flag_test(struct super_block *sb, unsigned int flag) ++{ ++ //SiMustAnyLock(sb); ++ return stosi(sb)->si_flags & flag; ++} ++ ++static inline unsigned int au_flag_test_udba(struct super_block *sb) ++{ ++ return au_flag_test(sb, AuMask_UDBA); ++} ++ ++static inline unsigned int au_flag_test_coo(struct super_block *sb) ++{ ++ return au_flag_test(sb, AuMask_COO); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++/* ++ * si_read_lock, si_write_lock, ++ * si_read_unlock, si_write_unlock, si_downgrade_lock ++ */ ++SimpleRwsemFuncs(si, struct super_block *sb, stosi(sb)->si_rwsem); ++ ++/* to debug easier, do not make them inlined functions */ ++#define SiMustReadLock(sb) RwMustReadLock(&stosi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) RwMustWriteLock(&stosi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) RwMustAnyLock(&stosi(sb)->si_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/sysaufs.c linux-2.6.22.1/fs/aufs/sysaufs.c +--- linux-2.6.22.1.oorig/fs/aufs/sysaufs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/sysaufs.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,620 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: sysaufs.c,v 1.6 2007/05/14 03:40:10 sfjro Exp $ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super_blocks list is not exported */ ++static DEFINE_MUTEX(aufs_sbilist_mtx); ++static LIST_HEAD(aufs_sbilist); ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef ssize_t (*rwfunc_t)(struct kobject *kobj, char *buf, loff_t offset, ++ size_t sz, struct sysaufs_args *args); ++static ssize_t sysaufs_read(struct kobject *kobj, char *buf, loff_t offset, ++ size_t sz, struct sysaufs_args *args); ++static ssize_t sysaufs_free_write(struct kobject *kobj, char *buf, loff_t ++ offset, size_t sz, struct sysaufs_args *args); ++ ++#define GFunc(name, _index, func) \ ++static ssize_t name(struct kobject *kobj, char *buf, loff_t offset, size_t sz) \ ++{ \ ++ struct sysaufs_args args = { \ ++ .index = (_index), \ ++ .mtx = &aufs_sbilist_mtx, \ ++ .sb = NULL \ ++ }; \ ++ return func(kobj, buf, offset, sz, &args); \ ++} ++ ++#define GFuncs(name, _index) \ ++ GFunc(read_##name, _index, sysaufs_read); \ ++ GFunc(write_##name, _index, sysaufs_free_write); ++ ++static struct super_block *find_sb_locked(struct kobject *kobj) ++{ ++ struct super_block *sb; ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ MtxMustLock(&aufs_sbilist_mtx); ++ ++ sb = NULL; ++ list_for_each_entry(sbinfo, &aufs_sbilist, si_list) { ++ if (&au_subsys_to_kset(sbinfo->si_sysaufs.subsys).kobj != kobj) ++ continue; ++ sb = sbinfo->si_mnt->mnt_sb; ++ si_read_lock(sb); ++ break; ++ } ++ return sb; ++} ++ ++static ssize_t sb_func(struct kobject *kobj, char *buf, loff_t offset, ++ size_t sz, struct sysaufs_args *args, rwfunc_t func) ++{ ++ ssize_t err; ++ ++ err = -ENOENT; ++ mutex_lock(&aufs_sbilist_mtx); ++ args->sb = find_sb_locked(kobj); ++ if (args->sb) { ++ err = func(kobj, buf, offset, sz, args); ++ si_read_unlock(args->sb); ++ } ++ mutex_unlock(&aufs_sbilist_mtx); ++ return err; ++} ++ ++#define SbFunc(name, _index, func) \ ++static ssize_t name(struct kobject *kobj, char *buf, loff_t offset, size_t sz) \ ++{ \ ++ struct sysaufs_args args = { \ ++ .index = (_index), \ ++ .mtx = NULL \ ++ }; \ ++ return sb_func(kobj, buf, offset, sz, &args, func); \ ++} ++ ++#define SbFuncs(name, index) \ ++ SbFunc(read_##name, index, sysaufs_read); \ ++ SbFunc(write_##name, index, sysaufs_free_write) ++ ++static decl_subsys(aufs, NULL, NULL); ++enum {Brs, Stat, Config, _Last}; ++static struct sysaufs_entry g_array[_Last]; ++GFuncs(brs, Brs); ++GFuncs(stat, Stat); ++GFuncs(config, Config); ++ ++SbFuncs(xino, SysaufsSb_XINO); ++ ++#define SetEntry(e, _name, init_size, _ops) \ ++ do { \ ++ (e)->attr.attr.name = #_name; \ ++ (e)->attr.attr.owner = THIS_MODULE; \ ++ (e)->attr.attr.mode = S_IRUGO | S_IWUSR; \ ++ (e)->attr.read = read_##_name; \ ++ (e)->attr.write = write_##_name; \ ++ (e)->allocated = init_size; \ ++ (e)->err = -1; \ ++ (e)->ops = _ops; \ ++ } while (0) ++ ++#define Priv(e) (e)->attr.private ++#define Allocated(e) (e)->allocated ++#define Len(e) (e)->attr.size ++#define Name(e) attr_name((e)->attr) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void free_entry(struct sysaufs_entry *e) ++{ ++ MtxMustLock(&aufs_sbilist_mtx); ++ DEBUG_ON(!Priv(e)); ++ ++ if (Allocated(e) > 0) ++ kfree(Priv(e)); ++ else ++ free_pages((unsigned long)Priv(e), -Allocated(e)); ++ Priv(e) = NULL; ++ Len(e) = 0; ++} ++ ++static void free_entries(void) ++{ ++ static int a[] = {Brs, -1}; ++ int *p = a; ++ ++ MtxMustLock(&aufs_sbilist_mtx); ++ ++ while (*p >= 0) { ++ if (Priv(g_array + *p)) ++ free_entry(g_array + *p); ++ p++; ++ } ++} ++ ++static int alloc_entry(struct sysaufs_entry *e) ++{ ++ MtxMustLock(&aufs_sbilist_mtx); ++ DEBUG_ON(Priv(e)); ++ //Dbg("%d\n", Allocated(e)); ++ ++ if (Allocated(e) > 0) ++ Priv(e) = kmalloc(Allocated(e), GFP_KERNEL); ++ else ++ Priv(e) = (void*)__get_free_pages(GFP_KERNEL, -Allocated(e)); ++ if (Priv(e)) ++ return 0; ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void unreg(au_subsys_t *subsys, struct sysaufs_entry *a, int n, ++ au_subsys_t *parent) ++{ ++ int i; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < n; i++, a++) ++ if (!a->err) { ++ sysfs_remove_bin_file ++ (&au_subsys_to_kset(*subsys).kobj, &a->attr); ++ if (Priv(a)) ++ free_entry(a); ++ } ++ ++ subsystem_unregister(subsys); ++ subsys_put(parent); ++} ++ ++static int reg(au_subsys_t *subsys, struct sysaufs_entry *a, int n, ++ au_subsys_t *parent) ++{ ++ int err, i; ++ ++ TraceEnter(); ++ ++ subsys_get(parent); ++ kobj_set_kset_s(&au_subsys_to_kset(*subsys), *parent); ++ err = subsystem_register(subsys); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < n; i++) ++ err = a[i].err = sysfs_create_bin_file ++ (&au_subsys_to_kset(*subsys).kobj, &a[i].attr); ++ if (unlikely(err)) ++ unreg(subsys, a, n, parent); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define SbSetEntry(index, name, init_size) \ ++ SetEntry(sa->array + index, name, init_size, au_si_ops); ++ ++void sysaufs_add(struct aufs_sbinfo *sbinfo) ++{ ++ int err; ++ struct sysaufs_sbinfo *sa = &sbinfo->si_sysaufs; ++ ++ TraceEnter(); ++ ++ mutex_lock(&aufs_sbilist_mtx); ++ list_add_tail(&sbinfo->si_list, &aufs_sbilist); ++ free_entries(); ++ ++ memset(sa, 0, sizeof(*sa)); ++ SbSetEntry(SysaufsSb_XINO, xino, 128); ++ err = kobject_set_name(&au_subsys_to_kset(sa->subsys).kobj, "%p", ++ sbinfo->si_mnt->mnt_sb); ++ if (!err) ++ err = reg(&sa->subsys, sa->array, ARRAY_SIZE(sa->array), ++ &aufs_subsys); ++ if (unlikely(err)) ++ Warn("failed adding sysfs (%d)\n", err); ++ ++ mutex_unlock(&aufs_sbilist_mtx); ++} ++ ++void sysaufs_del(struct aufs_sbinfo *sbinfo) ++{ ++ struct sysaufs_sbinfo *sa = &sbinfo->si_sysaufs; ++ ++ TraceEnter(); ++ ++ mutex_lock(&aufs_sbilist_mtx); ++ unreg(&sa->subsys, sa->array, ARRAY_SIZE(sa->array), &aufs_subsys); ++ list_del(&sbinfo->si_list); ++ free_entries(); ++ mutex_unlock(&aufs_sbilist_mtx); ++} ++ ++void sysaufs_notify_remount(void) ++{ ++ mutex_lock(&aufs_sbilist_mtx); ++ free_entries(); ++ mutex_unlock(&aufs_sbilist_mtx); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int make_brs(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size) ++{ ++ int err; ++ struct aufs_sbinfo *sbinfo; ++ ++ TraceEnter(); ++ MtxMustLock(&aufs_sbilist_mtx); ++ DEBUG_ON(args->index != Brs); ++ ++ err = 0; ++ list_for_each_entry(sbinfo, &aufs_sbilist, si_list) { ++ struct super_block *sb; ++ struct dentry *root; ++ struct vfsmount *mnt; ++ ++ sb = sbinfo->si_mnt->mnt_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, !AUFS_I_RLOCK); ++ mnt = sbinfo->si_mnt; ++ err = seq_escape ++ (seq, mnt->mnt_devname ? mnt->mnt_devname : "none", ++ au_esc_chars); ++ if (!err) ++ err = seq_putc(seq, ' '); ++ if (!err) ++ err = seq_path(seq, mnt, root, au_esc_chars); ++ if (err > 0) ++ err = seq_printf(seq, " %p br:", sb); ++ if (!err) ++ err = au_show_brs(seq, sb); ++ aufs_read_unlock(root, !AUFS_I_RLOCK); ++ if (!err) ++ err = seq_putc(seq, '\n'); ++ else ++ break; ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int make_config(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size) ++{ ++ int err; ++ ++ TraceEnter(); ++ DEBUG_ON(args->index != Config); ++ ++#ifdef CONFIG_AUFS ++ err = seq_puts(seq, "CONFIG_AUFS=y\n"); ++#else ++ err = seq_puts(seq, "CONFIG_AUFS=m\n"); ++#endif ++ ++#define puts(m, v) \ ++ if (!err) err = seq_puts(seq, "CONFIG_AUFS_" #m "=" #v "\n") ++#define puts_bool(m) puts(m, y) ++#define puts_mod(m) puts(m, m) ++ ++#ifdef CONFIG_AUFS_FAKE_DM ++ puts_bool(FAKE_DM); ++#endif ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++ puts_bool(BRANCH_MAX_127); ++#elif defined(CONFIG_AUFS_BRANCH_MAX_511) ++ puts_bool(BRANCH_MAX_511); ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++ puts_bool(BRANCH_MAX_1023); ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++ puts_bool(BRANCH_MAX_32767); ++#endif ++ puts_bool(SYSAUFS); ++#ifdef CONFIG_AUFS_HINOTIFY ++ puts_bool(HINOTIFY); ++#endif ++#ifdef CONFIG_AUFS_EXPORT ++ puts_bool(EXPORT); ++#endif ++#ifdef CONFIG_AUFS_ROBR ++ puts_bool(ROBR); ++#endif ++#ifdef CONFIG_AUFS_DLGT ++ puts_bool(DLGT); ++#endif ++#ifdef CONFIG_AUFS_LHASH_PATCH ++ puts_bool(LHASH_PATCH); ++#endif ++#ifdef CONFIG_AUFS_KSIZE_PATCH ++ puts_bool(KSIZE_PATCH); ++#endif ++#ifdef CONFIG_AUFS_DEBUG ++ puts_bool(DEBUG); ++#endif ++#ifdef CONFIG_AUFS_COMPAT ++ puts_bool(COMPAT); ++#endif ++ ++#undef puts_bool ++#undef puts ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int make_stat(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size) ++{ ++ int err, i; ++ ++ TraceEnter(); ++ DEBUG_ON(args->index != Stat); ++ ++ *do_size = 0; ++ err = seq_puts(seq, "wkq max_busy:"); ++ for (i = 0; !err && i < aufs_nwkq; i++) ++ err = seq_printf(seq, " %u", au_wkq[i].max_busy); ++ if (!err) ++ err = seq_printf(seq, ", %u(generic)\n", ++ au_wkq[aufs_nwkq].max_busy); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int make(struct sysaufs_entry *e, struct sysaufs_args *args, ++ int *do_size) ++ ++{ ++ int err; ++ struct seq_file *seq; ++ ++ TraceEnter(); ++ DEBUG_ON(Priv(e)); ++ MtxMustLock(&aufs_sbilist_mtx); ++ ++ err = -ENOMEM; ++ seq = kzalloc(sizeof(*seq), GFP_KERNEL); ++ if (unlikely(!seq)) ++ goto out; ++ ++ Len(e) = 0; ++ while (1) { ++ err = alloc_entry(e); ++ if (unlikely(err)) ++ break; ++ ++ //mutex_init(&seq.lock); ++ seq->buf = Priv(e); ++ seq->count = 0; ++ seq->size = Allocated(e); ++ if (unlikely(Allocated(e) <= 0)) ++ seq->size = PAGE_SIZE << -Allocated(e); ++ ++ err = e->ops[args->index](seq, args, do_size); ++ if (!err) { ++ Len(e) = seq->count; ++ break; /* success */ ++ } ++ ++ free_entry(e); ++ if (Allocated(e) > 0) { ++ Allocated(e) <<= 1; ++ if (unlikely(Allocated(e) >= (int)PAGE_SIZE)) ++ Allocated(e) = 0; ++ } else ++ Allocated(e)--; ++ //Dbg("%d\n", Allocated(e)); ++ } ++ kfree(seq); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* why does sysfs pass my parent kobject? */ ++static struct dentry *find_me(struct dentry *parent, struct sysaufs_entry *e) ++{ ++#if 1 ++ struct dentry *dentry; ++ const char *name = Name(e); ++ const unsigned int len = strlen(name); ++ ++ //Dbg("%.*s\n", DLNPair(parent)); ++ spin_lock(&dcache_lock); ++ list_for_each_entry(dentry, &parent->d_subdirs, D_CHILD) { ++ //Dbg("%.*s\n", DLNPair(dentry)); ++ if (len == dentry->d_name.len ++ && !strcmp(dentry->d_name.name, name)) { ++ spin_unlock(&dcache_lock); ++ return dentry; ++ } ++ } ++ spin_unlock(&dcache_lock); ++#endif ++ return NULL; ++} ++ ++static ssize_t sysaufs_read(struct kobject *kobj, char *buf, loff_t offset, ++ size_t sz, struct sysaufs_args *args) ++{ ++ ssize_t err; ++ loff_t len; ++ struct dentry *d; ++ struct sysaufs_entry *e; ++ int do_size; ++ ++ LKTRTrace("{%d, %p}, offset %Ld, sz %lu\n", ++ args->index, args->sb, offset, (unsigned long)sz); ++ ++ if (unlikely(!sz)) ++ return 0; ++ ++ err = 0; ++ d = NULL; ++ e = g_array + args->index; ++ if (args->sb) ++ e = stosi(args->sb)->si_sysaufs.array + args->index; ++ ++ do_size = 1; ++ if (args->mtx) ++ mutex_lock(args->mtx); ++ if (unlikely(!Priv(e))) { ++ err = make(e, args, &do_size); ++ DEBUG_ON(Len(e) > INT_MAX); ++ if (do_size) { ++ d = find_me(kobj->dentry, e); ++ if (d) ++ i_size_write(d->d_inode, Len(e)); ++ } ++ } ++ ++ if (!err) { ++ err = len = Len(e) - offset; ++ LKTRTrace("%Ld\n", len); ++ if (len > 0) { ++ if (len > sz) ++ err = sz; ++ memcpy(buf, Priv(e) + offset, err); ++ } ++ ++ if (!do_size) ++ free_entry(e); ++ } ++ if (args->mtx) ++ mutex_unlock(args->mtx); ++ ++ TraceErr(err); ++ return err; ++} ++ ++static ssize_t sysaufs_free_write(struct kobject *kobj, char *buf, ++ loff_t offset, size_t sz, ++ struct sysaufs_args *args) ++{ ++ struct dentry *d; ++ int allocated, len; ++ struct sysaufs_entry *e; ++ ++ LKTRTrace("{%d, %p}\n", args->index, args->sb); ++ ++ e = g_array + args->index; ++ if (args->sb) ++ e = stosi(args->sb)->si_sysaufs.array + args->index; ++ ++ if (args->mtx) ++ mutex_lock(args->mtx); ++ if (Priv(e)) { ++ allocated = Allocated(e); ++ if (unlikely(allocated <= 0)) ++ allocated = PAGE_SIZE << -allocated; ++ allocated >>= 1; ++ len = Len(e); ++ ++ free_entry(e); ++ if (unlikely(len <= allocated)) { ++ if (Allocated(e) >= 0) ++ Allocated(e) = allocated; ++ else ++ Allocated(e)++; ++ } ++ ++ d = find_me(kobj->dentry, e); ++ if (d && i_size_read(d->d_inode)) ++ i_size_write(d->d_inode, 0); ++ } ++ if (args->mtx) ++ mutex_unlock(args->mtx); ++ ++ return sz; ++} ++ ++static sysaufs_op g_ops[] = { ++ [Brs] = make_brs, ++ [Stat] = make_stat, ++ [Config] = make_config ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define GSetEntry(index, name, init_size) \ ++ SetEntry(g_array + index, name, init_size, g_ops) ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ GSetEntry(Brs, brs, 128); ++ GSetEntry(Stat, stat, 32); ++ GSetEntry(Config, config, 256); ++ err = reg(&aufs_subsys, g_array, ARRAY_SIZE(g_array), &fs_subsys); ++ TraceErr(err); ++ return err; ++} ++ ++void __exit sysaufs_fin(void) ++{ ++ mutex_lock(&aufs_sbilist_mtx); ++ unreg(&aufs_subsys, g_array, ARRAY_SIZE(g_array), &fs_subsys); ++ mutex_unlock(&aufs_sbilist_mtx); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef DbgDlgt ++int is_branch(struct super_block *h_sb) ++{ ++ int found = 0; ++ struct aufs_sbinfo *sbinfo; ++ ++ //Dbg("here\n"); ++ mutex_lock(&aufs_sbilist_mtx); ++ list_for_each_entry(sbinfo, &aufs_sbilist, si_list) { ++ aufs_bindex_t bindex, bend; ++ struct super_block *sb; ++ ++ sb = sbinfo->si_mnt->mnt_sb; ++ si_read_lock(sb); ++ bend = sbend(sb); ++ for (bindex = 0; !found && bindex <= bend; bindex++) ++ found = (h_sb == sbr_sb(sb, bindex)); ++ si_read_unlock(sb); ++ } ++ mutex_unlock(&aufs_sbilist_mtx); ++ return found; ++} ++#endif +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/sysaufs.h linux-2.6.22.1/fs/aufs/sysaufs.h +--- linux-2.6.22.1.oorig/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/sysaufs.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: sysaufs.h,v 1.3 2007/05/14 06:27:18 sfjro Exp $ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++typedef struct kset au_subsys_t; ++#define au_subsys_to_kset(subsys) (subsys) ++#else ++typedef struct subsystem au_subsys_t; ++#define au_subsys_to_kset(subsys) ((subsys).kset) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* arguments for an entry under sysfs */ ++struct sysaufs_args { ++ int index; ++ struct mutex *mtx; ++ struct super_block *sb; ++}; ++ ++typedef int (*sysaufs_op)(struct seq_file *seq, struct sysaufs_args *args, ++ int *do_size); ++ ++/* an entry under sysfs */ ++struct sysaufs_entry { ++ struct bin_attribute attr; ++ int allocated; /* zero minus means pages */ ++ int err; ++ sysaufs_op *ops; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_sbinfo; ++#ifdef CONFIG_AUFS_SYSAUFS ++void sysaufs_add(struct aufs_sbinfo *sbinfo); ++void sysaufs_del(struct aufs_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++void sysaufs_notify_remount(void); ++#else ++static inline void sysaufs_add(struct aufs_sbinfo *sbinfo) ++{ ++ /* nothing */ ++} ++ ++static inline void sysaufs_del(struct aufs_sbinfo *sbinfo) ++{ ++ /* nothing */ ++} ++#define sysaufs_init() 0 ++#define sysaufs_fin() /* */ ++#define sysaufs_notify_remount() /* */ ++#endif /* CONFIG_AUFS_SYSAUFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/vdir.c linux-2.6.22.1/fs/aufs/vdir.c +--- linux-2.6.22.1.oorig/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/vdir.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,802 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: vdir.c,v 1.22 2007/05/14 03:38:52 sfjro Exp $ */ ++ ++#include "aufs.h" ++ ++static int calc_size(int namelen) ++{ ++ int sz; ++ ++ sz = sizeof(struct aufs_de) + namelen; ++ if (sizeof(ino_t) == sizeof(long)) { ++ const int mask = sizeof(ino_t) - 1; ++ if (sz & mask) { ++ sz += sizeof(ino_t); ++ sz &= ~mask; ++ } ++ } else { ++#if 0 // remove ++ BUG(); ++ // this block will be discarded by optimizer. ++ int m; ++ m = sz % sizeof(ino_t); ++ if (m) ++ sz += sizeof(ino_t) - m; ++#endif ++ } ++ ++ DEBUG_ON(sz % sizeof(ino_t)); ++ return sz; ++} ++ ++static int set_deblk_end(union aufs_deblk_p *p, union aufs_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->p - p->p) { ++ p->de->de_str.len = 0; ++ //smp_mb(); ++ return 0; ++ } ++ return -1; // error ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union aufs_deblk_p *p, union aufs_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->p - p->p) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static aufs_deblk_t *last_deblk(struct aufs_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++void nhash_init(struct aufs_nhash *nhash) ++{ ++ int i; ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) ++ INIT_HLIST_HEAD(nhash->heads + i); ++} ++ ++struct aufs_nhash *nhash_new(gfp_t gfp) ++{ ++ struct aufs_nhash *nhash; ++ ++ nhash = kmalloc(sizeof(*nhash), gfp); ++ if (nhash) { ++ nhash_init(nhash); ++ return nhash; ++ } ++ return ERR_PTR(-ENOMEM); ++} ++ ++void nhash_del(struct aufs_nhash *nhash) ++{ ++ nhash_fin(nhash); ++ kfree(nhash); ++} ++ ++void nhash_move(struct aufs_nhash *dst, struct aufs_nhash *src) ++{ ++ int i; ++ ++ TraceEnter(); ++ ++ //DbgWhlist(src); ++ *dst = *src; ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ struct hlist_head *h; ++ h = dst->heads + i; ++ if (h->first) ++ h->first->pprev = &h->first; ++ INIT_HLIST_HEAD(src->heads + i); ++ } ++ //DbgWhlist(src); ++ //DbgWhlist(dst); ++ //smp_mb(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void nhash_fin(struct aufs_nhash *whlist) ++{ ++ int i; ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos, *n; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ head = whlist->heads + i; ++ hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) { ++ //hlist_del(pos); ++ kfree(tpos); ++ } ++ } ++} ++ ++int is_longer_wh(struct aufs_nhash *whlist, aufs_bindex_t btgt, int limit) ++{ ++ int n, i; ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos; ++ ++ LKTRTrace("limit %d\n", limit); ++ //return 1; ++ ++ n = 0; ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ head = whlist->heads + i; ++ hlist_for_each_entry(tpos, pos, head, wh_hash) ++ if (tpos->wh_bindex == btgt && ++n > limit) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++int test_known_wh(struct aufs_nhash *whlist, char *name, int namelen) ++{ ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos; ++ struct aufs_destr *str; ++ ++ LKTRTrace("%.*s\n", namelen, name); ++ ++ head = whlist->heads + au_name_hash(name, namelen); ++ hlist_for_each_entry(tpos, pos, head, wh_hash) { ++ str = &tpos->wh_str; ++ LKTRTrace("%.*s\n", str->len, str->name); ++ if (str->len == namelen && !memcmp(str->name, name, namelen)) ++ return 1; ++ } ++ return 0; ++} ++ ++int append_wh(struct aufs_nhash *whlist, char *name, int namelen, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct aufs_destr *str; ++ struct aufs_wh *wh; ++ ++ LKTRTrace("%.*s\n", namelen, name); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + namelen, GFP_KERNEL); ++ if (unlikely(!wh)) ++ goto out; ++ err = 0; ++ wh->wh_bindex = bindex; ++ str = &wh->wh_str; ++ str->len = namelen; ++ memcpy(str->name, name, namelen); ++ hlist_add_head(&wh->wh_hash, ++ whlist->heads + au_name_hash(name, namelen)); ++ //smp_mb(); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void free_vdir(struct aufs_vdir *vdir) ++{ ++ aufs_deblk_t **deblk; ++ ++ TraceEnter(); ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) { ++ kfree(*deblk); ++ deblk++; ++ } ++ kfree(vdir->vd_deblk); ++ cache_free_vdir(vdir); ++} ++ ++static int append_deblk(struct aufs_vdir *vdir) ++{ ++ int err, sz, i; ++ aufs_deblk_t **o; ++ union aufs_deblk_p p, deblk_end; ++ ++ TraceEnter(); ++ ++ err = -ENOMEM; ++ sz = sizeof(*o) * vdir->vd_nblk; ++ o = au_kzrealloc(vdir->vd_deblk, sz, sz + sizeof(*o), GFP_KERNEL); ++ if (unlikely(!o)) ++ goto out; ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(sizeof(*p.deblk), GFP_KERNEL); ++ if (p.deblk) { ++ i = vdir->vd_nblk++; ++ vdir->vd_deblk[i] = p.deblk; ++ vdir->vd_last.i = i; ++ vdir->vd_last.p.p = p.p; ++ deblk_end.deblk = p.deblk + 1; ++ err = set_deblk_end(&p, &deblk_end); ++ DEBUG_ON(err); ++ } ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static struct aufs_vdir *alloc_vdir(void) ++{ ++ struct aufs_vdir *vdir; ++ int err; ++ ++ TraceEnter(); ++ ++ err = -ENOMEM; ++ vdir = cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_KERNEL); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ kfree(vdir->vd_deblk); ++ ++ out_free: ++ cache_free_vdir(vdir); ++ out: ++ vdir = ERR_PTR(err); ++ TraceErrPtr(vdir); ++ return vdir; ++} ++ ++static int reinit_vdir(struct aufs_vdir *vdir) ++{ ++ int err; ++ union aufs_deblk_p p, deblk_end; ++ ++ TraceEnter(); ++ ++ while (vdir->vd_nblk > 1) { ++ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + 1; ++ err = set_deblk_end(&p, &deblk_end); ++ DEBUG_ON(err); ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ vdir->vd_last.i = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ //smp_mb(); ++ //DbgVdir(vdir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void free_dehlist(struct aufs_nhash *dehlist) ++{ ++ int i; ++ struct hlist_head *head; ++ struct aufs_dehstr *tpos; ++ struct hlist_node *pos, *n; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < AUFS_NHASH_SIZE; i++) { ++ head = dehlist->heads + i; ++ hlist_for_each_entry_safe(tpos, pos, n, head, hash) { ++ //hlist_del(pos); ++ cache_free_dehstr(tpos); ++ } ++ } ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct aufs_nhash *delist, char *name, int namelen) ++{ ++ struct hlist_head *head; ++ struct aufs_dehstr *tpos; ++ struct hlist_node *pos; ++ struct aufs_destr *str; ++ ++ LKTRTrace("%.*s\n", namelen, name); ++ ++ head = delist->heads + au_name_hash(name, namelen); ++ hlist_for_each_entry(tpos, pos, head, hash) { ++ str = tpos->str; ++ LKTRTrace("%.*s\n", str->len, str->name); ++ if (str->len == namelen && !memcmp(str->name, name, namelen)) ++ return 1; ++ } ++ return 0; ++ ++} ++ ++static int append_de(struct aufs_vdir *vdir, char *name, int namelen, ino_t ino, ++ unsigned int d_type, struct aufs_nhash *delist) ++{ ++ int err, sz; ++ union aufs_deblk_p p, *room, deblk_end; ++ struct aufs_dehstr *dehstr; ++ ++ LKTRTrace("%.*s %d, i%lu, dt%u\n", namelen, name, namelen, ino, d_type); ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + 1; ++ room = &vdir->vd_last.p; ++ DEBUG_ON(room->p < p.p || deblk_end.p <= room->p ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(namelen); ++ if (unlikely(sz > deblk_end.p - room->p)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + 1; ++ //smp_mb(); ++ DEBUG_ON(room->p != p.p); ++ } ++ ++ err = -ENOMEM; ++ dehstr = cache_alloc_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, ++ delist->heads + au_name_hash(name, namelen)); ++ ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = namelen; ++ memcpy(room->de->de_str.name, name, namelen); ++ ++ err = 0; ++ room->p += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ //smp_mb(); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct fillvdir_arg { ++ struct file *file; ++ struct aufs_vdir *vdir; ++ struct aufs_nhash *delist; ++ struct aufs_nhash *whlist; ++ aufs_bindex_t bindex; ++ int err; ++ int called; ++}; ++ ++static int fillvdir(void *__arg, const char *__name, int namelen, loff_t offset, ++ filldir_ino_t h_ino, unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = __arg; ++ char *name = (void*)__name; ++ aufs_bindex_t bindex, bend; ++ struct xino xino; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, namelen %d, i%Lu, dt%u\n", ++ namelen, name, namelen, (u64)h_ino, d_type); ++ ++ sb = arg->file->f_dentry->d_sb; ++ bend = arg->bindex; ++ arg->err = 0; ++ arg->called++; ++ //smp_mb(); ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ for (bindex = 0; bindex < bend; bindex++) ++ if (test_known(arg->delist + bindex, name, namelen) ++ || test_known_wh(arg->whlist + bindex, name, ++ namelen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = xino_read(sb, bend, h_ino, &xino); ++ if (!arg->err && !xino.ino) { ++ //struct inode *h_inode; ++ xino.ino = xino_new_ino(sb); ++ if (unlikely(!xino.ino)) ++ arg->err = -EIO; ++#if 0 ++ //xino.h_gen = AuXino_INVALID_HGEN; ++ h_inode = ilookup(sbr_sb(sb, bend), h_ino); ++ if (h_inode) { ++ if (!is_bad_inode(h_inode)) { ++ xino.h_gen = h_inode->i_generation; ++ WARN_ON(xino.h_gen == AuXino_INVALID_HGEN); ++ } ++ iput(h_inode); ++ } ++#endif ++ arg->err = xino_write(sb, bend, h_ino, &xino); ++ } ++ if (!arg->err) ++ arg->err = append_de(arg->vdir, name, namelen, xino.ino, ++ d_type, arg->delist + bend); ++ } else { ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ for (bindex = 0; bindex < bend; bindex++) ++ if (test_known_wh(arg->whlist + bend, name, namelen)) ++ goto out; /* already whiteouted */ ++ arg->err = append_wh(arg->whlist + bend, name, namelen, bend); ++ } ++ ++ out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ //smp_mb(); ++ TraceErr(arg->err); ++ return arg->err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err, do_read, dlgt; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct aufs_vdir *vdir, *allocated; ++ unsigned long expire; ++ struct fillvdir_arg arg; ++ aufs_bindex_t bindex, bend, bstart; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, may %d\n", DLNPair(dentry), may_read); ++ FiMustWriteLock(file); ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ IiMustWriteLock(inode); ++ DEBUG_ON(!S_ISDIR(inode->i_mode)); ++ ++ err = 0; ++ allocated = NULL; ++ do_read = 0; ++ sb = inode->i_sb; ++ expire = stosi(sb)->si_rdcache; ++ vdir = ivdir(inode); ++ if (!vdir) { ++ DEBUG_ON(fvdir_cache(file)); ++ do_read = 1; ++ vdir = alloc_vdir(); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (inode->i_version != vdir->vd_version ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ LKTRTrace("iver %lu, vdver %lu, exp %lu\n", ++ inode->i_version, vdir->vd_version, ++ vdir->vd_jiffy + expire); ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ //DbgVdir(vdir); goto out; ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ err = -ENOMEM; ++ bend = fbend(file); ++ arg.delist = kmalloc(sizeof(*arg.delist) * (bend + 1), GFP_KERNEL); ++ if (unlikely(!arg.delist)) ++ goto out_vdir; ++ arg.whlist = kmalloc(sizeof(*arg.whlist) * (bend + 1), GFP_KERNEL); ++ if (unlikely(!arg.whlist)) ++ goto out_delist; ++ err = 0; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ nhash_init(arg.delist + bindex); ++ nhash_init(arg.whlist + bindex); ++ } ++ ++ dlgt = need_dlgt(sb); ++ arg.file = file; ++ arg.vdir = vdir; ++ bstart = fbstart(file); ++ for (bindex = bstart; !err && bindex <= bend; bindex++) { ++ struct file *hf; ++ struct inode *h_inode; ++ ++ hf = au_h_fptr_i(file, bindex); ++ if (!hf) ++ continue; ++ ++ h_inode = hf->f_dentry->d_inode; ++ //hf->f_pos = 0; ++ arg.bindex = bindex; ++ do { ++ arg.err = 0; ++ arg.called = 0; ++ //smp_mb(); ++ err = vfsub_readdir(hf, fillvdir, &arg, dlgt); ++ if (err >= 0) ++ err = arg.err; ++ } while (!err && arg.called); ++ } ++ ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ free_dehlist(arg.delist + bindex); ++ nhash_fin(arg.whlist + bindex); ++ } ++ kfree(arg.whlist); ++ ++ out_delist: ++ kfree(arg.delist); ++ out_vdir: ++ if (!err) { ++ //file->f_pos = 0; ++ vdir->vd_version = inode->i_version; ++ vdir->vd_last.i = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ set_ivdir(inode, allocated); ++ } else if (allocated) ++ free_vdir(allocated); ++ //DbgVdir(vdir); goto out; ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static int copy_vdir(struct aufs_vdir *tgt, struct aufs_vdir *src) ++{ ++ int err, i, rerr, n; ++ ++ TraceEnter(); ++ DEBUG_ON(tgt->vd_nblk != 1); ++ //DbgVdir(tgt); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ aufs_deblk_t **p; ++ p = au_kzrealloc(tgt->vd_deblk, sizeof(*p) * tgt->vd_nblk, ++ sizeof(*p) * src->vd_nblk, GFP_KERNEL); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ n = tgt->vd_nblk = src->vd_nblk; ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], AUFS_DEBLK_SIZE); ++ //tgt->vd_last.i = 0; ++ //tgt->vd_last.p.deblk = tgt->vd_deblk[0]; ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ for (i = 1; i < n; i++) { ++ tgt->vd_deblk[i] = kmalloc(AUFS_DEBLK_SIZE, GFP_KERNEL); ++ if (tgt->vd_deblk[i]) ++ memcpy(tgt->vd_deblk[i], src->vd_deblk[i], ++ AUFS_DEBLK_SIZE); ++ else ++ goto out; ++ } ++ //smp_mb(); ++ //DbgVdir(tgt); ++ return 0; /* success */ ++ ++ out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ TraceErr(err); ++ return err; ++} ++ ++int au_init_vdir(struct file *file) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct aufs_vdir *vdir_cache, *allocated; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld\n", DLNPair(dentry), file->f_pos); ++ FiMustWriteLock(file); ++ inode = dentry->d_inode; ++ IiMustWriteLock(inode); ++ DEBUG_ON(!S_ISDIR(inode->i_mode)); ++ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ //DbgVdir(ivdir(inode)); goto out; ++ ++ allocated = NULL; ++ vdir_cache = fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ //err = 0; DbgVdir(vdir_cache); goto out; ++ ++ err = copy_vdir(vdir_cache, ivdir(inode)); ++ if (!err) { ++ file->f_version = inode->i_version; ++ if (allocated) ++ set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ free_vdir(allocated); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++static loff_t calc_offset(struct aufs_vdir *vdir) ++{ ++ loff_t offset; ++ union aufs_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.i]; ++ offset = vdir->vd_last.p.p - p.p; ++ offset += sizeof(*p.deblk) * vdir->vd_last.i; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file) ++{ ++ int valid, i, n; ++ struct dentry *dentry; ++ struct aufs_vdir *vdir_cache; ++ loff_t offset; ++ union aufs_deblk_p p, deblk_end; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld\n", DLNPair(dentry), file->f_pos); ++ vdir_cache = fvdir_cache(file); ++ DEBUG_ON(!vdir_cache); ++ //DbgVdir(vdir_cache); ++ ++ valid = 1; ++ offset = calc_offset(vdir_cache); ++ LKTRTrace("offset %Ld\n", offset); ++ if (file->f_pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.i = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!file->f_pos) ++ goto out; ++ ++ valid = 0; ++ i = file->f_pos / AUFS_DEBLK_SIZE; ++ LKTRTrace("i %d\n", i); ++ if (i >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ //DbgVdir(vdir_cache); ++ for (; i < n; i++) { ++ p.deblk = vdir_cache->vd_deblk[i]; ++ deblk_end.deblk = p.deblk + 1; ++ offset = i * AUFS_DEBLK_SIZE; ++ while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) { ++ int l; ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.p += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.i = i; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++ out: ++ //smp_mb(); ++ //DbgVdir(vdir_cache); ++ TraceErr(!valid); ++ return valid; ++} ++ ++int au_fill_de(struct file *file, void *dirent, filldir_t filldir) ++{ ++ int err, l; ++ struct dentry *dentry; ++ struct aufs_vdir *vdir_cache; ++ struct aufs_de *de; ++ union aufs_deblk_p deblk_end; ++ ++ dentry = file->f_dentry; ++ LKTRTrace("%.*s, pos %Ld\n", DLNPair(dentry), file->f_pos); ++ vdir_cache = fvdir_cache(file); ++ DEBUG_ON(!vdir_cache); ++ //DbgVdir(vdir_cache); ++ ++ if (!seek_vdir(file)) ++ return 0; ++ ++ while (1) { ++ deblk_end.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.i] + 1; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ LKTRTrace("%.*s, off%Ld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ++ file->f_pos, de->de_ino, de->de_type); ++ err = filldir(dirent, de->de_str.name, de->de_str.len, ++ file->f_pos, de->de_ino, de->de_type); ++ if (unlikely(err)) { ++ TraceErr(err); ++ //return err; ++ //todo: ignore the error caused by udba. ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.p += l; ++ file->f_pos += l; ++ } ++ if (vdir_cache->vd_last.i < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.i++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.i]; ++ file->f_pos = sizeof(*vdir_cache->vd_last.p.deblk) ++ * vdir_cache->vd_last.i; ++ continue; ++ } ++ break; ++ } ++ ++ //smp_mb(); ++ return 0; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/vfsub.c linux-2.6.22.1/fs/aufs/vfsub.c +--- linux-2.6.22.1.oorig/fs/aufs/vfsub.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/vfsub.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,665 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: vfsub.c,v 1.5 2007/04/23 00:55:06 sfjro Exp $ */ ++// I'm going to slightly mad ++ ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DLGT ++struct permission_args { ++ int *errp; ++ struct inode *inode; ++ int mask; ++ struct nameidata *nd; ++}; ++ ++static void call_permission(void *args) ++{ ++ struct permission_args *a = args; ++ *a->errp = do_vfsub_permission(a->inode, a->mask, a->nd); ++} ++ ++int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, ++ int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_permission(inode, mask, nd); ++ else { ++ int err; ++ struct permission_args args = { ++ .errp = &err, ++ .inode = inode, ++ .mask = mask, ++ .nd = nd ++ }; ++ au_wkq_wait(call_permission, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct create_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++ int mode; ++ struct nameidata *nd; ++}; ++ ++static void call_create(void *args) ++{ ++ struct create_args *a = args; ++ *a->errp = do_vfsub_create(a->dir, a->dentry, a->mode, a->nd); ++} ++ ++int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_create(dir, dentry, mode, nd); ++ else { ++ int err; ++ struct create_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry, ++ .mode = mode, ++ .nd = nd ++ }; ++ au_wkq_wait(call_create, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct symlink_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++ const char *symname; ++ int mode; ++}; ++ ++static void call_symlink(void *args) ++{ ++ struct symlink_args *a = args; ++ *a->errp = do_vfsub_symlink(a->dir, a->dentry, a->symname, a->mode); ++} ++ ++int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, ++ int mode, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_symlink(dir, dentry, symname, mode); ++ else { ++ int err; ++ struct symlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry, ++ .symname = symname, ++ .mode = mode ++ }; ++ au_wkq_wait(call_symlink, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct mknod_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++ int mode; ++ dev_t dev; ++}; ++ ++static void call_mknod(void *args) ++{ ++ struct mknod_args *a = args; ++ *a->errp = do_vfsub_mknod(a->dir, a->dentry, a->mode, a->dev); ++} ++ ++int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, ++ int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_mknod(dir, dentry, mode, dev); ++ else { ++ int err; ++ struct mknod_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry, ++ .mode = mode, ++ .dev = dev ++ }; ++ au_wkq_wait(call_mknod, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++ int mode; ++}; ++ ++static void call_mkdir(void *args) ++{ ++ struct mkdir_args *a = args; ++ *a->errp = do_vfsub_mkdir(a->dir, a->dentry, a->mode); ++} ++ ++int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_mkdir(dir, dentry, mode); ++ else { ++ int err; ++ struct mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry, ++ .mode = mode ++ }; ++ au_wkq_wait(call_mkdir, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct link_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *src_dentry, *dentry; ++}; ++ ++static void call_link(void *args) ++{ ++ struct link_args *a = args; ++ *a->errp = do_vfsub_link(a->src_dentry, a->dir, a->dentry); ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_link(src_dentry, dir, dentry); ++ else { ++ int err; ++ struct link_args args = { ++ .errp = &err, ++ .src_dentry = src_dentry, ++ .dir = dir, ++ .dentry = dentry ++ }; ++ au_wkq_wait(call_link, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct rename_args { ++ int *errp; ++ struct inode *src_dir, *dir; ++ struct dentry *src_dentry, *dentry; ++}; ++ ++static void call_rename(void *args) ++{ ++ struct rename_args *a = args; ++ *a->errp = do_vfsub_rename(a->src_dir, a->src_dentry, a->dir, ++ a->dentry); ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_rename(src_dir, src_dentry, dir, dentry); ++ else { ++ int err; ++ struct rename_args args = { ++ .errp = &err, ++ .src_dir = src_dir, ++ .src_dentry = src_dentry, ++ .dir = dir, ++ .dentry = dentry ++ }; ++ au_wkq_wait(call_rename, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++}; ++ ++static void call_rmdir(void *args) ++{ ++ struct rmdir_args *a = args; ++ *a->errp = do_vfsub_rmdir(a->dir, a->dentry); ++} ++ ++int vfsub_rmdir(struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_rmdir(dir, dentry); ++ else { ++ int err; ++ struct rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry ++ }; ++ au_wkq_wait(call_rmdir, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct read_args { ++ ssize_t *errp; ++ struct file *file; ++ union { ++ void *kbuf; ++ char __user *ubuf; ++ }; ++ size_t count; ++ loff_t *ppos; ++}; ++ ++static void call_read_k(void *args) ++{ ++ struct read_args *a = args; ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(a->file->f_dentry), (unsigned long)a->count, ++ *a->ppos); ++ *a->errp = do_vfsub_read_k(a->file, a->kbuf, a->count, a->ppos); ++} ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_read_u(file, ubuf, count, ppos); ++ else { ++ ssize_t err, read; ++ struct read_args args = { ++ .errp = &err, ++ .file = file, ++ .count = count, ++ .ppos = ppos ++ }; ++ ++ if (unlikely(!count)) ++ return 0; ++ ++ /* ++ * workaround an application bug. ++ * generally, read(2) or write(2) may return the value shorter ++ * than requested. But many applications don't support it, ++ * for example bash. ++ */ ++ err = -ENOMEM; ++ if (args.count > PAGE_SIZE) ++ args.count = PAGE_SIZE; ++ args.kbuf = kmalloc(args.count, GFP_KERNEL); ++ if (unlikely(!args.kbuf)) ++ goto out; ++ ++ read = 0; ++ do { ++ au_wkq_wait(call_read_k, &args, /*dlgt*/1); ++ if (unlikely(err > 0 ++ && copy_to_user(ubuf, args.kbuf, err))) { ++ err = -EFAULT; ++ goto out_free; ++ } else if (!err) ++ break; ++ else if (unlikely(err < 0)) ++ goto out_free; ++ count -= err; ++ /* do not read too much because of file i/o pointer */ ++ if (unlikely(count < args.count)) ++ args.count = count; ++ ubuf += err; ++ read += err; ++ } while (count); ++ smp_mb(); ++ err = read; ++ ++ out_free: ++ kfree(args.kbuf); ++ out: ++ return err; ++ } ++} ++ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_read_k(file, kbuf, count, ppos); ++ else { ++ ssize_t err; ++ struct read_args args = { ++ .errp = &err, ++ .file = file, ++ .count = count, ++ .ppos = ppos ++ }; ++ args.kbuf = kbuf; ++ au_wkq_wait(call_read_k, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct write_args { ++ ssize_t *errp; ++ struct file *file; ++ union { ++ void *kbuf; ++ const char __user *ubuf; ++ }; ++ void *buf; ++ size_t count; ++ loff_t *ppos; ++}; ++ ++static void call_write_k(void *args) ++{ ++ struct write_args *a = args; ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(a->file->f_dentry), (unsigned long)a->count, ++ *a->ppos); ++ *a->errp = do_vfsub_write_k(a->file, a->kbuf, a->count, a->ppos); ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_write_u(file, ubuf, count, ppos); ++ else { ++ ssize_t err, written; ++ struct write_args args = { ++ .errp = &err, ++ .file = file, ++ .count = count, ++ .ppos = ppos ++ }; ++ ++ if (unlikely(!count)) ++ return 0; ++ ++ /* ++ * workaround an application bug. ++ * generally, read(2) or write(2) may return the value shorter ++ * than requested. But many applications don't support it, ++ * for example bash. ++ */ ++ err = -ENOMEM; ++ if (args.count > PAGE_SIZE) ++ args.count = PAGE_SIZE; ++ args.kbuf = kmalloc(args.count, GFP_KERNEL); ++ if (unlikely(!args.kbuf)) ++ goto out; ++ ++ written = 0; ++ do { ++ if (unlikely(copy_from_user(args.kbuf, ubuf, args.count))) { ++ err = -EFAULT; ++ goto out_free; ++ } ++ ++ au_wkq_wait(call_write_k, &args, /*dlgt*/1); ++ if (err > 0) { ++ count -= err; ++ if (count < args.count) ++ args.count = count; ++ ubuf += err; ++ written += err; ++ } else if (!err) ++ break; ++ else if (unlikely(err < 0)) ++ goto out_free; ++ } while (count); ++ err = written; ++ ++ out_free: ++ kfree(args.kbuf); ++ out: ++ return err; ++ } ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_write_k(file, kbuf, count, ppos); ++ else { ++ ssize_t err; ++ struct write_args args = { ++ .errp = &err, ++ .file = file, ++ .count = count, ++ .ppos = ppos ++ }; ++ args.kbuf = kbuf; ++ au_wkq_wait(call_write_k, &args, /*dlgt*/1); ++ return err; ++ } ++} ++ ++struct readdir_args { ++ int *errp; ++ struct file *file; ++ filldir_t filldir; ++ void *arg; ++}; ++ ++static void call_readdir(void *args) ++{ ++ struct readdir_args *a = args; ++ *a->errp = do_vfsub_readdir(a->file, a->filldir, a->arg); ++} ++ ++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt) ++{ ++ if (!dlgt) ++ return do_vfsub_readdir(file, filldir, arg); ++ else { ++ int err; ++ struct readdir_args args = { ++ .errp = &err, ++ .file = file, ++ .filldir = filldir, ++ .arg = arg ++ }; ++ au_wkq_wait(call_readdir, &args, /*dlgt*/1); ++ return err; ++ } ++} ++#endif /* CONFIG_AUFS_DLGT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct dentry *h_dentry; ++ struct iattr *ia; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ ++ LKTRTrace("%.*s, ia_valid 0x%x\n", ++ DLNPair(a->h_dentry), a->ia->ia_valid); ++ h_inode = a->h_dentry->d_inode; ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ lockdep_off(); ++ *a->errp = notify_change(a->h_dentry, a->ia); ++ lockdep_on(); ++ } ++ TraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct dentry *dentry, struct iattr *ia, int dlgt) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .h_dentry = dentry, ++ .ia = ia ++ }; ++ ++#ifndef CONFIG_AUFS_DLGT ++ call_notify_change(&args); ++#else ++ if (!dlgt) ++ call_notify_change(&args); ++ else ++ au_wkq_wait(call_notify_change, &args, /*dlgt*/1); ++#endif ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct dentry *dentry; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct inode *h_inode; ++ const int stop_sillyrename = (au_is_nfs(a->dentry->d_sb) ++ && atomic_read(&a->dentry->d_count) == 1); ++ ++ LKTRTrace("%.*s, stop_silly %d, cnt %d\n", ++ DLNPair(a->dentry), stop_sillyrename, ++ atomic_read(&a->dentry->d_count)); ++ IMustLock(a->dir); ++ ++ if (!stop_sillyrename) ++ dget(a->dentry); ++ h_inode = a->dentry->d_inode; ++ if (h_inode) ++ atomic_inc(&h_inode->i_count); ++#if 0 // partial testing ++ { ++ struct qstr *name = &a->dentry->d_name; ++ if (name->len == sizeof(AUFS_XINO_FNAME) - 1 ++ && !strncmp(name->name, AUFS_XINO_FNAME, name->len)) { ++ lockdep_off(); ++ *a->errp = vfs_unlink(a->dir, a->dentry); ++ lockdep_on(); ++ } else ++ err = -1; ++ } ++#else ++ // vfs_unlink() locks inode ++ lockdep_off(); ++ *a->errp = vfs_unlink(a->dir, a->dentry); ++ lockdep_on(); ++#endif ++ ++ if (!stop_sillyrename) ++ dput(a->dentry); ++ if (h_inode) ++ iput(h_inode); ++ ++ TraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .dentry = dentry ++ }; ++ ++#ifndef CONFIG_AUFS_DLGT ++ call_unlink(&args); ++#else ++ if (!dlgt) ++ call_unlink(&args); ++ else ++ au_wkq_wait(call_unlink, &args, /*dlgt*/1); ++#endif ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct statfs_args { ++ int *errp; ++ void *arg; ++ struct kstatfs *buf; ++}; ++ ++static void call_statfs(void *args) ++{ ++ struct statfs_args *a = args; ++ *a->errp = vfs_statfs(a->arg, a->buf); ++} ++ ++int vfsub_statfs(void *arg, struct kstatfs *buf, int dlgt) ++{ ++ int err; ++ struct statfs_args args = { ++ .errp = &err, ++ .arg = arg, ++ .buf = buf ++ }; ++ ++#ifndef CONFIG_AUFS_DLGT ++ call_statfs(&args); ++#else ++ if (!dlgt) ++ call_statfs(&args); ++ else ++ au_wkq_wait(call_statfs, &args, /*dlgt*/1); ++#endif ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/vfsub.h linux-2.6.22.1/fs/aufs/vfsub.h +--- linux-2.6.22.1.oorig/fs/aufs/vfsub.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/vfsub.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,427 @@ ++/* ++ * Copyright (C) 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: vfsub.h,v 1.8 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "wkq.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* simple abstractions, for future use */ ++static inline ++int do_vfsub_permission(struct inode *inode, int mask, struct nameidata *nd) ++{ ++ LKTRTrace("i%lu, mask 0x%x, nd %p\n", inode->i_ino, mask, nd); ++#if 0 ++#else ++ return permission(inode, mask, nd); ++#endif ++} ++ ++static inline ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *err; ++ ++ LKTRTrace("%s\n", path); ++ ++ lockdep_off(); ++ err = filp_open(path, oflags, mode); ++ lockdep_on(); ++ return err; ++} ++ ++static inline ++int vfsub_path_lookup(const char *name, unsigned int flags, ++ struct nameidata *nd) ++{ ++ int err; ++ ++ LKTRTrace("%s\n", name); ++ ++ //lockdep_off(); ++ err = path_lookup(name, flags, nd); ++ //lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++int do_vfsub_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd) ++{ ++ LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, DLNPair(dentry), mode); ++#if 0 ++#else ++ return vfs_create(dir, dentry, mode, nd); ++#endif ++} ++ ++static inline ++int do_vfsub_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname, int mode) ++{ ++ LKTRTrace("i%lu, %.*s, %s, 0x%x\n", ++ dir->i_ino, DLNPair(dentry), symname, mode); ++#if 0 ++#else ++ return vfs_symlink(dir, dentry, symname, mode); ++#endif ++} ++ ++static inline ++int do_vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ dev_t dev) ++{ ++ LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, DLNPair(dentry), mode); ++#if 0 ++#else ++ return vfs_mknod(dir, dentry, mode, dev); ++#endif ++} ++ ++static inline ++int do_vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ LKTRTrace("%.*s, i%lu, %.*s\n", ++ DLNPair(src_dentry), dir->i_ino, DLNPair(dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_link(src_dentry, dir, dentry); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++static inline ++int do_vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ ++ LKTRTrace("i%lu, %.*s, i%lu, %.*s\n", ++ src_dir->i_ino, DLNPair(src_dentry), ++ dir->i_ino, DLNPair(dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_rename(src_dir, src_dentry, dir, dentry); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++static inline ++int do_vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, DLNPair(dentry), mode); ++#if 0 ++#else ++ return vfs_mkdir(dir, dentry, mode); ++#endif ++} ++ ++static inline int do_vfsub_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ ++ LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_rmdir(dir, dentry); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++ssize_t do_vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(file->f_dentry), (unsigned long)count, *ppos); ++ ++ /* nfs uses some locks */ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_read(file, ubuf, count, ppos); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++// kernel_read() ?? ++static inline ++ssize_t do_vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = do_vfsub_read_u(file, (char __user*)kbuf, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++static inline ++ssize_t do_vfsub_write_u(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ ++ LKTRTrace("%.*s, cnt %lu, pos %Ld\n", ++ DLNPair(file->f_dentry), (unsigned long)count, *ppos); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_write(file, ubuf, count, ppos); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++static inline ++ssize_t do_vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = do_vfsub_write_u(file, (const char __user*)kbuf, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++static inline ++int do_vfsub_readdir(struct file *file, filldir_t filldir, void *arg) ++{ ++ int err; ++ ++ LKTRTrace("%.*s\n", DLNPair(file->f_dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_readdir(file, filldir, arg); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ LKTRTrace("%.*s\n", DLNPair(file->f_dentry)); ++ ++ lockdep_off(); ++#if 0 ++#else ++ err = vfs_llseek(file, offset, origin); ++#endif ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DLGT ++static inline int need_dlgt(struct super_block *sb) ++{ ++ return (au_flag_test(sb, AuFlag_DLGT) && !is_au_wkq(current)); ++} ++ ++int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, ++ int dlgt); ++ ++int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd, int dlgt); ++int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, ++ int mode, int dlgt); ++int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, ++ int dlgt); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry, int dlgt); ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, int dlgt); ++int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, int dlgt); ++int vfsub_rmdir(struct inode *dir, struct dentry *dentry, int dlgt); ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt); ++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt); ++ ++#else ++ ++static inline int need_dlgt(struct super_block *sb) ++{ ++ return 0; ++} ++ ++static inline ++int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, ++ int dlgt) ++{ ++ return do_vfsub_permission(inode, mask, nd); ++} ++ ++static inline ++int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd, int dlgt) ++{ ++ return do_vfsub_create(dir, dentry, mode, nd); ++} ++ ++static inline ++int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, ++ int mode, int dlgt) ++{ ++ return do_vfsub_symlink(dir, dentry, symname, mode); ++} ++ ++static inline ++int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, ++ int dlgt) ++{ ++ return do_vfsub_mknod(dir, dentry, mode, dev); ++} ++ ++static inline ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry, int dlgt) ++{ ++ return do_vfsub_link(src_dentry, dir, dentry); ++} ++ ++static inline ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ return do_vfsub_rename(src_dir, src_dentry, dir, dentry); ++} ++ ++static inline ++int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, ++ int dlgt) ++{ ++ return do_vfsub_mkdir(dir, dentry, mode); ++} ++ ++static inline ++int vfsub_rmdir(struct inode *dir, struct dentry *dentry, int dlgt) ++{ ++ return do_vfsub_rmdir(dir, dentry); ++} ++ ++static inline ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt) ++{ ++ return do_vfsub_read_u(file, ubuf, count, ppos); ++} ++ ++static inline ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt) ++{ ++ return do_vfsub_read_k(file, kbuf, count, ppos); ++} ++ ++static inline ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos, int dlgt) ++{ ++ return do_vfsub_write_u(file, ubuf, count, ppos); ++} ++ ++static inline ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, ++ int dlgt) ++{ ++ return do_vfsub_write_k(file, kbuf, count, ppos); ++} ++ ++static inline ++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt) ++{ ++ return do_vfsub_readdir(file, filldir, arg); ++} ++#endif /* CONFIG_AUFS_DLGT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct dentry *d2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ return d; ++} ++ ++static inline void vfsub_unlock_rename(struct dentry *d1, struct dentry *d2) ++{ ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_notify_change(struct dentry *dentry, struct iattr *ia, int dlgt); ++int vfsub_unlink(struct inode *dir, struct dentry *dentry, int dlgt); ++int vfsub_statfs(void *arg, struct kstatfs *buf, int dlgt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/whout.c linux-2.6.22.1/fs/aufs/whout.c +--- linux-2.6.22.1.oorig/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/whout.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,933 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: whout.c,v 1.14 2007/05/14 03:40:40 sfjro Exp $ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++#define WH_MASK S_IRUGO ++ ++/* If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = { ++ .name = AUFS_WH_DIROPQ, ++ .len = sizeof(AUFS_WH_DIROPQ) - 1 ++}; ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by au_free_whname(). ++ */ ++int au_alloc_whname(const char *name, int len, struct qstr *wh) ++{ ++ char *p; ++ ++ DEBUG_ON(!name || !len || !wh); ++ ++ if (unlikely(len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = len + AUFS_WH_PFX_LEN; ++ wh->name = p = kmalloc(wh->len, GFP_KERNEL); ++ //if (LktrCond) {kfree(p); wh->name = p = NULL;} ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name, len); ++ //smp_mb(); ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++void au_free_whname(struct qstr *wh) ++{ ++ DEBUG_ON(!wh || !wh->name); ++ kfree(wh->name); ++#ifdef CONFIG_AUFS_DEBUG ++ wh->name = NULL; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @hidden_parent. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int is_wh(struct dentry *hidden_parent, struct qstr *wh_name, int try_sio, ++ struct lkup_args *lkup) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ struct inode *hidden_dir; ++ ++ LKTRTrace("%.*s/%.*s, lkup{%p, %d}\n", DLNPair(hidden_parent), ++ wh_name->len, wh_name->name, lkup->nfsmnt, lkup->dlgt); ++ hidden_dir = hidden_parent->d_inode; ++ DEBUG_ON(!S_ISDIR(hidden_dir->i_mode)); ++ IMustLock(hidden_dir); ++ ++ if (!try_sio) ++ wh_dentry = lkup_one(wh_name->name, hidden_parent, ++ wh_name->len, lkup); ++ else ++ wh_dentry = sio_lkup_one(wh_name->name, hidden_parent, ++ wh_name->len, lkup); ++ //if (LktrCond) {dput(wh_dentry); wh_dentry = ERR_PTR(-1);} ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ err = 0; ++ if (!wh_dentry->d_inode) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (S_ISREG(wh_dentry->d_inode->i_mode)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ IOErr("%.*s Invalid whiteout entry type 0%o.\n", ++ DLNPair(wh_dentry), wh_dentry->d_inode->i_mode); ++ ++ out_wh: ++ dput(wh_dentry); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * test if the @hidden_dentry sets opaque or not. ++ */ ++int is_diropq(struct dentry *hidden_dentry, struct lkup_args *lkup) ++{ ++ int err; ++ struct inode *hidden_dir; ++ ++ LKTRTrace("dentry %.*s\n", DLNPair(hidden_dentry)); ++ hidden_dir = hidden_dentry->d_inode; ++ DEBUG_ON(!S_ISDIR(hidden_dir->i_mode)); ++ IMustLock(hidden_dir); ++ ++ err = is_wh(hidden_dentry, &diropq_name, /*try_sio*/1, lkup); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *lkup_whtmp(struct dentry *hidden_parent, struct qstr *prefix, ++ struct lkup_args *lkup) ++{ ++#define HEX_LEN 4 ++ struct dentry *dentry; ++ int len, i; ++ char defname[AUFS_WH_PFX_LEN * 2 + DNAME_INLINE_LEN_MIN + 1 ++ + HEX_LEN + 1], *name, *p; ++ static unsigned char cnt; ++ ++ LKTRTrace("hp %.*s, prefix %.*s\n", ++ DLNPair(hidden_parent), prefix->len, prefix->name); ++ DEBUG_ON(!hidden_parent->d_inode); ++ IMustLock(hidden_parent->d_inode); ++ ++ name = defname; ++ len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(len >= PATH_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(len + 1, GFP_KERNEL); ++ //if (LktrCond) {kfree(name); name = NULL;} ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ // doubly whiteout-ed ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ DEBUG_ON(name + len + 1 - p <= HEX_LEN); ++ ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*d", HEX_LEN, cnt++); ++ dentry = sio_lkup_one(name, hidden_parent, len, lkup); ++ //if (LktrCond) {dput(dentry); dentry = ERR_PTR(-1);} ++ if (unlikely(IS_ERR(dentry) || !dentry->d_inode)) ++ goto out_name; ++ dput(dentry); ++ } ++ //Warn("could not get random name\n"); ++ dentry = ERR_PTR(-EEXIST); ++ Dbg("%.*s\n", len, name); ++ BUG(); ++ ++ out_name: ++ if (unlikely(name != defname)) ++ kfree(name); ++ out: ++ TraceErrPtr(dentry); ++ return dentry; ++#undef HEX_LEN ++} ++ ++/* ++ * rename the @dentry of @bindex to the whiteouted temporary name. ++ */ ++int rename_whtmp(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err; ++ struct inode *hidden_dir; ++ struct dentry *hidden_dentry, *hidden_parent, *tmp_dentry; ++ struct super_block *sb; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, b%d\n", DLNPair(dentry), bindex); ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ DEBUG_ON(!hidden_dentry || !hidden_dentry->d_inode); ++ hidden_parent = hidden_dentry->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ sb = dentry->d_sb; ++ lkup.nfsmnt = au_nfsmnt(sb, bindex); ++ lkup.dlgt = need_dlgt(sb); ++ tmp_dentry = lkup_whtmp(hidden_parent, &hidden_dentry->d_name, &lkup); ++ //if (LktrCond) {dput(tmp_dentry); tmp_dentry = ERR_PTR(-1);} ++ err = PTR_ERR(tmp_dentry); ++ if (!IS_ERR(tmp_dentry)) { ++ /* under the same dir, no need to lock_rename() */ ++ err = vfsub_rename(hidden_dir, hidden_dentry, ++ hidden_dir, tmp_dentry, lkup.dlgt); ++ //if (LktrCond) err = -1; //unavailable ++ TraceErr(err); ++ dput(tmp_dentry); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_unlink_wh_dentry(struct inode *hidden_dir, struct dentry *wh_dentry, ++ struct dentry *dentry, int dlgt) ++{ ++ int err; ++ ++ LKTRTrace("hi%lu, wh %.*s, d %p\n", hidden_dir->i_ino, ++ DLNPair(wh_dentry), dentry); ++ DEBUG_ON((dentry && dbwh(dentry) == -1) ++ || !wh_dentry->d_inode ++ || !S_ISREG(wh_dentry->d_inode->i_mode)); ++ IMustLock(hidden_dir); ++ ++ err = vfsub_unlink(hidden_dir, wh_dentry, dlgt); ++ //if (LktrCond) err = -1; // unavailable ++ if (!err && dentry) ++ set_dbwh(dentry, -1); ++ ++ TraceErr(err); ++ return err; ++} ++ ++static int unlink_wh_name(struct dentry *hidden_parent, struct qstr *wh, ++ struct lkup_args *lkup) ++{ ++ int err; ++ struct inode *hidden_dir; ++ struct dentry *hidden_dentry; ++ ++ LKTRTrace("%.*s/%.*s\n", DLNPair(hidden_parent), LNPair(wh)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ // au_test_perm() is already done ++ hidden_dentry = lkup_one(wh->name, hidden_parent, wh->len, lkup); ++ //if (LktrCond) {dput(hidden_dentry); hidden_dentry = ERR_PTR(-1);} ++ if (!IS_ERR(hidden_dentry)) { ++ err = 0; ++ if (hidden_dentry->d_inode) ++ err = vfsub_unlink(hidden_dir, hidden_dentry, ++ lkup->dlgt); ++ dput(hidden_dentry); ++ } else ++ err = PTR_ERR(hidden_dentry); ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void clean_wh(struct inode *h_dir, struct dentry *wh) ++{ ++ TraceEnter(); ++ if (wh->d_inode) { ++ int err = vfsub_unlink(h_dir, wh, /*dlgt*/0); ++ if (unlikely(err)) ++ Warn("failed unlink %.*s (%d), ignored.\n", ++ DLNPair(wh), err); ++ } ++} ++ ++static void clean_plink(struct inode *h_dir, struct dentry *plink) ++{ ++ TraceEnter(); ++ if (plink->d_inode) { ++ int err = vfsub_rmdir(h_dir, plink, /*dlgt*/0); ++ if (unlikely(err)) ++ Warn("failed rmdir %.*s (%d), ignored.\n", ++ DLNPair(plink), err); ++ } ++} ++ ++static int test_linkable(struct inode *h_dir) ++{ ++ if (h_dir->i_op && h_dir->i_op->link) ++ return 0; ++ return -ENOSYS; ++} ++ ++static int plink_dir(struct inode *h_dir, struct dentry *plink) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (!plink->d_inode) { ++ int mode = S_IRWXU; ++ if (unlikely(au_is_nfs(plink->d_sb))) ++ mode |= S_IXUGO; ++ err = vfsub_mkdir(h_dir, plink, mode, /*dlgt*/0); ++ } else if (S_ISDIR(plink->d_inode->i_mode)) ++ err = 0; ++ else ++ Err("unknown %.*s exists\n", DLNPair(plink)); ++ ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int init_wh(struct dentry *h_root, struct aufs_branch *br, ++ struct vfsmount *nfsmnt, struct super_block *sb) ++{ ++ int err; ++ struct dentry *wh, *plink; ++ struct inode *h_dir; ++ static struct qstr base_name[] = { ++ {.name = AUFS_WH_BASENAME, .len = sizeof(AUFS_WH_BASENAME) - 1}, ++ {.name = AUFS_WH_PLINKDIR, .len = sizeof(AUFS_WH_PLINKDIR) - 1} ++ }; ++ struct lkup_args lkup = { ++ .nfsmnt = nfsmnt, ++ .dlgt = 0 // always no dlgt ++ }; ++ const int do_plink = au_flag_test(sb, AuFlag_PLINK); ++ ++ LKTRTrace("nfsmnt %p\n", nfsmnt); ++ BrWhMustWriteLock(br); ++ SiMustWriteLock(sb); ++ h_dir = h_root->d_inode; ++ IMustLock(h_dir); ++ ++ // doubly whiteouted ++ wh = lkup_wh(h_root, base_name + 0, &lkup); ++ //if (LktrCond) {dput(wh); wh = ERR_PTR(-1);} ++ err = PTR_ERR(wh); ++ if (IS_ERR(wh)) ++ goto out; ++ DEBUG_ON(br->br_wh && br->br_wh != wh); ++ ++ plink = lkup_wh(h_root, base_name + 1, &lkup); ++ err = PTR_ERR(plink); ++ if (IS_ERR(plink)) ++ goto out_dput_wh; ++ DEBUG_ON(br->br_plink && br->br_plink != plink); ++ ++ dput(br->br_wh); ++ dput(br->br_plink); ++ br->br_wh = br->br_plink = NULL; ++ ++ err = 0; ++ switch (br->br_perm) { ++ case AuBr_RR: ++ case AuBr_RO: ++ case AuBr_RRWH: ++ case AuBr_ROWH: ++ clean_wh(h_dir, wh); ++ clean_plink(h_dir, plink); ++ break; ++ ++ case AuBr_RWNoLinkWH: ++ clean_wh(h_dir, wh); ++ if (do_plink) { ++ err = test_linkable(h_dir); ++ if (unlikely(err)) ++ goto out_nolink; ++ ++ err = plink_dir(h_dir, plink); ++ if (unlikely(err)) ++ goto out_err; ++ br->br_plink = dget(plink); ++ } else ++ clean_plink(h_dir, plink); ++ break; ++ ++ case AuBr_RW: ++ /* ++ * for the moment, aufs supports the branch filesystem ++ * which does not support link(2). ++ * testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. ++ * finally, such filesystem will not be used as the writable branch. ++ */ ++ err = test_linkable(h_dir); ++ if (unlikely(err)) ++ goto out_nolink; ++ ++ err = -EEXIST; ++ if (!wh->d_inode) ++ err = vfsub_create(h_dir, wh, WH_MASK, NULL, /*dlgt*/0); ++ else if (S_ISREG(wh->d_inode->i_mode)) ++ err = 0; ++ else ++ Err("unknown %.*s/%.*s exists\n", ++ DLNPair(h_root), DLNPair(wh)); ++ if (unlikely(err)) ++ goto out_err; ++ ++ if (do_plink) { ++ err = plink_dir(h_dir, plink); ++ if (unlikely(err)) ++ goto out_err; ++ br->br_plink = dget(plink); ++ } else ++ clean_plink(h_dir, plink); ++ br->br_wh = dget(wh); ++ break; ++ ++ default: ++ BUG(); ++ } ++ ++ out_dput: ++ dput(plink); ++ out_dput_wh: ++ dput(wh); ++ out: ++ TraceErr(err); ++ return err; ++ out_nolink: ++ Err("%.*s doesn't support link(2), use noplink and rw+nolwh\n", ++ DLNPair(h_root)); ++ goto out_dput; ++ out_err: ++ Err("an error(%d) on the writable branch %.*s(%s)\n", ++ err, DLNPair(h_root), au_sbtype(h_root->d_sb)); ++ goto out_dput; ++} ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct aufs_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ struct reinit_br_wh *a = arg; ++ struct inode *hidden_dir, *dir; ++ struct dentry *hidden_root; ++ aufs_bindex_t bindex; ++ ++ TraceEnter(); ++ DEBUG_ON(!a->br->br_wh || !a->br->br_wh->d_inode || current->fsuid); ++ ++ err = 0; ++ /* big lock */ ++ si_write_lock(a->sb); ++ if (unlikely(!br_writable(a->br->br_perm))) ++ goto out; ++ bindex = find_brindex(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ dir = a->sb->s_root->d_inode; ++ hidden_root = a->br->br_wh->d_parent; ++ hidden_dir = hidden_root->d_inode; ++ DEBUG_ON(!hidden_dir->i_op || !hidden_dir->i_op->link); ++ hdir_lock(hidden_dir, dir, bindex); ++ br_wh_write_lock(a->br); ++ err = vfsub_unlink(hidden_dir, a->br->br_wh, /*dlgt*/0); ++ //if (LktrCond) err = -1; ++ dput(a->br->br_wh); ++ a->br->br_wh = NULL; ++ if (!err) ++ err = init_wh(hidden_root, a->br, au_do_nfsmnt(a->br->br_mnt), ++ a->sb); ++ br_wh_write_unlock(a->br); ++ hdir_unlock(hidden_dir, dir, bindex); ++ ++ out: ++ atomic_dec(&a->br->br_wh_running); ++ br_put(a->br); ++ si_write_unlock(a->sb); ++ au_mntput(a->sb); ++ kfree(arg); ++ if (unlikely(err)) ++ IOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct aufs_branch *br) ++{ ++ int do_dec; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wh_running) != 1) ++ goto out; ++ ++ // ignore ENOMEM ++ arg = kmalloc(sizeof(*arg), GFP_KERNEL); ++ if (arg) { ++ // dec(wh_running), kfree(arg) and br_put() in reinit function ++ arg->sb = sb; ++ arg->br = br; ++ br_get(br); ++ /* prohibit umount */ ++ au_mntget(sb); ++ au_wkq_nowait(reinit_br_wh, arg, /*dlgt*/0); ++ do_dec = 0; ++ } ++ ++ out: ++ if (do_dec) ++ atomic_dec(&br->br_wh_running); ++} ++ ++/* ++ * create the whiteoute @wh. ++ */ ++static int link_or_create_wh(struct dentry *wh, struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ int err, dlgt; ++ struct aufs_branch *br; ++ struct dentry *hidden_parent; ++ struct inode *hidden_dir; ++ ++ LKTRTrace("%.*s\n", DLNPair(wh)); ++ SiMustReadLock(sb); ++ hidden_parent = wh->d_parent; ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ dlgt = need_dlgt(sb); ++ br = stobr(sb, bindex); ++ br_wh_read_lock(br); ++ if (br->br_wh) { ++ err = vfsub_link(br->br_wh, hidden_dir, wh, dlgt); ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ // link count full. re-initialize br_wh. ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ // return this error in this context ++ err = vfsub_create(hidden_dir, wh, WH_MASK, NULL, dlgt); ++ ++ out: ++ br_wh_read_unlock(br); ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ int do_create, int dlgt) ++{ ++ struct dentry *opq_dentry, *hidden_dentry; ++ struct inode *hidden_dir; ++ int err; ++ struct super_block *sb; ++ struct lkup_args lkup; ++ ++ LKTRTrace("%.*s, bindex %d, do_create %d\n", DLNPair(dentry), ++ bindex, do_create); ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ DEBUG_ON(!hidden_dentry); ++ hidden_dir = hidden_dentry->d_inode; ++ DEBUG_ON(!hidden_dir || !S_ISDIR(hidden_dir->i_mode)); ++ IMustLock(hidden_dir); ++ ++ // already checked by au_test_perm(). ++ sb = dentry->d_sb; ++ lkup.nfsmnt = au_nfsmnt(sb, bindex); ++ lkup.dlgt = dlgt; ++ opq_dentry = lkup_one(diropq_name.name, hidden_dentry, diropq_name.len, ++ &lkup); ++ //if (LktrCond) {dput(opq_dentry); opq_dentry = ERR_PTR(-1);} ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (do_create) { ++ DEBUG_ON(opq_dentry->d_inode); ++ err = link_or_create_wh(opq_dentry, sb, bindex); ++ //if (LktrCond) {vfs_unlink(hidden_dir, opq_dentry); err = -1;} ++ if (!err) { ++ set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ DEBUG_ON(/* !S_ISDIR(dentry->d_inode->i_mode) ++ * || */!opq_dentry->d_inode); ++ err = vfsub_unlink(hidden_dir, opq_dentry, lkup.dlgt); ++ //if (LktrCond) err = -1; ++ if (!err) ++ set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++ out: ++ TraceErrPtr(opq_dentry); ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ int do_create, dlgt; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->do_create, a->dlgt); ++} ++ ++struct dentry *sio_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ int do_create, int dlgt) ++{ ++ struct dentry *diropq, *hidden_dentry; ++ ++ LKTRTrace("%.*s, bindex %d, do_create %d\n", ++ DLNPair(dentry), bindex, do_create); ++ ++ hidden_dentry = au_h_dptr_i(dentry, bindex); ++ if (!au_test_perm(hidden_dentry->d_inode, MAY_EXEC | MAY_WRITE, dlgt)) ++ diropq = do_diropq(dentry, bindex, do_create, dlgt); ++ else { ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .do_create = do_create, ++ .dlgt = dlgt ++ }; ++ au_wkq_wait(call_do_diropq, &args, /*dlgt*/0); ++ } ++ ++ TraceErrPtr(diropq); ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @hidden_parent: hidden parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *lkup_wh(struct dentry *hidden_parent, struct qstr *base_name, ++ struct lkup_args *lkup) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ ++ LKTRTrace("%.*s/%.*s\n", DLNPair(hidden_parent), LNPair(base_name)); ++ IMustLock(hidden_parent->d_inode); ++ ++ err = au_alloc_whname(base_name->name, base_name->len, &wh_name); ++ //if (LktrCond) {au_free_whname(&wh_name); err = -1;} ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ // do not superio. ++ wh_dentry = lkup_one(wh_name.name, hidden_parent, wh_name.len, ++ lkup); ++ au_free_whname(&wh_name); ++ } ++ TraceErrPtr(wh_dentry); ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *simple_create_wh(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *hidden_parent, ++ struct lkup_args *lkup) ++{ ++ struct dentry *wh_dentry; ++ int err; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s/%.*s on b%d\n", DLNPair(hidden_parent), ++ DLNPair(dentry), bindex); ++ ++ sb = dentry->d_sb; ++ wh_dentry = lkup_wh(hidden_parent, &dentry->d_name, lkup); ++ //au_nfsmnt(sb, bindex), need_dlgt(sb)); ++ //if (LktrCond) {dput(wh_dentry); wh_dentry = ERR_PTR(-1);} ++ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { ++ IMustLock(hidden_parent->d_inode); ++ err = link_or_create_wh(wh_dentry, sb, bindex); ++ if (!err) ++ set_dbwh(dentry, bindex); ++ else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ TraceErrPtr(wh_dentry); ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory in branch bindex. */ ++static int del_wh_children(struct aufs_nhash *whlist, ++ struct dentry *hidden_parent, aufs_bindex_t bindex, ++ struct lkup_args *lkup) ++{ ++ int err, i; ++ struct qstr wh_name; ++ char *p; ++ struct inode *hidden_dir; ++ struct hlist_head *head; ++ struct aufs_wh *tpos; ++ struct hlist_node *pos; ++ struct aufs_destr *str; ++ ++ LKTRTrace("%.*s\n", DLNPair(hidden_parent)); ++ hidden_dir = hidden_parent->d_inode; ++ IMustLock(hidden_dir); ++ DEBUG_ON(IS_RDONLY(hidden_dir)); ++ //SiMustReadLock(??); ++ ++ err = -ENOMEM; ++ wh_name.name = p = __getname(); ++ //if (LktrCond) {__putname(p); wh_name.name = p = NULL;} ++ if (unlikely(!wh_name.name)) ++ goto out; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ ++ // already checked by au_test_perm(). ++ err = 0; ++ for (i = 0; !err && i < AUFS_NHASH_SIZE; i++) { ++ head = whlist->heads + i; ++ hlist_for_each_entry(tpos, pos, head, wh_hash) { ++ if (tpos->wh_bindex != bindex) ++ continue; ++ str = &tpos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(hidden_parent, &wh_name, ++ lkup); ++ //if (LktrCond) err = -1; ++ if (!err) ++ continue; ++ break; ++ } ++ IOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ __putname(wh_name.name); ++ ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct aufs_nhash *whlist; ++ struct dentry *hidden_parent; ++ aufs_bindex_t bindex; ++ struct lkup_args *lkup; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->whlist, a->hidden_parent, a->bindex, ++ a->lkup); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * rmdir the whiteouted temporary named dir @hidden_dentry. ++ * @whlist: whiteouted children. ++ */ ++int rmdir_whtmp(struct dentry *hidden_dentry, struct aufs_nhash *whlist, ++ aufs_bindex_t bindex, struct inode *dir, struct inode *inode) ++{ ++ int err; ++ struct inode *hidden_inode, *hidden_dir; ++ struct lkup_args lkup; ++ struct super_block *sb; ++ ++ LKTRTrace("hd %.*s, b%d, i%lu\n", ++ DLNPair(hidden_dentry), bindex, dir->i_ino); ++ IMustLock(dir); ++ IiMustAnyLock(dir); ++ hidden_dir = hidden_dentry->d_parent->d_inode; ++ IMustLock(hidden_dir); ++ ++ sb = inode->i_sb; ++ lkup.nfsmnt = au_nfsmnt(sb, bindex); ++ lkup.dlgt = need_dlgt(sb); ++ hidden_inode = hidden_dentry->d_inode; ++ DEBUG_ON(hidden_inode != au_h_iptr_i(inode, bindex)); ++ hdir2_lock(hidden_inode, inode, bindex); ++ if (!au_test_perm(hidden_inode, MAY_EXEC | MAY_WRITE, lkup.dlgt)) ++ err = del_wh_children(whlist, hidden_dentry, bindex, &lkup); ++ else { ++ // ugly ++ int dlgt = lkup.dlgt; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .whlist = whlist, ++ .hidden_parent = hidden_dentry, ++ .bindex = bindex, ++ .lkup = &lkup ++ }; ++ ++ lkup.dlgt = 0; ++ au_wkq_wait(call_del_wh_children, &args, /*dlgt*/0); ++ lkup.dlgt = dlgt; ++ } ++ hdir_unlock(hidden_inode, inode, bindex); ++ ++ if (!err) { ++ err = vfsub_rmdir(hidden_dir, hidden_dentry, lkup.dlgt); ++ //d_drop(hidden_dentry); ++ //if (LktrCond) err = -1; ++ } ++ ++ if (!err) { ++ if (ibstart(dir) == bindex) { ++ au_cpup_attr_timesizes(dir); ++ //au_cpup_attr_nlink(dir); ++ dir->i_nlink--; ++ } ++ return 0; /* success */ ++ } ++ ++ Warn("failed removing %.*s(%d), ignored\n", ++ DLNPair(hidden_dentry), err); ++ return err; ++} ++ ++static void do_rmdir_whtmp(void *arg) ++{ ++ int err; ++ struct rmdir_whtmp_arg *a = arg; ++ struct super_block *sb; ++ ++ LKTRTrace("%.*s, b%d, dir i%lu\n", ++ DLNPair(a->h_dentry), a->bindex, a->dir->i_ino); ++ ++ i_lock(a->dir); ++ sb = a->dir->i_sb; ++ si_read_lock(sb); ++ err = test_ro(sb, a->bindex, NULL); ++ if (!err) { ++ struct inode *hidden_dir = a->h_dentry->d_parent->d_inode; ++ ++ ii_write_lock_child(a->inode); ++ ii_write_lock_parent(a->dir); ++ hdir_lock(hidden_dir, a->dir, a->bindex); ++ err = rmdir_whtmp(a->h_dentry, &a->whlist, a->bindex, ++ a->dir, a->inode); ++ hdir_unlock(hidden_dir, a->dir, a->bindex); ++ ii_write_unlock(a->dir); ++ ii_write_unlock(a->inode); ++ } ++ dput(a->h_dentry); ++ nhash_fin(&a->whlist); ++ iput(a->inode); ++ si_read_unlock(sb); ++ au_mntput(sb); ++ i_unlock(a->dir); ++ iput(a->dir); ++ kfree(arg); ++ if (unlikely(err)) ++ IOErr("err %d\n", err); ++} ++ ++void kick_rmdir_whtmp(struct dentry *hidden_dentry, struct aufs_nhash *whlist, ++ aufs_bindex_t bindex, struct inode *dir, ++ struct inode *inode, struct rmdir_whtmp_arg *arg) ++{ ++ LKTRTrace("%.*s\n", DLNPair(hidden_dentry)); ++ IMustLock(dir); ++ ++ // all post-process will be done in do_rmdir_whtmp(). ++ arg->h_dentry = dget(hidden_dentry); ++ nhash_init(&arg->whlist); ++ nhash_move(&arg->whlist, whlist); ++ arg->bindex = bindex; ++ arg->dir = igrab(dir); ++ arg->inode = igrab(inode); ++ /* prohibit umount */ ++ au_mntget(dir->i_sb); ++ ++ au_wkq_nowait(do_rmdir_whtmp, arg, /*dlgt*/0); ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/whout.h linux-2.6.22.1/fs/aufs/whout.h +--- linux-2.6.22.1.oorig/fs/aufs/whout.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/whout.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: whout.h,v 1.8 2007/05/14 03:41:52 sfjro Exp $ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++int au_alloc_whname(const char *name, int len, struct qstr *wh); ++void au_free_whname(struct qstr *wh); ++ ++struct lkup_args; ++int is_wh(struct dentry *h_parent, struct qstr *wh_name, int try_sio, ++ struct lkup_args *lkup); ++int is_diropq(struct dentry *h_dentry, struct lkup_args *lkup); ++ ++struct dentry *lkup_whtmp(struct dentry *h_parent, struct qstr *prefix, ++ struct lkup_args *lkup); ++int rename_whtmp(struct dentry *dentry, aufs_bindex_t bindex); ++int au_unlink_wh_dentry(struct inode *h_dir, struct dentry *wh_dentry, ++ struct dentry *dentry, int dlgt); ++ ++struct aufs_branch; ++int init_wh(struct dentry *h_parent, struct aufs_branch *br, ++ struct vfsmount *nfsmnt, struct super_block *sb); ++ ++struct dentry *sio_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ int do_create, int dlgt); ++ ++struct dentry *lkup_wh(struct dentry *h_parent, struct qstr *base_name, ++ struct lkup_args *lkup); ++struct dentry *simple_create_wh(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, ++ struct lkup_args *lkup); ++ ++/* real rmdir the whiteout-ed dir */ ++struct rmdir_whtmp_arg { ++ struct dentry *h_dentry; ++ struct aufs_nhash whlist; ++ aufs_bindex_t bindex; ++ struct inode *dir, *inode; ++}; ++ ++struct aufs_nhash; ++int rmdir_whtmp(struct dentry *h_dentry, struct aufs_nhash *whlist, ++ aufs_bindex_t bindex, struct inode *dir, struct inode *inode); ++void kick_rmdir_whtmp(struct dentry *h_dentry, struct aufs_nhash *whlist, ++ aufs_bindex_t bindex, struct inode *dir, ++ struct inode *inode, struct rmdir_whtmp_arg *arg); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline ++struct dentry *create_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ int dlgt) ++{ ++ return sio_diropq(dentry, bindex, 1, dlgt); ++} ++ ++static inline ++int remove_diropq(struct dentry *dentry, aufs_bindex_t bindex, int dlgt) ++{ ++ return PTR_ERR(sio_diropq(dentry, bindex, 0, dlgt)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/wkq.c linux-2.6.22.1/fs/aufs/wkq.c +--- linux-2.6.22.1.oorig/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/wkq.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,283 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: wkq.c,v 1.14 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++#include ++#include "aufs.h" ++ ++struct au_wkq *au_wkq; ++ ++struct au_cred { ++#ifdef CONFIG_AUFS_DLGT ++ uid_t fsuid; ++ gid_t fsgid; ++ kernel_cap_t cap_effective, cap_inheritable, cap_permitted; ++ //unsigned keep_capabilities:1; ++ //struct user_struct *user; ++ //struct fs_struct *fs; ++ //struct nsproxy *nsproxy; ++#endif ++}; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ ++ unsigned int wait:1; ++ unsigned int dlgt:1; ++ struct au_cred cred; ++ ++ au_wkq_func_t func; ++ void *args; ++ ++ atomic_t *busyp; ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DLGT ++static void cred_store(struct au_cred *cred) ++{ ++ cred->fsuid = current->fsuid; ++ cred->fsgid = current->fsgid; ++ cred->cap_effective = current->cap_effective; ++ cred->cap_inheritable = current->cap_inheritable; ++ cred->cap_permitted = current->cap_permitted; ++} ++ ++static void cred_revert(struct au_cred *cred) ++{ ++ DEBUG_ON(!is_au_wkq(current)); ++ current->fsuid = cred->fsuid; ++ current->fsgid = cred->fsgid; ++ current->cap_effective = cred->cap_effective; ++ current->cap_inheritable = cred->cap_inheritable; ++ current->cap_permitted = cred->cap_permitted; ++} ++ ++static void cred_switch(struct au_cred *old, struct au_cred *new) ++{ ++ cred_store(old); ++ cred_revert(new); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void update_busy(struct au_wkq *wkq, struct au_wkinfo *wkinfo) ++{ ++#ifdef CONFIG_AUFS_SYSAUFS ++ unsigned int new, old; ++ ++ do { ++ new = atomic_read(wkinfo->busyp); ++ old = wkq->max_busy; ++ if (new <= old) ++ break; ++ } while (cmpxchg(&wkq->max_busy, old, new) == old); ++#endif ++} ++ ++static int enqueue(struct au_wkq *wkq, struct au_wkinfo *wkinfo) ++{ ++ wkinfo->busyp = &wkq->busy; ++ update_busy(wkq, wkinfo); ++ if (wkinfo->wait) ++ return !queue_work(wkq->q, &wkinfo->wk); ++ else ++ return !schedule_work(&wkinfo->wk); ++} ++ ++static void do_wkq(struct au_wkinfo *wkinfo) ++{ ++ unsigned int idle, n; ++ int i, idle_idx; ++ ++ TraceEnter(); ++ ++ while (1) { ++ if (wkinfo->wait) { ++ idle_idx = 0; ++ idle = UINT_MAX; ++ for (i = 0; i < aufs_nwkq; i++) { ++ n = atomic_inc_return(&au_wkq[i].busy); ++ if (n == 1 && !enqueue(au_wkq + i, wkinfo)) ++ return; /* success */ ++ ++ if (n < idle) { ++ idle_idx = i; ++ idle = n; ++ } ++ atomic_dec(&au_wkq[i].busy); ++ } ++ } else ++ idle_idx = aufs_nwkq; ++ ++ atomic_inc(&au_wkq[idle_idx].busy); ++ if (!enqueue(au_wkq + idle_idx, wkinfo)) ++ return; /* success */ ++ ++ /* impossible? */ ++ Warn1("failed to queue_work()\n"); ++ yield(); ++ } ++} ++ ++static AuWkqFunc(wkq_func, wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ LKTRTrace("wkinfo{%u, %u, %p, %p, %p}\n", ++ wkinfo->wait, wkinfo->dlgt, wkinfo->func, wkinfo->busyp, ++ wkinfo->comp); ++#ifdef CONFIG_AUFS_DLGT ++ if (!wkinfo->dlgt) ++ wkinfo->func(wkinfo->args); ++ else { ++ struct au_cred cred; ++ cred_switch(&cred, &wkinfo->cred); ++ wkinfo->func(wkinfo->args); ++ cred_revert(&cred); ++ } ++#else ++ wkinfo->func(wkinfo->args); ++#endif ++ atomic_dec(wkinfo->busyp); ++ if (wkinfo->wait) ++ complete(wkinfo->comp); ++ else { ++ kfree(wkinfo); ++ module_put(THIS_MODULE); ++ } ++} ++ ++void au_wkq_run(au_wkq_func_t func, void *args, int dlgt, int do_wait) ++{ ++ DECLARE_COMPLETION_ONSTACK(comp); ++ struct au_wkinfo _wkinfo = { ++ .wait = 1, ++ .dlgt = !!dlgt, ++ .func = func, ++ .args = args, ++ .comp = &comp ++ }, *wkinfo = &_wkinfo; ++ ++ LKTRTrace("dlgt %d, do_wait %d\n", dlgt, do_wait); ++ DEBUG_ON(is_au_wkq(current)); ++ ++ if (unlikely(!do_wait)) { ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ /* ++ * never fail. ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ wait_event(wq, (wkinfo = kmalloc(sizeof(*wkinfo), GFP_KERNEL))); ++ wkinfo->wait = 0; ++ wkinfo->dlgt = !!dlgt; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ __module_get(THIS_MODULE); ++ } ++ ++ AuInitWkq(&wkinfo->wk, wkq_func); ++#ifdef CONFIG_AUFS_DLGT ++ if (dlgt) ++ cred_store(&wkinfo->cred); ++#endif ++ do_wkq(wkinfo); ++ if (do_wait) ++ wait_for_completion(wkinfo->comp); ++} ++ ++#if 0 ++void au_wkq_wait_nwtask(void) ++{ ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ wait_event(wq, !atomic_read(&au_wkq[aufs_nwkq].busy)); ++} ++#endif ++ ++void au_wkq_fin(void) ++{ ++ int i; ++ ++ TraceEnter(); ++ ++ for (i = 0; i < aufs_nwkq; i++) ++ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) ++ destroy_workqueue(au_wkq[i].q); ++ kfree(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ int err, i; ++ struct au_wkq *nowaitq; ++ ++ LKTRTrace("%d\n", aufs_nwkq); ++ ++ /* '+1' is for accounting of nowait queue */ ++ err = -ENOMEM; ++ au_wkq = kcalloc(aufs_nwkq + 1, sizeof(*au_wkq), GFP_KERNEL); ++ if (unlikely(!au_wkq)) ++ goto out; ++ ++ err = 0; ++ for (i = 0; i < aufs_nwkq; i++) { ++ au_wkq[i].q = create_singlethread_workqueue(AUFS_WKQ_NAME); ++ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) { ++ atomic_set(&au_wkq[i].busy, 0); ++ au_wkq[i].max_busy = 0; ++ continue; ++ } ++ ++ err = PTR_ERR(au_wkq[i].q); ++ au_wkq_fin(); ++ break; ++ } ++ ++ /* nowait accounting */ ++ nowaitq = au_wkq + aufs_nwkq; ++ atomic_set(&nowaitq->busy, 0); ++ nowaitq->max_busy = 0; ++ nowaitq->q = NULL; ++ ++#if 0 // test accouting ++ if (!err) { ++ static void f(void *args) { ++ DbgSleep(1); ++ } ++ int i; ++ //au_debug_on(); ++ LKTRTrace("f %p\n", f); ++ for (i = 0; i < 10; i++) ++ au_wkq_nowait(f, NULL, 0); ++ for (i = 0; i < aufs_nwkq; i++) ++ au_wkq_wait(f, NULL, 0); ++ DbgSleep(11); ++ //au_debug_off(); ++ } ++#endif ++ ++ out: ++ TraceErr(err); ++ return err; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/wkq.h linux-2.6.22.1/fs/aufs/wkq.h +--- linux-2.6.22.1.oorig/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/wkq.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: wkq.h,v 1.9 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#define DECLARE_COMPLETION_ONSTACK(work) DECLARE_COMPLETION(work) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++struct au_wkq { ++ struct workqueue_struct *q; ++ ++ /* accounting */ ++ atomic_t busy; ++ unsigned int max_busy; ++} ;//__attribute__ ((aligned)); ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++#define AuInitWkq(wk, func) INIT_WORK(wk, func) ++#define AuWkqFunc(name, arg) void name(struct work_struct *arg) ++#else ++typedef void (*work_func_t)(void *arg); ++#define AuInitWkq(wk, func) INIT_WORK(wk, func, wk) ++#define AuWkqFunc(name, arg) void name(void *arg) ++#endif ++ ++extern struct au_wkq *au_wkq; ++ ++void au_wkq_run(au_wkq_func_t func, void *args, int dlgt, int do_wait); ++//void au_wkq_wait_nwtask(void); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int is_au_wkq(struct task_struct *tsk) ++{ ++ return (!tsk->mm && !strcmp(current->comm, AUFS_WKQ_NAME)); ++} ++ ++static inline void au_wkq_wait(au_wkq_func_t func, void *args, int dlgt) ++{ ++ au_wkq_run(func, args, dlgt, /*do_wait*/1); ++} ++ ++static inline void au_wkq_nowait(au_wkq_func_t func, void *args, int dlgt) ++{ ++ au_wkq_run(func, args, dlgt, /*do_wait*/0); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff -rduNp linux-2.6.22.1.oorig/fs/aufs/xino.c linux-2.6.22.1/fs/aufs/xino.c +--- linux-2.6.22.1.oorig/fs/aufs/xino.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/aufs/xino.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,644 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: xino.c,v 1.27 2007/05/14 03:39:10 sfjro Exp $ */ ++ ++//#include ++#include ++#include ++#include "aufs.h" ++ ++static readf_t find_readf(struct file *h_file) ++{ ++ const struct file_operations *fop = h_file->f_op; ++ ++ if (fop) { ++ if (fop->read) ++ return fop->read; ++ if (fop->aio_read) ++ return do_sync_read; ++ } ++ return ERR_PTR(-ENOSYS); ++} ++ ++static writef_t find_writef(struct file *h_file) ++{ ++ const struct file_operations *fop = h_file->f_op; ++ ++ if (fop) { ++ if (fop->write) ++ return fop->write; ++ if (fop->aio_write) ++ return do_sync_write; ++ } ++ return ERR_PTR(-ENOSYS); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t xino_fread(readf_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ LKTRTrace("%.*s, sz %lu, *pos %Ld\n", ++ DLNPair(file->f_dentry), (unsigned long)size, *pos); ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, (char __user*)buf, size, pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ set_fs(oldfs); ++ ++#if 0 ++ if (err > 0) ++ fsnotify_access(file->f_dentry); ++#endif ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t do_xino_fwrite(writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ lockdep_off(); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, (const char __user*)buf, size, pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ set_fs(oldfs); ++ lockdep_on(); ++ ++#if 0 ++ if (err > 0) ++ fsnotify_modify(file->f_dentry); ++#endif ++ ++ TraceErr(err); ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ writef_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite(writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ ++ LKTRTrace("%.*s, sz %lu, *pos %Ld\n", ++ DLNPair(file->f_dentry), (unsigned long)size, *pos); ++ ++ // signal block and no wkq? ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ if (!is_au_wkq(current)) { ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ au_wkq_wait(call_do_xino_fwrite, &args, /*dlgt*/0); ++ } else ++ err = do_xino_fwrite(func, file, buf, size, pos); ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @_ino. ++ * when @ino is zero, it is written to the xinofile and means no entry. ++ */ ++int xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ struct xino *xino) ++{ ++ struct aufs_branch *br; ++ loff_t pos; ++ ssize_t sz; ++ ++ LKTRTrace("b%d, hi%lu, i%lu\n", bindex, h_ino, xino->ino); ++ //DEBUG_ON(!xino->ino /* || !xino->h_gen */); ++ //WARN_ON(bindex == 0 && h_ino == 31); ++ ++ if (unlikely(!au_flag_test(sb, AuFlag_XINO))) ++ return 0; ++ ++ br = stobr(sb, bindex); ++ DEBUG_ON(!br || !br->br_xino); ++ pos = h_ino * sizeof(*xino); ++ sz = xino_fwrite(br->br_xino_write, br->br_xino, xino, sizeof(*xino), ++ &pos); ++ //if (LktrCond) sz = 1; ++ if (sz == sizeof(*xino)) ++ return 0; /* success */ ++ ++ IOErr("write failed (%ld)\n", (long)sz); ++ return -EIO; ++} ++ ++int xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct xino xino = { ++ .ino = 0 ++ }; ++ return xino_write(sb, bindex, h_ino, &xino); ++} ++ ++// why is not atomic_long_inc_return defined? ++static DEFINE_SPINLOCK(alir_lock); ++static long atomic_long_inc_return(atomic_long_t *a) ++{ ++ long l; ++ ++ spin_lock(&alir_lock); ++ atomic_long_inc(a); ++ l = atomic_long_read(a); ++ spin_unlock(&alir_lock); ++ return l; ++} ++ ++ino_t xino_new_ino(struct super_block *sb) ++{ ++ ino_t ino; ++ ++ TraceEnter(); ++ ino = atomic_long_inc_return(&stosi(sb)->si_xino); ++ BUILD_BUG_ON(AUFS_FIRST_INO < AUFS_ROOT_INO); ++ if (ino >= AUFS_ROOT_INO) ++ return ino; ++ else { ++ atomic_long_dec(&stosi(sb)->si_xino); ++ IOErr1("inode number overflow\n"); ++ return 0; ++ } ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * if @ino does not exist and @do_new is true, get new one. ++ */ ++int xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ struct xino *xino) ++{ ++ int err; ++ struct aufs_branch *br; ++ struct file *file; ++ loff_t pos; ++ ssize_t sz; ++ ++ LKTRTrace("b%d, hi%lu\n", bindex, h_ino); ++ ++ err = 0; ++ xino->ino = 0; ++ if (unlikely(!au_flag_test(sb, AuFlag_XINO))) ++ return 0; /* no ino */ ++ ++ br = stobr(sb, bindex); ++ file = br->br_xino; ++ DEBUG_ON(!file); ++ pos = h_ino * sizeof(*xino); ++ if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*xino)) ++ return 0; /* no ino */ ++ ++ sz = xino_fread(br->br_xino_read, file, xino, sizeof(*xino), &pos); ++ if (sz == sizeof(*xino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ IOErr("xino read error (%ld)\n", (long)sz); ++ } ++ ++ TraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file *xino_create(struct super_block *sb, char *fname, int silent, ++ struct dentry *parent) ++{ ++ struct file *file; ++ int err; ++ struct dentry *hidden_parent; ++ struct inode *hidden_dir; ++ //const int udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY); ++ ++ LKTRTrace("%s\n", fname); ++ //DEBUG_ON(!au_flag_test(sb, AuFlag_XINO)); ++ ++ // LSM may detect it ++ // use sio? ++ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, ++ S_IRUGO | S_IWUGO); ++ //file = ERR_PTR(-1); ++ if (IS_ERR(file)) { ++ if (!silent) ++ Err("open %s(%ld)\n", fname, PTR_ERR(file)); ++ return file; ++ } ++#if 0 ++ if (unlikely(udba && parent)) ++ au_direval_dec(parent); ++#endif ++ ++ /* keep file count */ ++ hidden_parent = dget_parent(file->f_dentry); ++ hidden_dir = hidden_parent->d_inode; ++ hi_lock_parent(hidden_dir); ++ err = vfsub_unlink(hidden_dir, file->f_dentry, /*dlgt*/0); ++#if 0 ++ if (unlikely(!err && udba && parent)) ++ au_direval_dec(parent); ++#endif ++ i_unlock(hidden_dir); ++ dput(hidden_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ Err("unlink %s(%d)\n", fname, err); ++ goto out; ++ } ++ if (sb != file->f_dentry->d_sb) ++ return file; /* success */ ++ ++ if (!silent) ++ Err("%s must be outside\n", fname); ++ err = -EINVAL; ++ ++ out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bend. ++ */ ++static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bend) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb = sbr_sb(sb, btgt); ++ ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (unlikely(btgt != bindex && tgt_sb == sbr_sb(sb, bindex))) ++ return bindex; ++ return -1; ++} ++ ++/* ++ * create a new xinofile at the same place/path as @base_file. ++ */ ++static struct file *xino_create2(struct file *base_file) ++{ ++ struct file *file; ++ int err; ++ struct dentry *base, *dentry, *parent; ++ struct inode *dir; ++ struct qstr *name; ++ struct lkup_args lkup = { ++ .nfsmnt = NULL, ++ .dlgt = 0 ++ }; ++ ++ base = base_file->f_dentry; ++ LKTRTrace("%.*s\n", DLNPair(base)); ++ parent = dget_parent(base); ++ dir = parent->d_inode; ++ IMustLock(dir); ++ ++ file = ERR_PTR(-EINVAL); ++ if (unlikely(au_is_nfs(parent->d_sb))) ++ goto out; ++ ++ // do not superio, nor NFS. ++ name = &base->d_name; ++ dentry = lkup_one(name->name, parent, name->len, &lkup); ++ //if (LktrCond) {dput(dentry); dentry = ERR_PTR(-1);} ++ if (IS_ERR(dentry)) { ++ file = (void*)dentry; ++ Err("%.*s lookup err %ld\n", LNPair(name), PTR_ERR(dentry)); ++ goto out; ++ } ++ err = vfsub_create(dir, dentry, S_IRUGO | S_IWUGO, NULL, /*dlgt*/0); ++ //if (LktrCond) {vfs_unlink(dir, dentry); err = -1;} ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ Err("%.*s create err %d\n", LNPair(name), err); ++ goto out_dput; ++ } ++ file = dentry_open(dget(dentry), mntget(base_file->f_vfsmnt), ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ if (IS_ERR(file)) { ++ Err("%.*s open err %ld\n", LNPair(name), PTR_ERR(file)); ++ goto out_dput; ++ } ++ err = vfsub_unlink(dir, dentry, /*dlgt*/0); ++ //if (LktrCond) err = -1; ++ if (!err) ++ goto out_dput; /* success */ ++ ++ Err("%.*s unlink err %d\n", LNPair(name), err); ++ fput(file); ++ file = ERR_PTR(err); ++ ++ out_dput: ++ dput(dentry); ++ out: ++ dput(parent); ++ TraceErrPtr(file); ++ return file; ++} ++ ++/* ++ * initialize the xinofile for the specified branch{@sb, @bindex} ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if @do_test is true. ++ */ ++int xino_init(struct super_block *sb, aufs_bindex_t bindex, ++ struct file *base_file, int do_test) ++{ ++ int err; ++ struct aufs_branch *br; ++ aufs_bindex_t bshared, bend; ++ struct file *file; ++ struct inode *inode, *hidden_inode; ++ struct xino xino; ++ ++ LKTRTrace("b%d, base_file %p, do_test %d\n", ++ bindex, base_file, do_test); ++ SiMustWriteLock(sb); ++ DEBUG_ON(!au_flag_test(sb, AuFlag_XINO)); ++ br = stobr(sb, bindex); ++ DEBUG_ON(br->br_xino); ++ ++ file = NULL; ++ bshared = -1; ++ bend = sbend(sb); ++ if (do_test) ++ bshared = is_sb_shared(sb, bindex, bend); ++ if (unlikely(bshared >= 0)) { ++ struct aufs_branch *shared_br = stobr(sb, bshared); ++ if (shared_br->br_xino) { ++ file = shared_br->br_xino; ++ get_file(file); ++ } ++ } ++ ++ if (!file) { ++ struct dentry *parent = dget_parent(base_file->f_dentry); ++ struct inode *dir = parent->d_inode; ++ ++ hi_lock_parent(dir); ++ file = xino_create2(base_file); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ i_unlock(dir); ++ dput(parent); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ } ++ br->br_xino_read = find_readf(file); ++ err = PTR_ERR(br->br_xino_read); ++ if (IS_ERR(br->br_xino_read)) ++ goto out_put; ++ br->br_xino_write = find_writef(file); ++ err = PTR_ERR(br->br_xino_write); ++ if (IS_ERR(br->br_xino_write)) ++ goto out_put; ++ br->br_xino = file; ++ ++ inode = sb->s_root->d_inode; ++ hidden_inode = au_h_iptr_i(inode, bindex); ++ xino.ino = inode->i_ino; ++ //xino.h_gen = hidden_inode->i_generation; ++ //WARN_ON(xino.h_gen == AuXino_INVALID_HGEN); ++ err = xino_write(sb, bindex, hidden_inode->i_ino, &xino); ++ //if (LktrCond) err = -1; ++ if (!err) ++ return 0; /* success */ ++ ++ br->br_xino = NULL; ++ ++ out_put: ++ fput(file); ++ out: ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * set xino mount option. ++ */ ++int xino_set(struct super_block *sb, struct opt_xino *xino, int remount) ++{ ++ int err, sparse; ++ aufs_bindex_t bindex, bend; ++ struct aufs_branch *br; ++ struct dentry *parent; ++ struct qstr *name; ++ struct file *cur_xino; ++ struct inode *dir; ++ ++ LKTRTrace("%s\n", xino->path); ++ ++ err = 0; ++ name = &xino->file->f_dentry->d_name; ++ parent = dget_parent(xino->file->f_dentry); ++ dir = parent->d_inode; ++ cur_xino = stobr(sb, 0)->br_xino; ++ if (remount ++ && cur_xino ++ && cur_xino->f_dentry->d_parent == parent ++ && name->len == cur_xino->f_dentry->d_name.len ++ && !memcmp(name->name, cur_xino->f_dentry->d_name.name, name->len)) ++ goto out; ++ ++ au_flag_set(sb, AuFlag_XINO); ++ bend = sbend(sb); ++ for (bindex = bend; bindex >= 0; bindex--) { ++ br = stobr(sb, bindex); ++ if (unlikely(br->br_xino && file_count(br->br_xino) > 1)) { ++ fput(br->br_xino); ++ br->br_xino = NULL; ++ } ++ } ++ ++ for (bindex = 0; bindex <= bend; bindex++) { ++ struct file *file; ++ struct inode *inode; ++ ++ br = stobr(sb, bindex); ++ if (unlikely(!br->br_xino)) ++ continue; ++ ++ DEBUG_ON(file_count(br->br_xino) != 1); ++ hi_lock_parent(dir); ++ file = xino_create2(xino->file); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) { ++ i_unlock(dir); ++ break; ++ } ++ inode = br->br_xino->f_dentry->d_inode; ++ err = au_copy_file(file, br->br_xino, i_size_read(inode), sb, ++ &sparse); ++ //if (LktrCond) err = -1; ++ i_unlock(dir); ++ if (unlikely(err)) { ++ fput(file); ++ break; ++ } ++ fput(br->br_xino); ++ br->br_xino = file; ++ br->br_xino_read = find_readf(file); ++ DEBUG_ON(IS_ERR(br->br_xino_read)); ++ br->br_xino_write = find_writef(file); ++ DEBUG_ON(IS_ERR(br->br_xino_write)); ++ } ++ ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (unlikely(!stobr(sb, bindex)->br_xino)) { ++ err = xino_init(sb, bindex, xino->file, /*do_test*/1); ++ //if (LktrCond) {fput(stobr(sb, bindex)->br_xino); ++ //stobr(sb, bindex)->br_xino = NULL; err = -1;} ++ if (!err) ++ continue; ++ IOErr("creating xino for branch %d(%d), " ++ "forcing noxino\n", bindex, err); ++ err = -EIO; ++ break; ++ } ++ out: ++ dput(parent); ++ if (!err) ++ au_flag_set(sb, AuFlag_XINO); ++ else ++ au_flag_clr(sb, AuFlag_XINO); ++ TraceErr(err); ++ return err; ++} ++ ++/* ++ * clear xino mount option ++ */ ++int xino_clr(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ TraceEnter(); ++ SiMustWriteLock(sb); ++ ++ bend = sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ struct aufs_branch *br; ++ br = stobr(sb, bindex); ++ if (br->br_xino) { ++ fput(br->br_xino); ++ br->br_xino = NULL; ++ } ++ } ++ ++ //todo: need to make iunique() to return the larger inode number ++ ++ au_flag_clr(sb, AuFlag_XINO); ++ return 0; ++} ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ aufs_bindex_t bend, bindex, bwr; ++ char *page, *p; ++ ++ bend = sbend(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (br_writable(sbr_perm(sb, bindex)) ++ && !au_is_nfs(au_h_dptr_i(sb->s_root, bindex)->d_sb)) { ++ bwr = bindex; ++ break; ++ } ++ ++ if (bwr != -1) { ++ // todo: rewrite with lkup_one() ++ file = ERR_PTR(-ENOMEM); ++ page = __getname(); ++ //if (LktrCond) {__putname(page); page = NULL;} ++ if (unlikely(!page)) ++ goto out; ++ p = d_path(au_h_dptr_i(sb->s_root, bwr), sbr_mnt(sb, bwr), page, ++ PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ //if (LktrCond) p = ERR_PTR(-1); ++ file = (void*)p; ++ if (p && !IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ LKTRTrace("%s\n", p); ++ file = xino_create(sb, p, /*silent*/0, sb->s_root); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ } ++ __putname(page); ++ } else { ++ file = xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, ++ /*parent*/NULL); ++ //if (LktrCond) {fput(file); file = ERR_PTR(-1);} ++ } ++ ++ out: ++ TraceErrPtr(file); ++ return file; ++} +diff -rduNp linux-2.6.22.1.oorig/fs/squashfs/Makefile linux-2.6.22.1/fs/squashfs/Makefile +--- linux-2.6.22.1.oorig/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/squashfs/Makefile 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,7 @@ ++# ++# Makefile for the linux squashfs routines. ++# ++ ++obj-$(CONFIG_SQUASHFS) += squashfs.o ++squashfs-y += inode.o ++squashfs-y += squashfs2_0.o +diff -rduNp linux-2.6.22.1.oorig/fs/squashfs/inode.c linux-2.6.22.1/fs/squashfs/inode.c +--- linux-2.6.22.1.oorig/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/squashfs/inode.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,2329 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * inode.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "squashfs.h" ++ ++static void vfs_read_inode(struct inode *i); ++static struct dentry *squashfs_get_parent(struct dentry *child); ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); ++static int squashfs_statfs(struct dentry *, struct kstatfs *); ++static int squashfs_symlink_readpage(struct file *file, struct page *page); ++static long long read_blocklist(struct inode *inode, int index, ++ int readahead_blks, char *block_list, ++ unsigned short **block_p, unsigned int *bsize); ++static int squashfs_readpage(struct file *file, struct page *page); ++static int squashfs_readpage4K(struct file *file, struct page *page); ++static int squashfs_readdir(struct file *, void *, filldir_t); ++static struct dentry *squashfs_lookup(struct inode *, struct dentry *, ++ struct nameidata *); ++static int squashfs_remount(struct super_block *s, int *flags, char *data); ++static void squashfs_put_super(struct super_block *); ++static int squashfs_get_sb(struct file_system_type *,int, const char *, void *, ++ struct vfsmount *); ++static struct inode *squashfs_alloc_inode(struct super_block *sb); ++static void squashfs_destroy_inode(struct inode *inode); ++static int init_inodecache(void); ++static void destroy_inodecache(void); ++ ++static struct file_system_type squashfs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "squashfs", ++ .get_sb = squashfs_get_sb, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV ++}; ++ ++static const unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static struct super_operations squashfs_super_ops = { ++ .alloc_inode = squashfs_alloc_inode, ++ .destroy_inode = squashfs_destroy_inode, ++ .statfs = squashfs_statfs, ++ .put_super = squashfs_put_super, ++ .remount_fs = squashfs_remount ++}; ++ ++static struct super_operations squashfs_export_super_ops = { ++ .alloc_inode = squashfs_alloc_inode, ++ .destroy_inode = squashfs_destroy_inode, ++ .statfs = squashfs_statfs, ++ .put_super = squashfs_put_super, ++ .read_inode = vfs_read_inode ++}; ++ ++static struct export_operations squashfs_export_ops = { ++ .get_parent = squashfs_get_parent ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = { ++ .readpage = squashfs_symlink_readpage ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_aops = { ++ .readpage = squashfs_readpage ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_aops_4K = { ++ .readpage = squashfs_readpage4K ++}; ++ ++static const struct file_operations squashfs_dir_ops = { ++ .read = generic_read_dir, ++ .readdir = squashfs_readdir ++}; ++ ++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = { ++ .lookup = squashfs_lookup ++}; ++ ++ ++static struct buffer_head *get_block_length(struct super_block *s, ++ int *cur_index, int *offset, int *c_byte) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ unsigned short temp; ++ struct buffer_head *bh; ++ ++ if (!(bh = sb_bread(s, *cur_index))) ++ goto out; ++ ++ if (msblk->devblksize - *offset == 1) { ++ if (msblk->swap) ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ else ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ brelse(bh); ++ if (!(bh = sb_bread(s, ++(*cur_index)))) ++ goto out; ++ if (msblk->swap) ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ bh->b_data); ++ else ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ bh->b_data); ++ *c_byte = temp; ++ *offset = 1; ++ } else { ++ if (msblk->swap) { ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset + 1)); ++ } else { ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset + 1)); ++ } ++ *c_byte = temp; ++ *offset += 2; ++ } ++ ++ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) { ++ if (*offset == msblk->devblksize) { ++ brelse(bh); ++ if (!(bh = sb_bread(s, ++(*cur_index)))) ++ goto out; ++ *offset = 0; ++ } ++ if (*((unsigned char *) (bh->b_data + *offset)) != ++ SQUASHFS_MARKER_BYTE) { ++ ERROR("Metadata block marker corrupt @ %x\n", ++ *cur_index); ++ brelse(bh); ++ goto out; ++ } ++ (*offset)++; ++ } ++ return bh; ++ ++out: ++ return NULL; ++} ++ ++ ++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, ++ long long index, unsigned int length, ++ long long *next_index, int srclength) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> ++ msblk->devblksize_log2) + 2]; ++ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); ++ unsigned int cur_index = index >> msblk->devblksize_log2; ++ int bytes, avail_bytes, b = 0, k = 0; ++ unsigned int compressed; ++ unsigned int c_byte = length; ++ ++ if (c_byte) { ++ bytes = msblk->devblksize - offset; ++ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); ++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); ++ ++ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed ++ ? "" : "un", (unsigned int) c_byte, srclength); ++ ++ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used) ++ goto read_failure; ++ ++ if (!(bh[0] = sb_getblk(s, cur_index))) ++ goto block_release; ++ ++ for (b = 1; bytes < c_byte; b++) { ++ if (!(bh[b] = sb_getblk(s, ++cur_index))) ++ goto block_release; ++ bytes += msblk->devblksize; ++ } ++ ll_rw_block(READ, b, bh); ++ } else { ++ if (index < 0 || (index + 2) > sblk->bytes_used) ++ goto read_failure; ++ ++ if (!(bh[0] = get_block_length(s, &cur_index, &offset, ++ &c_byte))) ++ goto read_failure; ++ ++ bytes = msblk->devblksize - offset; ++ compressed = SQUASHFS_COMPRESSED(c_byte); ++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); ++ ++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed ++ ? "" : "un", (unsigned int) c_byte); ++ ++ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used) ++ goto read_failure; ++ ++ for (b = 1; bytes < c_byte; b++) { ++ if (!(bh[b] = sb_getblk(s, ++cur_index))) ++ goto block_release; ++ bytes += msblk->devblksize; ++ } ++ ll_rw_block(READ, b - 1, bh + 1); ++ } ++ ++ if (compressed) { ++ int zlib_err = 0; ++ ++ /* ++ * uncompress block ++ */ ++ ++ mutex_lock(&msblk->read_data_mutex); ++ ++ msblk->stream.next_out = buffer; ++ msblk->stream.avail_out = srclength; ++ ++ for (bytes = 0; k < b; k++) { ++ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? ++ msblk->devblksize - offset : ++ c_byte - bytes; ++ wait_on_buffer(bh[k]); ++ if (!buffer_uptodate(bh[k])) ++ goto release_mutex; ++ ++ msblk->stream.next_in = bh[k]->b_data + offset; ++ msblk->stream.avail_in = avail_bytes; ++ ++ if (k == 0) { ++ zlib_err = zlib_inflateInit(&msblk->stream); ++ if (zlib_err != Z_OK) { ++ ERROR("zlib_inflateInit returned unexpected result 0x%x, srclength %d\n", ++ zlib_err, srclength); ++ goto release_mutex; ++ } ++ ++ if (avail_bytes == 0) { ++ offset = 0; ++ brelse(bh[k]); ++ continue; ++ } ++ } ++ ++ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); ++ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) { ++ ERROR("zlib_inflate returned unexpected result 0x%x, srclength %d, avail_in %d, avail_out %d\n", ++ zlib_err, srclength, msblk->stream.avail_in, msblk->stream.avail_out); ++ goto release_mutex; ++ } ++ ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ ++ if (zlib_err != Z_STREAM_END) ++ goto release_mutex; ++ ++ zlib_err = zlib_inflateEnd(&msblk->stream); ++ if (zlib_err != Z_OK) { ++ ERROR("zlib_inflateEnd returned unexpected result 0x%x, srclength %d\n", ++ zlib_err, srclength); ++ goto release_mutex; ++ } ++ bytes = msblk->stream.total_out; ++ mutex_unlock(&msblk->read_data_mutex); ++ } else { ++ int i; ++ ++ for(i = 0; i < b; i++) { ++ wait_on_buffer(bh[i]); ++ if(!buffer_uptodate(bh[i])) ++ goto block_release; ++ } ++ ++ for (bytes = 0; k < b; k++) { ++ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? ++ msblk->devblksize - offset : ++ c_byte - bytes; ++ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes); ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ } ++ ++ if (next_index) ++ *next_index = index + c_byte + (length ? 0 : ++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ++ ? 3 : 2)); ++ return bytes; ++ ++release_mutex: ++ mutex_unlock(&msblk->read_data_mutex); ++ ++block_release: ++ for (; k < b; k++) ++ brelse(bh[k]); ++ ++read_failure: ++ ERROR("sb_bread failed reading block 0x%x\n", cur_index); ++ return 0; ++} ++ ++ ++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, ++ long long block, unsigned int offset, ++ int length, long long *next_block, ++ unsigned int *next_offset) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ int n, i, bytes, return_length = length; ++ long long next_index; ++ ++ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); ++ ++ while ( 1 ) { ++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ if (msblk->block_cache[i].block == block) ++ break; ++ ++ mutex_lock(&msblk->block_cache_mutex); ++ ++ if (i == SQUASHFS_CACHED_BLKS) { ++ /* read inode header block */ ++ for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS; ++ n ; n --, i = (i + 1) % ++ SQUASHFS_CACHED_BLKS) ++ if (msblk->block_cache[i].block != ++ SQUASHFS_USED_BLK) ++ break; ++ ++ if (n == 0) { ++ wait_queue_t wait; ++ ++ init_waitqueue_entry(&wait, current); ++ add_wait_queue(&msblk->waitq, &wait); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ mutex_unlock(&msblk->block_cache_mutex); ++ schedule(); ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&msblk->waitq, &wait); ++ continue; ++ } ++ msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS; ++ ++ if (msblk->block_cache[i].block == ++ SQUASHFS_INVALID_BLK) { ++ if (!(msblk->block_cache[i].data = ++ kmalloc(SQUASHFS_METADATA_SIZE, ++ GFP_KERNEL))) { ++ ERROR("Failed to allocate cache" ++ "block\n"); ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } ++ } ++ ++ msblk->block_cache[i].block = SQUASHFS_USED_BLK; ++ mutex_unlock(&msblk->block_cache_mutex); ++ ++ msblk->block_cache[i].length = squashfs_read_data(s, ++ msblk->block_cache[i].data, block, 0, &next_index, SQUASHFS_METADATA_SIZE); ++ if (msblk->block_cache[i].length == 0) { ++ ERROR("Unable to read cache block [%llx:%x]\n", ++ block, offset); ++ mutex_lock(&msblk->block_cache_mutex); ++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; ++ kfree(msblk->block_cache[i].data); ++ wake_up(&msblk->waitq); ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } ++ ++ mutex_lock(&msblk->block_cache_mutex); ++ wake_up(&msblk->waitq); ++ msblk->block_cache[i].block = block; ++ msblk->block_cache[i].next_index = next_index; ++ TRACE("Read cache block [%llx:%x]\n", block, offset); ++ } ++ ++ if (msblk->block_cache[i].block != block) { ++ mutex_unlock(&msblk->block_cache_mutex); ++ continue; ++ } ++ ++ bytes = msblk->block_cache[i].length - offset; ++ ++ if (bytes < 1) { ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } else if (bytes >= length) { ++ if (buffer) ++ memcpy(buffer, msblk->block_cache[i].data + ++ offset, length); ++ if (msblk->block_cache[i].length - offset == length) { ++ *next_block = msblk->block_cache[i].next_index; ++ *next_offset = 0; ++ } else { ++ *next_block = block; ++ *next_offset = offset + length; ++ } ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto finish; ++ } else { ++ if (buffer) { ++ memcpy(buffer, msblk->block_cache[i].data + ++ offset, bytes); ++ buffer += bytes; ++ } ++ block = msblk->block_cache[i].next_index; ++ mutex_unlock(&msblk->block_cache_mutex); ++ length -= bytes; ++ offset = 0; ++ } ++ } ++ ++finish: ++ return return_length; ++out: ++ return 0; ++} ++ ++ ++static int get_fragment_location(struct super_block *s, unsigned int fragment, ++ long long *fragment_start_block, ++ unsigned int *fragment_size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start_block = ++ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); ++ struct squashfs_fragment_entry fragment_entry; ++ ++ if (msblk->swap) { ++ struct squashfs_fragment_entry sfragment_entry; ++ ++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, ++ start_block, offset, ++ sizeof(sfragment_entry), &start_block, ++ &offset)) ++ goto out; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, ++ start_block, offset, ++ sizeof(fragment_entry), &start_block, ++ &offset)) ++ goto out; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++ ++out: ++ return 0; ++} ++ ++ ++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct ++ squashfs_fragment_cache *fragment) ++{ ++ mutex_lock(&msblk->fragment_mutex); ++ fragment->locked --; ++ wake_up(&msblk->fragment_wait_queue); ++ mutex_unlock(&msblk->fragment_mutex); ++} ++ ++ ++SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block ++ *s, long long start_block, ++ int length) ++{ ++ int i, n; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ while ( 1 ) { ++ mutex_lock(&msblk->fragment_mutex); ++ ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS && ++ msblk->fragment[i].block != start_block; i++); ++ ++ if (i == SQUASHFS_CACHED_FRAGMENTS) { ++ for (i = msblk->next_fragment, n = ++ SQUASHFS_CACHED_FRAGMENTS; n && ++ msblk->fragment[i].locked; n--, i = (i + 1) % ++ SQUASHFS_CACHED_FRAGMENTS); ++ ++ if (n == 0) { ++ wait_queue_t wait; ++ ++ init_waitqueue_entry(&wait, current); ++ add_wait_queue(&msblk->fragment_wait_queue, ++ &wait); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ mutex_unlock(&msblk->fragment_mutex); ++ schedule(); ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&msblk->fragment_wait_queue, ++ &wait); ++ continue; ++ } ++ msblk->next_fragment = (msblk->next_fragment + 1) % ++ SQUASHFS_CACHED_FRAGMENTS; ++ ++ if (msblk->fragment[i].data == NULL) ++ if (!(msblk->fragment[i].data = SQUASHFS_ALLOC ++ (SQUASHFS_FILE_MAX_SIZE))) { ++ ERROR("Failed to allocate fragment " ++ "cache block\n"); ++ mutex_unlock(&msblk->fragment_mutex); ++ goto out; ++ } ++ ++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ msblk->fragment[i].locked = 1; ++ mutex_unlock(&msblk->fragment_mutex); ++ ++ if (!(msblk->fragment[i].length = squashfs_read_data(s, ++ msblk->fragment[i].data, ++ start_block, length, NULL, sblk->block_size))) { ++ ERROR("Unable to read fragment cache block " ++ "[%llx]\n", start_block); ++ msblk->fragment[i].locked = 0; ++ smp_mb(); ++ goto out; ++ } ++ ++ mutex_lock(&msblk->fragment_mutex); ++ msblk->fragment[i].block = start_block; ++ TRACE("New fragment %d, start block %lld, locked %d\n", ++ i, msblk->fragment[i].block, ++ msblk->fragment[i].locked); ++ mutex_unlock(&msblk->fragment_mutex); ++ break; ++ } ++ ++ msblk->fragment[i].locked++; ++ mutex_unlock(&msblk->fragment_mutex); ++ TRACE("Got fragment %d, start block %lld, locked %d\n", i, ++ msblk->fragment[i].block, ++ msblk->fragment[i].locked); ++ break; ++ } ++ ++ return &msblk->fragment[i]; ++ ++out: ++ return NULL; ++} ++ ++ ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, ++ struct squashfs_base_inode_header *inodeb) ++{ ++ i->i_ino = inodeb->inode_number; ++ i->i_mtime.tv_sec = inodeb->mtime; ++ i->i_atime.tv_sec = inodeb->mtime; ++ i->i_ctime.tv_sec = inodeb->mtime; ++ i->i_uid = msblk->uid[inodeb->uid]; ++ i->i_mode = inodeb->mode; ++ i->i_size = 0; ++ if (inodeb->guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msblk->guid[inodeb->guid]; ++} ++ ++ ++static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)]; ++ int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1); ++ squashfs_inode_t inode; ++ ++ TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino); ++ ++ if (msblk->swap) { ++ squashfs_inode_t sinode; ++ ++ if (!squashfs_get_cached_block(s, (char *) &sinode, start, offset, ++ sizeof(sinode), &start, &offset)) ++ goto out; ++ SQUASHFS_SWAP_INODE_T((&inode), &sinode); ++ } else if (!squashfs_get_cached_block(s, (char *) &inode, start, offset, ++ sizeof(inode), &start, &offset)) ++ goto out; ++ ++ TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode); ++ ++ return inode; ++ ++out: ++ return SQUASHFS_INVALID_BLK; ++} ++ ++ ++static void vfs_read_inode(struct inode *i) ++{ ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, i->i_ino); ++ ++ TRACE("Entered vfs_read_inode\n"); ++ ++ if(inode != SQUASHFS_INVALID_BLK) ++ (msblk->read_inode)(i, inode); ++} ++ ++ ++static struct dentry *squashfs_get_parent(struct dentry *child) ++{ ++ struct inode *i = child->d_inode; ++ struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode); ++ struct dentry *rv; ++ ++ TRACE("Entered squashfs_get_parent\n"); ++ ++ if(parent == NULL) { ++ rv = ERR_PTR(-EACCES); ++ goto out; ++ } ++ ++ rv = d_alloc_anon(parent); ++ if(rv == NULL) ++ rv = ERR_PTR(-ENOMEM); ++ ++out: ++ return rv; ++} ++ ++ ++SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct inode *i = iget_locked(s, inode_number); ++ ++ TRACE("Entered squashfs_iget\n"); ++ ++ if(i && (i->i_state & I_NEW)) { ++ (msblk->read_inode)(i, inode); ++ unlock_new_inode(i); ++ } ++ ++ return i; ++} ++ ++ ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode) ++{ ++ struct super_block *s = i->i_sb; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long block = SQUASHFS_INODE_BLK(inode) + ++ sblk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ long long next_block; ++ unsigned int next_offset; ++ union squashfs_inode_header id, sid; ++ struct squashfs_base_inode_header *inodeb = &id.base, ++ *sinodeb = &sid.base; ++ ++ TRACE("Entered squashfs_read_inode\n"); ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, ++ offset, sizeof(*sinodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, ++ sizeof(*sinodeb)); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) inodeb, block, ++ offset, sizeof(*inodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ squashfs_new_inode(msblk, i, inodeb); ++ ++ switch(inodeb->inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ unsigned int frag_size; ++ long long frag_blk; ++ struct squashfs_reg_inode_header *inodep = &id.reg; ++ struct squashfs_reg_inode_header *sinodep = &sid.reg; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG && ++ !get_fragment_location(s, ++ inodep->fragment, &frag_blk, &frag_size)) ++ goto failed_read; ++ ++ i->i_nlink = 1; ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ if (sblk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else ++ i->i_data.a_ops = &squashfs_aops_4K; ++ ++ TRACE("File inode %x:%x, start_block %llx, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_LREG_TYPE: { ++ unsigned int frag_size; ++ long long frag_blk; ++ struct squashfs_lreg_inode_header *inodep = &id.lreg; ++ struct squashfs_lreg_inode_header *sinodep = &sid.lreg; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG && ++ !get_fragment_location(s, ++ inodep->fragment, &frag_blk, &frag_size)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ if (sblk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else ++ i->i_data.a_ops = &squashfs_aops_4K; ++ ++ TRACE("File inode %x:%x, start_block %llx, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ struct squashfs_dir_inode_header *inodep = &id.dir; ++ struct squashfs_dir_inode_header *sinodep = &sid.dir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0; ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; ++ ++ TRACE("Directory inode %x:%x, start_block %x, offset " ++ "%x\n", SQUASHFS_INODE_BLK(inode), ++ offset, inodep->start_block, ++ inodep->offset); ++ break; ++ } ++ case SQUASHFS_LDIR_TYPE: { ++ struct squashfs_ldir_inode_header *inodep = &id.ldir; ++ struct squashfs_ldir_inode_header *sinodep = &sid.ldir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = ++ next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = ++ inodep->i_count; ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; ++ ++ TRACE("Long directory inode %x:%x, start_block %x, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, inodep->offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ struct squashfs_symlink_inode_header *inodep = ++ &id.symlink; ++ struct squashfs_symlink_inode_header *sinodep = ++ &sid.symlink; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ SQUASHFS_I(i)->start_block = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ ++ TRACE("Symbolic link inode %x:%x, start_block %llx, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ struct squashfs_dev_inode_header *inodep = &id.dev; ++ struct squashfs_dev_inode_header *sinodep = &sid.dev; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_mode |= (inodeb->inode_type == ++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : ++ S_IFBLK; ++ init_special_inode(i, i->i_mode, ++ old_decode_dev(inodep->rdev)); ++ ++ TRACE("Device inode %x:%x, rdev %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ struct squashfs_ipc_inode_header *inodep = &id.ipc; ++ struct squashfs_ipc_inode_header *sinodep = &sid.ipc; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ++ ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", ++ inodeb->inode_type); ++ goto failed_read1; ++ } ++ ++ return 1; ++ ++failed_read: ++ ERROR("Unable to read inode [%llx:%x]\n", block, offset); ++ ++failed_read1: ++ make_bad_inode(i); ++ return 0; ++} ++ ++ ++static int read_inode_lookup_table(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes); ++ ++ TRACE("In read_inode_lookup_table, length %d\n", length); ++ ++ /* Allocate inode lookup table */ ++ if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) { ++ ERROR("Failed to allocate inode lookup table\n"); ++ return 0; ++ } ++ ++ if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table, ++ sblk->lookup_table_start, length | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ++ ERROR("unable to read inode lookup table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ long long block; ++ ++ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { ++ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), ++ &msblk->inode_lookup_table[i], 1); ++ msblk->inode_lookup_table[i] = block; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int read_fragment_index_table(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); ++ ++ if(length == 0) ++ return 1; ++ ++ /* Allocate fragment index table */ ++ if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) { ++ ERROR("Failed to allocate fragment index table\n"); ++ return 0; ++ } ++ ++ if (!squashfs_read_data(s, (char *) msblk->fragment_index, ++ sblk->fragment_table_start, length | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ++ ERROR("unable to read fragment index table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ long long fragment; ++ ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { ++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), ++ &msblk->fragment_index[i], 1); ++ msblk->fragment_index[i] = fragment; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ msblk->read_inode = squashfs_read_inode; ++ msblk->read_blocklist = read_blocklist; ++ msblk->read_fragment_index_table = read_fragment_index_table; ++ ++ if (sblk->s_major == 1) { ++ if (!squashfs_1_0_supported(msblk)) { ++ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " ++ "are unsupported\n"); ++ SERROR("Please recompile with " ++ "Squashfs 1.0 support enabled\n"); ++ return 0; ++ } ++ } else if (sblk->s_major == 2) { ++ if (!squashfs_2_0_supported(msblk)) { ++ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " ++ "are unsupported\n"); ++ SERROR("Please recompile with " ++ "Squashfs 2.0 support enabled\n"); ++ return 0; ++ } ++ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > ++ SQUASHFS_MINOR) { ++ SERROR("Major/Minor mismatch, trying to mount newer %d.%d " ++ "filesystem\n", sblk->s_major, sblk->s_minor); ++ SERROR("Please update your kernel\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static int squashfs_fill_super(struct super_block *s, void *data, int silent) ++{ ++ struct squashfs_sb_info *msblk; ++ struct squashfs_super_block *sblk; ++ int i; ++ char b[BDEVNAME_SIZE]; ++ struct inode *root; ++ ++ TRACE("Entered squashfs_read_superblock\n"); ++ ++ if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info), ++ GFP_KERNEL))) { ++ ERROR("Failed to allocate superblock\n"); ++ goto failure; ++ } ++ memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info)); ++ msblk = s->s_fs_info; ++ if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) { ++ ERROR("Failed to allocate zlib workspace\n"); ++ goto failure; ++ } ++ sblk = &msblk->sblk; ++ ++ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); ++ msblk->devblksize_log2 = ffz(~msblk->devblksize); ++ ++ mutex_init(&msblk->read_data_mutex); ++ mutex_init(&msblk->read_page_mutex); ++ mutex_init(&msblk->block_cache_mutex); ++ mutex_init(&msblk->fragment_mutex); ++ mutex_init(&msblk->meta_index_mutex); ++ ++ init_waitqueue_head(&msblk->waitq); ++ init_waitqueue_head(&msblk->fragment_wait_queue); ++ ++ sblk->bytes_used = sizeof(struct squashfs_super_block); ++ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, ++ sizeof(struct squashfs_super_block) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) { ++ SERROR("unable to read superblock\n"); ++ goto failed_mount; ++ } ++ ++ /* Check it is a SQUASHFS superblock */ ++ msblk->swap = 0; ++ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) { ++ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) { ++ struct squashfs_super_block ssblk; ++ ++ WARNING("Mounting a different endian SQUASHFS " ++ "filesystem on %s\n", bdevname(s->s_bdev, b)); ++ ++ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); ++ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); ++ msblk->swap = 1; ++ } else { ++ SERROR("Can't find a SQUASHFS superblock on %s\n", ++ bdevname(s->s_bdev, b)); ++ goto failed_mount; ++ } ++ } ++ ++ /* Check the MAJOR & MINOR versions */ ++ if(!supported_squashfs_filesystem(msblk, silent)) ++ goto failed_mount; ++ ++ /* Check the filesystem does not extend beyond the end of the ++ block device */ ++ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode)) ++ goto failed_mount; ++ ++ /* Check the root inode for sanity */ ++ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE) ++ goto failed_mount; ++ ++ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); ++ TRACE("Inodes are %scompressed\n", ++ SQUASHFS_UNCOMPRESSED_INODES ++ (sblk->flags) ? "un" : ""); ++ TRACE("Data is %scompressed\n", ++ SQUASHFS_UNCOMPRESSED_DATA(sblk->flags) ++ ? "un" : ""); ++ TRACE("Check data is %s present in the filesystem\n", ++ SQUASHFS_CHECK_DATA(sblk->flags) ? ++ "" : "not"); ++ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); ++ TRACE("Block size %d\n", sblk->block_size); ++ TRACE("Number of inodes %d\n", sblk->inodes); ++ if (sblk->s_major > 1) ++ TRACE("Number of fragments %d\n", sblk->fragments); ++ TRACE("Number of uids %d\n", sblk->no_uids); ++ TRACE("Number of gids %d\n", sblk->no_guids); ++ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); ++ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); ++ if (sblk->s_major > 1) ++ TRACE("sblk->fragment_table_start %llx\n", ++ sblk->fragment_table_start); ++ TRACE("sblk->uid_start %llx\n", sblk->uid_start); ++ ++ s->s_flags |= MS_RDONLY; ++ s->s_op = &squashfs_super_ops; ++ ++ /* Init inode_table block pointer array */ ++ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * ++ SQUASHFS_CACHED_BLKS, GFP_KERNEL))) { ++ ERROR("Failed to allocate block cache\n"); ++ goto failed_mount; ++ } ++ ++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; ++ ++ msblk->next_cache = 0; ++ ++ /* Allocate read_page block */ ++ if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) { ++ ERROR("Failed to allocate read_page block\n"); ++ goto failed_mount; ++ } ++ ++ /* Allocate uid and gid tables */ ++ if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ goto failed_mount; ++ } ++ msblk->guid = msblk->uid + sblk->no_uids; ++ ++ if (msblk->swap) { ++ unsigned int suid[sblk->no_uids + sblk->no_guids]; ++ ++ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, ++ ((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int)) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ++ ERROR("unable to read uid/gid table\n"); ++ goto failed_mount; ++ } ++ ++ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids + ++ sblk->no_guids), (sizeof(unsigned int) * 8)); ++ } else ++ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, ++ ((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int)) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ++ ERROR("unable to read uid/gid table\n"); ++ goto failed_mount; ++ } ++ ++ ++ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) ++ goto allocate_root; ++ ++ if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) * ++ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { ++ ERROR("Failed to allocate fragment block cache\n"); ++ goto failed_mount; ++ } ++ ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { ++ msblk->fragment[i].locked = 0; ++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ msblk->fragment[i].data = NULL; ++ } ++ ++ msblk->next_fragment = 0; ++ ++ /* Allocate and read fragment index table */ ++ if (msblk->read_fragment_index_table(s) == 0) ++ goto failed_mount; ++ ++ if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK) ++ goto allocate_root; ++ ++ /* Allocate and read inode lookup table */ ++ if (read_inode_lookup_table(s) == 0) ++ goto failed_mount; ++ ++ s->s_op = &squashfs_export_super_ops; ++ s->s_export_op = &squashfs_export_ops; ++ ++allocate_root: ++ root = new_inode(s); ++ if ((msblk->read_inode)(root, sblk->root_inode) == 0) ++ goto failed_mount; ++ insert_inode_hash(root); ++ ++ if ((s->s_root = d_alloc_root(root)) == NULL) { ++ ERROR("Root inode create failed\n"); ++ iput(root); ++ goto failed_mount; ++ } ++ ++ TRACE("Leaving squashfs_read_super\n"); ++ return 0; ++ ++failed_mount: ++ kfree(msblk->inode_lookup_table); ++ kfree(msblk->fragment_index); ++ kfree(msblk->fragment); ++ kfree(msblk->uid); ++ kfree(msblk->read_page); ++ kfree(msblk->block_cache); ++ kfree(msblk->fragment_index_2); ++ vfree(msblk->stream.workspace); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ return -EINVAL; ++ ++failure: ++ return -ENOMEM; ++} ++ ++ ++static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ TRACE("Entered squashfs_statfs\n"); ++ ++ buf->f_type = SQUASHFS_MAGIC; ++ buf->f_bsize = sblk->block_size; ++ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1; ++ buf->f_bfree = buf->f_bavail = 0; ++ buf->f_files = sblk->inodes; ++ buf->f_ffree = 0; ++ buf->f_namelen = SQUASHFS_NAME_LEN; ++ ++ return 0; ++} ++ ++ ++static int squashfs_symlink_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes; ++ long long block = SQUASHFS_I(inode)->start_block; ++ int offset = SQUASHFS_I(inode)->offset; ++ void *pageaddr = kmap(page); ++ ++ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " ++ "%llx, offset %x\n", page->index, ++ SQUASHFS_I(inode)->start_block, ++ SQUASHFS_I(inode)->offset); ++ ++ for (length = 0; length < index; length += bytes) { ++ if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, ++ block, offset, PAGE_CACHE_SIZE, &block, ++ &offset))) { ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, ++ offset); ++ goto skip_read; ++ } ++ } ++ ++ if (length != index) { ++ ERROR("(squashfs_symlink_readpage) length != index\n"); ++ bytes = 0; ++ goto skip_read; ++ } ++ ++ bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : ++ i_size_read(inode) - length; ++ ++ if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, ++ offset, bytes, &block, &offset))) ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ return 0; ++} ++ ++ ++struct meta_index *locate_meta_index(struct inode *inode, int index, int offset) ++{ ++ struct meta_index *meta = NULL; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ int i; ++ ++ mutex_lock(&msblk->meta_index_mutex); ++ ++ TRACE("locate_meta_index: index %d, offset %d\n", index, offset); ++ ++ if(msblk->meta_index == NULL) ++ goto not_allocated; ++ ++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) ++ if (msblk->meta_index[i].inode_number == inode->i_ino && ++ msblk->meta_index[i].offset >= offset && ++ msblk->meta_index[i].offset <= index && ++ msblk->meta_index[i].locked == 0) { ++ TRACE("locate_meta_index: entry %d, offset %d\n", i, ++ msblk->meta_index[i].offset); ++ meta = &msblk->meta_index[i]; ++ offset = meta->offset; ++ } ++ ++ if (meta) ++ meta->locked = 1; ++ ++not_allocated: ++ mutex_unlock(&msblk->meta_index_mutex); ++ ++ return meta; ++} ++ ++ ++struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip) ++{ ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct meta_index *meta = NULL; ++ int i; ++ ++ mutex_lock(&msblk->meta_index_mutex); ++ ++ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); ++ ++ if(msblk->meta_index == NULL) { ++ if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) * ++ SQUASHFS_META_NUMBER, GFP_KERNEL))) { ++ ERROR("Failed to allocate meta_index\n"); ++ goto failed; ++ } ++ for(i = 0; i < SQUASHFS_META_NUMBER; i++) { ++ msblk->meta_index[i].inode_number = 0; ++ msblk->meta_index[i].locked = 0; ++ } ++ msblk->next_meta_index = 0; ++ } ++ ++ for(i = SQUASHFS_META_NUMBER; i && ++ msblk->meta_index[msblk->next_meta_index].locked; i --) ++ msblk->next_meta_index = (msblk->next_meta_index + 1) % ++ SQUASHFS_META_NUMBER; ++ ++ if(i == 0) { ++ TRACE("empty_meta_index: failed!\n"); ++ goto failed; ++ } ++ ++ TRACE("empty_meta_index: returned meta entry %d, %p\n", ++ msblk->next_meta_index, ++ &msblk->meta_index[msblk->next_meta_index]); ++ ++ meta = &msblk->meta_index[msblk->next_meta_index]; ++ msblk->next_meta_index = (msblk->next_meta_index + 1) % ++ SQUASHFS_META_NUMBER; ++ ++ meta->inode_number = inode->i_ino; ++ meta->offset = offset; ++ meta->skip = skip; ++ meta->entries = 0; ++ meta->locked = 1; ++ ++failed: ++ mutex_unlock(&msblk->meta_index_mutex); ++ return meta; ++} ++ ++ ++void release_meta_index(struct inode *inode, struct meta_index *meta) ++{ ++ meta->locked = 0; ++ smp_mb(); ++} ++ ++ ++static int read_block_index(struct super_block *s, int blocks, char *block_list, ++ long long *start_block, int *offset) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ unsigned int *block_listp; ++ int block = 0; ++ ++ if (msblk->swap) { ++ char sblock_list[blocks << 2]; ++ ++ if (!squashfs_get_cached_block(s, sblock_list, *start_block, ++ *offset, blocks << 2, start_block, offset)) { ++ ERROR("Unable to read block list [%llx:%x]\n", ++ *start_block, *offset); ++ goto failure; ++ } ++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ++ ((unsigned int *)sblock_list), blocks); ++ } else ++ if (!squashfs_get_cached_block(s, block_list, *start_block, ++ *offset, blocks << 2, start_block, offset)) { ++ ERROR("Unable to read block list [%llx:%x]\n", ++ *start_block, *offset); ++ goto failure; ++ } ++ ++ for (block_listp = (unsigned int *) block_list; blocks; ++ block_listp++, blocks --) ++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); ++ ++ return block; ++ ++failure: ++ return -1; ++} ++ ++ ++#define SIZE 256 ++ ++static inline int calculate_skip(int blocks) { ++ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES); ++ return skip >= 7 ? 7 : skip + 1; ++} ++ ++ ++static int get_meta_index(struct inode *inode, int index, ++ long long *index_block, int *index_offset, ++ long long *data_block, char *block_list) ++{ ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log); ++ int offset = 0; ++ struct meta_index *meta; ++ struct meta_entry *meta_entry; ++ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start; ++ int cur_offset = SQUASHFS_I(inode)->offset; ++ long long cur_data_block = SQUASHFS_I(inode)->start_block; ++ int i; ++ ++ index /= SQUASHFS_META_INDEXES * skip; ++ ++ while ( offset < index ) { ++ meta = locate_meta_index(inode, index, offset + 1); ++ ++ if (meta == NULL) { ++ if ((meta = empty_meta_index(inode, offset + 1, ++ skip)) == NULL) ++ goto all_done; ++ } else { ++ if(meta->entries == 0) ++ goto failed; ++ offset = index < meta->offset + meta->entries ? index : ++ meta->offset + meta->entries - 1; ++ meta_entry = &meta->meta_entry[offset - meta->offset]; ++ cur_index_block = meta_entry->index_block + sblk->inode_table_start; ++ cur_offset = meta_entry->offset; ++ cur_data_block = meta_entry->data_block; ++ TRACE("get_meta_index: offset %d, meta->offset %d, " ++ "meta->entries %d\n", offset, meta->offset, ++ meta->entries); ++ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" ++ " data_block 0x%llx\n", cur_index_block, ++ cur_offset, cur_data_block); ++ } ++ ++ for (i = meta->offset + meta->entries; i <= index && ++ i < meta->offset + SQUASHFS_META_ENTRIES; i++) { ++ int blocks = skip * SQUASHFS_META_INDEXES; ++ ++ while (blocks) { ++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : ++ blocks; ++ int res = read_block_index(inode->i_sb, block, ++ block_list, &cur_index_block, ++ &cur_offset); ++ ++ if (res == -1) ++ goto failed; ++ ++ cur_data_block += res; ++ blocks -= block; ++ } ++ ++ meta_entry = &meta->meta_entry[i - meta->offset]; ++ meta_entry->index_block = cur_index_block - sblk->inode_table_start; ++ meta_entry->offset = cur_offset; ++ meta_entry->data_block = cur_data_block; ++ meta->entries ++; ++ offset ++; ++ } ++ ++ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", ++ meta->offset, meta->entries); ++ ++ release_meta_index(inode, meta); ++ } ++ ++all_done: ++ *index_block = cur_index_block; ++ *index_offset = cur_offset; ++ *data_block = cur_data_block; ++ ++ return offset * SQUASHFS_META_INDEXES * skip; ++ ++failed: ++ release_meta_index(inode, meta); ++ return -1; ++} ++ ++ ++static long long read_blocklist(struct inode *inode, int index, ++ int readahead_blks, char *block_list, ++ unsigned short **block_p, unsigned int *bsize) ++{ ++ long long block_ptr; ++ int offset; ++ long long block; ++ int res = get_meta_index(inode, index, &block_ptr, &offset, &block, ++ block_list); ++ ++ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" ++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, ++ block); ++ ++ if(res == -1) ++ goto failure; ++ ++ index -= res; ++ ++ while ( index ) { ++ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; ++ int res = read_block_index(inode->i_sb, blocks, block_list, ++ &block_ptr, &offset); ++ if (res == -1) ++ goto failure; ++ block += res; ++ index -= blocks; ++ } ++ ++ if (read_block_index(inode->i_sb, 1, block_list, ++ &block_ptr, &offset) == -1) ++ goto failure; ++ *bsize = *((unsigned int *) block_list); ++ ++ return block; ++ ++failure: ++ return 0; ++} ++ ++ ++static int squashfs_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned char *block_list; ++ long long block; ++ unsigned int bsize, i = 0, bytes = 0, byte_offset = 0; ++ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); ++ void *pageaddr; ++ struct squashfs_fragment_cache *fragment = NULL; ++ char *data_ptr = msblk->read_page; ++ ++ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; ++ int start_index = page->index & ~mask; ++ int end_index = start_index | mask; ++ ++ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", ++ page->index, ++ SQUASHFS_I(inode)->start_block); ++ ++ if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) { ++ ERROR("Failed to allocate block_list\n"); ++ goto skip_read; ++ } ++ ++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> ++ PAGE_CACHE_SHIFT)) ++ goto skip_read; ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || index < (i_size_read(inode) >> ++ sblk->block_log)) { ++ if ((block = (msblk->read_blocklist)(inode, index, 1, ++ block_list, NULL, &bsize)) == 0) ++ goto skip_read; ++ ++ mutex_lock(&msblk->read_page_mutex); ++ ++ if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page, ++ block, bsize, NULL, sblk->block_size))) { ++ ERROR("Unable to read page, block %llx, size %x\n", block, ++ bsize); ++ mutex_unlock(&msblk->read_page_mutex); ++ goto skip_read; ++ } ++ } else { ++ if ((fragment = get_cached_fragment(inode->i_sb, ++ SQUASHFS_I(inode)-> ++ u.s1.fragment_start_block, ++ SQUASHFS_I(inode)->u.s1.fragment_size)) ++ == NULL) { ++ ERROR("Unable to read page, block %llx, size %x\n", ++ SQUASHFS_I(inode)-> ++ u.s1.fragment_start_block, ++ (int) SQUASHFS_I(inode)-> ++ u.s1.fragment_size); ++ goto skip_read; ++ } ++ bytes = SQUASHFS_I(inode)->u.s1.fragment_offset + ++ (i_size_read(inode) & (sblk->block_size ++ - 1)); ++ byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset; ++ data_ptr = fragment->data; ++ } ++ ++ for (i = start_index; i <= end_index && byte_offset < bytes; ++ i++, byte_offset += PAGE_CACHE_SIZE) { ++ struct page *push_page; ++ int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ? ++ PAGE_CACHE_SIZE : bytes - byte_offset; ++ ++ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", ++ bytes, i, byte_offset, avail); ++ ++ push_page = (i == page->index) ? page : ++ grab_cache_page_nowait(page->mapping, i); ++ ++ if (!push_page) ++ continue; ++ ++ if (PageUptodate(push_page)) ++ goto skip_page; ++ ++ pageaddr = kmap_atomic(push_page, KM_USER0); ++ memcpy(pageaddr, data_ptr + byte_offset, avail); ++ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(push_page); ++ SetPageUptodate(push_page); ++skip_page: ++ unlock_page(push_page); ++ if(i != page->index) ++ page_cache_release(push_page); ++ } ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || index < (i_size_read(inode) >> ++ sblk->block_log)) ++ mutex_unlock(&msblk->read_page_mutex); ++ else ++ release_cached_fragment(msblk, fragment); ++ ++ kfree(block_list); ++ return 0; ++ ++skip_read: ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ kfree(block_list); ++ return 0; ++} ++ ++ ++static int squashfs_readpage4K(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned char *block_list; ++ long long block; ++ unsigned int bsize, bytes = 0; ++ void *pageaddr; ++ ++ TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n", ++ page->index, ++ SQUASHFS_I(inode)->start_block); ++ ++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> ++ PAGE_CACHE_SHIFT)) { ++ block_list = NULL; ++ goto skip_read; ++ } ++ ++ if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) { ++ ERROR("Failed to allocate block_list\n"); ++ goto skip_read; ++ } ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || page->index < (i_size_read(inode) >> ++ sblk->block_log)) { ++ block = (msblk->read_blocklist)(inode, page->index, 1, ++ block_list, NULL, &bsize); ++ if(block == 0) ++ goto skip_read; ++ ++ mutex_lock(&msblk->read_page_mutex); ++ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, ++ bsize, NULL, sblk->block_size); ++ if (bytes) { ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memcpy(pageaddr, msblk->read_page, bytes); ++ kunmap_atomic(pageaddr, KM_USER0); ++ } else ++ ERROR("Unable to read page, block %llx, size %x\n", ++ block, bsize); ++ mutex_unlock(&msblk->read_page_mutex); ++ } else { ++ struct squashfs_fragment_cache *fragment = ++ get_cached_fragment(inode->i_sb, ++ SQUASHFS_I(inode)-> ++ u.s1.fragment_start_block, ++ SQUASHFS_I(inode)-> u.s1.fragment_size); ++ if (fragment) { ++ bytes = i_size_read(inode) & (sblk->block_size - 1); ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)-> ++ u.s1.fragment_offset, bytes); ++ kunmap_atomic(pageaddr, KM_USER0); ++ release_cached_fragment(msblk, fragment); ++ } else ++ ERROR("Unable to read page, block %llx, size %x\n", ++ SQUASHFS_I(inode)-> ++ u.s1.fragment_start_block, (int) ++ SQUASHFS_I(inode)-> u.s1.fragment_size); ++ } ++ ++skip_read: ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ kfree(block_list); ++ return 0; ++} ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ long long f_pos) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index index; ++ ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", ++ i_count, (unsigned int) f_pos); ++ ++ f_pos =- 3; ++ if (f_pos == 0) ++ goto finish; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) &index, ++ index_start, index_offset, ++ sizeof(index), &index_start, ++ &index_offset); ++ ++ if (index.index > f_pos) ++ break; ++ ++ squashfs_get_cached_block(s, NULL, index_start, index_offset, ++ index.size + 1, &index_start, ++ &index_offset); ++ ++ length = index.index; ++ *next_block = index.start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ ++finish: ++ return length + 3; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ const char *name, int size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index *index; ++ char *str; ++ ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); ++ ++ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_index\n"); ++ goto failure; ++ } ++ ++ index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1); ++ strncpy(str, name, size); ++ str[size] = '\0'; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX(index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) index, ++ index_start, index_offset, ++ sizeof(struct squashfs_dir_index), ++ &index_start, &index_offset); ++ ++ squashfs_get_cached_block(s, index->name, index_start, ++ index_offset, index->size + 1, ++ &index_start, &index_offset); ++ ++ index->name[index->size + 1] = '\0'; ++ ++ if (strcmp(index->name, str) > 0) ++ break; ++ ++ length = index->index; ++ *next_block = index->start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ kfree(str); ++failure: ++ return length + 3; ++} ++ ++ ++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header dirh; ++ struct squashfs_dir_entry *dire; ++ ++ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto finish; ++ } ++ ++ while(file->f_pos < 3) { ++ char *name; ++ int size, i_ino; ++ ++ if(file->f_pos == 0) { ++ name = "."; ++ size = 1; ++ i_ino = i->i_ino; ++ } else { ++ name = ".."; ++ size = 2; ++ i_ino = SQUASHFS_I(i)->u.s2.parent_inode; ++ } ++ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", ++ (unsigned int) dirent, name, size, (int) ++ file->f_pos, i_ino, ++ squashfs_filetype_table[1]); ++ ++ if (filldir(dirent, name, size, ++ file->f_pos, i_ino, ++ squashfs_filetype_table[1]) < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos += size; ++ } ++ ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, ++ file->f_pos); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header sdirh; ++ ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block, next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block, next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, ++ dire->size + 1, &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", ++ (unsigned int) dirent, dire->name, ++ dire->size + 1, (int) file->f_pos, ++ dirh.start_block, dire->offset, ++ dirh.inode_number + dire->inode_number, ++ squashfs_filetype_table[dire->type]); ++ ++ if (filldir(dirent, dire->name, dire->size + 1, ++ file->f_pos, ++ dirh.inode_number + dire->inode_number, ++ squashfs_filetype_table[dire->type]) ++ < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos = length; ++ } ++ } ++ ++finish: ++ kfree(dire); ++ return 0; ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ kfree(dire); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ const unsigned char *name = dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header dirh; ++ struct squashfs_dir_entry *dire; ++ ++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto exit_lookup; ++ } ++ ++ if (len > SQUASHFS_NAME_LEN) ++ goto exit_lookup; ++ ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, ++ len); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header sdirh; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block,next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block,next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, dire->size + 1, ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (name[0] < dire->name[0]) ++ goto exit_lookup; ++ ++ if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) { ++ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, ++ dire->offset); ++ ++ TRACE("calling squashfs_iget for directory " ++ "entry %s, inode %x:%x, %d\n", name, ++ dirh.start_block, dire->offset, ++ dirh.inode_number + dire->inode_number); ++ ++ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); ++ ++ goto exit_lookup; ++ } ++ } ++ } ++ ++exit_lookup: ++ kfree(dire); ++ if (inode) ++ return d_splice_alias(inode, dentry); ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ goto exit_lookup; ++} ++ ++ ++static int squashfs_remount(struct super_block *s, int *flags, char *data) ++{ ++ *flags |= MS_RDONLY; ++ return 0; ++} ++ ++ ++static void squashfs_put_super(struct super_block *s) ++{ ++ int i; ++ ++ if (s->s_fs_info) { ++ struct squashfs_sb_info *sbi = s->s_fs_info; ++ if (sbi->block_cache) ++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ if (sbi->block_cache[i].block != ++ SQUASHFS_INVALID_BLK) ++ kfree(sbi->block_cache[i].data); ++ if (sbi->fragment) ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) ++ SQUASHFS_FREE(sbi->fragment[i].data); ++ kfree(sbi->fragment); ++ kfree(sbi->block_cache); ++ kfree(sbi->read_page); ++ kfree(sbi->uid); ++ kfree(sbi->fragment_index); ++ kfree(sbi->fragment_index_2); ++ kfree(sbi->meta_index); ++ vfree(sbi->stream.workspace); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ } ++} ++ ++ ++static int squashfs_get_sb(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data, ++ struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, ++ mnt); ++} ++ ++ ++static int __init init_squashfs_fs(void) ++{ ++ int err = init_inodecache(); ++ if (err) ++ goto out; ++ ++ printk(KERN_INFO "squashfs: version 3.2-r2 (2007/01/15) " ++ "Phillip Lougher\n"); ++ ++ if ((err = register_filesystem(&squashfs_fs_type))) ++ destroy_inodecache(); ++ ++out: ++ return err; ++} ++ ++ ++static void __exit exit_squashfs_fs(void) ++{ ++ unregister_filesystem(&squashfs_fs_type); ++ destroy_inodecache(); ++} ++ ++ ++static struct kmem_cache * squashfs_inode_cachep; ++ ++ ++static struct inode *squashfs_alloc_inode(struct super_block *sb) ++{ ++ struct squashfs_inode_info *ei; ++ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); ++ if (!ei) ++ return NULL; ++ return &ei->vfs_inode; ++} ++ ++ ++static void squashfs_destroy_inode(struct inode *inode) ++{ ++ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); ++} ++ ++ ++static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) ++{ ++ struct squashfs_inode_info *ei = foo; ++ ++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == ++ SLAB_CTOR_CONSTRUCTOR) ++ inode_init_once(&ei->vfs_inode); ++} ++ ++ ++static int __init init_inodecache(void) ++{ ++ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", ++ sizeof(struct squashfs_inode_info), ++ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, ++ init_once, NULL); ++ if (squashfs_inode_cachep == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++ ++static void destroy_inodecache(void) ++{ ++ kmem_cache_destroy(squashfs_inode_cachep); ++} ++ ++ ++module_init(init_squashfs_fs); ++module_exit(exit_squashfs_fs); ++MODULE_DESCRIPTION("squashfs 3.2-r2, a compressed read-only filesystem"); ++MODULE_AUTHOR("Phillip Lougher "); ++MODULE_LICENSE("GPL"); +diff -rduNp linux-2.6.22.1.oorig/fs/squashfs/squashfs.h linux-2.6.22.1/fs/squashfs/squashfs.h +--- linux-2.6.22.1.oorig/fs/squashfs/squashfs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/squashfs/squashfs.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,87 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs.h ++ */ ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++#endif ++ ++#ifdef SQUASHFS_TRACE ++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) ++#else ++#define TRACE(s, args...) {} ++#endif ++ ++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) ++ ++#define SERROR(s, args...) do { \ ++ if (!silent) \ ++ printk(KERN_ERR "SQUASHFS error: "s, ## args);\ ++ } while(0) ++ ++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) ++ ++static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) ++{ ++ return list_entry(inode, struct squashfs_inode_info, vfs_inode); ++} ++ ++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY) ++#define SQSH_EXTERN ++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, ++ long long index, unsigned int length, ++ long long *next_index, int srclength); ++extern int squashfs_get_cached_block(struct super_block *s, char *buffer, ++ long long block, unsigned int offset, ++ int length, long long *next_block, ++ unsigned int *next_offset); ++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct ++ squashfs_fragment_cache *fragment); ++extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block ++ *s, long long start_block, ++ int length); ++extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); ++extern const struct address_space_operations squashfs_symlink_aops; ++extern const struct address_space_operations squashfs_aops; ++extern const struct address_space_operations squashfs_aops_4K; ++extern struct inode_operations squashfs_dir_inode_ops; ++#else ++#define SQSH_EXTERN static ++#endif ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk); ++#else ++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk) ++{ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk); ++#else ++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk) ++{ ++ return 0; ++} ++#endif +diff -rduNp linux-2.6.22.1.oorig/fs/squashfs/squashfs2_0.c linux-2.6.22.1/fs/squashfs/squashfs2_0.c +--- linux-2.6.22.1.oorig/fs/squashfs/squashfs2_0.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/fs/squashfs/squashfs2_0.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,742 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs2_0.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "squashfs.h" ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir); ++static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *, ++ struct nameidata *); ++ ++static struct file_operations squashfs_dir_ops_2 = { ++ .read = generic_read_dir, ++ .readdir = squashfs_readdir_2 ++}; ++ ++static struct inode_operations squashfs_dir_inode_ops_2 = { ++ .lookup = squashfs_lookup_2 ++}; ++ ++static unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static int read_fragment_index_table_2(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2 ++ (sblk->fragments), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ return 0; ++ } ++ ++ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && ++ !squashfs_read_data(s, (char *) ++ msblk->fragment_index_2, ++ sblk->fragment_table_start, ++ SQUASHFS_FRAGMENT_INDEX_BYTES_2 ++ (sblk->fragments) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { ++ ERROR("unable to read fragment index table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ unsigned int fragment; ++ ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments); ++ i++) { ++ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment), ++ &msblk->fragment_index_2[i], 1); ++ msblk->fragment_index_2[i] = fragment; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int get_fragment_location_2(struct super_block *s, unsigned int fragment, ++ long long *fragment_start_block, ++ unsigned int *fragment_size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start_block = ++ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment); ++ struct squashfs_fragment_entry_2 fragment_entry; ++ ++ if (msblk->swap) { ++ struct squashfs_fragment_entry_2 sfragment_entry; ++ ++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, ++ start_block, offset, ++ sizeof(sfragment_entry), &start_block, ++ &offset)) ++ goto out; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, ++ start_block, offset, ++ sizeof(fragment_entry), &start_block, ++ &offset)) ++ goto out; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++ ++out: ++ return 0; ++} ++ ++ ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, ++ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ i->i_ino = ino; ++ i->i_mtime.tv_sec = sblk->mkfs_time; ++ i->i_atime.tv_sec = sblk->mkfs_time; ++ i->i_ctime.tv_sec = sblk->mkfs_time; ++ i->i_uid = msblk->uid[inodeb->uid]; ++ i->i_mode = inodeb->mode; ++ i->i_nlink = 1; ++ i->i_size = 0; ++ if (inodeb->guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msblk->guid[inodeb->guid]; ++} ++ ++ ++static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) ++{ ++ struct super_block *s = i->i_sb; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int block = SQUASHFS_INODE_BLK(inode) + ++ sblk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ unsigned int ino = i->i_ino; ++ long long next_block; ++ unsigned int next_offset; ++ union squashfs_inode_header_2 id, sid; ++ struct squashfs_base_inode_header_2 *inodeb = &id.base, ++ *sinodeb = &sid.base; ++ ++ TRACE("Entered squashfs_iget\n"); ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, ++ offset, sizeof(*sinodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, ++ sizeof(*sinodeb)); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) inodeb, block, ++ offset, sizeof(*inodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ squashfs_new_inode(msblk, i, inodeb, ino); ++ ++ switch(inodeb->inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ struct squashfs_reg_inode_header_2 *inodep = &id.reg; ++ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; ++ long long frag_blk; ++ unsigned int frag_size = 0; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG && ++ !get_fragment_location_2(s, ++ inodep->fragment, &frag_blk, &frag_size)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ if (sblk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else ++ i->i_data.a_ops = &squashfs_aops_4K; ++ ++ TRACE("File inode %x:%x, start_block %x, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ struct squashfs_dir_inode_header_2 *inodep = &id.dir; ++ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops_2; ++ i->i_fop = &squashfs_dir_ops_2; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0; ++ SQUASHFS_I(i)->u.s2.parent_inode = 0; ++ ++ TRACE("Directory inode %x:%x, start_block %x, offset " ++ "%x\n", SQUASHFS_INODE_BLK(inode), ++ offset, inodep->start_block, ++ inodep->offset); ++ break; ++ } ++ case SQUASHFS_LDIR_TYPE: { ++ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; ++ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops_2; ++ i->i_fop = &squashfs_dir_ops_2; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = ++ next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = ++ inodep->i_count; ++ SQUASHFS_I(i)->u.s2.parent_inode = 0; ++ ++ TRACE("Long directory inode %x:%x, start_block %x, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, inodep->offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ struct squashfs_symlink_inode_header_2 *inodep = ++ &id.symlink; ++ struct squashfs_symlink_inode_header_2 *sinodep = ++ &sid.symlink; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ SQUASHFS_I(i)->start_block = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ ++ TRACE("Symbolic link inode %x:%x, start_block %llx, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ struct squashfs_dev_inode_header_2 *inodep = &id.dev; ++ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_mode |= (inodeb->inode_type == ++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : ++ S_IFBLK; ++ init_special_inode(i, i->i_mode, ++ old_decode_dev(inodep->rdev)); ++ ++ TRACE("Device inode %x:%x, rdev %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ++ ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", ++ inodeb->inode_type); ++ goto failed_read1; ++ } ++ ++ return 1; ++ ++failed_read: ++ ERROR("Unable to read inode [%x:%x]\n", block, offset); ++ ++failed_read1: ++ return 0; ++} ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ long long f_pos) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index_2 index; ++ ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", ++ i_count, (unsigned int) f_pos); ++ ++ if (f_pos == 0) ++ goto finish; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index_2 sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) &index, ++ index_start, index_offset, ++ sizeof(index), &index_start, ++ &index_offset); ++ ++ if (index.index > f_pos) ++ break; ++ ++ squashfs_get_cached_block(s, NULL, index_start, index_offset, ++ index.size + 1, &index_start, ++ &index_offset); ++ ++ length = index.index; ++ *next_block = index.start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ ++finish: ++ return length; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ const char *name, int size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index_2 *index; ++ char *str; ++ ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); ++ ++ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_index\n"); ++ goto failure; ++ } ++ ++ index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1); ++ strncpy(str, name, size); ++ str[size] = '\0'; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index_2 sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) index, ++ index_start, index_offset, ++ sizeof(struct squashfs_dir_index_2), ++ &index_start, &index_offset); ++ ++ squashfs_get_cached_block(s, index->name, index_start, ++ index_offset, index->size + 1, ++ &index_start, &index_offset); ++ ++ index->name[index->size + 1] = '\0'; ++ ++ if (strcmp(index->name, str) > 0) ++ break; ++ ++ length = index->index; ++ *next_block = index->start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ kfree(str); ++failure: ++ return length; ++} ++ ++ ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header_2 dirh; ++ struct squashfs_dir_entry_2 *dire; ++ ++ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto finish; ++ } ++ ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, ++ file->f_pos); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header_2 sdirh; ++ ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry_2 sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block, next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block, next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, ++ dire->size + 1, &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", ++ (unsigned int) dirent, dire->name, ++ dire->size + 1, (int) file->f_pos, ++ dirh.start_block, dire->offset, ++ squashfs_filetype_table[dire->type]); ++ ++ if (filldir(dirent, dire->name, dire->size + 1, ++ file->f_pos, SQUASHFS_MK_VFS_INODE( ++ dirh.start_block, dire->offset), ++ squashfs_filetype_table[dire->type]) ++ < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos = length; ++ } ++ } ++ ++finish: ++ kfree(dire); ++ return 0; ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ kfree(dire); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ const unsigned char *name = dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header_2 dirh; ++ struct squashfs_dir_entry_2 *dire; ++ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; ++ ++ TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto exit_loop; ++ } ++ ++ if (len > SQUASHFS_NAME_LEN) ++ goto exit_loop; ++ ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, ++ len); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header_2 sdirh; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry_2 sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block,next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block,next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, dire->size + 1, ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (sorted && name[0] < dire->name[0]) ++ goto exit_loop; ++ ++ if ((len == dire->size + 1) && !strncmp(name, ++ dire->name, len)) { ++ squashfs_inode_t ino = ++ SQUASHFS_MKINODE(dirh.start_block, ++ dire->offset); ++ unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, ++ dire->offset); ++ ++ TRACE("calling squashfs_iget for directory " ++ "entry %s, inode %x:%x, %lld\n", name, ++ dirh.start_block, dire->offset, ino); ++ ++ inode = squashfs_iget(i->i_sb, ino, inode_number); ++ ++ goto exit_loop; ++ } ++ } ++ } ++ ++exit_loop: ++ kfree(dire); ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ goto exit_loop; ++} ++ ++ ++int squashfs_2_0_supported(struct squashfs_sb_info *msblk) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ msblk->read_inode = squashfs_read_inode_2; ++ msblk->read_fragment_index_table = read_fragment_index_table_2; ++ ++ sblk->bytes_used = sblk->bytes_used_2; ++ sblk->uid_start = sblk->uid_start_2; ++ sblk->guid_start = sblk->guid_start_2; ++ sblk->inode_table_start = sblk->inode_table_start_2; ++ sblk->directory_table_start = sblk->directory_table_start_2; ++ sblk->fragment_table_start = sblk->fragment_table_start_2; ++ ++ return 1; ++} +diff -rduNp linux-2.6.22.1.oorig/include/linux/aufs_type.h linux-2.6.22.1/include/linux/aufs_type.h +--- linux-2.6.22.1.oorig/include/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/include/linux/aufs_type.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (C) 2005, 2006, 2007 Junjiro Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* $Id: aufs_type.h,v 1.55 2007/05/14 03:40:57 sfjro Exp $ */ ++ ++#include ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#define AUFS_VERSION "20070514" ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef char aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef short aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#else ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif ++ ++#define AUFS_NAME "aufs" ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_NWKQ_DEF 4 ++ ++#ifdef CONFIG_AUFS_COMPAT ++#define AUFS_DIROPQ_NAME "__dir_opaque" ++#else ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#endif ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++/* will be whiteouted doubly */ ++#define AUFS_WH_BASENAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX "plink" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum {AuCtlErr, AuCtlErr_Last}; ++enum { ++ AuCtl_REFRESH, //AuCtl_REFRESHV, ++ //AuCtl_FLUSH_PLINK, ++ //AuCtl_CPUP, ++ AuCtl_CPDOWN, AuCtl_MVDOWN ++}; ++ ++struct aufs_ctl_cp { ++ int bsrc, bdst; ++ int err; ++}; ++ ++#define Type 'A' ++#define AUFS_CTL_REFRESH _IO(Type, AuCtl_REFRESH) ++//#define AUFS_CTL_REFRESHV _IO(Type, AuCtl_REFRESHV) ++//#define AUFS_CTL_FLUSH_PLINK _IOR(Type, AuCtl_FLUSH_PLINK) ++//#define AUFS_CTL_CPUP _IOWR(Type, AuCtl_CPUP, struct aufs_ctl_cp) ++#define AUFS_CTL_CPDOWN _IOWR(Type, AuCtl_CPDOWN, struct aufs_ctl_cp) ++#define AUFS_CTL_MVDOWN _IOWR(Type, AuCtl_MVDOWN, struct aufs_ctl_cp) ++#undef Type ++ ++#endif /* __AUFS_TYPE_H__ */ +diff -rduNp linux-2.6.22.1.oorig/include/linux/squashfs_fs.h linux-2.6.22.1/include/linux/squashfs_fs.h +--- linux-2.6.22.1.oorig/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/include/linux/squashfs_fs.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,934 @@ ++#ifndef SQUASHFS_FS ++#define SQUASHFS_FS ++ ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs.h ++ */ ++ ++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY ++#endif ++ ++#ifdef CONFIG_SQUASHFS_VMALLOC ++#define SQUASHFS_ALLOC(a) vmalloc(a) ++#define SQUASHFS_FREE(a) vfree(a) ++#else ++#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL) ++#define SQUASHFS_FREE(a) kfree(a) ++#endif ++#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE ++#define SQUASHFS_MAJOR 3 ++#define SQUASHFS_MINOR 0 ++#define SQUASHFS_MAGIC 0x73717368 ++#define SQUASHFS_MAGIC_SWAP 0x68737173 ++#define SQUASHFS_START 0 ++ ++/* size of metadata (inode and directory) blocks */ ++#define SQUASHFS_METADATA_SIZE 8192 ++#define SQUASHFS_METADATA_LOG 13 ++ ++/* default size of data blocks */ ++#define SQUASHFS_FILE_SIZE 65536 ++#define SQUASHFS_FILE_LOG 16 ++ ++#define SQUASHFS_FILE_MAX_SIZE 65536 ++ ++/* Max number of uids and gids */ ++#define SQUASHFS_UIDS 256 ++#define SQUASHFS_GUIDS 255 ++ ++/* Max length of filename (not 255) */ ++#define SQUASHFS_NAME_LEN 256 ++ ++#define SQUASHFS_INVALID ((long long) 0xffffffffffff) ++#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) ++#define SQUASHFS_INVALID_BLK ((long long) -1) ++#define SQUASHFS_USED_BLK ((long long) -2) ++ ++/* Filesystem flags */ ++#define SQUASHFS_NOI 0 ++#define SQUASHFS_NOD 1 ++#define SQUASHFS_CHECK 2 ++#define SQUASHFS_NOF 3 ++#define SQUASHFS_NO_FRAG 4 ++#define SQUASHFS_ALWAYS_FRAG 5 ++#define SQUASHFS_DUPLICATE 6 ++#define SQUASHFS_EXPORT 7 ++ ++#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) ++ ++#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOI) ++ ++#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOD) ++ ++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOF) ++ ++#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NO_FRAG) ++ ++#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_ALWAYS_FRAG) ++ ++#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_DUPLICATE) ++ ++#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_EXPORT) ++ ++#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_CHECK) ++ ++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ ++ duplicate_checking, exortable) (noi | (nod << 1) | (check_data << 2) \ ++ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ ++ (duplicate_checking << 6) | (exportable << 7)) ++ ++/* Max number of types and file types */ ++#define SQUASHFS_DIR_TYPE 1 ++#define SQUASHFS_FILE_TYPE 2 ++#define SQUASHFS_SYMLINK_TYPE 3 ++#define SQUASHFS_BLKDEV_TYPE 4 ++#define SQUASHFS_CHRDEV_TYPE 5 ++#define SQUASHFS_FIFO_TYPE 6 ++#define SQUASHFS_SOCKET_TYPE 7 ++#define SQUASHFS_LDIR_TYPE 8 ++#define SQUASHFS_LREG_TYPE 9 ++ ++/* 1.0 filesystem type definitions */ ++#define SQUASHFS_TYPES 5 ++#define SQUASHFS_IPC_TYPE 0 ++ ++/* Flag whether block is compressed or uncompressed, bit is set if block is ++ * uncompressed */ ++#define SQUASHFS_COMPRESSED_BIT (1 << 15) ++ ++#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ ++ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) ++ ++#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) ++ ++#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) ++ ++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \ ++ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \ ++ ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) ++ ++#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) ++ ++/* ++ * Inode number ops. Inodes consist of a compressed block number, and an ++ * uncompressed offset within that block ++ */ ++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) ++ ++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) ++ ++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\ ++ << 16) + (B))) ++ ++/* Compute 32 bit VFS inode number from squashfs inode number */ ++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ ++ ((b) >> 2) + 1)) ++/* XXX */ ++ ++/* Translate between VFS mode and squashfs mode */ ++#define SQUASHFS_MODE(a) ((a) & 0xfff) ++ ++/* fragment and fragment table defines */ ++#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry)) ++ ++#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ ++ sizeof(long long)) ++ ++/* inode lookup table defines */ ++#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t)) ++ ++#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ ++ sizeof(long long)) ++ ++/* cached data constants for filesystem */ ++#define SQUASHFS_CACHED_BLKS 8 ++ ++#define SQUASHFS_MAX_FILE_SIZE_LOG 64 ++ ++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ ++ (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) ++ ++#define SQUASHFS_MARKER_BYTE 0xff ++ ++/* meta index cache */ ++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) ++#define SQUASHFS_META_ENTRIES 31 ++#define SQUASHFS_META_NUMBER 8 ++#define SQUASHFS_SLOTS 4 ++ ++struct meta_entry { ++ long long data_block; ++ unsigned int index_block; ++ unsigned short offset; ++ unsigned short pad; ++}; ++ ++struct meta_index { ++ unsigned int inode_number; ++ unsigned int offset; ++ unsigned short entries; ++ unsigned short skip; ++ unsigned short locked; ++ unsigned short pad; ++ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; ++}; ++ ++ ++/* ++ * definitions for structures on disk ++ */ ++ ++typedef long long squashfs_block_t; ++typedef long long squashfs_inode_t; ++ ++struct squashfs_super_block { ++ unsigned int s_magic; ++ unsigned int inodes; ++ unsigned int bytes_used_2; ++ unsigned int uid_start_2; ++ unsigned int guid_start_2; ++ unsigned int inode_table_start_2; ++ unsigned int directory_table_start_2; ++ unsigned int s_major:16; ++ unsigned int s_minor:16; ++ unsigned int block_size_1:16; ++ unsigned int block_log:16; ++ unsigned int flags:8; ++ unsigned int no_uids:8; ++ unsigned int no_guids:8; ++ unsigned int mkfs_time /* time of filesystem creation */; ++ squashfs_inode_t root_inode; ++ unsigned int block_size; ++ unsigned int fragments; ++ unsigned int fragment_table_start_2; ++ long long bytes_used; ++ long long uid_start; ++ long long guid_start; ++ long long inode_table_start; ++ long long directory_table_start; ++ long long fragment_table_start; ++ long long lookup_table_start; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_index { ++ unsigned int index; ++ unsigned int start_block; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_BASE_INODE_HEADER \ ++ unsigned int inode_type:4; \ ++ unsigned int mode:12; \ ++ unsigned int uid:8; \ ++ unsigned int guid:8; \ ++ unsigned int mtime; \ ++ unsigned int inode_number; ++ ++struct squashfs_base_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ squashfs_block_t start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_lreg_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ squashfs_block_t start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ long long file_size; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int start_block; ++ unsigned int parent_inode; ++} __attribute__ ((packed)); ++ ++struct squashfs_ldir_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned int file_size:27; ++ unsigned int offset:13; ++ unsigned int start_block; ++ unsigned int i_count:16; ++ unsigned int parent_inode; ++ struct squashfs_dir_index index[0]; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header { ++ struct squashfs_base_inode_header base; ++ struct squashfs_dev_inode_header dev; ++ struct squashfs_symlink_inode_header symlink; ++ struct squashfs_reg_inode_header reg; ++ struct squashfs_lreg_inode_header lreg; ++ struct squashfs_dir_inode_header dir; ++ struct squashfs_ldir_inode_header ldir; ++ struct squashfs_ipc_inode_header ipc; ++}; ++ ++struct squashfs_dir_entry { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ int inode_number:16; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_header { ++ unsigned int count:8; ++ unsigned int start_block; ++ unsigned int inode_number; ++} __attribute__ ((packed)); ++ ++struct squashfs_fragment_entry { ++ long long start_block; ++ unsigned int size; ++ unsigned int pending; ++} __attribute__ ((packed)); ++ ++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); ++extern int squashfs_uncompress_init(void); ++extern int squashfs_uncompress_exit(void); ++ ++/* ++ * macros to convert each packed bitfield structure from little endian to big ++ * endian and vice versa. These are needed when creating or using a filesystem ++ * on a machine with different byte ordering to the target architecture. ++ * ++ */ ++ ++#define SQUASHFS_SWAP_START \ ++ int bits;\ ++ int b_pos;\ ++ unsigned long long val;\ ++ unsigned char *s;\ ++ unsigned char *d; ++ ++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\ ++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ ++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ ++ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ ++ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ ++ SQUASHFS_SWAP((s)->flags, d, 288, 8);\ ++ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ ++ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ ++ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ ++ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ ++ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ ++ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ ++ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ ++ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ ++ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ ++ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ ++ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ ++ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ ++ SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\ ++} ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 64, 32); ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_ipc_inode_header))\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_dev_inode_header)); \ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_reg_inode_header));\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ ++ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_lreg_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ ++ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 224, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_dir_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 147, 13);\ ++ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_ldir_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ ++ SQUASHFS_SWAP((s)->offset, d, 155, 13);\ ++ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ ++ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ ++ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\ ++ SQUASHFS_SWAP((s)->index, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 64, 8);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ ++ SQUASHFS_SWAP((s)->size, d, 64, 32);\ ++} ++ ++#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) ++ ++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 2);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 16)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ ++} ++ ++#define SQUASHFS_SWAP_INTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 4);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 32)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 64)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ ++} ++ ++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * bits / 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ bits)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) ++#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++ ++struct squashfs_base_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int type:4; ++ unsigned int offset:4; ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int mtime; ++ unsigned int start_block; ++ unsigned int file_size:32; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ ++ SQUASHFS_SWAP((s)->guid, d, 20, 4); ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_ipc_inode_header_1));\ ++ SQUASHFS_SWAP((s)->type, d, 24, 4);\ ++ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_dev_inode_header_1));\ ++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header_1));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_reg_inode_header_1));\ ++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_dir_inode_header_1));\ ++ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ ++} ++ ++#endif ++ ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++ ++struct squashfs_dir_index_2 { ++ unsigned int index:27; ++ unsigned int start_block:29; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_base_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int mtime; ++ unsigned int start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size:32; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++struct squashfs_ldir_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:27; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++ unsigned int i_count:16; ++ struct squashfs_dir_index_2 index[0]; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header_2 { ++ struct squashfs_base_inode_header_2 base; ++ struct squashfs_dev_inode_header_2 dev; ++ struct squashfs_symlink_inode_header_2 symlink; ++ struct squashfs_reg_inode_header_2 reg; ++ struct squashfs_dir_inode_header_2 dir; ++ struct squashfs_ldir_inode_header_2 ldir; ++ struct squashfs_ipc_inode_header_2 ipc; ++}; ++ ++struct squashfs_dir_header_2 { ++ unsigned int count:8; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_entry_2 { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_fragment_entry_2 { ++ unsigned int start_block; ++ unsigned int size; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_dev_inode_header_2)); \ ++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header_2));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_reg_inode_header_2));\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_dir_inode_header_2));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 51, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ ++} ++ ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_ldir_inode_header_2));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ ++ SQUASHFS_SWAP((s)->offset, d, 59, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ ++ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ ++ SQUASHFS_SWAP((s)->index, d, 0, 27);\ ++ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ ++ SQUASHFS_SWAP((s)->size, d, 56, 8);\ ++} ++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 32, 32);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) ++ ++/* fragment and fragment table defines */ ++#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2)) ++ ++#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ ++ sizeof(int)) ++ ++#endif ++ ++#ifdef __KERNEL__ ++ ++/* ++ * macros used to swap each structure entry, taking into account ++ * bitfields and different bitfield placing conventions on differing ++ * architectures ++ */ ++ ++#include ++ ++#ifdef __BIG_ENDIAN ++ /* convert from little endian to big endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ ++ tbits, b_pos) ++#else ++ /* convert from big endian to little endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ ++ tbits, 64 - tbits - b_pos) ++#endif ++ ++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ ++ b_pos = pos % 8;\ ++ val = 0;\ ++ s = (unsigned char *)p + (pos / 8);\ ++ d = ((unsigned char *) &val) + 7;\ ++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ ++ *d-- = *s++;\ ++ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ ++} ++ ++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); ++ ++#endif ++#endif +diff -rduNp linux-2.6.22.1.oorig/include/linux/squashfs_fs_i.h linux-2.6.22.1/include/linux/squashfs_fs_i.h +--- linux-2.6.22.1.oorig/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/include/linux/squashfs_fs_i.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,45 @@ ++#ifndef SQUASHFS_FS_I ++#define SQUASHFS_FS_I ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_i.h ++ */ ++ ++struct squashfs_inode_info { ++ long long start_block; ++ unsigned int offset; ++ union { ++ struct { ++ long long fragment_start_block; ++ unsigned int fragment_size; ++ unsigned int fragment_offset; ++ long long block_list_start; ++ } s1; ++ struct { ++ long long directory_index_start; ++ unsigned int directory_index_offset; ++ unsigned int directory_index_count; ++ unsigned int parent_inode; ++ } s2; ++ } u; ++ struct inode vfs_inode; ++}; ++#endif +diff -rduNp linux-2.6.22.1.oorig/include/linux/squashfs_fs_sb.h linux-2.6.22.1/include/linux/squashfs_fs_sb.h +--- linux-2.6.22.1.oorig/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/include/linux/squashfs_fs_sb.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,74 @@ ++#ifndef SQUASHFS_FS_SB ++#define SQUASHFS_FS_SB ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher ++ * ++ * 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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_sb.h ++ */ ++ ++#include ++ ++struct squashfs_cache { ++ long long block; ++ int length; ++ long long next_index; ++ char *data; ++}; ++ ++struct squashfs_fragment_cache { ++ long long block; ++ int length; ++ unsigned int locked; ++ char *data; ++}; ++ ++struct squashfs_sb_info { ++ struct squashfs_super_block sblk; ++ int devblksize; ++ int devblksize_log2; ++ int swap; ++ struct squashfs_cache *block_cache; ++ struct squashfs_fragment_cache *fragment; ++ int next_cache; ++ int next_fragment; ++ int next_meta_index; ++ unsigned int *uid; ++ unsigned int *guid; ++ long long *fragment_index; ++ unsigned int *fragment_index_2; ++ char *read_page; ++ struct mutex read_data_mutex; ++ struct mutex read_page_mutex; ++ struct mutex block_cache_mutex; ++ struct mutex fragment_mutex; ++ struct mutex meta_index_mutex; ++ wait_queue_head_t waitq; ++ wait_queue_head_t fragment_wait_queue; ++ struct meta_index *meta_index; ++ z_stream stream; ++ long long *inode_lookup_table; ++ int (*read_inode)(struct inode *i, squashfs_inode_t \ ++ inode); ++ long long (*read_blocklist)(struct inode *inode, int \ ++ index, int readahead_blks, char *block_list, \ ++ unsigned short **block_p, unsigned int *bsize); ++ int (*read_fragment_index_table)(struct super_block *s); ++}; ++#endif +diff -rduNp linux-2.6.22.1.oorig/init/Kconfig linux-2.6.22.1/init/Kconfig +--- linux-2.6.22.1.oorig/init/Kconfig 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/init/Kconfig 2007-07-24 14:17:46.000000000 +0200 +@@ -246,23 +246,21 @@ config AUDITSYSCALL + ensure that INOTIFY is configured. + + config IKCONFIG +- tristate "Kernel .config support" ++ tristate "Kernel .miniconfig support" + ---help--- +- This option enables the complete Linux kernel ".config" file ++ This option enables the mini Linux kernel ".miniconfig" file + contents to be saved in the kernel. It provides documentation + of which kernel options are used in a running kernel or in an +- on-disk kernel. This information can be extracted from the kernel +- image file with the script scripts/extract-ikconfig and used as +- input to rebuild the current kernel or to build another kernel. +- It can also be extracted from a running kernel by reading +- /proc/config.gz if enabled (below). ++ on-disk kernel. ++ It can be extracted from a running kernel by reading ++ /proc/miniconfig.gz if enabled (below). + + config IKCONFIG_PROC +- bool "Enable access to .config through /proc/config.gz" ++ bool "Enable access to .miniconfig through /proc/miniconfig.gz" + depends on IKCONFIG && PROC_FS + ---help--- + This option enables access to the kernel configuration file +- through /proc/config.gz. ++ through /proc/miniconfig.gz. + + config LOG_BUF_SHIFT + int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" +diff -rduNp linux-2.6.22.1.oorig/init/LzmaDecode.c linux-2.6.22.1/init/LzmaDecode.c +--- linux-2.6.22.1.oorig/init/LzmaDecode.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/init/LzmaDecode.c 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,588 @@ ++/* ++ LzmaDecode.c ++ LZMA Decoder (optimized for Speed version) ++ ++ LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this Code, expressly permits you to ++ statically or dynamically link your Code (or bind by name) to the ++ interfaces of this file without subjecting your linked Code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#include "LzmaDecode.h" ++ ++#ifndef Byte ++#define Byte unsigned char ++#endif ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_READ_BYTE (*Buffer++) ++ ++#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ ++ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} ++ ++#ifdef _LZMA_IN_CB ++ ++#define RC_TEST { if (Buffer == BufferLim) \ ++ { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \ ++ BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }} ++ ++#define RC_INIT Buffer = BufferLim = 0; RC_INIT2 ++ ++#else ++ ++#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } ++ ++#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 ++ ++#endif ++ ++#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } ++ ++#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) ++#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; ++#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; ++ ++#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ ++ { UpdateBit0(p); mi <<= 1; A0; } else \ ++ { UpdateBit1(p); mi = (mi + mi) + 1; A1; } ++ ++#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) ++ ++#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ ++ { int i = numLevels; res = 1; \ ++ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \ ++ res -= (1 << numLevels); } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) ++{ ++ unsigned char prop0; ++ if (size < LZMA_PROPERTIES_SIZE) ++ return LZMA_RESULT_DATA_ERROR; ++ prop0 = propsData[0]; ++ if (prop0 >= (9 * 5 * 5)) ++ return LZMA_RESULT_DATA_ERROR; ++ { ++ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); ++ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); ++ propsRes->lc = prop0; ++ /* ++ unsigned char remainder = (unsigned char)(prop0 / 9); ++ propsRes->lc = prop0 % 9; ++ propsRes->pb = remainder / 5; ++ propsRes->lp = remainder % 5; ++ */ ++ } ++ ++ #ifdef _LZMA_OUT_READ ++ { ++ int i; ++ propsRes->DictionarySize = 0; ++ for (i = 0; i < 4; i++) ++ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); ++ if (propsRes->DictionarySize == 0) ++ propsRes->DictionarySize = 1; ++ } ++ #endif ++ return LZMA_RESULT_OK; ++} ++ ++#define kLzmaStreamWasFinishedId (-1) ++ ++int LzmaDecode(CLzmaDecoderState *vs, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *InCallback, ++ #else ++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, ++ #endif ++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) ++{ ++ CProb *p = vs->Probs; ++ SizeT nowPos = 0; ++ Byte previousByte = 0; ++ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; ++ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; ++ int lc = vs->Properties.lc; ++ ++ #ifdef _LZMA_OUT_READ ++ ++ UInt32 Range = vs->Range; ++ UInt32 Code = vs->Code; ++ #ifdef _LZMA_IN_CB ++ const Byte *Buffer = vs->Buffer; ++ const Byte *BufferLim = vs->BufferLim; ++ #else ++ const Byte *Buffer = inStream; ++ const Byte *BufferLim = inStream + inSize; ++ #endif ++ int state = vs->State; ++ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; ++ int len = vs->RemainLen; ++ UInt32 globalPos = vs->GlobalPos; ++ UInt32 distanceLimit = vs->DistanceLimit; ++ ++ Byte *dictionary = vs->Dictionary; ++ UInt32 dictionarySize = vs->Properties.DictionarySize; ++ UInt32 dictionaryPos = vs->DictionaryPos; ++ ++ Byte tempDictionary[4]; ++ ++ #ifndef _LZMA_IN_CB ++ *inSizeProcessed = 0; ++ #endif ++ *outSizeProcessed = 0; ++ if (len == kLzmaStreamWasFinishedId) ++ return LZMA_RESULT_OK; ++ ++ if (dictionarySize == 0) ++ { ++ dictionary = tempDictionary; ++ dictionarySize = 1; ++ tempDictionary[0] = vs->TempDictionary[0]; ++ } ++ ++ if (len == kLzmaNeedInitId) ++ { ++ { ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); ++ UInt32 i; ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ rep0 = rep1 = rep2 = rep3 = 1; ++ state = 0; ++ globalPos = 0; ++ distanceLimit = 0; ++ dictionaryPos = 0; ++ dictionary[dictionarySize - 1] = 0; ++ #ifdef _LZMA_IN_CB ++ RC_INIT; ++ #else ++ RC_INIT(inStream, inSize); ++ #endif ++ } ++ len = 0; ++ } ++ while(len != 0 && nowPos < outSize) ++ { ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ len--; ++ } ++ if (dictionaryPos == 0) ++ previousByte = dictionary[dictionarySize - 1]; ++ else ++ previousByte = dictionary[dictionaryPos - 1]; ++ ++ #else /* if !_LZMA_OUT_READ */ ++ ++ int state = 0; ++ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; ++ int len = 0; ++ const Byte *Buffer; ++ const Byte *BufferLim; ++ UInt32 Range; ++ UInt32 Code; ++ ++ #ifndef _LZMA_IN_CB ++ *inSizeProcessed = 0; ++ #endif ++ *outSizeProcessed = 0; ++ ++ { ++ UInt32 i; ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); ++ for (i = 0; i < numProbs; i++) ++ p[i] = kBitModelTotal >> 1; ++ } ++ ++ #ifdef _LZMA_IN_CB ++ RC_INIT; ++ #else ++ RC_INIT(inStream, inSize); ++ #endif ++ ++ #endif /* _LZMA_OUT_READ */ ++ ++ while(nowPos < outSize) ++ { ++ CProb *prob; ++ UInt32 bound; ++ int posState = (int)( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & posStateMask); ++ ++ prob = p + IsMatch + (state << kNumPosBitsMax) + posState; ++ IfBit0(prob) ++ { ++ int symbol = 1; ++ UpdateBit0(prob) ++ prob = p + Literal + (LZMA_LIT_SIZE * ++ ((( ++ (nowPos ++ #ifdef _LZMA_OUT_READ ++ + globalPos ++ #endif ++ ) ++ & literalPosMask) << lc) + (previousByte >> (8 - lc)))); ++ ++ if (state >= kNumLitStates) ++ { ++ int matchByte; ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ matchByte = dictionary[pos]; ++ #else ++ matchByte = outStream[nowPos - rep0]; ++ #endif ++ do ++ { ++ int bit; ++ CProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & 0x100); ++ probLit = prob + 0x100 + bit + symbol; ++ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) ++ } ++ while (symbol < 0x100); ++ } ++ while (symbol < 0x100) ++ { ++ CProb *probLit = prob + symbol; ++ RC_GET_BIT(probLit, symbol) ++ } ++ previousByte = (Byte)symbol; ++ ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit < dictionarySize) ++ distanceLimit++; ++ ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #endif ++ if (state < 4) state = 0; ++ else if (state < 10) state -= 3; ++ else state -= 6; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRep + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ state = state < kNumLitStates ? 0 : 3; ++ prob = p + LenCoder; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRepG0 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IfBit0(prob) ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos; ++ #endif ++ UpdateBit0(prob); ++ ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit == 0) ++ #else ++ if (nowPos == 0) ++ #endif ++ return LZMA_RESULT_DATA_ERROR; ++ ++ state = state < kNumLitStates ? 9 : 11; ++ #ifdef _LZMA_OUT_READ ++ pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ outStream[nowPos++] = previousByte; ++ #ifdef _LZMA_OUT_READ ++ if (distanceLimit < dictionarySize) ++ distanceLimit++; ++ #endif ++ ++ continue; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ } ++ } ++ else ++ { ++ UInt32 distance; ++ UpdateBit1(prob); ++ prob = p + IsRepG1 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ prob = p + IsRepG2 + state; ++ IfBit0(prob) ++ { ++ UpdateBit0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UpdateBit1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = p + RepLenCoder; ++ } ++ { ++ int numBits, offset; ++ CProb *probLen = prob + LenChoice; ++ IfBit0(probLen) ++ { ++ UpdateBit0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ numBits = kLenNumLowBits; ++ } ++ else ++ { ++ UpdateBit1(probLen); ++ probLen = prob + LenChoice2; ++ IfBit0(probLen) ++ { ++ UpdateBit0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ numBits = kLenNumMidBits; ++ } ++ else ++ { ++ UpdateBit1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ numBits = kLenNumHighBits; ++ } ++ } ++ RangeDecoderBitTreeDecode(probLen, numBits, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ int posSlot; ++ state += kNumLitStates; ++ prob = p + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ rep0 = (2 | ((UInt32)posSlot & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ rep0 <<= numDirectBits; ++ prob = p + SpecPos + rep0 - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ RC_NORMALIZE ++ Range >>= 1; ++ rep0 <<= 1; ++ if (Code >= Range) ++ { ++ Code -= Range; ++ rep0 |= 1; ++ } ++ } ++ while (--numDirectBits != 0); ++ prob = p + Align; ++ rep0 <<= kNumAlignBits; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ int i = 1; ++ int mi = 1; ++ do ++ { ++ CProb *prob3 = prob + mi; ++ RC_GET_BIT2(prob3, mi, ; , rep0 |= i); ++ i <<= 1; ++ } ++ while(--numDirectBits != 0); ++ } ++ } ++ else ++ rep0 = posSlot; ++ if (++rep0 == (UInt32)(0)) ++ { ++ /* it's for stream version */ ++ len = kLzmaStreamWasFinishedId; ++ break; ++ } ++ } ++ ++ len += kMatchMinLen; ++ #ifdef _LZMA_OUT_READ ++ if (rep0 > distanceLimit) ++ #else ++ if (rep0 > nowPos) ++ #endif ++ return LZMA_RESULT_DATA_ERROR; ++ ++ #ifdef _LZMA_OUT_READ ++ if (dictionarySize - distanceLimit > (UInt32)len) ++ distanceLimit += len; ++ else ++ distanceLimit = dictionarySize; ++ #endif ++ ++ do ++ { ++ #ifdef _LZMA_OUT_READ ++ UInt32 pos = dictionaryPos - rep0; ++ if (pos >= dictionarySize) ++ pos += dictionarySize; ++ previousByte = dictionary[pos]; ++ dictionary[dictionaryPos] = previousByte; ++ if (++dictionaryPos == dictionarySize) ++ dictionaryPos = 0; ++ #else ++ previousByte = outStream[nowPos - rep0]; ++ #endif ++ len--; ++ outStream[nowPos++] = previousByte; ++ } ++ while(len != 0 && nowPos < outSize); ++ } ++ } ++ RC_NORMALIZE; ++ ++ #ifdef _LZMA_OUT_READ ++ vs->Range = Range; ++ vs->Code = Code; ++ vs->DictionaryPos = dictionaryPos; ++ vs->GlobalPos = globalPos + (UInt32)nowPos; ++ vs->DistanceLimit = distanceLimit; ++ vs->Reps[0] = rep0; ++ vs->Reps[1] = rep1; ++ vs->Reps[2] = rep2; ++ vs->Reps[3] = rep3; ++ vs->State = state; ++ vs->RemainLen = len; ++ vs->TempDictionary[0] = tempDictionary[0]; ++ #endif ++ ++ #ifdef _LZMA_IN_CB ++ vs->Buffer = Buffer; ++ vs->BufferLim = BufferLim; ++ #else ++ *inSizeProcessed = (SizeT)(Buffer - inStream); ++ #endif ++ *outSizeProcessed = nowPos; ++ return LZMA_RESULT_OK; ++} +diff -rduNp linux-2.6.22.1.oorig/init/LzmaDecode.h linux-2.6.22.1/init/LzmaDecode.h +--- linux-2.6.22.1.oorig/init/LzmaDecode.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/init/LzmaDecode.h 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,131 @@ ++/* ++ LzmaDecode.h ++ LZMA Decoder interface ++ ++ LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08) ++ http://www.7-zip.org/ ++ ++ LZMA SDK is licensed under two licenses: ++ 1) GNU Lesser General Public License (GNU LGPL) ++ 2) Common Public License (CPL) ++ It means that you can select one of these two licenses and ++ follow rules of that license. ++ ++ SPECIAL EXCEPTION: ++ Igor Pavlov, as the author of this code, expressly permits you to ++ statically or dynamically link your code (or bind by name) to the ++ interfaces of this file without subjecting your linked code to the ++ terms of the CPL or GNU LGPL. Any modifications or additions ++ to this file, however, are subject to the LGPL or CPL terms. ++*/ ++ ++#ifndef __LZMADECODE_H ++#define __LZMADECODE_H ++ ++/* #define _LZMA_IN_CB */ ++/* Use callback for input data */ ++ ++/* #define _LZMA_OUT_READ */ ++/* Use read function for output data */ ++ ++/* #define _LZMA_PROB32 */ ++/* It can increase speed on some 32-bit CPUs, ++ but memory usage will be doubled in that case */ ++ ++/* #define _LZMA_LOC_OPT */ ++/* Enable local speed optimizations inside code */ ++ ++/* #define _LZMA_SYSTEM_SIZE_T */ ++/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/ ++ ++#ifndef UInt32 ++#ifdef _LZMA_UINT32_IS_ULONG ++#define UInt32 unsigned long ++#else ++#define UInt32 unsigned int ++#endif ++#endif ++ ++#ifndef SizeT ++#ifdef _LZMA_SYSTEM_SIZE_T ++#include ++#define SizeT size_t ++#else ++#define SizeT UInt32 ++#endif ++#endif ++ ++#ifdef _LZMA_PROB32 ++#define CProb UInt32 ++#else ++#define CProb unsigned short ++#endif ++ ++#define LZMA_RESULT_OK 0 ++#define LZMA_RESULT_DATA_ERROR 1 ++ ++#ifdef _LZMA_IN_CB ++typedef struct _ILzmaInCallback ++{ ++ int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize); ++} ILzmaInCallback; ++#endif ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LZMA_PROPERTIES_SIZE 5 ++ ++typedef struct _CLzmaProperties ++{ ++ int lc; ++ int lp; ++ int pb; ++ #ifdef _LZMA_OUT_READ ++ UInt32 DictionarySize; ++ #endif ++}CLzmaProperties; ++ ++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); ++ ++#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) ++ ++#define kLzmaNeedInitId (-2) ++ ++typedef struct _CLzmaDecoderState ++{ ++ CLzmaProperties Properties; ++ CProb *Probs; ++ ++ #ifdef _LZMA_IN_CB ++ const unsigned char *Buffer; ++ const unsigned char *BufferLim; ++ #endif ++ ++ #ifdef _LZMA_OUT_READ ++ unsigned char *Dictionary; ++ UInt32 Range; ++ UInt32 Code; ++ UInt32 DictionaryPos; ++ UInt32 GlobalPos; ++ UInt32 DistanceLimit; ++ UInt32 Reps[4]; ++ int State; ++ int RemainLen; ++ unsigned char TempDictionary[4]; ++ #endif ++} CLzmaDecoderState; ++ ++#ifdef _LZMA_OUT_READ ++#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; } ++#endif ++ ++int LzmaDecode(CLzmaDecoderState *vs, ++ #ifdef _LZMA_IN_CB ++ ILzmaInCallback *inCallback, ++ #else ++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, ++ #endif ++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); ++ ++#endif +diff -rduNp linux-2.6.22.1.oorig/init/do_mounts_rd.c linux-2.6.22.1/init/do_mounts_rd.c +--- linux-2.6.22.1.oorig/init/do_mounts_rd.c 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/init/do_mounts_rd.c 2007-07-24 14:17:46.000000000 +0200 +@@ -5,7 +5,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + + #include "do_mounts.h" +@@ -31,6 +33,9 @@ static int __init ramdisk_start_setup(ch + __setup("ramdisk_start=", ramdisk_start_setup); + + static int __init crd_load(int in_fd, int out_fd); ++#ifdef CONFIG_LZMA_INITRD ++static int __init lzma_rd_load(int in_fd, int out_fd); ++#endif + + /* + * This routine tries to find a RAM disk image to load, and returns the +@@ -39,6 +44,7 @@ static int __init crd_load(int in_fd, in + * numbers could not be found. + * + * We currently check for the following magic numbers: ++ * squashfs + * minix + * ext2 + * romfs +@@ -53,6 +59,7 @@ identify_ramdisk_image(int fd, int start + struct ext2_super_block *ext2sb; + struct romfs_super_block *romfsb; + struct cramfs_super *cramfsb; ++ struct squashfs_super_block *squashfsb; + int nblocks = -1; + unsigned char *buf; + +@@ -64,6 +71,7 @@ identify_ramdisk_image(int fd, int start + ext2sb = (struct ext2_super_block *) buf; + romfsb = (struct romfs_super_block *) buf; + cramfsb = (struct cramfs_super *) buf; ++ squashfsb = (struct squashfs_super_block *) buf; + memset(buf, 0xe5, size); + + /* +@@ -82,6 +90,17 @@ identify_ramdisk_image(int fd, int start + nblocks = 0; + goto done; + } ++ /* ++ * handle lzma compressed initrd, returns nblocks=1 as indication ++ */ ++ if( buf[0] < 9 * 5 * 5 && buf[9] == 0 && buf[10] == 0 && buf[11] == 0 ++ && buf[12] == 0 ) ++ { ++ printk( KERN_NOTICE "RAMDISK: LZMA image found at block %d\n", ++ start_block); ++ nblocks = 1; // just a convenient return flag ++ goto done; ++ } + + /* romfs is at block zero too */ + if (romfsb->word0 == ROMSB_WORD0 && +@@ -101,6 +120,18 @@ identify_ramdisk_image(int fd, int start + goto done; + } + ++ /* squashfs is at block zero too */ ++ if (squashfsb->s_magic == SQUASHFS_MAGIC) { ++ printk(KERN_NOTICE ++ "RAMDISK: squashfs filesystem found at block %d\n", ++ start_block); ++ if (squashfsb->s_major < 3) ++ nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ else ++ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ goto done; ++ } ++ + /* + * Read block 1 to test for minix and ext2 superblock + */ +@@ -172,7 +203,22 @@ int __init rd_load_image(char *from) + #endif + goto done; + } +- ++#ifdef CONFIG_LZMA_INITRD ++ /* ++ * handle lzma compressed image ++ */ ++ if ( nblocks == 1 ) ++ { ++ nblocks = 0; ++ if ( lzma_rd_load(in_fd, out_fd) == 0 ) ++ { ++ printk("\nLZMA initrd loaded successfully\n"); ++ goto successful_load; ++ } ++ printk(KERN_NOTICE "LZMA initrd is not in the correct format\n"); ++ goto done; ++ } ++#endif + /* + * NOTE NOTE: nblocks is not actually blocks but + * the number of kibibytes of data to load into a ramdisk. +@@ -393,6 +439,134 @@ static void __init error(char *x) + unzip_error = 1; + } + ++#ifdef CONFIG_LZMA_INITRD ++#define _LZMA_IN_CB ++#define _LZMA_OUT_READ ++#include "LzmaDecode.h" ++#include "LzmaDecode.c" ++ ++static int read_byte(void *object, const unsigned char **buffer, SizeT *bufferSize); ++ ++/* ++ * Do the lzma decompression ++ */ ++static int __init lzma_rd_load(int in_fd, int out_fd) ++{ ++ unsigned int i; ++ CLzmaDecoderState state; ++ unsigned char* outputbuffer; ++ unsigned int uncompressedSize = 0; ++ unsigned char* p; ++ unsigned int kBlockSize = 0x10000; ++ unsigned int nowPos = 0; ++ unsigned int outsizeProcessed = 0; ++ int res; ++ ILzmaInCallback callback; ++ ++ insize = 0; /* valid bytes in inbuf */ ++ inptr = 0; /* index of next byte to be processed in inbuf */ ++ exit_code = 0; ++ crd_infd = in_fd; ++ inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); ++ if (inbuf == 0) ++ { ++ printk(KERN_ERR "RAMDISK: Couldn't allocate lzma input buffer\n"); ++ return -1; ++ } ++ ++ callback.Read = read_byte; ++ ++ /* lzma args */ ++ i = get_byte(); ++ state.Properties.lc = i % 9, i = i / 9; ++ state.Properties.lp = i % 5, state.Properties.pb = i / 5; ++ ++ /* read dictionary size */ ++ p = (char*)&state.Properties.DictionarySize; ++ for (i = 0; i < 4; i++) ++ *p++ = get_byte(); ++ ++ /* get uncompressedSize */ ++ p= (char*)&uncompressedSize; ++ for (i = 0; i < 4; i++) ++ *p++ = get_byte(); ++ ++ /* skip big file */ ++ for (i = 0; i < 4; i++) ++ get_byte(); ++ ++ printk( KERN_NOTICE "RAMDISK: LZMA lc=%d,lp=%d,pb=%d,dictSize=%d,origSize=%d\n", ++ state.Properties.lc, state.Properties.lp, state.Properties.pb, state.Properties.DictionarySize, uncompressedSize); ++ outputbuffer = kmalloc(kBlockSize, GFP_KERNEL); ++ if (outputbuffer == 0) { ++ printk(KERN_ERR "RAMDISK: Couldn't allocate lzma output buffer\n"); ++ return -1; ++ } ++ ++ state.Probs = (CProb*)kmalloc( LzmaGetNumProbs(&state.Properties)*sizeof(CProb), GFP_KERNEL); ++ if ( state.Probs == 0) { ++ printk(KERN_ERR "RAMDISK: Couldn't allocate lzma workspace\n"); ++ return -1; ++ } ++ ++#ifdef CONFIG_LZMA_INITRD_KMALLOC_ONLY ++ state.Dictionary = kmalloc( state.Properties.DictionarySize, GFP_KERNEL); ++#else ++ state.Dictionary = vmalloc( state.Properties.DictionarySize); ++#endif ++ if ( state.Dictionary == 0) { ++ printk(KERN_ERR "RAMDISK: Couldn't allocate lzma dictionary\n"); ++ return -1; ++ } ++ ++ printk( KERN_NOTICE "LZMA initrd by Ming-Ching Tiew " ); ++ ++ LzmaDecoderInit( &state ); ++ ++ for( nowPos =0; nowPos < uncompressedSize ; ) ++ { ++ UInt32 blockSize = uncompressedSize - nowPos; ++ if( blockSize > kBlockSize) ++ blockSize = kBlockSize; ++ res = LzmaDecode( &state, &callback, outputbuffer, blockSize, &outsizeProcessed); ++ if( res != 0 ) { ++ printk( KERN_ERR "RAMDISK: Lzma decode failure\n"); ++ return -1; ++ } ++ if( outsizeProcessed == 0 ) ++ { ++ uncompressedSize = nowPos; ++ printk( KERN_NOTICE "RAMDISK nowPos=%d, uncompressedSize=%d\n", ++ nowPos, uncompressedSize ); ++ break; ++ } ++ sys_write(out_fd, outputbuffer, outsizeProcessed ); ++ nowPos += outsizeProcessed; ++ printk( "."); ++ } ++ ++#ifdef CONFIG_LZMA_INITRD_KMALLOC_ONLY ++ kfree(state.Dictionary); ++#else ++ vfree(state.Dictionary); ++#endif ++ kfree(inbuf); ++ kfree(outputbuffer); ++ kfree(state.Probs); ++ return 0; ++} ++ ++static int read_byte(void *object, const unsigned char **buffer, SizeT *bufferSize) ++{ ++ static unsigned char val; ++ *bufferSize = 1; ++ val = get_byte(); ++ *buffer = &val; ++ return LZMA_RESULT_OK; ++} ++ ++#endif /*CONFIG_LZMA_INITRD*/ ++ + static int __init crd_load(int in_fd, int out_fd) + { + int result; +diff -rduNp linux-2.6.22.1.oorig/init/initramfs.c linux-2.6.22.1/init/initramfs.c +--- linux-2.6.22.1.oorig/init/initramfs.c 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/init/initramfs.c 2007-07-24 14:17:46.000000000 +0200 +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + static __initdata char *message; + static void __init error(char *x) +@@ -441,6 +442,118 @@ static void __init flush_window(void) + outcnt = 0; + } + ++#ifdef CONFIG_LZMA_INITRAM_FS ++#define _LZMA_IN_CB ++#define _LZMA_OUT_READ ++#include "LzmaDecode.h" ++#ifndef CONFIG_LZMA_INITRD ++ #include "LzmaDecode.c" ++#endif ++static int read_byte(void *object, const unsigned char **buffer, SizeT *bufferSize) ++{ ++ static unsigned char val; ++ *bufferSize = 1; ++ val = get_byte(); ++ *buffer = &val; ++ return LZMA_RESULT_OK; ++} ++ ++static int __init lzma_unzip(void) ++{ ++ unsigned int i; ++ CLzmaDecoderState state; ++ unsigned char* outputbuffer; ++ unsigned int uncompressedSize = 0; ++ unsigned char* p; ++ unsigned int kBlockSize = 0x10000; ++ unsigned int nowPos = 0; ++ unsigned int outsizeProcessed = 0; ++ int res; ++ ILzmaInCallback callback; ++ ++ callback.Read = read_byte; ++ ++ // lzma args ++ i = get_byte(); ++ state.Properties.lc = i % 9, i = i / 9; ++ state.Properties.lp = i % 5, state.Properties.pb = i / 5; ++ ++ // read dictionary size ++ p = (char*)&state.Properties.DictionarySize; ++ for (i = 0; i < 4; i++) ++ *p++ = get_byte(); ++ ++ // get uncompressedSize ++ p= (char*)&uncompressedSize; ++ for (i = 0; i < 4; i++) ++ *p++ = get_byte(); ++ ++ // skip big file ++ for (i = 0; i < 4; i++) ++ get_byte(); ++ ++ printk( KERN_NOTICE "initramfs: LZMA lc=%d,lp=%d,pb=%d,dictSize=%d,origSize=%d\n", ++ state.Properties.lc,state.Properties.lp,state.Properties.pb,state.Properties.DictionarySize, uncompressedSize); ++ outputbuffer = kmalloc(kBlockSize, GFP_KERNEL); ++ if (outputbuffer == 0) { ++ printk(KERN_ERR "initramfs: Couldn't allocate lzma output buffer\n"); ++ return -1; ++ } ++ ++ state.Probs = (CProb*) kmalloc( LzmaGetNumProbs(&state.Properties)*sizeof(CProb), GFP_KERNEL); ++ if ( state.Probs == 0) { ++ printk(KERN_ERR "initramfs: Couldn't allocate lzma workspace\n"); ++ return -1; ++ } ++ ++#ifdef CONFIG_LZMA_INITRAM_FS_KMALLOC_ONLY ++ state.Dictionary = kmalloc( state.Properties.DictionarySize, GFP_KERNEL); ++#else ++ state.Dictionary = vmalloc( state.Properties.DictionarySize); ++#endif ++ if ( state.Dictionary == 0) { ++ printk(KERN_ERR "initramfs: Couldn't allocate lzma dictionary\n"); ++ return -1; ++ } ++ ++ printk( KERN_NOTICE "LZMA initramfs by Ming-Ching Tiew " ); ++ ++ LzmaDecoderInit( &state ); ++ ++ for( nowPos =0; nowPos < uncompressedSize ; ) ++ { ++ UInt32 blockSize = uncompressedSize - nowPos; ++ if( blockSize > kBlockSize) ++ blockSize = kBlockSize; ++ res = LzmaDecode( &state, &callback, outputbuffer, blockSize, &outsizeProcessed); ++ if( res != 0 ) { ++ panic( KERN_ERR "initramfs: Lzma decode failure\n"); ++ return -1; ++ } ++ if( outsizeProcessed == 0 ) ++ { ++ uncompressedSize = nowPos; ++ printk( KERN_NOTICE "initramfs: nowPos=%d, uncompressedSize=%d\n", ++ nowPos, uncompressedSize ); ++ break; ++ } ++ flush_buffer(outputbuffer, outsizeProcessed); ++ nowPos += outsizeProcessed; ++ printk( "."); ++ } ++ ++#ifdef CONFIG_LZMA_INITRAM_FS_KMALLOC_ONLY ++ kfree(state.Dictionary); ++#else ++ vfree(state.Dictionary); ++#endif ++ kfree(outputbuffer); ++ kfree(state.Probs); ++ return 0; ++} ++ ++#endif /*CONFIG LZMA_INITRAM_FS*/ ++ + static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) + { + int written; +@@ -475,12 +588,31 @@ static char * __init unpack_to_rootfs(ch + inptr = 0; + outcnt = 0; /* bytes in output buffer */ + bytes_out = 0; +- crc = (ulg)0xffffffffL; /* shift register contents */ +- makecrc(); +- gunzip(); +- if (state != Reset) ++ if( inbuf[0] == 037 && ((inbuf[1] == 0213) || (inbuf[1] == 0236))) ++ { ++ printk( KERN_NOTICE "detected gzip initramfs\n"); ++ crc = (ulg)0xffffffffL; /* shift register contents */ ++ makecrc(); ++ gunzip(); ++ if (state != Reset) + error("junk in gzipped archive"); +- this_header = saved_offset + inptr; ++ } ++#ifdef CONFIG_LZMA_INITRAM_FS ++ else if( inbuf[0] < 9 * 5 * 5 && buf[9] == 0 && buf[10] == 0 ++ && buf[11] == 0 && buf[12] == 0 ) ++ { ++ printk( KERN_NOTICE "detected lzma initramfs\n"); ++ lzma_unzip(); ++ } ++#endif ++ else ++ { ++ // skip forward ? ++ crc = (ulg)0xffffffffL; /* shift register contents */ ++ makecrc(); ++ gunzip(); ++ } ++ this_header = saved_offset + inptr; + buf += inptr; + len -= inptr; + } +diff -rduNp linux-2.6.22.1.oorig/kernel/Makefile linux-2.6.22.1/kernel/Makefile +--- linux-2.6.22.1.oorig/kernel/Makefile 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/kernel/Makefile 2007-07-24 14:17:46.000000000 +0200 +@@ -66,7 +66,7 @@ $(obj)/configs.o: $(obj)/config_data.h + # config_data.h contains the same information as ikconfig.h but gzipped. + # Info from config_data can be extracted from /proc/config* + targets += config_data.gz +-$(obj)/config_data.gz: .config FORCE ++$(obj)/config_data.gz: .miniconfig FORCE + $(call if_changed,gzip) + + quiet_cmd_ikconfiggz = IKCFG $@ +diff -rduNp linux-2.6.22.1.oorig/kernel/configs.c linux-2.6.22.1/kernel/configs.c +--- linux-2.6.22.1.oorig/kernel/configs.c 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/kernel/configs.c 2007-07-24 14:17:46.000000000 +0200 +@@ -79,7 +79,7 @@ static int __init ikconfig_init(void) + struct proc_dir_entry *entry; + + /* create the current config file */ +- entry = create_proc_entry("config.gz", S_IFREG | S_IRUGO, ++ entry = create_proc_entry("miniconfig.gz", S_IFREG | S_IRUGO, + &proc_root); + if (!entry) + return -ENOMEM; +@@ -95,7 +95,7 @@ static int __init ikconfig_init(void) + + static void __exit ikconfig_cleanup(void) + { +- remove_proc_entry("config.gz", &proc_root); ++ remove_proc_entry("miniconfig.gz", &proc_root); + } + + module_init(ikconfig_init); +diff -rduNp linux-2.6.22.1.oorig/kernel/time/clocksource.c linux-2.6.22.1/kernel/time/clocksource.c +--- linux-2.6.22.1.oorig/kernel/time/clocksource.c 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/kernel/time/clocksource.c 2007-07-24 14:17:46.000000000 +0200 +@@ -87,8 +87,8 @@ static void clocksource_ratewd(struct cl + if (delta > -WATCHDOG_THRESHOLD && delta < WATCHDOG_THRESHOLD) + return; + +- printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", +- cs->name, delta); ++/* printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", ++ cs->name, delta); */ + cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); + clocksource_change_rating(cs, 0); + cs->flags &= ~CLOCK_SOURCE_WATCHDOG; +diff -rduNp linux-2.6.22.1.oorig/miniconfig.sh linux-2.6.22.1/miniconfig.sh +--- linux-2.6.22.1.oorig/miniconfig.sh 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/miniconfig.sh 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,2 @@ ++#!/bin/sh -f ++make allnoconfig KCONFIG_ALLCONFIG=.miniconfig +diff -rduNp linux-2.6.22.1.oorig/scripts/Makefile.lib linux-2.6.22.1/scripts/Makefile.lib +--- linux-2.6.22.1.oorig/scripts/Makefile.lib 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/scripts/Makefile.lib 2007-07-24 14:17:46.000000000 +0200 +@@ -162,4 +162,9 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) + quiet_cmd_gzip = GZIP $@ + cmd_gzip = gzip -f -9 < $< > $@ + ++# LZMA ++# ++quiet_cmd_lzma = LZMA $@ ++cmd_lzma = lzma e $< $@ -lc7 -lp0 -pb0 2>/dev/null ++ + +diff -rduNp linux-2.6.22.1.oorig/scripts/gen_lzma_initramfs_list.sh linux-2.6.22.1/scripts/gen_lzma_initramfs_list.sh +--- linux-2.6.22.1.oorig/scripts/gen_lzma_initramfs_list.sh 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/scripts/gen_lzma_initramfs_list.sh 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,292 @@ ++#!/bin/bash ++# Copyright (C) Martin Schlemmer ++# Copyright (c) 2006 Sam Ravnborg ++# ++# Released under the terms of the GNU GPL ++# ++# Generate a cpio packed initramfs. It uses gen_init_cpio to generate ++# the cpio archive, and gzip to pack it. ++# The script may also be used to generate the inputfile used for gen_init_cpio ++# This script assumes that gen_init_cpio is located in usr/ directory ++ ++# error out on errors ++set -e ++ ++usage() { ++cat << EOF ++Usage: ++$0 [-o ] [-u ] [-g ] { -s | -d | } ... ++ -o Create lzma initramfs file named using ++ gen_init_cpio and lzma ++ -u User ID to map to user ID 0 (root). ++ is only meaningful if ++ is a directory. ++ -g Group ID to map to group ID 0 (root). ++ is only meaningful if ++ is a directory. ++ File list or directory for cpio archive. ++ If is a .cpio file it will be used ++ as direct input to initramfs. ++ -s Create lzma file with small dictionary size ++ -d Output the default cpio list. ++ ++All options except -o and -l may be repeated and are interpreted ++sequentially and immediately. -u and -g states are preserved across ++ options so an explicit "-u 0 -g 0" is required ++to reset the root/group mapping. ++EOF ++} ++ ++list_default_initramfs() { ++ # echo usr/kinit/kinit ++ : ++} ++ ++default_initramfs() { ++ cat <<-EOF >> ${output} ++ # This is a very simple, default initramfs ++ ++ dir /dev 0755 0 0 ++ nod /dev/console 0600 0 0 c 5 1 ++ dir /root 0700 0 0 ++ # file /kinit usr/kinit/kinit 0755 0 0 ++ # slink /init kinit 0755 0 0 ++ EOF ++} ++ ++filetype() { ++ local argv1="$1" ++ ++ # symlink test must come before file test ++ if [ -L "${argv1}" ]; then ++ echo "slink" ++ elif [ -f "${argv1}" ]; then ++ echo "file" ++ elif [ -d "${argv1}" ]; then ++ echo "dir" ++ elif [ -b "${argv1}" -o -c "${argv1}" ]; then ++ echo "nod" ++ elif [ -p "${argv1}" ]; then ++ echo "pipe" ++ elif [ -S "${argv1}" ]; then ++ echo "sock" ++ else ++ echo "invalid" ++ fi ++ return 0 ++} ++ ++list_print_mtime() { ++ : ++} ++ ++print_mtime() { ++ local my_mtime="0" ++ ++ if [ -e "$1" ]; then ++ my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1) ++ fi ++ ++ echo "# Last modified: ${my_mtime}" >> ${output} ++ echo "" >> ${output} ++} ++ ++list_parse() { ++ echo "$1 \\" ++} ++ ++# for each file print a line in following format ++# ++# for links, devices etc the format differs. See gen_init_cpio for details ++parse() { ++ local location="$1" ++ local name="${location/${srcdir}//}" ++ # change '//' into '/' ++ name="${name//\/\///}" ++ local mode="$2" ++ local uid="$3" ++ local gid="$4" ++ local ftype=$(filetype "${location}") ++ # remap uid/gid to 0 if necessary ++ [ "$uid" -eq "$root_uid" ] && uid=0 ++ [ "$gid" -eq "$root_gid" ] && gid=0 ++ local str="${mode} ${uid} ${gid}" ++ ++ [ "${ftype}" == "invalid" ] && return 0 ++ [ "${location}" == "${srcdir}" ] && return 0 ++ ++ case "${ftype}" in ++ "file") ++ str="${ftype} ${name} ${location} ${str}" ++ ;; ++ "nod") ++ local dev_type= ++ local maj=$(LC_ALL=C ls -l "${location}" | \ ++ gawk '{sub(/,/, "", $5); print $5}') ++ local min=$(LC_ALL=C ls -l "${location}" | \ ++ gawk '{print $6}') ++ ++ if [ -b "${location}" ]; then ++ dev_type="b" ++ else ++ dev_type="c" ++ fi ++ str="${ftype} ${name} ${str} ${dev_type} ${maj} ${min}" ++ ;; ++ "slink") ++ local target=$(LC_ALL=C ls -l "${location}" | \ ++ gawk '{print $11}') ++ str="${ftype} ${name} ${target} ${str}" ++ ;; ++ *) ++ str="${ftype} ${name} ${str}" ++ ;; ++ esac ++ ++ echo "${str}" >> ${output} ++ ++ return 0 ++} ++ ++unknown_option() { ++ printf "ERROR: unknown option \"$arg\"\n" >&2 ++ printf "If the filename validly begins with '-', " >&2 ++ printf "then it must be prefixed\n" >&2 ++ printf "by './' so that it won't be interpreted as an option." >&2 ++ printf "\n" >&2 ++ usage >&2 ++ exit 1 ++} ++ ++list_header() { ++ : ++} ++ ++header() { ++ printf "\n#####################\n# $1\n" >> ${output} ++} ++ ++# process one directory (incl sub-directories) ++dir_filelist() { ++ ${dep_list}header "$1" ++ ++ srcdir=$(echo "$1" | sed -e 's://*:/:g') ++ dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" 2>/dev/null) ++ ++ # If $dirlist is only one line, then the directory is empty ++ if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then ++ ${dep_list}print_mtime "$1" ++ ++ echo "${dirlist}" | \ ++ while read x; do ++ ${dep_list}parse ${x} ++ done ++ fi ++} ++ ++# if only one file is specified and it is .cpio file then use it direct as fs ++# if a directory is specified then add all files in given direcotry to fs ++# if a regular file is specified assume it is in gen_initramfs format ++input_file() { ++ source="$1" ++ if [ -f "$1" ]; then ++ ${dep_list}header "$1" ++ is_cpio="$(echo "$1" | sed 's/^.*\.cpio/cpio/')" ++ if [ $2 -eq 0 -a ${is_cpio} == "cpio" ]; then ++ cpio_file=$1 ++ [ ! -z ${dep_list} ] && echo "$1" ++ return 0 ++ fi ++ if [ -z ${dep_list} ]; then ++ print_mtime "$1" >> ${output} ++ cat "$1" >> ${output} ++ else ++ cat "$1" | while read type dir file perm ; do ++ if [ "$type" == "file" ]; then ++ echo "$file \\"; ++ fi ++ done ++ fi ++ elif [ -d "$1" ]; then ++ dir_filelist "$1" ++ else ++ echo " ${prog}: Cannot open '$1'" >&2 ++ exit 1 ++ fi ++} ++ ++prog=$0 ++root_uid=0 ++root_gid=0 ++dep_list= ++cpio_file= ++cpio_list= ++output="/dev/stdout" ++output_file="" ++opt="" ++ ++arg="$1" ++case "$arg" in ++ "-l") # files included in initramfs - used by kbuild ++ dep_list="list_" ++ echo "deps_initramfs := \\" ++ shift ++ ;; ++ "-o") # generate lzma-ed cpio image named $1 ++ shift ++ output_file="$1" ++ cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)" ++ output=${cpio_list} ++ shift ++ ;; ++esac ++while [ $# -gt 0 ]; do ++ arg="$1" ++ shift ++ case "$arg" in ++ "-u") # map $1 to uid=0 (root) ++ root_uid="$1" ++ shift ++ ;; ++ "-g") # map $1 to gid=0 (root) ++ root_gid="$1" ++ shift ++ ;; ++ "-s") ++ opt="-d16" ++ ;; ++ "-d") # display default initramfs list ++ default_list="$arg" ++ ${dep_list}default_initramfs ++ ;; ++ "-h") ++ usage ++ exit 0 ++ ;; ++ *) ++ case "$arg" in ++ "-"*) ++ unknown_option ++ ;; ++ *) # input file/dir - process it ++ input_file "$arg" "$#" ++ ;; ++ esac ++ ;; ++ esac ++done ++ ++# If output_file is set we will generate cpio archive and lzma it ++# we are carefull to delete tmp files ++if [ ! -z ${output_file} ]; then ++ if [ -z ${cpio_file} ]; then ++ cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)" ++ usr/gen_init_cpio ${cpio_list} > ${cpio_tfile} ++ else ++ cpio_tfile=${cpio_file} ++ fi ++ rm ${cpio_list} ++ lzma e ${cpio_tfile} ${output_file} ${opt} ++ [ -z ${cpio_file} ] && rm ${cpio_tfile} ++fi ++exit 0 +diff -rduNp linux-2.6.22.1.oorig/shrinkconfig.sh linux-2.6.22.1/shrinkconfig.sh +--- linux-2.6.22.1.oorig/shrinkconfig.sh 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.22.1/shrinkconfig.sh 2007-07-24 14:17:46.000000000 +0200 +@@ -0,0 +1,79 @@ ++#! /bin/bash ++ ++# shrinkconfig copyright 2006 by Rob Landley ++# Licensed under the GNU General Public License version 2. ++ ++if [ $# -ne 1 ] ++then ++ echo "Turns current .config into a miniconfig file." ++ echo "Usage: shrinkconfig mini.config" ++ exit 1 ++fi ++ ++if [ ! -f .config ] ++then ++ echo "Need a .config file to shrink." ++ exit 1 ++fi ++LENGTH=$(wc -l < .config) ++ ++OUTPUT="$1" ++cp .config "$OUTPUT" ++if [ $? -ne 0 ] ++then ++ echo "Couldn't create $OUTPUT" ++ exit 1 ++fi ++ ++# If we get interrupted, clean up the mess ++ ++KERNELOUTPUT="" ++ ++function cleanup ++{ ++ echo ++ echo "Interrupted." ++ [ ! -z "$KERNELOUTPUT" ] && rm -rf "$KERNELOUTPUT" ++ rm "$OUTPUT" ++ exit 1 ++} ++ ++trap cleanup HUP INT QUIT TERM ++ ++# Since the "O=" argument to make doesn't work recursively, we need to jump ++# through a few hoops to avoid overwriting the .config that we're shrinking. ++ ++# If we're building out of tree, we'll have absolute paths to source and build ++# directories in the Makefile. ++ ++KERNELSRC=$(sed -n -e 's/KERNELSRC[^/]*:=[^/]*//p' Makefile) ++[ -z "$KERNELSRC" ] && KERNELSRC=$(pwd) ++KERNELOUTPUT=`pwd`/.config.minitemp ++ ++mkdir -p "$KERNELOUTPUT" || exit 1 ++ ++echo "Shrinking .config to $OUTPUT..." ++ ++for I in $(seq 1 $LENGTH) ++do ++ echo -n -e "\r"$I/$LENGTH lines $(wc -c < "$OUTPUT") bytes ++ ++ sed -n "${I}!p" "$OUTPUT" > "$KERNELOUTPUT"/.config.test ++ # Do a config with this file ++ make -C "$KERNELSRC" O="$KERNELOUTPUT" allnoconfig KCONFIG_ALLCONFIG="$KERNELOUTPUT"/.config.test > /dev/null ++ ++ # Compare. The date changes, so expect a small difference each time. ++ D=$(diff "$KERNELOUTPUT"/.config .config | wc -l) ++ if [ $D -eq 4 ] ++ then ++ mv "$KERNELOUTPUT"/.config.test "$OUTPUT" ++ LENGTH=$[$LENGTH-1] ++ else ++ I=$[$I + 1] ++ fi ++done ++ ++rm -rf "$KERNELOUTPUT" ++ ++# One extra echo to preserve status line. ++echo +diff -rduNp linux-2.6.22.1.oorig/usr/Makefile linux-2.6.22.1/usr/Makefile +--- linux-2.6.22.1.oorig/usr/Makefile 2007-07-10 20:56:30.000000000 +0200 ++++ linux-2.6.22.1/usr/Makefile 2007-07-24 14:17:46.000000000 +0200 +@@ -19,6 +19,7 @@ $(obj)/initramfs_data.o: $(obj)/initramf + + hostprogs-y := gen_init_cpio + initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh ++lzma_initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_lzma_initramfs_list.sh + ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \ + $(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d) + ramfs-args := \ +@@ -36,6 +37,14 @@ endif + quiet_cmd_initfs = GEN $@ + cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) + ++ifdef CONFIG_LZMA_INITRAM_FS_SMALLMEM ++quiet_cmd_lzma_initfs = LZRAMFS $@ ++ cmd_lzma_initfs = $(lzma_initramfs) -o $@ $(ramfs-args) -s $(ramfs-input) ++else ++quiet_cmd_lzma_initfs = LZRAMFS $@ ++ cmd_lzma_initfs = $(lzma_initramfs) -o $@ $(ramfs-args) $(ramfs-input) ++endif ++ + targets := initramfs_data.cpio.gz + # do not try to update files included in initramfs + $(deps_initramfs): ; +@@ -48,5 +57,9 @@ $(deps_initramfs): klibcdirs + # 4) arguments to gen_initramfs.sh changes + $(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs + $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.gz.d ++ifdef CONFIG_LZMA_INITRAM_FS ++ $(call if_changed,lzma_initfs) ++else + $(call if_changed,initfs) ++endif + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-002-lzma-vmlinuz.01.patch b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-002-lzma-vmlinuz.01.patch new file mode 100644 index 0000000000..05361ff9d4 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-002-lzma-vmlinuz.01.patch @@ -0,0 +1,54 @@ +diff -rdup linux-2.6.21.5.oorig/arch/i386/boot/compressed/Makefile linux-2.6.21.5/arch/i386/boot/compressed/Makefile +--- linux-2.6.21.5.oorig/arch/i386/boot/compressed/Makefile 2007-07-24 13:08:51.000000000 +0200 ++++ linux-2.6.21.5/arch/i386/boot/compressed/Makefile 2007-07-24 14:54:38.000000000 +0200 +@@ -4,7 +4,7 @@ + # create a compressed vmlinux image from the original vmlinux + # + +-tragets := head.o lzma_misc.o piggy.o \ ++targets := head.o lzma_misc.o piggy.o \ + vmlinux.bin.all vmlinux.relocs \ + vmlinux vmlinux.bin vmlinux.bin.gz + EXTRA_AFLAGS := -traditional +diff -rdup linux-2.6.21.5.oorig/scripts/gen_lzma_initramfs_list.sh linux-2.6.21.5/scripts/gen_lzma_initramfs_list.sh +--- linux-2.6.21.5.oorig/scripts/gen_lzma_initramfs_list.sh 2007-07-24 13:08:51.000000000 +0200 ++++ linux-2.6.21.5/scripts/gen_lzma_initramfs_list.sh 2007-07-24 15:12:10.000000000 +0200 +@@ -253,7 +253,7 @@ while [ $# -gt 0 ]; do + shift + ;; + "-s") +- opt="-d16" ++ #opt="-d16" ? what was that supposed to do? + ;; + "-d") # display default initramfs list + default_list="$arg" +@@ -286,7 +286,7 @@ if [ ! -z ${output_file} ]; then + cpio_tfile=${cpio_file} + fi + rm ${cpio_list} +- lzma e ${cpio_tfile} ${output_file} ${opt} ++ lzma -z ${cpio_tfile} ${opt} -c > ${output_file} + [ -z ${cpio_file} ] && rm ${cpio_tfile} + fi + exit 0 +--- linux-2.6.21.5.oorig/arch/i386/boot/compressed/lzma_misc.c 2007-07-24 15:24:44.000000000 +0200 ++++ linux-2.6.21.5/arch/i386/boot/compressed/lzma_misc.c 2007-07-24 17:09:40.000000000 +0200 +@@ -241,7 +241,6 @@ static int lzma_unzip(uch* output) + + static int read_byte(void *object, const unsigned char **buffer, SizeT *bufferSize) + { +- static unsigned int i = 0; + static unsigned char val; + *bufferSize = 1; + val = get_byte(); +--- linux-2.6.21.5.oorig/scripts/Makefile.lib 2007-07-24 15:24:44.000000000 +0200 ++++ linux-2.6.21.5/scripts/Makefile.lib 2007-07-24 18:03:57.000000000 +0200 +@@ -165,6 +165,7 @@ cmd_gzip = gzip -f -9 < $< > $@ + # LZMA + # + quiet_cmd_lzma = LZMA $@ +-cmd_lzma = lzma e $< $@ -lc7 -lp0 -pb0 2>/dev/null ++#cmd_lzma = lzma e $< $@ -lc7 -lp0 -pb0 2>/dev/null ++cmd_lzma = lzma -z $< -c > $@ + + diff --git a/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-003-lzma-vmlinuz.patch b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-003-lzma-vmlinuz.patch new file mode 100644 index 0000000000..8fb7e882d1 --- /dev/null +++ b/cleopatre/buildroot/toolchain/kernel-headers/lzma/linux-2.6.22.1-003-lzma-vmlinuz.patch @@ -0,0 +1,44 @@ +diff -rdup linux-2.6.22.1.old/scripts/Makefile.lib linux-2.6.22.1/scripts/Makefile.lib +--- linux-2.6.22.1.old/scripts/Makefile.lib 2007-08-21 16:32:19.000000000 +0200 ++++ linux-2.6.22.1/scripts/Makefile.lib 2007-08-21 16:43:20.000000000 +0200 +@@ -166,6 +166,6 @@ cmd_gzip = gzip -f -9 < $< > $@ + # + quiet_cmd_lzma = LZMA $@ + #cmd_lzma = lzma e $< $@ -lc7 -lp0 -pb0 2>/dev/null +-cmd_lzma = lzma -z $< -c > $@ ++cmd_lzma = $(LZMA) -z $< -c > $@ + + +diff -rdup linux-2.6.22.1.old/scripts/gen_lzma_initramfs_list.sh linux-2.6.22.1/scripts/gen_lzma_initramfs_list.sh +--- linux-2.6.22.1.old/scripts/gen_lzma_initramfs_list.sh 2007-08-21 16:32:19.000000000 +0200 ++++ linux-2.6.22.1/scripts/gen_lzma_initramfs_list.sh 2007-08-21 16:42:56.000000000 +0200 +@@ -11,7 +11,7 @@ + + # error out on errors + set -e +- ++test "x$LZMA" = "x" && LZMA=lzma + usage() { + cat << EOF + Usage: +@@ -286,7 +286,7 @@ if [ ! -z ${output_file} ]; then + cpio_tfile=${cpio_file} + fi + rm ${cpio_list} +- lzma -z ${cpio_tfile} ${opt} -c > ${output_file} ++ $LZMA -z ${cpio_tfile} ${opt} -c > ${output_file} + [ -z ${cpio_file} ] && rm ${cpio_tfile} + fi + exit 0 +diff -rdup linux-2.6.22.1.old/usr/Makefile linux-2.6.22.1/usr/Makefile +--- linux-2.6.22.1.old/usr/Makefile 2007-08-21 16:32:19.000000000 +0200 ++++ linux-2.6.22.1/usr/Makefile 2007-08-21 16:46:22.000000000 +0200 +@@ -19,7 +19,7 @@ $(obj)/initramfs_data.o: $(obj)/initramf + + hostprogs-y := gen_init_cpio + initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh +-lzma_initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_lzma_initramfs_list.sh ++lzma_initramfs := LZMA=$(LZMA) $(CONFIG_SHELL) $(srctree)/scripts/gen_lzma_initramfs_list.sh + ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \ + $(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d) + ramfs-args := \ -- cgit v1.2.3