312 lines
11 KiB
TeX
312 lines
11 KiB
TeX
\documentclass[11pt]{article}
|
|
\usepackage[T1]{fontenc}
|
|
\usepackage[utf8]{inputenc}
|
|
\usepackage[polish]{babel}
|
|
\usepackage[a4paper,margin=1.75cm]{geometry}
|
|
\usepackage{array,tabularx,booktabs}
|
|
\usepackage{amsmath,amssymb}
|
|
\usepackage{xcolor,listings}
|
|
\usepackage{hyperref,fancyhdr,lastpage}
|
|
\usepackage{enumitem}
|
|
|
|
\definecolor{accent}{HTML}{16324A}
|
|
\definecolor{accentlight}{HTML}{EEF3F7}
|
|
\definecolor{rulegray}{HTML}{D7DEE5}
|
|
\hypersetup{colorlinks=true,linkcolor=accent,urlcolor=blue}
|
|
\IfFileExists{build-meta.tex}{\input{build-meta.tex}}{\newcommand{\BuildCommit}{local}}
|
|
\newcommand{\PublisherDomain}{mpabi}
|
|
\newcommand{\DocumentAuthor}{M. Pabiszczak}
|
|
\newcommand{\DocumentYear}{2026}
|
|
\newcommand{\CardArea}{inf}
|
|
\newcommand{\CardSeries}{rv32i-freertos}
|
|
\newcommand{\CardNumber}{01}
|
|
\newcommand{\CardCount}{14}
|
|
\newcommand{\CardSlug}{heap4}
|
|
\newcommand{\CardVersion}{v0.2}
|
|
\newcommand{\DocumentKey}{\PublisherDomain/\CardArea/\CardSeries/\CardNumber/\CardSlug/\CardVersion}
|
|
\newcommand{\DocumentUUID}{4654524c-73f2-46df-83a3-d448ba6d6c5a}
|
|
|
|
\lstset{
|
|
language=C,basicstyle=\ttfamily\scriptsize,columns=fullflexible,
|
|
keepspaces=true,frame=single,breaklines=true,showstringspaces=false,
|
|
numbers=left,numberstyle=\tiny\color{accent},numbersep=6pt,
|
|
backgroundcolor=\color{accentlight},rulecolor=\color{rulegray}
|
|
}
|
|
\pagestyle{fancy}
|
|
\fancyhf{}
|
|
\lhead{\textbf{FreeRTOS: heap\_4}}
|
|
\rhead{\small karta 01/14}
|
|
\lfoot{\scriptsize commit \BuildCommit}
|
|
\cfoot{\scriptsize \thepage/\pageref{LastPage}}
|
|
\rfoot{\scriptsize V11.3.0 / \CardVersion}
|
|
\setlength{\headheight}{15pt}
|
|
\setlength{\footskip}{22pt}
|
|
\setlist[itemize]{nosep,leftmargin=1.5em}
|
|
\setlist[enumerate]{itemsep=.25em,leftmargin=1.7em}
|
|
\newcommand{\checkline}{\(\square\)\;}
|
|
|
|
\begin{document}
|
|
\sloppy
|
|
|
|
\begin{center}
|
|
{\LARGE\bfseries Karta pracy: FreeRTOS \texttt{heap\_4}}\par
|
|
\vspace{.4em}
|
|
{\large model $\rightarrow$ prawdziwy upstream $\rightarrow$ RP2350}\par
|
|
\end{center}
|
|
|
|
\begin{tabularx}{\textwidth}{@{}lX@{}}
|
|
\toprule
|
|
Klucz & \texttt{\DocumentKey} \\
|
|
Wersja / commit & \texttt{\CardVersion} / \texttt{\BuildCommit} \\
|
|
Data & 14.07.2026 \\
|
|
Allocator & FreeRTOS-Kernel V11.3.0, \texttt{9b777ae5c5b8} \\
|
|
Port RP2350 & fork Raspberry Pi, \texttt{4f7299d6ea74} \\
|
|
Źródło & \texttt{portable/MemMang/heap\_4.c} — bez modyfikacji \\
|
|
Punkt wejścia & \texttt{stemctl} \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\section*{Tylko trzy kroki}
|
|
\begin{enumerate}
|
|
\item First-fit + split: skąd bierze się drugi nagłówek.
|
|
\item Free-list + coalescing: dlaczego lista jest uporządkowana po adresie.
|
|
\item API FreeRTOS: \texttt{pvPortMalloc}, \texttt{vPortFree}, stats, OOM.
|
|
\end{enumerate}
|
|
|
|
\section*{Warunek zaliczenia}
|
|
\begin{itemize}
|
|
\item \checkline przewiduję rozmiary nagłówków i bloków na AMD64/RV32;
|
|
\item \checkline rozpoznaję fragmentację: suma wolnych bajtów $\neq$ największy blok;
|
|
\item \checkline pokazuję split i dwa kierunki scalania w Memory;
|
|
\item \checkline odczytuję \texttt{xStart}, \texttt{pxEnd}, minimum-ever i stack frame;
|
|
\item \checkline Task 3 daje \texttt{pass=1} na host, Hazard3 i RP2350.
|
|
\end{itemize}
|
|
|
|
\newpage
|
|
\section{Start — polecenia i platformy}
|
|
|
|
\begin{lstlisting}[language=bash,numbers=none]
|
|
stemctl test native-amd64 freertos heap4 1
|
|
stemctl test hazard3-sim freertos heap4 2
|
|
stemctl debug hazard3-sim freertos heap4 3
|
|
stemctl test rp2350 freertos heap4 3
|
|
stemctl deploy rp2350 freertos heap4 3 \
|
|
--device /dev/bus/usb/BBB/DDD
|
|
\end{lstlisting}
|
|
|
|
\begin{tabularx}{\textwidth}{@{}p{3.1cm}XXX@{}}
|
|
\toprule
|
|
& AMD64 & Hazard3 & RP2350 \\
|
|
\midrule
|
|
Task 1--2 & model + sanitizery & model na RTL & build \\
|
|
Task 3 & V11.3 + adapter 1-thread & pełny V11.3 + port RISC-V & zgodny core+port RP; allocator V11.3 \\
|
|
Debug & GDB & GDB stub RTL & OpenOCD; SRAM \\
|
|
Deploy & --- & --- & SPI flash + verify \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\subsection*{Termdebug}
|
|
\begin{tabularx}{\textwidth}{@{}lXlX@{}}
|
|
\toprule
|
|
\texttt{F5} & continue & \texttt{F9} & breakpoint \\
|
|
\texttt{F10} & next & \texttt{F11} & step \\
|
|
\texttt{Shift-F11} & finish & \texttt{F8} & stepi \\
|
|
\texttt{:StudentStack} & frame + stos & \texttt{:StudentLst} & listing ELF-a \\
|
|
\bottomrule
|
|
\end{tabularx}
|
|
|
|
\textbf{Strategia obserwacji}: breakpoint przed zmianą $\rightarrow$ Memory
|
|
$\rightarrow$ continue/finish $\rightarrow$ Memory. Nie opieramy karty na data
|
|
watchpointach.
|
|
|
|
\newpage
|
|
\section{Task 1 — first-fit i split}
|
|
|
|
\subsection*{Policz przed uruchomieniem}
|
|
\begin{tabular}{@{}lcc@{}}
|
|
\toprule
|
|
& AMD64 & RV32 \\
|
|
\midrule
|
|
\texttt{sizeof(ModelBlock)} & \rule{1.6cm}{.2pt} & \rule{1.6cm}{.2pt} \\
|
|
request & 13 B & 13 B \\
|
|
\texttt{align8(header + request)} & \rule{1.6cm}{.2pt} & \rule{1.6cm}{.2pt} \\
|
|
remainder z 256 B & \rule{1.6cm}{.2pt} & \rule{1.6cm}{.2pt} \\
|
|
offset payloadu & \rule{1.6cm}{.2pt} & \rule{1.6cm}{.2pt} \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
|
|
\subsection*{Do wykonania}
|
|
\begin{enumerate}
|
|
\item Wskaż nagłówek bloku przydzielonego i nagłówek remainder.
|
|
\item Sprawdź: \texttt{wanted + remainder == 256}.
|
|
\item Zmień request 13 na 17; przewidź wynik bez uruchamiania.
|
|
\item W listingu znajdź dodawanie bajtowego offsetu do adresu areny.
|
|
\end{enumerate}
|
|
|
|
\lstinputlisting{../src/tasks/task01_first_fit_split.c}
|
|
|
|
\newpage
|
|
\section{Task 2 — lista adresowa i coalescing}
|
|
|
|
\subsection*{Eksperyment}
|
|
\begin{center}
|
|
\texttt{A:48 | B:48 | C:48}\quad
|
|
$\xrightarrow{\text{free A, free C}}$\quad
|
|
\texttt{A:48 -> C:48}\quad
|
|
$\xrightarrow{\text{free B}}$\quad
|
|
\texttt{A:144}
|
|
\end{center}
|
|
|
|
\subsection*{Do wykonania}
|
|
\begin{enumerate}
|
|
\item Zatrzymaj program w \texttt{task02\_fragmented\_checkpoint}.
|
|
\item Zapisz adresy i rozmiary dwóch elementów free-list.
|
|
\item Wykonaj \texttt{F5}; zatrzymaj w \texttt{task02\_debug\_checkpoint}.
|
|
\item Wskaż pierwszy warunek scalania: z blokiem po prawej.
|
|
\item Wskaż drugi warunek scalania: z blokiem po lewej.
|
|
\item Wyjaśnij, czemu kolejność po adresie redukuje koszt szukania sąsiadów.
|
|
\end{enumerate}
|
|
|
|
\subsection*{Tabela obserwacji}
|
|
\begin{tabular}{@{}lccc@{}}
|
|
\toprule
|
|
Stan & liczba bloków & suma & największy \\
|
|
\midrule
|
|
przed B & \rule{1.4cm}{.2pt} & \rule{1.4cm}{.2pt} & \rule{1.4cm}{.2pt} \\
|
|
po B & \rule{1.4cm}{.2pt} & \rule{1.4cm}{.2pt} & \rule{1.4cm}{.2pt} \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
|
|
\lstinputlisting{../src/tasks/task02_address_order_coalesce.c}
|
|
|
|
\newpage
|
|
\section{Task 3 — prawdziwy FreeRTOS \texttt{heap\_4.c}}
|
|
|
|
\subsection*{Sekwencja testowa}
|
|
\begin{enumerate}
|
|
\item init przez pierwsze \texttt{pvPortMalloc(1)} i \texttt{vPortFree}; zapisz $F_0$;
|
|
\item malloc: 24 B, 40 B, 16 B; zapisz $F_1$;
|
|
\item free pierwszego i trzeciego; oczekuj 2 wolnych bloków;
|
|
\item free środkowego; oczekuj jednego bloku i $F_{final}=F_0$;
|
|
\item malloc większy niż heap; oczekuj \texttt{NULL} i jednego hooka.
|
|
\end{enumerate}
|
|
|
|
\subsection*{Inwarianty — zaznacz po teście}
|
|
\begin{itemize}
|
|
\item \checkline $F_0 > F_1$;
|
|
\item \checkline $F_{final}=F_0$;
|
|
\item \checkline minimum-ever $\leq F_1$ i nie rośnie po free;
|
|
\item \checkline każdy payload ma adres podzielny przez 8;
|
|
\item \checkline OOM zwraca \texttt{NULL};
|
|
\item \checkline końcowa free-list ma dokładnie jeden blok.
|
|
\end{itemize}
|
|
|
|
\lstinputlisting{../src/tasks/task03_freertos_heap4.c}
|
|
|
|
\newpage
|
|
\section{Czytanie upstream \texttt{heap\_4.c}}
|
|
|
|
\subsection*{Znajdź w pliku — nie czytaj całego od góry}
|
|
\begin{lstlisting}[language=bash,numbers=none]
|
|
K=/opt/FreeRTOS-Kernel/portable/MemMang/heap_4.c
|
|
rg -n 'xHeapStructSize|pvPortMalloc|prvHeapInit' "$K"
|
|
rg -n 'prvInsertBlockIntoFreeList|vPortFree' "$K"
|
|
rg -n 'xFreeBytesRemaining|xMinimumEver' "$K"
|
|
rg -n 'heapADD_WILL_OVERFLOW|heapBLOCK_ALLOCATED' "$K"
|
|
\end{lstlisting}
|
|
|
|
\begin{itemize}[leftmargin=*,itemsep=2pt]
|
|
\item \texttt{xHeapStructSize}: dlaczego jest wyrównany oddzielnie od
|
|
\texttt{sizeof}?
|
|
\item \texttt{heapBLOCK\_ALLOCATED\_BITMASK}: który bit rozmiaru oznacza
|
|
właściciela?
|
|
\item \texttt{pvPortMalloc}: gdzie są overflow, alignment, first-fit i split?
|
|
\item \texttt{vPortFree}: jak odzyskuje nagłówek z payloadu?
|
|
\item \texttt{prvInsertBlockIntoFreeList}: gdzie są dwa kierunki scalania?
|
|
\item \texttt{xMinimumEverFreeBytesRemaining}: dlaczego free go nie zwiększa?
|
|
\end{itemize}
|
|
|
|
\subsection*{Breakpointy}
|
|
\begin{lstlisting}[numbers=none]
|
|
b pvPortMalloc
|
|
b vPortFree
|
|
b prvInsertBlockIntoFreeList
|
|
p xStart
|
|
p pxEnd
|
|
p xFreeBytesRemaining
|
|
p xMinimumEverFreeBytesRemaining
|
|
x/160bx ucHeap
|
|
\end{lstlisting}
|
|
|
|
\newpage
|
|
\section{RP2350 — deploy i dowód sprzętowy}
|
|
|
|
\subsection*{Polecenie}
|
|
\begin{lstlisting}[language=bash,numbers=none]
|
|
stemctl probe list
|
|
stemctl deploy rp2350 freertos heap4 3 \
|
|
--device /dev/bus/usb/BBB/DDD
|
|
\end{lstlisting}
|
|
|
|
\subsection*{Automatyczny test zatrzymuje się dwa razy}
|
|
\begin{enumerate}
|
|
\item \texttt{heap4\_fragmented\_checkpoint}: 2 wolne bloki;
|
|
\item \texttt{task03\_debug\_checkpoint}: heap odtworzony, OOM obsłużony.
|
|
\end{enumerate}
|
|
|
|
\subsection*{Zapis ucznia}
|
|
\begin{tabular}{@{}ll@{}}
|
|
\toprule
|
|
Wielkość & Wartość \\
|
|
\midrule
|
|
\texttt{initial free} & \rule{4cm}{.2pt} \\
|
|
\texttt{after allocations} & \rule{4cm}{.2pt} \\
|
|
\texttt{minimum ever} & \rule{4cm}{.2pt} \\
|
|
\texttt{final free} & \rule{4cm}{.2pt} \\
|
|
\texttt{sp / fp / pc} & \rule{7cm}{.2pt} \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
|
|
\subsection*{Kontrakt}
|
|
\begin{itemize}
|
|
\item flash: write + verify; ELF: RISC-V;
|
|
\item breakpointy sprzętowe, nie data watchpoint;
|
|
\item \texttt{aligned=1 oom=1 hooks=1 asserts=0 pass=1};
|
|
\item \texttt{sp \& 15 == 0};
|
|
\item \texttt{rp2350-hardware-ok task=task03 heap\_4=upstream}.
|
|
\end{itemize}
|
|
|
|
\textbf{Operacje są rozdzielone}: \texttt{debug} ładuje do SRAM;
|
|
\texttt{deploy} zapisuje trwały obraz do SPI flash.
|
|
|
|
\newpage
|
|
\section{Podsumowanie i oddanie}
|
|
|
|
\subsection*{Odpowiedz jednym zdaniem}
|
|
\begin{enumerate}
|
|
\item Dlaczego \texttt{heap\_4} scala, a nie tylko odkłada blok na listę?\\[.6em]
|
|
\rule{\textwidth}{.2pt}
|
|
\item Dlaczego „wolne razem” nie oznacza „można przydzielić jeden duży blok”?\\[.6em]
|
|
\rule{\textwidth}{.2pt}
|
|
\item Gdzie leży metadata bloku przydzielonego aplikacji?\\[.6em]
|
|
\rule{\textwidth}{.2pt}
|
|
\item Co mierzy minimum-ever-free, a czego nie mierzy?\\[.6em]
|
|
\rule{\textwidth}{.2pt}
|
|
\end{enumerate}
|
|
|
|
\subsection*{Oddaj}
|
|
\begin{itemize}
|
|
\item \checkline wyniki 3 tasków na AMD64;
|
|
\item \checkline Hazard3: trzy kody wyjścia 0;
|
|
\item \checkline zrzut Task 2: przed i po scaleniu;
|
|
\item \checkline zrzut Task 3: source + listing + Memory + Stack;
|
|
\item \checkline wynik RP2350 \texttt{rp2350-hardware-ok};
|
|
\item \checkline wypełnione inwarianty i cztery odpowiedzi.
|
|
\end{itemize}
|
|
|
|
\vfill
|
|
\noindent\textbf{Dalej}: taski FreeRTOS, scheduler, osobne stosy, 1 kHz tick;
|
|
następnie cienki C++ header wrapper i użycie w projekcie hoveboard.
|
|
|
|
\end{document}
|