<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Paging
//!
//! The `x86_64` architecture uses a four-level page table structure. The top
//! page table is called the Page Meta-Level 4 (PML4) table, followed by
//! the Page Directory Pointer Table (PDPT), Page Directory (PD) table, and
//! finally the bottom-level Page Table (PT).
use core::ops;
use core::ptr::Unique;

use alloc::FrameAllocator;
use memory::{Addr, PAGE_SIZE, PAddr, Page, PhysicalPage, VAddr, VirtualPage};
use params::InitParams;
use ::Mapper;

use self::table::*;
use self::temp::TempPage;

pub mod table;
pub mod tlb;
pub mod temp;
pub mod cr3;

pub struct ActivePageTable { pml4: ActivePML4 }

impl ops::Deref for ActivePageTable {
    type Target = ActivePML4;

    fn deref(&self) -> &ActivePML4 {
        &self.pml4
    }
}

impl ops::DerefMut for ActivePageTable {
    fn deref_mut(&mut self) -> &mut ActivePML4 {
        &mut self.pml4
    }
}

impl ActivePageTable {
    pub unsafe fn new() -> ActivePageTable {
        ActivePageTable { pml4: ActivePML4::new() }
    }

    /// Execute a closure with the recursive mapping temporarily changed to a
    /// new page table
    pub fn using<F>( &mut self
                   , table: &mut InactivePageTable
                   , temp_page: &mut temp::TempPage
                   , f: F)
    where F: FnOnce(&mut ActivePML4) {
        use self::tlb::flush_all;
        {
            // back up the current PML4 frame
            let prev_pml4_frame = unsafe {
                // this is safe to execute; we are in kernel mode
                cr3::current_pagetable_frame()
            };

            // remap the 511th PML4 entry (the recursive entry) to map to the // frame containing the new PML4.
            self.pml4_mut()[511]
                .set(table.pml4_frame, PRESENT | WRITABLE);
            unsafe {
                // this is safe to execute; we are in kernel mode
                flush_all();
            }

            // execute the closure
            f(self);

            // remap the 511th entry to point back to the original frame
            self.pml4_mut()[511]
                .set(prev_pml4_frame, PRESENT | WRITABLE);

            unsafe {
                // this is safe to execute; we are in kernel mode
                flush_all();
            }
        }
        temp_page.unmap(self);

    }

    /// Replace the current `ActivePageTable` with the given `InactivePageTable`
    ///
    /// # Arguments
    /// + `new_table`: the `InactivePageTable` that will replace the current
    ///                `ActivePageTable`.
    ///
    /// # Returns
    /// + the old active page table as an `InactivePageTable`.
    pub fn replace_with(&mut self, new_table: &mut InactivePageTable)
                       -> InactivePageTable {
        unsafe {
            // this is safe to execute; we are in kernel mode
            let old_pml4_frame = cr3::current_pagetable_frame();

            cr3::set_pagetable_frame(new_table.pml4_frame);

            InactivePageTable {
                pml4_frame: old_pml4_frame
            }
        }
    }

}

/// Struct representing the currently active PML4 instance.
///
/// The `ActivePML4` is a `Unique` reference to a PML4-level page table. It's
/// unique because, well, there can only be one active PML4 at a given time.
///
pub struct ActivePML4(Unique<Table<PML4Level>>);

/// The active PML4 table is the single point of entry for page mapping.
impl Mapper for ActivePML4 {
    type Flags = EntryFlags;

    fn translate(&self, vaddr: VAddr) -> Option<PAddr> {
        let offset = *vaddr % PAGE_SIZE as usize;
        self.translate_page(Page::containing(vaddr))
            .map(|frame| PAddr::from(frame.number + offset as u64) )
    }

    fn translate_page(&self, page: VirtualPage) -> Option<PhysicalPage> {
        let addr = page.base();
        let pdpt = self.pml4().next_table(addr);

        let huge_page = || {
            pdpt.and_then(|pdpt|
                pdpt[addr]
                    .do_huge(PDLevel::index_of(addr) + PTLevel::index_of(addr))
                    .or_else(|| {
                        pdpt.next_table(addr).and_then(|pd|
                            pd[addr].do_huge(PTLevel::index_of(addr))
                        )
                    })
                )
        };

        pdpt.and_then(|pdpt| pdpt.next_table(addr))
            .and_then(|pd| pd.next_table(addr))
            .and_then(|pt| pt[addr].get_frame())
            .or_else(huge_page)
    }

    /// Modifies the page tables so that `page` maps to `frame`.
    ///
    /// # Arguments
    /// + `page`: the virtual `Page` to map
    /// + `frame`: the physical `Frame` that `Page` should map to.
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map<A>( &mut self, page: VirtualPage, frame: PhysicalPage
             , flags: EntryFlags, alloc: &A)
    where A: FrameAllocator {
        // base virtual address of page being mapped
        let addr = page.base();

        // access or create all the lower-level page tables.
        let mut page_table
            // get the PML4
            = self.pml4_mut()
                  // get or create the PDPT table at the page's PML4 index
                  .create_next(addr, alloc)
                  // get or create the PD table at the page's PDPT index
                  .create_next(addr, alloc)
                  // get or create the page table at the  page's PD table index
                  .create_next(addr, alloc);
        trace!(" . . Map: Got page table");
        // check if the page at that index is not currently in use, as we
        // cannot map a page which is currently in use.
        assert!(page_table[addr].is_unused()
               , "Could not map frame {:?}, page table entry {} is already \
                  in use!", frame, PTLevel::index_of(addr));
        // set the page table entry at that index
        page_table[addr].set(frame, flags | table::PRESENT);
    }

    fn identity_map<A>(&mut self, frame: PhysicalPage, flags: EntryFlags
                      , alloc: &A)
    where A: FrameAllocator {
        self.map( Page::containing(VAddr::from(*frame.base_addr() as usize))
                , frame
                , flags
                , alloc )
    }

    fn map_to_any<A>( &mut self
                    , page: VirtualPage
                    , flags: EntryFlags
                    , alloc: &A)
    where A: FrameAllocator {
        let frame = unsafe {
            alloc.allocate()
             // TODO: would we rather rewrite this to return
             // a `Result`? I think so.
                 .expect("Couldn't map page, out of frames!")
        };
        self.map(page, frame, flags, alloc);
    }

    /// Unmap the given `VirtualPage`.
    ///
    /// All freed frames are returned to the given `FrameAllocator`.
    fn unmap<A>(&mut self, page: VirtualPage, alloc: &A)
    where A: FrameAllocator {
        use self::tlb::Flush;

        // get the page table entry corresponding to the page.
        let ref mut entry
            = self.pml4_mut()
                  .page_table_mut_for(page) // get the page table for the page
                  .expect("Could not unmap, huge pages not supported!")
                  [page.base()];        // index the entry from the table

        // get the pointed frame for the page table entry.
        let frame = entry.get_frame()
                         .expect("Could not unmap page that was not mapped!");

        // mark the page table entry as unused
        entry.set_unused();

        // deallocate the frame and flush the translation lookaside buffer
        // this is safe because we're in kernel mode
        assert!( page.flush()
               , "Could not flush TLB, we were not in kernel mode!");
        unsafe {
            // this is hopefully safe because nobody else should be using an
            // allocated page frame
            alloc.deallocate(frame);
        }
        // TODO: check if page tables containing the unmapped page are empty
        //       and deallocate them too?
    }

}

impl ActivePML4 {

    pub unsafe fn new() -> Self {
        ActivePML4(Unique::new(PML4_PTR))
    }

    fn pml4(&self) -> &Table<PML4Level> {
        unsafe { self.0.as_ref() }
    }

    fn pml4_mut(&mut self) -> &mut Table<PML4Level> {
        unsafe { self.0.as_mut() }
    }

    /// Returns true if the given page is mapped.
    #[inline]
    pub fn is_mapped(&self, page: &VirtualPage) -> bool {
         self.translate_page(*page).is_some()
    }

}

/// An inactive page table that the CPU is not currently using
pub struct InactivePageTable {
    pml4_frame: PhysicalPage
}

impl InactivePageTable {
    pub fn new( frame: PhysicalPage
              , active_table: &mut ActivePageTable
              , temp: &mut TempPage)
              -> Self {
        {
            let table = temp.map_to_table(frame.clone(), active_table);
            trace!( " . . . Mapped temp page to table frame.");
            table.zero();
            trace!( " . . . Zeroed inactive table frame.");
            table[511].set( frame.clone(), PRESENT | WRITABLE);
            trace!(" . . . Set active table to point to new inactive table.")
        }
        temp.unmap(active_table);
        trace!(" . . Unmapped temp page.");

        InactivePageTable { pml4_frame: frame }
    }
}

pub fn test_paging<A>(alloc: &A)
where A: FrameAllocator {
    // This testing code shamelessly stolen from Phil Oppermann.
    let mut pml4 = unsafe { ActivePML4::new() };

    // address 0 is mapped
    trace!("Some = {:?}", pml4.translate(VAddr::from(0)));
     // second PT entry
    trace!("Some = {:?}", pml4.translate(VAddr::from(4096)));
    // second PD entry
    trace!("Some = {:?}", pml4.translate(VAddr::from(512 * 4096)));
    // 300th PD entry
    trace!("Some = {:?}", pml4.translate(VAddr::from(300 * 512 * 4096)));
    // second PDPT entry
    trace!("None = {:?}", pml4.translate(VAddr::from(512 * 512 * 4096)));
    // last mapped byte
    trace!("Some = {:?}", pml4.translate(VAddr::from(512 * 512 * 4096 - 1)));

    let addr = VAddr::from(42 * 512 * 512 * 4096); // 42th PDPT entry
    let page = VirtualPage::containing(addr);
    let frame = unsafe { alloc.allocate().expect("no more frames") };
    trace!("None = {:?}, map to {:?}",
             pml4.translate(addr),
             frame);
    pml4.map(page, frame, EntryFlags::empty(), alloc);
    trace!("Some = {:?}", pml4.translate(addr));
    trace!( "next free frame: {:?}"
            , unsafe { alloc.allocate() });

    //trace!("{:#x}", *(Page::containing(addr).as_ptr()));

    pml4.unmap(Page::containing(addr), alloc);
    trace!("None = {:?}", pml4.translate(addr));

}

