Facultat d’Informàtica de Barcelona

Dept. d’Arquitectura de Computadors

curs 2024/25-2Q

Pràctiques de laboratori

Mach i MacOS

Tradicionalment, a CASO hem fet el laboratori sobre el microkernel Mach fent servir GNUHurd, i una versió de Debian que s’executa a sobre. A partir del curs 2023/2024-Q2 disposem d’un ordinador Apple Mac mini M2, amb MacOSX, sobre el qual podem fer el mateix estil de laboratori.

Com que MacOSX funciona sobre el Microkernel Mach, és una bona alternativa per fer els mateixos exercicis que els proposats per Debian/GNU Hurd.

Material

Compte a la màquina

  • Us haurem donat un compte d’usuari a la màquina de l’assignatura amb MacOSX.

Terminal (zsh)

Podeu obrir un terminal, connectant-vos per "ssh". El terminal per defecte té l’intèrpret de comandes zsh. El podeu canviar pel "bash" fent servir

$ chsh -s /bin/bash

Eines de desenvolupament (Xcode)

L’ordinador té instal·lades les eines de desenvolupament (Xcode) amb el gcc i els binutils. També disposa dels compiladors d’Apple (Clang i Clang++ / LLVM) i de l’SDK (Software Development Kit) de MacOSX, que us permetrà desenvolupar aplicacions sobre la interfície de Mach 3.0.

$ export PATH=/opt/homebrew/bin:/opt/homebrew/sbin:$PATH
$ export MANPATH=/opt/homebrew/share/man:    # Els ":" són molt importants... per què?
$ gcc-14 --version
$ clang --version
$ gcc --version
$ cc --version
$ g++-14 --version
$ clang++ --version
$ g++ --version
$ c++ --version
$ CC --version

Desenvolupament de programes sobre MacOSX

L’SDK queda instal·lat en el directori:

/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk

I en aquest directori, teniu els "header files" de Mach:

/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include

Clang/Clang++ sap incloure els fitxers d’include i enllaçar amb les llibreries automàticament.

Tingueu en compte - com ja haureu vist abans :) - que hi ha també els noms "gcc" i "g", que invoquen "clang" i "clang" respectivament, i són més o menys compatibles amb gcc-14 i g++-14 en quan a les opcions de compilació. Per invocar el "gcc" real cal posar-se el PATH apuntant a "/opt/homebrew/bin" i executar "gcc-14".

Informació sobre Mach

Tot i que hi ha algunes diferències, en aquest punt podeu trobar informació sobre Mach a la secció "La interfície de Mach" del document corresponent a GNU Hurd.

Exercicis de la pràctica

Copieu el codi d’exemple que us donem (codi-lab-macos-2025.tar.bz2), on teniu també el Makefile que us permetrà compilar el codi font de tots els exercicis.

  1. Comproveu que el programa proc.c funciona correctament per l’usuari root, però dóna l’error respecte l’accés al port privilegiat del host si l’executa un usuari no privilegiat (per exemple, si l’executeu des de l’usuari "caso").

  2. Quin(s) processador(s) indica que tenim el programa proc.c? Podeu buscar a <mach/machine.h> els codis de CPU Type i CPU Subtype, i veure com estan definits els tipus de CPU d’Intel (Penryn, Nehalem…​), ARM (…​ Xscale, …​, V8, 64E…​ quins deuen correspondre als M1 i M2?) i PowerPC (601, …​, 620…​, 970…​).

    1. Proveu també els següents programes. Quins processadors i quins tipus de processador coneixeu? Podeu obtenir alguna informació sobre els processadors que no coneixeu?

processor-types
processor-subtypes
  1. Expliqueu les altres característiques del processador que mostra proc.c. Obtingueu-les del fitxer <mach/processor_info.h>; localitzeu-hi l’estructura processor_basic_info.

  2. Comproveu que el programa memory-management.c dóna errors al compilar…​ com els podeu arreglar? (pista: falta una coma (,) a la línia 60). Són clars els missatges d’error que dóna el compilador GCC en aquesta situació?

  3. Un cop arreglat el problema de la pregunta anterior, comproveu que el programa memory-management.c funciona correctament. Aquest programa usa host_processors i vm_map de forma intercalada, per demanar memòria 8 cops. L’ús de processor_info per demanar memòria queda fora del seu ús habitual, però funciona correctament. Responeu:

    1. Quanta memòria assigna al procés cada crida a host_processors?

    2. Quanta memòria assigna al procés cada crida a vm_map?

    3. Quines adreces ens dóna el sistema en cada crida (host_processors i vm_map)?

    4. Són pàgines consecutives? (pista: us ajudarà, incrementar el número d’iteracions que fa el programa…​ per veure la seqüència d’adreces més clara)

    5. Quines proteccions podem demanar a l’assignar memòria a un procés Mach? (pista: veieu el fitxer <mach/vm_prot.h>)

    6. Canvieu el programa per a que la memòria demanada sigui de només lectura. Quin error us dóna el sistema quan executeu aquesta nova versió del programa?

    7. Després, afegiu una crida a vm_protect (…​) per tal de desprotegir la memòria per escriptura i que el programa torni a permetre les escriptures en la memòria assignada. Proveu la nova versió i comproveu que ara torna a funcionar correctament.

  4. Ara feu servir el programa vm-regions.c per veure les regions de memòria que té un programa amb enllaçat dinàmic.

    1. Quantes regions té?

    2. N’hi ha algunes que semblin "especials"? Podeu trobar informació sobre elles?

    3. Abans d’acabar l’execució el vm-regions fa una sèrie de "malloc"s. Podeu determinar en quina regió del programa es demana la memòria pel "malloc"?

    4. De quina manera podem obtenir la mateixa informació sobre les regions d’un procés en Linux?

    5. Podeu executar la versió "estàtica" del vm-regions per veure quines regions té? Per què? N’hauria de tenir més o menys?

  5. [opcional] Feu un nou programa que actuï com un ps, que llisti les tasks que estan corrent (o que estan aturades) en el sistema. Anomeneu-lo mps per aprofitar que ja tenim definida la seva compilació en el fitxer Makefile.

  6. [opcional] Feu un programa mtask que rebi una primera opció [-r|-s] i una llista de processos (pids) i els aturi (-s) o els deixi continuar executant-se (-r), usant les crides task_suspend/task_resume. Exemples:

     $ mtask -r 84 105   # fa un task_resume de les tasks que pertanyen als processos 84 i 105
     $ mtask -s 58 206 87  # atura l'execució dels processos 58, 206 i 87.
