diff --git a/repos/base-fiasco/src/core/platform.cc b/repos/base-fiasco/src/core/platform.cc index 66652379a..2f7f1e180 100644 --- a/repos/base-fiasco/src/core/platform.cc +++ b/repos/base-fiasco/src/core/platform.cc @@ -321,7 +321,7 @@ void Platform::_setup_irq_alloc() { _irq_alloc.add_range(0, 0x10); } -void Platform::_setup_basics() +static Fiasco::l4_kernel_info_t *get_kip() { using namespace Fiasco; @@ -370,14 +370,22 @@ void Platform::_setup_basics() printf(" root "); printf(" esp: %08lx eip: %08lx\n", kip->root_esp, kip->root_eip); } + return kip; +} + +void Platform::_setup_basics() +{ + using namespace Fiasco; + + l4_kernel_info_t * kip = get_kip(); + /* add KIP as ROM module */ _kip_rom = Rom_module((addr_t)kip, L4_PAGESIZE, "l4v2_kip"); _rom_fs.insert(&_kip_rom); /* update multi-boot info pointer from KIP */ - void *mb_info_ptr = (void *)kip->user_ptr; - _mb_info = Multiboot_info(mb_info_ptr); - if (verbose) printf("MBI @ %p\n", mb_info_ptr); + addr_t mb_info_addr = kip->user_ptr; + if (verbose) printf("MBI @ 0x%lx\n", mb_info_addr); /* parse memory descriptors - look for virtual memory configuration */ /* XXX we support only one VM region (here and also inside RM) */ @@ -412,8 +420,8 @@ void Platform::_setup_basics() /* remove KIP and MBI area from region and IO_MEM allocator */ remove_region(Region((addr_t)kip, (addr_t)kip + L4_PAGESIZE), _region_alloc); remove_region(Region((addr_t)kip, (addr_t)kip + L4_PAGESIZE), _io_mem_alloc); - remove_region(Region((addr_t)mb_info_ptr, (addr_t)mb_info_ptr + _mb_info.size()), _region_alloc); - remove_region(Region((addr_t)mb_info_ptr, (addr_t)mb_info_ptr + _mb_info.size()), _io_mem_alloc); + remove_region(Region(mb_info_addr, mb_info_addr + _mb_info.size()), _region_alloc); + remove_region(Region(mb_info_addr, mb_info_addr + _mb_info.size()), _io_mem_alloc); /* remove core program image memory from region and IO_MEM allocator */ addr_t img_start = (addr_t) &_prog_img_beg; @@ -459,7 +467,8 @@ void Platform::_setup_rom() Platform::Platform() : _ram_alloc(nullptr), _io_mem_alloc(core_mem_alloc()), _io_port_alloc(core_mem_alloc()), _irq_alloc(core_mem_alloc()), - _region_alloc(core_mem_alloc()) + _region_alloc(core_mem_alloc()), + _mb_info(get_kip()->user_ptr, true) { /* * We must be single-threaded at this stage and so this is safe. diff --git a/repos/base-foc/src/core/platform.cc b/repos/base-foc/src/core/platform.cc index a37f4d7bd..59fb31ed6 100644 --- a/repos/base-foc/src/core/platform.cc +++ b/repos/base-foc/src/core/platform.cc @@ -282,6 +282,10 @@ static Fiasco::l4_kernel_info_t *sigma0_map_kip() return 0; l4_addr_t ret = l4_trunc_page(l4_utcb_mr()->mr[0]); + + if (!ret) + panic("kip mapping failed"); + return (l4_kernel_info_t*) ret; } @@ -352,8 +356,6 @@ void Platform::_setup_basics() using namespace Fiasco; kip = sigma0_map_kip(); - if (!kip) - panic("kip mapping failed"); if (kip->magic != L4_KERNEL_INFO_MAGIC) panic("Sigma0 mapped something but not the KIP"); @@ -373,9 +375,8 @@ void Platform::_setup_basics() _rom_fs.insert(&_kip_rom); /* update multi-boot info pointer from KIP */ - void *mb_info_ptr = (void *)kip->user_ptr; - _mb_info = Multiboot_info(mb_info_ptr); - if (verbose) printf("MBI @ %p\n", mb_info_ptr); + addr_t mb_info_addr = kip->user_ptr; + if (verbose) printf("MBI @ %lx\n", mb_info_addr); /* parse memory descriptors - look for virtual memory configuration */ /* XXX we support only one VM region (here and also inside RM) */ @@ -413,8 +414,8 @@ void Platform::_setup_basics() /* remove KIP and MBI area from region and IO_MEM allocator */ remove_region(Region((addr_t)kip, (addr_t)kip + L4_PAGESIZE), _region_alloc); remove_region(Region((addr_t)kip, (addr_t)kip + L4_PAGESIZE), _io_mem_alloc); - remove_region(Region((addr_t)mb_info_ptr, (addr_t)mb_info_ptr + _mb_info.size()), _region_alloc); - remove_region(Region((addr_t)mb_info_ptr, (addr_t)mb_info_ptr + _mb_info.size()), _io_mem_alloc); + remove_region(Region(mb_info_addr, mb_info_addr + _mb_info.size()), _region_alloc); + remove_region(Region(mb_info_addr, mb_info_addr + _mb_info.size()), _io_mem_alloc); /* remove core program image memory from region and IO_MEM allocator */ addr_t img_start = (addr_t) &_prog_img_beg; @@ -468,6 +469,7 @@ Platform::Platform() : _ram_alloc(nullptr), _io_mem_alloc(core_mem_alloc()), _io_port_alloc(core_mem_alloc()), _irq_alloc(core_mem_alloc()), _region_alloc(core_mem_alloc()), _cap_id_alloc(core_mem_alloc()), + _mb_info(sigma0_map_kip()->user_ptr, true), _sigma0(cap_map()->insert(_cap_id_alloc.alloc(), Fiasco::L4_BASE_PAGER_CAP)) { /* diff --git a/repos/base-pistachio/src/core/multiboot_info.cc b/repos/base-pistachio/src/core/multiboot_info.cc index 09bf8e54c..a30bcb382 100644 --- a/repos/base-pistachio/src/core/multiboot_info.cc +++ b/repos/base-pistachio/src/core/multiboot_info.cc @@ -35,12 +35,6 @@ static const bool verbose = false; #define VPRINTF(fmt...) if (verbose) printf(fmt); else {} -void Multiboot_info::print_debug() -{ - printf("TODO Multiboot_info does not support print_debug."); -} - - unsigned Multiboot_info::num_modules() { using namespace Pistachio; @@ -48,8 +42,8 @@ unsigned Multiboot_info::num_modules() unsigned int i = 0; L4_Word_t entries; L4_BootRec_t *rec; - for (entries = L4_BootInfo_Entries(_mb_info), - rec = L4_BootInfo_FirstEntry(_mb_info); + for (entries = L4_BootInfo_Entries(reinterpret_cast(Mmio::base)), + rec = L4_BootInfo_FirstEntry(reinterpret_cast(Mmio::base)); entries > 0; entries--, rec = L4_Next(rec)) { @@ -71,8 +65,8 @@ Rom_module Multiboot_info::get_module(unsigned num) unsigned int i = 0; L4_Word_t entries; L4_BootRec_t *rec; - for (entries = L4_BootInfo_Entries(_mb_info), - rec = L4_BootInfo_FirstEntry(_mb_info); + for (entries = L4_BootInfo_Entries(reinterpret_cast(Mmio::base)), + rec = L4_BootInfo_FirstEntry(reinterpret_cast(Mmio::base)); entries > 0; entries--, rec = L4_Next(rec)) { @@ -116,47 +110,3 @@ Rom_module Multiboot_info::get_module(unsigned num) Rom_module ret = Rom_module(start, size, name); return ret; } - - -bool Multiboot_info::check_module(unsigned num, addr_t *start, addr_t *end) -{ - panic("TODO Who calls check_module?"); - return false; -} - - -Multiboot_info::Multiboot_info(void *mb_info) -: _mb_info(mb_info) -{ - using namespace Pistachio; - - if (!L4_BootInfo_Valid(mb_info)) - panic("Invalid BootInfo."); - - /* some debug info, can probably be removed */ - unsigned int i; - L4_Word_t entries; - L4_BootRec_t *rec; - for (entries = L4_BootInfo_Entries(mb_info), - rec = L4_BootInfo_FirstEntry(mb_info), - i = 0; - entries > 0; - entries--, i++, rec = L4_Next(rec)) { - - VPRINTF("Entry[%d]\n", i); - switch (L4_Type(rec)) { - case L4_BootInfo_Module: - VPRINTF(" Type: Module\n"); - VPRINTF(" Cmd : %s\n", L4_Module_Cmdline(rec)); - break; - case L4_BootInfo_SimpleExec: - VPRINTF(" Type: SimpleExec (ignored)\n"); - VPRINTF(" Cmd : %s\n", L4_SimpleExec_Cmdline(rec)); - break; - case L4_BootInfo_EFITables: - VPRINTF(" Type: EFITables (ignored)\n"); break; - case L4_BootInfo_Multiboot: - VPRINTF(" Type: Multiboot (ignored)\n"); break; - } - } -} diff --git a/repos/base-pistachio/src/core/platform.cc b/repos/base-pistachio/src/core/platform.cc index 43e06e1da..b11650042 100644 --- a/repos/base-pistachio/src/core/platform.cc +++ b/repos/base-pistachio/src/core/platform.cc @@ -466,15 +466,23 @@ void Platform::_setup_preemption() } -void Platform::_setup_basics() +static Pistachio::L4_KernelInterfacePage_t *init_kip() { using namespace Pistachio; /* completely map program image */ addr_t beg = trunc_page((addr_t)&_prog_img_beg); addr_t end = round_page((addr_t)&_prog_img_end); - for ( ; beg < end; beg += get_page_size()) - L4_Sigma0_GetPage(get_sigma0(), L4_Fpage(beg, get_page_size())); + for ( ; beg < end; beg += Pistachio::get_page_size()) + L4_Sigma0_GetPage(get_sigma0(), L4_Fpage(beg, Pistachio::get_page_size())); + + return get_kip(); +} + + +void Platform::_setup_basics() +{ + using namespace Pistachio; /* store mapping base from received mapping */ L4_KernelInterfacePage_t *kip = get_kip(); @@ -515,7 +523,6 @@ void Platform::_setup_basics() /* done magic */ - _mb_info = Multiboot_info(mb_info_ptr); if (verbose) printf("MBI @ %p\n", mb_info_ptr); /* get UTCB memory */ @@ -627,7 +634,8 @@ Platform_pd *Platform::core_pd() Platform::Platform() : _ram_alloc(nullptr), _io_mem_alloc(core_mem_alloc()), _io_port_alloc(core_mem_alloc()), _irq_alloc(core_mem_alloc()), - _region_alloc(core_mem_alloc()) + _region_alloc(core_mem_alloc()), + _mb_info(init_kip()->BootInfo) { /* * We must be single-threaded at this stage and so this is safe. diff --git a/repos/base/src/core/include/multiboot.h b/repos/base/src/core/include/multiboot.h index c1edb7719..8d7cc29ae 100644 --- a/repos/base/src/core/include/multiboot.h +++ b/repos/base/src/core/include/multiboot.h @@ -1,11 +1,12 @@ -/** - * \brief GRUB multi-boot information handling +/* + * \brief Multiboot handling * \author Christian Helmuth + * \author Alexander Boettcher * \date 2006-05-09 */ /* - * Copyright (C) 2006-2013 Genode Labs GmbH + * Copyright (C) 2006-2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -14,56 +15,78 @@ #ifndef _CORE__INCLUDE__MULTIBOOT_H_ #define _CORE__INCLUDE__MULTIBOOT_H_ +/* base includes */ +#include + +/* core includes */ #include -#include +namespace Genode { class Multiboot_info; } -namespace Genode { +class Genode::Multiboot_info : Mmio +{ + private: - class Multiboot_info - { - private: + struct Flags : Register<0x00, 32> { + struct Mem_map : Bitfield<6, 1> { }; + }; + struct Mods_count : Register<0x14, 32> { }; + struct Mods_addr : Register<0x18, 32> { }; - /* Location of MBI in memory */ - void *_mb_info; + struct Mmap_length: Register<0x2c, 32> { }; + struct Mmap_addr : Register<0x30, 32> { }; - public: + public: - /** Standard constructor creates invalid object */ - Multiboot_info() : _mb_info(0) { } + Multiboot_info(addr_t mbi) : Mmio(mbi) { } + Multiboot_info(addr_t mbi, bool strip); - Multiboot_info(void *mb_info); + struct Mmap : Genode::Mmio { + struct Size : Register <0x00, 32> { }; + struct Addr : Register <0x04, 64> { }; + struct Length : Register <0x0c, 64> { }; + struct Type : Register <0x14, 8> { + struct Memory : Bitfield<0, 1> { }; + struct Reserved : Bitfield<1, 1> { }; + }; - /** - * Number of boot modules - */ - unsigned num_modules(); + Mmap(addr_t mmap = 0) : Mmio(mmap) { } + }; - /** - * Use boot module num - * - * The module is marked as invalid in MBI and cannot be gotten again - */ - Rom_module get_module(unsigned num); + struct Mods : Genode::Mmio { + struct Start : Register <0x00, 32> { }; + struct End : Register <0x04, 32> { }; + struct Cmdline : Register <0x08, 32> { }; + struct Padding : Register <0x0c, 32> { }; - /** - * Read module info - */ - bool check_module(unsigned num, addr_t *start, addr_t *end); + Mods(addr_t mods) : Mmio(mods) { } + }; - /** - * Debugging (may be removed later) - */ - void print_debug(); + private: - /** - * Check validity - */ - bool valid() { return _mb_info ? true : false; } + Mods _get_mod(unsigned i) { + Genode::addr_t mods_addr = read(); - /* Accessors */ - size_t size() const { return 0x1000; } - }; -} + enum { MODS_SIZE_OF = 16 }; + return Mods(mods_addr + i * MODS_SIZE_OF); + } + + public: + + /** + * Number of boot modules + */ + unsigned num_modules(); + + /* Accessors */ + size_t size() const { return 0x1000; } + + /** + * Use boot module num + * + * The module is marked as invalid in MBI and cannot be gotten again + */ + Rom_module get_module(unsigned num); +}; #endif /* _CORE__INCLUDE__MULTIBOOT_H_ */ diff --git a/repos/base/src/core/mb_info.h b/repos/base/src/core/mb_info.h deleted file mode 100644 index 96e6d6202..000000000 --- a/repos/base/src/core/mb_info.h +++ /dev/null @@ -1,175 +0,0 @@ -/** - * \brief Multiboot info structure as defined by GRUB - * \author Christian Helmuth - * \date 2006-05-09 - * - * This is a stripped down version. Original code in - * l4/pkg/l4util/include/ARCH-x86/mb_info.h. - */ - -/* - * Copyright (C) 2006-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _MB_INFO_H_ -#define _MB_INFO_H_ - -#include - -/** - * Multi-boot module - */ -typedef struct -{ - uint32_t mod_start; /* starting address of module in memory. */ - uint32_t mod_end; /* end address of module in memory. */ - uint32_t cmdline; /* module command line */ - uint32_t pad; /* padding to take it to 16 bytes */ -} mb_mod_t; - - -/** VBE controller information. */ -typedef struct -{ - uint8_t signature[4]; - uint16_t version; - uint32_t oem_string; - uint32_t capabilities; - uint32_t video_mode; - uint16_t total_memory; - uint16_t oem_software_rev; - uint32_t oem_vendor_name; - uint32_t oem_product_name; - uint32_t oem_product_rev; - uint8_t reserved[222]; - uint8_t oem_data[256]; -} __attribute__((packed)) mb_vbe_ctrl_t; - - -/** VBE mode information. */ -typedef struct -{ - /* all VESA versions */ - uint16_t mode_attributes; - uint8_t win_a_attributes; - uint8_t win_b_attributes; - uint16_t win_granularity; - uint16_t win_size; - uint16_t win_a_segment; - uint16_t win_b_segment; - uint32_t win_func; - uint16_t bytes_per_scanline; - - /* >= VESA version 1.2 */ - uint16_t x_resolution; - uint16_t y_resolution; - uint8_t x_char_size; - uint8_t y_char_size; - uint8_t number_of_planes; - uint8_t bits_per_pixel; - uint8_t number_of_banks; - uint8_t memory_model; - uint8_t bank_size; - uint8_t number_of_image_pages; - uint8_t reserved0; - - /* direct color */ - uint8_t red_mask_size; - uint8_t red_field_position; - uint8_t green_mask_size; - uint8_t green_field_position; - uint8_t blue_mask_size; - uint8_t blue_field_position; - uint8_t reserved_mask_size; - uint8_t reserved_field_position; - uint8_t direct_color_mode_info; - - /* >= VESA version 2.0 */ - uint32_t phys_base; - uint32_t reserved1; - uint16_t reversed2; - - /* >= VESA version 3.0 */ - uint16_t linear_bytes_per_scanline; - uint8_t banked_number_of_image_pages; - uint8_t linear_number_of_image_pages; - uint8_t linear_red_mask_size; - uint8_t linear_red_field_position; - uint8_t linear_green_mask_size; - uint8_t linear_green_field_position; - uint8_t linear_blue_mask_size; - uint8_t linear_blue_field_position; - uint8_t linear_reserved_mask_size; - uint8_t linear_reserved_field_position; - uint32_t max_pixel_clock; - - uint8_t reserved3[189]; -} __attribute__ ((packed)) mb_vbe_mode_t; - - -/** - * Multi-boot information - */ -typedef struct -{ - uint32_t flags; /* MultiBoot info version number */ - uint32_t mem_lower; /* available memory below 1MB */ - uint32_t mem_upper; /* available memory starting from 1MB [kB] */ - uint32_t boot_device; /* "root" partition */ - uint32_t cmdline; /* Kernel command line */ - uint32_t mods_count; /* number of modules */ - uint32_t mods_addr; /* module list */ - - union - { - struct - { - /* (a.out) Kernel symbol table info */ - uint32_t tabsize; - uint32_t strsize; - uint32_t addr; - uint32_t pad; - } a; - - struct - { - /* (ELF) Kernel section header table */ - uint32_t num; - uint32_t size; - uint32_t addr; - uint32_t shndx; - } e; - } syms; - - uint32_t mmap_length; /* size of memory mapping buffer */ - uint32_t mmap_addr; /* address of memory mapping buffer */ - uint32_t drives_length; /* size of drive info buffer */ - uint32_t drives_addr; /* address of driver info buffer */ - uint32_t config_table; /* ROM configuration table */ - uint32_t boot_loader_name; /* Boot Loader Name */ - uint32_t apm_table; /* APM table */ - uint32_t vbe_ctrl_info; /* VESA video contoller info */ - uint32_t vbe_mode_info; /* VESA video mode info */ - uint16_t vbe_mode; /* VESA video mode number */ - uint16_t vbe_interface_seg; /* VESA segment of prot BIOS interface */ - uint16_t vbe_interface_off; /* VESA offset of prot BIOS interface */ - uint16_t vbe_interface_len; /* VESA lenght of prot BIOS interface */ -} mb_info_t; - -/** - * Flags to be set in the 'flags' parameter above - */ - -/** is the command-line defined? */ -#define MB_CMDLINE 0x00000004 - -/** Is there video information? */ -#define MB_VIDEO_INFO 0x00000800 - -/** If we are multiboot-compliant, this value is present in the eax register */ -#define MB_VALID 0x2BADB002 - -#endif diff --git a/repos/base/src/core/multiboot_info.cc b/repos/base/src/core/multiboot_info.cc index 51e9f4c91..6c5eb2cf5 100644 --- a/repos/base/src/core/multiboot_info.cc +++ b/repos/base/src/core/multiboot_info.cc @@ -11,75 +11,23 @@ * under the terms of the GNU General Public License version 2. */ -#include #include -#include using namespace Genode; -namespace Mb_info { -#include "mb_info.h" -} - -static const bool verbose = false; - - -void Multiboot_info::print_debug() -{ - Mb_info::mb_info_t *mbi = (Mb_info::mb_info_t *)_mb_info; - - printf(" flags = %x %s\n", mbi->flags, - mbi->flags & MB_CMDLINE ? "CMDLINE" : ""); - printf(" mem_lower = %xu\n", mbi->mem_lower); - printf(" mem_upper = %xu\n", mbi->mem_upper); - printf(" boot_device = %x\n", mbi->boot_device); - printf(" mods_count = %d\n", mbi->mods_count); - printf(" mods_addr = %xu\n", mbi->mods_addr); - - unsigned i = 0; - Mb_info::mb_mod_t *mods = reinterpret_cast(mbi->mods_addr); - for (i = 0; i < mbi->mods_count; i++) - printf(" mod[%02d] [%xu,%xu) %s\n", i, - mods[i].mod_start, (mods[i].mod_end), - reinterpret_cast(mods[i].cmdline)); - - printf(" mmap_length = %x\n", mbi->mmap_length); - printf(" mmap_addr = %x\n", mbi->mmap_addr); - printf(" drives_length = %x\n", mbi->drives_length); - printf(" drives_addr = %x\n", mbi->drives_addr); - printf(" config_table = %x\n", mbi->config_table); - printf(" boot_loader_name = %x\n", mbi->boot_loader_name); - printf(" apm_table = %x\n", mbi->apm_table); - printf(" vbe_ctrl_info = %xu\n", mbi->vbe_ctrl_info); - printf(" vbe_mode_info = %xu\n", mbi->vbe_mode_info); - printf(" vbe_mode = %x\n", mbi->vbe_mode); - printf(" vbe_interface_seg = %x\n", mbi->vbe_interface_seg); - printf(" vbe_interface_off = %x\n", mbi->vbe_interface_off); - printf(" vbe_interface_len = %x\n", mbi->vbe_interface_len); -} - - -unsigned Multiboot_info::num_modules() -{ - Mb_info::mb_info_t *mbi = (Mb_info::mb_info_t *)_mb_info; - - return mbi->mods_count; -} +unsigned Multiboot_info::num_modules() { return read(); } Rom_module Multiboot_info::get_module(unsigned num) { - Mb_info::mb_info_t *mbi = reinterpret_cast(_mb_info); - Mb_info::mb_mod_t *mods = reinterpret_cast(mbi->mods_addr); + if (num >= num_modules()) return Rom_module(); - /* num exceeds number of modules */ - if (!(num < mbi->mods_count)) return Rom_module(); + Mods mods = _get_mod(num); + char *cmdline = reinterpret_cast(mods.read()); /* invalid module -- maybe returned earlier */ - if (!mods[num].cmdline) return Rom_module(); - - char *cmdline = reinterpret_cast(mods[num].cmdline); + if (!cmdline) return Rom_module(); /* skip everything in front of the base name of the file */ for (unsigned i = 0; cmdline[i]; i++) { @@ -94,49 +42,30 @@ Rom_module Multiboot_info::get_module(unsigned num) i = 0; } - Rom_module ret = Rom_module(mods[num].mod_start, - mods[num].mod_end - mods[num].mod_start, + Rom_module ret = Rom_module(mods.read(), + mods.read() - mods.read(), cmdline); /* mark module as invalid */ - mods[num].cmdline = 0; + mods.write(0); return ret; } -bool Multiboot_info::check_module(unsigned num, addr_t *start, addr_t *end) -{ - Mb_info::mb_info_t *mbi = reinterpret_cast(_mb_info); - Mb_info::mb_mod_t *mods = reinterpret_cast(mbi->mods_addr); - - /* num exceeds number of modules */ - if (!(num < mbi->mods_count)) return false; - - *start = mods[num].mod_start; - *end = mods[num].mod_end; - - return true; -} - /** * Constructor */ -Multiboot_info::Multiboot_info(void *mb_info) -: _mb_info(mb_info) +Multiboot_info::Multiboot_info(addr_t mbi, bool path_strip) +: Mmio(mbi) { - Mb_info::mb_info_t *mbi = reinterpret_cast(_mb_info); - Mb_info::mb_mod_t *mods = reinterpret_cast(mbi->mods_addr); + if (!path_strip) + return; /* strip path and arguments from module name */ - for (unsigned i = 0; i < mbi->mods_count; i++) { - char *cmdline = reinterpret_cast(mods[i].cmdline); - mods[i].cmdline = (addr_t)commandline_to_basename(cmdline); - } - - if (verbose) { - printf("Multi-boot info with %d modules @ %p.\n", - mbi->mods_count, _mb_info); - print_debug(); + for (unsigned i = 0; i < num_modules(); i++) { + Mods mods = _get_mod(i); + char *cmdline = reinterpret_cast(mods.read()); + mods.write((addr_t)commandline_to_basename(cmdline)); } }