\documentclass[addpoints,12pt]{exam}

\usepackage{ngerman}
\usepackage{listings,color}
\usepackage{graphicx}
\usepackage[T1]{fontenc}

\firstpageheadrule
\runningheadrule
\lhead{Manuel Traut\\Sommersemester 2020}
\chead{Hochschule Ravensburg-Weingarten\\Linux-Kernelprogrammierung}
\rhead{MatrNr:\\Datum:}

\firstpagefootrule
\runningfootrule
\firstpagefooter{Page \thepage\ of \numpages}
{}
{Punkte: \makebox[.5in]{\hrulefill}\\
von \pointsonpage{\thepage} Punkten}

\runningfooter{Page \thepage\ of \numpages}
{}
{}

\pagestyle{headandfoot}

\pointsinrightmargin
\pointpoints{Punkt}{Punkte}

\begin{document}


\begin{coverpages}
\begin{titlepage}
\title{Pr\"ufung Linux-Kernelprogrammierung}
\author{Dozent: Manuel Traut}
\date{20. Juli 2020 16:00 Uhr}
\maketitle
\begin{center}
Hochschule Ravensburg-Weingarten
\vspace{1cm}

Raum: H062 Sektor 1

Dauer: 60 Minuten, erlaubte Hilfsmittel: alle
\end{center}


\vspace{2cm}
Name:\enspace\hrulefill
\vspace{2cm}
MatrNr:\enspace\hrulefill
\begin{center}
\begin{lstlisting}
              a8888b.
             d888888b.
             8P"YP"Y88      (((((((())))))))))
             8|o||o|88      ||VIEL ERFOLG !!||
             8'    .88      ((((((((((((()))))
             8`._.' Y8.
            d/      `8b.
          .dP   .     Y8b.
         d8:'   "   `::88b.
        d8"           `Y88b
       :8P     '       :888
        8a.    :      _a88P
      ._/"Yaa_ :    .| 88P|
      \    YP"      `| 8P  `.
      /     \._____.d|    .'
      `--..__)888888P`._.'
\end{lstlisting}
\end{center}
\end{titlepage}
\end{coverpages}

\lstset{ %
  basicstyle=\scriptsize,   % the size of the fonts that are used for the code
  breaklines=true,          % sets automatic line breaking
  frame=single,             % adds a frame around the code
  language=C,               % the language of the code
  numbers=left,             % where to put the line-numbers;
  numbersep=5pt,            % how far the line-numbers are from the code
  numberstyle=\tiny,        % the style that is used for the line-numbers
  tabsize=8,                % sets default tabsize to 2 spaces
}

\begin{questions}

\question[3] Was ist eine Linuxdistribution, was der Linuxkernel? Wie stehen
Sie in Relation?

\question[3] Was versteht man unter dem Begriff 'Kernelpatch'? Wie wird ein
  Patch erstellt und angewendet?

\question[4] Erkl\"aren Sie an einem Beispiel die Aufgaben eines Linux Kernel
  Maintainers.

\question [6] Beschreiben Sie stichwortartig den Releasezyklus des Linuxkernels
Erkl\"aren Sie in diesem Zusammenhang auch die Begriffe 'Release Candidate',
'Release', 'stable Kernel' und 'staging'.

\question
\begin{parts}
\part[1] Welches Tool ist auf folgendem Bild zu sehen?
\part[1] \"Uber welche Datei wird der Inhalt / Struktur des Tools gesteuert?
\part[2] Warum ist es notwendig, dass der Kernel konfigurierbar ist?
\part[4] Welche Einstellungen k\"onnen mit Hilfe dieses Tools konfiguriert
  werden? (beschreiben Sie 4 Kategorien)
\end{parts}

\includegraphics[height=0.3\textwidth]{./images/kconfig.png}


\question
Linux beinhaltet das Tracingsystem 'ftrace'.
\begin{parts}
\part[4] Beschreiben/Skizzieren Sie die Architektur und die wichtigsten
Funktionen des Systems.
\part[4] Beschreiben Sie am Beispiel sched::sched\_switch Event wie Sie
das Tracing konfigurieren, starten, auslesen.
\end{parts}

\question[4] Nennen Sie 4 Gr\"unde die f\"ur oder gegen die Integration eines
von Ihnen entwickelten Treibers in Mainline Linux sprechen.