Tip
Busqueu una crida a MacOSX/Mach que us permeti passar d’un pid al port (task_t) que identifica la task.
  1. Feu un programa, a partir del fitxer thread.c que creï un flux (thread_create) i li canviï l’estat (rsp, rip) amb les crides thread_get_state i thread_set_state, per engegar-lo posteriorment (thread_resume). Trobareu els tipus genèrics (independents de l’arquitectura) relacionats amb el context d’un flux en el fitxer <mach/thread_status.h>. La informació específica de com és l’estat d’un thread en una arquitectura ARM - AARCH64 la trobareu a <mach/arm/thread_status.h>: arm_thread_state64_t (i a <mach/arm/_structs.h: _STRUCT_ARM_THREAD_STATE64), i #defines ARM_THREAD_STATE64(flavor) i ARM_THREAD_STATE64_COUNT.

La informació per x86_64, per si voleu fer la mateixa pràctica en un MacOS en l’arquitectura d’Intel, la trobareu a <mach/i386/thread_status.h>: x86_thread_state_t (i a <mach/i386/_structs.h: _STRUCT_X86_THREAD_STATE64), i #defines x86_THREAD_STATE64(flavor), i x86_THREAD_STATE64_COUNT.

Feu que el flux executi una funció amb un bucle infinit i comproveu amb el 'top' que està consumint processador (el top hauria de dir 99% CPU, pel programa - thread - que es situa a dalt de tot), abans de destruir-lo (thread_terminate).

Ara feu que el thread faci un printf(…​). Per què us dóna un segmentation fault? Podeu esbrinar què passa?

Tip
useu el lldb, i mireu quina instrucció està executant el thread que falla.
  1. Observeu que en el fitxer "tsd.h" tenim la definició d’una funció interessant per resoldre el problema de la pregunta anterior. Podeu solucionar el problema?

void _thread_set_tsd_base(void *tsd_base);
Tip
Mireu també els comentaris que tenim al fitxer thread.c sobre com fer funcionar les variables privades per thread.
  1. [opcional, aquesta pregunta possiblement només es pot fer amb GNU Hurd i no amb MacOSX] Feu un programa que creï una task (task_create / task_terminate), i li doni memòria (vm_allocate), per després copiar-li una pàgina de dades (vm_write) Si heu fet la comanda [mps] (exercici 6), comproveu que la vostra task només té la memòria que li heu donat, haurieu d’obtenir una informació com:

virtual size 16384 # si li heu demanat 16KB (4 pàgines)
resident size 0

Comproveu que amb la comanda ps aquesta task també es veu:

$ ps -e -o pid,stat,sz,rss,args
PID     Stat    SZ  RSS Args
1670    p       16K 0   ?
  1. Feu un programa que accepti un pid i una adreça com a paràmetres, faci un vm_read de l’adreça donada en el procés donat i mostri la informació obtinguda. Creieu que això mateix es pot fer en UNIX/Linux? I en Windows?

  1. [opcional] Feu un programa que creï un procés amb fork() i faci que pare i fill es comuniquin amb un missatge de Mach, usant mach_msg_send() i mach_msg_receive().

  1. [opcional] Amplieu el programa [mps] (exercici 7), de forma que també mostri la informació bàsica dels fluxos de cada task.

  1. [opcional, aquesta pregunta possiblement només es pot fer amb GNU Hurd i no amb MacOSX] Feu un programa anomenat cp_mach.c que accepti dos arguments, noms de fitxer. El resultat serà la còpia del fitxer origen (primer argument) al fitxer destí (segon argument). Només haurieu de fer servir crides Mach, sense utilitzar open i close.

  1. [aquesta comanda ja existeix a MaxOSX] A MacOSX, la comanda lsmp mostra els mach ports d’un o de tots els processos.

    1. Proveu com funciona a MacOSX

    2. [opcional] Baixeu el {url-lsmp}[codi] d’aquest programa i recompileu-lo en Hurd. Feu els canvis al codi que considereu adients. Aquesta és l’ajuda de la comanda:

Usage: lsmp -p <pid> [-a|-v|-h]
   Lists information about mach ports. Please see man page for description of each
   column.
   -p <pid> :  print all mach ports for process id <pid>.
   -a :  print all mach ports for all processeses.
   -v :  print verbose details for kernel objects.
   -j <path> :  save output as JSON to <path>.
   -h :  print this help.
Important
Entregueu: Prepareu els programes i les respostes a les preguntes 2, 3, 4, 5, 6, 9, 10 i 12 per pujar-los al Racó.

Informació addicional