Hi all, I have written a new RPC that is called from startup for shutting down the pc. It has been tested on QEMU and successfully powers off the machine causing the qemu window to disappear without manually closing it when you type "halt" as root and it goes through the proper shutdown sequence first.
In summary, the startup translator does its shutdown sequence, then calls the shutdown translator which calls into the ACPI translator to fetch the ACPI registers for shutdown and values to write, then writes the correct shutdown sequence to the IO. The reason for all the indirection is that the acpi tables can be reused for other purposes than just shutdown, and it makes sense to put the shutdown sequence as a separate RPC so that other machine specific shutdown sequences can be added later, not just for x86. Please see attached 3 patches for a complete working implementation. Thanks, Damien
>From 22758da0b147980c11dbd456f7a4e00404261212 Mon Sep 17 00:00:00 2001 From: Damien Zammit <dam...@zamaudio.com> Date: Tue, 6 Nov 2018 02:53:36 -0500 Subject: [PATCH 1/3] ACPI tables translator Exposes x86 ACPI tables as a netfs on a mount point --- Makefile | 3 +- acpi/Makefile | 35 ++++ acpi/acpi.c | 290 +++++++++++++++++++++++++ acpi/acpi.h | 74 +++++++ acpi/acpifs.c | 265 +++++++++++++++++++++++ acpi/acpifs.h | 147 +++++++++++++ acpi/func_files.c | 76 +++++++ acpi/func_files.h | 39 ++++ acpi/main.c | 100 +++++++++ acpi/ncache.c | 90 ++++++++ acpi/ncache.h | 32 +++ acpi/netfs_impl.c | 525 ++++++++++++++++++++++++++++++++++++++++++++++ acpi/netfs_impl.h | 43 ++++ acpi/options.c | 149 +++++++++++++ acpi/options.h | 51 +++++ hurd/hurd_types.h | 1 + 16 files changed, 1919 insertions(+), 1 deletion(-) create mode 100644 acpi/Makefile create mode 100644 acpi/acpi.c create mode 100644 acpi/acpi.h create mode 100644 acpi/acpifs.c create mode 100644 acpi/acpifs.h create mode 100644 acpi/func_files.c create mode 100644 acpi/func_files.h create mode 100644 acpi/main.c create mode 100644 acpi/ncache.c create mode 100644 acpi/ncache.h create mode 100644 acpi/netfs_impl.c create mode 100644 acpi/netfs_impl.h create mode 100644 acpi/options.c create mode 100644 acpi/options.h diff --git a/Makefile b/Makefile index 6288a157..aa4ddc5a 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,8 @@ prog-subdirs = auth proc exec term \ init \ devnode \ eth-multiplexer \ - pci-arbiter + pci-arbiter \ + acpi ifeq ($(HAVE_SUN_RPC),yes) prog-subdirs += nfs nfsd diff --git a/acpi/Makefile b/acpi/Makefile new file mode 100644 index 00000000..b3b7407b --- /dev/null +++ b/acpi/Makefile @@ -0,0 +1,35 @@ +# Copyright (C) 2018 Free Software Foundation, Inc. +# +# This file is part of the GNU Hurd. +# +# The GNU Hurd is free software; you can redistribute 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. +# +# The GNU Hurd is distributed in the hope that it will be useful, but +# WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. + +dir = acpi +makemode = server + +PORTDIR = $(srcdir)/port + +SRCS = main.c netfs_impl.c acpi.c \ + acpifs.c ncache.c options.c func_files.c +MIGSRCS = +OBJS = $(patsubst %.S,%.o,$(patsubst %.c,%.o, $(SRCS) $(MIGSRCS))) + +HURDLIBS= fshelp ports shouldbeinlibc netfs +LDLIBS = -lpthread + +target = acpi + +include ../Makeconf + +CFLAGS += -I$(PORTDIR)/include diff --git a/acpi/acpi.c b/acpi/acpi.c new file mode 100644 index 00000000..63066aaf --- /dev/null +++ b/acpi/acpi.c @@ -0,0 +1,290 @@ +/* + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +#include <sys/mman.h> +#include <sys/io.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> + +#include "acpi.h" + +int +mmap_phys_acpi_header(uintptr_t base_addr, struct acpi_header **ptr_to_header, + void **virt_addr, int fd) +{ + /* The memory mapping must be done aligned to page size + * but we have a known physical address we want to inspect, + * therefore we must compute offsets. + */ + uintptr_t pa_acpi = base_addr & ~(sysconf(_SC_PAGE_SIZE) - 1); + uintptr_t pa_start = base_addr - pa_acpi; + + /* Map the ACPI table at the nearest page (rounded down) */ + *virt_addr = 0; + *virt_addr = mmap(NULL, ESCD_SIZE, PROT_READ, MAP_SHARED | MAP_FIXED, + fd, (off_t) pa_acpi); + + if (*virt_addr == MAP_FAILED) + return errno; + + /* Fabricate a pointer to our magic address */ + *ptr_to_header = (struct acpi_header *)(*virt_addr + pa_start); + + return 0; +} + +int +acpi_get_num_tables(size_t *num_tables) +{ + int fd_mem; + int err; + void *virt_addr, *virt_addr2; + bool found = false; + struct rsdp_descr2 rsdp = { 0 }; + uintptr_t sdt_base = (uintptr_t)0; + bool is_64bit = false; + unsigned char *buf; + struct acpi_header *root_sdt; + struct acpi_header *next; + + if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) + return EPERM; + + virt_addr = mmap(NULL, ESCD_SIZE, PROT_READ, + MAP_SHARED | MAP_FIXED, fd_mem, ESCD); + if (virt_addr == MAP_FAILED) + return errno; + + buf = (unsigned char *)virt_addr; + found = false; + + /* RSDP magic string is 16 byte aligned */ + for (int i = 0; i < ESCD_SIZE; i += 16) + { + if (!memcmp(&buf[i], RSDP_MAGIC, 8)) { + rsdp = *((struct rsdp_descr2 *)(&buf[i])); + found = true; + break; + } + } + + if (!found) { + munmap(virt_addr, ESCD_SIZE); + return ENODEV; + } + + if (rsdp.v1.revision == 0) { + // ACPI 1.0 + sdt_base = rsdp.v1.rsdt_addr; + is_64bit = false; + } else if (rsdp.v1.revision == 2) { + // ACPI >= 2.0 + sdt_base = rsdp.xsdt_addr; + is_64bit = true; + } else { + munmap(virt_addr, ESCD_SIZE); + return ENODEV; + } + + munmap(virt_addr, ESCD_SIZE); + + /* Now we have the sdt_base address and knowledge of 32/64 bit ACPI */ + + err = mmap_phys_acpi_header(sdt_base, &root_sdt, &virt_addr, fd_mem); + if (err) { + munmap(virt_addr, ESCD_SIZE); + return err; + } + + /* Get total tables */ + uint32_t ntables; + uint8_t sz_ptr; + sz_ptr = is_64bit ? 8 : 4; + ntables = (root_sdt->length - sizeof(*root_sdt)) / sz_ptr; + + /* Get pointer to first ACPI table */ + uintptr_t acpi_ptr = (uintptr_t)root_sdt + sizeof(*root_sdt); + + /* Get number of readable tables */ + *num_tables = 0; + for (int i = 0; i < ntables; i++) + { + uintptr_t acpi_ptr32 = (uintptr_t)*((uint32_t *)(acpi_ptr + i*sz_ptr)); + uintptr_t acpi_ptr64 = (uintptr_t)*((uint64_t *)(acpi_ptr + i*sz_ptr)); + if (is_64bit) { + err = mmap_phys_acpi_header(acpi_ptr64, &next, &virt_addr2, fd_mem); + } else { + err = mmap_phys_acpi_header(acpi_ptr32, &next, &virt_addr2, fd_mem); + } + + char name[5] = { 0 }; + snprintf(name, 5, "%s", &next->signature[0]); + if (next->signature[0] == '\0' || next->length == 0) { + munmap(virt_addr2, ESCD_SIZE); + continue; + } + *num_tables += 1; + munmap(virt_addr2, ESCD_SIZE); + } + + munmap(virt_addr, ESCD_SIZE); + + return 0; +} + +int +acpi_get_tables(struct acpi_table **tables) +{ + int err; + int fd_mem; + void *virt_addr, *virt_addr2; + uint32_t phys_addr = ESCD; + bool found = false; + struct rsdp_descr2 rsdp = { 0 }; + uintptr_t sdt_base = (uintptr_t)0; + bool is_64bit = false; + unsigned char *buf; + struct acpi_header *root_sdt; + struct acpi_header *next; + size_t ntables_actual; + int cur_tab = 0; + + err = acpi_get_num_tables(&ntables_actual); + if (err) + return err; + + *tables = malloc(ntables_actual * sizeof(**tables)); + if (!*tables) + return ENOMEM; + + if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) + return EPERM; + + virt_addr = mmap(NULL, ESCD_SIZE, PROT_READ, MAP_SHARED | MAP_FIXED, + fd_mem, (off_t) phys_addr); + + if (virt_addr == MAP_FAILED) + return errno; + + buf = (unsigned char *)virt_addr; + found = false; + + /* RSDP magic string is 16 byte aligned */ + for (int i = 0; i < ESCD_SIZE; i += 16) + { + if (!memcmp(&buf[i], RSDP_MAGIC, 8)) { + rsdp = *((struct rsdp_descr2 *)(&buf[i])); + found = true; + break; + } + } + + if (!found) { + munmap(virt_addr, ESCD_SIZE); + return ENODEV; + } + + if (rsdp.v1.revision == 0) { + // ACPI 1.0 + sdt_base = rsdp.v1.rsdt_addr; + is_64bit = false; + } else if (rsdp.v1.revision == 2) { + // ACPI >= 2.0 + sdt_base = rsdp.xsdt_addr; + is_64bit = true; + } else { + munmap(virt_addr, ESCD_SIZE); + return ENODEV; + } + + munmap(virt_addr, ESCD_SIZE); + + /* Now we have the sdt_base address and knowledge of 32/64 bit ACPI */ + + err = mmap_phys_acpi_header(sdt_base, &root_sdt, &virt_addr, fd_mem); + if (err) { + munmap(virt_addr, ESCD_SIZE); + return err; + } + + /* Get total tables */ + uint32_t ntables; + uint8_t sz_ptr; + sz_ptr = is_64bit ? 8 : 4; + ntables = (root_sdt->length - sizeof(*root_sdt)) / sz_ptr; + + /* Get pointer to first ACPI table */ + uintptr_t acpi_ptr = (uintptr_t)root_sdt + sizeof(*root_sdt); + + /* Get all tables and data */ + for (int i = 0; i < ntables; i++) + { + uintptr_t acpi_ptr32 = (uintptr_t)*((uint32_t *)(acpi_ptr + i*sz_ptr)); + uintptr_t acpi_ptr64 = (uintptr_t)*((uint64_t *)(acpi_ptr + i*sz_ptr)); + if (is_64bit) { + err = mmap_phys_acpi_header(acpi_ptr64, &next, &virt_addr2, fd_mem); + if (err) { + munmap(virt_addr, ESCD_SIZE); + return err; + } + } else { + err = mmap_phys_acpi_header(acpi_ptr32, &next, &virt_addr2, fd_mem); + if (err) { + munmap(virt_addr, ESCD_SIZE); + return err; + } + } + + char name[5] = { 0 }; + snprintf(name, 5, "%s", &next->signature[0]); + if (next->signature[0] == '\0' || next->length == 0) { + munmap(virt_addr2, ESCD_SIZE); + continue; + } + uint32_t datalen = next->length - sizeof(*next); + void *data = (void *)((uintptr_t)next + sizeof(*next)); + + /* We now have a pointer to the data, + * its length and header. + */ + struct acpi_table *t = *tables + cur_tab; + memcpy(&t->h, next, sizeof(*next)); + t->datalen = 0; + t->data = malloc(datalen); + if (!t->data) { + munmap(virt_addr2, ESCD_SIZE); + munmap(virt_addr, ESCD_SIZE); + return ENOMEM; + } + t->datalen = datalen; + memcpy(t->data, data, datalen); + cur_tab++; + munmap(virt_addr2, ESCD_SIZE); + } + + munmap(virt_addr, ESCD_SIZE); + + return 0; +} diff --git a/acpi/acpi.h b/acpi/acpi.h new file mode 100644 index 00000000..7c21a442 --- /dev/null +++ b/acpi/acpi.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* ACPI tables basic structure */ + +#ifndef ACPI_H +#define ACPI_H + +#include <stdlib.h> +#include <inttypes.h> + +/* PnP Extended System Configuration Data (ESCD) memory region */ +#define ESCD 0xe0000U +#define RSDP_MAGIC (const unsigned char *)"RSD PTR " +#define ESCD_SIZE 0x20000U + +struct rsdp_descr +{ + uint8_t magic[8]; + uint8_t checksum; + uint8_t oem_id[6]; + uint8_t revision; + uint32_t rsdt_addr; +} __attribute__ ((packed)); + +struct rsdp_descr2 +{ + struct rsdp_descr v1; + uint32_t length; + uint64_t xsdt_addr; + uint8_t checksum; + uint8_t reserved[3]; +} __attribute__ ((packed)); + +struct acpi_header +{ + uint8_t signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + uint8_t oem_id[6]; + uint8_t oem_table_id[8]; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; +} __attribute__ ((packed)); + +struct acpi_table +{ + struct acpi_header h; + void *data; + size_t datalen; +} __attribute__ ((packed)); + +int acpi_get_num_tables(size_t *num_tables); +int acpi_get_tables(struct acpi_table **tables); + +#endif /* ACPI_H */ diff --git a/acpi/acpifs.c b/acpi/acpifs.c new file mode 100644 index 00000000..e779e0f9 --- /dev/null +++ b/acpi/acpifs.c @@ -0,0 +1,265 @@ +/* + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* ACPI Filesystem implementation */ + +#include <acpifs.h> + +#include <error.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <pthread.h> +#include <hurd/netfs.h> + +#include <ncache.h> +#include <func_files.h> + +static error_t +create_dir_entry (char *name, struct acpi_table *t, + struct acpifs_dirent *parent, io_statbuf_t stat, + struct node *node, struct acpifs_dirent *entry) +{ + uint16_t parent_num_entries; + + strncpy (entry->name, name, NAME_SIZE); + entry->acpitable = t; + entry->parent = parent; + entry->stat = stat; + entry->dir = 0; + entry->node = node; + + /* Update parent's child list */ + if (entry->parent) + { + if (!entry->parent->dir) + { + /* First child */ + entry->parent->dir = calloc (1, sizeof (struct acpifs_dir)); + if (!entry->parent->dir) + return ENOMEM; + } + + parent_num_entries = entry->parent->dir->num_entries++; + entry->parent->dir->entries = realloc (entry->parent->dir->entries, + entry->parent->dir->num_entries * + sizeof (struct acpifs_dirent *)); + if (!entry->parent->dir->entries) + return ENOMEM; + entry->parent->dir->entries[parent_num_entries] = entry; + } + + return 0; +} + +error_t +alloc_file_system (struct acpifs **fs) +{ + *fs = calloc (1, sizeof (struct acpifs)); + if (!*fs) + return ENOMEM; + + return 0; +} + +error_t +init_file_system (file_t underlying_node, struct acpifs *fs) +{ + error_t err; + struct node *np; + io_statbuf_t underlying_node_stat; + + /* Initialize status from underlying node. */ + err = io_stat (underlying_node, &underlying_node_stat); + if (err) + return err; + + np = netfs_make_node_alloc (sizeof (struct netnode)); + if (!np) + return ENOMEM; + np->nn_stat = underlying_node_stat; + np->nn_stat.st_fsid = getpid (); + np->nn_stat.st_mode = + S_IFDIR | S_IROOT | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | + S_IXOTH; + np->nn_translated = np->nn_stat.st_mode; + + /* Set times to now */ + fshelp_touch (&np->nn_stat, TOUCH_ATIME | TOUCH_MTIME | TOUCH_CTIME, + acpifs_maptime); + + fs->entries = calloc (1, sizeof (struct acpifs_dirent)); + if (!fs->entries) + { + free (fs->entries); + return ENOMEM; + } + + /* Create the root entry */ + err = create_dir_entry ("", 0, 0, np->nn_stat, np, fs->entries); + + fs->num_entries = 1; + fs->root = netfs_root_node = np; + fs->root->nn->ln = fs->entries; + pthread_mutex_init (&fs->node_cache_lock, 0); + + return 0; +} + +error_t +create_fs_tree (struct acpifs *fs) +{ + error_t err = 0; + int i; + size_t nentries, ntables = 0; + struct acpifs_dirent *e, *list, *parent; + struct stat e_stat; + char entry_name[NAME_SIZE]; + struct acpi_table *iter = NULL; + + /* Copy the root stat */ + e_stat = fs->entries->stat; + + err = acpi_get_num_tables(&ntables); + if (err) + return err; + + /* Allocate enough for / + "tables"/ + each table */ + nentries = ntables + 2; + + list = realloc (fs->entries, nentries * sizeof (struct acpifs_dirent)); + if (!list) { + if (fs->entries) + free(fs->entries); + return ENOMEM; + } + + e = list + 1; + parent = list; + e_stat.st_mode &= ~S_IROOT; /* Remove the root mode */ + memset (entry_name, 0, NAME_SIZE); + strncpy (entry_name, DIR_TABLES_NAME, NAME_SIZE); + + err = create_dir_entry (entry_name, 0, parent, e_stat, 0, e); + if (err) + return err; + + parent = e; + + /* Remove all permissions to others */ + e_stat.st_mode &= ~(S_IROTH | S_IWOTH | S_IXOTH); + + /* Change mode to a regular read-only file */ + e_stat.st_mode &= ~(S_IFDIR | S_IXUSR | S_IXGRP | S_IWUSR | S_IWGRP); + e_stat.st_mode |= S_IFREG; + + /* Get all ACPI tables */ + err = acpi_get_tables(&iter); + if (err) + return err; + + for (i = 0; i < ntables; i++, iter++) + { + e_stat.st_size = iter->datalen; + + // Create ACPI table entry + memset (entry_name, 0, NAME_SIZE); + + snprintf (entry_name, NAME_SIZE, "%c%c%c%c", + iter->h.signature[0], + iter->h.signature[1], + iter->h.signature[2], + iter->h.signature[3]); + e++; + err = create_dir_entry (entry_name, iter, parent, e_stat, 0, e); + if (err) + return err; + } + + /* The root node points to the first element of the entry list */ + fs->entries = list; + fs->num_entries = nentries; + fs->root->nn->ln = fs->entries; + + return err; +} + +error_t +entry_check_perms (struct iouser *user, struct acpifs_dirent *e, int flags) +{ + error_t err = 0; + + if (!err && (flags & O_READ)) + err = fshelp_access (&e->stat, S_IREAD, user); + if (!err && (flags & O_WRITE)) + err = fshelp_access (&e->stat, S_IWRITE, user); + if (!err && (flags & O_EXEC)) + err = fshelp_access (&e->stat, S_IEXEC, user); + + return err; +} + +/* Set default permissions to the given entry */ +static void +entry_default_perms (struct acpifs *fs, struct acpifs_dirent *e) +{ + /* Set default owner and group */ + UPDATE_OWNER (e, fs->root->nn->ln->stat.st_uid); + UPDATE_GROUP (e, fs->root->nn->ln->stat.st_gid); + + /* Update ctime */ + UPDATE_TIMES (e, TOUCH_CTIME); + + return; +} + +static void +entry_set_perms (struct acpifs *fs, struct acpifs_dirent *e) +{ + struct acpifs_perm *perm = &fs->perm; + if (perm->uid >= 0) + UPDATE_OWNER (e, perm->uid); + if (perm->gid >= 0) + UPDATE_GROUP (e, perm->gid); + + /* Update ctime */ + UPDATE_TIMES (e, TOUCH_CTIME); + + return; +} + +/* Update all entries' permissions */ +error_t +fs_set_permissions (struct acpifs *fs) +{ + int i; + struct acpifs_dirent *e; + + for (i = 0, e = fs->entries; i < fs->num_entries; i++, e++) + { + /* Restore default perms, as this may be called from fsysopts */ + entry_default_perms (fs, e); + + /* Set new permissions, if any */ + entry_set_perms (fs, e); + } + + return 0; +} diff --git a/acpi/acpifs.h b/acpi/acpifs.h new file mode 100644 index 00000000..2e9063cc --- /dev/null +++ b/acpi/acpifs.h @@ -0,0 +1,147 @@ +/* + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* ACPI Filesystem header */ + +#ifndef ACPIFS_H +#define ACPIFS_H + +#include <hurd/netfs.h> +#include <pthread.h> +#include <maptime.h> + +#include <netfs_impl.h> +#include <acpi.h> + +/* Size of a directory entry name */ +#ifndef NAME_SIZE +#define NAME_SIZE 8 +#endif + +/* Node cache defaults size */ +#define NODE_CACHE_MAX 16 + +/* + * User and group ids to grant permission to acpi + */ +struct acpifs_perm +{ + int32_t uid; + int32_t gid; +}; + +/* + * Directory entry. + * + * All directory entries are created on startup and used to generate the + * fs tree and create or retrieve libnetfs node objects. + * + * From libnetfs' point of view, these are the light nodes. + */ +struct acpifs_dirent +{ + char name[NAME_SIZE]; + struct acpifs_dirent *parent; + io_statbuf_t stat; + + /* + * We only need two kind of nodes: files and directories. + * When `dir' is null, this is a file; when not null, it's a directory. + */ + struct acpifs_dir *dir; + + /* Active node on this entry */ + struct node *node; + + /* ACPI table related to an entry */ + struct acpi_table *acpitable; +}; + +/* + * A directory, it only contains a list of directory entries + */ +struct acpifs_dir +{ + /* Number of directory entries */ + uint16_t num_entries; + + /* Array of directory entries */ + struct acpifs_dirent **entries; +}; + +/* A particular ACPI filesystem. */ +struct acpifs +{ + /* Root of filesystem. */ + struct node *root; + + /* A cache that holds a reference to recently used nodes. */ + struct node *node_cache_mru, *node_cache_lru; + size_t node_cache_len; /* Number of entries in it. */ + size_t node_cache_max; + pthread_mutex_t node_cache_lock; + + struct acpifs_perm perm; + + struct acpifs_dirent *entries; + size_t num_entries; +}; + +/* Main FS pointer */ +struct acpifs *fs; + +/* Global mapped time */ +volatile struct mapped_time_value *acpifs_maptime; + +/* Update entry and node times */ +#define UPDATE_TIMES(e, what) (\ + {\ + fshelp_touch (&e->stat, what, acpifs_maptime);\ + if(e->node)\ + fshelp_touch (&e->node->nn_stat, what, acpifs_maptime);\ + }\ +) + +/* Update entry and node owner */ +#define UPDATE_OWNER(e, uid) (\ + {\ + e->stat.st_uid = uid;\ + if(e->node)\ + e->node->nn_stat.st_uid = uid;\ + }\ +) + +/* Update entry and node group */ +#define UPDATE_GROUP(e, gid) (\ + {\ + e->stat.st_gid = gid;\ + if(e->node)\ + e->node->nn_stat.st_gid = gid;\ + }\ +) + +/* FS manipulation functions */ +error_t alloc_file_system (struct acpifs **fs); +error_t init_file_system (file_t underlying_node, struct acpifs *fs); +error_t create_fs_tree (struct acpifs *fs); +error_t fs_set_permissions (struct acpifs *fs); +error_t entry_check_perms (struct iouser *user, struct acpifs_dirent *e, + int flags); + +#endif /* ACPIFS_H */ diff --git a/acpi/func_files.c b/acpi/func_files.c new file mode 100644 index 00000000..371f989a --- /dev/null +++ b/acpi/func_files.c @@ -0,0 +1,76 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* + * Per-function files implementation. + * + * Implementation of all files repeated for each function. + */ + +#include <func_files.h> +#include <assert.h> + +/* Read an acpi table */ +error_t +io_acpi_table (struct acpi_table *t, off_t offset, size_t *len, void *data) +{ + error_t err; + size_t datalen; + + /* This should never happen */ + assert_backtrace (t != 0); + + datalen = t->datalen; + + /* Don't exceed the size of the acpi table */ + if (offset > datalen) + return EINVAL; + if ((offset + *len) > datalen) + *len = datalen - offset; + + memcpy (data, t->data + offset, *len); + + return err; +} + +/* Read from an acpi table file */ +error_t +io_acpi_file (struct acpifs_dirent *e, off_t offset, size_t *len, + void *data) +{ + size_t datalen; + struct acpi_table *table; + + /* This should never happen */ + assert_backtrace (e->acpitable != 0); + + /* Get the table */ + table = e->acpitable; + + datalen = table->datalen; + /* Don't exceed the region size */ + if (offset > datalen) + return EINVAL; + if ((offset + *len) > datalen) + *len = datalen - offset; + + memcpy (data, table->data + offset, *len); + + return 0; +} diff --git a/acpi/func_files.h b/acpi/func_files.h new file mode 100644 index 00000000..90d92cc3 --- /dev/null +++ b/acpi/func_files.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* Per-function files header */ + +#ifndef FUNC_FILES_H +#define FUNC_FILES_H + +#include <acpifs.h> +#include <acpi.h> + +typedef int (*acpi_read_op_t) (struct acpi_table *t, void *data, + off_t offset, size_t *len); + +/* Tables */ +#define DIR_TABLES_NAME "tables" + +error_t io_read_table (struct acpi_table *t, struct acpifs_dirent *e, + off_t offset, size_t *len, void *data); +error_t io_acpi_file (struct acpifs_dirent *e, off_t offset, size_t *len, + void *data); + +#endif /* FUNC_FILES_H */ diff --git a/acpi/main.c b/acpi/main.c new file mode 100644 index 00000000..f675470c --- /dev/null +++ b/acpi/main.c @@ -0,0 +1,100 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* Translator initialization and demuxing */ + +#include <stdio.h> +#include <error.h> +#include <fcntl.h> +#include <version.h> +#include <argp.h> +#include <hurd/netfs.h> + +#include "libnetfs/io_S.h" +#include "libnetfs/fs_S.h" +#include "libports/notify_S.h" +#include "libnetfs/fsys_S.h" +#include "libports/interrupt_S.h" +#include "libnetfs/ifsock_S.h" +#include <acpifs.h> + +/* Libnetfs stuff */ +int netfs_maxsymlinks = 0; +char *netfs_server_name = "acpi"; +char *netfs_server_version = HURD_VERSION; + +int +netfs_demuxer (mach_msg_header_t * inp, mach_msg_header_t * outp) +{ + mig_routine_t routine; + + if ((routine = netfs_io_server_routine (inp)) || + (routine = netfs_fs_server_routine (inp)) || + (routine = ports_notify_server_routine (inp)) || + (routine = netfs_fsys_server_routine (inp)) || + (routine = ports_interrupt_server_routine (inp)) || + (routine = netfs_ifsock_server_routine (inp))) + { + (*routine) (inp, outp); + return TRUE; + } + else + return FALSE; +} + +int +main (int argc, char **argv) +{ + error_t err; + mach_port_t bootstrap; + + /* Parse options */ + alloc_file_system (&fs); + argp_parse (netfs_runtime_argp, argc, argv, 0, 0, 0); + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap == MACH_PORT_NULL) + error (1, 0, "must be started as a translator"); + + /* Initialize netfs and start the translator. */ + netfs_init (); + + err = maptime_map (0, 0, &acpifs_maptime); + if (err) + error (1, err, "mapping time"); + + /* Create the ACPI filesystem */ + err = init_file_system (netfs_startup (bootstrap, O_READ), fs); + if (err) + error (1, err, "creating the ACPI filesystem"); + + /* Create the filesystem tree */ + err = create_fs_tree (fs); + if (err) + error (1, err, "creating the ACPI filesystem tree"); + + /* Set permissions */ + err = fs_set_permissions (fs); + if (err) + error (1, err, "setting permissions"); + + netfs_server_loop (); /* Never returns. */ + + return 0; +} diff --git a/acpi/ncache.c b/acpi/ncache.c new file mode 100644 index 00000000..61bc6592 --- /dev/null +++ b/acpi/ncache.c @@ -0,0 +1,90 @@ +/* Node caching + + Copyright (C) 1997 Free Software Foundation, Inc. + Written by Miles Bader <address@hidden> + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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, USA. */ + +#include <ncache.h> + +#include <unistd.h> +#include <string.h> +#include <hurd/netfs.h> + +#include <acpifs.h> +#include <netfs_impl.h> + +/* Implementation of node caching functions */ + +/* Remove NN's node from its position in FS's node cache. */ +void +node_unlink (struct node *node, struct acpifs *fs) +{ + struct netnode *nn = node->nn; + if (nn->ncache_next) + nn->ncache_next->nn->ncache_prev = nn->ncache_prev; + if (nn->ncache_prev) + nn->ncache_prev->nn->ncache_next = nn->ncache_next; + if (fs->node_cache_mru == node) + fs->node_cache_mru = nn->ncache_next; + if (fs->node_cache_lru == node) + fs->node_cache_lru = nn->ncache_prev; + nn->ncache_next = 0; + nn->ncache_prev = 0; + fs->node_cache_len--; +} + +/* Add NODE to the recently-used-node cache, which adds a reference to + prevent it from going away. NODE should be locked. */ +void +node_cache (struct node *node) +{ + struct netnode *nn = node->nn; + + pthread_mutex_lock (&fs->node_cache_lock); + + if (fs->node_cache_max > 0 || fs->node_cache_len > 0) + { + if (fs->node_cache_mru != node) + { + if (nn->ncache_next || nn->ncache_prev) + /* Node is already in the cache. */ + node_unlink (node, fs); + else + /* Add a reference from the cache. */ + netfs_nref (node); + + nn->ncache_next = fs->node_cache_mru; + nn->ncache_prev = 0; + if (fs->node_cache_mru) + fs->node_cache_mru->nn->ncache_prev = node; + if (!fs->node_cache_lru) + fs->node_cache_lru = node; + fs->node_cache_mru = node; + fs->node_cache_len++; + } + + /* Forget the least used nodes. */ + while (fs->node_cache_len > fs->node_cache_max) + { + struct node *lru = fs->node_cache_lru; + node_unlink (lru, fs); + netfs_nrele (lru); + } + } + + pthread_mutex_unlock (&fs->node_cache_lock); +} diff --git a/acpi/ncache.h b/acpi/ncache.h new file mode 100644 index 00000000..b4fa430b --- /dev/null +++ b/acpi/ncache.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* Header for node caching functions */ + +#ifndef NCACHE_H +#define NCACHE_H + +#include <hurd/netfs.h> + +#include <acpifs.h> + +void node_cache (struct node *node); +void node_unlink (struct node *node, struct acpifs *fs); + +#endif /* NCACHE_H */ diff --git a/acpi/netfs_impl.c b/acpi/netfs_impl.c new file mode 100644 index 00000000..84f52c89 --- /dev/null +++ b/acpi/netfs_impl.c @@ -0,0 +1,525 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + Written by Miles Bader <address@hidden> + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* Libnetfs callbacks */ + +#include <netfs_impl.h> + +#include <stddef.h> +#include <stdlib.h> +#include <dirent.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <hurd/netfs.h> + +#include <acpifs.h> +#include <ncache.h> +#include <func_files.h> + +#define DIRENTS_CHUNK_SIZE (8*1024) +/* Returned directory entries are aligned to blocks this many bytes long. + * Must be a power of two. */ +#define DIRENT_ALIGN 4 +#define DIRENT_NAME_OFFS offsetof (struct dirent, d_name) + +/* Length is structure before the name + the name + '\0', all + * padded to a four-byte alignment. */ +#define DIRENT_LEN(name_len) \ + ((DIRENT_NAME_OFFS + (name_len) + 1 + (DIRENT_ALIGN - 1)) \ + & ~(DIRENT_ALIGN - 1)) + +/* Fetch a directory, as for netfs_get_dirents. */ +static error_t +get_dirents (struct acpifs_dirent *dir, + int first_entry, int max_entries, char **data, + mach_msg_type_number_t *data_len, + vm_size_t max_data_len, int *data_entries) +{ + struct acpifs_dirent *e; + error_t err = 0; + int i, count; + size_t size; + char *p; + + if (first_entry >= dir->dir->num_entries) + { + *data_len = 0; + *data_entries = 0; + return 0; + } + + if (max_entries < 0) + count = dir->dir->num_entries; + else + { + count = ((first_entry + max_entries) >= dir->dir->num_entries ? + dir->dir->num_entries : max_entries) - first_entry; + } + + size = + (count * DIRENTS_CHUNK_SIZE) > + max_data_len ? max_data_len : count * DIRENTS_CHUNK_SIZE; + + *data = mmap (0, size, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0); + err = ((void *) *data == (void *) -1) ? errno : 0; + if (err) + return err; + + p = *data; + for (i = 0; i < count; i++) + { + struct dirent hdr; + size_t name_len; + size_t sz; + int entry_type; + + e = dir->dir->entries[i + first_entry]; + name_len = strlen (e->name) + 1; + sz = DIRENT_LEN (name_len); + entry_type = IFTODT (e->stat.st_mode); + + hdr.d_namlen = name_len; + hdr.d_fileno = e->stat.st_ino; + hdr.d_reclen = sz; + hdr.d_type = entry_type; + + memcpy (p, &hdr, DIRENT_NAME_OFFS); + strncpy (p + DIRENT_NAME_OFFS, e->name, name_len); + p += sz; + } + + vm_address_t alloc_end = (vm_address_t) (*data + size); + vm_address_t real_end = round_page (p); + if (alloc_end > real_end) + munmap ((caddr_t) real_end, alloc_end - real_end); + *data_len = p - *data; + *data_entries = count; + + return err; +} + +static struct acpifs_dirent * +lookup (struct node *np, char *name) +{ + int i; + struct acpifs_dirent *ret = 0, *e; + + for (i = 0; i < np->nn->ln->dir->num_entries; i++) + { + e = np->nn->ln->dir->entries[i]; + + if (!strncmp (e->name, name, NAME_SIZE)) + { + ret = e; + break; + } + } + + return ret; +} + +static error_t +create_node (struct acpifs_dirent * e, struct node ** node) +{ + struct node *np; + struct netnode *nn; + + np = netfs_make_node_alloc (sizeof (struct netnode)); + if (!np) + return ENOMEM; + np->nn_stat = e->stat; + np->nn_translated = np->nn_stat.st_mode; + + nn = netfs_node_netnode (np); + memset (nn, 0, sizeof (struct netnode)); + nn->ln = e; + + *node = e->node = np; + + return 0; +} + +static void +destroy_node (struct node *node) +{ + if (node->nn->ln) + node->nn->ln->node = 0; + free (node); +} + +/* Attempt to create a file named NAME in DIR for USER with MODE. Set *NODE + to the new node upon return. On any error, clear *NODE. *NODE should be + locked on success; no matter what, unlock DIR before returning. */ +error_t +netfs_attempt_create_file (struct iouser * user, struct node * dir, + char *name, mode_t mode, struct node ** node) +{ + *node = 0; + pthread_mutex_unlock (&dir->lock); + return EOPNOTSUPP; +} + +/* Node NODE is being opened by USER, with FLAGS. NEWNODE is nonzero if we + just created this node. Return an error if we should not permit the open + to complete because of a permission restriction. */ +error_t +netfs_check_open_permissions (struct iouser * user, struct node * node, + int flags, int newnode) +{ + return entry_check_perms (user, node->nn->ln, flags); +} + +/* This should attempt a utimes call for the user specified by CRED on node + NODE, to change the atime to ATIME and the mtime to MTIME. */ +error_t +netfs_attempt_utimes (struct iouser * cred, struct node * node, + struct timespec * atime, struct timespec * mtime) +{ + return EOPNOTSUPP; +} + +/* Return the valid access types (bitwise OR of O_READ, O_WRITE, and O_EXEC) + in *TYPES for file NODE and user CRED. */ +error_t +netfs_report_access (struct iouser * cred, struct node * node, int *types) +{ + return EOPNOTSUPP; +} + +/* Trivial definitions. */ + +/* Make sure that NP->nn_stat is filled with current information. CRED + identifies the user responsible for the operation. */ +error_t +netfs_validate_stat (struct node * node, struct iouser * cred) +{ + /* Nothing to do here */ + return 0; +} + +/* This should sync the file NODE completely to disk, for the user CRED. If + WAIT is set, return only after sync is completely finished. */ +error_t +netfs_attempt_sync (struct iouser * cred, struct node * node, int wait) +{ + return EOPNOTSUPP; +} + +error_t +netfs_get_dirents (struct iouser * cred, struct node * dir, + int first_entry, int max_entries, char **data, + mach_msg_type_number_t * data_len, + vm_size_t max_data_len, int *data_entries) +{ + error_t err = 0; + + if (dir->nn->ln->dir) + { + err = get_dirents (dir->nn->ln, first_entry, max_entries, + data, data_len, max_entries, data_entries); + } + else + err = ENOTDIR; + + if (!err) + /* Update atime */ + UPDATE_TIMES (dir->nn->ln, TOUCH_ATIME); + + return err; +} + +/* Lookup NAME in DIR for USER; set *NODE to the found name upon return. If + the name was not found, then return ENOENT. On any error, clear *NODE. + (*NODE, if found, should be locked, this call should unlock DIR no matter + what.) */ +error_t +netfs_attempt_lookup (struct iouser *user, struct node *dir, + char *name, struct node **node) +{ + error_t err = 0; + struct acpifs_dirent *entry; + + if (*name == '\0' || strcmp (name, ".") == 0) + /* Current directory -- just add an additional reference to DIR's node + and return it. */ + { + netfs_nref (dir); + *node = dir; + return 0; + } + else if (strcmp (name, "..") == 0) + /* Parent directory. */ + { + if (dir->nn->ln->parent) + { + *node = dir->nn->ln->parent->node; + pthread_mutex_lock (&(*node)->lock); + netfs_nref (*node); + } + else + { + err = ENOENT; /* No .. */ + *node = 0; + } + + pthread_mutex_unlock (&dir->lock); + + return err; + } + + /* `name' is not . nor .. */ + if (dir->nn->ln->dir) + { + /* `dir' is a directory */ + + /* Check dir permissions */ + err = entry_check_perms (user, dir->nn->ln, O_READ | O_EXEC); + if (!err) + { + entry = lookup (dir, name); + if (!entry) + { + err = ENOENT; + } + else + { + if (entry->node) + { + netfs_nref (entry->node); + } + else + { + /* + * No active node, create one. + * The new node is created with a reference. + */ + err = create_node (entry, node); + } + + if (!err) + { + *node = entry->node; + /* We have to unlock DIR's node before locking the child node + because the locking order is always child-parent. We know + the child node won't go away because we already hold the + additional reference to it. */ + pthread_mutex_unlock (&dir->lock); + pthread_mutex_lock (&(*node)->lock); + } + } + } + } + else + { + err = ENOTDIR; + } + + if (err) + { + *node = 0; + pthread_mutex_unlock (&dir->lock); + } + else + { + /* Update the node cache */ + node_cache (*node); + } + + return err; +} + +/* Delete NAME in DIR for USER. */ +error_t +netfs_attempt_unlink (struct iouser * user, struct node * dir, char *name) +{ + return EOPNOTSUPP; +} + +/* Note that in this one call, neither of the specific nodes are locked. */ +error_t +netfs_attempt_rename (struct iouser * user, struct node * fromdir, + char *fromname, struct node * todir, + char *toname, int excl) +{ + return EOPNOTSUPP; +} + +/* Attempt to create a new directory named NAME in DIR for USER with mode + MODE. */ +error_t +netfs_attempt_mkdir (struct iouser * user, struct node * dir, + char *name, mode_t mode) +{ + return EOPNOTSUPP; +} + +/* Attempt to remove directory named NAME in DIR for USER. */ +error_t +netfs_attempt_rmdir (struct iouser * user, struct node * dir, char *name) +{ + return EOPNOTSUPP; +} + +/* This should attempt a chmod call for the user specified by CRED on node + NODE, to change the owner to UID and the group to GID. */ +error_t +netfs_attempt_chown (struct iouser * cred, struct node * node, + uid_t uid, uid_t gid) +{ + return EOPNOTSUPP; +} + +/* This should attempt a chauthor call for the user specified by CRED on node + NODE, to change the author to AUTHOR. */ +error_t +netfs_attempt_chauthor (struct iouser * cred, struct node * node, + uid_t author) +{ + return EOPNOTSUPP; +} + +/* This should attempt a chmod call for the user specified by CRED on node + NODE, to change the mode to MODE. Unlike the normal Unix and Hurd meaning + of chmod, this function is also used to attempt to change files into other + types. If such a transition is attempted which is impossible, then return + EOPNOTSUPP. */ +error_t +netfs_attempt_chmod (struct iouser * cred, struct node * node, mode_t mode) +{ + return EOPNOTSUPP; +} + +/* Attempt to turn NODE (user CRED) into a symlink with target NAME. */ +error_t +netfs_attempt_mksymlink (struct iouser * cred, struct node * node, char *name) +{ + return EOPNOTSUPP; +} + +/* Attempt to turn NODE (user CRED) into a device. TYPE is either S_IFBLK or + S_IFCHR. */ +error_t +netfs_attempt_mkdev (struct iouser * cred, struct node * node, + mode_t type, dev_t indexes) +{ + return EOPNOTSUPP; +} + +/* This should attempt a chflags call for the user specified by CRED on node + NODE, to change the flags to FLAGS. */ +error_t +netfs_attempt_chflags (struct iouser * cred, struct node * node, int flags) +{ + return EOPNOTSUPP; +} + +/* This should attempt to set the size of the file NODE (for user CRED) to + SIZE bytes long. */ +error_t +netfs_attempt_set_size (struct iouser * cred, struct node * node, off_t size) +{ + /* Do nothing */ + return 0; +} + +/* This should attempt to fetch filesystem status information for the remote + filesystem, for the user CRED. */ +error_t +netfs_attempt_statfs (struct iouser * cred, struct node * node, + struct statfs * st) +{ + memset (st, 0, sizeof *st); + st->f_type = FSTYPE_ACPI; + st->f_fsid = getpid (); + return 0; +} + +/* This should sync the entire remote filesystem. If WAIT is set, return + only after sync is completely finished. */ +error_t +netfs_attempt_syncfs (struct iouser * cred, int wait) +{ + return 0; +} + +/* Create a link in DIR with name NAME to FILE for USER. Note that neither + DIR nor FILE are locked. If EXCL is set, do not delete the target, but + return EEXIST if NAME is already found in DIR. */ +error_t +netfs_attempt_link (struct iouser * user, struct node * dir, + struct node * file, char *name, int excl) +{ + return EOPNOTSUPP; +} + +/* Attempt to create an anonymous file related to DIR for USER with MODE. + Set *NODE to the returned file upon success. No matter what, unlock DIR. */ +error_t +netfs_attempt_mkfile (struct iouser * user, struct node * dir, + mode_t mode, struct node ** node) +{ + return EOPNOTSUPP; +} + +/* Read the contents of NODE (a symlink), for USER, into BUF. */ +error_t +netfs_attempt_readlink (struct iouser * user, struct node * node, char *buf) +{ + return EOPNOTSUPP; +} + +/* Read from the file NODE for user CRED starting at OFFSET and continuing for + up to *LEN bytes. Put the data at DATA. Set *LEN to the amount + successfully read upon return. */ +error_t +netfs_attempt_read (struct iouser * cred, struct node * node, + off_t offset, size_t * len, void *data) +{ + error_t err; + + if (!strncmp (node->nn->ln->name, DIR_TABLES_NAME, NAME_SIZE)) + return EOPNOTSUPP; + else + { + err = io_acpi_file (node->nn->ln, offset, len, data); + if (!err) + /* Update atime */ + UPDATE_TIMES (node->nn->ln, TOUCH_ATIME); + } + return err; +} + +/* Write to the file NODE for user CRED starting at OFSET and continuing for up + to *LEN bytes from DATA. Set *LEN to the amount seccessfully written upon + return. */ +error_t +netfs_attempt_write (struct iouser * cred, struct node * node, + off_t offset, size_t * len, void *data) +{ + return EOPNOTSUPP; +} + +/* Node NP is all done; free all its associated storage. */ +void +netfs_node_norefs (struct node *node) +{ + destroy_node (node); +} diff --git a/acpi/netfs_impl.h b/acpi/netfs_impl.h new file mode 100644 index 00000000..71717579 --- /dev/null +++ b/acpi/netfs_impl.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* Data types required to create a directory tree using libnetfs */ + +#ifndef NETFS_IMPL_H +#define NETFS_IMPL_H + +#include <hurd/netfs.h> + +#include <acpifs.h> + +/* + * A netnode has a 1:1 relation with a generic libnetfs node. Hence, it's only + * purpose is to extend a generic node to add the new attributes our problem + * requires. + */ +struct netnode +{ + /* Light node */ + struct acpifs_dirent *ln; + + /* Position in the node cache. */ + struct node *ncache_next, *ncache_prev; +}; + +#endif /* NETFS_IMPL_H */ diff --git a/acpi/options.c b/acpi/options.c new file mode 100644 index 00000000..8dbcd263 --- /dev/null +++ b/acpi/options.c @@ -0,0 +1,149 @@ +/* + Copyright (C) 2017 Free Software Foundation, Inc. + + Written by Miles Bader <address@hidden> + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* Fsysopts and command line option parsing */ + +#include <options.h> + +#include <stdlib.h> +#include <argp.h> +#include <argz.h> +#include <error.h> + +#include <acpifs.h> + +/* Option parser */ +static error_t +parse_opt (int opt, char *arg, struct argp_state *state) +{ + error_t err = 0; + struct parse_hook *h = state->hook; + + /* Return _ERR from this routine */ +#define RETURN(_err) \ + do { return _err; } while (0) + + /* Print a parsing error message and (if exiting is turned off) return the + error code ERR. */ +#define PERR(err, fmt, args...) \ + do { argp_error (state, fmt , ##args); RETURN (err); } while (0) + + /* Like PERR but for non-parsing errors. */ +#define FAIL(rerr, status, perr, fmt, args...) \ + do{ argp_failure (state, status, perr, fmt , ##args); RETURN (rerr); } while(0) + + if (!arg && state->next < state->argc && (*state->argv[state->next] != '-')) + { + arg = state->argv[state->next]; + state->next++; + } + + switch (opt) + { + case 'U': + h->perm.uid = atoi (arg); + break; + case 'G': + h->perm.gid = atoi (arg); + break; + + case ARGP_KEY_INIT: + /* Initialize our parsing state. */ + h = malloc (sizeof (struct parse_hook)); + if (!h) + FAIL (ENOMEM, 1, ENOMEM, "option parsing"); + + h->ncache_len = NODE_CACHE_MAX; + h->perm.uid = 0; + h->perm.gid = 0; + state->hook = h; + break; + + case ARGP_KEY_SUCCESS: + /* Set permissions to FS */ + fs->perm = h->perm; + + /* Set cache len */ + fs->node_cache_max = h->ncache_len; + + if (fs->root) + { + /* + * FS is already initialized, that means we've been called by fsysopts. + * Update permissions. + */ + + /* Don't accept new RPCs during this process */ + err = ports_inhibit_all_rpcs (); + if (err) + return err; + + err = fs_set_permissions (fs); + + /* Accept RPCs again */ + ports_resume_all_rpcs (); + } + + /* Free the hook */ + free (h); + + break; + + case ARGP_KEY_ERROR: + /* Parsing error occurred, free the permissions. */ + free (h); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return err; +} + +/* + * Print current permissions. Called by fsysopts. + */ +error_t +netfs_append_args (char **argz, size_t * argz_len) +{ + error_t err = 0; + struct acpifs_perm *p; + +#define ADD_OPT(fmt, args...) \ + do { char buf[100]; \ + if (! err) { \ + snprintf (buf, sizeof buf, fmt , ##args); \ + err = argz_add (argz, argz_len, buf); } } while (0) + + p = &fs->perm; + if (p->uid >= 0) + ADD_OPT ("--uid=%u", p->uid); + if (p->gid >= 0) + ADD_OPT ("--gid=%u", p->gid); + +#undef ADD_OPT + return err; +} + +struct argp acpi_argp = { options, parse_opt, 0, doc }; + +struct argp *netfs_runtime_argp = &acpi_argp; diff --git a/acpi/options.h b/acpi/options.h new file mode 100644 index 00000000..36ccc48b --- /dev/null +++ b/acpi/options.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT 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 the GNU Hurd. If not, see <<a rel="nofollow" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>. +*/ + +/* Command line option parsing */ + +#ifndef OPTIONS_H +#define OPTIONS_H + +#include <stdint.h> +#include <sys/types.h> +#include <argp.h> + +#include <acpifs.h> + +#define STR2(x) #x +#define STR(x) STR2(x) + +/* Used to hold data during argument parsing. */ +struct parse_hook +{ + struct acpifs_perm perm; + size_t ncache_len; +}; + +/* ACPI translator options. Used for both startup and runtime. */ +static const struct argp_option options[] = { + {0, 0, 0, 0, "These apply to the whole acpi tree:", 1}, + {"uid", 'U', "UID", 0, "User ID to give permissions to"}, + {"gid", 'G', "GID", 0, "Group ID to give permissions to"}, + {0} +}; + +static const char doc[] = "Permissions on acpi are currently global."; + +#endif // OPTIONS_H diff --git a/hurd/hurd_types.h b/hurd/hurd_types.h index eb06029b..a77a9e43 100644 --- a/hurd/hurd_types.h +++ b/hurd/hurd_types.h @@ -360,6 +360,7 @@ typedef const int *const_procinfo_t; #define FSTYPE_MEMFS 0x00000019 /* In-core filesystem */ #define FSTYPE_ISO9660 0x0000001a /* ISO9660 */ #define FSTYPE_PCI 0x0000001b /* PCI filesystem */ +#define FSTYPE_ACPI 0x0000001c /* ACPI filesystem */ /* Standard port assignments for file_exec_paths and exec_* */ enum -- 2.17.1
>From 2be6b5cab503e4358d60b4d97d1705cbf06bdf44 Mon Sep 17 00:00:00 2001 From: Damien Zammit <dam...@zamaudio.com> Date: Wed, 21 Nov 2018 04:17:33 -0500 Subject: [PATCH 2/3] Add shutdown RPC && ACPI specific disappear routine --- Makefile | 3 +- hurd/hurd_types.defs | 18 +++++ hurd/hurd_types.h | 1 + hurd/shutdown.defs | 33 +++++++++ shutdown/Makefile | 28 +++++++ shutdown/acpi_shutdown.c | 62 ++++++++++++++++ shutdown/acpi_shutdown.h | 18 +++++ shutdown/mig-mutate.h | 8 ++ shutdown/shutdown.c | 153 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 hurd/shutdown.defs create mode 100644 shutdown/Makefile create mode 100644 shutdown/acpi_shutdown.c create mode 100644 shutdown/acpi_shutdown.h create mode 100644 shutdown/mig-mutate.h create mode 100644 shutdown/shutdown.c diff --git a/Makefile b/Makefile index aa4ddc5a..f1d10c35 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,8 @@ prog-subdirs = auth proc exec term \ devnode \ eth-multiplexer \ pci-arbiter \ - acpi + acpi \ + shutdown ifeq ($(HAVE_SUN_RPC),yes) prog-subdirs += nfs nfsd diff --git a/hurd/hurd_types.defs b/hurd/hurd_types.defs index 0e9b990e..f0d1a351 100644 --- a/hurd/hurd_types.defs +++ b/hurd/hurd_types.defs @@ -314,6 +314,24 @@ destructor: PCI_DESTRUCTOR #endif ; +/* Shutdown */ +type shutdown_t = mach_port_copy_send_t +#ifdef SHUTDOWN_INTRAN +intran: SHUTDOWN_INTRAN +intranpayload: SHUTDOWN_INTRAN_PAYLOAD +#else +#ifdef HURD_DEFAULT_PAYLOAD_TO_PORT +intranpayload: shutdown_t HURD_DEFAULT_PAYLOAD_TO_PORT +#endif +#endif +#ifdef SHUTDOWN_OUTTRAN +outtran: SHUTDOWN_OUTTRAN +#endif +#ifdef SHUTDOWN_DESTRUCTOR +destructor: SHUTDOWN_DESTRUCTOR +#endif +; + type proccoll_t = mach_port_copy_send_t; type sreply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic diff --git a/hurd/hurd_types.h b/hurd/hurd_types.h index a77a9e43..bc6b618b 100644 --- a/hurd/hurd_types.h +++ b/hurd/hurd_types.h @@ -52,6 +52,7 @@ typedef mach_port_t interrupt_t; typedef mach_port_t proccoll_t; typedef mach_port_t ctty_t; typedef mach_port_t pci_t; +typedef mach_port_t shutdown_t; #include <errno.h> /* Defines `error_t'. */ diff --git a/hurd/shutdown.defs b/hurd/shutdown.defs new file mode 100644 index 00000000..b2ceb751 --- /dev/null +++ b/hurd/shutdown.defs @@ -0,0 +1,33 @@ +/* Definitions for shutdown + Copyright (C) 2018 Free Software Foundation, Inc. + +This file is part of the GNU Hurd. + +The GNU Hurd is free software; you can redistribute 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. + +The GNU Hurd is distributed in the hope that it will be useful, +but WITHOUT 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 the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +subsystem shutdown 40000; + +#include <hurd/hurd_types.defs> + +#ifdef SHUTDOWN_IMPORTS +SHUTDOWN_IMPORTS +#endif + +/* + * Shut down the computer + */ +routine shutdown ( + server : shutdown_t +); diff --git a/shutdown/Makefile b/shutdown/Makefile new file mode 100644 index 00000000..ced79702 --- /dev/null +++ b/shutdown/Makefile @@ -0,0 +1,28 @@ +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 2008 Free Software Foundation, Inc. +# This file is part of the GNU Hurd. +# +# The GNU Hurd is free software; you can redistribute 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. +# +# The GNU Hurd is distributed in the hope that it will be useful, +# but WITHOUT 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 the GNU Hurd; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +dir := shutdown +makemode := server + +SRCS = shutdown.c acpi_shutdown.c +HURDLIBS = ports shouldbeinlibc trivfs +target = shutdown +MIGSTUBS = shutdownServer.o +MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h +OBJS = $(SRCS:.c=.o) $(MIGSTUBS) + +include ../Makeconf diff --git a/shutdown/acpi_shutdown.c b/shutdown/acpi_shutdown.c new file mode 100644 index 00000000..af9b15d4 --- /dev/null +++ b/shutdown/acpi_shutdown.c @@ -0,0 +1,62 @@ +#include <stdio.h> +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> +#include <sys/io.h> +#include <mach.h> +#include "acpi_shutdown.h" + +void disappear_via_acpi(void) +{ + uint16_t i, pm1a_ctl, smi_cmd; + uint8_t regbuf[2], acpi_en; + FILE *facp; + + /* Open the ACPI FADT table */ + facp = fopen(SERVERS_ACPI_FADT, "r"); + if (!facp) + exit(errno); + + /* Grab value to write to SMI_CMD to enable ACPI */ + fseek(facp, SMI_EN_OFFSET, SEEK_SET); + fread(&acpi_en, 1, 1, facp); + + /* Grab SMI_CMD I/O port */ + fseek(facp, SMI_CMD_OFFSET, SEEK_SET); + fread(regbuf, 2, 1, facp); + smi_cmd = (uint16_t)regbuf[0] | + ((uint16_t)regbuf[1] << 8); + + /* Grab PM1a Control I/O port */ + fseek(facp, PM1A_CTL_OFFSET, SEEK_SET); + fread(regbuf, 2, 1, facp); + pm1a_ctl = (uint16_t)regbuf[0] | + ((uint16_t)regbuf[1] << 8); + + /* Close the ACPI FADT table */ + fclose(facp); + + /* Get I/O permissions */ + if (ioperm(0, 0xffff, 1)) { + mach_print("EPERM on ioperm()\n"); + return; + } + + /* Enable ACPI */ + outb(acpi_en, smi_cmd); + for (i = 0; i < 300; i++) + { + if ( (inw(pm1a_ctl) & SCI_EN) == SCI_EN) + break; + } + + /* Kill machine */ + + /* try sleep state 5 first */ + outw(SLP_TYP5 | SLP_EN, pm1a_ctl); + + /* if we reach here then above did not work */ + outw(SLP_TYP0 | SLP_EN, pm1a_ctl); + + /* Never reached */ +} diff --git a/shutdown/acpi_shutdown.h b/shutdown/acpi_shutdown.h new file mode 100644 index 00000000..50b7f1f6 --- /dev/null +++ b/shutdown/acpi_shutdown.h @@ -0,0 +1,18 @@ +#ifndef _ACPI_SHUTDOWN_H_ +#define _ACPI_SHUTDOWN_H_ + +#include <hurd/paths.h> + +#define _SERVERS_ACPI _SERVERS "/acpi/tables" +#define SERVERS_ACPI_FADT _SERVERS_ACPI "/FACP" +#define SLP_TYP0 (0x0 << 10) +#define SLP_TYP5 (0x5 << 10) +#define SLP_EN (0x1 << 13) +#define SCI_EN 1 +#define SMI_CMD_OFFSET 12 +#define SMI_EN_OFFSET 16 +#define PM1A_CTL_OFFSET 28 + +void disappear_via_acpi(void); + +#endif diff --git a/shutdown/mig-mutate.h b/shutdown/mig-mutate.h new file mode 100644 index 00000000..9eaf3db0 --- /dev/null +++ b/shutdown/mig-mutate.h @@ -0,0 +1,8 @@ +#define SHUTDOWN_INTRAN \ + trivfs_protid_t trivfs_begin_using_protid (shutdown_t) +#define SHUTDOWN_INTRAN_PAYLOAD \ + trivfs_protid_t trivfs_begin_using_protid_payload +#define SHUTDOWN_DESTRUCTOR \ + trivfs_end_using_protid (trivfs_protid_t) +#define SHUTDOWN_IMPORTS \ + import "libtrivfs/mig-decls.h"; diff --git a/shutdown/shutdown.c b/shutdown/shutdown.c new file mode 100644 index 00000000..413b5148 --- /dev/null +++ b/shutdown/shutdown.c @@ -0,0 +1,153 @@ +/* + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute 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. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT 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 the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This program is a translator that implements an RPC to halt the pc. + */ + +#include <argp.h> +#include <assert-backtrace.h> +#include <errno.h> +#include <error.h> +#include <stdlib.h> +#include <string.h> +#include <hurd.h> +#include <hurd/fs.h> +#include <hurd/ports.h> +#include <hurd/trivfs.h> +#include <hurd/paths.h> +#include <sys/file.h> +#include <version.h> + +#include "acpi_shutdown.h" +#include "shutdown_S.h" + +/* Port bucket we service requests on. */ +struct port_bucket *port_bucket; + +/* Trivfs hooks. */ +int trivfs_fstype = FSTYPE_MISC; +int trivfs_fsid = 0; +int trivfs_support_read = 0; +int trivfs_support_write = 0; +int trivfs_support_exec = 0; +int trivfs_allow_open = O_READ | O_WRITE; + +/* Our port classes. */ +struct port_class *trivfs_protid_class; +struct port_class *trivfs_control_class; + +kern_return_t +S_shutdown(trivfs_protid_t server) +{ + mach_print ("YAY RPC\n"); + disappear_via_acpi(); + return 0; +} + +static int +shutdown_demuxer (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + mig_routine_t routine; + if ((routine = shutdown_server_routine (inp)) || + (routine = NULL, trivfs_demuxer (inp, outp))) + { + if (routine) + (*routine) (inp, outp); + return TRUE; + } + else + return FALSE; +} + +void +trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) +{ +} + +error_t +trivfs_goaway (struct trivfs_control *fsys, int flags) +{ + int count; + + /* Stop new requests. */ + ports_inhibit_class_rpcs (trivfs_control_class); + ports_inhibit_class_rpcs (trivfs_protid_class); + + /* Are there any extant user ports for the /servers/password file? */ + count = ports_count_class (trivfs_protid_class); + if (count > 0 && !(flags & FSYS_GOAWAY_FORCE)) + { + /* We won't go away, so start things going again... */ + ports_enable_class (trivfs_protid_class); + ports_resume_class_rpcs (trivfs_control_class); + ports_resume_class_rpcs (trivfs_protid_class); + + return EBUSY; + } + + exit (0); +} + + +int +main (int argc, char *argv[]) +{ + error_t err; + mach_port_t bootstrap; + struct trivfs_control *fsys; + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap == MACH_PORT_NULL) + error (1, 0, "must be started as a translator"); + + err = trivfs_add_port_bucket (&port_bucket); + if (err) + error (1, 0, "error creating port bucket"); + + err = trivfs_add_control_port_class (&trivfs_control_class); + if (err) + error (1, 0, "error creating control port class"); + + err = trivfs_add_protid_port_class (&trivfs_protid_class); + if (err) + error (1, 0, "error creating protid port class"); + + /* Reply to our parent. */ + err = trivfs_startup (bootstrap, 0, + trivfs_control_class, port_bucket, + trivfs_protid_class, port_bucket, + &fsys); + mach_port_deallocate (mach_task_self (), bootstrap); + if (err) + error (3, err, "Contacting parent"); + + mach_print("Hello shutdown before ports loop\n"); + + /* Launch. */ + do + ports_manage_port_operations_multithread (port_bucket, shutdown_demuxer, + 2 * 60 * 1000, + 10 * 60 * 1000, + 0); + while (1); + + return 0; +} -- 2.17.1
>From b31590aca88a0a372cfd6f681aef353794d376ff Mon Sep 17 00:00:00 2001 From: Damien Zammit <dam...@zamaudio.com> Date: Sat, 24 Nov 2018 01:12:52 -0500 Subject: [PATCH 3/3] Add to startup relevant shutdown rpc call --- startup/Makefile | 1 + startup/startup.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/startup/Makefile b/startup/Makefile index bda3ffb3..8df0bd85 100644 --- a/startup/Makefile +++ b/startup/Makefile @@ -20,6 +20,7 @@ makemode := server SRCS = startup.c OBJS = $(SRCS:.c=.o) \ + shutdownUser.o \ startupServer.o notifyServer.o startup_replyUser.o msgServer.o \ startup_notifyUser.o fsysServer.o fsServer.o ioServer.o target = startup diff --git a/startup/startup.c b/startup/startup.c index 3679ebc9..3ca38e64 100644 --- a/startup/startup.c +++ b/startup/startup.c @@ -52,7 +52,9 @@ #include <argp.h> #include <pids.h> #include <idvec.h> +#include <stdlib.h> +#include "shutdown_U.h" #include "startup_notify_U.h" #include "startup_reply_U.h" #include "startup_S.h" @@ -74,6 +76,8 @@ const char *argp_program_version = STANDARD_HURD_VERSION (startup); #define OPT_KERNEL_TASK -1 +#define _SERVERS_SHUTDOWN _SERVERS "/shutdown" + static struct argp_option options[] = { @@ -173,6 +177,22 @@ getstring (char *buf, size_t bufsize) /** System shutdown **/ +/* Do an RPC to /servers/shutdown + * to call platform specific shutdown routine + */ +error_t +do_shutdown (void) +{ + shutdown_t pc; + + pc = file_name_lookup (_SERVERS_SHUTDOWN, O_READ, 0); + if (! MACH_PORT_VALID (pc)) + return errno; + + shutdown (pc); + return 0; +} + /* Reboot the microkernel. */ void reboot_mach (int flags) @@ -189,9 +209,13 @@ reboot_mach (int flags) fprintf (stderr, "%s: %sing Mach (flags %#x)...\n", program_invocation_short_name, BOOT (flags), flags); sleep (5); - err = host_reboot (host_priv, flags); - if (err) - error (1, err, "reboot"); + if (flags & RB_HALT) { + do_shutdown(); + } else { + err = host_reboot (host_priv, flags); + if (err) + error (1, err, "reboot"); + } for (;;) sleep (1); } } -- 2.17.1