\question[4] Kernel- und Userspace arbeiten in unterschiedlichen
  Addressr\"aumen. Nennen Sie eine M\"oglichkeit, wie Daten zwischen den
  Bereichen ausgetauscht werden k\"onnen. Nennen Sie typische
  Verwendung, gegebenenfalls Einschr\"ankungen.

\newpage

\question
Die folgenden Frage bezieht sich auf den Quellcode 1 im Anhang.
\begin{parts}
\part[10] Mit den Funktionen 'set\_latch\_green und get\_latch\_green' (welche
in asm/mach-rc32434/gpio.h definiert sind) kann analog zu den bereits verwendeten
Funktionen 'set\_latch\_u5 / get\_latch\_u5' eine gr\"une LED angesteuert
werden. Erweitern Sie den Treiber so, dass die gr\"une LED z.B. mit
  'echo 1 > /sys/class/leds/huhu/brightness'
eingeschaltet werden kann.
\end{parts}

\question
Die folgenden Fragen beziehen sich auf den Quellcode 2 im Anhang.
\begin{parts}
\part[4] Der Treiber wird in einem System geladen, welches 2 PCI Devices mit
  Vendor ID 0x186c und Device ID 0x0624 besitzt. Wie oft wird mf624\_pci\_probe
  und mf624\_init aufgerufen?
\part[8] Egal auf welches Device Sie zugreifen, Sie interagieren immer nur mit
  einer der zwei PCI Karten. Wie m\"usssen Sie den Treiber modifizieren, damit
  beide Karten funktionieren?
\end{parts}

\end{questions}

\vspace{1cm}
Punkte: \_\_\_\_ von \numpoints
\hspace{1cm}
Note:

\newpage

\begin{appendix}

Quellcode 1:

\begin{lstlisting}
/*
 * LEDs driver for the "User LED" on Routerboard532
 *
 * Copyright (C) 2009 Phil Sutter <n0-1@freewrt.org>
 *
 * Based on leds-cobalt-qube.c by Florian Fainelly and
 * rb-diag.c (my own standalone driver for both LED and
 * button of Routerboard532).
 */

#include <linux/leds.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <asm/mach-rc32434/gpio.h>
#include <asm/mach-rc32434/rb.h>

static void rb532_led_set(struct led_classdev *cdev,
        enum led_brightness brightness)
{
  if (brightness)
    set_latch_u5(LO_ULED, 0);
  else
    set_latch_u5(0, LO_ULED);
}

static enum led_brightness rb532_led_get(struct led_classdev *cdev)
{
  return (get_latch_u5() & LO_ULED) ? LED_FULL : LED_OFF;
}

static struct led_classdev rb532_uled = {
  .name = "uled",
  .brightness_set = rb532_led_set,
  .brightness_get = rb532_led_get,
  .default_trigger = "nand-disk",
};

static int rb532_led_probe(struct platform_device *pdev)
{
  return led_classdev_register(&pdev->dev, &rb532_uled);
}

static int rb532_led_remove(struct platform_device *pdev)
{
  led_classdev_unregister(&rb532_uled);
  return 0;
}

static struct platform_driver rb532_led_driver = {
  .probe = rb532_led_probe,
  .remove = rb532_led_remove,
  .driver = {
    .name = "rb532-led",
  },
};

