Add support to map the contents of a file

Add a package HW.File with a single procedure Map():

   procedure Map
     (Path     : in     String;
      Addr     : in     Word64;
      Len      : in     Natural;
      Readable : in     Boolean := False;
      Writable : in     Boolean := False;
      Map_Copy : in     Boolean := False;
      Success  :    out Boolean)
   with
      Pre => (Readable or Writable) and
             (if Map_Copy then Readable and not Writable);

If `Map_Copy` is `False`, it should map `Len` bytes from the start of
the file given by `Path` into the application's address space at `Addr`
using mmap(). If `Map_Copy` is `True`, anonymous memory should be map-
ped instead and be filled with a copy of the file's content using
read().

The current implementation is backed by C code to reduce dependencies
to external libraries (e.g. Florist is not packaged by a famous Linux
distro).

While we are at it, also add a configuration file for common POSIX
environments (configs/posix).

Change-Id: Ic10c35b35d3216dab6a5b2baba7ba619c885b346
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/18779
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Nico Huber 2017-03-04 13:57:09 +01:00 committed by Stefan Reinauer
parent e86fff93bd
commit f03ef4f2d4
9 changed files with 221 additions and 1 deletions

View File

@ -1,2 +1,2 @@
subdirs-y += ada common proof
subdirs-y += ada common proof c
subdirs-y += debug

View File

@ -5,3 +5,5 @@ hw-$(CONFIG_HWBASE_TIMER_CLOCK_GETTIME) += clock_gettime/hw-time-timer.adb
hw-$(CONFIG_HWBASE_TIMER_MUTIME) += $(muen-common-path)/musinfo/musinfo.ads
hw-$(CONFIG_HWBASE_TIMER_MUTIME) += $(muen-common-path)/muschedinfo/muschedinfo.ads
hw-$(CONFIG_HWBASE_TIMER_MUTIME) += mutime/hw-time-timer.adb
hw-$(CONFIG_HWBASE_POSIX_FILE) += posix/hw-file.adb

68
ada/posix/hw-file.adb Normal file
View File