/// Remaps the kernel using 4KiB pages.
pub fn kernel_remap<A>(params: &InitParams, alloc: &A) -> ActivePageTable
where A: FrameAllocator {
    // create a  temporary page for switching page tables
    // page number chosen fairly arbitrarily.
    const TEMP_PAGE_NUMBER: usize = 0xcafebabe;
    let mut temp_page = TempPage::new(TEMP_PAGE_NUMBER, alloc);
    trace!(" . . Created temporary page.");

    // old and new page tables
    let mut current_table = unsafe { ActivePageTable::new() };
    trace!(" . . Got current page table.");

    let mut new_table = unsafe {
        InactivePageTable::new(
             alloc.allocate().expect("Out of physical pages!")
          , &mut current_table
          , &mut temp_page
          )
    };
    trace!(" . . Created new page table.");

    // actually remap the kernel --------------------------------------------
    current_table.using(&mut new_table, &mut temp_page, |pml4| {
        // extract allocated ELF sections
        let sections
            = params.elf_sections()
                    .filter(|section| section.is_allocated());

        for section in sections { // remap ELF sections
            assert!( section.addr().is_page_aligned()
                   , "Section address must be page aligned to remap!");
            trace!( " . . Identity mapping section at {:?} with size {:?}"
                    , section.addr()
                    , section.length() );

            let flags = EntryFlags::from(&section);

            let start_frame = PhysicalPage::from(section.addr());
            let end_frame = PhysicalPage::from(section.end_addr());

            for frame in start_frame .. end_frame {
                pml4.identity_map(frame, flags, alloc)
            }
        }

        // remap VGA buffer
        trace!( " . . Identity mapping VGA buffer" );
        let vga_buffer_frame = PhysicalPage::from(PAddr::from(0xb8000));
        pml4.identity_map(vga_buffer_frame, WRITABLE, alloc);

        // remap Multiboot info
        trace!( " . . Identity mapping multiboot info" );
        let multiboot_start = PhysicalPage::from(params.multiboot_start());
        let multiboot_end = PhysicalPage::from(params.multiboot_end());

        for frame in multiboot_start .. multiboot_end {
            pml4.identity_map(frame, PRESENT, alloc)
        }

    });

    // switch page tables ---------------------------------------------------
    let old_table = current_table.replace_with(&mut new_table);
    trace!(" . . Successfully switched to remapped page table!");

    // create guard page at the location of the old PML4 table
    let old_pml4_page
        = VirtualPage::containing(
            VAddr::from(*(old_table.pml4_frame.base()) as usize)
        );
    current_table.unmap(old_pml4_page, alloc);
    trace!(" . . Unmapped guard page at {:?}", old_pml4_page.base());

    current_table
}
<commit_msg>fix(paging): update paging module to use changed ELF API from 9d2eb03cd444cfa89867b1ffe202719410590cd8<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Paging
//!
//! The `x86_64` architecture uses a four-level page table structure. The top
//! page table is called the Page Meta-Level 4 (PML4) table, followed by
//! the Page Directory Pointer Table (PDPT), Page Directory (PD) table, and
//! finally the bottom-level Page Table (PT).
use core::ops;
use core::ptr::Unique;

use alloc::FrameAllocator;
use memory::{Addr, PAGE_SIZE, PAddr, Page, PhysicalPage, VAddr, VirtualPage};
use params::InitParams;
use ::Mapper;

use self::table::*;
use self::temp::TempPage;

pub mod table;
pub mod tlb;
pub mod temp;
pub mod cr3;

pub struct ActivePageTable { pml4: ActivePML4 }

impl ops::Deref for ActivePageTable {
    type Target = ActivePML4;

    fn deref(&self) -> &ActivePML4 {
        &self.pml4
    }
}

impl ops::DerefMut for ActivePageTable {
    fn deref_mut(&mut self) -> &mut ActivePML4 {
        &mut self.pml4
    }
}

impl ActivePageTable {
    pub unsafe fn new() -> ActivePageTable {
        ActivePageTable { pml4: ActivePML4::new() }
    }

    /// Execute a closure with the recursive mapping temporarily changed to a
    /// new page table
    pub fn using<F>( &mut self
                   , table: &mut InactivePageTable
                   , temp_page: &mut temp::TempPage
                   , f: F)
    where F: FnOnce(&mut ActivePML4) {
        use self::tlb::flush_all;
        {
            // back up the current PML4 frame
            let prev_pml4_frame = unsafe {
                // this is safe to execute; we are in kernel mode
                cr3::current_pagetable_frame()
            };

            // remap the 511th PML4 entry (the recursive entry) to map to the // frame containing the new PML4.
            self.pml4_mut()[511]
                .set(table.pml4_frame, PRESENT | WRITABLE);
            unsafe {
                // this is safe to execute; we are in kernel mode
                flush_all();
            }

            // execute the closure
            f(self);

            // remap the 511th entry to point back to the original frame
            self.pml4_mut()[511]
                .set(prev_pml4_frame, PRESENT | WRITABLE);

            unsafe {
                // this is safe to execute; we are in kernel mode
                flush_all();
            }
        }
        temp_page.unmap(self);

    }

    /// Replace the current `ActivePageTable` with the given `InactivePageTable`
    ///
    /// # Arguments
    /// + `new_table`: the `InactivePageTable` that will replace the current
    ///                `ActivePageTable`.
    ///
    /// # Returns
    /// + the old active page table as an `InactivePageTable`.
    pub fn replace_with(&mut self, new_table: &mut InactivePageTable)
                       -> InactivePageTable {
        unsafe {
            // this is safe to execute; we are in kernel mode
            let old_pml4_frame = cr3::current_pagetable_frame();

            cr3::set_pagetable_frame(new_table.pml4_frame);

            InactivePageTable {
                pml4_frame: old_pml4_frame
            }
        }
    }

}

/// Struct representing the currently active PML4 instance.
///
/// The `ActivePML4` is a `Unique` reference to a PML4-level page table. It's
/// unique because, well, there can only be one active PML4 at a given time.
///
pub struct ActivePML4(Unique<Table<PML4Level>>);

/// The active PML4 table is the single point of entry for page mapping.
impl Mapper for ActivePML4 {
    type Flags = EntryFlags;

    fn translate(&self, vaddr: VAddr) -> Option<PAddr> {
        let offset = *vaddr % PAGE_SIZE as usize;
        self.translate_page(Page::containing(vaddr))
            .map(|frame| PAddr::from(frame.number + offset as u64) )
    }

    fn translate_page(&self, page: VirtualPage) -> Option<PhysicalPage> {
        let addr = page.base();
        let pdpt = self.pml4().next_table(addr);

        let huge_page = || {
            pdpt.and_then(|pdpt|
                pdpt[addr]
                    .do_huge(PDLevel::index_of(addr) + PTLevel::index_of(addr))
                    .or_else(|| {
                        pdpt.next_table(addr).and_then(|pd|
                            pd[addr].do_huge(PTLevel::index_of(addr))
                        )
                    })
                )
        };

        pdpt.and_then(|pdpt| pdpt.next_table(addr))
            .and_then(|pd| pd.next_table(addr))
            .and_then(|pt| pt[addr].get_frame())
            .or_else(huge_page)
    }

    /// Modifies the page tables so that `page` maps to `frame`.
    ///
    /// # Arguments
    /// + `page`: the virtual `Page` to map
    /// + `frame`: the physical `Frame` that `Page` should map to.
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map<A>( &mut self, page: VirtualPage, frame: PhysicalPage
             , flags: EntryFlags, alloc: &A)
    where A: FrameAllocator {
        // base virtual address of page being mapped
        let addr = page.base();

        // access or create all the lower-level page tables.
        let mut page_table
            // get the PML4
            = self.pml4_mut()
                  // get or create the PDPT table at the page's PML4 index
                  .create_next(addr, alloc)
                  // get or create the PD table at the page's PDPT index
                  .create_next(addr, alloc)
                  // get or create the page table at the  page's PD table index
                  .create_next(addr, alloc);
        trace!(" . . Map: Got page table");
        // check if the page at that index is not currently in use, as we
        // cannot map a page which is currently in use.
        assert!(page_table[addr].is_unused()
               , "Could not map frame {:?}, page table entry {} is already \
                  in use!", frame, PTLevel::index_of(addr));
        // set the page table entry at that index
        page_table[addr].set(frame, flags | table::PRESENT);
    }

    fn identity_map<A>(&mut self, frame: PhysicalPage, flags: EntryFlags
                      , alloc: &A)
    where A: FrameAllocator {
        self.map( Page::containing(VAddr::from(*frame.base_addr() as usize))
                , frame
                , flags
                , alloc )
    }

    fn map_to_any<A>( &mut self
                    , page: VirtualPage
                    , flags: EntryFlags
                    , alloc: &A)
    where A: FrameAllocator {
        let frame = unsafe {
            alloc.allocate()
             // TODO: would we rather rewrite this to return
             // a `Result`? I think so.
                 .expect("Couldn't map page, out of frames!")
        };
        self.map(page, frame, flags, alloc);
    }