module_platform_driver(rb532_led_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("User LED support for Routerboard532");
MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>");
MODULE_ALIAS("platform:rb532-led");
\end{lstlisting}

\newpage

Quellcode 2:

\begin{lstlisting}
/*
 * UIO driver fo Humusoft MF624 DAQ card.
 * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>,
 *                    Czech Technical University in Prague
 *
 * Copyright (C) 2016 Manuel Traut <manut@mecka.net>,
 *                    modified for usage in kernel exams
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/uio_driver.h>

#define PCI_VENDOR_ID_HUMUSOFT    0x186c
#define PCI_DEVICE_ID_MF624   0x0624
/* BAR0 Interrupt control/status register */
#define INTCSR        0x4C
#define INTCSR_ADINT_ENABLE   (1 << 0)
#define INTCSR_CTR4INT_ENABLE   (1 << 3)
#define INTCSR_PCIINT_ENABLE    (1 << 6)
#define INTCSR_ADINT_STATUS   (1 << 2)
#define INTCSR_CTR4INT_STATUS   (1 << 5)

enum mf624_interrupt_source {ADC, CTR4, ALL};

static void mf624_disable_interrupt(enum mf624_interrupt_source source,
           struct uio_info *info)
{
  void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;

  switch (source) {
  case ADC:
    iowrite32(ioread32(INTCSR_reg)
      & ~(INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE),
      INTCSR_reg);
    break;
  case CTR4:
  default:
    iowrite32(ioread32(INTCSR_reg)
      & ~(INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE),
      INTCSR_reg);
    break;
  }
}

static irqreturn_t mf624_irq_handler(int irq, struct uio_info *info)
{
  void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;

  if ((ioread32(INTCSR_reg) & INTCSR_ADINT_ENABLE)
      && (ioread32(INTCSR_reg) & INTCSR_ADINT_STATUS)) {
    mf624_disable_interrupt(ADC, info);
    return IRQ_HANDLED;
  }

  if ((ioread32(INTCSR_reg) & INTCSR_CTR4INT_ENABLE)
      && (ioread32(INTCSR_reg) & INTCSR_CTR4INT_STATUS)) {
    mf624_disable_interrupt(CTR4, info);
    return IRQ_HANDLED;
  }
  return IRQ_NONE;
}

static struct uio_info mf624_info = {
  .name = "mf624";
  .version = "0.0.1";
};

static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
  struct uio_info *info = &mf624_info;

  if (pci_enable_device(dev))
    return -1;

  if (pci_request_regions(dev, "mf624"))
    goto out_disable;

  /* BAR0 */
  info->mem[0].name = "PCI chipset, interrupts, status "
      "bits, special functions";
  info->mem[0].addr = pci_resource_start(dev, 0);
  if (!info->mem[0].addr)
    goto out_release;
  info->mem[0].size = pci_resource_len(dev, 0);
  info->mem[0].memtype = UIO_MEM_PHYS;
  info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
  if (!info->mem[0].internal_addr)
    goto out_release;

  /* BAR2 */
  info->mem[1].name = "ADC, DAC, DIO";
  info->mem[1].addr = pci_resource_start(dev, 2);
  if (!info->mem[1].addr)
    goto out_unmap0;
  info->mem[1].size = pci_resource_len(dev, 2);
  info->mem[1].memtype = UIO_MEM_PHYS;
  info->mem[1].internal_addr = pci_ioremap_bar(dev, 2);
  if (!info->mem[1].internal_addr)
    goto out_unmap0;

  info->irq = dev->irq;
  info->irq_flags = IRQF_SHARED;
  info->handler = mf624_irq_handler;

  if (uio_register_device(&dev->dev, info))
    goto out_unmap1;

  pci_set_drvdata(dev, info);
  return 0;

out_unmap1:
  iounmap(info->mem[1].internal_addr);
out_unmap0:
  iounmap(info->mem[0].internal_addr);

out_release:
  pci_release_regions(dev);

out_disable:
  pci_disable_device(dev);

  return -ENODEV;
}

static void mf624_pci_remove(struct pci_dev *dev)
{
  struct uio_info *info = pci_get_drvdata(dev);

  mf624_disable_interrupt(ALL, info);

  uio_unregister_device(info);
  pci_release_regions(dev);
  pci_disable_device(dev);

  iounmap(info->mem[0].internal_addr);
  iounmap(info->mem[1].internal_addr);

  kfree(info);
}

static const struct pci_device_id mf624_pci_id[] = {
  { PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
  { 0, }
};

static struct pci_driver mf624_pci_driver = {
  .name = "mf624",
  .id_table = mf624_pci_id,
  .probe = mf624_pci_probe,
  .remove = mf624_pci_remove,
};
MODULE_DEVICE_TABLE(pci, mf624_pci_id);

int mf624_init(void)
{
  return pci_driver_register(&mf624_pci_driver);
}

void mf624_exit(void)
{
  pci_driver_unregister(&mf624_pci_driver);
}

module_init(mf624_init);
module_exit(mf624_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
\end{lstlisting}


\end{appendix}
\end{document}