@ -0,0 +1,68 @@
--
-- Copyright (C) 2017 Nico Huber <nico.h@gmx.de>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
with Interfaces.C;
with Interfaces.C.Strings;
with HW.Debug;
use Interfaces.C;
use Interfaces.C.Strings;
package body HW.File is
READ : constant := 16#01#;
WRITE : constant := 16#02#;
function c_map
(path : chars_ptr;
addr : Word64;
len : Word32;
mode : Word32;
copy : int)
return int;
pragma Import (C, c_map, "hw_file_map");
procedure Map
(Path : in String;
Addr : in Word64;
Len : in Natural;
Readable : in Boolean := False;
Writable : in Boolean := False;
Map_Copy : in Boolean := False;
Success : out Boolean)
is
use type HW.Word32;
cpath : chars_ptr := New_String (Path);
ret : constant int := c_map
(path => cpath,
addr => Addr,
len => Word32 (Len),
mode => (if Readable then READ else 0) or
(if Writable then WRITE else 0),
copy => (if Map_Copy then 1 else 0));
begin
pragma Warnings(GNAT, Off, """cpath"" modified*, but* never referenced",
Reason => "Free() demands to set it to null_ptr");
Free (cpath);
pragma Warnings(GNAT, On, """cpath"" modified*, but* never referenced");
Success := ret = 0;
pragma Debug (not Success, Debug.Put ("Mapping failed: "));
pragma Debug (not Success, Debug.Put_Int32 (Int32 (ret)));
pragma Debug (not Success, Debug.New_Line);
end Map;
end HW.File;

1
c/Makefile.inc Normal file
View File

@ -0,0 +1 @@
hw-$(CONFIG_HWBASE_POSIX_FILE) += hw-file.c

103
c/hw-file.c Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2017 Nico Huber <nico.h@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#define HW_FILE_READ 0x01
#define HW_FILE_WRITE 0x02
static int map_file(const char *const path,
const uint64_t addr,
const uint32_t len,
const uint32_t mode)
{
const int prot = (mode & HW_FILE_READ ? PROT_READ : 0) |
(mode & HW_FILE_WRITE ? PROT_WRITE : 0);
if (mode & ~(HW_FILE_READ | HW_FILE_WRITE) ||
!(mode & (HW_FILE_READ | HW_FILE_WRITE)))
return EINVAL;
const int fd = open(path, mode & HW_FILE_WRITE ? O_RDWR : O_RDONLY);
if (fd < 0)
return errno;
void *const mapped = mmap((void *)(uintptr_t)addr, len, prot,
MAP_SHARED | MAP_FIXED, fd, (off_t)0);
close(fd);
if (mapped == MAP_FAILED)
return errno;
return 0;
}
static int map_fill_from_file(const char *const path,
const uint64_t addr,
const uint32_t len,
const uint32_t mode)
{
uint32_t xferred;
ssize_t read_ret;
if (mode != HW_FILE_READ)
return EINVAL;
void *const mapped = mmap((void *)(uintptr_t)addr, len,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
-1, (off_t)0);
if (mapped == MAP_FAILED)
return errno;
const int fd = open(path, O_RDONLY);
if (fd < 0)
goto _munmap;
xferred = 0;
do {
read_ret = read(fd, (uint8_t *)mapped + xferred, len - xferred);
if (read_ret > 0)
xferred += read_ret;
} while ((read_ret > 0 || (read_ret == -1 && errno == EINTR))
&& xferred < len);
close(fd);
if (xferred < len)
goto _munmap;
if (mprotect(mapped, len, PROT_READ))
goto _munmap;
return 0;
_munmap:
munmap(mapped, len);
return errno;
}
int hw_file_map(const char *const path,
const uint64_t addr,
const uint32_t len,
const uint32_t mode,
const int copy)
{
if (copy)
return map_fill_from_file(path, addr, len, mode);
else
return map_file(path, addr, len, mode);
}

View File

@ -9,3 +9,5 @@ hw-y += hw-sub_regs.ads
hw-y += hw-time.ads
hw-y += hw-time.adb
hw-y += hw-time-timer.ads
hw-$(CONFIG_HWBASE_POSIX_FILE) += hw-file.ads

36
common/hw-file.ads Normal file
View File

@ -0,0 +1,36 @@
--
-- Copyright (C) 2017 Nico Huber <nico.h@gmx.de>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
package HW.File is
-- Map a file's content into our address space
--
-- If `Map_Copy` is `False`, `Len` bytes from the start of the file
-- given by `Path` shall be mapped into the application's address
-- space at `Addr` using mmap(). If `Map_Copy` is `True`, anonymous
-- memory should be mapped instead and be filled with a copy of the
-- file's content using read().
procedure Map
(Path : in String;
Addr : in Word64;
Len : in Natural;
Readable : in Boolean := False;
Writable : in Boolean := False;
Map_Copy : in Boolean := False;
Success : out Boolean)
with
Pre => (Readable or Writable) and
(if Map_Copy then Readable and not Writable);
end HW.File;

View File

@ -4,3 +4,4 @@ CONFIG_HWBASE_STATIC_MMIO = y
CONFIG_HWBASE_DYNAMIC_MMIO =
CONFIG_HWBASE_TIMER_CLOCK_GETTIME = y
CONFIG_HWBASE_TIMER_MUTIME =
CONFIG_HWBASE_POSIX_FILE =

7
configs/posix Normal file
View File

@ -0,0 +1,7 @@
CONFIG_HWBASE_DEBUG_NULL =
CONFIG_HWBASE_DEBUG_TEXT_IO = y
CONFIG_HWBASE_STATIC_MMIO =
CONFIG_HWBASE_DYNAMIC_MMIO = y
CONFIG_HWBASE_TIMER_CLOCK_GETTIME = y
CONFIG_HWBASE_TIMER_MUTIME =
CONFIG_HWBASE_POSIX_FILE = y