    /// Unmap the given `VirtualPage`.
    ///
    /// All freed frames are returned to the given `FrameAllocator`.
    fn unmap<A>(&mut self, page: VirtualPage, alloc: &A)
    where A: FrameAllocator {
        use self::tlb::Flush;

        // get the page table entry corresponding to the page.
        let ref mut entry
            = self.pml4_mut()
                  .page_table_mut_for(page) // get the page table for the page
                  .expect("Could not unmap, huge pages not supported!")
                  [page.base()];        // index the entry from the table

        // get the pointed frame for the page table entry.
        let frame = entry.get_frame()
                         .expect("Could not unmap page that was not mapped!");

        // mark the page table entry as unused
        entry.set_unused();

        // deallocate the frame and flush the translation lookaside buffer
        // this is safe because we're in kernel mode
        assert!( page.flush()
               , "Could not flush TLB, we were not in kernel mode!");
        unsafe {
            // this is hopefully safe because nobody else should be using an
            // allocated page frame
            alloc.deallocate(frame);
        }
        // TODO: check if page tables containing the unmapped page are empty
        //       and deallocate them too?
    }

}

impl ActivePML4 {

    pub unsafe fn new() -> Self {
        ActivePML4(Unique::new(PML4_PTR))
    }

    fn pml4(&self) -> &Table<PML4Level> {
        unsafe { self.0.as_ref() }
    }

    fn pml4_mut(&mut self) -> &mut Table<PML4Level> {
        unsafe { self.0.as_mut() }
    }

    /// Returns true if the given page is mapped.
    #[inline]
    pub fn is_mapped(&self, page: &VirtualPage) -> bool {
         self.translate_page(*page).is_some()
    }

}

/// An inactive page table that the CPU is not currently using
pub struct InactivePageTable {
    pml4_frame: PhysicalPage
}

impl InactivePageTable {
    pub fn new( frame: PhysicalPage
              , active_table: &mut ActivePageTable
              , temp: &mut TempPage)
              -> Self {
        {
            let table = temp.map_to_table(frame.clone(), active_table);
            trace!( " . . . Mapped temp page to table frame.");
            table.zero();
            trace!( " . . . Zeroed inactive table frame.");
            table[511].set( frame.clone(), PRESENT | WRITABLE);
            trace!(" . . . Set active table to point to new inactive table.")
        }
        temp.unmap(active_table);
        trace!(" . . Unmapped temp page.");

        InactivePageTable { pml4_frame: frame }
    }
}

pub fn test_paging<A>(alloc: &A)
where A: FrameAllocator {
    // This testing code shamelessly stolen from Phil Oppermann.
    let mut pml4 = unsafe { ActivePML4::new() };

    // address 0 is mapped
    trace!("Some = {:?}", pml4.translate(VAddr::from(0)));
     // second PT entry
    trace!("Some = {:?}", pml4.translate(VAddr::from(4096)));
    // second PD entry
    trace!("Some = {:?}", pml4.translate(VAddr::from(512 * 4096)));
    // 300th PD entry
    trace!("Some = {:?}", pml4.translate(VAddr::from(300 * 512 * 4096)));
    // second PDPT entry
    trace!("None = {:?}", pml4.translate(VAddr::from(512 * 512 * 4096)));
    // last mapped byte
    trace!("Some = {:?}", pml4.translate(VAddr::from(512 * 512 * 4096 - 1)));

    let addr = VAddr::from(42 * 512 * 512 * 4096); // 42th PDPT entry
    let page = VirtualPage::containing(addr);
    let frame = unsafe { alloc.allocate().expect("no more frames") };
    trace!("None = {:?}, map to {:?}",
             pml4.translate(addr),
             frame);
    pml4.map(page, frame, EntryFlags::empty(), alloc);
    trace!("Some = {:?}", pml4.translate(addr));
    trace!( "next free frame: {:?}"
            , unsafe { alloc.allocate() });

    //trace!("{:#x}", *(Page::containing(addr).as_ptr()));

    pml4.unmap(Page::containing(addr), alloc);
    trace!("None = {:?}", pml4.translate(addr));

}

/// Remaps the kernel using 4KiB pages.
pub fn kernel_remap<A>(params: &InitParams, alloc: &A) -> ActivePageTable
where A: FrameAllocator {
    // create a  temporary page for switching page tables
    // page number chosen fairly arbitrarily.
    const TEMP_PAGE_NUMBER: usize = 0xcafebabe;
    let mut temp_page = TempPage::new(TEMP_PAGE_NUMBER, alloc);
    trace!(" . . Created temporary page.");

    // old and new page tables
    let mut current_table = unsafe { ActivePageTable::new() };
    trace!(" . . Got current page table.");

    let mut new_table = unsafe {
        InactivePageTable::new(
             alloc.allocate().expect("Out of physical pages!")
          , &mut current_table
          , &mut temp_page
          )
    };
    trace!(" . . Created new page table.");

    // actually remap the kernel --------------------------------------------
    current_table.using(&mut new_table, &mut temp_page, |pml4| {
        // extract allocated ELF sections
        let sections
            = params.elf_sections()
                    .filter(|section| section.is_allocated());

        for section in sections { // remap ELF sections
            assert!( section.address().is_page_aligned()
                   , "Section address must be page aligned to remap!");
            trace!( " . . Identity mapping section at {:?} with size {:?}"
                    , section.address()
                    , section.length() );

            let flags = EntryFlags::from(section);

            let start_frame = PhysicalPage::from(section.address());
            let end_frame = PhysicalPage::from(section.end_address());

            for frame in start_frame .. end_frame {
                pml4.identity_map(frame, flags, alloc)
            }
        }

        // remap VGA buffer
        trace!( " . . Identity mapping VGA buffer" );
        let vga_buffer_frame = PhysicalPage::from(PAddr::from(0xb8000));
        pml4.identity_map(vga_buffer_frame, WRITABLE, alloc);

        // remap Multiboot info
        trace!( " . . Identity mapping multiboot info" );
        let multiboot_start = PhysicalPage::from(params.multiboot_start());
        let multiboot_end = PhysicalPage::from(params.multiboot_end());

        for frame in multiboot_start .. multiboot_end {
            pml4.identity_map(frame, PRESENT, alloc)
        }

    });

    // switch page tables ---------------------------------------------------
    let old_table = current_table.replace_with(&mut new_table);
    trace!(" . . Successfully switched to remapped page table!");

    // create guard page at the location of the old PML4 table
    let old_pml4_page
        = VirtualPage::containing(
            VAddr::from(*(old_table.pml4_frame.base()) as usize)
        );
    current_table.unmap(old_pml4_page, alloc);
    trace!(" . . Unmapped guard page at {:?}", old_pml4_page.base());

    current_table
}
<|endoftext|>


<commit_before>//! Shim which is passed to Cargo as "rustc" when running the bootstrap.
//!
//! This shim will take care of some various tasks that our build process
//! requires that Cargo can't quite do through normal configuration:
//!
//! 1. When compiling build scripts and build dependencies, we need a guaranteed
//!    full standard library available. The only compiler which actually has
//!    this is the snapshot, so we detect this situation and always compile with
//!    the snapshot compiler.
//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling
//!    (and this slightly differs based on a whether we're using a snapshot or
//!    not), so we do that all here.
//!
//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.

use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::time::Instant;

fn main() {
    let args = env::args_os().skip(1).collect::<Vec<_>>();

    // Detect whether or not we're a build script depending on whether --target
    // is passed (a bit janky...)
    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
    let version = args.iter().find(|w| &**w == "-vV");

    let verbose = match env::var("RUSTC_VERBOSE") {
        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
        Err(_) => 0,
    };

    // Use a different compiler for build scripts, since there may not yet be a
    // libstd for the real compiler to use. However, if Cargo is attempting to
    // determine the version of the compiler, the real compiler needs to be
    // used. Currently, these two states are differentiated based on whether
    // --target and -vV is/isn't passed.
    let (rustc, libdir) = if target.is_none() && version.is_none() {
        ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
    } else {
        ("RUSTC_REAL", "RUSTC_LIBDIR")
    };
    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
    let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
    let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);

    let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
    let mut dylib_path = bootstrap::util::dylib_path();
    dylib_path.insert(0, PathBuf::from(&libdir));

    let mut cmd = Command::new(rustc);
    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());

    // Get the name of the crate we're compiling, if any.
    let crate_name =
        args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str());

    if let Some(crate_name) = crate_name {
        if let Some(target) = env::var_os("RUSTC_TIME") {
            if target == "all"
                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
            {
                cmd.arg("-Ztime");
            }
        }
    }

    // Print backtrace in case of ICE
    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
        cmd.env("RUST_BACKTRACE", "1");
    }

    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
        cmd.args(lint_flags.split_whitespace());
    }

    if target.is_some() {
        // The stage0 compiler has a special sysroot distinct from what we
        // actually downloaded, so we just always pass the `--sysroot` option,
        // unless one is already set.
        if !args.iter().any(|arg| arg == "--sysroot") {
            cmd.arg("--sysroot").arg(&sysroot);
        }

        // If we're compiling specifically the `panic_abort` crate then we pass
        // the `-C panic=abort` option. Note that we do not do this for any
        // other crate intentionally as this is the only crate for now that we
        // ship with panic=abort.
        //
        // This... is a bit of a hack how we detect this. Ideally this
        // information should be encoded in the crate I guess? Would likely
        // require an RFC amendment to RFC 1513, however.
        //
        // `compiler_builtins` are unconditionally compiled with panic=abort to
        // workaround undefined references to `rust_eh_unwind_resume` generated
        // otherwise, see issue https://github.com/rust-lang/rust/issues/43095.
        if crate_name == Some("panic_abort")
            || crate_name == Some("compiler_builtins") && stage != "0"
        {
            cmd.arg("-C").arg("panic=abort");
        }
    } else {
        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
        // here, but rather Cargo should know what flags to pass rustc itself.

        // Override linker if necessary.
        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
            cmd.arg(format!("-Clinker={}", host_linker));
        }
        if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() {
            cmd.arg("-Clink-args=-fuse-ld=lld");
        }

        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
            if s == "true" {
                cmd.arg("-C").arg("target-feature=+crt-static");
            }
            if s == "false" {
                cmd.arg("-C").arg("target-feature=-crt-static");
            }
        }
    }

    if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
        cmd.arg("--remap-path-prefix").arg(&map);
    }

    // Force all crates compiled by this compiler to (a) be unstable and (b)
    // allow the `rustc_private` feature to link to other unstable crates
    // also in the sysroot. We also do this for host crates, since those
    // may be proc macros, in which case we might ship them.
    if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) {
        cmd.arg("-Z").arg("force-unstable-if-unmarked");
    }

    if verbose > 1 {
        let rust_env_vars =
            env::vars().filter(|(k, _)| k.starts_with("RUST") || k.starts_with("CARGO"));
        for (i, (k, v)) in rust_env_vars.enumerate() {
            eprintln!("rustc env[{}]: {:?}={:?}", i, k, v);
        }
        eprintln!("rustc working directory: {}", env::current_dir().unwrap().display());
        eprintln!(
            "rustc command: {:?}={:?} {:?}",
            bootstrap::util::dylib_path_var(),
            env::join_paths(&dylib_path).unwrap(),
            cmd,
        );
        eprintln!("sysroot: {:?}", sysroot);
        eprintln!("libdir: {:?}", libdir);
    }

    let start = Instant::now();
    let status = {
        let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd);
        cmd.status().expect(&errmsg)
    };

    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
        || env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some()
    {
        if let Some(crate_name) = crate_name {
            let dur = start.elapsed();
            let is_test = args.iter().any(|a| a == "--test");
            // If the user requested resource usage data, then
            // include that in addition to the timing output.
            let rusage_data =
                env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data());
            eprintln!(
                "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
                crate_name,
                is_test,
                dur.as_secs(),
                dur.subsec_millis(),
                if rusage_data.is_some() { " " } else { "" },
                rusage_data.unwrap_or(String::new()),
            );
        }
    }

    if status.success() {
        std::process::exit(0);
        // note: everything below here is unreachable. do not put code that
        // should run on success, after this block.
    }
    if verbose > 0 {
        println!("\nDid not run successfully: {}\n{:?}\n-------------", status, cmd);
    }

    if let Some(mut on_fail) = on_fail {
        on_fail.status().expect("Could not run the on_fail command");
    }

    // Preserve the exit code. In case of signal, exit with 0xfe since it's
    // awkward to preserve this status in a cross-platform way.
    match status.code() {
        Some(i) => std::process::exit(i),
        None => {
            eprintln!("rustc exited with {}", status);
            std::process::exit(0xfe);
        }
    }
}

#[cfg(not(unix))]
/// getrusage is not available on non-unix platforms. So for now, we do not
/// bother trying to make a shim for it.
fn format_rusage_data() -> Option<String> {
    None
}

#[cfg(unix)]
/// Tries to build a string with human readable data for several of the rusage
/// fields. Note that we are focusing mainly on data that we believe to be
/// supplied on Linux (the `rusage` struct has other fields in it but they are
/// currently unsupported by Linux).
fn format_rusage_data() -> Option<String> {
    let rusage: libc::rusage = unsafe {
        let mut recv = std::mem::zeroed();
        // -1 is RUSAGE_CHILDREN, which means to get the rusage for all children
        // (and grandchildren, etc) processes that have respectively terminated
        // and been waited for.
        let retval = libc::getrusage(-1, &mut recv);
        if retval != 0 {
            return None;
        }
        recv
    };
    // Mac OS X reports the maxrss in bytes, not kb.
    let divisor = if env::consts::OS == "macos" { 1024 } else { 1 };
    let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor;

    let mut init_str = format!(
        "user: {USER_SEC}.{USER_USEC:03} \
         sys: {SYS_SEC}.{SYS_USEC:03} \
         max rss (kb): {MAXRSS}",
        USER_SEC = rusage.ru_utime.tv_sec,
        USER_USEC = rusage.ru_utime.tv_usec,
        SYS_SEC = rusage.ru_stime.tv_sec,
        SYS_USEC = rusage.ru_stime.tv_usec,
        MAXRSS = maxrss
    );

    // The remaining rusage stats vary in platform support. So we treat
    // uniformly zero values in each category as "not worth printing", since it
    // either means no events of that type occurred, or that the platform
    // does not support it.

    let minflt = rusage.ru_minflt;
    let majflt = rusage.ru_majflt;
    if minflt != 0 || majflt != 0 {
        init_str.push_str(&format!(" page reclaims: {} page faults: {}", minflt, majflt));
    }

    let inblock = rusage.ru_inblock;
    let oublock = rusage.ru_oublock;
    if inblock != 0 || oublock != 0 {
        init_str.push_str(&format!(" fs block inputs: {} fs block outputs: {}", inblock, oublock));
    }

    let nvcsw = rusage.ru_nvcsw;
    let nivcsw = rusage.ru_nivcsw;
    if nvcsw != 0 || nivcsw != 0 {
        init_str.push_str(&format!(
            " voluntary ctxt switches: {} involuntary ctxt switches: {}",
            nvcsw, nivcsw
        ));
    }

    return Some(init_str);
}
<commit_msg>Make rustc shim's verbose output include crate_name being compiled.<commit_after>//! Shim which is passed to Cargo as "rustc" when running the bootstrap.
//!
//! This shim will take care of some various tasks that our build process
//! requires that Cargo can't quite do through normal configuration:
//!
//! 1. When compiling build scripts and build dependencies, we need a guaranteed
//!    full standard library available. The only compiler which actually has
//!    this is the snapshot, so we detect this situation and always compile with
//!    the snapshot compiler.
//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling
//!    (and this slightly differs based on a whether we're using a snapshot or
//!    not), so we do that all here.
//!
//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.

use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::time::Instant;

fn main() {
    let args = env::args_os().skip(1).collect::<Vec<_>>();

    // Detect whether or not we're a build script depending on whether --target
    // is passed (a bit janky...)
    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
    let version = args.iter().find(|w| &**w == "-vV");

    let verbose = match env::var("RUSTC_VERBOSE") {
        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
        Err(_) => 0,
    };

    // Use a different compiler for build scripts, since there may not yet be a
    // libstd for the real compiler to use. However, if Cargo is attempting to
    // determine the version of the compiler, the real compiler needs to be
    // used. Currently, these two states are differentiated based on whether
    // --target and -vV is/isn't passed.
    let (rustc, libdir) = if target.is_none() && version.is_none() {
        ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
    } else {
        ("RUSTC_REAL", "RUSTC_LIBDIR")
    };
    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
    let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
    let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);

    let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
    let mut dylib_path = bootstrap::util::dylib_path();
    dylib_path.insert(0, PathBuf::from(&libdir));

    let mut cmd = Command::new(rustc);
    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());

    // Get the name of the crate we're compiling, if any.
    let crate_name =
        args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str());

    if let Some(crate_name) = crate_name {
        if let Some(target) = env::var_os("RUSTC_TIME") {
            if target == "all"
                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
            {
                cmd.arg("-Ztime");
            }
        }
    }

    // Print backtrace in case of ICE
    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
        cmd.env("RUST_BACKTRACE", "1");
    }

    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
        cmd.args(lint_flags.split_whitespace());
    }

    if target.is_some() {
        // The stage0 compiler has a special sysroot distinct from what we
        // actually downloaded, so we just always pass the `--sysroot` option,
        // unless one is already set.
        if !args.iter().any(|arg| arg == "--sysroot") {
            cmd.arg("--sysroot").arg(&sysroot);
        }

        // If we're compiling specifically the `panic_abort` crate then we pass
        // the `-C panic=abort` option. Note that we do not do this for any
        // other crate intentionally as this is the only crate for now that we
        // ship with panic=abort.
        //
        // This... is a bit of a hack how we detect this. Ideally this
        // information should be encoded in the crate I guess? Would likely
        // require an RFC amendment to RFC 1513, however.
        //
        // `compiler_builtins` are unconditionally compiled with panic=abort to
        // workaround undefined references to `rust_eh_unwind_resume` generated
        // otherwise, see issue https://github.com/rust-lang/rust/issues/43095.
        if crate_name == Some("panic_abort")
            || crate_name == Some("compiler_builtins") && stage != "0"
        {
            cmd.arg("-C").arg("panic=abort");
        }
    } else {
        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
        // here, but rather Cargo should know what flags to pass rustc itself.

        // Override linker if necessary.
        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
            cmd.arg(format!("-Clinker={}", host_linker));
        }
        if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() {
            cmd.arg("-Clink-args=-fuse-ld=lld");
        }

        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
            if s == "true" {
                cmd.arg("-C").arg("target-feature=+crt-static");
            }
            if s == "false" {
                cmd.arg("-C").arg("target-feature=-crt-static");
            }
        }
    }

    if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
        cmd.arg("--remap-path-prefix").arg(&map);
    }

    // Force all crates compiled by this compiler to (a) be unstable and (b)
    // allow the `rustc_private` feature to link to other unstable crates
    // also in the sysroot. We also do this for host crates, since those
    // may be proc macros, in which case we might ship them.
    if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) {
        cmd.arg("-Z").arg("force-unstable-if-unmarked");
    }

    if verbose > 1 {
        let rust_env_vars =
            env::vars().filter(|(k, _)| k.starts_with("RUST") || k.starts_with("CARGO"));
        let prefix = match crate_name {
            Some(crate_name) => format!("rustc {}", crate_name),
            None => "rustc".to_string(),
        };
        for (i, (k, v)) in rust_env_vars.enumerate() {
            eprintln!("{} env[{}]: {:?}={:?}", prefix, i, k, v);
        }
        eprintln!("{} working directory: {}", prefix, env::current_dir().unwrap().display());
        eprintln!(
            "{} command: {:?}={:?} {:?}",
            prefix,
            bootstrap::util::dylib_path_var(),
            env::join_paths(&dylib_path).unwrap(),
            cmd,
        );
        eprintln!("{} sysroot: {:?}", prefix, sysroot);
        eprintln!("{} libdir: {:?}", prefix, libdir);
    }

    let start = Instant::now();
    let status = {
        let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd);
        cmd.status().expect(&errmsg)
    };

    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
        || env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some()
    {
        if let Some(crate_name) = crate_name {
            let dur = start.elapsed();
            let is_test = args.iter().any(|a| a == "--test");
            // If the user requested resource usage data, then
            // include that in addition to the timing output.
            let rusage_data =
                env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data());
            eprintln!(
                "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
                crate_name,
                is_test,
                dur.as_secs(),
                dur.subsec_millis(),
                if rusage_data.is_some() { " " } else { "" },
                rusage_data.unwrap_or(String::new()),
            );
        }
    }

    if status.success() {
        std::process::exit(0);
        // note: everything below here is unreachable. do not put code that
        // should run on success, after this block.
    }
    if verbose > 0 {
        println!("\nDid not run successfully: {}\n{:?}\n-------------", status, cmd);
    }

    if let Some(mut on_fail) = on_fail {
        on_fail.status().expect("Could not run the on_fail command");
    }

    // Preserve the exit code. In case of signal, exit with 0xfe since it's
    // awkward to preserve this status in a cross-platform way.
    match status.code() {
        Some(i) => std::process::exit(i),
        None => {
            eprintln!("rustc exited with {}", status);
            std::process::exit(0xfe);
        }
    }
}

#[cfg(not(unix))]
/// getrusage is not available on non-unix platforms. So for now, we do not
/// bother trying to make a shim for it.
fn format_rusage_data() -> Option<String> {
    None
}

#[cfg(unix)]
/// Tries to build a string with human readable data for several of the rusage
/// fields. Note that we are focusing mainly on data that we believe to be
/// supplied on Linux (the `rusage` struct has other fields in it but they are
/// currently unsupported by Linux).
fn format_rusage_data() -> Option<String> {
    let rusage: libc::rusage = unsafe {
        let mut recv = std::mem::zeroed();
        // -1 is RUSAGE_CHILDREN, which means to get the rusage for all children
        // (and grandchildren, etc) processes that have respectively terminated
        // and been waited for.
        let retval = libc::getrusage(-1, &mut recv);
        if retval != 0 {
            return None;
        }
        recv
    };
    // Mac OS X reports the maxrss in bytes, not kb.
    let divisor = if env::consts::OS == "macos" { 1024 } else { 1 };
    let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor;

    let mut init_str = format!(
        "user: {USER_SEC}.{USER_USEC:03} \
         sys: {SYS_SEC}.{SYS_USEC:03} \
         max rss (kb): {MAXRSS}",
        USER_SEC = rusage.ru_utime.tv_sec,
        USER_USEC = rusage.ru_utime.tv_usec,
        SYS_SEC = rusage.ru_stime.tv_sec,
        SYS_USEC = rusage.ru_stime.tv_usec,
        MAXRSS = maxrss
    );

    // The remaining rusage stats vary in platform support. So we treat
    // uniformly zero values in each category as "not worth printing", since it
    // either means no events of that type occurred, or that the platform
    // does not support it.

    let minflt = rusage.ru_minflt;
    let majflt = rusage.ru_majflt;
    if minflt != 0 || majflt != 0 {
        init_str.push_str(&format!(" page reclaims: {} page faults: {}", minflt, majflt));
    }

    let inblock = rusage.ru_inblock;
    let oublock = rusage.ru_oublock;
    if inblock != 0 || oublock != 0 {
        init_str.push_str(&format!(" fs block inputs: {} fs block outputs: {}", inblock, oublock));
    }

    let nvcsw = rusage.ru_nvcsw;
    let nivcsw = rusage.ru_nivcsw;
    if nvcsw != 0 || nivcsw != 0 {
        init_str.push_str(&format!(
            " voluntary ctxt switches: {} involuntary ctxt switches: {}",
            nvcsw, nivcsw
        ));
    }

    return Some(init_str);
}
<|endoftext|>


<commit_before>use core::mem;
use core::ops::{Index, IndexMut};
use hil;

use common::take_cell::TakeCell;

use peripheral_registers::{GPIO_BASE, GPIO};

#[allow(non_snake_case)]
fn GPIO() -> &'static GPIO {
    unsafe { mem::transmute(GPIO_BASE as usize) }
}

pub struct GPIOPin {
    pin: u8,
    client_data: Cell<usize>,
    client: TakeCell<&'static hil::gpio::Client>,
}

impl GPIOPin {
    const fn new(pin: u8) -> GPIOPin {
        GPIOPin {
            pin: pin,
            client_data: Cell::new(0),
            client: TakeCell::empty(),
        }
    }

    pub fn set_client<C: hil::gpio::Client>(&self, client: &'static C) {
        self.client.replace(client);
    }

}

impl hil::gpio::GPIOPin for GPIOPin {
    fn enable_output(&self) {
        // bit 0: set as output
        // bit 1: disconnect input buffer
        // bit 2-3: no pullup/down
        // bit 8-10: drive configruation
        // bit 16-17: sensing
        GPIO().pin_cnf[self.pin as usize].set((1 << 0) | (1 << 1) | (0 << 2) | (0 << 8) | (0 << 16));
    }

    // Configuration constants stolen from
    // mynewt/hw/mcu/nordic/nrf51xxx/include/mcu/nrf51_bitfields.h
    fn enable_input(&self, _mode: hil::gpio::InputMode) {
        let conf = match _mode {
            hil::gpio::InputMode::PullUp   => 0x3 << 2,
            hil::gpio::InputMode::PullDown => 0x1 << 2,
            hil::gpio::InputMode::PullNone => 0,
        };
        GPIO().pin_cnf[self.pin as usize].set(conf);
    }

    // Not clk
    fn disable(&self) {
        self.enable_input(hil::gpio::OutputMode::PullNone);
    }

    fn set(&self) {
        GPIO().outset.set(1 << self.pin);
    }

    fn clear(&self) {
        GPIO().outclr.set(1 << self.pin);
    }

    fn toggle(&self) {
        // TODO: check need for a atomic XOR operator
        GPIO().out.set((1 << self.pin) ^ GPIO().out.get());
    }

    fn read(&self) -> bool {
        GPIO().in_.get() & (1 << self.pin);
    }

    fn enable_interrupt(&self, _client_data: usize, _mode: hil::gpio::InterruptMode) {
       self.client_data.set(_client_data);
       let mode_bits = match _mode {
           hil::gpio::InterruptMode::Change      => 0,
           hil::gpio::InterruptMode::RisingEdge  => 0,
           hil::gpio::InterruptMode::FallingEdge => 0,
       }
    }

    fn disable_interrupt(&self) {
        unimplemented!();
    }
}

pub struct Port {
    pins: [GPIOPin; 32]
}

impl Index<usize> for Port {
    type Output = GPIOPin;

    fn index(&self, index: usize) -> &GPIOPin {
        &self.pins[index]
    }
}

impl IndexMut<usize> for Port {
    fn index_mut(&mut self, index: usize) -> &mut GPIOPin {
        &mut self.pins[index]
    }
}

pub static mut PA : Port = Port {
    pins: [
        GPIOPin::new(0), GPIOPin::new(1), GPIOPin::new(2), GPIOPin::new(3),
        GPIOPin::new(4), GPIOPin::new(5), GPIOPin::new(6), GPIOPin::new(7),
        GPIOPin::new(8), GPIOPin::new(9), GPIOPin::new(10), GPIOPin::new(11),
        GPIOPin::new(12), GPIOPin::new(13), GPIOPin::new(14), GPIOPin::new(15),
        GPIOPin::new(16), GPIOPin::new(17), GPIOPin::new(18), GPIOPin::new(19),
        GPIOPin::new(20), GPIOPin::new(21), GPIOPin::new(22), GPIOPin::new(23),
        GPIOPin::new(24), GPIOPin::new(25), GPIOPin::new(26), GPIOPin::new(27),
        GPIOPin::new(28), GPIOPin::new(29), GPIOPin::new(30), GPIOPin::new(31),
    ],
};
<commit_msg>Starting to fill in GPIO.<commit_after>use core::mem;
use core::cell::Cell;
use core::ops::{Index, IndexMut};
use hil;

use common::take_cell::TakeCell;

use peripheral_registers::{GPIO_BASE, GPIO};

#[allow(non_snake_case)]
fn GPIO() -> &'static GPIO {
    unsafe { mem::transmute(GPIO_BASE as usize) }
}

pub struct GPIOPin {
    pin: u8,
    client_data: Cell<usize>,
    client: TakeCell<&'static hil::gpio::Client>,
}

impl GPIOPin {
    const fn new(pin: u8) -> GPIOPin {
        GPIOPin {
            pin: pin,
            client_data: Cell::new(0),
            client: TakeCell::empty(),
        }
    }

    pub fn set_client<C: hil::gpio::Client>(&self, client: &'static C) {
        self.client.replace(client);
    }

}

impl hil::gpio::GPIOPin for GPIOPin {
    fn enable_output(&self) {
        // bit 0: set as output
        // bit 1: disconnect input buffer
        // bit 2-3: no pullup/down
        // bit 8-10: drive configruation
        // bit 16-17: sensing
        GPIO().pin_cnf[self.pin as usize].set((1 << 0) | (1 << 1) | (0 << 2) | (0 << 8) | (0 << 16));
    }

    // Configuration constants stolen from
    // mynewt/hw/mcu/nordic/nrf51xxx/include/mcu/nrf51_bitfields.h
    fn enable_input(&self, _mode: hil::gpio::InputMode) {
        let conf = match _mode {
            hil::gpio::InputMode::PullUp   => 0x3 << 2,
            hil::gpio::InputMode::PullDown => 0x1 << 2,
            hil::gpio::InputMode::PullNone => 0,
        };
        GPIO().pin_cnf[self.pin as usize].set(conf);
    }

    // Not clk
    fn disable(&self) {
        self.enable_input(hil::gpio::InputMode::PullNone);
    }

    fn set(&self) {
        GPIO().outset.set(1 << self.pin);
    }

    fn clear(&self) {
        GPIO().outclr.set(1 << self.pin);
    }

    fn toggle(&self) {
        // TODO: check need for a atomic XOR operator
        GPIO().out.set((1 << self.pin) ^ GPIO().out.get());
    }

    fn read(&self) -> bool {
        GPIO().in_.get() & (1 << self.pin) != 0
    }

    fn enable_interrupt(&self, _client_data: usize, _mode: hil::gpio::InterruptMode) {
       self.client_data.set(_client_data);
       let mode_bits = match _mode {
           hil::gpio::InterruptMode::Change      => 0,
           hil::gpio::InterruptMode::RisingEdge  => 0,
           hil::gpio::InterruptMode::FallingEdge => 0,
       };
    }

    fn disable_interrupt(&self) {
        unimplemented!();
    }
}

pub struct Port {
    pins: [GPIOPin; 32]
}

impl Index<usize> for Port {
    type Output = GPIOPin;

    fn index(&self, index: usize) -> &GPIOPin {
        &self.pins[index]
    }
}

impl IndexMut<usize> for Port {
    fn index_mut(&mut self, index: usize) -> &mut GPIOPin {
        &mut self.pins[index]
    }
}

pub static mut PA : Port = Port {
    pins: [
        GPIOPin::new(0), GPIOPin::new(1), GPIOPin::new(2), GPIOPin::new(3),
        GPIOPin::new(4), GPIOPin::new(5), GPIOPin::new(6), GPIOPin::new(7),
        GPIOPin::new(8), GPIOPin::new(9), GPIOPin::new(10), GPIOPin::new(11),
        GPIOPin::new(12), GPIOPin::new(13), GPIOPin::new(14), GPIOPin::new(15),
        GPIOPin::new(16), GPIOPin::new(17), GPIOPin::new(18), GPIOPin::new(19),
        GPIOPin::new(20), GPIOPin::new(21), GPIOPin::new(22), GPIOPin::new(23),
        GPIOPin::new(24), GPIOPin::new(25), GPIOPin::new(26), GPIOPin::new(27),
        GPIOPin::new(28), GPIOPin::new(29), GPIOPin::new(30), GPIOPin::new(31),
    ],
};
<|endoftext|>


<commit_before>use libc;
use std::str::FromStr;
use std::cmp::{self,Ord};
use std::sync::{Mutex, Once, ONCE_INIT};
use std::cell::RefCell;
use std::fmt::{Arguments,format,write};
use std::io::{stdout,Stdout,Write};
use std::ascii::AsciiExt;
use std::net::{SocketAddr,UdpSocket};
use std::net::TcpStream;
use mio_uds::UnixDatagram;

lazy_static! {
  pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::new());
  pub static ref PID:    i32           = unsafe { libc::getpid() };
  pub static ref TAG:    String        = LOGGER.lock().unwrap().tag.clone();
}

pub struct Logger {
  pub directives: Vec<LogDirective>,
  pub backend:    LoggerBackend,
  pub tag:        String,
}

impl Logger {
  pub fn new() -> Logger {
    Logger {
      directives: vec!(LogDirective {
        name:  None,
        level: LogLevelFilter::Error,
      }),
      backend: LoggerBackend::Stdout(stdout()),
      tag:     "WAAAAAAAH".to_string()
    }
  }

  pub fn init(tag: String, spec: &str, backend: LoggerBackend) {
    let directives = parse_logging_spec(spec);
    if let Ok(ref mut logger) = LOGGER.lock() {
      logger.set_directives(directives);
      logger.backend = backend;
      logger.tag     = tag;
    }
    //trying to init the logger tag
    let ref t = *TAG;
  }

  pub fn log<'a>(&mut self, meta: &LogMetadata, args: Arguments) {
    if self.enabled(meta) {
      match self.backend {
        LoggerBackend::Stdout(ref mut stdout) => {
          stdout.write_fmt(args);
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Unix(ref mut socket) => {
          socket.send(format(args).as_bytes());
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Udp(ref mut socket, ref address) => {
          socket.send_to(format(args).as_bytes(), address);
        }
        LoggerBackend::Tcp(ref mut socket) => {
          socket.write_fmt(args);
        },
      }
    }
  }

  pub fn set_directives(&mut self, directives: Vec<LogDirective>) {
    self.directives = directives;
  }

  fn enabled(&self, meta: &LogMetadata) -> bool {
    // Search for the longest match, the vector is assumed to be pre-sorted.
    for directive in self.directives.iter().rev() {
      match directive.name {
        Some(ref name) if !meta.target.starts_with(&**name) => {},
        Some(..) | None => {
          return meta.level <= directive.level
        }
      }
    }
    false
  }
}

pub enum LoggerBackend {
  Stdout(Stdout),
  Unix(UnixDatagram),
  Udp(UdpSocket, SocketAddr),
  Tcp(TcpStream)
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevel {
    /// The "error" level.
    ///
    /// Designates very serious errors.
    Error = 1, // This way these line up with the discriminants for LogLevelFilter below
    /// The "warn" level.
    ///
    /// Designates hazardous situations.
    Warn,
    /// The "info" level.
    ///
    /// Designates useful information.
    Info,
    /// The "debug" level.
    ///
    /// Designates lower priority information.
    Debug,
    /// The "trace" level.
    ///
    /// Designates very low priority, often extremely verbose, information.
    Trace,
}

static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO",
                                             "DEBUG", "TRACE"];

impl Clone for LogLevel {
    #[inline]
    fn clone(&self) -> LogLevel {
        *self
    }
}

impl PartialEq for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevelFilter> for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialOrd for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevelFilter> for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some((*self as usize).cmp(&(*other as usize)))
    }
}

impl Ord for LogLevel {
    #[inline]
    fn cmp(&self, other: &LogLevel) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl LogLevel {
    fn from_usize(u: usize) -> Option<LogLevel> {
        match u {
            1 => Some(LogLevel::Error),
            2 => Some(LogLevel::Warn),
            3 => Some(LogLevel::Info),
            4 => Some(LogLevel::Debug),
            5 => Some(LogLevel::Trace),
            _ => None
        }
    }

    /// Returns the most verbose logging level.
    #[inline]
    pub fn max() -> LogLevel {
        LogLevel::Trace
    }

    /// Converts the `LogLevel` to the equivalent `LogLevelFilter`.
    #[inline]
    pub fn to_log_level_filter(&self) -> LogLevelFilter {
        LogLevelFilter::from_usize(*self as usize).unwrap()
    }
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevelFilter {
    Off,
    Error,
    Warn,
    Info,
    Debug,
    Trace,
}

impl Clone for LogLevelFilter {
    #[inline]
    fn clone(&self) -> LogLevelFilter {
        *self
    }
}

impl PartialEq for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevel> for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        other.eq(self)
    }
}

impl PartialOrd for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevel> for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        other.partial_cmp(self).map(|x| x.reverse())
    }
}

impl Ord for LogLevelFilter {
    #[inline]
    fn cmp(&self, other: &LogLevelFilter) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl FromStr for LogLevelFilter {
    type Err = ();
    fn from_str(level: &str) -> Result<LogLevelFilter, ()> {
        ok_or(LOG_LEVEL_NAMES.iter()
                    .position(|&name| name.eq_ignore_ascii_case(level))
                    .map(|p| LogLevelFilter::from_usize(p).unwrap()), ())
    }
}

impl LogLevelFilter {
    fn from_usize(u: usize) -> Option<LogLevelFilter> {
        match u {
            0 => Some(LogLevelFilter::Off),
            1 => Some(LogLevelFilter::Error),
            2 => Some(LogLevelFilter::Warn),
            3 => Some(LogLevelFilter::Info),
            4 => Some(LogLevelFilter::Debug),
            5 => Some(LogLevelFilter::Trace),
            _ => None
        }
    }
    /// Returns the most verbose logging level filter.
    #[inline]
    pub fn max() -> LogLevelFilter {
        LogLevelFilter::Trace
    }

    /// Converts `self` to the equivalent `LogLevel`.
    ///
    /// Returns `None` if `self` is `LogLevelFilter::Off`.
    #[inline]
    pub fn to_log_level(&self) -> Option<LogLevel> {
        LogLevel::from_usize(*self as usize)
    }
}

/// Metadata about a log message.
pub struct LogMetadata {
  pub level:  LogLevel,
  pub target: &'static str,
}

pub struct LogDirective {
    name:  Option<String>,
    level: LogLevelFilter,
}

fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {
    match t {
        Some(t) => Ok(t),
        None => Err(e),
    }
}

pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return dirs;
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match part0.parse() {
                    Ok(num) => (num, None),
                    Err(_) => (LogLevelFilter::max(), Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)),
            (Some(part0), Some(part1), None) => {
                match part1.parse() {
                    Ok(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    return dirs;
}

#[macro_export]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $format:expr, $level_tag:expr, $($arg:tt)+) => ({
      use $crate::logging::LOGGER;
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      {
        let mut logger = LOGGER.lock().unwrap();
        logger.log(
          &_META,
          format_args!(
            concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
            ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
            $level_tag, *$crate::logging::TAG, $($arg)+));
      }
    });
    (target: $target:expr, $lvl:expr, $format:expr, $level_tag:expr) => ({
      use $crate::logging::LOGGER;
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      {
        let mut logger = LOGGER.lock().unwrap();
        logger.log(
          &_META,
          format_args!(
            concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
            ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
            $level_tag, *$crate::logging::TAG));
      }
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: module_path!(), $lvl, $($arg)+));
}

#[macro_export]
macro_rules! error {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Error, $format, "ERROR", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Error, $format, "ERROR");
    };
}

#[macro_export]
macro_rules! warn {
    ($format:expr, $($arg:tt)*) => {
        use time;
        use logging::PID;
        log!($crate::logging::LogLevel::Warn, $format, "WARN", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Warn, $format, "WARN");
    }
}

#[macro_export]
macro_rules! info {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Info, $format, "INFO", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Info, $format, "INFO");
    }
}

#[macro_export]
macro_rules! debug {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format),
          "DEBUG", module_path!(), $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format),
          "DEBUG", module_path!());
    }
}

#[macro_export]
macro_rules! trace {
    ($format:expr, $($arg:tt)*) => (
        log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format),
          "TRACE", module_path!(), $($arg)*);
    );
    ($format:expr) => (
        log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format),
          "TRACE", module_path!());
    )
}

#[macro_export]
macro_rules! setup_test_logger {
  () => (
    $crate::logging::Logger::init(module_path!().to_string(), "error", $crate::logging::LoggerBackend::Stdout(::std::io::stdout()));
  );
}
<commit_msg>do not hang on logging<commit_after>use libc;
use std::str::FromStr;
use std::cmp::{self,Ord};
use std::sync::{Mutex, Once, ONCE_INIT};
use std::cell::RefCell;
use std::fmt::{Arguments,format,write};
use std::io::{stdout,Stdout,Write};
use std::ascii::AsciiExt;
use std::net::{SocketAddr,UdpSocket};
use std::net::TcpStream;
use mio_uds::UnixDatagram;

lazy_static! {
  pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::new());
  pub static ref PID:    i32           = unsafe { libc::getpid() };
  pub static ref TAG:    String        = LOGGER.lock().unwrap().tag.clone();
}

pub struct Logger {
  pub directives: Vec<LogDirective>,
  pub backend:    LoggerBackend,
  pub tag:        String,
}

impl Logger {
  pub fn new() -> Logger {
    Logger {
      directives: vec!(LogDirective {
        name:  None,
        level: LogLevelFilter::Error,
      }),
      backend: LoggerBackend::Stdout(stdout()),
      tag:     "WAAAAAAAH".to_string()
    }
  }

  pub fn init(tag: String, spec: &str, backend: LoggerBackend) {
    let directives = parse_logging_spec(spec);
    if let Ok(ref mut logger) = LOGGER.lock() {
      logger.set_directives(directives);
      logger.backend = backend;
      logger.tag     = tag;
    }
    //trying to init the logger tag
    let ref t = *TAG;
  }

  pub fn log<'a>(&mut self, meta: &LogMetadata, args: Arguments) {
    if self.enabled(meta) {
      match self.backend {
        LoggerBackend::Stdout(ref mut stdout) => {
          stdout.write_fmt(args);
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Unix(ref mut socket) => {
          socket.send(format(args).as_bytes());
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Udp(ref mut socket, ref address) => {
          socket.send_to(format(args).as_bytes(), address);
        }
        LoggerBackend::Tcp(ref mut socket) => {
          socket.write_fmt(args);
        },
      }
    }
  }

  pub fn set_directives(&mut self, directives: Vec<LogDirective>) {
    self.directives = directives;
  }

  fn enabled(&self, meta: &LogMetadata) -> bool {
    // Search for the longest match, the vector is assumed to be pre-sorted.
    for directive in self.directives.iter().rev() {
      match directive.name {
        Some(ref name) if !meta.target.starts_with(&**name) => {},
        Some(..) | None => {
          return meta.level <= directive.level
        }
      }
    }
    false
  }
}

pub enum LoggerBackend {
  Stdout(Stdout),
  Unix(UnixDatagram),
  Udp(UdpSocket, SocketAddr),
  Tcp(TcpStream)
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevel {
    /// The "error" level.
    ///
    /// Designates very serious errors.
    Error = 1, // This way these line up with the discriminants for LogLevelFilter below
    /// The "warn" level.
    ///
    /// Designates hazardous situations.
    Warn,
    /// The "info" level.
    ///
    /// Designates useful information.
    Info,
    /// The "debug" level.
    ///
    /// Designates lower priority information.
    Debug,
    /// The "trace" level.
    ///
    /// Designates very low priority, often extremely verbose, information.
    Trace,
}

static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO",
                                             "DEBUG", "TRACE"];

impl Clone for LogLevel {
    #[inline]
    fn clone(&self) -> LogLevel {
        *self
    }
}

impl PartialEq for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevelFilter> for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialOrd for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevelFilter> for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some((*self as usize).cmp(&(*other as usize)))
    }
}

impl Ord for LogLevel {
    #[inline]
    fn cmp(&self, other: &LogLevel) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl LogLevel {
    fn from_usize(u: usize) -> Option<LogLevel> {
        match u {
            1 => Some(LogLevel::Error),
            2 => Some(LogLevel::Warn),
            3 => Some(LogLevel::Info),
            4 => Some(LogLevel::Debug),
            5 => Some(LogLevel::Trace),
            _ => None
        }
    }

    /// Returns the most verbose logging level.
    #[inline]
    pub fn max() -> LogLevel {
        LogLevel::Trace
    }

    /// Converts the `LogLevel` to the equivalent `LogLevelFilter`.
    #[inline]
    pub fn to_log_level_filter(&self) -> LogLevelFilter {
        LogLevelFilter::from_usize(*self as usize).unwrap()
    }
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevelFilter {
    Off,
    Error,
    Warn,
    Info,
    Debug,
    Trace,
}

impl Clone for LogLevelFilter {
    #[inline]
    fn clone(&self) -> LogLevelFilter {
        *self
    }
}

impl PartialEq for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevel> for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        other.eq(self)
    }
}

impl PartialOrd for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevel> for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        other.partial_cmp(self).map(|x| x.reverse())
    }
}

impl Ord for LogLevelFilter {
    #[inline]
    fn cmp(&self, other: &LogLevelFilter) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl FromStr for LogLevelFilter {
    type Err = ();
    fn from_str(level: &str) -> Result<LogLevelFilter, ()> {
        ok_or(LOG_LEVEL_NAMES.iter()
                    .position(|&name| name.eq_ignore_ascii_case(level))
                    .map(|p| LogLevelFilter::from_usize(p).unwrap()), ())
    }
}

impl LogLevelFilter {
    fn from_usize(u: usize) -> Option<LogLevelFilter> {
        match u {
            0 => Some(LogLevelFilter::Off),
            1 => Some(LogLevelFilter::Error),
            2 => Some(LogLevelFilter::Warn),
            3 => Some(LogLevelFilter::Info),
            4 => Some(LogLevelFilter::Debug),
            5 => Some(LogLevelFilter::Trace),
            _ => None
        }
    }
    /// Returns the most verbose logging level filter.
    #[inline]
    pub fn max() -> LogLevelFilter {
        LogLevelFilter::Trace
    }

    /// Converts `self` to the equivalent `LogLevel`.
    ///
    /// Returns `None` if `self` is `LogLevelFilter::Off`.
    #[inline]
    pub fn to_log_level(&self) -> Option<LogLevel> {
        LogLevel::from_usize(*self as usize)
    }
}

/// Metadata about a log message.
pub struct LogMetadata {
  pub level:  LogLevel,
  pub target: &'static str,
}

pub struct LogDirective {
    name:  Option<String>,
    level: LogLevelFilter,
}

fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {
    match t {
        Some(t) => Ok(t),
        None => Err(e),
    }
}

pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return dirs;
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match part0.parse() {
                    Ok(num) => (num, None),
                    Err(_) => (LogLevelFilter::max(), Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)),
            (Some(part0), Some(part1), None) => {
                match part1.parse() {
                    Ok(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    return dirs;
}

#[macro_export]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $format:expr, $level_tag:expr, $($arg:tt)+) => ({
      use $crate::logging::LOGGER;
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      {
        //FIXME: we will lose logs in multithreading like this
        if let Ok(mut logger) = LOGGER.try_lock() {
          logger.log(
            &_META,
            format_args!(
              concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
              ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
              $level_tag, *$crate::logging::TAG, $($arg)+));
        }
      }
    });
    (target: $target:expr, $lvl:expr, $format:expr, $level_tag:expr) => ({
      use $crate::logging::LOGGER;
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      {
        //FIXME: we will lose logs in multithreading like this
        if let Ok(mut logger) = LOGGER.try_lock() {
          logger.log(
            &_META,
            format_args!(
              concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
              ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
              $level_tag, *$crate::logging::TAG));
        }
      }
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: module_path!(), $lvl, $($arg)+));
}

#[macro_export]
macro_rules! error {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Error, $format, "ERROR", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Error, $format, "ERROR");
    };
}

#[macro_export]
macro_rules! warn {
    ($format:expr, $($arg:tt)*) => {
        use time;
        use logging::PID;
        log!($crate::logging::LogLevel::Warn, $format, "WARN", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Warn, $format, "WARN");
    }
}

#[macro_export]
macro_rules! info {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Info, $format, "INFO", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Info, $format, "INFO");
    }
}

#[macro_export]
macro_rules! debug {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format),
          "DEBUG", module_path!(), $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format),
          "DEBUG", module_path!());
    }
}

#[macro_export]
macro_rules! trace {
    ($format:expr, $($arg:tt)*) => (
        log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format),
          "TRACE", module_path!(), $($arg)*);
    );
    ($format:expr) => (
        log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format),
          "TRACE", module_path!());
    )
}

#[macro_export]
macro_rules! setup_test_logger {
  () => (
    $crate::logging::Logger::init(module_path!().to_string(), "error", $crate::logging::LoggerBackend::Stdout(::std::io::stdout()));
  );
}
<|endoftext|>


<commit_before>// Copyright (C) 2021 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::Result;
use bitar::{Archive, ChunkIndex, CloneOutput, ReaderRemote};
use futures_util::{StreamExt, TryStreamExt};
use slog_scope::trace;
use std::path::Path;
use tokio::{fs, io::AsyncSeekExt};

pub(crate) async fn get_required_size(seed: &str, output: &Path) -> Result<u64> {
    let archive_source_size = {
        let seed_as_path = Path::new(seed);

        if seed_as_path.exists() {
            trace!("Loading archive from file: {:?}", seed_as_path);
            let archive = Archive::try_init(fs::File::open(seed_as_path).await?).await?;
            archive.total_source_size()
        } else {
            trace!("Loading archive from url: {}", seed);
            let archive = Archive::try_init(ReaderRemote::from_url(url::Url::parse(seed)?)).await?;
            archive.total_source_size()
        }
    };

    let current_size = fs::metadata(output).await?.len();

    Ok(archive_source_size.checked_sub(current_size).unwrap_or_default())
}

pub(crate) async fn clone(input: &str, output: &Path, output_seek: u64) -> Result<()> {
    let input_as_path = Path::new(input);

    if input_as_path.exists() {
        trace!("Cloning from file: {:?}", input_as_path);
        let archive = Archive::try_init(fs::File::open(input_as_path).await?).await?;
        clone_to_file(archive, output, output_seek).await
    } else {
        trace!("Cloning from url: {}", input);
        let archive = Archive::try_init(ReaderRemote::from_url(url::Url::parse(input)?)).await?;
        clone_to_file(archive, output, output_seek).await
    }
}

async fn clone_to_file<R, E1, E2>(
    mut archive: Archive<R>,
    output: &Path,
    output_seek: u64,
) -> std::result::Result<(), E2>
where
    R: bitar::Reader<Error = E1>,
    E2: From<E1>
        + From<std::io::Error>
        + From<bitar::HashSumMismatchError>
        + From<bitar::CompressionError>,
{
    // Open output file
    let mut output_file =
        fs::OpenOptions::new().create(true).write(true).read(true).open(output).await?;
    output_file.seek(std::io::SeekFrom::Start(output_seek)).await?;

    // Scan the output file for chunks and build a chunk index
    let mut output_index = ChunkIndex::new_empty();
    {
        let chunker = archive.chunker_config().new_chunker(&mut output_file);
        let mut chunk_stream = chunker.map_ok(|(offset, chunk)| (offset, chunk.verify()));
        while let Some(r) = chunk_stream.next().await {
            let (offset, verified) = r?;
            let (hash, chunk) = verified.into_parts();
            output_index.add_chunk(hash, chunk.len(), &[offset]);
        }
    }

    // Create output to contain the clone of the archive's source
    let mut output = CloneOutput::new(output_file, archive.build_source_index());

    // Reorder chunks in the output
    let _reused_bytes = output.reorder_in_place(output_index).await?;

    // Fetch the rest of the chunks from the archive
    let mut chunk_stream = archive.chunk_stream(output.chunks());
    // let mut read_archive_bytes = 0;
    while let Some(result) = chunk_stream.next().await {
        let compressed = result?;
        // read_archive_bytes += compressed.len();
        let unverified = compressed.decompress()?;
        let verified = unverified.verify()?;
        output.feed(&verified).await?;
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_inplace_clone() {
        // Create file with incomplete data
        let output_file = tempfile::NamedTempFile::new().unwrap();
        fs::write(output_file.path(), "Test message sample: [...], in Rio.").await.unwrap();

        clone("fixtures/message.bita", output_file.path(), 0).await.unwrap();

        // Assert that the file now has the full predefined message
        assert_eq!(
            fs::read_to_string(output_file.path()).await.unwrap().as_str(),
            "Test message sample: The Brazilian campaign at the Tokyo Games ended with positive results. With 21 medals, the country surpassed the record of 19 registered in 2016, in Rio.",
        );
    }
}
<commit_msg>uh: Add flush to delta::clone<commit_after>// Copyright (C) 2021 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::Result;
use bitar::{Archive, ChunkIndex, CloneOutput, ReaderRemote};
use futures_util::{StreamExt, TryStreamExt};
use slog_scope::trace;
use std::path::Path;
use tokio::{
    fs,
    io::{AsyncSeekExt, AsyncWriteExt},
};

pub(crate) async fn get_required_size(seed: &str, output: &Path) -> Result<u64> {
    let archive_source_size = {
        let seed_as_path = Path::new(seed);

        if seed_as_path.exists() {
            trace!("Loading archive from file: {:?}", seed_as_path);
            let archive = Archive::try_init(fs::File::open(seed_as_path).await?).await?;
            archive.total_source_size()
        } else {
            trace!("Loading archive from url: {}", seed);
            let archive = Archive::try_init(ReaderRemote::from_url(url::Url::parse(seed)?)).await?;
            archive.total_source_size()
        }
    };

    let current_size = fs::metadata(output).await?.len();

    Ok(archive_source_size.checked_sub(current_size).unwrap_or_default())
}

pub(crate) async fn clone(input: &str, output: &Path, output_seek: u64) -> Result<()> {
    let input_as_path = Path::new(input);

    if input_as_path.exists() {
        trace!("Cloning from file: {:?}", input_as_path);
        let archive = Archive::try_init(fs::File::open(input_as_path).await?).await?;
        clone_to_file(archive, output, output_seek).await
    } else {
        trace!("Cloning from url: {}", input);
        let archive = Archive::try_init(ReaderRemote::from_url(url::Url::parse(input)?)).await?;
        clone_to_file(archive, output, output_seek).await
    }
}

async fn clone_to_file<R, E1, E2>(
    mut archive: Archive<R>,
    output: &Path,
    output_seek: u64,
) -> std::result::Result<(), E2>
where
    R: bitar::Reader<Error = E1>,
    E2: From<E1>
        + From<std::io::Error>
        + From<bitar::HashSumMismatchError>
        + From<bitar::CompressionError>,
{
    // Open output file
    let mut output_file =
        fs::OpenOptions::new().create(true).write(true).read(true).open(output).await?;
    output_file.seek(std::io::SeekFrom::Start(output_seek)).await?;

    // Scan the output file for chunks and build a chunk index
    let mut output_index = ChunkIndex::new_empty();
    {
        let chunker = archive.chunker_config().new_chunker(&mut output_file);
        let mut chunk_stream = chunker.map_ok(|(offset, chunk)| (offset, chunk.verify()));
        while let Some(r) = chunk_stream.next().await {
            let (offset, verified) = r?;
            let (hash, chunk) = verified.into_parts();
            output_index.add_chunk(hash, chunk.len(), &[offset]);
        }
    }

    // Create output to contain the clone of the archive's source
    let mut output = CloneOutput::new(&mut output_file, archive.build_source_index());

    // Reorder chunks in the output
    let _reused_bytes = output.reorder_in_place(output_index).await?;

    // Fetch the rest of the chunks from the archive
    let mut chunk_stream = archive.chunk_stream(output.chunks());
    // let mut read_archive_bytes = 0;
    while let Some(result) = chunk_stream.next().await {
        let compressed = result?;
        // read_archive_bytes += compressed.len();
        let unverified = compressed.decompress()?;
        let verified = unverified.verify()?;
        output.feed(&verified).await?;
    }

    // Ensure that the output file has been fully updated before returning
    output_file.flush().await?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_inplace_clone() {
        // Create file with incomplete data
        let output_file = tempfile::NamedTempFile::new().unwrap();
        fs::write(output_file.path(), "Test message sample: [...], in Rio.").await.unwrap();

        clone("fixtures/message.bita", output_file.path(), 0).await.unwrap();

        // Assert that the file now has the full predefined message
        assert_eq!(
            fs::read_to_string(output_file.path()).await.unwrap().as_str(),
            "Test message sample: The Brazilian campaign at the Tokyo Games ended with positive results. With 21 medals, the country surpassed the record of 19 registered in 2016, in Rio.",
        );
    }
}
<|endoftext|>